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

          JavaScript 混淆與逆向必讀之 AST 語(yǔ)法樹

          共 4357字,需瀏覽 9分鐘

           ·

          2020-08-16 10:17

          我在《Python3 反爬蟲原理與繞過(guò)實(shí)戰(zhàn)》[1]一書中給出了“爬蟲與反爬蟲都是綜合技術(shù)的應(yīng)用”、“技術(shù)在對(duì)抗中進(jìn)步”這樣的觀點(diǎn)。隨著時(shí)間的推移、技術(shù)的普及和進(jìn)步,Web 應(yīng)用方給爬蟲增加了越來(lái)越多的限制,其中效果最顯著的就是代碼混淆。

          單純的加密算法或者自定義的字符處理函數(shù)已經(jīng)無(wú)法滿足防御需求了, Web 應(yīng)用方將目光轉(zhuǎn)移到了代碼混淆技術(shù)。代碼混淆有幾個(gè)優(yōu)點(diǎn):

          ?操作門檻低,有現(xiàn)成可用且免費(fèi)的混淆產(chǎn)品;?混淆效果好,混淆后真的是連親媽都不認(rèn)識(shí);?瀏覽器能夠正常解析混淆后的代碼,一萬(wàn)行以內(nèi)的小規(guī)?;煜龑?duì)性能影響不大;?混淆帶來(lái)的性能影響可以通過(guò)其他優(yōu)化降低,不慌;

          加密算法和字符串處理函數(shù)配合代碼混淆,防御力直線上升。舉個(gè)簡(jiǎn)單例子,一個(gè)簡(jiǎn)單的字符處理函數(shù)如下:

          這里有三個(gè)函數(shù),stringArray 返回一個(gè)包含字符的數(shù)組對(duì)象、mergeArray 將數(shù)組對(duì)象里的元素拼接成為一個(gè)字符串并返回、main 調(diào)用 stringArray 函數(shù)和 mergeArray 函數(shù)并打印得到的字符串,下方的 output 注釋即運(yùn)行結(jié)果。

          這么清晰明了的函數(shù)調(diào)用,爬蟲工程師能看不懂嗎?

          我們看看上面三個(gè)函數(shù)混淆后的樣子:

          一樣的功能、一樣的輸出,但是代碼卻完全不一樣了,變得不可讀。如果把下面的注釋去掉,那你根本就不知道發(fā)生了什么,也不知道會(huì)輸出什么,這就是代碼混淆給 Web 應(yīng)用方帶來(lái)的防御力。

          作為一名爬蟲工程師,你現(xiàn)在有兩個(gè)選擇:

          1.通過(guò)一個(gè)入口函數(shù)強(qiáng)行找出關(guān)聯(lián)的函數(shù)調(diào)用,直到鋪滿調(diào)用鏈后拿到正確的輸出;2.還原部分混淆,從這堆雜亂無(wú)章的代碼中捋清邏輯,再根據(jù)復(fù)雜度選擇用其他語(yǔ)言實(shí)現(xiàn)或回到第一步;

          第一種方法,就是平時(shí)爬蟲工程師說(shuō)的“硬扣”,如果有跨文件的函數(shù)調(diào)用和冗長(zhǎng)復(fù)雜的調(diào)用鏈,那“硬扣”真的是會(huì)掉頭發(fā)的。

          第二種方法的技術(shù)門檻稍微高一些,需要爬蟲工程師懂得 AST 理論,并學(xué)會(huì)編寫還原代碼,將雜亂無(wú)章的代碼閱讀難度降低,從而降低自己閱讀代碼邏輯或者整理調(diào)用鏈的難度與成本。

          什么是 AST?

          這里引用百度百科對(duì) AST 的解釋:

          在計(jì)算機(jī)科學(xué)中,抽象語(yǔ)法樹Abstract?Syntax?Tree,AST),或簡(jiǎn)稱語(yǔ)法樹(Syntax tree),是源代碼語(yǔ)法結(jié)構(gòu)的一種抽象表示。它以樹狀的形式表現(xiàn)編程語(yǔ)言的語(yǔ)法結(jié)構(gòu),樹上的每個(gè)節(jié)點(diǎn)都表示源代碼中的一種結(jié)構(gòu)。之所以說(shuō)語(yǔ)法是“抽象”的,是因?yàn)檫@里的語(yǔ)法并不會(huì)表示出真實(shí)語(yǔ)法中出現(xiàn)的每個(gè)細(xì)節(jié)。比如,嵌套括號(hào)被隱含在樹的結(jié)構(gòu)中,并沒(méi)有以節(jié)點(diǎn)的形式呈現(xiàn);而類似于 if-condition-then 這樣的條件跳轉(zhuǎn)語(yǔ)句,可以使用帶有兩個(gè)分支的節(jié)點(diǎn)來(lái)表示。

          嗯,這看起來(lái)有點(diǎn)繞,我打算用一個(gè)例子來(lái)表述。JavaScript 變量聲明和賦值的代碼示例如下:

          var nick = "vansenb";

          這一行代碼會(huì)被解析成很長(zhǎng)的語(yǔ)法樹,具體解析可通過(guò)?AST Explorer[2]?查看。以下是 JavaScript 語(yǔ)句和語(yǔ)法樹的對(duì)應(yīng)關(guān)系:

          圖有點(diǎn)模糊,想看清晰結(jié)構(gòu)的請(qǐng)移步 AST Explorer。

          AST 有什么用?

          上圖的語(yǔ)法樹中表明了程序主體、聲明類型、標(biāo)識(shí)符、字面量等信息,由此我們可以得出:

          ?var - VariableDeclarator 變量聲明;?nick - Identifier 標(biāo)識(shí)符;?vansenb - Literal 字面量;

          從人類閱讀的角度來(lái)看,這行代碼:聲明了一個(gè)名為 nick 、值為 vansenb 的變量。

          如果你想改變這行代碼,將它變成:

          var nick = "James";

          只需要改變語(yǔ)法樹中 type 為 Literal 下的 value 屬性對(duì)應(yīng)的值即可,那么代碼的語(yǔ)義就變成了:聲明了一個(gè)名為 nick 、值為 James 的變量。了解到這一點(diǎn)之后,我們就可以思路放在代碼的混淆和還原上面了。

          你想想,當(dāng)你使用那些一鍵混淆/還原工具的時(shí)候,是不是只需要將代碼粘貼到輸入框并點(diǎn)擊“混淆”按鈕即可得到混淆后的代碼?而且相同結(jié)構(gòu)的代碼混淆后的結(jié)構(gòu)也是相同的?

          這說(shuō)明一鍵混淆/還原工具通過(guò)改變?cè)a的抽象語(yǔ)法樹實(shí)現(xiàn)混淆/還原的效果,例如在樹的某個(gè)節(jié)點(diǎn)前后增加或刪除節(jié)點(diǎn),亦或在混淆時(shí)將原本直接可以輸出結(jié)果的單個(gè)函數(shù)轉(zhuǎn)換為相互調(diào)用的多個(gè)函數(shù)。

          常用的 JavaScript AST 解析庫(kù)

          語(yǔ)法樹并不是 JavaScript 獨(dú)有的,幾乎所有編程語(yǔ)言都有語(yǔ)法樹,例如 Golang、Python 和 Java。JavaScript 的語(yǔ)法樹出現(xiàn)頻次較高,這是因?yàn)?JavaScript 隔代語(yǔ)法的差異和不得不考慮的兼容性造成的,ES5 和 ES6 語(yǔ)法隔代,在實(shí)際應(yīng)用中會(huì)需要進(jìn)行語(yǔ)法的轉(zhuǎn)換,這就使得語(yǔ)法樹能夠在實(shí)際場(chǎng)景中發(fā)揮作用。

          語(yǔ)法樹的作用就像是一個(gè)轉(zhuǎn)接頭,把代碼的表現(xiàn)形式 A 轉(zhuǎn)換為表現(xiàn)形式 B

          JavaScript 領(lǐng)域常用的 AST 解析庫(kù)有 babel、esprima、espree 和 acorn 等,各位工程師可根據(jù)自己的喜好和風(fēng)格選擇趁手的庫(kù)。

          這些庫(kù)常常被前端開(kāi)發(fā)工程師用來(lái)編寫代碼轉(zhuǎn)換的工具或者代碼混淆工具,甚至是將 React 和 Vue 的工程代碼編譯為瀏覽器能運(yùn)行的 JavaScript 代碼,而在爬蟲工程師這里,大概率會(huì)用來(lái)輔助自己逆向 JavaScript 代碼。

          AST 節(jié)點(diǎn)類型名詞基礎(chǔ)

          語(yǔ)法樹相關(guān)的知識(shí)和技巧需要一定的時(shí)間學(xué)習(xí)(大概一兩個(gè)月),對(duì)此感興趣的你可以通過(guò)以下幾篇實(shí)戰(zhàn)型文章了解它的具體應(yīng)用:

          AST 還原 obfuscator 混淆[3]

          操作AST還原混淆代碼基礎(chǔ)系列課程三:十六進(jìn)制字符串還原

          操作AST還原混淆代碼:讓代碼分析變得如此簡(jiǎn)單

          AST實(shí)戰(zhàn):全自動(dòng)解密經(jīng)obfuscator混淆的加密字符串

          操作AST還原混淆代碼課程九:還原簡(jiǎn)單的CallExpression 類型

          上面列舉了常用的幾個(gè) AST 解析庫(kù),雖然各個(gè)庫(kù)解析同一份代碼得到的結(jié)構(gòu)不完全一致,但用于表示節(jié)點(diǎn)類型的名詞幾乎都是一致的,例如 VariableDeclaration 代表這是變量聲明語(yǔ)句、CallExpression 代表這是調(diào)用表達(dá)式。

          掌握節(jié)點(diǎn)類型的名詞,有助于我們?cè)陂喿x語(yǔ)法樹結(jié)構(gòu)時(shí)更清晰地了解節(jié)點(diǎn)的作用和意圖,也可以說(shuō)節(jié)點(diǎn)名詞是我們成為代碼混淆大師或代碼逆向大師的必經(jīng)之路,非常重要!

          我們以下圖的代碼為例,看看 AST 中常用的節(jié)點(diǎn)類型名詞有哪些。

          上圖代碼包含了 JavaScript 語(yǔ)法中常用的語(yǔ)句,例如變量聲明、函數(shù)聲明、三元表達(dá)式、if 控制流語(yǔ)句、switch 控制流、函數(shù)調(diào)用、賦值語(yǔ)句、數(shù)組聲明、for 循環(huán)等。

          將上面的代碼復(fù)制到 AST Explorer 便可以得到語(yǔ)法樹,根據(jù)左側(cè)的代碼和右側(cè)的語(yǔ)法樹,我們可以統(tǒng)計(jì)語(yǔ)法樹節(jié)點(diǎn)名詞和具體描述,如下表:

          序號(hào)類型原名稱中文名稱描述
          1Program程序主體整段代碼的主體
          2VariableDeclaration變量聲明聲明一個(gè)變量,例如 var let const
          3FunctionDeclaration函數(shù)聲明聲明一個(gè)函數(shù),例如 function
          4ExpressionStatement表達(dá)式語(yǔ)句通常是調(diào)用一個(gè)函數(shù),例如 console.log()
          5BlockStatement塊語(yǔ)句包裹在 {} 塊內(nèi)的代碼,例如 if (condition){var a = 1;}
          6BreakStatement中斷語(yǔ)句通常指 break
          7ContinueStatement持續(xù)語(yǔ)句通常指 continue
          8ReturnStatement返回語(yǔ)句通常指 return
          9SwitchStatementSwitch 語(yǔ)句通常指 Switch Case 語(yǔ)句中的 Switch
          10IfStatementIf 控制流語(yǔ)句控制流語(yǔ)句,通常指 if(condition){}else{}
          11Identifier標(biāo)識(shí)符標(biāo)識(shí),例如聲明變量時(shí) var identi = 5 中的 identi
          12CallExpression調(diào)用表達(dá)式通常指調(diào)用一個(gè)函數(shù),例如 console.log()
          13BinaryExpression二進(jìn)制表達(dá)式通常指運(yùn)算,例如 1+2
          14MemberExpression成員表達(dá)式通常指調(diào)用對(duì)象的成員,例如 console 對(duì)象的 log 成員
          15ArrayExpression數(shù)組表達(dá)式通常指一個(gè)數(shù)組,例如 [1, 3, 5]
          16NewExpressionNew 表達(dá)式通常指使用 New 關(guān)鍵詞
          17AssignmentExpression賦值表達(dá)式通常指將函數(shù)的返回值賦值給變量
          18UpdateExpression更新表達(dá)式通常指更新成員值,例如 i++
          19Literal字面量通常指字符串型的字面量
          20BooleanLiteral布爾型字面量布爾值,例如 true false
          21NumericLiteral數(shù)字型字面量數(shù)字,例如 100
          22StringLiteral字符型字面量字符串,例如 vansenb
          23SwitchCaseCase 語(yǔ)句通常指 Switch 語(yǔ)句中的 Case

          這只是常用的那部分,更多節(jié)點(diǎn)類型名詞在你需要用到時(shí)再補(bǔ)充即可。我會(huì)持續(xù)更新相關(guān)資料,感興趣的朋友可以到夜幕團(tuán)隊(duì)的 GitHub 倉(cāng)庫(kù) https://github.com/NightTeam/JavaScriptAST 查看 。

          有了這些名詞對(duì)照關(guān)系之后,我們閱讀語(yǔ)法樹結(jié)構(gòu)就變得簡(jiǎn)單了。當(dāng)你看到節(jié)點(diǎn) tpye 為 IfStatement 的時(shí)候,你知道后面必定會(huì)有至少一個(gè) BlockStatement,即 if (condition){}。

          移動(dòng)端看不清表格可以看圖:

          References

          [1]?《Python3 反爬蟲原理與繞過(guò)實(shí)戰(zhàn)》:?https://item.jd.com/12794078.html
          [2]?AST Explorer:?https://astexplorer.net/
          [3]?AST 還原 obfuscator 混淆:?https://blog.csdn.net/zhao_5352269/article/details/106492177



          推薦閱讀


          就想寫個(gè)爬蟲,我到底要學(xué)多少東西???

          華為"天才少年"火了!剛畢業(yè)就拿201萬(wàn)年薪,全球僅4人!又是這個(gè)學(xué)校的



          THANKS

          - End -



          點(diǎn)個(gè)“在看”必升職加薪喔!
          瀏覽 128
          點(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>
                  欧美拍拍视频 | 豆花视频操逼视频 | 免费看男女操逼的网站 | 国产高清成人a片 | 熟女少妇内射日韩亚洲 |