某成人app分析
本帖最后由 Arcticlyc 于 2023-5-3 23:52 编辑## 声明
##### 文章中所有内容仅供学习交流,不得用于其他任何目的,文中敏感内容已做脱敏处理,严禁用于商业和非法用途,否则由此产生的一切后果与作者无关。如有侵权,请联系作者立即删除。
## 简介
这里讲到的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 多个结果,选择一个进去看看。
可以看到这里调用了一个 decryptFromBase64 方法,并传入了三个参数,待解密字符、key和iv,点击进入获取key或者iv的方法中。
可以看到这个类调用了 so 文件中的方法,尽管如此,我们并不需要去分析 so 文件,因为它只是用来获取密钥和iv值,而加密并不在其中进行。那么可以直接尝试 hook 这个类中的方法,经过检验,所有的key和iv都是固定值,可以直接得到。
现在可以试一试对刚才的响应进行解密。可是这里有这么多组密钥,该用哪个呢,从前面的分析可以明显看出,不知道的话就每个试一试就行了。
解密成功,那么这组密钥应该就是用于加解密请求和响应数据了,加密使用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" 的生成方法
可以看到,首先是在treemap对象中(这里可以理解为一个json对象)加入了一个参数 k ,获取treemap对象的 md5 值作为参数 s 的值,然后将其中的 k 删去,最后将整个对象进行加密后作为参数 d 的值。这里不进行具体展示,**需要注意的是,json中的参数顺序需要自行调整,参数顺序不同也会导致最终的 s 值不同,从而导致请求失败。** 但是现在还有一个问题:k 又是什么。很明显,它是我们在获取加密方法时其中的一个密钥。
###### 到这里我们已经可以成功构建请求并获取响应结果,但是本次分析并没有到此结束。因为,它不仅对请求进行了加密,而且将最重要的部分(图片和视频)也进行了加密。
## 图片和视频的获取
通过上面的分析,我们可以成功获取到明文响应了,然而当你对获取到的视频和图片进行请求时,会发现得到的内容根本无法查看,因为它们都是加密的。
app提供了视频下载功能,但是肯定也是加密的了。
现在就知道之前获取到的那么多密钥有啥用了。
这部分并未进行详细的分析,光看密钥的名字也能知道哪个用于解密视频了。经过检验,视频的解密采用AES-ECB模式,图片采用AES-CBC模式,key和iv值在之前已经获取到了,这里不再赘述。
需要注意的是视频是 m3u8 格式,但是下载 m3u8 的源码很容易找到(github),就不需要自己重新写了,只需要对获取到的结果进行解密就行。而且貌似视频和常规请求不一样,并不验证请求头(是否可以绕过vip限制直接获取呢?这里不做分析)。
## 部分代码展示
```python
def encrypt_data(self, data=''):
'''请求头和参数加密方法'''
if data:
_data = {**data}
else:
_data = {
"Connection": "close",
"app": "1",
"k": self.mv,
"platform": "1",
"t": int(time.time()*1000),
"token": '',
"version": "2.9.3.8",
"versionapi": "2.9.3.8"
}
if 'token' in _data and self.token:
_data['token'] = self.token
sign = hashlib.md5(json.dumps(_data, separators=(',', ':'), ensure_ascii=False).encode()).hexdigest()
_data['s'] = sign
# print(sign)
_data.pop('k')
d = self.aes.encrypt(json.dumps(_data, separators=(',', ':')))
res = {'d': d}
return res
```
再贴两张效果图
## 结语
也许你会问剩下的密钥有啥用呢?我也不知道,反正目前用不到。 frankwugo 发表于 2023-4-30 13:33
楼主为什么不公布APP。我不相信这是你的技术,要不你公布下APP 我来实验下?
果酱视频,原名茄子视频 你翻评论找成品的样子很狼狈(doge) 我是为我朋友看的,我看这玩意干啥 我一直以为我学的没用处,直到看到这篇教程才明白,书到用时方恨少{:1_906:} 我朋友让我问一下有没有解密后的成品因为他实在是太菜了不会弄。。{:301_98. 成功实现利用成人两字获得点击量的效果 翻了54页,没有找到干货。{:1_909:} 可惜看到得太晚了,已经充值永久VIP{:1_909:} 我朋友让我问一下有没有解密后的成品因为他实在是太菜了不会弄 Arcticlyc 发表于 2023-5-2 11:38
哈哈,我担心发出来会违规呢
我的建议是 私发给我 帮你看看技术到位了没有 真心牛逼。。。。。。。。。。 满怀期待的进来,一脸懵逼的出去,书到用时方恨少啊! 朋友,可不可以借一步说话,我有个朋友想问问 我朋友让我问一下有没有解密后的成品因为他实在是太菜了不会弄 这东西还是少看的好,看多了伤身体。 这评论量有东西:lol 我有个朋友想学习一下{:301_1004:} 我有个朋友想问问 我朋友让我问一下有没有解密后的成品因为他实在是太菜了不会弄,私发我{:1_887:} 我有一个朋友想知道更详细的步骤