feat: 完整Frida控制脚本v3 sdk/agent/hook/wechat_class_finder.js

This commit is contained in:
2026-05-18 20:37:41 +08:00
parent 5f120b49de
commit 2f1fc4ebc4

View File

@@ -0,0 +1,270 @@
/**
* 微信8.0.56 类名发现脚本
* 通过ClassLoader枚举找到真实类名
*/
'use strict';
function getWechatLoader() {
var wechatLoader = null;
Java.enumerateClassLoaders({
onMatch: function(loader) {
if (wechatLoader) return;
try {
loader.loadClass('com.tencent.mm.app.Application');
wechatLoader = loader;
} catch(e) {}
},
onComplete: function() {}
});
return wechatLoader;
}
rpc.exports = {
// 获取ChattingUIFragment所有方法
getChattingMethods: function() {
return Java.performNow(function() {
var loader = getWechatLoader();
if (!loader) return { error: 'no loader' };
try {
var cls = loader.loadClass('com.tencent.mm.ui.chatting.ChattingUIFragment');
var methods = cls.getDeclaredMethods();
var result = [];
for (var i = 0; i < methods.length; i++) {
var m = methods[i];
var params = m.getParameterTypes().map(function(p) { return p.getName(); });
result.push({
name: m.getName(),
params: params,
ret: m.getReturnType().getName()
});
}
return { success: true, count: result.length, methods: result };
} catch(e) {
return { success: false, error: String(e) };
}
});
},
// 搜索双字母类名
findDoubleLetterClasses: function() {
return Java.performNow(function() {
var loader = getWechatLoader();
if (!loader) return { error: 'no loader' };
var letters = 'abcdefghijklmnopqrstuvwxyz';
var found = [];
var prefixes = [
'com.tencent.mm.modelmulti.',
'com.tencent.mm.plugin.messenger.foundation.a.',
'com.tencent.mm.plugin.messenger.foundation.b.',
'com.tencent.mm.plugin.messenger.foundation.c.',
];
for (var p = 0; p < prefixes.length; p++) {
for (var i = 0; i < letters.length; i++) {
for (var j = 0; j < letters.length; j++) {
var clsName = prefixes[p] + letters[i] + letters[j];
try {
var cls = loader.loadClass(clsName);
var methods = cls.getDeclaredMethods();
var mNames = [];
for (var k = 0; k < methods.length; k++) {
var params = methods[k].getParameterTypes().map(function(t) { return t.getName(); });
mNames.push(methods[k].getName() + '(' + params.join(',') + ')');
}
found.push({ cls: clsName, methods: mNames });
send({ type: 'found', cls: clsName, methods: mNames });
} catch(e) {}
}
}
}
return { success: true, count: found.length, found: found };
});
},
// Hook SQLite insert监听消息写入
hookMessageInsert: function() {
try {
var WCDB = Java.use('com.tencent.wcdb.database.SQLiteDatabase');
WCDB.insert.overload(
'java.lang.String',
'java.lang.String',
'android.content.ContentValues'
).implementation = function(table, nullCol, values) {
var result = this.insert(table, nullCol, values);
if (table === 'message') {
try {
var isSend = values.getAsInteger('isSend');
if (isSend && parseInt(isSend.toString()) === 1) {
var content = values.getAsString('content');
var talker = values.getAsString('talker');
// 捕获调用栈
var Exception = Java.use('java.lang.Exception');
var ex = Exception.$new('stack capture');
var stack = ex.getStackTrace();
var stackInfo = [];
for (var i = 0; i < Math.min(stack.length, 30); i++) {
var frame = stack[i];
var cn = frame.getClassName();
if (cn.indexOf('com.tencent.mm') !== -1) {
stackInfo.push(cn + '.' + frame.getMethodName() + ':' + frame.getLineNumber());
}
}
send({
type: 'message_sent_captured',
talker: talker,
content: content ? content.substring(0, 80) : '',
stack: stackInfo
});
}
} catch(e2) {}
}
return result;
};
return { success: true, msg: 'WCDB insert hooked' };
} catch(e) {
return { success: false, error: String(e) };
}
},
// 通过反射找到DB实例并获取密钥
findDBInstance: function() {
return Java.performNow(function() {
var loader = getWechatLoader();
if (!loader) return { error: 'no loader' };
// 尝试找到MicroMsgDBHelper
var helperCandidates = [
'com.tencent.mm.storage.MicroMsgDBHelper',
'com.tencent.mm.storage.DatabaseHelper',
'com.tencent.mm.storage.MicroMsgDB',
'com.tencent.mm.storage.db.MicroMsgDB',
];
var found = [];
for (var i = 0; i < helperCandidates.length; i++) {
try {
var cls = loader.loadClass(helperCandidates[i]);
var methods = cls.getDeclaredMethods();
var mNames = [];
for (var j = 0; j < methods.length; j++) {
mNames.push(methods[j].getName());
}
found.push({ cls: helperCandidates[i], methods: mNames.slice(0, 10) });
} catch(e) {}
}
return { success: true, found: found };
});
},
// 通过WCDB直接操作DB用已打开的DB连接
queryViaWCDB: function(sql) {
return Java.performNow(function() {
try {
// 获取已打开的DB实例通过Application的静态字段
var WCDB = Java.use('com.tencent.wcdb.database.SQLiteDatabase');
// 找到所有WCDB实例
var instances = [];
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(instance) {
try {
var path = instance.getPath();
instances.push({ path: path, open: instance.isOpen() });
} catch(e) {}
},
onComplete: function() {}
});
return { success: true, instances: instances, count: instances.length };
} catch(e) {
return { success: false, error: String(e) };
}
});
},
// 通过Java.choose找到已打开的DB并执行查询
executeOnOpenDB: function(sql) {
return Java.performNow(function() {
try {
var results = [];
var executed = false;
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(db) {
if (executed) return;
try {
var path = db.getPath();
if (path && path.indexOf('EnMicroMsg') !== -1 && db.isOpen()) {
// 执行查询
var cursor = db.rawQuery(sql, null);
if (cursor) {
var cols = cursor.getColumnNames();
while (cursor.moveToNext()) {
var row = {};
for (var i = 0; i < cols.length; i++) {
try { row[cols[i]] = cursor.getString(i); } catch(e) { row[cols[i]] = null; }
}
results.push(row);
}
cursor.close();
executed = true;
send({ type: 'db_query_ok', path: path, rows: results.length });
}
}
} catch(e) {
send({ type: 'db_query_err', error: String(e).substring(0, 100) });
}
},
onComplete: function() {}
});
return { success: executed, results: results, count: results.length };
} catch(e) {
return { success: false, error: String(e) };
}
});
},
// 通过Java.choose找到DB并INSERT消息
insertViaOpenDB: function(params) {
return Java.performNow(function() {
var toId = params.to_id;
var content = params.content;
try {
var inserted = false;
var dbPath = '';
Java.choose('com.tencent.wcdb.database.SQLiteDatabase', {
onMatch: function(db) {
if (inserted) return;
try {
var path = db.getPath();
if (path && path.indexOf('EnMicroMsg') !== -1 && db.isOpen()) {
dbPath = path;
var ContentValues = Java.use('android.content.ContentValues');
var cv = ContentValues.$new();
var now = Date.now();
cv.put('msgId', Java.use('java.lang.Long').$new(now));
cv.put('type', Java.use('java.lang.Integer').$new(1));
cv.put('isSend', Java.use('java.lang.Integer').$new(1));
cv.put('talker', toId);
cv.put('content', content);
cv.put('createTime', Java.use('java.lang.Long').$new(now));
cv.put('status', Java.use('java.lang.Integer').$new(2));
cv.put('imgPath', '');
var rowId = db.insert('message', null, cv);
if (rowId > 0) {
inserted = true;
send({ type: 'message_inserted', row_id: rowId.toString(), path: path });
}
}
} catch(e) {
send({ type: 'insert_err', error: String(e).substring(0, 150) });
}
},
onComplete: function() {}
});
return { success: inserted, db_path: dbPath, method: 'wcdb_direct_insert' };
} catch(e) {
return { success: false, error: String(e) };
}
});
}
};
Java.perform(function() {
send({ type: 'ready', msg: 'wechat_class_finder loaded' });
});