虛擬8086模式的記憶體管理(轉)
下邊我們用到的V86即指虛擬8086模式。 在以前的教程中,你學習了怎樣模擬V86中斷,但還有一個問題沒有解決:在VxD和V86程式碼之間交換資料。我們將在此學習如何使用V86記憶體管理器來實現這個功能。在這裡下載例子程式
理論
假如你的VxD和一些V86程式一起執行,如何傳送大量資料到V86程式中或從V86程式中傳送大量資料遲早是一個大問題。透過暫存器傳送大量資料是不現實的。可能你的下一個想法是在ring0中分配一大塊記憶體,並且透過一些暫存器傳送其指標到V86程式,使其能訪問這些資料。假如你這樣做,可能會破壞你的系統,因為V86的地址定位方式需要segment:offset對,而不是線性定位方式。對這個問題,有很多解決的方法。然而,我選擇了一個由V86記憶體管理器提供的一種簡便的方法。
如你能在你可使用的V86記憶體範圍內找到一個空閒的記憶體塊作為通訊緩衝區,這將解決其中的一個問題。然而,指標傳送的問題依然存在。你可以透過V86記憶體管理器的服務來解決這兩個問題。V86記憶體管理器是為V86應用管理記憶體的靜態VxD。它還為V86應用提供EMS和XMS服務和為其他VxD提供API傳送服務。API傳送是一個從ring0複製資料到V86範圍內的緩衝區並且傳送V86緩衝區地址到V86程式碼的過程。V86記憶體管理器有一個在V86記憶體範圍內的傳送緩衝區,其含有VxD複製到V86記憶體範圍內的資料,反之亦然。初始的緩衝區是4K。你以呼叫V86MMGR_Set_Mapping_Info來增加它的大小。
現在你知道了傳送緩衝區,我們如何拷入或拷出資料呢?這個問題透過呼叫兩個服務來解決:V86MMGR_Allocate_Buffer和V86MMGR_Free_Buffer。
V86MMGR_Allocate_Buffer從傳送緩衝區分配一塊記憶體並且從ring0複製一些資料到分配的V86緩衝區。V86MMGR_Free_Buffer正好相反:它從分配的V86記憶體塊複製一些資料到ring0緩衝區並且釋放由V86MMGR_Allocate_Buffer分配的記憶體塊。
記住,V86在記憶體管理器象堆疊一樣管理被分配的緩衝區。這意味著分配/釋放必須按先進後出的規則。所以如你呼叫了兩次V86MMGR_Allocate_Buffer,第一個V86MMGR_Free_Buffer將釋放由第二個V86MMGR_Allocate_Buffer呼叫而分配的緩衝區。
我們來看一下V86MMGR_Allocate_Buffer的定義,它是一個基本暫存器傳送引數的服務。
EBX 當前VM的控制程式碼
EBP 指向當前VM的客戶暫存器結構的指標
ECX 從傳送緩衝區分配的位元組數 CARRY FLAG 進位標誌位,如你不想從ring0緩衝區複製資料到分配的記憶體塊就清零, 如你想從ring0緩衝區複製資料到分配的記憶體塊就置1
FS:ESI 指向ring0緩衝區的selector:offset指標,緩衝區中有要被複製到被分配的 緩衝區中的資料如果進位標誌位被清零,則忽略它。
假如呼叫成功,進位標誌位被清零並且ECX包含在傳送緩衝區中的位元組數。這個數值應小於你要求的數值,所以你應保持這個數值,V86MMGR_Free_Buffer待會要用到它。EDI的高字包含被分配的記憶體塊的V86段地址,偏移地址在在低字中。進位標誌位當錯誤發生時被置位。
V86MMGR_Free_Buffer和V86MMGR_Allocate_Buffer接受同樣的引數。
當你呼叫V86MMGR_Allocate_Buffer時,你在當前VM的V86記憶體範圍內分配了一塊記憶體,並且把其地址放到了EDI中。你可以使用這些服務傳送資料到V86中斷中或從V86中斷中取得資料。
在附加的API傳送中,V86記憶體管理器也給其他VxDs提供了API對映服務。API對映服務是對映一些在擴充套件記憶體中的頁到每個VM的V86記憶體範圍。你可以使用V86MMGR_Map_Pages執行API對映。使用這個服務,頁被對映到每個VM的同一線性地址空間上。如你僅僅工作在一個VM上,這將浪費地址空間。因為API對映比API傳送要慢,所以你儘可能使用API傳送方式。API對映僅僅使用在一些要訪問同一線性地址空間並作用到所有VM的V86操作上。
例子:
這個例子演示了API傳送方式,使用了int 21h的440Dh功能(從程式碼66h)。這個中斷呼叫得到媒體ID,你的第一個固定磁碟的卷標號。
;---------------------------------------------------------------
; VxDLabel.asm
;---------------------------------------------------------------
.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
VMMCall Get_Sys_VM_Handle
mov Handle,ebx
assume ebx:ptr cb_s
mov ebp,[ebx+CB_Client_Pointer]
mov ecx,sizeof MID
stc
push esi
mov esi,OFFSET32 MediaID
push ds
pop fs
VxDCall V86MMGR_Allocate_Buffer
pop esi
jc EndI
mov AllocSize,ecx
Push_Client_State
VMMCall Begin_Nest_V86_Exec
assume ebp:ptr Client_Byte_Reg_Struc
mov [ebp].Client_ch,8
mov [ebp].Client_cl,66h
assume ebp:ptr Client_word_reg_struc
mov edx,edi
mov [ebp].Client_bx,3 ; drive A
mov [ebp].Client_ax,440dh
mov [ebp].Client_dx,dx
shr edx,16
mov [ebp].Client_ds,dx
mov eax,21h
VMMCall Exec_Int
VMMCall End_Nest_Exec
Pop_Client_State
;-------------------------------
; retrieve the data
;-------------------------------
mov ecx,AllocSize
stc
mov ebx,Handle
push esi
mov esi,OFFSET32 MediaID
push ds
pop fs
VxDCall V86MMGR_Free_Buffer
pop esi
mov edx,esi
assume edx:ptr DIOCParams
mov edi,[edx].lpvOutBuffer
mov esi,OFFSET32 MediaID.midVolLabel
mov ecx,11
rep movsb
mov byte ptr [edi],0
mov ecx,[edx].lpcbBytesReturned
mov dword ptr [edx],11
EndI:
.endif
xor eax,eax
ret
EndProc OnDeviceIoControl
VXD_PAGEABLE_CODE_ENDS
VXD_PAGEABLE_DATA_SEG
MID struct
midInfoLevel dw 0
midSerialNum dd ?
midVolLabel db 11 dup(?)
midFileSysType db 8 dup(?)
MID ends
MediaID MID <>
Handle dd ?
AllocSize dd ?
VXD_PAGEABLE_DATA_ENDS
end
;------------------------------------------------------------
; Label.asm
; The win32 VxD loader.
;------------------------------------------------------------
.386
.model flat,stdcall
option casemap:none
include masm32includewindows.inc
include masm32includeuser32.inc
include masm32includekernel32.inc
includelib masm32libuser32.lib
includelib masm32libkernel32.lib
DlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
.data
Failure db "Cannot load VxDLabel.VXD",0
AppName db "Get Disk Label",0
VxDName db ".vxdLabel.vxd",0
OutputTemplate db "Volume Label of Drive C",0
.data?
hInstance HINSTANCE ?
hVxD dd ?
DiskLabel db 12 dup(?)
BytesReturned dd ?
.const
IDD_VXDRUN equ 101
IDC_LOAD equ 1000
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke DialogBoxParam, hInstance, IDD_VXDRUN ,NULL,addr DlgProc,NULL
invoke ExitProcess,eax
DlgProc proc hDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_INITDIALOG
invoke CreateFile,addr VxDName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0
.if eax==INVALID_HANDLE_VALUE
invoke MessageBox,hDlg,addr Failure,addr AppName,MB_OK+MB_ICONERROR
mov hVxD,0
invoke EndDialog,hDlg,NULL
.else
mov hVxD,eax
.endif
.elseif uMsg==WM_CLOSE
.if hVxD!=0
invoke CloseHandle,hVxD
.endif
invoke EndDialog,hDlg,0
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
mov edx,wParam
shr edx,16
.if dx==BN_CLICKED
.IF ax==IDC_LOAD
invoke DeviceIoControl,hVxD,1,NULL,0,addr DiskLabel,12,addr BytesReturned,NULL
invoke MessageBox,hDlg,addr DiskLabel,addr OutputTemplate,MB_OK+MB_ICONINFORMATION
.endif
.endif
.ELSE
mov eax,FALSE
ret
.ENDIF
mov eax,TRUE
ret
DlgProc endp
end start
講解
我們首先分析lable.asm,它是一個載入了VxD的WIN32應用程式。
invoke DeviceIoControl,hVxD,1,NULL,0,addr DiskLabel,12,addr BytesReturned,NULL
它呼叫DeviceIoControl,裝置程式碼是1,沒有輸入緩衝區,一個指向輸出緩衝區的指標及其大小。DiskLable是一個接收由VxD返回的卷標號的緩衝區。BytesReturned變數存有返回的位元組數。這個例子說明了怎樣傳送資料和從VxD接收資料:你傳送輸入/輸出緩衝區給VxD並且VxD讀取/寫入資料到指定的緩衝區。
我們下面看看VxD程式碼。
VMMCall Get_Sys_VM_Handle
mov Handle,ebx
assume ebx:ptr cb_s
mov ebp,[ebx+CB_Client_Pointer]
當一個VxD接收W32_DeviceIoControl訊息,它呼叫Get_Sys_VM_Handle得到系統VM的控制程式碼並把它存在一個叫Handle的變數中。下面將從VM控制塊中提取指向客戶暫存器結構的指標到EBP。
mov ecx,sizeof MID
stc
push esi
mov esi,OFFSET32 MediaID
push ds
pop fs
VxDCall V86MMGR_Allocate_Buffer
pop esi
jc EndI
mov AllocSize,ecx
下面,準備傳送到V86MMGR_Allocate_Buffer的引數。我們必須初始化被分配的緩衝區。我們把MediaID的偏移量送到ESI中,並且把選擇子放在FS中,然後呼叫V86MMGR_Allocate_Buffer。你等會要恢復指向DIOCParams的指標,所以我們必須透過push esi 和pop esi來保護它。
Push_Client_State
VMMCall Begin_Nest_V86_Exec
assume ebp:ptr Client_Byte_Reg_Struc
mov [ebp].Client_ch,8
mov [ebp].Client_cl,66h
assume ebp:ptr Client_word_reg_struc
mov edx,edi
mov [ebp].Client_bx,3 ; drive C
mov [ebp].Client_ax,440dh
我們在客戶暫存器結構中準備引數值來執行int 21h的440Dh功能(從程式碼66h),得到盤C的媒體ID。我們複製edi的值到edx中(edi中有由V86MMGR_Allocate_Buffer分配的記憶體塊的V86地址)。
mov [ebp].Client_dx,dx
shr edx,16
mov [ebp].Client_ds,dx
呼叫了int 21h的440Dh功能(從程式碼66h)後,在ds:dx中得到一指向一個MID結構的指標,我們必須把在edx中的segment:offset對轉換成兩個部分並把它們放到合適的暫存器映象中。
mov eax,21h
VMMCall Exec_Int
VMMCall End_Nest_Exec
Pop_Client_State
當一切都準備好了,我們將執行Exec_Int去模擬一箇中斷。
mov ecx,AllocSize
stc
mov ebx,Handle
push esi
mov esi,OFFSET32 MediaID
push ds
pop fs
VxDCall V86MMGR_Free_Buffer
pop esi
當Exec_Int返回時,分配的緩衝已經由我們想要的資訊填滿了。下一步是檢索資訊。我們使用 V86MMGR_Free_Buffer來完成這個目標。這個服務釋放由V86MMGR_Allocate_Memory分配的記憶體塊,並且從分配的記憶體塊中複製資料到ring0中的記憶體塊。象V86MMGR_Allocate_Memory,如果你想要進行複製操作,你必須先把進位標誌位置1,再呼叫服務。
mov edx,esi
assume edx:ptr DIOCParams
mov edi,[edx].lpvOutBuffer
mov esi,OFFSET32 MediaID.midVolLabel
mov ecx,11
rep movsb
mov byte ptr [edi],0
mov ecx,[edx].lpcbBytesReturned
mov dword ptr [edx],11
我們在ring0中得到這個資訊後,複製這個卷標值到Win32應用程式提供的緩衝區中。我們可以用DIOCParams的成員lpvOutBuffer來訪問它。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10172717/viewspace-928822/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 記憶體管理兩部曲之虛擬記憶體管理記憶體
- 聊聊虛擬記憶體記憶體
- Linux 虛擬記憶體Linux記憶體
- 淺析虛擬機器記憶體管理模型虛擬機記憶體模型
- 【Java基礎】實體記憶體&虛擬記憶體Java記憶體
- 5.虛擬記憶體記憶體
- 虛擬記憶體有什麼用 虛擬記憶體不足怎麼解決記憶體
- 虛擬記憶體系統——瞭解記憶體的工作原理記憶體
- 虛擬記憶體(待補充)記憶體
- Java虛擬機器:記憶體管理與執行引擎Java虛擬機記憶體
- 虛擬記憶體對 OI 的影響記憶體
- win10怎麼刪除虛擬記憶體 刪除win10虛擬記憶體的方法Win10記憶體
- win10怎樣刪虛擬記憶體_Win10虛擬記憶體如何關閉Win10記憶體
- 帶你清晰認識,Java虛擬機器記憶體管理!Java虛擬機記憶體
- Ubuntu 新增虛擬記憶體檔案Ubuntu記憶體
- Linux 虛擬記憶體引數配置Linux記憶體
- 詳細理解Linux虛擬記憶體Linux記憶體
- JAVA 虛擬機器可用記憶體Java虛擬機記憶體
- win10怎麼清除虛擬記憶體 win10系統虛擬記憶體清理的辦法Win10記憶體
- win10虛擬記憶體怎麼設定 win10虛擬記憶體設定方法Win10記憶體
- win10怎麼更改虛擬記憶體_win10更改虛擬記憶體大小方法Win10記憶體
- win10怎麼加虛擬記憶體_win10系統增加虛擬記憶體教程Win10記憶體
- win10怎麼調整虛擬記憶體_win10怎麼調虛擬記憶體Win10記憶體
- win10虛擬記憶體如何優化_win10怎麼優化虛擬記憶體Win10記憶體優化
- win10 虛擬記憶體怎麼設定好 win10 虛擬記憶體設定方法Win10記憶體
- 怎麼設定虛擬記憶體win10 win10虛擬記憶體如何設定記憶體Win10
- 虛擬函式的記憶體佈局(上)函式記憶體
- win10 8g記憶體虛擬記憶體設定多少合適_win10 8g記憶體怎麼分配虛擬記憶體Win10記憶體
- win10 8g記憶體還需要虛擬記憶體嗎 win10系統8g記憶體怎麼分配虛擬記憶體Win10記憶體
- 關於虛擬機器記憶體和JVM記憶體設定的思考虛擬機記憶體JVM
- win10電腦虛擬記憶體怎麼設定 win10虛擬記憶體設定的方法Win10記憶體
- windows10怎麼關閉虛擬記憶體_win10關閉c盤虛擬記憶體的方法Windows記憶體Win10
- win10虛擬記憶體怎麼設定 筆記本win10虛擬記憶體怎麼看Win10記憶體筆記
- JVM虛擬機器和Oracle資料庫記憶體管理的學習JVM虛擬機Oracle資料庫記憶體
- 為什麼 Linux 需要虛擬記憶體Linux記憶體
- linux伺服器增加虛擬記憶體Linux伺服器記憶體
- 計算機作業系統——虛擬記憶體與實體記憶體計算機作業系統記憶體
- 記憶體管理篇——實體記憶體的管理記憶體
- win10虛擬記憶體怎麼設定最好 win10虛擬記憶體設定多少好Win10記憶體