爬蟲反爬:JS逆向之某d翻譯

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 抓包找接口

首先性置,進(jìn)入頁面按F12,打開控制面板揍堰,調(diào)到Network板塊后在翻譯處寫入需要翻譯的信息(我這里輸入的是“你好”)觸發(fā)網(wǎng)絡(luò)請(qǐng)求鹏浅,打開請(qǐng)求面板查看該請(qǐng)求的具體信息。

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ù)

從上圖中可以看到sign和token有加密嫌疑幽纷,所以目標(biāo)就暫定為對(duì)這兩個(gè)參數(shù)進(jìn)行一個(gè)簡(jiǎn)單逆向式塌。

3.3 斷點(diǎn)分類

下斷多種方法:

  1. 元素下斷
  2. 事件下斷
  3. XHR下斷
  4. 搜索下斷

3.4 學(xué)會(huì)快速下斷

這里主要展示XHR下斷和搜索下斷,在此比較好用友浸。


XHR斷點(diǎn):首先復(fù)制請(qǐng)求鏈接?前的部分路徑峰尝,這里是/v2transapi,到Source下的XHR斷點(diǎn)處下斷,回車輸入新翻譯內(nèi)容即可觸發(fā)收恢。

可以看到斷點(diǎn)斷在了send()方法的調(diào)用處武学,在Call stack中查看函數(shù)方法的調(diào)用棧,目前代碼可讀性太低伦意,我們需要對(duì)其進(jìn)行格式化查看火窒,就需要左下角的此按鈕。

格式化

在調(diào)用棧中查看自己所需參數(shù)的作用域,首先在調(diào)用棧中找到加密后的參數(shù)位置,然后往前推,直到找到加密的方法,此處直接展示尋找結(jié)果棒妨。

如上圖,作用域的位置就看提示的參數(shù)數(shù)據(jù)即可,windows下如果使用Chrome可以用ctrl鍵觸發(fā),這里查看的是ajax()的方法棧栏妖,同時(shí)我們可以找到加密后的結(jié)果乱豆,鼠標(biāo)放到函數(shù)參數(shù)里可以看到奖恰,我們也可以直接從Scope中查看然后返回源碼找。


此處左右兩側(cè)都可以看到一個(gè)加密后的sign和token數(shù)據(jù),就往前找調(diào)用的方法棧即可。

再往前一個(gè)方法棧就可以看到瑟啃,headers里面必須有個(gè)"Acs-Token"的參數(shù)论泛,data中的數(shù)據(jù)來源是b,往上看b是一個(gè)對(duì)象蛹屿,請(qǐng)求內(nèi)容在對(duì)象里屁奏,sign:x(n)|token:window.common.token這兩個(gè)參數(shù)是這樣獲取的。 我們可以直接知道x(n)就是sign的加密函數(shù),token存在window.common下错负。

鼠標(biāo)放置在x函數(shù)上會(huì)給一個(gè)跳轉(zhuǎn)提示坟瓢,點(diǎn)擊index_61616b2.js有利于我們直接找到函數(shù)調(diào)用的方法,我們可以直接去摳代碼本地運(yùn)行,n鼠標(biāo)放上去可以發(fā)現(xiàn)就是"你好",將斷點(diǎn)打在8782行犹撒,重新鍵入更改斷點(diǎn)作用域折联。

測(cè)試確認(rèn)x(n)方法確實(shí)是sign獲取的方法位置,進(jìn)入函數(shù)识颊。

image.png

此處可以直接摳到本地用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):


image.png

因?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è)固定值脸狸。


image.png

直接摳值替換源碼里的window[l]即可,調(diào)試發(fā)現(xiàn)i還是undefined,所以在變量上定義一個(gè)i的初始化方法即可藐俺。
image.png

image.png

再次測(cè)試調(diào)用炊甲,對(duì)比瀏覽器請(qǐng)求參數(shù)。
image.png

結(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值官辽。


image.png

image.png

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
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蛹磺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子同仆,更是在濱河造成了極大的恐慌萤捆,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俗批,死亡現(xiàn)場(chǎng)離奇詭異俗或,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)岁忘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門蕴侣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人臭觉,你說我怎么就攤上這事昆雀。” “怎么了蝠筑?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵狞膘,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我什乙,道長(zhǎng)挽封,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任臣镣,我火速辦了婚禮辅愿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忆某。我一直安慰自己点待,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布弃舒。 她就那樣靜靜地躺著癞埠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪聋呢。 梳的紋絲不亂的頭發(fā)上苗踪,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音削锰,去河邊找鬼通铲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛器贩,可吹牛的內(nèi)容都是我干的颅夺。 我是一名探鬼主播央串,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼碗啄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起稳摄,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤稚字,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后厦酬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胆描,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年仗阅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昌讲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡减噪,死狀恐怖短绸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情筹裕,我是刑警寧澤醋闭,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站朝卒,受9級(jí)特大地震影響证逻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抗斤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一囚企、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瑞眼,春花似錦龙宏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至掩浙,卻和暖如春花吟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厨姚。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工衅澈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谬墙。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓今布,卻偏偏與公主長(zhǎng)得像经备,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子部默,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容