wechat_hook.js 3.44 KB
/*
 * WeChat macOS SQLCipher key interceptor
 * Hook sqlite3_key / sqlite3_key_v2 in all loaded modules
 */

var found_keys = {};

function hookSqliteKey(moduleName, exports) {
    var key_funcs = ['sqlite3_key', 'sqlite3_key_v2'];
    key_funcs.forEach(function(fname) {
        var sym = exports.find(function(e) { return e.name === fname; });
        if (!sym) return;

        Interceptor.attach(sym.address, {
            onEnter: function(args) {
                try {
                    var db = args[0];
                    if (fname === 'sqlite3_key') {
                        var pKey = args[1];
                        var nKey = args[2].toInt32();
                        if (nKey > 0 && nKey <= 128) {
                            var key = pKey.readByteArray(nKey);
                            var keyHex = Array.from(new Uint8Array(key))
                                .map(function(b) { return ('0' + b.toString(16)).slice(-2); })
                                .join('');
                            if (!found_keys[keyHex]) {
                                found_keys[keyHex] = true;
                                send({type: 'key', func: fname, module: moduleName, key_hex: keyHex, key_len: nKey});
                            }
                        }
                    } else {
                        // sqlite3_key_v2(db, zDbName, pKey, nKey)
                        var pKey = args[2];
                        var nKey = args[3].toInt32();
                        if (nKey > 0 && nKey <= 128) {
                            var key = pKey.readByteArray(nKey);
                            var keyHex = Array.from(new Uint8Array(key))
                                .map(function(b) { return ('0' + b.toString(16)).slice(-2); })
                                .join('');
                            if (!found_keys[keyHex]) {
                                found_keys[keyHex] = true;
                                send({type: 'key', func: fname, module: moduleName, key_hex: keyHex, key_len: nKey});
                            }
                        }
                    }
                } catch(e) {
                    send({type: 'error', msg: e.toString()});
                }
            }
        });
        send({type: 'hooked', func: fname, module: moduleName, addr: sym.address.toString()});
    });
}

// 扫描所有已加载模块
Process.enumerateModules().forEach(function(mod) {
    try {
        var exports = mod.enumerateExports();
        var hasKey = exports.some(function(e) {
            return e.name === 'sqlite3_key' || e.name === 'sqlite3_key_v2';
        });
        if (hasKey) {
            hookSqliteKey(mod.name, exports);
        }
    } catch(e) {}
});

// 也 hook Module.load 以捕获之后加载的动态库
var dlopen_ptr = Module.findExportByName(null, 'dlopen');
if (dlopen_ptr) {
    Interceptor.attach(dlopen_ptr, {
        onLeave: function(retval) {
            try {
                Process.enumerateModules().forEach(function(mod) {
                    try {
                        var exports = mod.enumerateExports();
                        var hasKey = exports.some(function(e) {
                            return e.name === 'sqlite3_key' || e.name === 'sqlite3_key_v2';
                        });
                        if (hasKey) hookSqliteKey(mod.name, exports);
                    } catch(e) {}
                });
            } catch(e) {}
        }
    });
}

send({type: 'ready', msg: 'WeChat key interceptor active'});