


本文档内容仅用于网络安全技术学习、安全研究、合规渗透测试等合法教学场景。
文中所涉及的APP逆向、脱壳、调试分析等技术操作,均为个人技术研究记录,仅用于安全防御学习与技术交流。
本人严格遵守《网络安全法》及相关法律法规,严禁将本文档内容用于非法逆向、破解、篡改、侵权等一切违规违法用途。
若任何人利用本文档内容进行非合规操作,所产生的一切法律后果、风险与作者无关,均由操作者自行承担全部责任。
请勿用于商业用途、非法牟利、恶意攻击等违规场景,一切技术仅供合规安全学习使用。
使用Jadx对目标APP进行初步反编译分析

加载程序壳文件后,可明确判定该APP搭载***SO壳

尝试直接通过Frida附加进程调试,程序立即闪退。
程序内置完整的Frida检测机制,常规附加调试方式无法正常使用。

本次分析针对程序核心的两个SO文件进行内存Dump操作
const so = Process.findModuleByName("libexec.so");
if (so) {
const savePath = "/data/local/tmp/libexec.so";
const file = new File(savePath, "wb");
if (file) {
console.log(`[+] 开始分段 Dump: ${so.base} - ${so.size} bytes`);
let currentAddr = so.base;
const endAddr = so.base.add(so.size);
const pageSize = 4096;
while (currentAddr.compare(endAddr) < 0) {
Memory.protect(currentAddr, pageSize, 'rwx');
let bytesToWrite = pageSize;
if (currentAddr.add(pageSize).compare(endAddr) > 0) {
bytesToWrite = endAddr.sub(currentAddr).toInt32();
}
try {
const buffer = currentAddr.readByteArray(bytesToWrite);
file.write(buffer);
} catch (e) {
console.warn(`[!] 无法读取地址: ${currentAddr},填充空数据`);
const emptyBuffer = new ArrayBuffer(bytesToWrite);
file.write(emptyBuffer);
}
currentAddr = currentAddr.add(bytesToWrite);
}
file.flush();
file.close();
console.log(`[✅] Dump 完成!保存至: ${savePath}`);
}
}将Dump得到的libexecmain.so文件导入IDA工具开展静态分析
通过检索ClassLoader关键字符串,精准定位程序Native函数注册核心代码段。


追踪注册函数入口,进入sub_5EB20函数进行逻辑分析。
可判定该函数为程序初始化核心函数,同时集成全套反调试、反模拟器检测逻辑。
逐层拆解分析该函数内的各类校验分支。

函数内置qemud模拟器检测逻辑,该逻辑无关键防护作用,可直接忽略。
程序核心致命防护为一处条件判断分支,触发后会直接终止APP进程。


跟随汇编跳转链路逐层追溯,该校验逻辑会依次调用 sub_4860c、sub_49D00 函数完成核心安全检测

其中,sub_4b6d8 为核心文件读取函数,主要负责读取系统关键文件数据。
sub_68d94 为字符串匹配校验函数,用于匹配系统文件内的风控特征关键字。

程序会遍历校验目标系统文件的特征信息,命中任意风控特征即判定为调试环境。
检测异常时函数返回1,触发进程强制杀死逻辑。
仅当函数返回0时,可成功绕过该层防护校验。





检测到其中一个都会跳转到返回1

针对程序核心反调试检测逻辑,采用Hook篡改返回值的方式绕过防护。
通过Frida挂钩 sub_49D00 函数执行内存地址。
在函数执行阶段直接将寄存器x0赋值为0,强制检测函数返回合法数值。
该操作可彻底绕过文件特征检测、Frida环境检测双重防护机制。
const targetSoName = "libexec.so";
function hook_target(base) {
Interceptor.attach(base.add(0x48618), {
onEnter: function () {
this.context.x0 = 0x0;
}
});
}
// 方案 B: Hook Linker 的 dlopen (更专业,能抢在 SO 入口执行前)
const android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
if (android_dlopen_ext) {
Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
this.path = args[0].readUtf8String();
},
onLeave: function (retval) {
if (this.path && this.path.indexOf(targetSoName) !== -1) {
console.log("[+] 监测到 dlopen 加载模块: " + this.path);
var module = Process.findModuleByName(targetSoName);
if (module) hook_target(module.base);
}
}
});
}Frida脚本注入执行后,可成功附加目标APP进程。
程序不再出现闪退问题,逆向调试环境正常生效。

成功绕过全部反调试、反附加限制后,调用壳Dump脚本完整导出程序内存数据。
var sym = Module.findExportByName("libart.so", "_ZN3art13DexFileLoader10OpenCommonEPKhmS2_mRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEEPNS0_12VerifyResultE");
if (!sym) {
console.log("[-] 未找到 OpenCommon 函数");
return;
}
console.log("[+] 挂钩 OpenCommon 成功:" + sym);
Interceptor.attach(sym, {
onEnter: function (args) {
console.log("\n======== 进入 OpenCommon ========");
var dex_base = args[0];
var dex_size = args[1].toUInt32();
try {
var magic = Memory.readUtf8String(dex_base, 4);
console.log("magic = " + magic);
if (magic === "dex\n" || magic === "dey\n" || magic.startsWith("dex")) {
console.log("[+] 找到有效 DEX,基址:" + dex_base + " 大小:" + dex_size);
if (dex_size <= 0) {
dex_size = Memory.readU32(dex_base.add(0x20)); // 0x20 = 32
}
var path = "/data/local/tmp/dump_com.greenpoint.android.mc10086/dump_" + dex_base + "_" + dex_size + ".dex";
var file = new File(path, "wb");
file.write(Memory.readByteArray(dex_base, dex_size));
file.flush();
file.close();
console.log("[+] Dump 成功:" + path);
}
} catch (e) {
console.log("[-] 读取内存失败:", e);
}
}
});
获取到完整的脱壳后程序文件。
使用Jadx工具对脱壳文件进行反编译处理。
可正常解析出完整、无乱码、无强混淆的Java源码,核心脱壳任务顺利完成。

本次逆向分析过程中存在一处遗留问题。
在绕过所有反调试、反检测防护后,程序仍存在一处标志位校验逻辑。
该校验逻辑会无条件触发APP进程终止,存在顽固残留防护。
深入逆向分析该残留校验逻辑后发现,该校验会读取base.apk文件的指定偏移位数据。

这里有一个校验


理论上该偏移数值固定为1,会持续判定程序运行环境异常。
目前暂未完全定位该固定异常校验的核心成因,作为本次分析遗留疑点。
虽该底层标志位校验逻辑未彻底溯源并绕过,但不影响核心逆向工作。
已成功实现Frida稳定附加、完整Dump程序内存文件、正常反编译获取源码。
整体不受残留防护影响,最终顺利完成APP***壳脱壳分析工作。

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 20小时前
被kanxue编辑
,原因: 脱敏