Python 爬蟲進階必備 | 某爬蟲練習站之 js 混淆
今日網(wǎng)站
aHR0cDovL21hdGNoLnl1YW5yZW54dWUuY29tL21hdGNoLzE=
這個網(wǎng)站是某大佬搭建的闖關(guān)網(wǎng)站
無限 debugger 的繞過
打開開發(fā)者工具會出現(xiàn) debugger

直接在 debugger 對應(yīng)的行號,右鍵選擇Never pause here即可跳過

抓包分析與定位
跳過 debugger,通過網(wǎng)絡(luò)面板,找到我們需要分析的參數(shù)是下面這個請求的m參數(shù)

參數(shù)名字只有一個m,直接檢索的話就會出現(xiàn)下面這么多的結(jié)果,所以放棄直接檢索這個參數(shù)來查找位置。

所以轉(zhuǎn)換思路,使用xhr斷點查找參數(shù)位置

找到如下位置即為m參數(shù)的生成位置

這里沒辦法格式化,不好查看對應(yīng)的邏輯,所以拷貝到 IDE 中查看
定位m可以看到下面的邏輯

這里的m由oo0O0與window.f的值相加得到
加密分析與實現(xiàn)
上面我們定位了m的生成位置,這里需要分析出m的表達式的oo0O0和window.f
先看oo0O0
function oo0O0(mw) {
window.b = '';
for (var i = 0, len = window.a.length; i < len; i++) {
console.log(window.a[i]);
window.b += String[document.e + document.g](window.a[i][document.f + document.h]() - i - window.c)
}
var U = ['W5r5W6VdIHZcT8kU', 'WQ8CWRaxWQirAW=='];
var J = function (o, E) {
o = o - 0x0;
var N = U[o];
if (J['bSSGte'] === undefined) {
var Y = function (w) {
var m = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=',
T = String(w)['replace'](/=+$/, '');
var A = '';
for (var C = 0x0, b, W, l = 0x0; W = T['charAt'](l++); ~W && (b = C % 0x4 ? b * 0x40 + W : W, C++ % 0x4) ? A += String['fromCharCode'](0xff & b >> (-0x2 * C & 0x6)) : 0x0) {
W = m['indexOf'](W)
}
return A
};
var t = function (w, m) {
var T = [], A = 0x0, C, b = '', W = '';
w = Y(w);
for (var R = 0x0, v = w['length']; R < v; R++) {
W += '%' + ('00' + w['charCodeAt'](R)['toString'](0x10))['slice'](-0x2)
}
w = decodeURIComponent(W);
var l;
for (l = 0x0; l < 0x100; l++) {
T[l] = l
}
for (l = 0x0; l < 0x100; l++) {
A = (A + T[l] + m['charCodeAt'](l % m['length'])) % 0x100, C = T[l], T[l] = T[A], T[A] = C
}
l = 0x0, A = 0x0;
for (var L = 0x0; L < w['length']; L++) {
l = (l + 0x1) % 0x100, A = (A + T[l]) % 0x100, C = T[l], T[l] = T[A], T[A] = C, b += String['fromCharCode'](w['charCodeAt'](L) ^ T[(T[l] + T[A]) % 0x100])
}
return b
};
J['luAabU'] = t, J['qlVPZg'] = {}, J['bSSGte'] = !![]
}
var H = J['qlVPZg'][o];
return H === undefined ? (J['TUDBIJ'] === undefined && (J['TUDBIJ'] = !![]), N = J['luAabU'](N, E), J['qlVPZg'][o] = N) : N = H, N
};
eval(atob(window['b'])[J('0x0', ']dQW')](J('0x1', 'GTu!'), '\x27' + mw + '\x27'));
return ''
}
直接復(fù)制在控制臺運行,得到結(jié)果是空

那么m的值由window.f決定,window.f在邏輯中沒有找到。
但是每次運行oo0O0都會改變window.f的值,所以問題還是出在oo0O0中,所以進一步分析oo0O0的邏輯
oo0O0中雖然返回值是空的字符串,但是在返回前執(zhí)行了下面這行代碼
eval(atob(window['b'])[J('0x0', ']dQW')](J('0x1', 'GTu!'), '\x27' + mw + '\x27'));
通過執(zhí)行atob(window['b'])得到下面這一大串的邏輯

這里面就包含了window.f

再結(jié)合oo0O0中的J和U可以得出J('0x0', ']dQW')和J('0x1', 'GTu!')的結(jié)果如下

這樣原有的代碼
eval(atob(window['b'])[J('0x0', ']dQW')](J('0x1', 'GTu!'), '\x27' + mw + '\x27'));
可以等價為
// 這里的省略號為上面 atob(window['b']) 的結(jié)果
eval('........hex_md5(mwqqppz)'.replace('mwqqppz', '\x27' + mw + '\x27'));
所以這里的加密是通過將 hex_md5 的主體加密邏輯隱藏在 base64 編碼里,然后將關(guān)鍵的參數(shù)通過字符串替換的方式替換,再使用eval執(zhí)行
厲害厲害,比一般的商業(yè)網(wǎng)站還會玩
好了,今天的文章就到這里了,咱們下次再會~
對了,看完記得一鍵四連,這個對我真的很重要。
