首页
社区
课程
招聘
[原创]不知妻美,sign参数分析
发表于: 2天前 1424

[原创]不知妻美,sign参数分析

2天前
1424

目标接口:搜索 https://api.m.ooxx.com/client.action?functionId=search

版本:13.1.0

目标参数:body 中的 x-api-eid-token 和 sign

1280X1280

定位接口参数的方法

这里我们直接使用最朴素的搜索大法,一次就中。

aa7b3a0d-812b-4194-9655-1a1c28024808

继续跟踪,进最下面这个看看。

cbbafcde-bf1e-4eda-870c-80222b7994df

7a32e864-bcbb-4eb6-9ada-0a282ace6b17

下面拼接了 urlEncodeUTF82 ,看英文就是一个 utf 编码之后的数据。继续向上跟踪

进入第一个,函数返回的是一个字符串。还不是加密的地方。

829abc7d-0b52-4963-a4d2-a32fa14e56da

66b305ed-3fa7-421e-93eb-2f1bcd4181a6

4df6c474-20b3-4169-8e25-9512db580b92

1280X1280

JDHttpTookit.getEngine().getSignatureHandlerImpl().signature 这就是签名函数。

f9d17560-1cee-487a-86e6-f5cde7c53e50

接口函数一般是 implement 或者直接 new 出来。这里跟进 new 出来的

ccdf666c-35db-449d-a204-ae26a17a89fb

27a3e561-259d-4c18-8509-ed7f153b2382

7627c33c-d0af-4a24-8f1e-5ef1d5727465

通过 frida 获取传入的参数

image-20241114142805715

主动调用,方便后续做测试

结果中就包含了我们今天的主角 ==sign== 。长度为 32 脑海中就冒出 MD5了。

调用到了 native 层了。java 层的分析就到这里了。这里类中并没有看到加载 so 。需要通过 frida hook 导出的符号表,反查 so 的名字。

image-20241114142933483

得到模板 so 的名字为 libjdbitmapkit.so

IDA 打开可以看到 getSignFromJni 的导出函数 。通过 IDA frida-trace 先 trace 一份日志方便后面分析

工具:https://github.com/Pr0214/trace_natives

把下载到的 traceNatives.py 放到 ida 根目录的 plugin 目录下重启 IDA。点击 edit -> plugins -> traceNatives 会生成一个文件夹给frida-trace 使用。

frida 就会开始trace 此时不要关闭命令行,直接调用刚才的主动触发的函数 call_by_java() 就会生成追踪数据,复制保存成一个 log 文件方便后面分析。

再用 findHash 插件看看能不能找到什么有用的信息

c3d5356a-652a-4b0f-a9e4-223d610010b4

把两个数据做对比发现了 sub_27A4 这个函数在两边都有出现。

image-20241114144429468

IDA 中按 g 跳转过去看看

561dbbc2-05a8-4cd2-b74d-3a5cdd176a6b

看上去很像 MD5 哦,点击数字按 h 转换成十六进制然后去搜索一下

8ad2b53b-5e64-4ddc-9da1-8d6c8d382118

image-20241114144910691

有点意思!! 应该是MD5。查看 trace 日志,sub_8134() 是最开始的地方,IDA 中看看是什么内容。

image-20241114145020553

经过对比发现,我们的入口函数也就是 8134 。那还有什么说的,盘他咯!!

650c2dd0-88c2-4558-b0da-4bdf16fc1967

在 trace 日志中 8134 这层调用的最后一个函数是 33b4,进入 33b4 之后就是 MD5算法了。我们先 hook 7e08 查看入参。

image-20241114150756263

传入的参数很像 base64 但是解密之后还是乱码。传入之前做了处理。向上追踪,在 trace 日志,上一个被调用的函数是 2698

a30f644c-0e7f-4330-9022-8e31dcd3d943

hook 2698 看看返回值,刚好就是 33B4 的入参

image-20241114151239972

跟踪 2698 第二个参数,它来自 v37 , v37 又是来自 7E08 这个函数 。而且 在 trace 日志中也有它的身影。

image-20241114151543609

经过分析可以发现 7E08 最后两个参数是两个随机数,就是这两个随机数决定了之后使用不同的分支算法。

f3d1c40f-71a7-4818-bc65-c9a218aa9e6d

进入 7E08 。先判断最后一个参数的随机数,用不同方式在生成一个随机数,然后与倒数第二参数的随机数相加产生新的随机数。

0cfcbe2f-3f88-4bcf-a1fd-103c5c91f75e

使用新的随机数来决定最终进入那个分支的算法。特别注意一下 gen_str_44e这是一个固定的字符串。在进入不同分支的时候,根据新的随机数取了这个字符串中不同的数据

01b9b9b8-40c1-447c-8077-d1faebd042e2

hook 7E08 得到的参数

image-20241114152931578

在我们的 trace log 中 进入了 case2 分支,就先分析这个分支。

这里要特别注意一下,因为这里是根据随机数来进入不同的分支的。所以在测试的时候不是每次都进入到这个 8cc8 分支。多调用几次,总会有一个进入的。

image-20241114153203444

020b7a83-c136-4268-b79c-6da9e8d081d7

通过代码看到各参数都进入到 1ADCC这个函数,优先分析这个函数。hook 查看参数

image-20241114153843183

修改一下hook代码把第二参数输出一下

image-20241114154225994

