在使用某插件的過程中,大量個性化需求不能滿足,於是我有了更改源碼的衝動。翻遍所有角落,只找了一份壓縮混淆的 js 文件。
能否反混淆,這是本節討論的重點。
一、場景復現
先來說說幾種我們迫切需要知道源碼的情況:
1.閱讀源碼,當然,大部分開源的代碼都是可以直接查看的;
2.對某插件做個性化的需求更改,這時候你渴望看到未混淆壓縮的代碼;
3.為了增加代碼分析的難度,混淆(obfuscate)工具被應用到了許多惡意軟件(如 0day 掛馬、跨站攻擊等)當中。
分析人員為了掀開惡意軟件的面紗,首先就得對腳本進行反混淆(deobfuscate)處理。
4.當你準備抄襲別人代碼時,這個稍微有點不可描述;
本文,我們假設是在前兩種場景的條件下,來探索一下 js 反混淆問題。
二、尋求方案
為了快速的解決問題,我們首先嚐試一下現有方案:
http://jsnice.org/
一個簡單的示例:
解析後:
是不是反混淆之後,可讀性強了很多。
2.js 代碼混淆站長工具
我們先從 Lodash 找一段演示代碼,如下:
普通混淆後,就變成了這樣:
為了測試一下如何反混淆,我們將混淆後代碼拷貝到 jsnice :
可以看到,普通混淆後,代碼還是可以做一些復原。
好的,我們加大力度,採用加密壓縮方式。這次代碼明顯多了,而 jsnice 也反混淆失敗了:
這段代碼,地球人已經沒法讀懂了,亂七八糟的。那麼,問題來了,加密混淆的代碼真的沒有辦法復原嗎?
三、思維突破
從上面的演示可以看出來,加密之後的混淆,已經完全無法反混淆了。
除非我們知道混淆算法,可是混淆方式不計其數,你需要知曉它的混淆方式,並制定出反混淆算法,那估計會累死。
如果我們這麼想的話,那麼就陷入了泥潭,甚至無法自救。那麼,突破點到底在哪裡呢?
眾所周知,JavaScript 是解釋性語言,它嚴重依賴遊覽器。不管 JavaScript 如何混淆,最終瀏覽器都會知道最真實的代碼。所以,我們還得以瀏覽器為突破口。
首先,同步一下原始代碼:
其次,確定源碼中是否包含在 eval 中,參考代碼如下:
然後,查找關鍵字 throw,如果有,那就成功了一大步;
最後,改動源碼,讓源碼拋出異常,讓 Eval Code 還原出真實代碼;
可以看到,為了演示,我們讓源代碼具有某些特性,然而實際情況會遠遠複雜於此;
四、相關工具介紹
我們先來看一下,目前常用的混淆工具:
- YUI Compressor
- Google Closure Compiler
- UglifyJS
- JScrambler
反混淆工具:
- jsbeautifier
- JSDetox
瞭解更多,請參考:幾種常見的JavaScript混淆和反混淆工具分析實戰
五、瞭解混淆手段
1.base62 編碼,其最明顯的特徵是生成的代碼以
eval(function(p,a,c,k,e,r)) 開頭;看到這裡,上述站長工具的加密方式,就不難理解了。
這類混淆的關鍵思想在於將需要執行的代碼進行一次編碼,在執行的時候還原出瀏覽器可執行的合法的腳本,然後執行之。
看上去和可執行文件的加殼有那麼點類似。Javascript 提供了將字符串當做代碼執行(evaluate)的能力,可以通過 Function 構造器、eval、setTimeout、setInterval 將字符串傳遞給 js 引擎進行解析執行。
無論代碼如何進行變形,其最終都要調用一次 eval 等函數。
解密的方法不需要對其算法做任何分析,只需要簡單地找到這個最終的調用,改為 console.log 或者其他方式,將程序解碼後的結果按照字符串輸出即可。
2.隱寫術
嚴格說這不能稱之為混淆,只是將 js 代碼隱藏到了特定的介質當中。
如通過最低有效位(LSB)算法嵌入到圖片的 RGB 通道、隱藏在圖片 EXIF 元數據、隱藏在 HTML 空白字符等。
比如這個聳人聽聞的議題:《一張圖片黑掉你》在圖片中嵌入惡意程序,正是使用了最低有效位平面算法。結合 HTML5 的 canvas 或者處理二進制數據的 TypeArray,腳本可以抽取出載體中隱藏的數據(如代碼)。
隱寫的方式同樣需要解碼程序和動態執行,所以破解的方式和前者相同,在瀏覽器上下文中劫持替換關鍵函數調用的行為,改為文本輸出即可得到載體中隱藏的代碼。
3.複雜表達式
代碼混淆不一定會調用 eval,也可以通過在代碼中填充無效的指令來增加代碼複雜度,極大地降低可讀性。
Javascript 中存在許多稱得上喪心病狂的特性,這些特性組合起來,可以把原本簡單的字面量(Literal)、成員訪問(MemberExpression)、函數調用(CallExpression)等代碼片段變得難以閱讀。
在 js 中可以找到許多這樣互逆的運算,通過使用隨機生成的方式將其組合使用,可以把簡單的表達式無限複雜化。
深入瞭解,請移步使用 estools 輔助反混淆 Javascript。
六、寫在最後
JavaScript 作為一個以函數式為核心的多範式動態弱類型腳本語言,因為它的靈活性,導致了源代碼在經過一些壓縮工具處理後,變得極難還原。
也有可能,當我們費勁心思還原出來的代碼,也許只是與源代碼運行流程一致的另一套代碼。當然,我們可以繼續探索,發掘未知的領域。
1.
2.
3.
閱讀更多 F2EAwesome 的文章