本文講的是<b>程式設計實作小型虛拟機保護并逆向分析及其保護</b>,
1.引言
虛拟機保護技術已經出現了10多年,目前已有較多、較為成熟的商業化虛拟機保護産品,如VMProtect、Themida等。這些産品實作的虛拟機過于複雜,而本文僅僅是逆向分析和程式設計實作小型虛拟機保護,這種小型虛拟機僅用于說明虛拟機保護這種技術,可以用于開發CrackMe,但與真正的虛拟機保護還有非常遠的路要走。
2017年看雪CTF大賽正在火熱征題中,防守組的各位參賽者随手寫一個适用于自己CrackMe的虛拟機,相信可以如虎添翼。
GitHub确實是個好地方,寫代碼之前可以先去逛一逛。筆者原本打算自行寫一個小型虛拟機,不過在GitHub找到了非常理想的代碼,是以幹脆把這份代碼拿出來說一說。這份代碼出自NWMonster大神的CrackMe倉庫。
本文的後續按照如下方式組織:首先逆向分析一下這個CrackMe,進而分析一下源碼并實作自己的小型虛拟機,最後是一個小小的總結。
2.逆向分析
在逆向分析之前,了解一點關于小型虛拟機的程式結構還是很有幫助的。一般來講,一個小型的虛拟機保護結構圖如下:

上圖中,VM_code代表虛拟機可以解讀的位元組碼,VM_register為虛拟機使用的寄存器,在一次VM_loop中,虛拟機讀取VM_code,并根據讀取的内容選擇并執行相應的VM_handler。為了明确被虛拟機保護的代碼所實作的功能,我們需要了解每個VM_handler的含義,進而了解被隐藏的代碼。
需要注意的是,該流程圖并不适用于商業虛拟機保護軟體,商業的虛拟機保護往往更複雜一些。
通常情況下,可以使用OllyDbg (OD)的trace功能,找到虛拟機的VM_loop。但本次我們使用IDA完成分析,這主要因為IDA的圖形界面更加清晰明了。為了友善調試,筆者将源碼重新編譯為32位windows的debug版本。後文會把所有的材料都上傳到Github,需要的讀者可自行下載下傳。
用IDA打開CrackMe,不難發現其207位元組的VM_code:
上圖中的VM_code被指派給[eax + 20h],如下圖:
根據這些代碼,可以推測VM_register的結構如下:
其中,eax指向VM_register,[eax + 20h]指向虛拟機的指令寄存器。緊接着就可以找到完整的VM_loop,如下圖:
數一下上圖中的方塊數量,可以推測這裡有大約23個VM_handler。下面開始根據VM_code的順序逐一分析這些VM_handler。VM_code的第一個位元組為0xDE,該位元組會使虛拟機執行VM_handler_defaultcase,如下圖所示:
而VM_handler_defaultcase的詳細内容如下:
上圖中,[this + 0x24]即為指令寄存器,因為VM_register是VM類中的第一個元素,其僞代碼如下:
是以,在0x20的基礎上又增加了0x4位元組的偏移。這段代碼并無實際功能,隻增加了指令寄存器,故可了解為NOP指令。VM_code中的第2,3,4位元組同樣會令虛拟機執行VM_handler_defaultcase分支,故可以如下代碼重寫VM_code:
VM_code的第5個位元組為0x7C,該位元組會使虛拟機執行VM_handler_22分支,該分支的具體内容如下:
該段代碼的含義是:将後續0xF位元組的VM_code與0x66異或。暫不清楚其異或的目的為何。可以用如下方式表示該指令:
VM_code的第21位元組為0x70,與之相應的VM_handler_10的内容如下:
這個VM_handler的作用是明顯是入棧操作,即将後續4位元組的VM_code壓入虛拟機的棧,其[this + 20h]為棧指針。由此,可以進一步推斷出VM_register結構如下:
該虛拟機指令可表示如下:
到此為止,筆者已經分析了25位元組的VM_code和3個VM_handler以及一部分VM_register,後續内容還是留給感興趣的讀者。此外,其被虛拟機保護的代碼被還原為等價的C代碼也上傳到了Github,供讀者參考。
3.程式設計實作小型虛拟機
根據已有的源代碼,可以很友善的構造小型虛拟機。首先來看一下該源代碼,虛拟機使用的VM_register結構如下圖:
其中,cf為标志位,*db指向使用者輸入資料。虛拟機中的VM_loop是通過一個while-switch結構實作的:
上圖中的r.ip指向虛拟機的VM_code,該位元組碼被定義為一個位元組數組,如圖:
而完整的虛拟機類,即VM類如下圖:
其中,結構體REG即為VM_register,為VM類的第一個成員。虛拟機中的各個VM_handler也可以在該類中找到。在每次VM_loop中,虛拟機讀取 VM_code,并選擇執行響應的VM_handler。
基于這些已有代碼,構造一個定制的虛拟機變得非常簡單。可以使用已有的VM_handler和VM_register,也可以增加更多的VM_handler,并适當地增加一些混淆。增加混淆的VM_handler會使虛拟機保護更加難以分析。
在已有的架構之上,定制虛拟機的問題是變為設計一段VM_code用來實作所需目的即可。比如說,如果我們需要檢查使用者輸入是否為0x27位元組的16進制數字,則可以使用如下VM_code:
這部分代碼是取自源檔案中的VM_code,并加以相應的修改。在以上清單中,令使用者輸入的每一位與‘F’, ‘0’, ’9’, ’A’進行比較,進而判斷出是否為16進制數字。當全部滿足條件時,虛拟機運作結束後,R0寄存機為1,否則為0。
最後,用這段VM_code替換原先的代碼,調試運作确認沒有bug之後,就可以正常使用了。
4.小結
本文主要讨論了小型虛拟機保護的相關内容,前一部分逆向分析了一個使用虛拟機保護的CrackMe,後一部分讨論了如果定制一些被虛拟機保護的代碼。在分析虛拟機保護過程中,最主要的步驟是分析每一個VM_handler的作用,進而了解被保護的代碼含義;而在定制小型虛拟機保護是,關鍵是設計一段VM_code使之能夠順利完成其目的。
原文釋出時間為:2017年5月22日
本文作者:胡一米
本文來自雲栖社群合作夥伴嘶吼,了解相關資訊可以關注嘶吼網站。
<a href="http://www.4hou.com/technology/4593.html" target="_blank">原文連結</a>