应用安全 --- 安卓安全 之 恋人精灵高级版hook脚本
/*** Frida综合Hook脚本 - 字符串比较绕过 + Lua解密监控* 功能1: 强制sub_7F9EF字符串比较函数返回1 (优先执行)* 功能2: 监控sub_13860A函数的LuaState结构体和Lua字节码解密* 目标进程: com.test.mlgm:sc* 执行顺序: 先绕过字符串验证,再监控Lua解密过程*/console.log("[+] ========================================"); console.log("[+] 综合Hook脚本启动"); console.log("[+] 功能: 字符串绕过 + Lua解密监控"); console.log("[+] ========================================");// ==================== 全局配置 ==================== const GLOBAL_CONFIG = {// 模块配置 TARGET_MODULE_NAMES: ["libengine.so","libnative.so", "libengine_exported_functions.so"],// 函数配置 STRING_COMPARE_FUNCTION: {name: "sub_7F9EF",offset: 0x7F9EF,description: "字符串比较函数"},LUA_DECRYPT_FUNCTION: {name: "sub_13860A", offset: 0x13860A,description: "Lua解密函数"},// 日志配置 LOGGING: {enableDetailedStringLog: false, // 减少字符串hook的详细日志enableDetailedLuaLog: true, // 启用Lua详细日志enableHexDump: true, // 启用hex dumpmaxDumpSize: 500 // 最大dump大小 },// 安全配置 SAFETY: {maxStringReadLength: 32, // 字符串读取最大长度maxMemoryDumpSize: 1000, // 内存dump最大大小enableSafeMemoryAccess: true // 启用安全内存访问 } };// ==================== 全局状态管理 ==================== const GLOBAL_STATE = {targetModule: null,stringHookInstalled: false,luaHookInstalled: false,hookStats: {stringCompareCalls: 0,luaDecryptCalls: 0,startTime: Date.now()} };// ==================== 通用工具函数 ====================// 查找目标模块 function findTargetModule() {console.log("[+] 正在查找目标模块...");for (const moduleName of GLOBAL_CONFIG.TARGET_MODULE_NAMES) {const module = Process.findModuleByName(moduleName);if (module) {console.log(`[+] 找到目标模块: ${moduleName}`);console.log(`[+] 模块基址: ${module.base}`);console.log(`[+] 模块大小: 0x${module.size.toString(16)}`);return module;}}console.log("[!] 未找到任何目标模块,尝试的模块名:");GLOBAL_CONFIG.TARGET_MODULE_NAMES.forEach(name => console.log(`[!] - ${name}`));// 列出相关模块console.log("[+] 当前已加载的相关模块:");Process.enumerateModules().forEach(mod => {if (mod.name.toLowerCase().includes('engine') || mod.name.toLowerCase().includes('native') ||mod.name.toLowerCase().includes('lib')) {console.log(`[+] - ${mod.name} (${mod.base})`);}});return null; }// 等待模块加载 function waitForModule() {return new Promise((resolve) => {const checkModule = () => {const module = findTargetModule();if (module) {resolve(module);} else {setTimeout(checkModule, 500);}};checkModule();}); }// 安全内存读取函数 function safeReadMemory(address, size, description) {try {if (!address || address.isNull()) {if (GLOBAL_CONFIG.LOGGING.enableDetailedLuaLog) {console.log(`[!] ${description}: 地址为NULL`);}return null;}return Memory.readByteArray(address, size);} catch (e) {if (GLOBAL_CONFIG.LOGGING.enableDetailedLuaLog) {console.log(`[!] ${description}: 内存读取失败 - ${e.message}`);}return null;} }function safeReadPointer(address, description) {try {if (!address || address.isNull()) {return ptr(0);}return address.readPointer();} catch (e) {if (GLOBAL_CONFIG.LOGGING.enableDetailedLuaLog) {console.log(`[!] ${description}: 指针读取失败 - ${e.message}`);}return ptr(0);} }function safeReadU32(address, description) {try {if (!address || address.isNull()) {return 0;}return address.readU32();} catch (e) {if (GLOBAL_CONFIG.LOGGING.enableDetailedLuaLog) {console.log(`[!] ${description}: U32读取失败 - ${e.message}`);}return 0;} }function safeHexdump(address, size, description) {if (!GLOBAL_CONFIG.LOGGING.enableHexDump) return;try {if (!address || address.isNull()) {console.log(`[!] ${description}: 地址为NULL,无法进行hexdump`);return;}console.log(`[+] ${description} hexdump:`);console.log(hexdump(address, {offset: 0,length: Math.min(size, GLOBAL_CONFIG.SAFETY.maxMemoryDumpSize),header: true,ansi: true}));} catch (e) {console.log(`[!] ${description}: hexdump失败 - ${e.message}`);} }// ==================== 字符串比较Hook (优先级1) ==================== function installStringCompareHook(module) {try {const functionOffset = GLOBAL_CONFIG.STRING_COMPARE_FUNCTION.offset;const functionAddress = module.base.add(functionOffset);console.log(`[+] 安装字符串比较Hook: ${GLOBAL_CONFIG.STRING_COMPARE_FUNCTION.name}`);console.log(`[+] Hook地址: ${functionAddress} (偏移: 0x${functionOffset.toString(16)})`);Interceptor.attach(functionAddress, {onEnter: function(args) {GLOBAL_STATE.hookStats.stringCompareCalls++;// 保存参数this.str1 = args[0];this.str2 = args[1];if (GLOBAL_CONFIG.LOGGING.enableDetailedStringLog) {console.log(`[STR] ${GLOBAL_CONFIG.STRING_COMPARE_FUNCTION.name} 调用 #${GLOBAL_STATE.hookStats.stringCompareCalls}`);console.log(`[STR] 参数1: ${this.str1}, 参数2: ${this.str2}`);// 获取调用者信息(简化版)try {const callerAddress = this.returnAddress;const callerModule = Process.findModuleByAddress(callerAddress);if (callerModule) {const offset = callerAddress.sub(callerModule.base);console.log(`[STR] 调用者: ${callerModule.name}+0x${offset.toString(16)}`);}} catch (e) {// 忽略调用者信息获取错误 }// 尝试读取字符串内容(简化版)const readSimpleString = (strPtr, label) => {try {if (!strPtr || strPtr.isNull()) return;const firstByte = strPtr.readU8();const isLongString = firstByte & 1;let dataPtr = isLongString ? strPtr.add(8).readPointer() : strPtr.add(1);let content = dataPtr.readCString(16) || "无法读取";console.log(`[STR] ${label}: "${content}" (${isLongString ? '长' : '短'}字符串)`);} catch (e) {console.log(`[STR] ${label}: 读取失败`);}};readSimpleString(this.str1, "字符串1");readSimpleString(this.str2, "字符串2");}},onLeave: function(retval) {const originalReturn = retval.toInt32();// 强制返回1retval.replace(ptr(1));if (GLOBAL_CONFIG.LOGGING.enableDetailedStringLog) {console.log(`[STR] 原始返回值: ${originalReturn} -> 强制返回值: 1`);} else {// 简化日志:只在返回值不为1时输出if (originalReturn !== 1) {console.log(`[STR] 字符串比较被绕过 (${originalReturn} -> 1) [调用#${GLOBAL_STATE.hookStats.stringCompareCalls}]`);}}}});GLOBAL_STATE.stringHookInstalled = true;console.log(`[+] 字符串比较Hook安装成功!`);return true;} catch (error) {console.log(`[!] 字符串比较Hook安装失败: ${error.message}`);return false;} }// ==================== LuaState结构体定义 ==================== const LuaStateStruct = {PADDING_OFFSET: 0x00,BYTECODE_PTR_OFFSET: 0x1C,BYTECODE_SIZE_OFFSET: 0x20,CURRENT_EXEC_POS_OFFSET: 0x24,PADDING2_OFFSET: 0x28,INIT_FLAG_OFFSET: 0x2C,SCRIPT_START_PTR_OFFSET: 0x30,TOTAL_SCRIPT_SIZE_OFFSET: 0x34 };// ==================== Lua解密Hook (优先级2) ==================== function parseLuaState(luaStatePtr, paramName, callNumber) {if (!GLOBAL_CONFIG.LOGGING.enableDetailedLuaLog) return;console.log(`\n[LUA] ========== 解析${paramName} LuaState结构体 (调用#${callNumber}) ==========`);console.log(`[LUA] LuaState地址: ${luaStatePtr}`);if (luaStatePtr.isNull()) {console.log(`[LUA] ${paramName} LuaState指针为NULL`);return;}try {// 读取结构体各字段const bytecodePtr = safeReadPointer(luaStatePtr.add(LuaStateStruct.BYTECODE_PTR_OFFSET), "字节码指针");const bytecodeSize = safeReadU32(luaStatePtr.add(LuaStateStruct.BYTECODE_SIZE_OFFSET), "字节码大小");const currentExecPos = safeReadPointer(luaStatePtr.add(LuaStateStruct.CURRENT_EXEC_POS_OFFSET), "当前执行位置");const initFlag = safeReadU32(luaStatePtr.add(LuaStateStruct.INIT_FLAG_OFFSET), "初始化标志");const scriptStartPtr = safeReadPointer(luaStatePtr.add(LuaStateStruct.SCRIPT_START_PTR_OFFSET), "脚本开始指针");const totalScriptSize = safeReadU32(luaStatePtr.add(LuaStateStruct.TOTAL_SCRIPT_SIZE_OFFSET), "脚本总大小");console.log(`[LUA] 字节码指针 (+0x1C): ${bytecodePtr}`);console.log(`[LUA] 字节码大小 (+0x20): ${bytecodeSize} bytes`);console.log(`[LUA] 当前执行位置 (+0x24): ${currentExecPos}`);console.log(`[LUA] 初始化标志 (+0x2C): 0x${initFlag.toString(16)}`);console.log(`[LUA] 脚本开始指针 (+0x30): ${scriptStartPtr}`);console.log(`[LUA] 脚本总大小 (+0x34): ${totalScriptSize} bytes`);// 输出LuaState结构体的内存dump console.log(`\n[LUA] ${paramName} LuaState结构体内存dump:`);safeHexdump(luaStatePtr, GLOBAL_CONFIG.LOGGING.maxDumpSize, `${paramName} LuaState结构体`);// 输出字节码内容if (!bytecodePtr.isNull() && bytecodeSize > 0 && bytecodeSize < 10000) {const dumpSize = Math.min(bytecodeSize, GLOBAL_CONFIG.LOGGING.maxDumpSize);console.log(`\n[LUA] ${paramName} Lua字节码内容 (前${dumpSize}字节):`);safeHexdump(bytecodePtr, dumpSize, `${paramName} Lua字节码`);// 尝试识别Lua字节码头部try {const header = bytecodePtr.readByteArray(12);if (header) {const headerBytes = new Uint8Array(header);const headerHex = Array.from(headerBytes).map(b => b.toString(16).padStart(2, '0')).join(' ');console.log(`[LUA] 字节码头部: ${headerHex}`);// 检查Lua签名if (headerBytes[0] === 0x1B && headerBytes[1] === 0x4C && headerBytes[2] === 0x75 && headerBytes[3] === 0x61) {console.log(`[LUA] ✓ 检测到标准Lua字节码签名`);} else {console.log(`[LUA] ⚠ 非标准Lua字节码或已加密`);}}} catch (e) {console.log(`[LUA] 字节码头部分析失败: ${e.message}`);}}// 输出脚本内容if (!scriptStartPtr.isNull() && totalScriptSize > 0 && totalScriptSize < 10000) {const dumpSize = Math.min(totalScriptSize, GLOBAL_CONFIG.LOGGING.maxDumpSize);console.log(`\n[LUA] ${paramName} 脚本内容 (前${dumpSize}字节):`);safeHexdump(scriptStartPtr, dumpSize, `${paramName} 脚本内容`);}} catch (e) {console.log(`[LUA] 解析${paramName} LuaState结构体时发生错误: ${e.message}`);} }function installLuaDecryptHook(module) {try {const functionOffset = GLOBAL_CONFIG.LUA_DECRYPT_FUNCTION.offset;const functionAddress = module.base.add(functionOffset);console.log(`[+] 安装Lua解密Hook: ${GLOBAL_CONFIG.LUA_DECRYPT_FUNCTION.name}`);console.log(`[+] Hook地址: ${functionAddress} (偏移: 0x${functionOffset.toString(16)})`);Interceptor.attach(functionAddress, {onEnter: function(args) {GLOBAL_STATE.hookStats.luaDecryptCalls++;console.log(`\n[LUA] ==================== ${GLOBAL_CONFIG.LUA_DECRYPT_FUNCTION.name} 函数调用开始 ====================`);console.log(`[LUA] 调用次数: #${GLOBAL_STATE.hookStats.luaDecryptCalls}`);console.log(`[LUA] 调用时间: ${new Date().toISOString()}`);console.log(`[LUA] 线程ID: ${Process.getCurrentThreadId()}`);// __fastcall约定:ECX=第一个参数,EDX=第二个参数const param1 = this.context.ecx; // LuaState指针const param2 = this.context.edx; // 第二个参数 console.log(`[LUA] 参数1 (ECX - LuaState*): ${param1}`);console.log(`[LUA] 参数2 (EDX): ${param2}`);// 保存参数this.param1 = param1;this.param2 = param2;this.startTime = Date.now();// 解析LuaState结构体if (!param1.isNull()) {parseLuaState(param1, "输入参数", GLOBAL_STATE.hookStats.luaDecryptCalls);}// 输出寄存器状态(简化版)if (GLOBAL_CONFIG.LOGGING.enableDetailedLuaLog) {console.log(`\n[LUA] 关键寄存器状态:`);console.log(`[LUA] EAX: ${this.context.eax}`);console.log(`[LUA] ECX: ${this.context.ecx} (LuaState*)`);console.log(`[LUA] EDX: ${this.context.edx} (参数2)`);console.log(`[LUA] ESP: ${this.context.esp}`);}},onLeave: function(retval) {const endTime = Date.now();const duration = endTime - this.startTime;console.log(`\n[LUA] ==================== ${GLOBAL_CONFIG.LUA_DECRYPT_FUNCTION.name} 函数调用结束 ====================`);console.log(`[LUA] 返回时间: ${new Date().toISOString()}`);console.log(`[LUA] 执行耗时: ${duration}ms`);console.log(`[LUA] 返回值 (EAX): ${retval}`);// 再次检查LuaState结构体(可能已被修改)if (!this.param1.isNull()) {parseLuaState(this.param1, "返回时参数", GLOBAL_STATE.hookStats.luaDecryptCalls);}console.log(`[LUA] ==================== Hook结束 ====================\n`);}});GLOBAL_STATE.luaHookInstalled = true;console.log(`[+] Lua解密Hook安装成功!`);return true;} catch (error) {console.log(`[!] Lua解密Hook安装失败: ${error.message}`);return false;} }// ==================== 状态监控和统计 ==================== function printHookStatus() {const runtime = Date.now() - GLOBAL_STATE.hookStats.startTime;const runtimeMinutes = Math.floor(runtime / 60000);const runtimeSeconds = Math.floor((runtime % 60000) / 1000);console.log(`\n[+] ========== Hook状态报告 ==========`);console.log(`[+] 运行时间: ${runtimeMinutes}分${runtimeSeconds}秒`);console.log(`[+] 字符串比较Hook: ${GLOBAL_STATE.stringHookInstalled ? '✓ 已安装' : '✗ 未安装'}`);console.log(`[+] Lua解密Hook: ${GLOBAL_STATE.luaHookInstalled ? '✓ 已安装' : '✗ 未安装'}`);console.log(`[+] 字符串比较调用次数: ${GLOBAL_STATE.hookStats.stringCompareCalls}`);console.log(`[+] Lua解密调用次数: ${GLOBAL_STATE.hookStats.luaDecryptCalls}`);console.log(`[+] =====================================\n`); }// 定期输出状态报告 setInterval(printHookStatus, 30000); // 每30秒输出一次状态// ==================== 主执行逻辑 ====================async function main() {try {console.log("[+] 等待目标模块加载...");const module = await waitForModule();if (!module) {console.log("[!] 未找到目标模块,脚本退出");return;}GLOBAL_STATE.targetModule = module;console.log(`[+] 目标模块加载完成: ${module.name}`);// 优先级1: 安装字符串比较Hook (绕过验证)console.log("\n[+] ========== 第一阶段: 安装字符串比较Hook ==========");const stringHookSuccess = installStringCompareHook(module);if (stringHookSuccess) {console.log("[+] ✓ 字符串比较Hook安装成功,验证绕过已激活");} else {console.log("[!] ✗ 字符串比较Hook安装失败,可能影响后续功能");}// 短暂延迟,确保字符串Hook生效await new Promise(resolve => setTimeout(resolve, 1000));// 优先级2: 安装Lua解密Hook (监控解密过程)console.log("\n[+] ========== 第二阶段: 安装Lua解密Hook ==========");const luaHookSuccess = installLuaDecryptHook(module);if (luaHookSuccess) {console.log("[+] ✓ Lua解密Hook安装成功,开始监控解密过程");} else {console.log("[!] ✗ Lua解密Hook安装失败");}// 最终状态报告console.log("\n[+] ========================================");console.log("[+] 综合Hook脚本安装完成!");console.log(`[+] 字符串比较绕过: ${stringHookSuccess ? '✓ 激活' : '✗ 失败'}`);console.log(`[+] Lua解密监控: ${luaHookSuccess ? '✓ 激活' : '✗ 失败'}`);console.log("[+] 脚本正在运行,等待目标函数调用...");console.log("[+] ========================================");// 输出首次状态报告setTimeout(printHookStatus, 5000);} catch (error) {console.log(`[!] 主执行流程出错: ${error.message}`);console.log(`[!] 错误堆栈: ${error.stack}`);} }// ==================== 异常处理和清理 ====================// 进程异常处理 Process.setExceptionHandler(function(details) {console.log(`[!] 进程异常捕获: ${JSON.stringify(details, null, 2)}`);console.log(`[!] 异常发生时Hook状态:`);printHookStatus();return true; // 继续执行 });// 脚本退出处理 function onScriptExit() {console.log("\n[+] ========== 脚本退出清理 ==========");printHookStatus();console.log("[+] 综合Hook脚本已退出");console.log("[+] ==================================="); }// 注册退出处理 if (typeof Script !== 'undefined' && Script.setGlobalAccessHandler) {Script.setGlobalAccessHandler({enumerate: function() { return []; },get: function(property) { return undefined; },set: function(property, value) { return false; }}); }// ==================== 启动脚本 ==================== console.log("[+] 综合Hook脚本初始化完成,开始执行..."); main().catch(error => {console.log(`[!] 脚本启动失败: ${error.message}`); });// 脚本加载完成提示 console.log("[+] 综合Hook脚本加载完成,等待目标模块和函数调用...");
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/942094.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!