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

          Python 爬蟲進(jìn)階必備 | R數(shù) 4 代加密分析

          共 6540字,需瀏覽 14分鐘

           ·

          2021-12-16 00:55

          事先聲明:


          本篇文章僅作為學(xué)術(shù)研究和安全交流使用,切勿用于商業(yè)用途。如因違反規(guī)定產(chǎn)生任何法律糾紛,本人概不負(fù)責(zé)。如果本篇文章影響到官方利益,請(qǐng)?zhí)砑游哪┑淖髡呶⑿盘?hào)告知,本人會(huì)在第一時(shí)間將文章刪除。


          【本文共計(jì)5225個(gè)字,閱讀大約需要11分鐘】


          寫在前面:


          爬蟲界大山,這是其中一座。如果你認(rèn)為我用的比喻有點(diǎn)言過其實(shí),那么不妨看看下面的截圖。之后你就會(huì)對(duì)我說的話深以為然,甚至還會(huì)覺得,它的難度被我嚴(yán)重低估了。



          2020年12月13日,差不多就是去年的這個(gè)時(shí)候。我在沈陽遠(yuǎn)程面試了一家坐落于大連的互聯(lián)網(wǎng)公司。公司的技術(shù)總監(jiān)為了測(cè)試我的技術(shù)能力,就把一個(gè)名為“中國(guó)海關(guān)進(jìn)口商品查詢網(wǎng)”的站點(diǎn),作為面試題目,限期三天之內(nèi)抓取1w條數(shù)據(jù),開出的薪資是8k。當(dāng)時(shí)有過大約兩年工作經(jīng)驗(yàn)的我,很自命不凡,一番折騰下,終于用了整整三十天的時(shí)間,才知道它的名字:R數(shù)第5代加密。從此我心中也萌生出了一個(gè)至今都無法消除的疑問:他媽的,耍我玩呢?


          轉(zhuǎn)眼已經(jīng)過去了一年,我一直無法對(duì)這件事釋懷。同時(shí),也把研究這項(xiàng)加密技術(shù)當(dāng)成了我業(yè)余生活中勢(shì)在必行的一件事,甚至列入有生之年系列。但好在,隨著我在研究上的慢慢深入和知識(shí)上的層層儲(chǔ)備,我終于在2021年12月6號(hào)21點(diǎn)32分整突破這項(xiàng)技術(shù)瓶頸,當(dāng)時(shí)的心情和海因斯突破百米紀(jì)錄心情一樣:“原來那扇門是虛掩著的!”


          故事要留給過去,但成長(zhǎng)要用于分享。所以接下來,我將會(huì)把時(shí)間的指針撥回一年之前,以一個(gè)初學(xué)者的身份出現(xiàn)在R數(shù)面前。從對(duì)它的一無所知到的豁然開朗,從對(duì)它的聞風(fēng)喪膽再到泰然自若。這是一個(gè)分析的過程,更像是一個(gè)渡劫的經(jīng)歷。但往往這種經(jīng)歷會(huì)伴隨著一個(gè)不一樣的開端,所以我們要


          0x01 先從無限debugger說起


          分析的網(wǎng)站是什么,對(duì)于我們無關(guān)緊要。因?yàn)镽數(shù)是一個(gè)系列,而這個(gè)系列具體表現(xiàn)在于:你在打開網(wǎng)絡(luò)分析工具后立馬就會(huì)引起你的警覺



          上述代碼我們暫時(shí)不太了解它意義,但唯一能讓你感受到不明覺厲的地方是,即使你釋放斷點(diǎn),0.1s過后它又會(huì)自動(dòng)執(zhí)行了這段代碼,反反復(fù)復(fù),永無止境。如果解決不了這個(gè)問題,那么調(diào)試工作就會(huì)難以為繼。所以,必要時(shí),我們要采取一些強(qiáng)硬的手段來對(duì)付它



          使用 chrome 斷點(diǎn)工具 Never pause here (永不再此處停止)即可解決這一問題,但這也不過是權(quán)宜之計(jì),因?yàn)橹灰闼⑿戮W(wǎng)站,就會(huì)驚奇的發(fā)現(xiàn),代碼也會(huì)發(fā)生變化!而且每一次都極度的混淆(也可以稱之為動(dòng)態(tài)混淆)



          這些代碼難以理解起來比較難,我們大可不必避重就輕,非要把它研究個(gè)所以然來。別忘了我們初心和目的:抓取數(shù)據(jù)


          0x02 分析請(qǐng)求


          這個(gè)環(huán)節(jié)對(duì)于我們必不可少,所以在解決掉 debugger 問題后,我們來看下它每一次接口請(qǐng)求的數(shù)據(jù)



          可以看到它的鏈接中攜帶一個(gè) MmEwMD 的簽名,同時(shí)它的 cookie 信息也看上去不是那么友善



          而且最讓人不解的是,每一次請(qǐng)求,它的 cookie 竟然也會(huì)跟著變化!正常而言 cookie 是服務(wù)端與客戶端建立唯一的會(huì)話標(biāo)識(shí)。如果 cookie 發(fā)生變化就意味著服務(wù)端不會(huì)保存你的登錄狀態(tài)!帶著這個(gè)疑問,我們看一下 chrome 的 Application 來更好的證實(shí)這一結(jié)論



          可以看到里面有很多關(guān)于 cookie 信息。這里有一個(gè)知識(shí)點(diǎn),是 CSDN 山東大蔥哥教我的:我們辨別 cookie 來源時(shí),可以看 httpOnly 這一欄,如果有 的是來自于服務(wù)端,如果沒有  的話是本地生成的。由此,我們結(jié)論得到證實(shí):本地cookie 確實(shí)存在變化。同時(shí),我們也能想到讓它變化的方法



          直觀點(diǎn)來講,官方肯定有過給上述方法重新賦值的過程,而且還是存在一定的定時(shí)性,至于賦的值如何生成,以及它定時(shí)的規(guī)律是什么,我們會(huì)在后續(xù)章節(jié)研究,現(xiàn)在主要深挖它的特點(diǎn)


          0x03 為什么是202?


          出于好奇,我們嘗試把它的 cookie 信息寫死,然后用 python 程序?qū)λ牡刂穼?shí)現(xiàn)一次請(qǐng)求



          然后發(fā)現(xiàn)了一個(gè)更為驚奇的事情:它的響應(yīng)結(jié)果響應(yīng)狀態(tài)跟官方截然不同



          官方的響應(yīng)狀態(tài)是:200,而我們本地的響應(yīng)狀態(tài)是:202


          為什么?


          0x03 抓包分析cookie


          至此,我們可以總結(jié)出R數(shù)的一部分特點(diǎn)


          1.  無限 debugger 會(huì)對(duì)調(diào)試造成干擾


          2.  極強(qiáng)代碼混淆會(huì)讓你徹底喪失對(duì)它的閱讀興趣


          3.  cookie 存在動(dòng)態(tài)刷新機(jī)制而且每次請(qǐng)求都各不相同


          4. 眼見并不一定為實(shí),比如同樣的請(qǐng)求會(huì)在兩種不同的途徑下呈現(xiàn)不同的結(jié)果


          為了盡快的找出內(nèi)部的玄機(jī),我們可以借助 fiddler 進(jìn)行抓包,要相信你看到的所有不可思議的東西,都是服務(wù)端在始作俑者。所以,我們不應(yīng)該放過服務(wù)端所留下的任何線索。對(duì)了,抓包之前要把 cookie 清掉(這點(diǎn)很重要)



          通過抓包可以看到,同一個(gè)鏈接地址它一下子請(qǐng)求了兩遍,但竟然出現(xiàn)了兩個(gè)不同結(jié)果。下圖是第一遍請(qǐng)求,我們所能獲取到的信息



          在第二遍請(qǐng)求中,我們可以獲取到這些信息。鑒于對(duì)請(qǐng)求的描述太蹩腳,我們就姑且把第一次遍請(qǐng)求叫做:初始化請(qǐng)求。第二遍請(qǐng)求叫做:列表頁請(qǐng)求。



          這里可能有點(diǎn)亂,我們先梳理一下:初始化請(qǐng)求->獲取服務(wù)端 cookie + 本地生成的 cookie ->列表頁請(qǐng)求->獲取請(qǐng)求接口的部分 cookie 我們可以試著畫出個(gè)流程圖



          經(jīng)過這樣分析,我們對(duì) cookie 的機(jī)制有了新的認(rèn)識(shí)。同時(shí),我們可以把初始化請(qǐng)求時(shí)服務(wù)端返回 cookie 輕松拿到手,攜帶它去發(fā)送列表頁請(qǐng)求。但由于攜帶的cookie信息不完整,我們并不能請(qǐng)求成功。所以要想成功的完成列表頁請(qǐng)求,我們需要把重心放到——如何生成后半段 cookie 上,否則一直會(huì)是202


          0x04 被隱藏的代碼


          不管你相信與否,請(qǐng)求列表頁后半段 cookie 的生成方法,就隱藏在初始化請(qǐng)求所返回的代碼中。雖然這個(gè)鏈接沒有以 .js 作為后綴,卻包含著海量的 js 信息。而這些信息正是生成 cookie 的關(guān)鍵所在



          為了方便研究,我們可以把這段代碼下載到本地,這樣一來,就更能看清它的細(xì)節(jié)



          這里面注意兩點(diǎn),第一點(diǎn):上述文件引用了一個(gè)名為 c.FxJzG50F.dfe1675.js 的文件,我們也需要把它下載到本地進(jìn)行引用。第二點(diǎn):編碼 charset 需要改成 UFT-8 格式,不然的肯定報(bào)錯(cuò)



          0x05 eval 的注冊(cè)機(jī)制


          仿照上述操作,我們將下載到本地的代碼文件用瀏覽器打開后,令人不可思議的一幕發(fā)生了,本地的代碼竟然跟官方的代碼出現(xiàn)了一致的格調(diào):無限 debugger



          同時(shí)我們又發(fā)現(xiàn)了一個(gè)新的疑問:這些代碼從何而來?無論在線上還是本地,我們都無法捕捉到它的蹤跡。就像幽靈一般,沒等你感覺到,就憑空出現(xiàn)在了你的面前。嗯...這里有點(diǎn)故弄玄虛了哈。如果我們想要知道它的來源,其實(shí)也不是很難,可以在這份代碼最開始的地方打上斷點(diǎn)



          然后刷新瀏覽器后,根據(jù)它右側(cè)的調(diào)用棧信息,對(duì)它進(jìn)行定位追蹤。



          然后切換到它生成前的一步,就會(huì)有一些新的發(fā)現(xiàn):紅色箭頭所指的變量,是由字符串構(gòu)建成的代碼



          而調(diào)用它的函數(shù)竟然是 eval,換句話講,我們感到疑惑代碼都是由字符串拼接而成,然后通過 eval 函數(shù)執(zhí)行后變成了現(xiàn)在的這般形式,妙哉!



          0x06 層級(jí)關(guān)系


          在對(duì)代碼的運(yùn)行機(jī)制有過簡(jiǎn)單了解后,我們就可以把它做為切入點(diǎn)更加深入的去探究它的經(jīng)過。同時(shí),也要把耐心和興趣結(jié)合起來,因?yàn)橹挥羞@樣我們才能勇往直前又會(huì)樂在其中。


          如果有劃分的概念存在,我們將這段代碼分為三部分:


             1. 賦值層(變量賦值)



          2. 應(yīng)用層(各種函數(shù))


            


          3. VM 層(一個(gè)大到令人窒息的死循環(huán))



          0x07 屬性盲盒


          鑒于這種層級(jí)關(guān)系的存在,我們可以先從賦值層進(jìn)行研究。顧名思義,代碼在運(yùn)行之初給很多變量進(jìn)行了賦值操作,而且這些值基本屬于 javascript 的內(nèi)置函數(shù),其作用暫且不明。但有一部分賦值操作,更他娘的讓我們一頭霧水



          當(dāng)然,如果你想搞明白這件事情,我們可以利用斷點(diǎn)來一探究竟



          上述這些屬性儲(chǔ)存在一個(gè)大數(shù)組中,展開之后,讓我們看起來更加全面和具體。與此同時(shí)官方是利用索引的方式,對(duì)這些屬性進(jìn)行讀取和操作。看起來就像一個(gè)盲盒一樣,我們對(duì)它里面的內(nèi)容一無所知。所以我們暫且把它稱之為:屬性盲盒


          0x08 拆箱


          盲盒里的東西對(duì)我們確實(shí)極具吸引力,但要想對(duì)他逐個(gè)分析卻不太容易。不過我們可以借助 indexOf 索引工具,來對(duì)它一些關(guān)鍵的信息進(jìn)行提取



          嗯,通過上述操作得知,那些所謂的 cookiedebuggersetInterval 等一些相關(guān)方法不是它沒有引用,而是換一種方式對(duì)我們進(jìn)行了一次誤導(dǎo)。所以我們可以撥開迷霧,通過索引關(guān)系對(duì)他們逐一定位分析,比如:cookie



          可以看到與之 cookie 相關(guān)的共有13個(gè)結(jié)果,我們?cè)囍谄渲幸惶幋騻€(gè)斷點(diǎn)分析一下,這樣的話就能更好的去捕捉到運(yùn)行動(dòng)態(tài)



          如上圖我們就能定位到 cookie 生成的最終位置,然后根據(jù)右側(cè)調(diào)用棧的信息,我們還可以定位到它的初始位置



          由上圖可見,cookie 是由一個(gè) VM 層函數(shù)通過加工一個(gè)里面全是整型數(shù)字的數(shù)組而來



          而想要追溯到這些整型數(shù)字的來源,這個(gè)過程真的是太過復(fù)雜,這里面我只能介紹一下方法


          0x09 可以借鑒的分析方法


          因?yàn)樵?nbsp;VM 層有個(gè)索引,會(huì)決定代碼每次進(jìn)入到哪個(gè)流程去運(yùn)行。根據(jù)這種變化特點(diǎn),我們姑且稱它為:震蕩索引



          而R數(shù)有個(gè)特點(diǎn),就是在流程中,每個(gè)分支都比震蕩索引值大1,比如:震蕩索引值=255,那我們就可以去到 > 266 的流程去尋找流程還有一點(diǎn)就是 VM 頂層很多為了未定義的變量,在 VM 運(yùn)行的過程中都會(huì)漸漸產(chǎn)生變化




          我們也可以通過對(duì)他們插裝的方式,對(duì)他們進(jìn)行賦值關(guān)系進(jìn)行輸出,這樣的話也會(huì)對(duì)我們的分析過程帶來莫大的裨益


          0x10 metadata 閉包的緩存


          利用上一章所介紹的方法,我費(fèi)盡周折對(duì) cookie 的加密進(jìn)行了全方位的跟蹤。當(dāng)然,涉及的流程很多,這里我就先不一一列舉了。但我可以介紹一下它加密之前的都取了那些原始數(shù)據(jù)。一個(gè)是本地的 localStorage 另一個(gè)則是 metadata 的拆分區(qū)間。



          鑒于 localStorage 好理解也容易處理。接下來,著重研究一下 metadata 是怎么一回事兒



          如果細(xì)心的話,你會(huì)注意到,這個(gè) metadata 每一次請(qǐng)求都會(huì)發(fā)生變化,而這種變化是隨機(jī)無序且讓人倍感迷惑的。雖然我沒有探究過它的具體作用,但是有一點(diǎn)可以肯定,它的存在會(huì)跟 cookie 或者后面 MmEwMD 的簽名計(jì)算都有很大關(guān)系。當(dāng)然了官方還對(duì)它做了一個(gè)極其重要的操作:拆分



          如上圖所示,我們就可以看到 metadata 被拆分后的結(jié)果。而且還有一點(diǎn)需要注意的是,這個(gè)拆分過程是以函數(shù)嵌套形式存在的,也就是閉包模式




          所以遇到這種情況,我們一定要它先運(yùn)行 metadata 才會(huì)加入緩存,不然的話你讀不到 metadata 的拆分值



          但有個(gè)問題,我們把生成 cookie 的相關(guān)代碼全部扣出來,是不是就可以模擬生成正確的 cookie 了?答案:不能!

           

          0x11 配套原則的隨機(jī)變量


          先來看看我找出來計(jì)算 cookie 代碼的運(yùn)行結(jié)果



          雖然我沒有驗(yàn)證過 cookie 是否有效,但我想說明的問題是,這套代碼只適用于當(dāng)前你停留的初始化頁面,如果下一次發(fā)生新的初始化請(qǐng)求, metadata 被更換后就會(huì)出現(xiàn)一些異常



          后來,我發(fā)現(xiàn)原來是有個(gè)隨機(jī)值決定了 cookie 的計(jì)算,注意這個(gè)值是服務(wù)端返回的,有一定的隨機(jī)性。不過話說回來,在我們眼里這個(gè)值看似隨機(jī),但在服務(wù)端或許可能是存在一定的配套機(jī)制,只不過我們無從知曉而已



          由以上得出的結(jié)果,我們證明一件事:即便你計(jì)算出了 cookie 加密,但也僅限于當(dāng)前的使用。一旦頁面發(fā)生變化,你所有的努力都將付之一炬。所以對(duì)于 cookie 的計(jì)算,我們能不能換一種方式去進(jìn)行?或者說,我們能不能模擬出一個(gè)瀏覽器環(huán)境,讓它自動(dòng)拉取到 cookie ?答案是:可以的!


          0x12 jsdom 的應(yīng)用


          談起 nodejs 里的這個(gè)類庫(kù),可謂是集大成之作,也是模擬瀏覽器環(huán)境的不二之選。有興趣的可以谷歌一下,功能很多我這里不過多的贅述。然后利用這種工具我們可以模擬官方一樣的流程,將代碼插入到 jsdom 模擬的瀏覽器環(huán)境中,讓他自動(dòng)拉取 cookie,問題就會(huì)迎刃而解,不會(huì)在枉費(fèi)周折。



          這里的暫且不提供核心代碼,原因是簡(jiǎn)單:保命要緊但有幾個(gè)地方特別需要我們注意一下1.關(guān)于 python execjs 類庫(kù) 調(diào)用 js 問題



          可能是底層計(jì)算機(jī)制不一樣,使用這種方法,計(jì)算的 cookie 不正確。


          2.使用 express 搭建服務(wù)實(shí)現(xiàn)不了功能持久化。具體原因是:把代碼插入到 jsdom 環(huán)境后,緩存無法清除,這樣第二次再次插入代碼時(shí),跟上一次插入的代碼會(huì)產(chǎn)生沖突,導(dǎo)致什么也獲取不到



          3. 結(jié)合 node 的 minimist 的命令行交互命令,使用 pythonos.popen 直接調(diào)用會(huì)出現(xiàn)指令太長(zhǎng)的問題(畢竟傳入的是幾千行代碼和長(zhǎng)度過千的 metadata



          后來機(jī)緣巧合之下,我找到了這一問題的解決方案:我們可以把要傳入的參數(shù)變成 json 的字符串形式,并用 base64 進(jìn)行編碼。最后,通過下面的指令進(jìn)行傳參



          當(dāng)然別忘了,在 node 里面寫個(gè)方法對(duì) base64 編碼格式的數(shù)據(jù)進(jìn)行解碼,然后以這種方式,我們確實(shí)能夠完成列表頁的請(qǐng)求并拿到接口請(qǐng)求的 cookie




          0x13 簽名與請(qǐng)求的寄生關(guān)系


          讀到這里,或許有人會(huì)感到害怕和恐懼:寫了將近 5000 字,才剛剛把 202 的請(qǐng)求狀態(tài)給解決。那是不是研究它的簽名,又得洋洋灑灑寫下 5000 字?答案:當(dāng)不會(huì)的(我雖然能寫但我會(huì)惜墨如金)!因?yàn)橹灰阏J(rèn)真閱讀上述內(nèi)容,就會(huì)斷然的發(fā)現(xiàn),其實(shí)研究簽名跟研究 202 請(qǐng)求狀態(tài)如出一轍。只不過計(jì)算簽名的代碼是在列表頁返回的




          要想搞明白簽名的計(jì)算方式,我們需要了解一下 javascript hook 機(jī)制。可以最簡(jiǎn)單的打印為例



          如上圖可以看到,方法被 hook 后每次在調(diào)用 console.log 函數(shù)時(shí),都會(huì)加入我的個(gè)人簽名。同樣的問題,我們也會(huì)想。它每次請(qǐng)求都會(huì)出現(xiàn)一個(gè)簽名,那是不是官方也用了如法炮制了呢?



          確實(shí)有了不一樣的發(fā)現(xiàn)。如果你還看不懂話,可以對(duì)比一下正常的



          也就是說,它內(nèi)部的請(qǐng)求方法被重構(gòu)了。我們可以切入進(jìn)入去一探究竟



          如果加入斷點(diǎn),這個(gè)簽名就不期而然的出現(xiàn)在我們面前



          也就是說每次接口請(qǐng)求都會(huì)觸發(fā)計(jì)算簽名的函數(shù),然后將計(jì)算好的簽名掛到請(qǐng)求鏈接上。下面是生成簽名的方法



          0x14 歸檔整理


          在發(fā)現(xiàn)簽名的奧秘后,我們就可以繼續(xù)利用 jsdom 來完成簽名的計(jì)算。但有個(gè)問題也會(huì)順勢(shì)出現(xiàn)。就是說:你每次把動(dòng)態(tài)的代碼插入到 jsdom 環(huán)境中, XMLHttpRequest 確實(shí)被重構(gòu)了。但最根本的問題我們還是無法解決:拿不到簽名而且還會(huì)拋出請(qǐng)求的異常



          面對(duì)這類問題,我提供一個(gè)思路:再對(duì) XMLHttpRequest 進(jìn)行重構(gòu)。把它的請(qǐng)求機(jī)制改為返回機(jī)制。只能提示到這里,僅此而已


          最后附上一張效果圖:



          瀏覽 140
          點(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>
                  51妺嘿嘿午夜福利在线 | 无码人妻一区二区三区在线 | 欧美精品蜜桃69桔色 | 在线观看大机吧操逼 | 在线 中文字幕 日韩 |