客戶暫存器結構(轉)

heying1229發表於2007-07-28
客戶暫存器結構:

  我們將學習本教程中另外一個重要的結構,叫客戶暫存器結構。在本文中,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喇叭發聲。

.386p
include masmincludevmm.inc
include masmincludevwin32.inc
include masmincludev86mmgr.inc
VxDName TEXTEQU
ControlName TEXTEQU
VxDMajorVersion TEXTEQU <1>
VxDMinorVersion TEXTEQU <0>

VxD_STATIC_DATA_SEG
VxD_STATIC_DATA_ENDS

VXD_LOCKED_CODE_SEG
;----------------------------------------------------------------------------
; Remember: The name of the vxd MUST be uppercase else it won't work/unload
;----------------------------------------------------------------------------
DECLARE_VIRTUAL_DEVICE %VxDName,%VxDMajorVersion,%VxDMinorVersion, %ControlName,UNDEFINED_DEVICE_ID,UNDEFINED_INIT_ORDER

Begin_control_dispatch %VxDName
Control_Dispatch W32_DEVICEIOCONTROL, OnDeviceIoControl
End_control_dispatch %VxDName

VXD_LOCKED_CODE_ENDS

VXD_PAGEABLE_CODE_SEG
BeginProc OnDeviceIoControl
assume esi:ptr DIOCParams
.if [esi].dwIoControlCode==1
Push_Client_State
VMMCall Begin_Nest_V86_Exec
assume ebp:ptr Client_Byte_Reg_Struc
mov [ebp].Client_dl,7
mov [ebp].Client_ah,2
mov eax,21h
VMMCall Exec_Int
VMMCall End_Nest_Exec
Pop_Client_State
EndI:
.endif
xor eax,eax
ret
EndProc OnDeviceIoControl
VXD_PAGEABLE_CODE_ENDS

end

講解

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喇叭發出一聲響。

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10172717/viewspace-928819/,如需轉載,請註明出處,否則將追究法律責任。

相關文章