frida
可以正常注入程序,但是一使用Java.use
就会闪退
这里编译frida-bridge
或者使用ZygiskFrida
都可以绕过Java.use
检测
编译frida-bridge
可以参考这个视频
frida模块化开发,frida-compile,解决frida的java的api检测相关问题,frida-java-bridge调试_哔哩哔哩_bilibili
加载编译好的_agent.js
即可绕过检测
ZygiskFrida
这里使用的是这个项目
https://github.com/sucsand/sucsand
首先抓到的数据包是这样的,请求体和响应体都是json
格式,并且以=
作为键。
先上算法助手hook一遍,然后搜索相关的密文字符串,但是并没有找到相关联的hook结果,那大概率加解密都是放在native
层,然后看到请求头中有验签的字段X-Emp-Signature
,索性直接jadx
大法,全局搜索X-Emp-Signature
。
经过分析定位到initHttpRequest
方法,这里签名字段是通过HmacSha1实现的
这里encryptHMAC
通过配置决定使用国密 SM3 算法还是传入的算法配置对输入数据和密钥进行 HMAC 运算。
签名的算法搞定后,再去看请求体是如何加密的,一般验证签名都是在数据加密后再去做的,可以通过jadx
向上找引用,这里省的看代码直接用frida打印堆栈去看
往上追踪定位到sendResquest
方法,sendResquest
中通过handleRequestBody
函数来处理请求体
继续跟到handleRequestBody
,这里直接贴出GPT给出的解释
handleRequestBody
处理完请求体之后,会调用sendResquest
发送请求,这里再看下sendResquest
的逻辑
这里会再对上面handleRequestBody
的结果再进行一次Base64编码,然后再拼接成json发送数据包
这样逻辑就比较清晰了
resultByts = HMAC(序列号 || AES(RNC + 请求体)) || 序列号 || AES(RNC + 请求体)result = Base64(resultByts)请求体 = Base64(result)
所以只要能拿到AESCipher.clientKey
_和AESCipher.ClientIv_
以及ClientHello.ServerHmacKey
即可对加密后的数据进行还原并且重放,这里继续往下跟踪AESCipher
和ClientHello
代码,发现只是定义了静态变量没有进行赋值。
为了找到clientKey_
和clientIv_
,继续追踪AESAdapter.encrypt
方法,发现每次重新打开APP,对应的clientKey_
和clientIv_
都会改变,一开始想的是是不是动态向服务器去请求的clientKey_
和clientIv_
,但是抓包并没有发现类似的请求,事情开始变得有趣了起来。
clientKey_
和clientIv_
既不是通过HTTP请求传输的,又不是硬编码在代码中的,那服务端到底是如何解密的呢?
为了搞清楚clientKey_
和clientIv_
的生成逻辑,继续往上找AESCipher
这个类的相关引用,最后发现一个可疑的方法,
这里的关键其实是第一行代码,其余的代码都是在做密钥的分割,然后赋值。
byte[] allSecret = PRFCipher.PRF(ms2, HMac.TLS_MD_CLIENT_SERVER_KEYIVMAC_CONST(), ms2RncRnsSeed, R2.attr.arrowHeadLength);
所以还是得继续往上找引用,看看ms2
是如何生成的,定位到handleServerKeyExchange
方法,熟悉TLS流程的朋友这里就能看出来,这里的TLS握手流程中的服务器密钥交换 过程非常相似。
继续往上找,定位到handlerServerKeyExchange
函数
继续追handleFacilityServerHelloResponse
继续往上追,发现了一个可疑的请求,生成的密钥结果都是从这个请求中提取的。
抓包也同样看到了这个请求
继续向上看定位到ClientHello
的构造方法
这里直接贴出GPT给的代码解释
但是由于测试时间有限,按理说这部分代码也是可以通过Python
代码去解析响应然后提取clientIv
、clientKey
、serverKey
、serverIv
的,但转念一想这几个参数都是静态参数,可以直接用frida
去获取。
首先用frida+rpc+flask
获取clientIv
、clientKey
、serverKey
、serverIv
,脚本如下
在上文编译好的_agent.js
中添加需要发送到Python
端的数据。
Java.perform(function () {var ClientHello = Java.use("com.rytong.emp.net.ClientHello");var mClient