1. 程式人生 > 實用技巧 >VMP加殼(二):VMP的虛擬化原理

VMP加殼(二):VMP的虛擬化原理

  介紹VMP虛擬化原理之前,先簡單介紹一下計算機執行的原理。總所周知,現代計算機的核心部件是CPU、記憶體、磁碟、鍵盤、顯示器等;最最最核心的就屬CPU、記憶體和磁碟了。使用者按開機鍵,CPU會把OS從磁碟載入到記憶體執行。由於CPU只能識別並執行二進位制檔案,所以程式碼、資料等都是以二進位制存放在磁碟和記憶體的。

1、為了在軟體層面“虛擬化”出底層的硬體,讓OS順利在虛擬機器執行,虛擬機器也要提供CPU、記憶體和磁碟的“虛擬”環境,讓二進位制程式碼得以順利執行。目前主流的虛擬化技術是intel/amd推出的VT技術,讓VMware、virtualBox這種虛擬機器可以“直接”讓硬體CPU執行二進位制程式碼,極大提升了虛擬機器的效率和速度,減少了模擬的效能損耗。但這種虛擬機器的功能相對較重,並且直接讓硬體CPU執行虛擬機器的二進位制程式碼,達不到保護、混淆程式碼的目的,所以這種硬體虛擬化是不適合做程式碼保護的,只能考慮通過純軟體模擬虛擬機器執行程式碼指令。

  為了在軟體層面模擬CPU執行二進位制的程式碼指令,需要有以下關鍵點:

  • 虛擬機器的暫存器,用來存放各種臨時資料
  • 虛擬機器的堆疊,用來做各種資料交換
  • 虛擬機器的指令。x86架構下,CPU一旦讀取到0x55指令,就知道執行push ebp;一旦讀取到0x8BEC,就知道執行mov ebp,esp; 同理,虛擬機器也需要有自己的指令集,虛擬CPU才知道自己要幹啥。一般虛擬機器的指令要麼是操作暫存器,要麼是操作堆疊,要麼做各種算數運算,虛擬機器指令的handler都要模擬這些功能。那麼問題來了,虛擬機器的指令集能不能和物理CPU一樣了? 顯然是不行的! 兩個原因:(1)如果一樣,還要純軟體虛擬機器幹啥? (2)如果一樣,達不到混淆指令的目的
  • 虛擬機器的EIP,用來指明虛擬CPU當前執行的程式碼

為了滿足以上關鍵點,VMP採取的方案:

  • 虛擬機器的暫存器:在記憶體開闢一段連續的區域當成虛擬機器的暫存器,業界稱之為VM_CONTEXT,某些版本的VMP用EDI指向這個區域
  • 虛擬機器的堆疊: 這個和物理機是一樣的,直接在記憶體開闢就好。VMP還是用EBP指向棧頂
  • 虛擬機器的指令:不同版本VMP的指令是不一樣的,這樣可以在一定程度上防止VMP本身被破解,業界俗稱VM_DATA
  • 虛擬機器的EIP:業界俗稱vEIP,某些版本的VMP用ESI替代,指向VM_DATA,用以讀取虛擬CPU需要執行的指令;

2、VMP虛擬機器的執行流程

  (1)想想啟動VT時,是不是要先開闢一段記憶體空間,把當前guestOS部分暫存器的值儲存好?VMP也一樣,先儲存物理暫存器的值,後續退出VM後才能還原

(2)讓vEIP從VM_DATA讀取虛擬機器的指令

(3)由於虛擬機器的指令和物理CPU完全不同,那麼在指令讀取後,該怎麼去執行了?舉個栗子:比如0x1表示入棧,0x2表示出棧,0x3表示暫存器之間互相傳資料(當然實際的指令可能不會這麼簡單,VMP每個版本的指令集都不同),這些指令該怎麼執行了?在VMP中,有個概念叫handler,專門根據不同的指令執行不同的操作(當然這些操作VMP事先都定義好了)。這個和VT中VMX的handler作用類似:根據不同的異常有不同的處理方法(我個人猜測VMP的作者肯定借鑑了VT的原理和思路);

   為了達到這種不同指令執行不同handler分支的效果,編碼實現層面通常用switch+case實現,用於將不同的指令跳轉到不同的分支執行,業界俗稱dispatcher。具體到彙編程式碼,switch+case一般的彙編形式為:mov ecx,dword ptr ds:[eax*4+base] (注意暫存器可能會變成其他的,但這 xxx*4+基址的形式不會變), 這是比較明顯的特徵,用以用來定位VMP的dispatcher。

  (4)執行完一個handler,vEIP接著指向下VM_DATA的下一個指令,然後重複(2)-(4)這幾個步驟;

整個過程展示如下:

