逆向分析中的‘签名’玄学:如何从脱壳后的Dex中定位并还原App的请求加密逻辑

张开发
2026/6/8 23:22:42 15 分钟阅读
逆向分析中的‘签名’玄学:如何从脱壳后的Dex中定位并还原App的请求加密逻辑
逆向工程中的签名追踪术从Dex脱壳到加密逻辑还原实战当你在夜神模拟器的昏暗光线下盯着jadx反编译出的那一行行被混淆为a.b.c.d的代码时突然发现一个关键线索——那个每次请求都会变化的signature参数。这种感觉就像侦探在犯罪现场发现指纹既兴奋又充满挑战。本文将带你深入App逆向的核心战场从脱壳后的Dex文件中抽丝剥茧最终还原出完整的请求加密逻辑。1. 逆向工程的环境搭建与工具链逆向分析如同外科手术需要精密工具配合。我的工作台上常年备着这些手术器械动态分析三件套Frida用于运行时Hook和动态调试Xposed修改系统级Java方法调用IDA ProNative层逆向分析的瑞士军刀静态分析双雄# 安装jadx反编译工具 brew install jadx # MacOS choco install jadx # WindowsJadx将Dex/Smali转为可读Java代码GhidraNSA开源的逆向工程框架网络监控哨兵# 使用mitmproxy进行流量拦截 from mitmproxy import http def request(flow: http.HTTPFlow) - None: if signature in flow.request.url: print(f捕获签名参数: {flow.request.query.get(signature)})提示建议使用隔离的测试环境避免触发App的安全防护机制。虚拟机快照功能能大幅提高实验效率。工具组合的威力体现在交叉验证上。比如当静态分析遇到混淆时可以用Frida注入日志输出来确认关键函数的实际行为// Frida脚本示例拦截加密函数 Interceptor.attach(Module.findExportByName(libencrypt.so, generate_sign), { onEnter: function(args) { console.log(参数1:, args[0].readUtf8String()); console.log(参数2:, args[1].toInt32()); } });2. 从抓包到代码定位的侦查技术Charles抓包看到signature参数只是开始真正的挑战在于如何在数十个被混淆的类中找到它的生成位置。我常用的三点定位法如下特征字符串搜索在jadx中搜索抓包看到的固定参数名如signature调用链回溯从OkHttp的Interceptor接口实现类入手动态注入标记在关键函数入口插入日志输出最近分析某新闻App时发现其签名逻辑藏在com.example.a.b.c.d这样的包结构中。通过以下特征最终锁定位置包含时间戳参数调用了MessageDigest.getInstance(MD5)出现在网络请求拦截器附近关键代码片段往往呈现特定模式// 典型的签名生成代码结构 public String generateSign(String params) { String salt 固定密钥; String input params salt; return md5(input); }逆向工程师需要培养对这类代码模式的敏感度。当看到字符串拼接后接哈希函数调用时就要意识到这可能是签名生成点。3. 对抗代码混淆的实用技巧现代加固方案会使用名称混淆、控制流平坦化等技术增加分析难度。面对a.a(a).b(b)这样的代码我的破解策略是3.1 建立变量映射表用表格记录混淆前后的对应关系混淆名称实际含义出现位置a.aMD5工具类加密模块b.b时间戳生成器请求拦截器c.c设备ID获取应用上下文3.2 关键算法识别模式常见加密算法在字节码层面有特征可循MD5会出现MessageDigest.getInstance(MD5)HMAC包含Mac.getInstance(HmacSHA256)AESCipher.getInstance(AES/CBC/PKCS5Padding)3.3 动态调试技巧当静态分析陷入死胡同时可以用Frida打印调用栈// 打印当前线程调用栈 console.log(Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress).join(\n));对于Native层混淆IDA的FLIRT技术可以识别标准库函数减少分析范围。4. 加密算法的精准还原与重构定位到签名算法只是成功了一半准确还原才是真正的考验。以常见的HMAC-SHA256为例还原过程需要关注密钥来源硬编码、动态获取还是服务端下发参数顺序字段拼接是否有特定排序规则编码方式结果是否经过Base64/Hex编码Python还原示例import hmac import hashlib import time def generate_sign(params: dict, secret: str): # 1. 参数按key排序 sorted_params sorted(params.items(), keylambda x: x[0]) # 2. 拼接为keyvalue格式 query_string .join([f{k}{v} for k,v in sorted_params]) # 3. 计算HMAC signature hmac.new( secret.encode(), query_string.encode(), hashlib.sha256 ).hexdigest() return signature # 测试用例 params { timestamp: int(time.time()), nonce: abc123, device_id: IMEI123456 } secret f1190aca-d08e-4041-8666-29931cd89dde print(generate_sign(params, secret))当遇到更复杂的算法时可以考虑直接将关键Java代码编译为Jar供Python调用// SignUtils.java public class SignUtils { public static native String nativeSign(String input); public static String generate(String input) { return md5(nativeSign(input) 固定后缀); } }# Python调用示例 from jpype import * startJVM(getDefaultJVMPath(), -Djava.class.path./sign.jar) SignUtils JClass(com.example.SignUtils) sign SignUtils.generate(input_data) shutdownJVM()5. 逆向工程中的防御与反制随着逆向技术的普及App的防护措施也在升级。最近遇到几个棘手案例签名算法动态化每次启动从服务端获取不同算法环境检测检测Root/Xposed/Frida等工具代码自修改运行时解密关键函数对抗方案需要创造性思维# 绕过简单环境检测的Frida脚本 Java.perform(function() { var DetectionClass Java.use(com.security.Detection); DetectionClass.isRooted.implementation function() { return false; // 永远返回未root }; });对于Native层保护可以内存Dump解密后的so文件# 使用Frida从内存导出模块 frida -U -l dump.js com.example.app// dump.js var lib Process.getModuleByName(libencrypt.so); var file new File(/tmp/libencrypt_dump.so, wb); file.write(lib.base.readByteArray(lib.size)); file.close();逆向工程就像一场永无止境的猫鼠游戏。每次当我以为掌握了所有技巧时总会遇到新的保护方案。记得有一次分析某金融App它的关键代码会在检测到调试器时自我删除最后不得不通过硬件级调试才突破防线。这种技术对抗带来的刺激感正是逆向工程最吸引我的地方。

更多文章