App信息
包名:com.baicorv.yueyequan

抓包分析数据
进入全部话题,刷新进行抓包

1 | url: https://customer.yueyequan.cn/comu-core/v1.0/topic/appList |
这里面要逆向的参数是ice-auth-sign
逆向分析
反编译搜索ice-auth-sign,并没有相关信息,尝试其他思路。
根据数据长度分析,ice-auth-sign的长度是128个字节,这128字节应该是转为hex之后的长度,原长度是64字节,可能是sha512算法
hook RegisterNatives()
也是出于尝试的心理,猜测它是在so中生成的
恰好就找到了与sign有关的函数

对里面的签名算法进行hook
1 | function hook_sign(){ |
hook到的签名与抓到的数据包中的签名是一样的,那就说明找到了对应的位置

hook NewStringUTF()
还有一种方式也是出于猜测的方式,通过hook字符串,指定长度为128,打印相关信息及调用栈
1 | function hook_NewStringUTF(){ |
也可以打印出相关信息
1 | dataString: 1f28d7d65c10c3af2d5c53d46772064ae16bdcac33880f394a351edbe957701562e4fc47dd344a02657e15bdec3054bf40da3c50df79049467955f7075fc12da |
反编译分析
getEncryptSign()

查找用例是在getSign()中被调用的,同时getEncryptSign也是一个native函数
getSign()

hook getSign()
1 | function hook_getsign(){ |
结果
1 | SignatureUtils.getSign is called: str=GET, str2=/comu-core/v1.0/topic/appList, str3=pagenum=1pagesize=20 |
发现ice-auth-sign是从这个方法返回的
call_getEncryptSign()
在分析so之前,写一个主动调用getEncryptSign()的函数,用于固定参数,后面分析的时候参数是固定的
1 | function call_getEncryptSign(){ |
so分析

使用IDA反编译找到getEncryptSign()进行分析
sub_9F368()
看到一个函数sub9F368

这里hook一下查看参数及返回值
1 | function hook_9f368() { |
hook结果
1 | 9f368 onEnter |
这里是在原来的参数里拼接了ice-auth-appkey和ice-auth-timestamp及e494454bb61acae31109befb58aa774386b646035af606e9314fab13b9adffe7
这里面的ice-auth-appkey和e494454bb61acae31109befb58aa774386b646035af606e9314fab13b9adffe7都是定值,但是ice-auth-timestamp这个时间戳是会变动的,所以会导致后面输出的结果也会变动
通过打印内存可以查看ice-auth-appkey和e494454bb61acae31109befb58aa774386b646035af606e9314fab13b9adffe7
1 | function temp_call(){ |

urlEncode()
进入到一个函数urlEncode()

hook一下
1 | function hook_urlcode(){ |
结果
1 | urlcode is called |
这里就是进行了url编码
BIO_set_fun_update()
url编码之后就来到了BIO_set_fun_update()函数里

对它进行hook

可以根据符号名或地址进行hook
1 | function hook_updateout(){ |
hook 结果
1 | updateout is called |
这里返回值是签名的值
进入BIO_set_fun_update()函数进行分析
又出现了两个BIO_set_fun_update()

不一样的是这里的符号名和地址与前面的不一样

这里在hook一下,我用out和inner把两个BIO_set_fun_update()区分开了
1 | function hook_updateout(){ |
结果
1 | updateout is called |
updateinner被调用了两次,它的第二个参数一个是0xb,另一个是0x6,好像是一种标识
根据它的源码进行分析,如下,它是用来做switch判断的

firstKeyIndex和secondKeyIndex
其实在传参的时候就可以看到这两个值

通过打印内存查看这两个变量的值
1 | function temp_call(){ |
结果如下

case 11

先调用EVP_sha3_256()然后根据返回值判断是否跳转到LABEL_4
先来hook一下
1 | function hook_EVP_sha3_256(){ |
结果
1 | EVP_sha3_256 is called |
返回值是I,那就回跳转到LABEL_4

这里会调用calculateHash
calculateHash()
这里就直接hook一下他
1 | function hook_calculatehash(){ |
结果
1 | calculatehash is called |
经过测试,这是一个sha3-256算法
如下验证

这里执行完之后会跳转到下一个BIO_set_fun_update()里,然后到case 6分支里
case 6

这里执行的是sha512
hook 一下
1 | function hook_sha512(){ |
结果
1 | sha512 is called |
验证是否为标准的sha512,如下可以确定是标准的sha512

把这些代码整合一下放一起进行hook
代码整合
1 | function hook_getEncryptSign(){ |
hook结果
1 | SignatureUtils.getEncryptSign is called: str=GET, str2=/comu-core/v1.0/topic/appList, str3=name=pagenum=1pagesize=10 |
python生成ice-auth-sign
1 | import time |
Python请求获取话题数据
1 | import requests |