1. 爬蟲篇之JS逆向破解

        共 8078字,需瀏覽 17分鐘

         ·

        2022-07-08 08:50


        爬蟲中很重要的一個點就是JS的逆向破解加密,今天我們來淺析一下


        背景


        先簡單介紹一下為什么要有JS解密,目前大部分網(wǎng)頁都是采用的前后端分離的方式,所以呢,爬蟲的一般破解之道都是從后端接口來做文章,進行突破


        不過道高一尺,魔高一丈,網(wǎng)頁開發(fā)會對API接口請求參數(shù)進行加密,來增加爬蟲抓取的門檻。為此可以通過js逆向來分析破解加密方式,模擬瀏覽器發(fā)送請求獲取接口數(shù)據(jù)。


        當然,先說明,這篇文章并不是非常專業(yè)的JS解密,因為JS的解密涉及很多種,多種行為的解密,本文只是對其中一種情況進行簡單的介紹


        來吧,讓我們一起簡單學(xué)習(xí)一下




        上面這個圖是請求翻譯的全過程



        我們能清晰的看到這是直接以表單的形式提交的數(shù)據(jù)到后端API層,然后API來執(zhí)行翻譯的作用


        接下來我們用python模擬以下這個過程




        一定要注意的是,請求頭寫全,包括cookie和user-agent這些,還有下面的params一定要按照網(wǎng)頁中的來


        代碼給到大家


        import requests
        #請求頭headers = { "Accept": "application/json, text/javascript, */*; q=0.01", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "Content-Length": "255", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Cookie": "OUTFOX_SEARCH_USER_ID_NCOO=1992896419.125546; [email protected]; fanyi-ad-id=306808; fanyi-ad-closed=1; DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|; JSESSIONID=abcJJxrChyTjz_26EmBgy; ___rl__test__cookies=1656205889631", "Host": "fanyi.youdao.com", "Origin": "http://fanyi.youdao.com", "Referer": "http://fanyi.youdao.com/", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36", "X-Requested-With": "XMLHttpRequest",}
        #提交參數(shù)params = { "i": "love you , my baby", "from": "AUTO", "to": "AUTO", "smartresult": "dict", "client": "fanyideskweb", "salt": "16562058896377", "sign": "f85458213e7db4207f135599c7ddfac7", "lts": "1656205889637", "bv": "bdc0570a34c12469d01bfac66273680d", "doctype": "json", "version": "2.1", "keyfrom": "fanyi.web", "action": "FY_BY_REALTlME",}
        url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"#發(fā)起POST請求response = requests.post(url=url,headers=headers,data=params).json()
        print(response)


        一部分是header信息,一部分是params信息


        我們可以看到,參數(shù)params中除了我們要傳遞的參數(shù)翻譯內(nèi)容之外,還有好多我們不認識的參數(shù),如果這里錯了會怎么樣呢,隨便改一下其中的一個參數(shù),我們看看效果



        可以看到,直接返回錯誤了,很明顯被禁止了,或者說是校驗沒通過,屬于非法請求


        我們再來看一下,只改變翻譯的內(nèi)容,靠這些鹽和簽名是不是能夠成功翻譯呢



        結(jié)果發(fā)現(xiàn),我們只改變了要翻譯的內(nèi)容,結(jié)果還是不行,很明顯生成這些校驗參數(shù)的過程是和要翻譯的內(nèi)容是相關(guān)的


        搜索不同的關(guān)鍵詞,請求body參數(shù)如下,分析發(fā)現(xiàn)除了我們要傳遞的翻譯內(nèi)容外還有4個參數(shù)是變量:



        "salt": "16562058896377",
        "sign": "f85458213e7db4207f135599c7ddfac7",
        "lts": "1656205889637",
        "bv": "bdc0570a34c12469d01bfac66273680d",



        這些就是屬于請求鹽和校驗參數(shù),有對應(yīng)的加密格式,接下來我們圍繞這四個參數(shù)來進行破解


        接下來我們打開控制臺,打開我們要分析的JS程序,直接ctrl+f全局搜索salt關(guān)鍵字



        找到我們要分析的地方,然后在打上斷點,重新請求一遍


        F10往下一步一步的執(zhí)行




        當執(zhí)行到如圖所示的位置的時候,我們把鼠標移動到r這個對象的位置上去,為什么要看這個對象呢,因為你看下面的salt、sign、lts、bv這些參數(shù)都是屬于r這個對象的屬性


        我們能夠看到此時r對象的這幾個屬性已經(jīng)被賦予了值了,



        接著看看這個r到底是什么



            var r = function(e) {        var t = n.md5(navigator.appVersion)          , r = "" + (new Date).getTime()          , i = r + parseInt(10 * Math.random(), 10);        return {            ts: r,            bv: t,            salt: i,            sign: n.md5("fanyideskweb" + e + i + "Ygy_4c=r#e#4EX^NUGUc5")        }    };


        進一步分析發(fā)現(xiàn):


        r:當前的時間戳


        i:當前的時間戳+(0到10的隨機數(shù))


        salt:salt=i


        e:搜索關(guān)鍵字


        sign:md5("fanyideskweb" + e + i + "Ygy_4c=r#e#4EX^NUGUc5")


        至此完成簽名算法的實現(xiàn),接下來可以通過python來實現(xiàn)




        代碼如下:


        import requestsfrom hashlib import md5import timeimport random

        #請求地址url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
        appVersion = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"
        headers = { "Accept": "application/json, text/javascript, */*; q=0.01", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "Content-Length": "244", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Cookie": "[email protected]; JSESSIONID=aaaUggpd8kfhja1AIJYpx; OUTFOX_SEARCH_USER_ID_NCOO=108436537.92676207; ___rl__test__cookies=1597502296408", "Host": "fanyi.youdao.com", "Origin": "http://fanyi.youdao.com", "Referer": "http://fanyi.youdao.com/", "user-agent": appVersion, "X-Requested-With": "XMLHttpRequest",}

        def r(e): # bv t = md5(appVersion.encode()).hexdigest()
        # lts r = str(int(time.time() * 1000))
        # i i = r + str(random.randint(0,9))
        return { "ts": r, "bv": t, "salt": i, "sign": md5(("fanyideskweb" + e + i + "Ygy_4c=r#e#4EX^NUGUc5").encode()).hexdigest() }

        def fanyi(word):
        data = r(word) params = { "i": word, "from": "AUTO", "to": "AUTO", "smartresult": "dict", "client": "fanyideskweb", "salt": data["salt"], "sign": data["sign"], "lts": data["ts"], "bv": data["bv"], "doctype": "json", "version": "2.1", "keyfrom": "fanyi.web", "action": "FY_BY_REALTlME", }
        response = requests.post(url=url,headers=headers,data=params) #返回json數(shù)據(jù) return response.json()


        if __name__ == "__main__": while True: word = input("請輸入要翻譯的語句:") result = fanyi(word)
        #對返回的json數(shù)據(jù)進行提取,提取出我們需要的數(shù)據(jù) r_data = result["translateResult"][0] print(r_data[0]["src"]) print(r_data[0]["tgt"])





        給大家看一看JS的逆向技巧,從網(wǎng)上看到的總結(jié)



        下面總結(jié)來源于:http://t.zoukankan.com/Renyi-Fan-p-12650448.html,侵刪


        一句話總結(jié)


        1. 搜索:全局搜索、代碼內(nèi)搜索


        2. debug:常規(guī)debug、XHR debug、行為debug


        3. 查看請求調(diào)用的堆棧


        4. 執(zhí)行堆內(nèi)存中的函數(shù)


        5. 修改堆棧中的參數(shù)值


        6. 寫js代碼


        7. 打印windows對象的值


        8. 勾子:cookie鉤子、請求鉤子、header鉤子


        技巧簡單介紹


        1. 搜索

        適用于根據(jù)關(guān)鍵詞快速定位關(guān)鍵文件及代碼

        當前頁面右鍵->檢查,彈出檢查工具



        2. debug + 調(diào)試




        調(diào)試




        如圖所示,我標記了1到6,下面分別介紹其含義

        1. 執(zhí)行到下一個端點

        2. 執(zhí)行下一步,不會進入所調(diào)用的函數(shù)內(nèi)部

        3. 進入所調(diào)用的函數(shù)內(nèi)部

        4. 跳出函數(shù)內(nèi)部

        5. 一步步執(zhí)行代碼,遇到有函數(shù)調(diào)用,則進入函數(shù)

        6. Call Stack 為代碼調(diào)用的堆棧信息,代碼執(zhí)行順序為由下至上,這對于著關(guān)鍵函數(shù)前后調(diào)用關(guān)系很有幫助


        XHR debug


        匹配url中關(guān)鍵詞,匹配到則跳轉(zhuǎn)到參數(shù)生成處,適用于url中的加密參數(shù)全局搜索搜不到,可采用這種方式攔截



        2.3 行為debug


        適用于點擊按鈕時,分析代碼執(zhí)行邏輯



        如圖所示,可快速定位點擊探索按鈕后,所執(zhí)行的js。


        3 查看請求調(diào)用的堆棧


        可以在 Network 選項卡下,該請求的 Initiator 列里看到它的調(diào)用棧,調(diào)用順序由上而下:


        4. 執(zhí)行堆內(nèi)存中的函數(shù)


        當debug到某一個函數(shù)時,我們想主動調(diào)用,比如傳遞下自定義的參數(shù),這時可以在檢查工具里的console里調(diào)用




        此處要注意,只有debug打這個函數(shù)時,控制臺里才可以調(diào)用。如果想保留這個函數(shù),可使用this.xxx=xxx 的方式。之后調(diào)用時無需debug到xxx函數(shù),直接使用this.xxx 即可。


        5. 修改堆棧中的參數(shù)值



        6. 寫js代碼


        7. 打印windows對象的值

        在console中輸入如下代碼,如只打印_$開頭的變量值

        for (var p in window) {    if (p.substr(0, 2) !== "_$")         continue;    console.log(p + " >>> " + eval(p))}

        8. 勾子

        以chrome插件的方式,在匹配到關(guān)鍵詞處插入斷點


        8.1 cookie鉤子:用于定位cookie中關(guān)鍵參數(shù)生成位置

        var code = function(){    var org = document.cookie.__lookupSetter__('cookie');    document.__defineSetter__("cookie",function(cookie){        if(cookie.indexOf('TSdc75a61a')>-1){            debugger;        }        org = cookie;    });    document.__defineGetter__("cookie",function(){return org;});}var script = document.createElement('script');script.textContent = '(' + code + ')()';(document.head||document.documentElement).appendChild(script);script.parentNode.removeChild(script);

        當cookie中匹配到了 TSdc75a61a, 則插入斷點。


        8.2 請求鉤子:用于定位請求中關(guān)鍵參數(shù)生成位置

        var code = function(){var open = window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open = function (method, url, async){    if (url.indexOf("MmEwMD")>-1){        debugger;    }    return open.apply(this, arguments);};}var script = document.createElement('script');script.textContent = '(' + code + ')()';(document.head||document.documentElement).appendChild(script);script.parentNode.removeChild(script);


        當請求的url里包含MmEwMD時,則插入斷點


        8.3 header鉤子:用于定位header中關(guān)鍵參數(shù)生成位置

        var code = function(){var org = window.XMLHttpRequest.prototype.setRequestHeader;window.XMLHttpRequest.prototype.setRequestHeader = function(key,value){    if(key=='Authorization'){        debugger;    }    return org.apply(this,arguments);}}var script = document.createElement('script');script.textContent = '(' + code + ')()';(document.head||document.documentElement).appendChild(script);script.parentNode.removeChild(script);


        當header中包含Authorization時,則插入斷點


        8.4 manifest.json:插件的配置文件

        {   "name": "Injection",    "version": "2.0",    "description": "RequestHeader鉤子",    "manifest_version": 2,    "content_scripts": [        {            "matches": [                "<all_urls>"            ],            "js": [                "inject.js"            ],            "all_frames": true,            "permissions": [                "tabs"            ],            "run_at": "document_start"        }    ]}

        使用方法

        a、如圖所示,創(chuàng)建一個文件夾,文件夾中創(chuàng)建一個鉤子函數(shù)文件inject.js 及 插件的配置文件 mainfest.json 即可


        b、打開chrome 的擴展程序, 加載已解壓的擴展程序,選擇步驟1創(chuàng)建的文件夾即可


        c、切換回原網(wǎng)頁,刷新頁面,若鉤子函數(shù)關(guān)鍵詞匹配到了,則觸發(fā)debug




        結(jié)束語


        后續(xù)所有的文章都會更新到這里,點贊關(guān)注不迷路


        https://github.com/DayuMM2021/Java






        瀏覽 181
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 久久9视频| 五月天亚洲综合 | 夜精品无码A片一区二区蜜桃 | 电影院揉捏啊湿哒哒 | chinese叫床videos |