xxxx签名算法逆向&&python脚本实现
前言
人生中第一次被公关,不提软件的名字了~~~
本文分析一下在 重置密码时对 数据包 进行签名来防篡改的方案。
正文
burp抓取htttps数据
首先导入 burp 证书到手机, 装上 xposed , 然后安装
|
|
这个插件应该就可以抓到 https 数据了。
然后触发 找回密码 逻辑,抓包

这里有一个 sign 的参数,可以推测这个是用来 保存签名的参数。
如果正常发送的数据包得到的响应类似于下面(这里是验证输错的情况)
如果重放数据包

经过测试发现 _r 参数用于标识数据包的唯一性,如果修改其他的字段会提示 重复的 URL, 但是如果修改了 _r, 则会提示 URL签名错误

于是大概可以推测服务端校验请求的流程
- 拿到
_r判断是否是重复的请求 - 计算请求的 签名,与签名字段进行校验
- 如果前面两步均通过,服务端则认为数据包没有被篡改,于是开始校验 验证码。
定位关键代码
我列举一下我用了的方法
搜参数名
程序中可能会用到参数的名称来设置参数的值,因为我的目标是分析签名算法,sign 这个参数名这么的明显,就搜他了。

发现太多的文件里面有这个关键字,不可用
搜 url 路径
观察抓到的数据包,发现它是向 /api/open/v2/forgot-password/check.htm 发起了 POST 请求。
这个貌似靠谱,可以追踪到进行请求的代码,于是我从第一个结果开始分析,一路往下,追踪,大概搞清楚了发送 请求的流程,以及一些参数的得到方式,但是貌似是看花眼了,而且程序的混淆强度比较大,没用找到 _r 和 sign 设置位置。 于是开始了其他的定位尝试
监控 系统层的 加密类和方法
进行签名常用的方案就是 对待签名数据,算 hash 或者 用一些加密算法。于是想着是不是可以通过监控 java 层常用的 加密 api 来定位 算法。
|
|
找到了这个插件, 通过 hook 的方式来监控, 同时会在 /sdcard/ydsec/包名.txt 留下日志。

试了试,发现也没有找到相关的数据,通过这样的方式被加密,于是推测应该是自己实现了相关的加密算法。
再次搜参数名
忽然想起,参数名如果在程序中被使用的话应该是直接存在于程序中的, 然后 smali 代码引用字符串 会加上 " 来包裹字符串
开始了另一种搜索尝试

发现搜 "sign" 和 "sign 得到的结果不多,但是貌似都不太相关,倒是 "_r" ,就两个结果。
想起 既然 _r 用于标识请求的唯一性,那么签名肯定是要用到它的,而且 _r 应该没次都是随机生成的,那么用到它的位置,应该离 生成 sign 的位置不远了。
进入第一个结果的代码(程序太大了,jeb打不开之前的我分析时的数据,只能重新看没有命名函数名的了)

可以知道 _r 通过
|
|
生成随机字符串,来保证数据包不被重放
生成 _r 后 ,会调用 a.N ,其中会调用 aa.ao ,跟进去看看

根据 URL(url) 可以确定 ,第一个参数是一个 url, 接着对 url 上的参数进行了处理。
然后定位 sign 参数的起始位置
接着删除了 sign 参数

然后重新生成 sign 参数

调用了 Riddle.s 生成了 sign 参数,传入的参数是 处理后的 url_path 和 签名用的 key 。
Riddle.s 是一个 native 方法, 在 libtnpn.so 里面,去 lib\armeabi目录下找就是了。


拖进 ida 发现 so 倒是挺友好的 ,没有混淆。

进入 Java_cn_mucang_android_core_jni_Riddle_s, 这就是 Riddle.s 方法在 so 中的命名,jni 函数的第一个参数类型为 JNIEnv_ * , 首先 需要导入 jni.h , 然后设置一下类型便于分析。

首先就是把传入的 参数变成 c 语言中的字符串类型,然后根据 key 的格式判断, 使用哪种签名方案,经过调试重置密码用的 key 为 *#06#i3lrRYudcZZ2fIx9fI6VqJV8
所以会调用
跟进到 SignUrl1

首先对 key 进行解密,然后进入 j_j_SignUrl0

流程很清晰,就是 拼接 path 和 解密后的 key, 然后计算 md5, 存在 a3 地址,回到 SignUrl1

接着又对传入的 没有被解密的key 来了一个求和,然后进入
|
|
这个函数有点复杂,我是直接抠了出来,用 python 重写了。先继续看后面。
把 v11 的值 附加到 之前刚刚计算好的 md5 的数值后面,v11 来自于 v14, 而 v14 并没有设置的地方,这里是 IDA F5 识别错了。直接看汇编把。

实际上 v14 就是调用 calc_sum 后的 r1 寄存器。
跟进到 sub_788640D4

首先对传入的参数和 lr 进行了保存,然后调用 sub_78864000 , 然后用之前保存的参数值 与 sub_78864000 的返回值进行运算,结果保存到 r1(专门用来迷惑 ida ^_^).
伪代码:
sub_78864000 看起来比较复杂,我就直接用 python, 照着重写了一遍。

其中有一个有意思的地方: ida 无法 对 clz 指令进行转换,所以用

表示

这使得重写造成了困扰,我的解决办法是,根据 clz 的作用,自己实现。

实现的 python 代码如下:
|
|
本站文章均原创, 转载注明来源
本文链接:http://blog.hac425.top/2018/03/15/jiakao_rev.html