CTF逆向-[安恒杯 2022 春季赛]shield-安卓脱壳实战:Frida-DexDump动态脱壳与源码还原分析

张开发
2026/5/11 11:18:39 15 分钟阅读
CTF逆向-[安恒杯 2022 春季赛]shield-安卓脱壳实战:Frida-DexDump动态脱壳与源码还原分析
1. 安卓脱壳技术背景与实战意义在移动安全领域加壳技术就像给应用程序穿上了防弹衣而脱壳则是破解这层防护的关键手段。这次我们要分析的[安恒杯 2022 春季赛]shield题目就是一个典型的安卓加壳案例。我去年在参加某次CTF比赛时就遇到过类似的加壳题目当时花了整整6个小时才成功脱壳这段经历让我深刻理解了动态脱壳技术的重要性。安卓加壳技术主要分为两类一类是传统的Dex加密另一类则是更高级的VMP虚拟机保护技术。这次我们要对付的shield属于第一类它通过加密原始Dex文件在运行时动态解密。这种保护方式虽然不能完全阻止逆向分析但确实增加了分析难度。在实际工作中安全研究人员经常需要分析这类加壳应用比如检测恶意软件或进行安全审计。Frida-DexDump这套组合工具之所以成为行业标配主要是因为它解决了传统静态脱壳工具的局限性。我记得第一次用Frida脱壳时看到内存中的Dex文件被完整dump出来的那种兴奋感就像考古学家发现了埋藏千年的文物。这套工具链最大的优势在于它不需要提前知道加壳算法的细节而是直接在内存中捕获解密后的Dex文件。2. 环境搭建与工具配置2.1 模拟器选择与配置工欲善其事必先利其器。我测试过各种安卓模拟器包括Genymotion、夜神和官方模拟器最后发现对于脱壳任务来说Android Studio自带的模拟器最稳定。具体推荐使用API 28Android 9的x86镜像这个版本对Frida的支持最好。安装完模拟器后有几个关键配置需要注意在AVD Manager中编辑设备配置将RAM设置为2048MB以上关闭Play Protect功能设置 → Google → 安全 → Play Protect开启USB调试模式设置 → 系统 → 关于手机 → 连续点击版本号7次开启开发者选项我遇到过不少同学因为没调这些设置导致后续步骤出现问题。特别是内存设置如果太小的话在dump大体积Dex时很容易导致进程崩溃。2.2 Frida全家桶安装Frida的安装说简单也简单说复杂也复杂。在Ubuntu系统上可能一条命令就能搞定但在Windows上可能会遇到各种幺蛾子。以下是经过我多次踩坑总结出的可靠安装方案# 先安装Python环境推荐3.8版本 python -m pip install --upgrade pip pip install frida15.1.17 frida-tools10.4.1这里特别指定了版本号因为新版Frida有时会有兼容性问题。如果遇到安装错误可以尝试手动下载whl文件安装pip install https://github.com/frida/frida/releases/download/15.1.17/frida-15.1.17-py3-none-win_amd64.whl接下来需要准备frida-server这个要和客户端版本严格匹配。下载后推送到模拟器adb push frida-server-15.1.17-android-x86 /data/local/tmp/ adb shell chmod 755 /data/local/tmp/frida-server-15.1.17-android-x86 adb shell /data/local/tmp/frida-server-15.1.17-android-x86 测试连接是否成功frida-ps -U如果能看到进程列表说明环境搭建成功。3. 动态脱壳实战过程3.1 目标应用分析与壳检测拿到shield.apk后我习惯先用APKTool进行初步分析apktool d shield.apk -o output_dir打开解包后的目录如果在smali文件夹中看不到业务逻辑代码而是充斥着各种a、b、c这样的类名基本可以确定有壳。更专业的检测方法是查看AndroidManifest.xml中的application标签application android:namecom.secshell.ApplicationWrapper ... /application这种非标准Application类名是加壳的明显特征。还可以用DroidLysis等工具进行自动化检测python droidlysis.py -i shield.apk -o report/3.2 Frida-DexDump脱壳技巧常规的脱壳命令大家可能都知道frida-dexdump -FU但这个命令只能dump前台应用。对于后台服务或者动态加载的Dex我们需要更精准的定位。我的经验是先用Frida枚举内存中的Dex文件Process.enumerateRanges(r-x).forEach(range { if (range.file range.file.path.includes(.dex)) { console.log(JSON.stringify(range)); } });找到目标Dex后使用高级过滤参数进行dumpfrida-dexdump -U -n com.example.shield --deep-search这里有几个实用参数--size-limit 10M过滤掉太小的Dex碎片--sleep 5给应用留出解密时间--output dex_files/指定输出目录我曾在某个比赛中遇到过多层壳的情况需要通过hook ClassLoader来触发后续解密Java.perform(() { const DexClassLoader Java.use(dalvik.system.DexClassLoader); DexClassLoader.loadClass.overload(java.lang.String).implementation function(name) { const result this.loadClass(name); console.log(Loaded class:, name); return result; }; });4. 源码还原与逆向分析4.1 Dex转Jar的陷阱与解决方案拿到Dex文件后很多人直接用dex2jar转换d2j-dex2jar.sh classes.dex -o output.jar但这样经常会遇到各种错误。经过多次实践我发现以下组合最可靠# 先用enjarify做初步转换 python3 -m enjarify.main classes.dex -o classes.jar # 再用jadx做补充修复 jadx --export-gradle classes.jar -d src/对于复杂的混淆代码我还会用以下技巧使用Procyon进行二次反编译用Bytecode Viewer对比不同反编译器的结果对关键方法进行字节码级分析4.2 Shield题目关键逻辑分析在shield这个题目中flag验证逻辑通常藏在以下几个地方所有名为check、verify、validate的方法字符串操作密集的类调用了MessageDigest或Cipher的代码块用jadx搜索关键字符串jadx-gui -j 4 --search flag{ shield.apk如果代码被严重混淆可以尝试动态跟踪Java.perform(() { const Activity Java.use(com.example.shield.MainActivity); Activity.checkFlag.implementation function(input) { console.log(Flag input:, input); const result this.checkFlag(input); console.log(Validation result:, result); return result; }; });5. 进阶技巧与疑难解答5.1 对抗反调试措施现代加壳方案通常会检测Frida常见检测手段包括检查/proc/self/maps中的frida字符检测关键端口27042检查线程名对抗方案示例// 隐藏Frida字符串 Process.enumerateModules().forEach(module { if (module.name.includes(frida)) { console.log(Found Frida module:, module.name); Memory.protect(module.base, module.size, rw-); Memory.writeUtf8String(module.base, librandom.so); } });5.2 性能优化技巧处理大型应用时可能会遇到性能问题。我的优化经验包括使用frida --runtimev8提升脚本执行效率对hook代码进行懒加载限制枚举范围frida -U -l script.js --runtimev8 -n com.example.app在分析过程中及时保存工作状态也很重要// 保存已hook的类和方法 const knownClasses {}; Java.enumerateLoadedClasses({ onMatch: function(name) { if (name.includes(crypto)) { knownClasses[name] true; } }, onComplete: function() {} });记得随时备份dump出来的Dex文件我习惯用时间戳命名mkdir -p dumps/$(date %Y%m%d) frida-dexdump -U -n com.example.app -o dumps/$(date %Y%m%d)

更多文章