1. 簡(jiǎn)介
快速優(yōu)雅地學(xué)會(huì)JS逆向,就需要從實(shí)戰(zhàn)開始鲸阻,接下來我會(huì)提供Base64加密的原網(wǎng)址以及接口參數(shù),從實(shí)戰(zhàn)中學(xué)習(xí)如何下斷點(diǎn)、摳代碼鸟悴、本地運(yùn)行等操作陈辱,此技術(shù)一般用于爬蟲上,是一個(gè)爬蟲程序猿進(jìn)階的必經(jīng)之路遣臼。
2. 實(shí)戰(zhàn)信息
網(wǎng)址:
aHR0cHM6Ly9mYW55aS5iYWlkdS5jb20vP2FsZHR5cGU9MTYwNDcjYXV0by96aA==
接口:
aHR0cHM6Ly9mYW55aS5iYWlkdS5jb20vdjJ0cmFuc2FwaT9mcm9tPXpoJnRvPWVu
逆向參數(shù):
- sign:232427.485594
- token:3dde9ef10b6f6ae310af38e6f1bd564f
3. 實(shí)戰(zhàn)流程
3.1 抓包找接口
General
請(qǐng)求信息
- URL:請(qǐng)求API地址
- Method:請(qǐng)求方式GET/POST
Request headers
請(qǐng)求頭
除了自定義請(qǐng)求頭參數(shù)屏歹,其余Host隐砸、Origin、Referer一般為爬蟲必須參數(shù)蝙眶,Cookie看站點(diǎn)是否有對(duì)其校驗(yàn)季希,如果有特殊的自定義參數(shù)一般也為爬蟲需要。
- Acs-Token:自定義的校驗(yàn)參數(shù)
- Cookie:客戶端緩存信息
- Host:域名
- Origin:來源信息
- Referer:防止跨站攻擊
3.2 查找加密參數(shù)
3.3 斷點(diǎn)分類
下斷多種方法:
- 元素下斷
- 事件下斷
- XHR下斷
- 搜索下斷
3.4 學(xué)會(huì)快速下斷
這里主要展示XHR下斷和搜索下斷,在此比較好用友浸。
如上圖,作用域的位置就看提示的參數(shù)數(shù)據(jù)即可,windows下如果使用Chrome可以用ctrl鍵觸發(fā),這里查看的是ajax()的方法棧栏妖,同時(shí)我們可以找到加密后的結(jié)果乱豆,鼠標(biāo)放到函數(shù)參數(shù)里可以看到奖恰,我們也可以直接從Scope中查看然后返回源碼找。
此處可以直接摳到本地用Node運(yùn)行诚镰,代碼調(diào)用可以看到調(diào)用了兩個(gè)作用域里的函數(shù),所以對(duì)代碼摳全祥款,進(jìn)行部分改寫清笨,此處直接粘代碼。
function a(r) {
if (Array.isArray(r)) {
for (var o = 0, t = Array(r.length); o < r.length; o++)
t[o] = r[o];
return t
}
return Array.from(r)
}
function n(r, o) {
for (var t = 0; t < o.length - 2; t += 3) {
var a = o.charAt(t + 2);
a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
a = "+" === o.charAt(t + 1) ? r >>> a : r << a,
r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a
}
return r
}
function e(r) {
var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === o) {
var t = r.length;
t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))
} else {
for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)
"" !== e[C] && f.push.apply(f, a(e[C].split(""))),
C !== h - 1 && f.push(o[C]);
var g = f.length;
g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))
}
var u = void 0
, l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
u = null !== i ? i : (i = window[l] || "") || "";
for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
var A = r.charCodeAt(v);
128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),
S[c++] = A >> 18 | 240,
S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,
S[c++] = A >> 6 & 63 | 128),
S[c++] = 63 & A | 128)
}
for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)
p += S[b],
p = n(p, F);
return p = n(p, D),
p ^= s,
0 > p && (p = (2147483647 & p) + 2147483648),
p %= 1e6,
p.toString() + "." + (p ^ m)
}
console.log(e('你好'))
調(diào)試發(fā)現(xiàn)報(bào)錯(cuò)(命令行輸入node xx.js):
因?yàn)楸镜丨h(huán)境沒有window對(duì)象刃跛,因?yàn)閘是一步計(jì)算的到為固定值抠艾,我們需要獲取到window[l]的值,就先獲取l的值奠伪,鼠標(biāo)放在l上即可獲取因?yàn)榇怂惴楣潭ㄖ档剩@取到l = "gtk",所以此處的window[l] === window["gtk"],我們通過搜索ctrl+shift+f/Command+shift+f調(diào)出搜索面板绊率,通過搜索(window["gtk"]|window['gtk']|window.gtk)這三個(gè)方法去查找谨敛,就看此處調(diào)用哪個(gè),某度翻譯用的window.gtk滤否,是一個(gè)固定值脸狸。
直接摳值替換源碼里的window[l]即可,調(diào)試發(fā)現(xiàn)i還是undefined,所以在變量上定義一個(gè)i的初始化方法即可藐俺。
結(jié)果一致就說明獲取成功了欲芹,獲取到sign了還有個(gè)token值沒有獲取卿啡,這個(gè)又怎么獲取呢。上面我們發(fā)現(xiàn)是window.common.token產(chǎn)生菱父,通過搜索(window["common"]|window['common']|window.common)先找父節(jié)點(diǎn)值颈娜,這里用window['common']即可搜到剑逃,發(fā)現(xiàn)common是頁面定義的變量,刷新頁面發(fā)現(xiàn)token值寫死我們這里就直接獲取到了token值官辽。
4. JS完整代碼
var token = "3dde9ef10b6f6ae310af38e6f1bd564f"
function a(r) {
if (Array.isArray(r)) {
for (var o = 0, t = Array(r.length); o < r.length; o++)
t[o] = r[o];
return t
}
return Array.from(r)
}
function n(r, o) {
for (var t = 0; t < o.length - 2; t += 3) {
var a = o.charAt(t + 2);
a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
a = "+" === o.charAt(t + 1) ? r >>> a : r << a,
r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a
}
return r
}
function e(r) {
var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === o) {
var t = r.length;
t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))
} else {
for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)
"" !== e[C] && f.push.apply(f, a(e[C].split(""))),
C !== h - 1 && f.push(o[C]);
var g = f.length;
g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))
}
var u = void 0
, l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
var i = null;
u = null !== i ? i : (i = "320305.131321201" || "") || "";
for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
var A = r.charCodeAt(v);
128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),
S[c++] = A >> 18 | 240,
S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,
S[c++] = A >> 6 & 63 | 128),
S[c++] = 63 & A | 128)
}
for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)
p += S[b],
p = n(p, F);
return p = n(p, D),
p ^= s,
0 > p && (p = (2147483647 & p) + 2147483648),
p %= 1e6,
p.toString() + "." + (p ^ m)
}
// console.log(e('你好'))
// console.log(token)
// 獲取Sign
function getSign(str){
return e(str)
}
// 獲取Token
function getToken(){
return token
}
// Node導(dǎo)出方法方式
module.exports = {
getSign,
getToken
}