當前位置:
首頁 > 新聞 > 如何使用Hex-Rays API有效解決問題

如何使用Hex-Rays API有效解決問題

一、簡介

IDA Pro是二進位逆向工程中的標準。它不僅是一個出色的反彙編器和調試器,還可以從Hex-Rays購買額外的許可來擴展更強大的反編譯器。然而在反彙編和反編譯代碼之間切換的能力可以大大縮短分析時間。

反編譯器(從現在開始稱為Hex-Rays)已經存在了很長時間,並且已經達到了很高的成熟度。但是,好像缺乏關於此主題的簡明和完整的資源(教程或其他)。本文的目標是通過示例展示使用Hex-Rays腳本可以提高效率、節約時間。

二、回顧反編譯器

為了理解反編譯器的工作原理,首先回顧一下正常的編譯過程。

編譯和反編譯以抽象語法樹(Abstract Syntax Tree (AST))為中心。本質上,編譯器會採用源代碼,根據語法將其分解為令牌,然後將這些令牌分組為邏輯表達式。在編譯過程階段,稱為解析,代碼結構被表示為一個複雜的對象AST。從AST中,編譯器將為指定的平台生成彙編代碼。

反編譯器採取相反的路線。從給定的彙編代碼,它返回生成一個AST,並從中生成偽代碼。

從代碼和彙編之間的所有中間步驟來看,AST非常重要,因為大部分時間都會使用Hex-Rays API,實際上就是正在讀取和/或修改抽象語法樹(或Hex-Rays中的ctree)。

三、項,表達式和語句

現在我們知道Hex-Rays的ctree是一個樹狀數據結構。此樹的節點是cinsn_t或cexpr_t類型的節點。我們將立即定義這些內容,它們都來自非常基本的類型,即citem_t類型,這一點很重要,如以下代碼片段所示:

因此,ctree中的所有節點都具有op屬性,表示節點類型(變數,數字,邏輯表達式等)。

op(ctype_t)類型是一個枚舉,其中所有常量都被命名為cit_(用於語句)或cot_(用於表達式)。記住這一點,因為這非常重要。檢查所有ctype_t常量及其值的快速方法是執行以下代碼片段:

產生如下輸出:

讓我們深入解釋兩種類型的節點:表達式和語句。

將表達式看作代碼的「小邏輯元素」是很有用的。它們從簡單類型(如變數,字元串或數字常量)到小代碼結構(賦值,比較,加法,邏輯操作,數組索引等)。

這些類型是cexpr_t,它是一個包含多個成員的大型結構。可以訪問的成員取決於其op值。例如,獲取數值的成員n在處理常量時才有意義。

另一方面,我們有發言權。這些與語言關鍵字大致相關(if, for, do, while, return等)。它們大多與控制流有關,可以被認為是代碼的「大圖片元素」。

綜上所述,我們已經看到反編譯器公開了這個類樹結構(ctree),它由兩種類型的節點組成:表達式和語句。為了從反編譯代碼中提取信息或修改反編譯代碼,我們必須通過依賴於節點類型的方法與ctree節點進行交互。但是,問題出現了:「如何到達節點?」

這是通過Hex-Rays的一個公開類完成的:樹訪問者(ctree_visitor_t)。這個類有兩個虛擬方法,visit_insn和visit_expr,它們在遍歷ctree時發現語句或表達式。可以通過繼承並重載相應的方法來創建自己的visitor類。

四、示例腳本

在本節中,我們將使用Hex-Rays API來解決兩個實際問題:

·識別對GetProcAddress的調用,動態解析Windows API,將結果地址分配給全局變數。

·為便於閱讀,將與堆棧字元串相關的分配顯示為字元而不是數字。

(一)GetProcAddress

我們將通過第一個例子是如何在運行時自動處理動態解析的重命名全局變數。這是惡意軟體用於在靜態分析工具隱藏其功能的常用技術。圖1顯示了使用GetProcAddress動態解析全局變數的一個示例。

圖1:使用GetProcAddress獲取動態API

有幾種方法可以重命名全局變數,最簡單的方法是手動複製和粘貼。但是,這個任務重複性強,可以使用Hex-Rays API編寫腳本。編寫任何Hex-Rays腳本,首先一點可視化ctree很重要。Hex-Rays SDK包含一個示例sample5,可用於查看當前函數的ctree。ctree中顯示的數據量可能會很大。使用該示例的修改版本來生成圖1所示函數的sub-ctree。單個表達式的sub-ctree:"dword_1000B2D8 =(int)GetProcAdress(v0,「CreateThread」);"如圖2所示。

圖2: GetProcAddress任務的Sub-ctree

在了解使用的sub-ctree的情況下,我們可以編寫一個腳本來自動重命名使用此方法分配的所有全局變數。

自動重命名所有局部變數的代碼如圖3所示。代碼通過遍歷ctree尋找對GetProcAddress函數的調用。一旦找到,代碼將獲取正在解析的函數的名稱,並找到正在設置的全局變數。然後代碼使用IDA MakeName API將地址重命名為正確的函數。

圖3: 重命名全局變數的函數

腳本執行完畢後,可以在圖4中看到所有的全局變數已經被重命名為相應函數的名稱。

圖4: 重命名的全局變數

(二)堆棧字元串

接下來的一個例子是處理惡意軟體時遇到的一個典型問題:堆棧字元串。這是一種旨在通過在代碼中使用字元數組而不是字元串來使分析變得更加困難的技術。在圖5中可以看到一個例子,惡意軟體將每個字元的ASCII值存儲在堆棧中,然後在調用sprintf時引用它。乍一看,很難知道這個字元串的含義是什麼(除非你知道ASCII表格)。

圖5: Hex-Rays的輸出,堆棧字元串很難閱讀

我們的腳本會將這些修改為更具可讀性的內容。代碼的重要部分是前面提到的ctree visitor,如圖6所示。

圖6: 自定義的ctree visitor

實現的邏輯非常簡單。定義一個ctree visitor的子類(第1行)並覆蓋它的visit_expr方法,這隻會在發現任務時發生(第9行)。要滿足的另一個條件是,任務的左側是一個變數,右側是一個數字(第15行)。此外,數值必須在可讀的ASCII範圍內(第20和21行)。

一旦找到這種表達式,我們將右邊的類型從數字改為字元串(第26至31行),並用對應的ASCII字元(第32行)替換它的數值。

運行此腳本之後修改的偽代碼如圖7所示。

圖7: 賦值顯示成字元

完整的腳本可以在我們的FLARE GitHub存儲庫decompiler scripts中找到。

五、總結

這兩個公認的簡單示例應該能夠讓人了解IDA反編譯器API的強大功能。在這篇文章中,我們已經介紹了所有反編譯器腳本的基礎:ctree對象,一個由表達式和語句表示代碼中的每個元素以及它們之間關係組成的結構。通過創建自定義visitor,我們展示了如何遍歷樹並讀取或修改代碼元素,從而分析或修改偽代碼。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

Memcached DDoS攻擊已出現緩解對策
對Avzhan DDoS bot的深入介紹及樣本的層層分析

TAG:嘶吼RoarTalk |