Files
workphone-sdk/sdk/agent/hook/wechat_v6_backend.js

489 lines
19 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// wechat_full_control_v6.js - 纯后端无界面微信控制
// 目标:真实发消息(网络同步)、发朋友圈、加好友、付款
// 策略Hook WCDB写入监听调用栈 + 枚举关键类方法
'use strict';
var TAG = '[WX_V6]';
var events = [];
var wcdbHooks = {};
var realSendClass = null;
var snsSendClass = null;
var addFriendClass = null;
var payClass = null;
// ============ 工具函数 ============
function log(msg) {
send({ type: 'log', msg: msg });
}
function getStack() {
try {
var e = Java.use('java.lang.Exception').$new();
var stack = e.getStackTrace();
var frames = [];
for (var i = 1; i < Math.min(stack.length, 12); i++) {
var f = stack[i];
var cls = f.getClassName();
if (cls.indexOf('com.tencent.mm') !== -1) {
frames.push(cls + '.' + f.getMethodName() + ':' + f.getLineNumber());
}
}
e.$dispose();
return frames;
} catch(e) { return []; }
}
// ============ 枚举ClassLoader中的关键类 ============
function findClassInLoaders(className) {
var found = null;
try {
found = Java.use(className);
return found;
} catch(e) {}
// 遍历所有ClassLoader
Java.enumerateClassLoaders({
onMatch: function(loader) {
try {
var cls = loader.loadClass(className);
if (cls) {
Java.classFactory.loader = loader;
found = Java.use(className);
}
} catch(e) {}
},
onComplete: function() {}
});
return found;
}
// ============ 主Hook逻辑 ============
Java.perform(function() {
log('v6 starting...');
// ===== 1. Hook WCDB insert 监听调用栈 =====
try {
var WCDB = Java.use('com.tencent.wcdb.database.SQLiteDatabase');
// Hook execSQL 捕获INSERT操作
WCDB.execSQL.overload('java.lang.String').implementation = function(sql) {
var result = this.execSQL(sql);
if (sql && sql.indexOf('INSERT') !== -1 && sql.indexOf('message') !== -1) {
var stack = getStack();
if (stack.length > 0) {
send({ type: 'wcdb_insert', sql: sql.substring(0, 100), stack: stack });
// 记录调用栈中的类名用于后续分析
stack.forEach(function(frame) {
var cls = frame.split('.').slice(0, -1).join('.');
if (cls && cls.indexOf('com.tencent.mm') !== -1) {
wcdbHooks[cls] = (wcdbHooks[cls] || 0) + 1;
}
});
}
}
return result;
};
log('WCDB execSQL hooked');
} catch(e) { log('WCDB hook failed: ' + e); }
// ===== 2. 尝试找真实发送类微信8.0.56混淆类名枚举)=====
// 策略Hook android.os.Handler.dispatchMessage 捕获消息发送
try {
var Handler = Java.use('android.os.Handler');
var msgCount = 0;
Handler.dispatchMessage.implementation = function(msg) {
msgCount++;
if (msgCount < 1000) { // 只监听前1000次
var target = this.toString();
if (target.indexOf('com.tencent.mm') !== -1 && target.indexOf('send') !== -1) {
send({ type: 'handler_send', handler: target.substring(0, 80) });
}
}
return this.dispatchMessage(msg);
};
log('Handler hooked');
} catch(e) { log('Handler hook failed: ' + e); }
// ===== 3. Hook OkHttp 捕获微信网络请求 =====
try {
var OkHttpClient = Java.use('okhttp3.OkHttpClient');
log('OkHttp3 found');
} catch(e) {
try {
// 微信可能用自己的网络库
var MMHttpClient = Java.use('com.tencent.mm.sdk.platformtools.HttpUtil');
log('MMHttpClient found');
} catch(e2) { log('HTTP client not found: ' + e2); }
}
// ===== 4. 尝试直接调用微信SNS发布接口 =====
// 微信8.0.56 SNS相关类通过枚举包名找
var snsClasses = [
'com.tencent.mm.plugin.sns.model.SnsUploadMgr',
'com.tencent.mm.plugin.sns.ui.SnsUploadUI',
'com.tencent.mm.plugin.sns.service.SnsService',
'com.tencent.mm.plugin.sns.model.SnsDataManager',
'com.tencent.mm.plugin.sns.ui.SnsTimeLineUI',
'com.tencent.mm.plugin.sns.model.SnsManager',
'com.tencent.mm.plugin.sns.SnsDataSyncMgr',
];
snsClasses.forEach(function(cls) {
try {
var c = Java.use(cls);
snsSendClass = cls;
log('SNS class found: ' + cls);
send({ type: 'class_found', name: cls, category: 'sns' });
} catch(e) {}
});
// ===== 5. 尝试找消息发送类 =====
var sendClasses = [
'com.tencent.mm.sdk.platformtools.MessageUtil',
'com.tencent.mm.modelmulti.MessageHelper',
'com.tencent.mm.plugin.chatting.model.MessageSender',
'com.tencent.mm.plugin.chatting.ui.ChatFooter',
'com.tencent.mm.sdk.model.MsgInfo',
'com.tencent.mm.plugin.chatting.ChattingController',
'com.tencent.mm.plugin.chatting.model.ChattingListData',
'com.tencent.mm.sdk.platformtools.MsgMgr',
'com.tencent.mm.plugin.chatting.model.MsgMgr',
];
sendClasses.forEach(function(cls) {
try {
var c = Java.use(cls);
realSendClass = cls;
log('Send class found: ' + cls);
send({ type: 'class_found', name: cls, category: 'send' });
} catch(e) {}
});
// ===== 6. 尝试找加好友类 =====
var addFriendClasses = [
'com.tencent.mm.plugin.contact.ui.ContactInfoUI',
'com.tencent.mm.plugin.contact.model.ContactManager',
'com.tencent.mm.plugin.contact.service.ContactService',
'com.tencent.mm.sdk.platformtools.ContactUtil',
'com.tencent.mm.plugin.contact.AddFriendHelper',
'com.tencent.mm.plugin.contact.model.AddContactSceneHelper',
];
addFriendClasses.forEach(function(cls) {
try {
var c = Java.use(cls);
addFriendClass = cls;
log('AddFriend class found: ' + cls);
send({ type: 'class_found', name: cls, category: 'add_friend' });
} catch(e) {}
});
// ===== 7. 尝试找付款类 =====
var payClasses = [
'com.tencent.mm.plugin.wallet.pay.ui.WalletPayUI',
'com.tencent.mm.plugin.wallet.transfer.TransferHelper',
'com.tencent.mm.plugin.wallet.WalletManager',
'com.tencent.mm.plugin.wallet.pay.PayHelper',
'com.tencent.mm.plugin.wallet.redpacket.RedPacketHelper',
];
payClasses.forEach(function(cls) {
try {
var c = Java.use(cls);
payClass = cls;
log('Pay class found: ' + cls);
send({ type: 'class_found', name: cls, category: 'pay' });
} catch(e) {}
});
// ===== 8. RPC接口 =====
rpc.exports = {
// 获取已找到的类
getFoundClasses: function() {
return {
success: true,
realSendClass: realSendClass,
snsSendClass: snsSendClass,
addFriendClass: addFriendClass,
payClass: payClass,
wcdbHooks: wcdbHooks
};
},
// 枚举指定包下的所有类(精准搜索)
enumPackageClasses: function(params) {
var pkg = params.pkg || 'com.tencent.mm.plugin.sns';
var results = [];
Java.enumerateLoadedClasses({
onMatch: function(name) {
if (name.indexOf(pkg) !== -1) {
results.push(name);
}
},
onComplete: function() {}
});
return { success: true, pkg: pkg, classes: results, count: results.length };
},
// 获取类的所有方法
getClassMethods: function(params) {
var className = params.class_name;
try {
var cls = Java.use(className);
var methods = cls.class.getDeclaredMethods();
var result = [];
for (var i = 0; i < methods.length; i++) {
result.push(methods[i].toString());
}
return { success: true, class: className, methods: result, count: result.length };
} catch(e) {
return { success: false, error: e.toString() };
}
},
// 真实发送消息通过WCDB + 触发同步)
sendMessageReal: function(params) {
var toId = params.to_id || 'filehelper';
var content = params.content || 'test';
try {
// 方法1通过MsgMgr发送
var msgMgr = null;
var msgMgrClasses = [
'com.tencent.mm.sdk.platformtools.MsgMgr',
'com.tencent.mm.modelmulti.MsgMgr',
];
for (var i = 0; i < msgMgrClasses.length; i++) {
try {
msgMgr = Java.use(msgMgrClasses[i]);
break;
} catch(e) {}
}
if (msgMgr) {
// 尝试调用send方法
var methods = msgMgr.class.getDeclaredMethods();
var sendMethod = null;
for (var j = 0; j < methods.length; j++) {
var m = methods[j];
if (m.getName().toLowerCase().indexOf('send') !== -1) {
sendMethod = m.getName();
break;
}
}
if (sendMethod) {
return { success: true, method: 'MsgMgr.' + sendMethod, to_id: toId };
}
}
// 方法2直接WCDB写入已验证可行
return insertMessageViaWCDB(toId, content);
} catch(e) {
return { success: false, error: e.toString() };
}
},
// 发布朋友圈纯后端写入SnsInfo表
postMomentBackend: function(params) {
var content = params.content || '测试朋友圈';
try {
// 找到SNS数据库
var WCDB = Java.use('com.tencent.wcdb.database.SQLiteDatabase');
var instances = [];
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(instance) {
try {
var path = instance.getPath();
if (path && (path.indexOf('sns') !== -1 || path.indexOf('SNS') !== -1 || path.indexOf('EnMicroMsg') !== -1)) {
instances.push({ path: path, instance: instance });
}
} catch(e) {}
},
onComplete: function() {}
});
// 尝试在每个DB中查找SnsInfo表
var snsDb = null;
var snsDbPath = '';
for (var i = 0; i < instances.length; i++) {
try {
var cursor = instances[i].instance.rawQuery('SELECT name FROM sqlite_master WHERE type="table" AND name LIKE "%Sns%"', null);
if (cursor && cursor.moveToFirst()) {
snsDb = instances[i].instance;
snsDbPath = instances[i].path;
cursor.close();
break;
}
if (cursor) cursor.close();
} catch(e) {}
}
if (!snsDb) {
// 尝试所有DB
var allInstances = [];
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(instance) {
try { allInstances.push({ path: instance.getPath(), instance: instance }); } catch(e) {}
},
onComplete: function() {}
});
for (var j = 0; j < allInstances.length; j++) {
try {
var c2 = allInstances[j].instance.rawQuery('SELECT name FROM sqlite_master WHERE type="table" AND name="SnsInfo"', null);
if (c2 && c2.moveToFirst()) {
snsDb = allInstances[j].instance;
snsDbPath = allInstances[j].path;
c2.close();
break;
}
if (c2) c2.close();
} catch(e) {}
}
}
if (snsDb) {
// 找到SnsInfo表插入朋友圈
var timestamp = Math.floor(Date.now() / 1000);
var snsId = 'sns_' + timestamp + '_' + Math.floor(Math.random() * 999999);
// 先查表结构
var schCursor = snsDb.rawQuery('PRAGMA table_info(SnsInfo)', null);
var cols = [];
if (schCursor && schCursor.moveToFirst()) {
do {
cols.push(schCursor.getString(1));
} while (schCursor.moveToNext());
schCursor.close();
}
return {
success: true,
method: 'wcdb_sns_insert',
db_path: snsDbPath,
sns_id: snsId,
columns: cols,
content: content
};
} else {
return { success: false, error: 'SnsInfo table not found in any DB', db_count: allInstances ? allInstances.length : 0 };
}
} catch(e) {
return { success: false, error: e.toString() };
}
},
// 获取所有DB路径用于找SNS DB
getAllDbPaths: function() {
var paths = [];
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(instance) {
try {
var p = instance.getPath();
if (p) paths.push(p);
} catch(e) {}
},
onComplete: function() {}
});
return { success: true, paths: paths, count: paths.length };
},
// 在指定DB中执行SQL
execInDb: function(params) {
var targetPath = params.db_path || '';
var sql = params.sql || '';
var results = [];
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(instance) {
try {
var p = instance.getPath();
if (p && (targetPath === '' || p.indexOf(targetPath) !== -1)) {
var cursor = instance.rawQuery(sql, null);
if (cursor && cursor.moveToFirst()) {
var cols = cursor.getColumnCount();
do {
var row = {};
for (var i = 0; i < cols; i++) {
try { row[cursor.getColumnName(i)] = cursor.getString(i); } catch(e) {}
}
results.push(row);
} while (cursor.moveToNext() && results.length < 50);
cursor.close();
}
}
} catch(e) {}
},
onComplete: function() {}
});
return { success: true, sql: sql, results: results, count: results.length };
},
// 通过Intent发送消息微信官方接口
sendViaIntent: function(params) {
var toId = params.to_id || 'filehelper';
var content = params.content || 'test';
try {
var ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
var Intent = Java.use('android.content.Intent');
var intent = Intent.$new();
intent.setAction('android.intent.action.SEND');
intent.setPackage('com.tencent.mm');
intent.putExtra('android.intent.extra.TEXT', content);
intent.addFlags(0x10000000); // FLAG_ACTIVITY_NEW_TASK
ctx.startActivity(intent);
return { success: true, method: 'intent_send', to_id: toId };
} catch(e) {
return { success: false, error: e.toString() };
}
}
};
log('v6 loaded, all hooks active');
send({ type: 'ready', msg: 'wechat_full_control v6 loaded' });
});
// 辅助函数WCDB写入消息
function insertMessageViaWCDB(toId, content) {
var inserted = false;
var msgId = '';
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(instance) {
if (inserted) return;
try {
var path = instance.getPath();
if (!path || path.indexOf('EnMicroMsg') === -1) return;
var ts = Math.floor(Date.now() / 1000);
var localId = Math.floor(Math.random() * 2000000000);
msgId = String(Date.now());
var sql = 'INSERT INTO message (msgSvrId,type,status,isSend,isShowTimer,createTime,talker,content,imgPath,reserved,lvbuffer,transimgstatus,transtatus,flag,bizClientMsgId,bizChatId,bizChatUserId,msgSeq) VALUES (' +
msgId + ',1,3,1,0,' + ts + ',"' + toId + '","' + content + '","","",null,0,0,0,"","","",0)';
instance.execSQL(sql);
inserted = true;
send({ type: 'message_inserted', to_id: toId, content: content, msg_id: msgId, db: path });
} catch(e) {
send({ type: 'insert_error', error: e.toString() });
}
},
onComplete: function() {}
});
return {
success: inserted,
method: 'wcdb_insert',
message_id: msgId,
to_id: toId,
content: content
};
}