码上爬平台第十二题逆向分析

网址: aHR0cHM6Ly93d3cubWFzaGFuZ3BhLmNvbS9wcm9ibGVtLWRldGFpbC8xMi8=

1、抓包找到对应接口,点击查看启动器,点击启动器进入分析

2、打上断点进行翻页


在$.ajax()打上断点,做过图灵题目的都知道这里的$.ajax是关键的加密逻辑,这里的$.ajax并非是来自于jquery,而是对ajax进行了重写

3、点击$.ajax()函数

进入到$.ajax()函数中发现里面的变量名以及函数名经过了混淆,我们观察整体代码,可以看到有明显的jsvmp混淆特征

可以参考网站:https://www.jsjiami.com/

4、全扣补环境

对于jsvmp混淆的代码,这里直接采用全扣补环境的方式,将代码全部拿下来之后在本地先运行,出现如下报错:

1
2
3
OOO00OO['push'](Q0OQO0O[OQOQQ0Q]);

TypeError: Cannot read properties of undefined (reading 'ajax')

定位到报错的行号打印对应的Q0OQO0O[OQOQQ0Q]

1
2
console.log(Q0OQO0O[OQOQQ0Q])
console.log(OQOQQ0Q)

这里发现Q0OQO0O[OQOQQ0Q]是一个undefined,OQOQQ0Q的值为$,这里我们就需要在页面上对应的位置打上条件断点,去观察看看浏览器中当OQOQQ0Q==$时Q0OQO0O[OQOQQ0Q]的值是什么

发现当OQOQQ0Q==$时Q0OQO0O[OQOQQ0Q]是一个function,那我们在这里改造一下代码,当OQOQQ0Q==$时给Q0OQO0O[OQOQQ0Q]赋值为一个function

1
2
3
4
5
6
7
$e = function() {

}
if (OQOQQ0Q === '$') {
Q0OQO0O[OQOQQ0Q] = $e
}
OOO00OO['push'](Q0OQO0O[OQOQQ0Q]);

继续运行会发现接下来就是补一些浏览器的环境对象了,我们直接上代理器进行补环境,补完环境之后发现不报错了,但是也不出结果,那是因为我们没有调用对应的启动函数,我们直接调用loadPage函数传入参数(参数为对应的页码),在调用loadPage函数的时候还是会出现一些报错,这里直接修改一下loadPage函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function loadPage(page) {
$.ajax({
url: `/api/problem-detail/12/data/?page=${page}`,
method: 'GET',
dataType: 'json',
success: function (data) {
if (!data) {
return
}
updatePageContent(data);
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('Error fetching problem details:', textStatus, errorThrown);
}
});
}

改造完loadPage函数之后还会出现报错$不存在,根据刚才在浏览器条件断点的时候,window.$是一个function,我们将window.$复制给了$e,那么我们需要把$e的值复制给window.$

1
2
3
4
$e = function() {

}
window.$ = $e

再次运行还是出现报错,我们将pycharm调试模式下的出现异常断点模式打开,右击进行调试模式,等到出现异常时断住,我们可以看到其实完整的请求url已经来了,在QQO0OQ0参数中

出来之后我们往上看代码,发现QQO0OQ0最开始赋值的是一个空数组然后经过for循环进行元素的push,那么我们改造一下,当数组的长度为4时将数组中的url进行全局导出然后将代码进行return,这样就可以得到最终的结果了

1
2
3
4
5
6
7
QQO0OQ0 = [];
for (Q0OQO0Q = 0x0; QQ0OQOQ[OQQQ00Q(0x258, 'TUGE')](Q0OQO0Q, OQOQQ0Q); Q0OQO0Q++)
QQO0OQ0[OQQQ00Q(0x31e, 'ck!W')](OOO00OO[OQQQ00Q(0x295, 'SEv2')]());
if (QQO0OQ0.length === 4) {
window.url = QQO0OQ0[2]['url']
return
}

我们在调用完loadPage函数之后,将window.url的值打印出来,发现已经得到了最终的结果了,将调用过程封装成一个函数传参调用

1
2
3
4
5
6
function get_url(page) {
loadPage(page)
console.log(window.url)
}

get_url(process.argv[2])
5、python调用
1
2
3
4
5
6
7
8
base_url = "https://www.mashangpa.com"

for page in range(1, 21):
url = subprocess.run(['node', 'encrypt.js', str(page)], capture_output=True, text=True)
new_url = url.stdout.strip()
finally_url = base_url + new_url

response = requests.get(finally_url, headers=headers, cookies=cookies)