文章中所有内容仅供学习交流,不得用于其他任何目的,文中敏感内容已做脱敏处理,严禁用于商业和非法用途,否则由此产生的一切后果与作者无关。如有侵权,请联系作者立即删除。
简介
这里讲到的app已经有些年头了,期间改过一次名字。
5p6c6YWx6KeG6aKR77yM5Y6f5ZCN6IyE5a2Q6KeG6aKR
经检测,app对常规接口的请求头和请求参数均进行加密,图片和视频同样经过加密处理。这里主要探讨它的数据是如何加密的。
抓包分析
使用Charles + 雷电模拟器成功捕获到应用的数据包,这里大概讲解下流程。
1) 打开app时,首先检测域名的有效性(有多个域名),如果域名有效,则接下来的请求都采用该域名进行,在app中则表现为切换有效线路。
https://域名/domain/check
2) 进行账号初始化,app在打开后就会自动注册一个账号,账号与设备特征绑定,每次打开app都会通过设备信息自动登录账号。
https://域名/api/account/init
3) 接下来就主要是加载广告和一些其他功能,这里不做过多介绍,其中包含一个获取用户信息的请求
https://域名/api/user/read
我们随便查看一个请求的内容
{
"d": "OCZVDwF7iM0DWJzQ0nQ5zk**************9YCdyHCSRPaWq5q+DjAbGEmhH4="
}
发现请求进行了加密。经过分析,这种加密存在于三个地方,分别是请求头,请求体和响应体中,且全部是以 {"d": "**"} 的形式存在。因此想要进一步分析,首先需要对它进行解密。猜测应该是 AES 或者 DES 加密。
寻找加解密方法
首先查看 apk 文件,没有加固,获取加密方法可以使用算法助手捕获或者使用 frida 进行 hook 。第一种方法非常简单,这里讲解第二种方法,使用 jadx 打开 apk ,等待加载完成后,直接搜索关键字。由于这里的请求和响应都完全加密了,选择搜索含 decrypt 的方法看看有没有结果,搜索出来有 20 多个结果,选择一个进去看看。
1.png (82.92 KB, 下载次数: 0)
下载附件
2023-4-28 19:38 上传
可以看到这里调用了一个 decryptFromBase64 方法,并传入了三个参数,待解密字符、key和iv,点击进入获取key或者iv的方法中。
2.png (44.69 KB, 下载次数: 0)
下载附件
2023-4-28 19:38 上传
可以看到这个类调用了 so 文件中的方法,尽管如此,我们并不需要去分析 so 文件,因为它只是用来获取密钥和iv值,而加密并不在其中进行。那么可以直接尝试 hook 这个类中的方法,经过检验,所有的key和iv都是固定值,可以直接得到。
现在可以试一试对刚才的响应进行解密。可是这里有这么多组密钥,该用哪个呢,从前面的分析可以明显看出,不知道的话就每个试一试就行了。
3.png (176.58 KB, 下载次数: 0)
下载附件
2023-4-28 19:38 上传
解密成功,那么这组密钥应该就是用于加解密请求和响应数据了,加密使用AES-CBC模式。其他的密钥暂时用不到,我们继续向下分析。
构造请求获取响应
上面讲到过,请求头、请求体和响应都进行了加密,现在进行请求的复现并获取响应结果。
1) 首先是请求头
我们随便查看一个请求,这里只关注请求头中的这个参数。
{"d": "suh8B7nUE**********/1aPQQTtYbFMu9Hb15pmTQdF+"}
我们使用刚才获取到的key和iv对它解密
{
"Connection": "close",
"app": "1",
"platform": "1",
"s": "84f24a********76f0a2b2c893",
"t": "168154******",
"token": "bmFXcHBmem**********zcll1czE=",
"version": "2.9.4.0",
"versionapi": "2.9.4.0"
}
可以看到,除了一些固定值外,其中有几个关键参数,s、t和token,t肯定是时间戳了,token猜测是用户的token,应该是登录时的返回值(在上文中的账号初始化时也会返回),那么剩下的 s 肯定是一个校验参数了,这里我们先不管,继续往下分析。
2) 再来查看请求体
随便查看一个请求并解密
{"d": "rSu3V/LPjWmPLMiaMIva********7BaN++p3ltjyYwGbF4gfUkOe7VTBzAk7/aJfABhc7YRgzlQ"}
{
"channel": "1",
"s": "94fa296fb******0bcca3ec",
"t": "168154*******",
"terminal": "0"
}
发现同样存在参数 t 和 s ,其中t是时间戳,s 随时在变化。那么只要找到 s 的生成方法,我们就可以自己发送请求并获得响应了。
3) 参数 s 的生成
使用mt管理器解析dex文件后,搜索上面请求中的关键字,可以查看参数 "s" 的生成方法
4.jpg (220.05 KB, 下载次数: 0)
下载附件
2023-4-28 19:38 上传
可以看到,首先是在treemap对象中(这里可以理解为一个json对象)加入了一个参数 k ,获取treemap对象的 md5 值作为参数 s 的值,然后将其中的 k 删去,最后将整个对象进行加密后作为参数 d 的值。这里不进行具体展示,需要注意的是,json中的参数顺序需要自行调整,参数顺序不同也会导致最终的 s 值不同,从而导致请求失败。 但是现在还有一个问题:k 又是什么。很明显,它是我们在获取加密方法时其中的一个密钥。
到这里我们已经可以成功构建请求并获取响应结果,但是本次分析并没有到此结束。因为,它不仅对请求进行了加密,而且将最重要的部分(图片和视频)也进行了加密。
图片和视频的获取
通过上面的分析,我们可以成功获取到明文响应了,然而当你对获取到的视频和图片进行请求时,会发现得到的内容根本无法查看,因为它们都是加密的。
app提供了视频下载功能,但是肯定也是加密的了。
现在就知道之前获取到的那么多密钥有啥用了。
这部分并未进行详细的分析,光看密钥的名字也能知道哪个用于解密视频了。经过检验,视频的解密采用AES-ECB模式,图片采用AES-CBC模式,key和iv值在之前已经获取到了,这里不再赘述。
需要注意的是视频是 m3u8 格式,但是下载 m3u8 的源码很容易找到(github),就不需要自己重新写了,只需要对获取到的结果进行解密就行。而且貌似视频和常规请求不一样,并不验证请求头(是否可以绕过vip限制直接获取呢?这里不做分析)。
结语
也许你会问剩下的密钥有啥用呢?我也不知道,反正目前用不到。