說說 JS 反混淆與常用手段

說說 JS 反混淆與常用手段

在使用某插件的過程中,大量個性化需求不能滿足,於是我有了更改源碼的衝動。翻遍所有角落,只找了一份壓縮混淆的 js 文件

能否反混淆,這是本節討論的重點。

一、場景復現

說說 JS 反混淆與常用手段

先來說說幾種我們迫切需要知道源碼的情況:

1.閱讀源碼,當然,大部分開源的代碼都是可以直接查看的;

2.對某插件做個性化的需求更改,這時候你渴望看到未混淆壓縮的代碼;

3.為了增加代碼分析的難度,混淆(obfuscate)工具被應用到了許多惡意軟件(如 0day 掛馬、跨站攻擊等)當中。

分析人員為了掀開惡意軟件的面紗,首先就得對腳本進行反混淆(deobfuscate)處理。

4.當你準備抄襲別人代碼時,這個稍微有點不可描述;

本文,我們假設是在前兩種場景的條件下,來探索一下 js 反混淆問題。

二、尋求方案

說說 JS 反混淆與常用手段

為了快速的解決問題,我們首先嚐試一下現有方案:

http://jsnice.org/
說說 JS 反混淆與常用手段

一個簡單的示例:

說說 JS 反混淆與常用手段

解析後:

說說 JS 反混淆與常用手段

是不是反混淆之後,可讀性強了很多。

2.js 代碼混淆站長工具

我們先從 Lodash 找一段演示代碼,如下:

說說 JS 反混淆與常用手段

普通混淆後,就變成了這樣:

說說 JS 反混淆與常用手段

為了測試一下如何反混淆,我們將混淆後代碼拷貝到 jsnice :

說說 JS 反混淆與常用手段

可以看到,普通混淆後,代碼還是可以做一些復原。

好的,我們加大力度,採用加密壓縮方式。這次代碼明顯多了,而 jsnice 也反混淆失敗了:

說說 JS 反混淆與常用手段

這段代碼,地球人已經沒法讀懂了,亂七八糟的。那麼,問題來了,加密混淆的代碼真的沒有辦法復原嗎?

三、思維突破

從上面的演示可以看出來,加密之後的混淆,已經完全無法反混淆了。

除非我們知道混淆算法,可是混淆方式不計其數,你需要知曉它的混淆方式,並制定出反混淆算法,那估計會累死。

如果我們這麼想的話,那麼就陷入了泥潭,甚至無法自救。那麼,突破點到底在哪裡呢?

眾所周知,JavaScript 是解釋性語言,它嚴重依賴遊覽器。不管 JavaScript 如何混淆,最終瀏覽器都會知道最真實的代碼。所以,我們還得以瀏覽器為突破口。

首先,同步一下原始代碼:

說說 JS 反混淆與常用手段

其次,確定源碼中是否包含在 eval 中,參考代碼如下:

說說 JS 反混淆與常用手段

然後,查找關鍵字 throw,如果有,那就成功了一大步;

最後,改動源碼,讓源碼拋出異常,讓 Eval Code 還原出真實代碼;

可以看到,為了演示,我們讓源代碼具有某些特性,然而實際情況會遠遠複雜於此;

四、相關工具介紹

說說 JS 反混淆與常用手段

我們先來看一下,目前常用的混淆工具:

  • YUI Compressor
  • Google Closure Compiler
  • UglifyJS
  • JScrambler

反混淆工具:

  • jsbeautifier
  • JSDetox

瞭解更多,請參考:幾種常見的JavaScript混淆和反混淆工具分析實戰

五、瞭解混淆手段

說說 JS 反混淆與常用手段

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

六、寫在最後

說說 JS 反混淆與常用手段

JavaScript 作為一個以函數式為核心的多範式動態弱類型腳本語言,因為它的靈活性,導致了源代碼在經過一些壓縮工具處理後,變得極難還原。

也有可能,當我們費勁心思還原出來的代碼,也許只是與源代碼運行流程一致的另一套代碼。當然,我們可以繼續探索,發掘未知的領域。

1.

2.

3.

說說 JS 反混淆與常用手段


分享到:


相關文章: