p-code 執行(譯)

看雪資料發表於2015-11-15

小弟在上一篇短文“有關VB程式P-CODE程式碼逆向工程入門淺說”中介紹了除錯p-code程式碼的一點簡單方法,今天,再來和各位初學者一起回顧一下p-code的有關資料。

John Chamberlain 在他的文章“Microsoft's P-Code Implementation”中是這樣介紹的:

最初的Pascal編譯器涉及特定的計算機,它的複雜性基於編譯器自身。為了解決生成程式碼的跨平臺問題,編譯器產生一種虛擬碼(偽執行程式碼,與特定計算機的指令無關)“pseudo-opcode”,它被稱為"Pascal-P",編譯器能夠輸出偽指令“p-pcode”。大約10年後,Microsoft為它自己相關產品採用了這個慣用的術語"p-code" 和 "p-code 引擎"。對於“VB p-code”,可移植性“portable”不是被優先考慮的,這個字首“p”的含義被轉義為壓縮“packed”,可執行程式被壓縮成位元組佔用很小的檔案。1995年sun公司的java席捲了web世界,Microsoft 作為回應,將它的 p-code 引擎轉換成更性感的新名稱 vb虛擬機器"VB Virtual Machine",其實這並不十分恰當。無論如何,Java's 操作碼opcode 對應的是抽象的cpu指令,Microsoft的p-codes 是一種抽象的程式語言和環境,它更適當的稱呼應該是vb虛擬語言 "VB Virtual Language".

VB 虛擬機器基礎 
如是我聞,John Chamberlain 接著說,VB6 有1351 條偽指令opcodes,它維護一個暫存器指標和一個跳轉表,指向那些待處理的後續虛擬碼,並且,vb不透過p-code進行迴圈操作。

舉例:執行偽指令f5,將一個Long(長整型,32 位,4 個位元組)變數儲存. ESI 暫存器總是指向有關的偽指令,EAX 包含跳轉地址的索引。



Address………..(p-code bytes)
001a56d1………3c 00 0a f5  ;f5 當前執行的偽指令
001a56d5………08 00 00 00 
001a56d9………71 78 ff 00 

當前偽指令指令結束後,將跳到下一條偽指令(71)處
Eax=000000f5 (begin)  ; 偽指令
Eax=00000071 (end)

Esi=001a56d5 (begin)  ; 偽指令序列指標
Esi=001a56da (enbd)

0FC01377 mov eax,dword ptr [esi] (1) 引出偽指令參量
0FC01379 push eax (2) 進行偽指令相應的工作
0FC0137A xor eax,eax (3) 轉入下一個偽指令
0FC0137C mov al,byte ptr [esi+4] 
0FC0137F add esi,5 ; 下一個待處理的偽指令位置
0FC01382 jmp dword ptr [eax*4+0FC027CCh] 執行相關偽指令的處理控制程式

注:0FC01382 語句中的0FC027CCh 指向一個向量表

處理引擎的工作:在位元組程式碼流中,放入一個long資料型別的常量8(好像這樣的形式"F5 08 00 00 00"等待被vb處理機執行. 所有的虛擬碼都是基於類似的形式。

如是我聞,John Chamberlain 又繼續解釋上面的這個例項:
以上例項中,向量表指向0FC027CC,因此,一個偽指令(71)將跳到這個向量表的第71個入口地址71*4+0FC027CC. 在這裡,第二步只是進行了一個簡單的壓棧操作,但是其他的虛擬碼可能有很複雜的執行過程。不管那些處理過程有多複雜,你不必介入具體的執行過程,只要你清楚每個偽指令對應的向量表中執行入口即可。
例如:在debugger中設定一個斷點在0FC01377(參照以上例項),你就會中斷在執行偽指令f5之前. 
Vb6虛擬機器僅僅指定暫存器ESI,EAX作為專用暫存器,EAX總是在被呼叫之前清除(xor eax, eax),並且裝入有關的跳轉參量,在相應的偽指令處理過程中,ESI 暫存器是被保護的. 在上例中,(add esi, 5) 使得esi指向下一條偽指令,並忽略當前執行的偽指令的引數。vb應用程式的執行控制流是基於對ESI暫存器的設定. Vb6中有775 偽指令處理子程式,大概是因為1351 偽指令中有一些對應著同一個偽指令處理程式。 
John Chamberlain 提供的The opcode database(見附件)格式:
|Opcode|__|VB6虛擬機器的rva|__|VBA的rva|__|引數尺寸|__|註釋|
1F___________09AD_____________0A32__________2_1_2____vbaRecUniToAnsi                                                                                                                                                   
引數尺寸:
1. 引數總尺寸(bytes)
2. 引數總個數
3. 第1,2,3個引數的尺寸(bytes)
更多的資訊請參照:
http://www.programmersheaven.com/articles/userarticles/john/vbvm.htm.

相關文章