iczelion Vxd cntut8

 

客戶寄存器結構


我們將學習本教程中另外一個重要的結構,叫客戶寄存器結構。在本文中,V86指虛擬8086模式。在這裏下載例子程序

理論

VxDs與正常的win32/win16/DOS應用程序有很大不同。大多數情況下,當其他應用程序正常工作時,它們是休眠的。它們象一個監管者一樣工作,其作用是監視ring-3應用程序並在其出錯時改正它們。下面是其工作時的典型的情況:

1、中斷髮生時
2、VMM得到控制權時
3、VMM存貯寄存器組的值時
4、VMM服務於中斷或調用其他VxDs完成此工作時
5、VMM交還控制權給被中斷的程序時

在以上過程中令人感興趣的是,VMM只有這一種方式能影響被中斷的應用程序,即修改存儲的寄存器映象。例如,VMM認爲被中斷的程序應該返回到另外一個地址,它就修改存儲的寄存器映象中CS:IP的值,當這個程序被重新分派時,它將在新的CS:IP處開始執行。

VMM在客戶寄存器結構中存儲中斷點處的寄存器值。

Client_Reg_Struc STRUC
Client_EDI DD ?
Client_ESI DD ?
Client_EBP DD ?
Client_res0 DD ?
Client_EBX DD ?
Client_EDX DD ?
Client_ECX DD ?
Client_EAX DD ?
Client_Error DD ?
Client_EIP DD ?
Client_CS DW ?
Client_res1 DW ?
Client_EFlags DD ?
Client_ESP DD ?
Client_SS DW ?
Client_res2 DW ?
Client_ES DW ?
Client_res3 DW ?
Client_DS DW ?
Client_res4 DW ?
Client_FS DW ?
Client_res5 DW ?
Client_GS DW ?
Client_res6 DW ?
Client_Alt_EIP DD ?
Client_Alt_CS DW ?
Client_res7 DW ?
Client_Alt_EFlags DD ?
Client_Alt_ESP DD ?
Client_Alt_SS DW ?
Client_res8 DW ?
Client_Alt_ES DW ?
Client_res9 DW ?
Client_Alt_DS DW ?
Client_res10 DW ?
Client_Alt_FS DW ?
Client_res11 DW ?
Client_Alt_GS DW ?
Client_res12 DW ?
Client_Reg_Struc ENDS

你可以看到這個結構分爲兩個部分:Client_xxx和Client_Alt_xxx。在這稍作說明,在一個給定的VM中,可能有兩個運行的線程:V86和保護模式。當V86程序運行時,假如一箇中斷產生,Client_xxx將包含V86程序的寄存器映象,Client_Alt_xxx將包含保護模式程序的寄存器映象。相應的,當保護模式程序運行時,假如一箇中斷產生,Client_xxx將包含保護模式程序的寄存器映象,Client_Alt_xxx將包含V86程序的寄存器映象。Client_resX被保留而沒有使用。

在查看過這個結構後,你可能有一問題:怎樣改變寄存器中的一個字節,比如al?上面的結構僅僅描述了字和雙字大小的寄存器組。不用擔心,在vmm.inc找一找。那有兩個爲此附加的結構:Client_Word_Reg_Struc和Client_Byte_Reg_Struc。假如你想以字或字節大小來訪問寄存器,根據你的需要轉換Client_Reg_Struc到Client_Word_Reg_Struc或Client_Byte_Reg_Struc。

下一個問題:我們如何得到一個指向客戶寄存器結構的指針?

這相當簡單:一般地,當VMM調用我們的VxD時,把客戶寄存器結構的地址放在ebp中。在這裏的客戶寄存器結構是當前VM的。你可以從VM的句柄中得到這個指針。記住,VM的句柄是VM控制塊的線性地址。

cb_s STRUC

CB_VM_Status DD ?
CB_High_Linear DD ?
CB_Client_Pointer DD ?
CB_VMID DD ?
CB_Signature DD ?

cb_s ENDS
CB

CB_Client_Pointer包含指向VM的客戶寄存器結構的指針。例如:你可用下邊的代碼得到指向當前VM中的客戶寄存器結構的指針:

VMMCall Get_Cur_VM_Handle ; return the current VM handle in ebx
assume ebx:ptr cb_s
mov ebp,[ebx+CB_Client_Pointer] ; pointer to client reg struct

現在我們瞭解了客戶寄存器結構,我們可以用它來開始工作了。我們將使用客戶寄存器結構去傳送寄存器組的值到一個DOS中斷中,也就是,int 21h,功能2h,顯示一個字符。這個DOS服務把要顯示的字符放在dl中。假如我們傳送響鈴字符(07h)到這個服務,將通過PC喇叭發出一聲響。

記住,int 21h是一個DOS服務,因而其在V86模式下是可用的,我們如何在VxD中調用一個V86中斷?一個方法是使用Exec_Int服務。這個VMM服務把要調用的中斷號放在eax中。它模擬指定的中斷然後返回到調用的VM。然而,它必須在一個嵌套執行塊中被調用。嵌套執行塊被Begin_Nest_V86_Exec (或 Begin_Nest_Exec)和End_Nest_Exec包括起來。如果我們要調用int 21h功能2h,我們需要在嵌套執行塊內轉換Client_Byte_Reg_Struc結構的Client_ah和Client_Dl,然後把值21h放在eax中。當一切準備好了,就調用Exec_Int。

例子:

例子是一個動態VxD,它調用int 21h的功能2使PC喇叭發聲。


講解

Push_Client_State

這沒什麼好講解的。當一個VxD接收到一個DeviceIoControl消息,ebp已經指向了當前VM的客戶寄存器結構。我們調用Push_Client_State宏在堆棧中存儲客戶寄存器結構的狀態。然後用Pop_Client_State宏恢復客戶寄存器。

VMMCall Begin_Nest_V86_Exec

通過調用Begin_Nest_V86_Exec開始嵌套執行塊。

assume ebp:ptr Client_Byte_Reg_Struc
mov [ebp].Client_dl,7
mov [ebp].Client_ah,2

改變在客戶寄存器中的dl和ah寄存器的映象。這個改變的值將由中斷使用。

mov eax,21h
VMMCall Exec_Int

Exec_Int要求在eax存有一箇中斷號。我們想使用int 21h。等會我們調用Exec_Int去模擬中斷。

VMMCall End_Nest_Exec
Pop_Client_State

當Exec_Int返回,我們完成了嵌套執行塊,並且由堆棧中恢復了客戶寄存器結構的值。 你將聽到你的PC喇叭發出一聲響。




翻譯:呂駿,整理:LuoYunBin's Win32 ASM Page, http://asm.yeah.net
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章