分享
 
 
 

iczelion Vxd tut9

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Virtual 8086 Memory Manager

In the previous tutorial, you learn how to simulate V86 interrupt. However, there is one problem that hasn't been addressed yet: exchanging data between VxD and V86 code. We will learn how to use the V86 Memory Manager to our advantage in this regard.

Download the example.

Some Theory

If your VxD works with some V86 routines, it will be necessary sooner or later to pass large chunks of data to and from the V86 program. Passing a large amount of data via registers is out of question. Your next attempt might be to allocate a block of memory in ring 0 and pass the pointer to the memory block via some register so the V86 code can access the data. If you do so, it will probably crash your system because V86 addressing mode requires segment:offset pair, not the linear address.

There are many solutions to that problem. However, I choose an easy way here to demonstrate services provided by the V86 Memory Manager.

If somehow you can find a free memory block in the V86 region that you can use as the communcation buffer, that would solve one of the problems. However, the pointer translation problem remains. You can solve both problems by using the V86 Memory Mananger's services.

The V86 Memory Manager is the static VxD that manages memory for V86 applications. It also provides EMS and XMS services to V86 apps and API translation services to other VxDs. API translation is actually the process of copying the data from ring-0 into a buffer in V86 region and then passing the V86 address of the data to the V86 code. No magic here. The V86 Memory Manager maintains a translation buffer which is a block of memory in the V86 region for copying data from VxD to V86 region and vice versa. Initially this translation buffer is 4 kilobytes. You can increase the size of this buffer by calling V86MMGR_Set_Mapping_Info.

Now that you know about the translation buffer, how can we copy data to and from it? This question involves two services: V86MMGR_Allocate_Buffer and V86MMGR_Free_Buffer.

V86MMGR_Allocate_Buffer allocates a block of memory from the translation buffer and optionally copies the data from ring 0 into the allocated V86 block. V86MMGR_Free_Buffer does the reverse: it optionally copies the data from the allocated V86 block into a ring-0 buffer and frees the memory block allocated by V86MMGR_Allocate_Buffer.

Note that the V86 Memory Manager maintains the allocated buffers as a stack. That means the allocation/deallocation must observe the first in/first out rule. So if you make two calls to V86MMGR_Allocate_Buffer, the first V86MMGR_Free_Buffer will free the buffer allocated by the second V86MMGR_Allocate_Buffer call.

We can now proceed to examine V86MMGR_Allocate_Buffer definition. It's a register-based service.

ebx

Handle of the current VM

ebp

Pointer to the current VM's client register structure

ecx

Number of bytes to allocate from the translation buffer

carry flag

clear if you don't want to copy data from ring-0 buffer to the allocated block. Set if you want to copy data from ring-0 buffer to the allocated block

fs:esi

selector:offset of the ring-0 memory block that contains the data to be copied to the allocated buffer. Ignored if the carry flag is clear.

If the call is successful, the carry flag is clear and ecx contains the number of bytes actually allocated in the translation buffer. This value can be less than the value you requested so you should keep this value for use with V86MMGR_Free_Buffer call later. edi contains the v86 address of the allocated block with the segment in the high word, the offset in the low word. The carry flag is set if an error occurs.

V86MMGR_Free_Buffer accepts exactly the same parameters as V86MMGR_Allocate_Buffer.

What actually occurs when you call V86MMGR_Allocate_Buffer is that you allocate a block of memory in V86 region of the current VM and obtain the V86 address of that memory block in edi. We can use these services to pass data to and from V86 interrupts.

In addition to API translation, the V86 Memory Manager also offers API mapping service to other VxDs. API mapping is actually the process of mapping some pages in extended memory into V86 region of every VM. You can use V86MMGR_Map_Pages to do API mapping. With this service, the pages are mapped into the same linear address in every VM. This waste address space if you want to work with only one VM. Also API mapping is slower than API translation so you should use API translation as much as possible. API mapping is required for some V86 operation that needs to access the same linear address and must be present in all VMs.

The Example

This example uses API translation with int 21h, 440Dh minor code 66h, Get Media ID, to obtain the volume label of your first fixed disk.

;---------------------------------------------------------------

; VxDLabel.asm

;---------------------------------------------------------------

.386p

include \masm\include\vmm.inc

include \masm\include\vwin32.inc

include \masm\include\v86mmgr.inc

VxDName TEXTEQU <VXDLABEL>

ControlName TEXTEQU <VXDLABEL_Control>

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 \masm32\include\windows.inc

include \masm32\include\user32.inc

include \masm32\include\kernel32.inc

includelib \masm32\lib\user32.lib

includelib \masm32\lib\kernel32.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

Analysis

We will examine label.asm which is the win32 application which loads the VxD first.

invoke DeviceIoControl,hVxD,1,NULL,0,addr DiskLabel,12,\

addr BytesReturned,NULL

It calls DeviceIoControl with device code equal to 1, no input buffer, a pointer to an output buffer and its size. DiskLabel is the buffer set aside for receiving the volume label returned by the VxD. The number of bytes actually returned will be stored in BytesReturned variable. This example demonstrates how to pass data to and receive data from a VxD: you pass input/output buffers to the VxD and the VxD reads from/write to the submitted buffers.

We will examine the VxD code next.

VMMCall Get_Sys_VM_Handle

mov Handle,ebx

assume ebx:ptr cb_s

mov ebp,[ebx+CB_Client_Pointer]

When the VxD receives W32_DeviceIoControl message, it calls Get_Sys_VM_Handle to obtain the system VM handle and store it into a variable named Handle. It next extracts the pointer to the client register structure from the VM control block into 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

Next, it prepares the parameters to be passed to V86MMGR_Allocate_Buffer. We must initialize the allocated buffer, hence the stc instruction. We put the offset of MediaID into esi and the selector into fs then call V86MMGR_Allocate_Buffer. You'll recall that esi contains the pointer to DIOCParams so we must preserve it by push esi and 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

We prepare the values in the client register structure for the int 21h, 440Dh minor code 66h. Specifying that we want to get the media ID of drive C. We also copy the value in edi into edx (edi contains the V86 address of the memory block allocated by V86MMGR_Allocate_Buffer).

mov [ebp].Client_dx,dx

shr edx,16

mov [ebp].Client_ds,dx

Since int 21h, 440Dh, minor code 66h expects pointer to an MID structure in ds:dx, we must break the segment:offset pair in edx into two parts and put them into the corresponding register images.

mov eax,21h

VMMCall Exec_Int

VMMCall End_Nest_Exec

Pop_Client_State

When everything is ready, we call Exec_Int to simulate the interrupt.

mov ecx,AllocSize

stc

mov ebx,Handle

push esi

mov esi,OFFSET32 MediaID

push ds

pop fs

VxDCall V86MMGR_Free_Buffer

pop esi

After Exec_Int returns, the allocated buffer is filled by the information we want. The next step is to retrieve that information. We achieve that goal by calling V86MMGR_Free_Buffer. This service frees the memory block allocated by V86MMGR_Allocate_Memory and copies the data in the allocated memory block to the specified ring-0 memory block. Like V86MMGR_Allocate_Memory, if you want the copy operation, you must set the carry flag prior to calling the service.

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

After we have the information in the ring-0 buffer, we copy the volume label to the buffer provided by the win32 application. We can access the buffer by using lpvOutBuffer member of DIOCParams.

[Iczelion's Win32 Assembly Homepage]

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有