尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Frida实战:Hook Java层逆向Shopee App加密参数生成逻辑

Frida实战:Hook Java层逆向Shopee App加密参数生成逻辑 1. 项目概述与核心价值最近在分析一些电商App的数据交互时Shopee虾皮这个东南亚的巨头平台进入了我的视线。它的App在请求中使用了相当复杂的加密参数这对于想要进行自动化数据采集或者安全研究的朋友来说无疑是一道需要攻克的难关。直接去逆向分析它的Native层C/C或者混淆严重的JavaScript代码工作量巨大且容易迷失方向。经过一番摸索我发现了一条相对清晰的路径使用Frida框架在Java层对关键的参数生成函数进行Hook。这种方法避开了最复杂的部分直击要害能够清晰地看到参数从明文到密文的转换过程。这篇文章我将以一个实战者的身份带你完整走一遍这个流程。从环境搭建、目标定位到编写Hook脚本、解析加密逻辑最后附上我调试好的完整脚本。无论你是移动安全的研究者还是对数据爬虫有需求的开发者亦或是单纯对逆向工程感兴趣的技术爱好者这篇内容都能给你提供一个清晰、可复现的实操指南。我们不会涉及任何违规操作纯粹从技术角度探讨如何理解一个App的通信安全机制。2. 逆向分析环境搭建与工具选型工欲善其事必先利其器。一个稳定、高效的逆向分析环境是成功的第一步。这里我选择的是“真机PC”的经典组合而不是模拟器。虽然雷电模拟器等安卓模拟器安装Frida也很方便但在处理某些加固或反调试机制时真机的兼容性和真实性更胜一筹。2.1 核心工具链解析我的工具链主要围绕Frida构建它是一个动态插桩工具包允许我们将自己的JavaScript代码片段注入到目标进程这里是Shopee App中从而拦截、修改函数调用和内存数据。Frida Server (运行在手机上)这是一个守护进程运行在目标设备已Root的安卓手机或模拟器上负责接收来自PC端的指令并执行Hook操作。你需要根据你的手机CPU架构通常是arm64下载对应的版本。Frida Client (运行在PC上)即我们常说的frida和frida-toolsPython包。我们通过Python脚本或命令行工具frida、frida-ps等与手机上的Server通信。ADB (Android Debug Bridge)这是连接PC和手机的桥梁用于推送文件、开启端口转发、获取进程列表等。反编译工具 (可选但推荐)如Jadx-GUI或Bytecode Viewer。它们用于静态分析Shopee App的APK文件帮助我们快速浏览Java代码结构定位潜在的关键类和方法为动态Hook提供“地图”。注意关于Frida和Frida-tools的版本对应关系这是一个常被忽略但至关重要的问题。版本不匹配会导致连接失败或功能异常。一个简单的原则是尽量保持Server端和Client端的主版本号一致。例如你从Frida官网下载了frida-server-16.1.11-android-arm64.xz那么在PC上最好也安装frida和frida-tools的16.x.x版本。你可以使用pip install frida16.1.11 frida-tools12.1.1这样的命令来指定安装。通常Frida-tools的版本号独立但选择与当前Frida版本发布时间相近的稳定版即可官网或PyPI上会有兼容性说明。2.2 详细环境配置步骤第一步手机端准备准备一台已经获得Root权限的安卓手机。这是运行Frida Server的前提。从Frida官网的releases页面下载对应你手机架构的frida-server压缩包。使用adb shell getprop ro.product.cpu.abi命令可以查询架构。使用adb push命令将解压后的frida-server文件推送到手机的/data/local/tmp/目录。通过adb shell进入手机终端切换到/data/local/tmp/目录为frida-server文件添加可执行权限(chmod 755 frida-server-*)然后在后台运行它(./frida-server-* )。为了持久化你可以考虑将启动命令写入init.rc或使用Magisk模块。第二步PC端准备确保Python环境建议3.7已安装。使用pip安装指定版本的frida和frida-tools如pip install frida frida-tools。如果遇到网络问题可以使用国内镜像源。通过adb forward tcp:27042 tcp:27042命令将手机端的Frida默认端口转发到PC。也可以使用adb forward tcp:27043 tcp:27043转发D-Bus端口。第三步验证连接在PC端命令行输入frida-ps -U。如果一切正常这个命令会列出手机上当前运行的所有进程。看到这个列表就说明你的Frida环境已经打通了。实操心得在真机上首次运行frida-server后可能会被系统或安全软件杀死。一个稳妥的做法是将frida-server重命名为一个不起眼的名字如/system/bin/mediaserver注意备份原文件并修改其权限和属主使其更好地隐藏。此外使用nohup命令或将其包装为系统服务可以增强稳定性。3. 加密参数定位与Java层Hook策略环境就绪后下一步就是找到我们要Hook的目标。Shopee App的加密参数可能出现在请求头如X-Signature,X-Token或请求体一个经过加密的JSON字符串中。我们的策略是“由外及内动态追踪”。3.1 初步侦察与目标确定首先我们需要知道加密参数长什么样。最直接的方法是抓包。在PC上设置好代理如Charles或Fiddler并在手机上配置Wi-Fi代理指向PC。在Shopee App内进行任意操作如搜索商品、查看详情。观察抓包工具截获的请求。你会发现关键的API请求尤其是涉及商品列表、详情、登录的请求其URL可能看起来是明文的但请求头中通常包含类似x-api-signature、x-common-params等字段或者整个POST的请求体是一串毫无规律的字符。这些就是我们的目标——加密后的参数。我们的核心目标就是找到生成这串加密字符的Java函数。3.2 静态分析与关键类搜寻盲目地在运行中Hook成千上万个函数是不现实的。我们需要借助静态分析来缩小范围。将Shopee的APK文件拖入Jadx-GUI。搜索关键词在Jadx中全局搜索快捷键CtrlShiftF你在抓包中看到的可疑参数名如signature、encrypt、encode、security等。注意大小写和可能的拼写变体。关注网络库搜索常用的网络库包名如okhttp3、retrofit2。特别是寻找自定义的Interceptor拦截器或Converter转换器加密逻辑常常封装在这里以便对所有请求进行统一处理。查找工具类搜索可能包含加密算法的类如SecurityUtil、SignUtil、CryptoManager、AES、RSA、HMAC等。以我的分析为例通过搜索signature我定位到了一个名为com.shopee.**.security.SignatureGenerator的类类名已做泛化处理实际可能不同。这个类里有一个generate方法其参数包含时间戳、设备信息、请求体明文等返回值是一个字符串。这非常可疑3.3 动态验证与精确Hook点选择静态分析找到的只是“嫌疑人”需要动态Hook来“定罪”。我们编写一个初步的Frida脚本去Hook这个可疑的generate方法。Java.perform(function () { // 替换成你找到的完整类名 var SignatureGenerator Java.use(com.shopee.**.security.SignatureGenerator); SignatureGenerator.generate.overload(java.lang.String, java.lang.String, java.lang.String).implementation function (param1, param2, param3) { console.log([] SignatureGenerator.generate called!); console.log( |- param1: param1); // 可能是设备ID console.log( |- param2: param2); // 可能是时间戳 console.log( |- param3: param3); // 可能是请求体JSON var result this.generate(param1, param2, param3); // 调用原方法获取结果 console.log( |- result: result); console.log(); return result; // 返回原结果不影响App运行 }; });将这个脚本保存为hook_sign.js然后使用命令frida -U -f com.shopee.app -l hook_sign.js --no-pause启动Shopee App并注入脚本。随后在App内进行操作观察控制台输出。如果当你在App内触发网络请求时控制台打印出了我们Hook方法的日志并且result的输出正好匹配抓包中看到的加密参数那么恭喜你目标找到了如果没有输出说明Hook的类或方法不对需要回到Jadx继续搜索和尝试或者尝试Hook更底层的字节数组加密方法。注意事项Java方法可能存在重载overload。你需要通过.overload()指定准确的参数类型列表。在Jadx中查看方法签名确保Frida脚本中的重载签名与之一致。generate(param1, param2, param3)只是一个示例实际参数类型可能是String、long、byte[]、JSONObject等。4. 加密逻辑深度解析与脚本编写一旦定位到核心的加密函数我们的工作就完成了一大半。接下来的任务是深入理解它的逻辑并编写一个功能完善的Hook脚本不仅要能打印输入输出最好还能模拟生成。4.1 逆向加密算法在Hook中我们打印出了函数的输入和输出。但这还不够我们需要知道函数内部是如何计算的。通常有两种情况纯Java实现加密算法完全用Java代码实现如AES、RSA、HMAC-SHA256。这时你可以直接在Jadx中阅读generate方法的源码。虽然可能被混淆变量名、方法名无意义但算法结构循环、条件判断、调用其他加密方法是清晰的。你可以尝试在Python或Node.js中复现这个逻辑。JNI调用Native库generate方法内部可能只是调用了native方法真正的加密逻辑在.so动态链接库里。这增加了难度。此时Frida依然强大你可以Hook这个native函数或者退而求其次将Hook点放在调用native函数之后、返回结果之前的位置确保能捕获到最终的加密结果。对于复杂的Native逆向可能需要结合IDA Pro等工具这超出了本文的范围。但很多时候我们并不需要完全逆向算法只要能可靠地获取到加密结果即可。在我的这次实战中幸运地遇到了第一种情况。SignatureGenerator.generate方法内部实际上是调用了另一个SecurityUtil.hmacSha256()方法将“设备ID时间戳请求体”拼接成一个字符串然后用一个固定的密钥硬编码在代码中或从服务器获取进行HMAC-SHA256运算最后将结果进行Base64编码。4.2 编写功能完整的Frida Hook脚本一个用于学习和分析的Hook脚本应该包含详细的日志、对多种重载方法的支持、以及良好的可读性。下面是我优化后的脚本框架Java.perform(function () { console.log([] Script loaded. Targeting Shopee...\n); var targetClass com.shopee.**.security.SignatureGenerator; var targetMethod generate; try { var HookClass Java.use(targetClass); // 情况一Hook String generate(String a, String b, String c) var overload1 HookClass.generate.overload(java.lang.String, java.lang.String, java.lang.String); overload1.implementation function (deviceId, timestamp, body) { console.log(\n[] ${targetClass}.${targetMethod} (String, String, String) called.); console.log( |- Thread: ${Java.use(java.lang.Thread).currentThread().getName()}); console.log( |- DeviceId: ${deviceId}); console.log( |- Timestamp: ${timestamp}); console.log( |- Body: ${body}); var startTime Date.now(); var result overload1.call(this, deviceId, timestamp, body); // 调用原方法 var costTime Date.now() - startTime; console.log( |- Result: ${result}); console.log( |- Time Cost: ${costTime}ms); console.log( |- Caller Stack:); console.log(Java.use(android.util.Log).getStackTraceString(Java.use(java.lang.Exception).$new())); console.log(); // 可选将结果存储到变量供其他函数查询简易RPC send({type: signature, data: result, input: {deviceId: deviceId, timestamp: timestamp, body: body}}); return result; }; console.log([*] Hook set for ${targetMethod}(String, String, String)); } catch (e) { console.log([-] Error hooking ${targetMethod}: e.message); } // 情况二如果存在其他重载方法如 byte[] generate(byte[] data) try { var overload2 HookClass.generate.overload([B); overload2.implementation function (data) { console.log(\n[] ${targetClass}.${targetMethod} (byte[]) called.); var dataStr Java.use(java.lang.String).$new(data); console.log( |- Input bytes as String: ${dataStr}); var result overload2.call(this, data); var resultStr Java.use(java.lang.String).$new(result); console.log( |- Result bytes as String: ${resultStr}); console.log(); return result; }; console.log([*] Hook set for ${targetMethod}(byte[])); } catch (e) { // 忽略未找到此重载的错误 } // 监听特定网络请求的触发示例Hook OkHttp的RealCall.execute方法 var OkHttpClient_Call Java.use(okhttp3.Call); if (OkHttpClient_Call) { OkHttpClient_Call.execute.implementation function () { var request this.request(); var url request.url().toString(); // 只关注包含特定路径的请求避免日志泛滥 if (url.indexOf(/api/v2/) ! -1) { console.log(\n[Network] Request URL: ${url}); console.log([Network] Method: ${request.method()}); } return this.execute(); }; console.log([*] Hook set for OkHttp Call.execute); } });脚本解析与技巧多重重载处理使用try...catch包裹每个overload的Hook避免因某个重载不存在而导致整个脚本失败。性能监控记录函数执行耗时costTime有助于评估算法复杂度和性能瓶颈。调用栈打印打印调用栈getStackTraceString是逆向工程中的“神器”它能告诉你这个加密函数是被谁调用的从而理清整个参数组装流程。这在分析复杂调用链时至关重要。信息过滤通过URL路径判断只打印我们关心的网络请求日志避免被海量日志淹没。RPC通信使用send()函数可以将Hook到的数据发送到Frida的Python控制端实现外部程序与脚本的交互便于自动化。5. 常见问题排查与实战心得在实际操作中你几乎一定会遇到各种问题。这里我总结了一份“避坑指南”。5.1 连接与注入问题排查表问题现象可能原因解决方案frida-ps -U无输出或报错1. ADB连接不稳定或未授权。2. Frida Server未运行或已崩溃。3. 端口转发失败。4. 手机未Root或Frida Server权限不足。1. 执行adb devices确认设备在线且为device状态。重启ADB服务。2. 重新adb shell进入手机ps | grep frida查看进程若无则重新启动。3. 检查adb forward命令是否执行成功可尝试重启ADB daemonadb kill-server adb start-server。4. 确认Root权限并使用su -c命令以Root身份启动Frida Server。注入脚本后App闪退1. Frida版本与Android系统/App不兼容。2. Hook了敏感或关键函数导致App逻辑异常。3. App具有反调试或反Frida检测。1. 尝试更换不同版本的Frida Server和Client如降级到较旧的稳定版。2. 检查脚本确保Hook函数后正确调用了原方法使用.call(this, ...)或.apply(this, arguments)。3. 使用frida -U -f com.shopee.app --no-pause在App启动前注入有时能绕过检测。或使用Frida的隐身技术如修改Frida Server特征。控制台无Hook日志输出1. 目标类名/方法名不正确。2. 方法重载签名不匹配。3. 脚本注入时机太晚方法已被调用。1. 在Jadx中反复确认类名和方法名注意混淆可能导致类名变化。2. 使用Java.choose()或Object.Class.getDeclaredMethods()枚举类的方法找到准确签名。3. 使用setImmediate或Java.perform确保脚本在Java运行时就绪后立即执行或使用-f参数在App启动时附着。5.2 Hook过程中的高级技巧与心得处理代码混淆Shopee的APK很可能被混淆了。你看到的类名可能是a.a.a.c方法名可能是a()、b()。这增加了定位难度。策略是搜索字符串常量加密算法中常包含算法名如HmacSHA256、字符集如UTF-8或固定的密钥片段。在Jadx中搜索这些字符串能找到引用它们的混淆类和方法。关注调用关系即使类名混淆网络库OkHttp的调用关系通常是清晰的。从okhttp3.Call的执行入手回溯拦截器Interceptor链找到自定义的加密拦截器。动态枚举在Frida脚本中可以使用Java.enumerateMethods(*Signature*!*)或遍历已加载的类来寻找名称中包含特定关键词的方法但这比较耗时。应对App加固如果Shopee使用了商业加固方案Java层代码可能被加密或隐藏Jadx反编译出来全是乱码或空方法。这时Frida的动态Hook优势更明显。因为无论怎么加固代码最终都要在内存中解密执行。我们可以尝试Hookjava.lang.ClassLoader的loadClass方法在类被加载时进行Hook。或者寻找加固方案的薄弱点但这对技术要求更高。数据关联与模拟Hook脚本不仅能打印日志还能修改数据。例如你可以尝试修改generate函数的输入参数观察输出变化从而验证每个参数的作用。更进一步你可以在Python端根据Hook到的算法逻辑如HMAC-SHA256用Python的hmac和hashlib库重新实现一遍加密函数。这样你就可以在不启动App的情况下独立生成有效的加密参数用于自动化脚本。保持脚本的健壮性在Hook函数时一定要用try...catch包裹你的实现代码。因为你的代码运行在目标App的进程空间里一旦出现未捕获的异常很可能导致整个App崩溃。此外避免在Hook函数中执行耗时操作或阻塞操作这会影响App的响应速度甚至引发ANR应用无响应。最后我想分享一点个人体会。逆向工程就像解谜需要耐心、细心和逻辑推理能力。面对像Shopee这样的大型商业应用不要指望一蹴而就。从抓包开始到静态分析找线索再到动态Hook验证每一步都可能遇到挫折。关键是把大问题拆解成小问题先找到加密参数在哪再找是谁生成的最后看它是怎么生成的。Frida在这个过程中提供了无与伦比的动态观察能力让你能像调试自己代码一样去窥探别人的应用逻辑。这个过程本身就是对移动应用安全机制一次深刻的学习。
返回列表