某右sign-v2签名算法追踪及逆向还原

可以看到 请求中"sign=v2-xxxxxxxxxx"老样子 拖入ida中分析 进行字符串搜索"sign="

第四个看起来比较像 双击字符串进入

按下快捷键X

只有一处 我们还是双击进入

继续按下快捷键X

从函数名来看的话"-[ZYURLRequest obtainMostSuitableRequest]"比较像 此处没什么捷径 只能通过看哪个函数名像 如果选错了就会浪费些时间

双中双击进入 直接F5查看伪代码

可以看到通过传参调用"+[libProtocol sign_data:]"函数来进行签名的 参数又是通过传参调用"+[libProtocol encode_aes:]"得到的

1

2

3

4

5

v240 = +[libProtocol encode_aes:](&OBJC_CLASS___libProtocol, "encode_aes:", v239);

v241 = objc_retainAutoreleasedReturnValue(v240);

v242 = +[libProtocol sign_data:](&OBJC_CLASS___libProtocol, "sign_data:", v241);

v243 = objc_retainAutoreleasedReturnValue(v242);

v249 = objc_msgSend(&OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("?sign=%@"), v243);

直接HOOK

1

2

3

4

5

6

7

8

9

10

11

12

13

14

%hook libProtocol

+ (id)encode_aes:(id)arg1 {

  %log;

  id result = %orig;

  HBLogDebug(@"[Hook] libProtocol encode_aes] ret: %@", result);

  return result;

}

+ (id)sign_data:(id)arg1 {

  %log;

  id result = %orig;

  HBLogDebug(@"[Hook] libProtocol sign_data] ret: %@", result);

  return result;

}

%end // hook libProtocol class end

日志打印如下

先复制出encode_aes的参数 保存hex查看

可以看到参数是明文的 既然是aes加密那就需要key 至于key是什么 如何产生的我们后面再来分析

我们先进入内部查看签名算法是如何实现的 F5代码如下:

关注点在一个函数"MD5String" 先来看下参数是什么

1

2

3

4

5

6

7

8

9

v3 = objc_retain(a3, a2);

v4 = (void *)objc_retainAutorelease(v3);

v5 = objc_msgSend(v4, "bytes");

v6 = objc_msgSend(v4, "length");

v7 = (size_t)v6;

v8 = (void **)operator new(((unsigned __int64)v6 + 16) & 0xFFFFFFFFFFFFFFF0LL);

memcpy(v8, v5, v7);

v28 = v8;

MD5String(&v28);

相信看到这里各位已经明白了参数是什么 参数就是aes加密后的数据 只是做了层转换 从NSData转为byte 根据函数名得知该算法是md5

那么直接编写代码进行测试

1

2

3

4

5

= bytes.fromhex('8a07d175 47300202 02ead3bc bcbca5a5 19b21e13 1186e096 2a467fa5 661081c1 65d014f7 2a74a7bf 333c2a27 5937de20 25d2c4f9 c232a50a 3e90affc 319ca0ee b0e34df3 016bf74d a231d5da 41fde907 f6242573 f20d38d2 86e61d42 0487db3b bf029d65 a0733533 198b6194 63db3d3c fe234f84 7dcdee21 2521ab89 7f48e3f2 5d002559 7b5e814b 55fe2581 bec64b24 5082bd16 9910e2f8 e24cf3e8 e4346e3c 40f43237 cc75baff 0d97aea6 9f4c04d9 8f6d9f5f 91c31faa dbbda58d 13664d3a f5d7dd77 625f3559 91e74de9 4fcb3149 f9d54897 b2ac8ee4 2a613df6 cbdeda5e 98c9ba39 cdd717f9 19e7cbad 42c171d6 03d09daa b42aa123 66da3320 eddaf432 b655cc97 93280ee9 94687272 7d724658 8492a7b3 8b6ae9a7 bd33d63f 1f122155')

md5 = hashlib.md5()

md5.update(d)

print(md5.hexdigest())

# f94fd832969b8655eab3078e924b989e

结果发现计算结果不对

好吧 看来它并不是简简单单的MD5算法了 大概率是魔改过的md5算法

那么直接上手 先看下MD5String调用了多少函数

也没几个函数 那么就不管他改了什么 直接上手还原算法吧 当然你也可以下载MD5算法源码进行调试对比算法差异

以下是还原出的算法 直接放源码 由于算法过长 论坛发帖无法放下 所以直接放到附件里了

OK 结果跟手机上算出的一致  到这里sign-v2算法就还原完了

至于AES加密中key的来源 我们大概看下 后续有时间的话我会在帖子中补充

在之前我们Hook了 +[libProtocol encode_aes:] 我们直接在IDA中搜索一下类名"libProtocol"

set_portocol_key和get_portocol_key 看起来比较像设置key和获取key的函数 我们直接Hook

日志打印如下

抓包工具如下

抓包工具对比 可以看到加密key 在Headers["X-Xc-Proto-Req"]字段中 通过调用[libProtocol get_protocol_key]函数获取

而request data为[libProtocol encode_aes]加密后的数据  那么具体aes key是如何产生的呢 这个容我日后再做分析

可以看到response headers['X-Xc-Proto-Res'] 也有疑似加密key的数据

截图对比 [libProtocol set_protocol_key] 设置的参数为respnose headers['X-Xc-Proto-Res']字段的数据

截取response data hex数据查看对比 可以看到[libProtocol decode_aes]参数就是请求返回的数据 而且[libProtocol decode_aes]函数返回的数据是明文数据

最新版本的变化有两处

1.新增了"sign-v2"算法

2.request data 以及 response data 内容进行了加密

OK 我们直接来抓包 具体如何抓包上篇文章有讲 就不在此具体描述了

