今天突然想起刚开始学逆向的时候遇到的一个站,当时没能力解决,现在得安排一下它才行。
时间过得真快啊,转眼都差不多一年了(我还是从前那个菜鸡,没有一丝丝改变)
目标网站:aHR0cHM6Ly9hYy5xcS5jb20vQ29taWNWaWV3L2luZGV4L2lkLzYzMDE2Ni9jaWQvMQ==
一、抓包分析
可以看到,数据是以图片的形式返回的,而这个图片的网址是加密的,那就跟栈找到它生成的地方呗
二、跟栈分析
下断点刷新页面
可以看到imgSrcList已经有数据了,现在我们全局搜一下,看它是在哪里被赋值的
可以看到imgSrcList是被imgobj赋值的,那接下来再搜下imgobj
imgobj是被PICTURE赋值的,再搜下PICTURE…
然后就追到_v了,这时候再搜_v好像也没啥东西了,细心观察会发现在PICTURE被_v赋值的上面有eval这种字眼,遇到eval的要特别留意,往往会有意想不到的惊喜。
把这个自执行函数copy下来,eval改成concole.log就能可能到内容了
这里window.DATA和window.nonce都是未知的,像这种赋值在window上的,一般都要去源码上喵一眼,看有没有找到
那接下来就好办了呗,正则匹配出来然后放到那个解密函数跑一下行了
注意:
(1)window.nonce在源码上两次被赋值,第二次才是真正的window.nonce
(2)生成window.nonce的地方会检测一些环境,由于每次检测的点都是不一样的,这里建议用jsdom补环境
import requests
import execjs
import re
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
}
for k in range(1,10):
print("第"+str(k)+"页")
response = requests.get('https://ac.qq.com/ComicView/index/id/630166/cid/%s?fromPrev=1'%(str(k)), headers=headers)
nonce_js=re.findall('] = (.*?);',str(response.text))[1]
f_str='const jsdom = require("jsdom");const { JSDOM } = jsdom;const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);window = dom.window;document = window.document;XMLHttpRequest = window.XMLHttpRequest;'+'function a(){var b='+nonce_js+'; return b}'
js = execjs.compile(f_str)
nonce = js.call("a")
print("nonce: ",nonce)
data=re.findall("DATA = '(.*?)'",str(response.text))[0]
print("data: ",data)
with open('test.js', 'r', encoding='utf-8') as f:
content = f.read()
ctx = execjs.compile(content)
result_data = ctx.call('get_data', data, nonce)
for i in result_data:
print(i)
print("\n")
js代码:
function Base() {
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
this.decode = function(c) {
var a = "", b, d, h, f, g, e = 0;
for (c = c.replace(/[^A-Za-z0-9\+\/\=]/g, ""); e < c.length; )
b = _keyStr.indexOf(c.charAt(e++)),
d = _keyStr.indexOf(c.charAt(e++)),
f = _keyStr.indexOf(c.charAt(e++)),
g = _keyStr.indexOf(c.charAt(e++)),
b = b << 2 | d >> 4,
d = (d & 15) << 4 | f >> 2,
h = (f & 3) << 6 | g,
a += String.fromCharCode(b),
64 != f && (a += String.fromCharCode(d)),
64 != g && (a += String.fromCharCode(h));
return a = _utf8_decode(a)
}
;
_utf8_decode = function(c) {
for (var a = "", b = 0, d = c1 = c2 = 0; b < c.length; )
d = c.charCodeAt(b),
128 > d ? (a += String.fromCharCode(d),
b++) : 191 < d && 224 > d ? (c2 = c.charCodeAt(b + 1),
a += String.fromCharCode((d & 31) << 6 | c2 & 63),
b += 2) : (c2 = c.charCodeAt(b + 1),
c3 = c.charCodeAt(b + 2),
a += String.fromCharCode((d & 15) << 12 | (c2 & 63) << 6 | c3 & 63),
b += 3);
return a
}
}
function get_data(data,nonce) {
var B = new Base(), T = data.split(''), N = nonce, len, locate, str;
N = N.match(/\d+[a-zA-Z]+/g);
len = N.length;
while (len--) {
locate = parseInt(N[len]) & 255;
str = N[len].replace(/\d+/g, '');
T.splice(locate, str.length)
}
T = T.join('');
_v = JSON.parse(B.decode(T));
console.log(_v.picture)
return _v.picture
}