某数和某5秒-反混淆动态注入调试的一种方案
@(某数和某5秒-反混淆动态注入调试的一种方案)本篇文章主要讲述使用mitmproxy进行代码注入的一种方案,可以解决动态js和加密js的情况,本篇主要使用两个案例来展示。js逆向分析相关的在本篇文章中不会详细说,因为关系不大。本篇文章参考以下内容
(https://www.52pojie.cn/thread-1208999-1-1.html)
(https://blog.csdn.net/weixin_43411585/article/details/122142433)
(https://www.52pojie.cn/thread-1500547-1-1.html)
(https://www.52pojie.cn/thread-1595155-1-1.html)
某数的动态js,每次访问返回的都是不同的js,使用无痕模式打开浏览器,打开f12里面,选中事件监听断点中的脚本
![在这里插入图片描述](https://img-blog.csdnimg.cn/2827c0e569e6451ea7f2329f5c978005.png#pic_center)
此时打开网页可以看到如下的类型的代码
![在这里插入图片描述](https://img-blog.csdnimg.cn/f56016e19eae41ceb1ed900f40fc68fb.png?)
按照前面的思路,那么就是先把代码拿到手,然后进行反混淆,再讲反混淆后的代码设置回响应。这次依然是使用mitmproxy进行拦截,使用ast进行反混淆并添加断点
![在这里插入图片描述](https://img-blog.csdnimg.cn/27ce395febc74dbf8b3e9018c1b100f8.png?)
此时调试代码就比较方便了,也不用再去设置事件监听断点。,下一步可以在eval.call前面找到已经组装好的第二层代码,接下来就是进入vm了。
![在这里插入图片描述](https://img-blog.csdnimg.cn/0a04a2cc4b7a4ebab09f5260d007e0c5.png?)
如果要将这里面的代码进行反混淆,还是一样需要先把代码拿到手,也就是说需要主动执行第一层的代码,然后拿到第二层的代码,此时将代码反混淆后,在第一层代码合适的地方,用反混淆后的代码替换掉原来第二层的代码。
![在这里插入图片描述](https://img-blog.csdnimg.cn/159f433adfde48d3b40953f0554911d4.png?)
这样就可以反混淆vm里面的代码里面的任意地方加上断点来调试,整体代码如下
```python
def response(flow: http.HTTPFlow):
if 'new_house.html' in flow.request.url:
# 拦截首层html
print('数据拦截', flow.request.url)
with open('new_house.html', 'wb') as f:
f.write(flow.response.content)
# 反混淆第一层,并注入代码,等待生成第二层
os.system('node astfangdi_init')
print('首次处理完成')
# 主动执行生成第二层代码
nodejs = os.popen('node fangdi_init')
jscode = nodejs.read().replace('\n', '')
nodejs.close()
with open('fangdi_init.json', 'w', encoding='utf-8') as f:
f.write(jscode)
print('二层代码获取完成')
# 反混淆第二层代码
os.system('node astfangdi2')
print('二层代码反混淆完成')
# 反混淆第一层代码,并注入前面生成的第二层代码
os.system('node astfangdi')
with open('new_house_decrypt.html', 'rb') as f:
htmlcon = f.read()
flow.response.set_content(htmlcon)
print('首层代码注入完成')
```
然后是某5秒的加密js,还是使用无痕模式打开浏览器以及选中事件监听断点中的脚本
![在这里插入图片描述](https://img-blog.csdnimg.cn/f40808e0de1942298c3a95e5d20503b5.png?)
会断在一个_cf_chl_opt的参数上面,然后会请求一个jsch/v1的接口
![在这里插入图片描述](https://img-blog.csdnimg.cn/920e38b5f17c46a0a35a23c72b74438e.png#pic_center)
返回的是一段带有ob混淆的内容,脚本断点会在解密后执行时断下
![在这里插入图片描述](https://img-blog.csdnimg.cn/500d33702ce644aebcd2d29c720013a0.png?)
这个的拦截就和之前是一样的了,直接可以替换掉。不是说有加密的js吗?那么继续往下看。
![在这里插入图片描述](https://img-blog.csdnimg.cn/b9eee3602d1c4188998aa9e9e162a69c.png#pic_center)
后面还会接着请求一个flow/ov1这样的接口,里面的请求体和响应体就是加密了的,当然,准确来说不是加密,后面会说到。
![在这里插入图片描述](https://img-blog.csdnimg.cn/11672294e10748f694f1250e42a82620.png?)
![在这里插入图片描述](https://img-blog.csdnimg.cn/5357dbc1a9f64f1fae6bf9e952dce529.png?)
这里解密后会使用function的构造函数进行代码。
![在这里插入图片描述](https://img-blog.csdnimg.cn/ea36fb60a79a417c920ac174f949aa9a.png?)
这里也是有ob混淆的代码,这里想要拦截反混淆就不是这么简单了,因为返回的是加密了的代码,如果想要反混淆,那么就必须先解密代码。而这里又衍生出一个问题,就算我解密反混淆后,还是不能直接把响应设置进去,因为原本代码是加密的,我直接设置没有加密的代码,那么网页肯定会报错的。
那么这里在原来的基础上,还要多两步,就是把js解密,和重新加密回去。如何找到解密的函数这里就不详细说了,逻辑比较简单,那么就可以直接改成python的代码来解密
```python
data64 = base64.b64decode(flow.response.content)
x = reduce(lambda n, m: n ^ m, + list((cRay + "_0").encode()))
dedata = bytes([((data64 & 255) - x - A % 65535 + 65535) % 255 for A in range(len(data64))])
```
这里的dedata 就是得到的js明文,接下来就可以愉快的对代码进行反混淆了,那么怎么加密回去呢,这里其实就是一个反向运算。举个简单的例子就是解密是减去1,那么加密就是加上。如果解密是乘以x,那么加密就是除以x。加密的代码如下
```python
endata = bytes([((dedata) - 65535 + (A % 65535) + x) % 255 for A in range(len(dedata))])
flow.response.set_content(base64.b64encode(endata))
```
这样就可以把反混淆的代码设置回去了
![在这里插入图片描述](https://img-blog.csdnimg.cn/0159ff72d08340d3a3283dda631bbc81.png?)
这样就可以得到反混淆后的vm代码。调试起来就相对简单了一些,这个是响应体,那请求体也加密了。如果想看看请求的时候提交了什么,或者直接修改请求体的话,那是类似的逻辑,需要先解密,然后再加密才能设置回去。这里主要说一下加密的内容,其实说加密不太准备,应该说只是一个压缩方法。
![在这里插入图片描述](https://img-blog.csdnimg.cn/518d025af6f145fc8de3f977f1e7e97d.png?)
这里的逻辑其实就是lzstring的压缩算法,python中也有lzstring这个库,但是不能直接使用,因为这里使用的是非标准的base64编码表,需要对源码进行部分修改
![在这里插入图片描述](https://img-blog.csdnimg.cn/3ab194626b36497d9ce9016d696e5bd6.png#pic_center)
这样我们就可以随时对请求体和响应体拦截,不断的对比本地生成的数据和网页提交的数据的差别来生成我们的本地环境,mitmproxy的学习到此就结束啦。 本帖最后由 ghd19940802 于 2022-3-8 11:14 编辑
shayu2021 发表于 2022-3-8 09:18
再次谢谢帮助,整好了。
不客气 PHP我不是很懂
备份下我的
<?php
function getMmsKey($e) {
$t = 185025305;
$n = rotateRight($e, $t % 17);
return yihuo($n, $t);
}
function rotateRight($e, $t) {
for ($r, $n = 0;$t > $n;$n++) {
$r = 1 & $e;
$e = rr($e, 1);
$r = ll($r, 31);
$e = $e + $r;
}
return $e;
}
function rr($v, $n) {
$v = $v & 0x80000000 ? $v | 0xFFFFFFFF00000000 : $v & 0xFFFFFFFF;
return $v >> ($n & 0x1F);
}
function ll($v, $n) {
$t = ($v & 0xFFFFFFFF) << ($n & 0x1F);
return $t & 0x80000000 ? $t | 0xFFFFFFFF00000000 : $t & 0xFFFFFFFF;
}
function yihuo($a, $b) {
$c = ($a ^ $b) & 0xffffffff;
if ($c & 0x80000000) $c-= 0x100000000;
return $c;
}
echo getMmsKey(time());
?> 本帖最后由 ghd19940802 于 2022-3-7 18:14 编辑
shayu2021 发表于 2022-3-7 10:45
求大神解密一下这个视频,获取视频的地址加密的,解不了
http://www.le.com/ptv/vplay/31530669.html
获取视频页面ID http://www.le.com/ptv/vplay/31530669.html31530669就是ID
请求视频信息 http://player-pc.le.com/mms/out/video/playJson.json?platid=1&splatid=103&tss=ios&id=31530669&domain=www.le.com&tkey={{tkey}}&source=1001®ion=cn 关键参数tkey 需要配合JS加密时间戳生成
获取到各分辨率地址 拼接上http://play.g3proxy.lecloud.com{{r1080p}}&format=1&tzm={{tzm}}关键参数tzm 需要配合JS加密时间戳生成发送请求获得播放地址,只适用于免费视频, 收费视频应该需要大佬来我只会这些了 下面是加密算法
"1080p": [
"/vod/v2/Mjc4LzMxLzM0L2xldHYtdXRzLzE0L3Zlcl8wMF8yMi0xMTIyNTA0NTk0LWF2Yy0yOTkyMTc4LWFhYy0xMjgwMDAtNTcxNTU2MC0yMjM4MDk3MzEzLWM5ZDA1NjE0NWRkNjMyZDQzMjZjMDhmN2UxZmYxZDFiLTE1NDc5ODc1NzgyNDgubXA0?b=3132&mmsid=66909480&tm=1646647630&key=015af80874a1a468f55d8d23b875c839&platid=1&splatid=103&playid=0&tss=ios&vtype=52&cvid=996928022288&payff=0&pip=6c9d4734fbf9db5d668d8f59c592cbdf&xm=51386a1e98ff9e7872202c7b93526786",
"278/31/34/letv-uts/14/ver_00_22-1122504594-avc-2992178-aac-128000-5715560-2238097313-c9d056145dd632d4326c08f7e1ff1d1b-1547987578248.mp4"
],
function getMmsKey (e) {
var t = 185025305
n = rotateRight(e, t % 17);
return n ^ t
}
function rotateRight (e, t) {
for (var r, n = 0; t > n; n++) r = 1 & e, e >>= 1, r <<= 31, e += r;
return e
}
// postman命令 主要是上面的两个方法 自己改下
pm.environment.set("tkey", getMmsKey (Date.now() / 1000)); 漁滒牛呀{:1_919:}又有技术可以学了,关键还免费 感谢分享,楼主辛苦了! 渔哥开课吧:lol 开课啦,好好学习,天天向上,谢谢分享 学习了,多谢大佬分享 大佬牛逼 大神啊!求技术 大佬牛逼