首页
社区
课程
招聘
[原创]某运营商APP加固脱壳与反 Frida 检测绕过分析
发表于: 1天前 334

[原创]某运营商APP加固脱壳与反 Frida 检测绕过分析

1天前
334

文本

描述已自动生成文本

描述已自动生成文本

描述已自动生成

本文档内容仅用于网络安全技术学习、安全研究、合规渗透测试等合法教学场景。

文中所涉及的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编辑 ,原因: 脱敏
收藏
免费 2
支持
分享
最新回复 (1)
雪    币: 406
活跃值: (2754)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
中国移动
19小时前
0
游客
登录 | 注册 方可回帖
返回