第二参数是字符串,第四个参数是传入的数据,第五个参数是传入数据的长度。所以可以让 hexdump 根据这个参数 dump 出完整的数据。
图片描述
图片描述

分析之后 1ADCC 就是最终的算法

image-20241114154720500

141df5ba-a851-4080-aa4d-7ae31146b15f

下面是还原之后的算法

可以看到是一致的

image-20241114155102087

最后把这段数据 base64 之后再进行 md5 就是最终的 sign 值。最终拼接上 sv 和 t 值返回到 java 层

faedb4a6-4e8d-4ddb-905b-4934f13cf983

今天就先分析case2 的分支,以后有机会再分析其他分支啦!!

以 x-api-eid-token 作为入口点,分析 java 层的最终点在 BitmapkitUtils.getSignFromJni。结合 frida-trace 和 findHash 找到关键点 sub_27A4 。在这个函数内部使用了随机数的方式进入不同的分支。使用 CASE2 分支作为今天的入口点,最终成功得到 sign 具体的算法逻辑。

第一次写文章,有什么表达的不清楚的希望大家多包涵。有什么问题,可以在评论区提出哈!

function call_by_java() {
    Java.perform(function(){
        let BitmapkitUtils = Java.use("com.ooxx.common.utils.BitmapkitUtils");
        let context = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext();
        let str = 'search'
        let str2 = '{"addrFilter":"1","addressId":"0","articleEssay":"1","attrRet":"0","buriedExpLabel":"","deviceidTail":"38","exposedCount":"0","filterServiceIds":"1468131091","first_search":"1","frontExpids":"F_001","gcAreaId":"1,72,55674,0","gcLat":"39.944093","gcLng":"116.482276","imagesize":{"gridImg":"531x531","listImg":"358x358","longImg":"531x708"},"insertArticle":"1","insertScene":"1","insertedCount":"0","isCorrect":"1","jdv":"0|kong|t_2018512525_cpv_nopay|tuiguang|17303608941925019140008|1730360893","keyword":"空气加湿器","localNum":"2","newMiddleTag":"1","newVersion":"3","oneBoxMod":"1","orignalSearch":"1","orignalSelect":"1","page":"1","pageEntrance":"1","pagesize":"10","populationType":"232","pvid":"","searchVersionCode":"10110","secondInsedCount":"0","showShopTab":"yes","showStoreTab":"1","show_posnum":"0","sourceRef":[{"action":"","eventId":"MyJD_WordSizeResult","isDirectSearch":"0","logid":"","pageId":"Home_Main","pvId":""},{"action":"","eventId":"Search_History","isDirectSearch":"0","logid":"","pageId":"Search_Activity","pvId":"632ba208e4854bb1839e6e32a5e6b841"}],"stock":"1","ver":"142"}'
        let str3 = "bd132c578e85c7cd";
        let str4 = "android";
        let str5 = "13.1.0";
 
        let result = BitmapkitUtils.getSignFromJni(context, str, str2, str3, str4, str5);
        console.log("BitmapkitUtils.getSignFromJni result = " + result);
    })
}
function call_by_java() {
    Java.perform(function(){
        let BitmapkitUtils = Java.use("com.ooxx.common.utils.BitmapkitUtils");
        let context = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext();
        let str = 'search'
        let str2 = '{"addrFilter":"1","addressId":"0","articleEssay":"1","attrRet":"0","buriedExpLabel":"","deviceidTail":"38","exposedCount":"0","filterServiceIds":"1468131091","first_search":"1","frontExpids":"F_001","gcAreaId":"1,72,55674,0","gcLat":"39.944093","gcLng":"116.482276","imagesize":{"gridImg":"531x531","listImg":"358x358","longImg":"531x708"},"insertArticle":"1","insertScene":"1","insertedCount":"0","isCorrect":"1","jdv":"0|kong|t_2018512525_cpv_nopay|tuiguang|17303608941925019140008|1730360893","keyword":"空气加湿器","localNum":"2","newMiddleTag":"1","newVersion":"3","oneBoxMod":"1","orignalSearch":"1","orignalSelect":"1","page":"1","pageEntrance":"1","pagesize":"10","populationType":"232","pvid":"","searchVersionCode":"10110","secondInsedCount":"0","showShopTab":"yes","showStoreTab":"1","show_posnum":"0","sourceRef":[{"action":"","eventId":"MyJD_WordSizeResult","isDirectSearch":"0","logid":"","pageId":"Home_Main","pvId":""},{"action":"","eventId":"Search_History","isDirectSearch":"0","logid":"","pageId":"Search_Activity","pvId":"632ba208e4854bb1839e6e32a5e6b841"}],"stock":"1","ver":"142"}'
        let str3 = "bd132c578e85c7cd";
        let str4 = "android";
        let str5 = "13.1.0";
 
        let result = BitmapkitUtils.getSignFromJni(context, str, str2, str3, str4, str5);

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 2
支持
分享
最新回复 (4)
雪    币: 542
活跃值: (3004)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
起的一手好标题
2天前
0
雪    币: 3862
活跃值: (1504)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这个sign已经被大家分析快烂了,不过还是支持下
2天前
0
雪    币: 562
活跃值: (4065)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
允许你一东时间奖励自己
2天前
0
雪    币: 343
活跃值: (903)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
标题好
2天前
0
游客
登录 | 注册 方可回帖
返回
//