安卓逆向工程实战:从脱壳到协议分析全流程
1. 安卓逆向工程概述与工具链搭建安卓逆向工程是通过分析已编译的APK文件还原其源代码逻辑的技术手段。在本次实战中我们将针对引力播新闻类APP进行完整的逆向分析流程重点解决接口参数加密逆向问题。逆向工程通常涉及以下核心环节脱壳处理移除APP的加固保护代码反编译将DEX文件转换为可读的Java代码动态调试运行时分析关键逻辑协议分析破解网络通信加密1.1 环境准备与模拟器选型逆向工程首选Genymotion模拟器而非真机原因有三避免真机系统崩溃风险方便快照回滚操作支持Xposed框架稳定运行具体配置步骤# 安装VirtualBoxGenymotion依赖 sudo apt install virtualbox -y # 下载Genymotion个人版需注册账号 wget https://dl.genymotion.com/releases/genymotion-3.3.2/Genymotion-3.3.2-linux_x64.bin chmod x Genymotion-3.3.2-linux_x64.bin ./Genymotion-3.3.2-linux_x64.bin推荐使用Android 6.0镜像API 23这个版本对Xposed框架兼容性最佳。创建模拟器时需注意分配至少2核CPU和2048MB内存开启VT-x/AMD-V虚拟化支持设置共享文件夹方便文件传输注意避免使用游戏向模拟器如雷电、夜神这些模拟器通常对开发者工具支持不完善且存在性能瓶颈。1.2 Xposed框架部署Xposed是逆向工程的核心工具通过HOOK机制可以动态修改APP行为。安装流程如下下载对应版本的Xposed安装包xposed-v89-sdk23-x86.zip框架XposedInstaller_3.1.5.apk管理器通过ADB刷入框架adb push xposed-v89-sdk23-x86.zip /sdcard/ adb shell su flash-archive.sh /sdcard/xposed-v89-sdk23-x86.zip安装管理器APK并激活模块adb install XposedInstaller_3.1.5.apk激活后需要重启模拟器在Xposed Installer的模块界面可以确认框架状态。常见问题处理若显示未激活检查是否授予root权限出现bootloop时通过恢复模式刷入卸载包2. 脱壳实战与代码提取2.1 fdex2脱壳原理fdex2基于Xposed的HOOK技术通过拦截DexFile.loadDex()方法获取解密后的DEX文件。其工作流程目标APP启动时加载加密的DEXXposed拦截类加载器调用将解密后的字节码导出到/data/data/[package]/fdex2目录关键配置参数输出路径/data/user/0/[package]/fdex2过滤条件仅捕获目标APP的类加载2.2 脱壳操作实录以引力播APP包名com.iCitySuzhou.suzhou001为例安装fdex2模块adb install fdex2.apk激活模块并配置目标adb shell am start -n de.robv.android.xposed.installer/de.robv.android.xposed.installer.WelcomeActivity执行脱壳操作# 启动目标APP adb shell am start -n com.iCitySuzhou.suzhou001/.MainActivity # 提取DEX文件 adb pull /data/user/0/com.iCitySuzhou.suzhou001/fdex2 ~/Desktop/dex_output脱壳成功的标志是获取多个DEX文件如classes.dex, classes2.dex。若未成功尝试以下排查步骤确认Xposed日志无错误检查APP是否有多进程需hook所有进程尝试其他脱壳工具如DumpDex2.3 代码反编译技巧使用jadx-gui处理脱壳得到的DEX文件jadx-gui -d ./src ./dex_output/classes.dex代码分析要点搜索关键类MyApplication入口类定位网络库OkHttp/Retrofit相关包查找加密工具类包含MD5/AES/RSA等关键词对于混淆代码可通过以下方式还原语义分析调用链上下文重命名有意义的方法变量使用Enjarot进行二次反编译3. 网络抓包与协议分析3.1 Charles抓包配置配置模拟器代理adb shell settings put global http_proxy 电脑IP:8888安装Charles根证书adb push charles.pem /sdcard/ adb shell mv /sdcard/charles.pem /system/etc/security/cacerts/ adb shell chmod 644 /system/etc/security/cacerts/charles.pem针对HTTPS流量需要额外配置目标APP添加networkSecurityConfig禁用证书固定Pinnging3.2 引力播接口分析抓包发现关键请求特征GET /api/v1/appNews/getBannerNewsList7?page1 HTTP/1.1 signature: 850196b383f11879ebb2c232d04d3b47 timestamp: 1632747791参数加密规律分析signature随timestamp变化采用32位MD5格式静态分析发现加密原料为UDID timestamp 固定密钥3.3 加密定位技巧在jadx中高效定位加密代码搜索字符串signature跟踪HeaderInterceptor类分析网络库的拦截器栈关键代码片段// 混淆后的加密类 public class C1234a { public static String m4567(String str) { return MD5Utils.encode(str System.currentTimeMillis() f1190aca-d08e-4041-8666-29931cd89dde); } }通过交叉引用Xref可找到所有调用点确认这是全局签名生成方法。4. 加密算法逆向与调用4.1 Java代码还原将混淆代码重构为可读版本import java.security.MessageDigest; public class SignatureGenerator { private static final String SECRET f1190aca-d08e-4041-8666-29931cd89dde; public static String generate(String deviceId) { String input deviceId (System.currentTimeMillis()/1000) SECRET; return md5(input); } private static String md5(String input) { try { MessageDigest md MessageDigest.getInstance(MD5); byte[] digest md.digest(input.getBytes()); StringBuilder sb new StringBuilder(); for (byte b : digest) { sb.append(String.format(%02x, b)); } return sb.toString(); } catch (Exception e) { return ; } } }4.2 Python调用方案方案对比方案优点缺点JPype直接调用Java需配置JVM环境重写算法无依赖复杂算法实现困难REST服务跨语言需要额外服务推荐使用JPype实现import jpype import time def get_signature(device_id): jarpath SignatureGenerator.jar jpype.startJVM(jpype.getDefaultJVMPath(), -ea, f-Djava.class.path{jarpath}) SignatureGenerator jpype.JClass(SignatureGenerator) signature SignatureGenerator.generate(device_id) jpype.shutdownJVM() return signature4.3 完整请求示例import requests device_id IMEI867686023834169-IMSI460NNNNNNNNNNNN timestamp str(int(time.time())) signature get_signature(device_id) headers { udid: device_id, timestamp: timestamp, signature: signature, user-agent: okhttp/3.9.0 } response requests.get( https://app.suzhou-news.cn/api/v1/appNews/getBannerNewsList7, params{page: 1, bannerID: 11}, headersheaders ) print(response.json())5. 高级技巧与异常处理5.1 对抗加固方案当遇到高级加固如梆梆、360加固时使用Frida进行内存DumpInterceptor.attach(Module.findExportByName(libart.so, DexFile_openMemory), { onLeave: function(retval) { dumpMemory(retval); } });定制Xposed模块绕过检测XposedHelpers.findAndHookMethod(java.lang.System, loadPackageParam.classLoader, loadLibrary, String.class, new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam param) { if (anti_xposed.equals(param.args[0])) { param.setResult(null); } } });5.2 常见问题排查脱壳失败检查Xposed日志adb logcat -s Xposed尝试不同API等级的模拟器使用反射大师等辅助工具抓包无数据确认证书已正确安装检查APP是否使用原生代码如Cronet尝试使用r0capture进行双向抓包算法还原困难使用JEB进行动态调试查找so文件中的加密函数分析密钥生成流程5.3 法律与道德边界逆向工程需注意仅用于学习研究目的不破坏数字版权保护不窃取用户隐私数据遵守《计算机软件保护条例》建议在逆向前进行法律风险评估必要授权获取敏感信息脱敏处理