html5|腾讯漫画(js逆向)

今天突然想起刚开始学逆向的时候遇到的一个站,当时没能力解决,现在得安排一下它才行。
时间过得真快啊,转眼都差不多一年了(我还是从前那个菜鸡,没有一丝丝改变)

目标网站:aHR0cHM6Ly9hYy5xcS5jb20vQ29taWNWaWV3L2luZGV4L2lkLzYzMDE2Ni9jaWQvMQ==

一、抓包分析
可以看到,数据是以图片的形式返回的,而这个图片的网址是加密的,那就跟栈找到它生成的地方呗
html5|腾讯漫画(js逆向)
文章图片

二、跟栈分析
下断点刷新页面
html5|腾讯漫画(js逆向)
文章图片

可以看到imgSrcList已经有数据了,现在我们全局搜一下,看它是在哪里被赋值的
html5|腾讯漫画(js逆向)
文章图片

可以看到imgSrcList是被imgobj赋值的,那接下来再搜下imgobj
html5|腾讯漫画(js逆向)
文章图片

imgobj是被PICTURE赋值的,再搜下PICTURE…
html5|腾讯漫画(js逆向)
文章图片

然后就追到_v了,这时候再搜_v好像也没啥东西了,细心观察会发现在PICTURE被_v赋值的上面有eval这种字眼,遇到eval的要特别留意,往往会有意想不到的惊喜。
把这个自执行函数copy下来,eval改成concole.log就能可能到内容了
html5|腾讯漫画(js逆向)
文章图片

这里window.DATA和window.nonce都是未知的,像这种赋值在window上的,一般都要去源码上喵一眼,看有没有找到
html5|腾讯漫画(js逆向)
文章图片

html5|腾讯漫画(js逆向)
文章图片

那接下来就好办了呗,正则匹配出来然后放到那个解密函数跑一下行了
注意:
(1)window.nonce在源码上两次被赋值,第二次才是真正的window.nonce
(2)生成window.nonce的地方会检测一些环境,由于每次检测的点都是不一样的,这里建议用jsdom补环境
三、请求验证
html5|腾讯漫画(js逆向)
文章图片

python代码:
import requests import execjs import reheaders = { '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(`Hello world
`); 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=https://www.it610.com/article/re.findall("DATA = 'https://www.it610.com/article/(.*?)'",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 = https://www.it610.com/article/ctx.call('get_data', data, nonce) for i in result_data: print(i) print("\n")

【html5|腾讯漫画(js逆向)】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 }

    推荐阅读