<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          爬蟲篇之JS逆向破解

          共 8078字,需瀏覽 17分鐘

           ·

          2022-07-08 08:50


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


          背景


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


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


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


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




          上面這個(gè)圖是請(qǐng)求翻譯的全過程



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


          接下來我們用python模擬以下這個(gè)過程




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


          代碼給到大家


          import requests
          #請(qǐng)求頭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請(qǐng)求response = requests.post(url=url,headers=headers,data=params).json()
          print(response)


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


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



          可以看到,直接返回錯(cuò)誤了,很明顯被禁止了,或者說是校驗(yàn)沒通過,屬于非法請(qǐng)求


          我們?cè)賮砜匆幌拢桓淖兎g的內(nèi)容,靠這些鹽和簽名是不是能夠成功翻譯呢



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


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



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



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


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



          找到我們要分析的地方,然后在打上斷點(diǎn),重新請(qǐng)求一遍


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




          當(dāng)執(zhí)行到如圖所示的位置的時(shí)候,我們把鼠標(biāo)移動(dòng)到r這個(gè)對(duì)象的位置上去,為什么要看這個(gè)對(duì)象呢,因?yàn)槟憧聪旅娴膕alt、sign、lts、bv這些參數(shù)都是屬于r這個(gè)對(duì)象的屬性


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



          接著看看這個(gè)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")        }    };


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


          r:當(dāng)前的時(shí)間戳


          i:當(dāng)前的時(shí)間戳+(0到10的隨機(jī)數(shù))


          salt:salt=i


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


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


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




          代碼如下:


          import requestsfrom hashlib import md5import timeimport random

          #請(qǐng)求地址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("請(qǐng)輸入要翻譯的語句:") result = fanyi(word)
          #對(duì)返回的json數(shù)據(jù)進(jìn)行提取,提取出我們需要的數(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. 查看請(qǐng)求調(diào)用的堆棧


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


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


          6. 寫js代碼


          7. 打印windows對(duì)象的值


          8. 勾子:cookie鉤子、請(qǐng)求鉤子、header鉤子


          技巧簡單介紹


          1. 搜索

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

          當(dāng)前頁面右鍵->檢查,彈出檢查工具



          2. debug + 調(diào)試




          調(diào)試




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

          1. 執(zhí)行到下一個(gè)端點(diǎn)

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

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

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

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

          6. Call Stack 為代碼調(diào)用的堆棧信息,代碼執(zhí)行順序?yàn)橛上轮辽希@對(duì)于著關(guān)鍵函數(shù)前后調(diào)用關(guān)系很有幫助


          XHR debug


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



          2.3 行為debug


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



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


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


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


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


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




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


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



          6. 寫js代碼


          7. 打印windows對(duì)象的值

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

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

          8. 勾子

          以chrome插件的方式,在匹配到關(guān)鍵詞處插入斷點(diǎ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);

          當(dāng)cookie中匹配到了 TSdc75a61a, 則插入斷點(diǎn)。


          8.2 請(qǐng)求鉤子:用于定位請(qǐng)求中關(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);


          當(dāng)請(qǐng)求的url里包含MmEwMD時(shí),則插入斷點(diǎn)


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


          當(dāng)header中包含Authorization時(shí),則插入斷點(diǎn)


          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)建一個(gè)文件夾,文件夾中創(chuàng)建一個(gè)鉤子函數(shù)文件inject.js 及 插件的配置文件 mainfest.json 即可


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


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




          結(jié)束語


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


          https://github.com/DayuMM2021/Java






          瀏覽 181
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  动漫无码视频 | 毛片大香蕉 | 最近中文字幕免费MV第一季歌词怀孕 | 日韩精品一级毛斤 | 学生妹一级a片免费看 |