案例为最新版某马拉雅,可在豌豆夹下载
抓包
发送验证码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
我们主要分析signature参数,signature长度为40,大概率为SHA1
逆向分析
发送验证码参数signature
首先搜索请求体字段中的fdsOtp定位关键代码
总共有三个,分别对应不同的登录形式,我们只关注验证码登录即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
可以发现signature参数的生成与代码
1 |
|
有关,追踪,最终定位到
最终定位到此处代码,发现需要分析so层实现内容(login_encrypt),为了更清楚的分析,我们需要先了解进入so层前传入的参数是什么形式,
打印传入的参数,内容为:
1 2 3 4 5 |
|
发现so层代码将近2500行,存在Ollvm混淆
我们从头开始分析代码
修正函数头之后,先分析前几行代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
|
可以看到存在一定程度的混淆,去除控制流垃圾
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
按照JNI模式解析,大概率为
1 2 3 4 |
|
查看一下对应的内存地址,是否为类名
可以看到字符串被混淆了,根据交叉引用寻找
发现存在解密代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
其他解密也是相同的,这样我们就知道了这个函数其实就是获取包名,脚本写为Idapython脚本更方便
发现都是进行比较,我们解密另一个参数即可,还是按照刚才的方法
1 2 3 4 5 6 7 8 |
|
可以看到所有的strcmp就是和硬编码的包名比较,所以我们需要找到对应的包名
最终是在一千一百多行发现
发现比较成功之后,会设置v13=1825021717,这个v13就是状态机,觉得下一步会执行什么代码,因此我们追踪if(v13==1825021717)的代码即可
这两个地址解密的数据为:
1 2 |
|
可以发现设置v13的状态为2590219376,继续跟进发现没有搜到,这时候可以切换为十六进制形式0x9A639C70发现找到了对应代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
所以我们继续跟进新的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
寻找有没有等于3581685779和909332025的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
所以我们现在需要追踪v240
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
状态转移:v240 存进 v223,状态 v13 = 493313113
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
这两个新状态都可以找到,一个是加密后检查,一个是加密,我贴上加密的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
全部解密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
可以看到进行了SHA1,现在我们需要搞清楚的就是
喂给 update 的 byte[] 是谁,digest 出来的 byte[] 是如何变成最终 sign
所以这时候重新考虑Hook
上面我们已经知道调用了java层的这么多方法,因此可以每个方法都试试,我这里选择的是hook toUpperCase
下面是输出
1 2 3 4 5 6 |
|
此时Signature参数的生成也很清晰了
1 2 |
|