如何分析虛擬機器(2):進階篇 VMProtect 2.13.8
原文網址:https://www.52pojie.cn/forum.php?mod=viewthread&tid=723307&page=1
序言系列第1篇對一個極弱的虛擬機器 VMProtect 1.81 Demo 版進行了分析,初步展示了一下對虛擬機器保護程式碼的分析方法。 Demo 版因為程式碼沒有混淆處理,因此在 IDA 中可以分析的很清楚了,甚至還可以根據位元組碼(VM_DATA)一點點靜態還原虛擬指令。 然而正式版本的 VMProtect 虛擬機器是有比較嚴重的混淆的(實際是一種冗餘指令的新增),直接使用 IDA 分析十分困難,許多基本塊會截斷,也沒有第1篇中介紹的明顯的解釋迴圈圖結構。動態除錯也不方便,裡面大量的CALL\JMP,跳來跳去。ESI 還有指令的立即數等還有加密,整體複雜度有很大的提升。 對於這種情況如何處理呢?本文以 VMProtect 2.13.8 為例,展示如何在混淆比較嚴重的情況下找到虛擬機器關鍵結構、快速的分析 Handler,提取出虛擬指令。 本文主要介紹兩個關鍵的部分:
VMProtect 2.13.8 樣本說明這裡使用的樣本仍是第1篇中的程式碼加 VM 的。
加密級別為最大速度,目前我們只討論虛擬機器本身,其他諸如IAT保護、反除錯等其他 VMP 保護選項都關閉,讓我們專注於虛擬機器的分析。 其實即使到了 2.13.8 版本, VMProcect 的整體結構仍是和 VMProtect 1.81 一致的。 因此雖然存在混淆,經驗豐富的人還是可以迅速找到關鍵的指令分發點(Dispatcher)位置,從而找到跳轉表,提取所有的 Handler。 如下指令(加*的部分)就是典型的 dispatcher 程式碼,根據 0x404cf8 跳轉表,再找到 ESI 解密的方式,就可以提取所有 Handler。
這是前人總結出來的特徵。如果是不瞭解 VMProtect 的人,分析起來就要困難一些。 如果我們對 VMProtect 並不十分清楚,直接面對 VMProtect 2.13.8 版本的樣本該如何處理? 虛擬機器結構分析首先仍 IDA 開啟樣本,跳到 0x401000 處,看下前幾條指令: 其實這些程式碼並沒有什麼有用的操作,先向棧中壓入一些無用的資料,然後又通過 我們還是很喜歡第1篇中的 IDA 生成的控制流圖的。通過圖中明顯的解釋迴圈結構,可以很快的定位哪裡是 Dispatcher,哪裡是 Handler。但現在 jmp 和 call 干擾了 IDA 的分析,IDA 沒法生成完整的 CFG 圖。 為了恢復這個圖,我們還是使用 Trace 分析的方法。Trace 是 x86 指令執行的序列,Trace 中所有 jmp 和 call 會天然的和跳轉目標指令連線起來。Trace 分析其實是很強大的功能。單步執行時我們的注意力可能會被暫存器、記憶體的值所分散,而忽略了程式整體的執行情況。而通過對 Trace 的整體分析,則可以讓我們跳出區域性,從整體去觀察。 虛擬機器解釋執行的過程是一個迴圈:首先取指令,解碼,然後跳轉到 Handler 程式碼,執行完成後再跳轉回來。在 Trace 中我們如何捕捉這個關鍵的迴圈?我想到的方法是,由 Trace 構造一個像之前 IDA 顯示的 CFG 圖類似的圖。 通過找圖中的中心結點,來確定 dispatcher 的位置。 由 Trace 構造的圖,是反映了程式執行過程的基本塊圖,我們可以稱之為執行流圖。構造圖的方法說起來比較費力,直接看圖。 假設ABCD是執行的指令序列,按照每條指令在Trace中的先後順序,就可以構造一個圖。相鄰結點合併一下,就可以得到最終的執行流圖。最終 AB 形成一個塊,執行到 CDE 塊,再跳轉回來,再執行FG塊,再跳轉回來,再執行HI塊,再跳轉回來。整個執行的過程就很清楚了。通過寫指令碼分析 OD 的 Trace 檔案,就可以構造出這個圖,程式設計有基礎的同學實現一下並不困難。 我做過一個工具,具備生成這種圖的功能。不過為了 Trace 的效率,這個工具沒有使用 OD Trace,而是利用 Intel 的插裝工具 Pin 記錄指令序列。(這個工具還在寫,目前比較渣,不多介紹了。如果寫好了會單獨寫文章介紹。想嚐鮮可以自己下載下來編譯原始碼,傳送門在 https://github.com/lmy375/pinvmp ) 下面是用這個工具分析 VMP 樣本生成的執行流圖。 (圖太大無法顯示清楚,看得清基本的結構就好,完整的SVG格式圖見附件) 這回已經非常直觀了。圖中間的結點跳轉到其他結點中再跳轉回來,是典型的 dispatcher 結構,並列成排的每個程式碼塊,就是 Handler 程式碼塊。 dispatcher 結點的程式碼如下: 除了註釋外的程式碼,大多是混淆作用,不用關心。 Handler 分析接下來看 Handler 程式碼。當然我們也可以一個一個人工分析 Handler 程式碼。因為 VMProtect 的混淆沒有程式碼變形,只是添加了很多的棧指令。 因為原本的程式碼沒變,人工分析也不困難,對於瞭解 VMP 的人,即使人工分析,分析每個Handler也不會太困難。 然而如果不瞭解 VMP Handler 的特徵,看這種混淆程式碼是很痛苦的。 這裡介紹一種利用符號執行分析 Handler 的方法。(參考:http://www.miasm.re/blog/2016/09/03/zeusvm_analysis.html) 首先簡單說明一下什麼是符號執行。符號執行是將所有暫存器和記憶體當作符號變數,然後模擬執行所有語句。執行完畢後,每個暫存器和寫入的記憶體都會變成符號表達式。 比如如下程式碼 記eax和ebx的值是 最終的結果 說明執行了上述程式碼, eax 增加了初始值的 1;ebx 變成 ebx 初始值加 ecx;ecx 還是初始值不變。值得注意的是 ebx 加 eax 又減 eax 這個過程沒有顯示在最終的結果裡,符號執行引擎把結果化簡了。VMP 新增的指令就是這類不影響最終結果的指令,因此可以被符號執行引擎化簡掉。 下面證明我們的想法。 使用 Miasm 這個符號執行引擎去分析混淆的程式碼。(Miasm:https://github.com/cea-sec/miasm) 以如下的 Handler 程式碼塊為例: 我們把所有跳轉指令去掉,當作一個連續的程式碼塊。然後把每條指令的二進位制位元組提取出來,拼接在一起,十進位制表示如下: 之所以轉化成二進位制是為了方便使用 Miasm 進行符號執行(程式碼參考:https://github.com/lmy375/pinvmp/blob/master/py/symexec.py ) 符號執行後,可以輸出如下結果: 上面的表示式是Miasm使用的表示式 其中
因此可以很容易的確定這條指令是 vPushImm1。 這樣分析起來就容易了非常多。(後面有時間會寫一篇利用符號執行處理 Code Virtualizer 混淆的例子,效果也十分明顯!) 很方便就可以分析出每條 Handler。 提取偽指令及偽指令分析分析完每條 handler 後,就可以從 Trace 中取出 Handler 的呼叫序列。 方法和第1篇一樣,首先用 OD2 跑 Trace,再寫指令碼還原虛擬碼。 同樣的對於需要使用暫存器或者立即數的指令,需要額外處理一下。 比如前面的 而對於 push 和 pop 指令 我們這次除了從Trace中提取出暫存器下標,還提取出讀寫的暫存器值,方便我們分析虛擬碼。 VMProtect 2.13.8 相對之前的 Demo 版本,不但虛擬機器內部混淆有明顯增強,關鍵是虛擬碼級別變得更加難複雜了。(這其實才是 VMP 強度的關鍵) 其實虛擬碼也是可以利用前面介紹的符號執行方法進行分析,不過需要自行處理偽指令的語義(後面有空的話會專門寫東西講利用符號執行分析偽指令) 這裡簡單人肉分析一下: 總結本篇介紹了利用 Trace 和符號執行分析 VMProtect 2.13.8 的方法。其實只是大概提下思路,想要完全自動化分析還有很長的路要走。 Trace 分析這種方法對混淆程式碼其實還是不錯的,動態執行資訊有了,比靜態看 IDA 要好很多。但這種方法也是有侷限的,首先Trace 檔案可能會非常大,處理起來很麻煩。另一方面 Trace 只記錄跑過的指令,沒有跑過的程式碼 Trace 是分析不到的。就像文中所述,這個VMP樣本使用 Trace 大概只能提取到 20 多個 Handler,因為樣本實際只用到了這麼多。 符號執行是個新東西。對於學術界可能不新了,但是開始出現好用的實用工具如 angr, miasm, triton 等也是近年的事。這種新方法如果應用到虛擬機器保護上也許會有奇效。 (文章涉及的樣本、IDB檔案、Trace檔案、部分指令碼見附件,密碼123456) Moon (本文也發於看雪 https://bbs.pediy.com/thread-225803.htm ) |
2.14 MB, 下載次數: 85, 下載積分: 吾愛幣 -1 CB