(5)綜上所述,要想全面瞭解、分析和掌控VMP,必須要找準這麼幾個點:

  •  VM_DATA:虛擬機器的指令都集中在這了
  • VM_CONTEXT:虛擬暫存器都儲存在這裡
  • diapatcher:所有指令都從這裡路由到對應的handler執行(可以簡單理解為管理層派發活的,不過3.x版本的VMP貌似去掉了統一的dispatcher,由上個handler直接跳轉到下個handler,有點P2P、區塊鏈去中心化的感覺)
  • handler:具體模擬執行虛擬指令的分支(可以簡單理解為具體幹活的工具人)。handler之間跳轉通過jmp esi 或 push esi ,ret等指令實現(不同版本使用的暫存器可能不同,但跳轉實現的方式就這些)
  • vEIP:當前執行的指令,需要明確是由那個物理暫存器儲存的
  • vStack:存放了臨時資料用於各種交換,目前版本還是由

  3、上面講了大段各種理論,下面說說具體怎麼找這些關鍵點(注意: 下面OD分析的截圖不是一次除錯擷取的,事實上我測試時反覆除錯了十幾次,每次用OD開啟樣本的地址都不同,但不影響程式碼執行的順序和關鍵點的分析)。

(1)demo程式碼如下:這裡模擬一個密碼、lisence之類的場景:正確的密碼是123,輸入後輸出ok;輸入錯誤的密碼就輸出fail;

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

char buf[1204];

void main()
{
    while (1)
    {
        scanf("%s", buf);
        if (!strcmp(buf, "123"))
            printf("ok\n");
        else
            printf("fail\n");
    }

}

  (2)這裡只把main函式虛擬保護即可:

  (3)虛擬化後的結果:從40K增加到602K,增加了15倍;

用OD開啟:VMP0段564K,膨脹的部分都集中在這裡了;

(4)剛進入OD,看到的全是jmp。根據之前的理論分析,這些jmp構成了handler表:

  

  在剛才那個記憶體檢視,選中vmp0段,右鍵選擇記憶體訪問斷點,後續只要訪問這個段就會立即斷下來。然後開始執行,斷到下面:push xxxx,call xxxx這是非常明顯的VMP3.xx版本的殼特徵

不停F7單步進入後來到這裡:看到了好多push 暫存器的指令,這裡就是儲存原始物理暫存器的值的,為後續進入VM加殼做準備;可以看到在push指令之間載入著大量沒用的垃圾指令;

這些push指令執行完後,棧如右圖所示;注意這裡一行關鍵程式碼已經標紅: esp+0x28處的值賦給了edi,edi指向了VM_DATA,也就是虛擬指令集(後面會進一步解密edi)

 

經過下面add edi,edx後,得到真正的VM_DATA地址:

繼續往下:又有一條關鍵指令:sub esp,0xC0; 這裡把esp往上開闢192byte的空間,作為VM_CONTEXT(也就是虛擬存器)。後續會用esp+edx來讀取這些虛擬暫存器;此時堆疊圖如右邊:下面儲存的是物理暫存器,上面是VM_CONTEXT,中間以ebp隔開

 

繼續F7(後續能看到大量這類似的程式碼):通過ebp從棧取原物理暫存器的值,然後通過edi取指令,接著根據指令對取出的數做各種運算:

計算完畢後寫回VM_CONTEXT:

 

  接著繼續取指令和棧的值:

計算完畢後繼續寫回VM_CONTEXT:

期間還檢查虛擬棧是否填滿:

   棧頂和棧底比較,看看誰大:

如果棧夠用就通過jmp繼續執行下個handler:

如此往復好多次,都快把VM_CONTEXT填滿為止,終於到了while迴圈。這時不知道密碼是多少,先隨便輸入,看到程式輸出了fail,突破點就在這了: 通過ASCII在記憶體中找fail,然後下個訪問的斷點,成功斷下來:

這裡回溯棧:在棧中儲存了函式的呼叫關係,這裡肯定有while迴圈、判斷對比的函式:這裡把password在棧上所有的函式都輪詢個遍(kernerl32、ucrtbase這些windows系統自帶的API就沒必要了),挨個下斷點,一共下了十幾個:

這裡用辨識度比較高的字串"aaaaaaaaaaaaa"輸入,然後挨個斷點地檢查,終於在一個斷點處找到了密碼字元:這個大概率是strcmp函式

總結:1、大段程式碼被人為切割成一小塊一小塊地執行,程式碼之間通過jmp、call、push+ret方式跳轉

2、統一的dispatcher是真的沒有了,handler倒是有一個大表(整個程式的入口點也改到這裡了),裡面全是jmp語句,對應不同的handler分支

3、esp指向VM_CONTEXT,edx是虛擬暫存器的偏移,通過esp+edx定位虛擬暫存器的位置;讀取的虛擬暫存器儲存在ecx,各種處理後通過ecx寫回虛擬暫存器;

ebp指向虛擬棧頂,通過ebp+偏移挨個讀寫虛擬棧的資料;

4、取指令、解密、執行、跳轉到下一個handler:很多程式碼都是一樣的,重複生成了好多次

參考:1、https://bbs.pediy.com/thread-225262.htm新手篇VMProtect 1.81 Demo

2、https://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458296943&idx=1&sn=8ba937d6216a37025d5f97d8a4989f4a VMProtect 3.3.1虛擬機器&程式碼混淆機制入門

3、https://bbs.pediy.com/thread-225803.htm 如何分析虛擬機器(2):進階篇 VMProtect 2.13.8