APP sign签名参数分析
2024-3-23 16:5:30 Author: mp.weixin.qq.com(查看原文) 阅读量:8 收藏

分析该APP的包请求,在Fiddler中发现一个请求包:
想把其中的签名弄清楚,然后用python去模拟协议。
原始返回的数据是protobuf的格式,通过修改请求头Accept,可以让服务器返回json的数据格式。
具体操作步骤为:直接将请求头中的Accept: application/x2-protostuff; charset=UTF-8,更改为:Accept: application/json; charset=UTF-8
但是如果直接请求,浏览器会报签名错误:
注意看请求头中,有两个签名(sign和sg字段),因此这两个签名需要逆向解决,另外还需要知道oak(可能是key)是什么东西。
所以直接将app拖到jeb里面,首先通过查找网址,可以搜索到其构造URL的代码逻辑块,位于:
通过上述定位,可以找到发起请求的入口:
再往下分析,查看函数makeRequestByPkgName,这个调用就是通过包名获取信息的函数接口:
这里new了一个请求ProductDetailRequest,实现了com.nearme.network.request.IRequest接口,进入到请求类中,查看具体的实现:
上图中可以发现,请求操作在com.nearme.network.c类中的函数中,查看函数上一跳,发现请求接口:com.nearme.network.extend.d.request。
继续分析可以发现该请求接口设置了拦截器并通过initHeader函数初始化了请求头:
通过分析请求头中的参数来源,将部分重要参数和对应的说明,以及抓包中获取的值列表如下:
参数
参数说明
抓包获取的值
otaver
OTA版本,即系统属性”ro.build.version.ota“
PERM00_11.C.08_1080_202201271341
device_type
设备类型
0:手机
1:折叠设备
2:平板
0
User-Agent
浏览器UA信息(URLEncode)
数据格式是:设备生产商/设备型号/安卓系统版本号/安卓版本/设备ROM版本号/APP_CODE/APP渠道号(默认为0)/应用市场版本号/应用市场版本名
OPPO%2FPERM00%2F30%2F11%2FV11.1%2F2%2F2101%2F110005%2F11.0.1
t
当前时间戳
1699251997861
id
代码中的openid
数据格式是:GUID/OUID/DUID/AndroidId
/2bcba0937bc629468b9886c10bf3cbbada3d743768ece4f548a80e41d9360e6a/AA177E8E54FA42CA928C9638A9BDFB8C5bb7929185700b4a882306a43cc6710f/CD623898E41E4FB18BD2ED0842CC0AADEC7D424979CC9C51C70EAC900ECAD017
ocs
数据格式:设备生产商/设备型号/安卓系统版本号/安卓版本/设备ROM版本号/APP_CODE/ro.build.display.id/应用市场版本号
然后经过URLencode处理
OPPO%2FPERM00%2F30%2F11%2FV11.1%2F2%2FPERM00_11_C.08%2F110005
sign
签名1
47e29daacff4479021520eac9100a1cd
sg
签名2
4df40cedbd7d5fec9876600cccb235a9
oak
签名密钥key
cdb09c43063ea6bb
通过请求测试,签名sign、sg、oak是服务器作为校验的依据,所以需要对上面三个参数做分析。
①:参数”oak“来源的分析
java层获取该参数的代码块是:
函数跳转到native层,so文件名称:libocstool.so。
上述JNI函数通过静态注册,查看b函数:
发现key1通过a函数初始化得出,在请求之前进行初始化,并校验APP的签名。
如果APP签名校验不通过,则key得不到初始化,应用内所有的请求都会返回错误。
进入init_key,key1的来源通过包名进行绑定,所以与该应用市场对应的包名的key1为cdb09c43063ea6bb。

②:参数”sign“来源的分析

在java层,通过组合特定的参数传入签名函数中:
hook一下,可以看到值,通过分析也可以知道传入的参数为:设备生产商/设备型号/安卓系统版本号/安卓版本/设备ROM版本号/APP_CODE/ro.build.display.id/应用市场版本号+当前时间戳/GUID/OUID/DUID/AndroidId/URL_Path+URL_Query
参数已经分析完毕,接下来来看sign的签名算法:
在上述初始化key1结束后,函数立即初始化了key2:
跟踪调用实现,发现key2 通过计算得出:
简单描述一下生成逻辑:算法:通过去掉v1前两位,然后将v1剩下的部分头尾交换,再拼接上key1,组成一个48位的key2:
进入到c函数,可以发现sign的签名是通过MD5计算得出:
算法可以概括为:toHex(MD5(key2 + a1 +(a1的长度+key2的长度)+OBSCURE_CODE))
③:参数”sg“来源的分析
java层中,签名1将作为参数传递给签名2:
然后再组合相应的参数,丢到native层中:
通过分析也可以知道d函数的两个参数是什么,参数a3为Url_path + Url_query+Accept+请求类型字符串(get、post、put、head四选一)+openid+时间戳,参数a4为上面计算的sign。
查看函数d,首先这里将参数a3、key1和a4字符串相合并,然后计算长度,然后再加上计算的长度数字,计算一轮MD5,即MD5(a3+key1+a4+长度数字字符串):
然后这里计算出MD5之后,拿着MD5的byte字节数据数组,数组中的每一个数字取绝对值之后,取个位数字(%10)相加再%10:
最后得到的v28其实是个数字,取值范围为0-9。然后,对得到的数字再%5,取密钥数组的下标:
密钥数组sgk和sgsk是一个长度为5的数组:
通过上面的计算得到目标密钥sgk_sel和sgsk_sel。然后将参数a3与两个目标密钥相加,最后链接上相加后字符串的长度作为待签名数据。
对累加后的字符串,根据上面计算的v28数字选择不同的签名算法,最后再转为String,即得到签名sg的值:
◆v28大于5,使用SHA1算法签名,即:SHA1(a3+sgk_sel+sgsk_sel+长度)
◆v28小于5,使用MD5算法签名,即:MD5(a3+sgk_sel+sgsk_sel+长度)
基于上述分析,就可以编写一个简单的python request请求。通过请求就能获取到正确的返回数据了:

看雪ID:Aimees

https://bbs.kanxue.com/user-home-978841.htm

*本文为看雪论坛优秀文章,由 Aimees 原创,转载请注明来自看雪社区

# 往期推荐

1、ELF文件脱壳纪事

2、Glibc-2.35下对tls_dtor_list的利用详解

3、对旅行APP的检测以及参数计算分析【Simplesign篇】

4、2023强网杯warmup题解

5、Directory Opus 13.2 逆向分析

6、Pwn-oneday题目解析

球分享

球点赞

球在看

点击阅读原文查看更多


文章来源: https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458548774&idx=1&sn=fbc9f2f77b85f8e318cee3879cb4e117&chksm=b18d4aac86fac3bad991492153a16c52a058e38cbddae6cd816e6d993e462802f94df667078d&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh