271 lines
12 KiB
JavaScript
271 lines
12 KiB
JavaScript
/**
|
||
* 微信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' });
|
||
});
|