可以看到 请求中"sign=v2-xxxxxxxxxx"老样子 拖入ida中分析 进行字符串搜索"sign="

第四个看起来比较像 双击字符串进入

按下快捷键X

只有一处 我们还是双击进入

继续按下快捷键X

从函数名来看的话"-[ZYURLRequest obtainMostSuitableRequest]"比较像 此处没什么捷径 只能通过看哪个函数名像 如果选错了就会浪费些时间

双中双击进入 直接F5查看伪代码

可以看到通过传参调用"+[libProtocol sign_data:]"函数来进行签名的 参数又是通过传参调用"+[libProtocol encode_aes:]"得到的

1

2

3

4

5

v240 = +[libProtocol encode_aes:](&OBJC_CLASS___libProtocol, "encode_aes:", v239);

v241 = objc_retainAutoreleasedReturnValue(v240);

v242 = +[libProtocol sign_data:](&OBJC_CLASS___libProtocol, "sign_data:", v241);

v243 = objc_retainAutoreleasedReturnValue(v242);

v249 = objc_msgSend(&OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("?sign=%@"), v243);

直接HOOK

1

2

3

4

5

6

7

8

9

10

11

12

13

14

%hook libProtocol

+ (id)encode_aes:(id)arg1 {

  %log;

  id result = %orig;

  HBLogDebug(@"[Hook] libProtocol encode_aes] ret: %@", result);

  return result;

}

+ (id)sign_data:(id)arg1 {

  %log;

  id result = %orig;

  HBLogDebug(@"[Hook] libProtocol sign_data] ret: %@", result);

  return result;

}

%end // hook libProtocol class end

日志打印如下

先复制出encode_aes的参数 保存hex查看

可以看到参数是明文的 既然是aes加密那就需要key 至于key是什么 如何产生的我们后面再来分析

我们先进入内部查看签名算法是如何实现的 F5代码如下:

关注点在一个函数"MD5String" 先来看下参数是什么

1

2

3

4

5

6

7

8

9

v3 = objc_retain(a3, a2);

v4 = (void *)objc_retainAutorelease(v3);

v5 = objc_msgSend(v4, "bytes");

v6 = objc_msgSend(v4, "length");

v7 = (size_t)v6;

v8 = (void **)operator new(((unsigned __int64)v6 + 16) & 0xFFFFFFFFFFFFFFF0LL);

memcpy(v8, v5, v7);

v28 = v8;

MD5String(&v28);

相信看到这里各位已经明白了参数是什么 参数就是aes加密后的数据 只是做了层转换 从NSData转为byte 根据函数名得知该算法是md5

那么直接编写代码进行测试

1

2

3

4

5

= bytes.fromhex('8a07d175 47300202 02ead3bc bcbca5a5 19b21e13 1186e096 2a467fa5 661081c1 65d014f7 2a74a7bf 333c2a27 5937de20 25d2c4f9 c232a50a 3e90affc 319ca0ee b0e34df3 016bf74d a231d5da 41fde907 f6242573 f20d38d2 86e61d42 0487db3b bf029d65 a0733533 198b6194 63db3d3c fe234f84 7dcdee21 2521ab89 7f48e3f2 5d002559 7b5e814b 55fe2581 bec64b24 5082bd16 9910e2f8 e24cf3e8 e4346e3c 40f43237 cc75baff 0d97aea6 9f4c04d9 8f6d9f5f 91c31faa dbbda58d 13664d3a f5d7dd77 625f3559 91e74de9 4fcb3149 f9d54897 b2ac8ee4 2a613df6 cbdeda5e 98c9ba39 cdd717f9 19e7cbad 42c171d6 03d09daa b42aa123 66da3320 eddaf432 b655cc97 93280ee9 94687272 7d724658 8492a7b3 8b6ae9a7 bd33d63f 1f122155')

md5 = hashlib.md5()

md5.update(d)

print(md5.hexdigest())

# f94fd832969b8655eab3078e924b989e

结果发现计算结果不对

好吧 看来它并不是简简单单的MD5算法了 大概率是魔改过的md5算法

那么直接上手 先看下MD5String调用了多少函数

也没几个函数 那么就不管他改了什么 直接上手还原算法吧 当然你也可以下载MD5算法源码进行调试对比算法差异

以下是还原出的算法 直接放源码 由于算法过长 论坛发帖无法放下 所以直接放到附件里了

OK 结果跟手机上算出的一致  到这里sign-v2算法就还原完了

至于AES加密中key的来源 我们大概看下 后续有时间的话我会在帖子中补充

在之前我们Hook了 +[libProtocol encode_aes:] 我们直接在IDA中搜索一下类名"libProtocol"

set_portocol_key和get_portocol_key 看起来比较像设置key和获取key的函数 我们直接Hook

日志打印如下

抓包工具如下

抓包工具对比 可以看到加密key 在Headers["X-Xc-Proto-Req"]字段中 通过调用[libProtocol get_protocol_key]函数获取

而request data为[libProtocol encode_aes]加密后的数据  那么具体aes key是如何产生的呢 这个容我日后再做分析

可以看到response headers['X-Xc-Proto-Res'] 也有疑似加密key的数据

截图对比 [libProtocol set_protocol_key] 设置的参数为respnose headers['X-Xc-Proto-Res']字段的数据

截取response data hex数据查看对比 可以看到[libProtocol decode_aes]参数就是请求返回的数据 而且[libProtocol decode_aes]函数返回的数据是明文数据

至此某右的请求及返回数据的加密与解密流程分析完毕 至于aeskey是如何生成的就留到下次分解了 有时间的话我会再编辑到本篇文章末尾

至此某右的请求及返回数据的加密与解密流程分析完毕 至于aeskey是如何生成的就留到下次分解了 有时间的话我会再编辑到本篇文章末尾

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值