jsvmp-洞察先机
一、前言
又是很长时间没更博客了,今天终于花时间把最后一题给解决了,至此猿人学赛题的学习基本告一段落,总的来说大部分题对我来说都很有挑战性,而每次解题过程中也会学到点新知识。目前的达到的水准是即使有些完全没思路的加密,看下其他大神分享的解题过程,基本上自己也能摸索着还原出来,虽然距离大佬们还有不小的差距,但相比起挑战习题最初的我来说,还算是有一定进步了。总之也算是完成了猿人学赛题的挑战目标,嗯,废话不多说,进入正题。
二、解析过程分析
首选进主页,发现这题内容上跟以往其他题没太大区别,都是抓取数字,不过这题明确说了是jsvmp加密,网上搜了一番也没找到比较好的教程资料,但总之可以确定的是加密很难破解,再就是可以确定加密代码是在虚拟机环境运行,不那么好调试。
打开调试模式,观察一下请求内容,发现请求第一页时没有加密参数,从第二页开始,url会携带t和v两个参数,这里v应该是加密字符串了。
继续观察请求主页源代码,发现这么一大串看着很费劲的js代码,推测加密参数应该就是在这里生成的。
一番调试后,发现最终请求数返回值是在执行完xml.open
这个函数后得到的:
xml.open('GET', location.href + 'data?page=' + page, true);
xml.open
其实就是混淆代码里的y__函数,也就是说加密参数应该是在这里生成的。
观察一下,变量u__
是一个数组,从其第二个元素里可以看到AES的字样,看出是用了AES加密。
虽然知道是什么加密,但是这里是真的很不好调试,没法像很多常规加密那样追踪调用栈来看AES加密前都调用了哪些函数,因为调试过程中大部分代码都会跳转回这个函数,这里参照了一个大佬分享的思路,即hook一下AES加密函数,在加密过程中打印出相关加密信息:
成功hook到加密函数以后,打印一下加密函数传进去的几个参数,然后发现待加密文本text的值是页码加一串有特殊规律的字符串,key和iv的值相同。
那么这些参数到底是怎么生成的呢,这个时候就可以看看调用栈了,查看调用栈往上走,进入这个_y__函数:
点击进入,跳转到了图下这一行,鼠标放在这里可以看出,被hook的加密函数就在这里。
找到加密位置以后,还是不太好观察参数都是怎么传进去的,于是在这里设置一个日志断点,让代码运行到这里的时候自动输出我们想要观察的参数。
然后当鼠标在主页滑动时,可以发现控制台会不停输出新的内容
结合前期调试时发现的u__
数组内的mouses
对象,可以确定这串数组内容就是鼠标的移动轨迹值,这个轨迹值是随机的,所以可以随便确定一组,跟请求页码组成待加密的text值。
确定text值以后,剩下的就是key和iv值的生成逻辑,这里有个简便方法是观察调试过程中日志断点里输出的内容,从这里可以看到一些可疑对象,比如调试过程中,输出了明显是时间戳的字符串,对时间戳做一定处理后,得到最终的key和iv值。
这里可以观察到,key和iv值明显是两个相同字符串的加和,而这个字符串又是基于时间戳转换而来,经过验证发现,这里实际上就是把时间戳转换为十六进制,去掉前两位0x后的结果,于是key和iv值也得以确定,这题的加密点也算是找出来了。
乍一看解析过程吧,感觉其实好像不难,但实际上最难的是处理思路,比如一开始能不能想到要hook AES函数,而在这之后又使用日志断点观察加密参数,这也是不熟悉调试工具的情况下很难想到的地方,如果这题靠常规的追调用栈去找加密逻辑,怕是搞到头秃都难以搞清加密逻辑。当然这仅是对于吾等入门级的人而言,可能高手会有更好地解法。
三、代码实现
弄清楚加密逻辑以后,代码实现就比较简单了,直接使用python的AES加密库就行:
from Crypto.Util.Padding import pad, unpad
from Crypto.Cipher import AES
import time
import base64
import requests
headers = {
'authority': 'match.yuanrenxue.com',
'pragma': 'no-cache',
'cache-control': 'no-cache',
'sec-ch-ua': '"Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36',
'sec-ch-ua-platform': '"Windows"',
'accept': '*/*',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'referer': 'https://match.yuanrenxue.com/match/18',
'accept-language': 'zh-CN,zh;q=0.9',
'cookie': 'Hm_lvt_c99546cf032aaa5a679230de9a95c7db=1635170677,1635258075,1635304521,1635306736; no-alert3=true; Hm_lpvt_c99546cf032aaa5a679230de9a95c7db=1635339533',
}
for i in range(1,6):
#构造有鼠标轨迹构成的text值,鼠标移动轨迹可以固定
text='{0}|756d354,756d354,756u354,756u354'.format(str(i))
byte_text = bytes(text, encoding="utf-8")#转换为字节形式
#将时间戳转换为KEY,iv
t = int(time.time())
iv=hex(t)[2:]*2
byte_iv=bytes(iv, encoding="utf-8")
byte_key=byte_iv
# 初始化加密器,使用CBC模式进行加密
cryptor =AES.new(byte_key, AES.MODE_CBC,byte_iv)
enc_result=base64.b64encode(cryptor.encrypt(pad(byte_text,16)))
params = (
('page', str(i)),
('t', str(t)),
('v', str(enc_result,'utf-8')),
)
response = requests.get('https://match.yuanrenxue.com/match/18data', headers=headers, params=params)
print(response.json())
请求输出结果如下:
{'status': '1', 'state': 'success', 'data': [{'value': 8944}, {'value': 4564}, {'value': 7199}, {'value': 8411}, {'value': 1811}, {'value': 2058}, {'value': 131}, {'value': 3398}, {'value': 115}, {'value': 3819}]}
{'status': '1', 'state': 'success', 'data': [{'value': 5183}, {'value': 7979}, {'value': 5907}, {'value': 5889}, {'value': 7532}, {'value': 5075}, {'value': 3963}, {'value': 9235}, {'value': 4401}, {'value': 2151}]}
{'status': '1', 'state': 'success', 'data': [{'value': 6036}, {'value': 8475}, {'value': 8476}, {'value': 9654}, {'value': 2602}, {'value': 9780}, {'value': 3552}, {'value': 8938}, {'value': 8192}, {'value': 350}]}
{'status': '1', 'state': 'success', 'data': [{'value': 9945}, {'value': 7245}, {'value': 6307}, {'value': 2850}, {'value': 8055}, {'value': 1846}, {'value': 3398}, {'value': 6228}, {'value': 2306}, {'value': 2003}]}
{'status': '1', 'state': 'success', 'data': [{'value': 8147}, {'value': 220}, {'value': 2509}, {'value': 9079}, {'value': 2371}, {'value': 6805}, {'value': 6272}, {'value': 5763}, {'value': 7494}, {'value': 7466}]}
四、参考文献
1、猿人学第十八题(jsvmp)题解
2、vvv 大佬的 jsvm(猿人学18 及 新版本)