2026/2/13 2:36:57
网站建设
项目流程
文具网站建设合同书,微分销商城系统,产品销售型的网站,网络系统架构0. 引言#xff1a;那串令人绝望的 sign
作为一名爬虫工程师或者协议分析爱好者#xff0c;你一定经历过这样的绝望时刻#xff1a;
你挂上 Charles#xff0c;配置好 SSL Unpinning#xff0c;成功抓到了包。你兴奋地打开请求体#xff0c;准备复现 API。
然而#xff…0. 引言那串令人绝望的sign作为一名爬虫工程师或者协议分析爱好者你一定经历过这样的绝望时刻你挂上 Charles配置好 SSL Unpinning成功抓到了包。你兴奋地打开请求体准备复现 API。然而映入眼帘的不仅有常规的userId、timestamp还有一个让你透心凉的参数sign:a1b2c3d4e5f6...你尝试修改任何一个参数服务器都会冷冷地回你一句{code: 403, msg: Invalid Signature}。这个sign是怎么来的是 MD5是 SHA256还是加了盐盐是在本地生成的还是服务器下发的面对大厂 App 动辄几百 MB 的混淆代码Obfuscated Code静态分析就像在大海捞针。但是动态 Hook技术的出现让这场游戏变得公平了。今天我不谈枯燥的汇编只讲实战。我将带你用Frida这把手术刀直接切入 App 的内存血管在加密函数执行的前一毫秒截获它的“核心机密”。⚠️ 免责声明本文技术仅用于移动安全研究与教学。请勿用于通过非法手段获取数据、攻击服务器或进行任何商业黑产行为。逆向工程应严格遵守《网络安全法》白帽子需自律。1. 战前准备工欲善其事在开始“手术”之前我们需要准备好全套工具。1.1 核心武器库测试设备一台已 Root 的 Android 手机推荐 Pixel 或 Nexus系统 Android 8-10 最佳。抓包工具Charles 或 Fiddler配合 Postern/Drony 解决代理检测。静态分析Jadx-GUI看 Java 层代码、IDA Pro看 So 层代码本篇主要聚焦 Java 层。动态注入Frida (Client Server)。开发环境Python 3 VS Code。1.2 目标确认为了避嫌我们将目标 App 称为“TargetApp”。目标破解其核心搜索接口的sign生成逻辑并实现 Python 自动化调用。2. 第一阶段侦察抓包与定位2.1 抓包分析打开 TargetApp进行一次搜索操作。Charles 抓到的请求如下POST /api/v2/search HTTP/1.1 Content-Type: application/json { keyword: 逆向手机, page: 1, timestamp: 1678888888, nonce: Ax9871hz, sign: 3f8a0b9c7d6e5f4a3b2c1d0e9f8a7b6c }分析timestamp和nonce随机数通常用于防重放。sign长度为 32 位且由 0-9, a-f 组成。初步推测是 MD5。现在的任务是找到生成这个 MD5 之前的原始内容Plaintext。2.2 静态分析定位 (Jadx)将 APK 拖入 Jadx等待反编译完成。面对成千上万个类不要慌。我们要利用关键词搜索。搜索策略搜索sign双引号包裹精确匹配字符串。搜索 URL 路径/api/v2/search。搜索常见的加密类名如SecurityUtil,SignUtil,Encrypt。经过一番苦搜我发现了一个可疑的类com.targetapp.utils.SecurityUtils里面有一个静态方法// 混淆后的代码片段publicstaticStringa(Contextcontext,MapString,Stringmap){// ... 省略部分代码 ...StringsortedStringb(map);// 看起来像是在对参数排序StringsaltAppConfig.getSalt();// 获取盐值returnMD5.encode(sortedStringsalt);// 疑似最终加密点}虽然代码被混淆成了a,b,c但逻辑结构出卖了它排序 - 加盐 - MD5。3. 第二阶段手术Frida Hook静态分析只能通过猜测。万一AppConfig.getSalt()是在 Native 层.so生成的动态盐呢万一排序规则很特殊呢这时候Frida登场了。3.1 Frida 原理图解Frida 就像是一个植入 App 大脑的“寄生虫”。它将 V8 引擎注入到目标进程中允许我们使用 JavaScript 代码动态地修改 Java 方法的行为。3.2 编写 Hook 脚本我们要做的就是 Hook 上面找到的com.targetapp.utils.SecurityUtils.a方法。我想看看传入这个方法的map到底长什么样返回的String又是什么创建一个hook_sign.jsJava.perform(function(){console.log([*] Frida script started...);// 1. 定位目标类varSecurityUtilsJava.use(com.targetapp.utils.SecurityUtils);// 2. Hook 目标方法 a// 注意如果方法有重载需要用 .overload(...) 指明参数类型SecurityUtils.a.overload(android.content.Context,java.util.Map).implementationfunction(context,map){console.log(\n HOOK DETECTED );// 3. 打印入参// 将 Map 转换为 JSON 字符串方便查看varmapStrJava.cast(map,Java.use(java.util.HashMap)).toString();console.log([] Input Map: mapStr);// 4. 执行原方法获取结果varresultthis.a(context,map);// 5. 打印结果console.log([] Output Sign: result);// 6. 打印堆栈信息可选用于追踪是谁调用了它// console.log(Java.use(android.util.Log).getStackTraceString(Java.use(java.lang.Throwable).$new()));console.log(\n);returnresult;};});3.3 注入并见证奇迹在 PC 终端运行 Frida 命令frida -U -f com.targetapp.android -l hook_sign.js手机上 App 自动启动。我随意在搜索框输入“Python”点击搜索。那一刻终端屏幕疯狂滚动直到这一行日志出现我悟了 HOOK DETECTED [] Input Map: {keywordPython, page1, timestamp1678888888, nonceAx9871hz} [] Output Sign: 3f8a0b9c7d6e5f4a3b2c1d0e9f8a7b6c 等等这还不够。我还需要知道salt是什么我们可以进一步 Hook 那个 MD5 的入口或者直接在刚才的代码里Hook 那个b(map)方法疑似排序拼接字符串的方法。修改脚本HookSecurityUtils.bSecurityUtils.b.implementationfunction(map){varresultthis.b(map);console.log([*] Serialized String (Pre-Salt): result);returnresult;}再次运行输出[*] Serialized String (Pre-Salt): keywordPythonnonceAx9871hzpage1timestamp1678888888看来是标准的 ASCII 排序拼接。那么盐呢通常盐是直接拼在字符串后面的。如果我 Hook MD5 函数的入参就能看到完整体了。Hookcom.targetapp.utils.MD5.encode(String str):varMD5Java.use(com.targetapp.utils.MD5);MD5.encode.implementationfunction(str){console.log([!!!] MD5 Input (THE SECRET): str);returnthis.encode(str);}最终的真相[!!!] MD5 Input (THE SECRET): keywordPythonnonceAx9871hzpage1timestamp1678888888secretUnicorn_2024_!#我悟了原来所谓的“高强度加密”就是在参数屁股后面拼了一个固定的盐值secretUnicorn_2024_!#然后做了一次 MD5。所谓的“大厂防线”在内存可视化的那一刻就像没穿衣服一样。4. 第三阶段武器化Python RPC知道了原理我们就可以用 Python 复现算法。但有些时候算法可能极其复杂例如魔改的 AES或者逻辑在 .so 层很难还原。这时候最好的办法不是还原而是借用。我们要利用Frida-RPC让 Python 脚本远程调用手机里的加密函数。4.1 修改 JS 脚本为 RPC 模式// rpc_sign.jsrpc.exports{// 导出这个函数给 Python 调用getSign:function(keyword,page,timestamp,nonce){varresult;// 必须在 Java 线程中执行Java.perform(function(){// 获取当前 Context (通常用 ActivityThread 或者 Application)varcurrentApplicationJava.use(android.app.ActivityThread).currentApplication();varcontextcurrentApplication.getApplicationContext();// 构造 HashMapvarHashMapJava.use(java.util.HashMap);varmapHashMap.$new();map.put(keyword,keyword);map.put(page,page.toString());// 注意类型转换map.put(timestamp,timestamp.toString());map.put(nonce,nonce);// 主动调用加密函数varSecurityUtilsJava.use(com.targetapp.utils.SecurityUtils);resultSecurityUtils.a(context,map);});returnresult;}};4.2 编写 Python 脚本importfridaimporttime# 连接 USB 设备devicefrida.get_usb_device()# 启动或附加到进程sessiondevice.attach(com.targetapp.android)# 加载 JSwithopen(rpc_sign.js)asf:scriptsession.create_script(f.read())script.load()# 调用导出函数# 这里的 script.exports 对应 js 里的 rpc.exportsprint([*] Calling App function via RPC...)keywordCSDNpage1tsint(time.time())noncerandom123# 就像调用本地函数一样调用手机里的函数signscript.exports.get_sign(keyword,page,ts,nonce)print(f[-] Keyword:{keyword})print(f[-] Timestamp:{ts})print(f[-] Generated Sign:{sign})# 接下来就可以拿着这个 sign 去发 requests 请求了效果你运行 Python 脚本手机后台默默地计算出了sign并返回给了你。你不需要扣算法细节不需要关心盐值变没变。只要 App 不更新你的爬虫就永远有效。这就是RPC (Remote Procedure Call)的降维打击。5. 进阶思考如果逻辑在 Native 层 (.so) 怎么办如果SecurityUtils.a是native方法publicstaticnativeStringa(Contextcontext,MapString,Stringmap);Jadx 就看不到了。这时候我们需要解压 APK提取.so文件。使用IDA Pro进行反汇编。利用 Frida HookInterceptor.attach(Module.findExportByName(libnative.so, Java_com_...), ...)。分析汇编指令ARM64查看寄存器x0, x1…中的值。虽然难度升级但核心思路不变Input - BlackBox - Output。只要我们能在 BlackBox 执行前截获数据我们就赢了。6. 总结与反思回顾整个过程为什么我说“我悟了”加密不是魔法无论 App 吹嘘多么安全的算法在客户端层面它必须包含“加密逻辑”和“密钥”。只要它在本地运行就有被逆向的可能。Hook 的上帝视角静态分析是读天书动态分析是看电影。Frida 让我们跳过了复杂的逻辑推导直接看到了结果。攻防的不对称性开发者为了保护一个参数可能写了上千行混淆代码而逆向者只需要几十行 Frida 脚本就能绕过。给开发者的建议防御不要把核心盐值硬编码在 Java 层字符串里。关键逻辑放入 Native 层C并进行虚假控制流混淆OLLVM。增加 Frida 检测、Root 检测、模拟器检测。最重要的风控要放在服务端不要轻信客户端传来的任何sign要结合 IP、行为轨迹、设备指纹做综合判定。互动环节 (Hook)你在逆向过程中遇到过最奇葩的加密算法是什么把参数转成 Base64 再倒序把时间戳藏在 User-Agent 里或者是把密钥写死在图片 Exif 信息里在评论区晒出你的“脱坑”经历点赞最高的评论我下期专门出一篇针对 Native 层 .so 逆向的保姆级教程别忘了关注我带你硬核玩转 Android 安全