news 2026/7/1 17:45:18

汇编语言全接触-49.虚拟8086模式的内存管理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
汇编语言全接触-49.虚拟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 \masm\include\vmm.inc

include \masm\include\vwin32.inc

include \masm\include\v86mmgr.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 \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

讲解

我们首先分析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。你等会要恢

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/1 10:55:08

C4D材质基础:从金属到玻璃的贴图技巧

C4D材质基础&#xff1a;从金属到玻璃的贴图技巧 在三维设计中&#xff0c;一个模型是否“真实”&#xff0c;往往不取决于建模精度有多高&#xff0c;而在于它的表面是否可信。即便是一个简单的球体&#xff0c;只要材质做得好&#xff0c;也能让人误以为是刚抛光的不锈钢轴承…

作者头像 李华
网站建设 2026/7/1 6:07:23

PHP木马代码分析与安全风险揭示

PHP木马代码分析与安全风险揭示 在当今生成式 AI 技术迅猛发展的背景下&#xff0c;越来越多企业选择部署本地化的图像生成系统&#xff0c;比如基于 Z-Image-ComfyUI 的可视化推理平台。这类工具极大提升了内容创作效率&#xff0c;但其背后的安全隐患却常常被开发者忽视——尤…

作者头像 李华
网站建设 2026/7/1 10:55:09

坐标转换与投影:解决 WebGIS 的坐标混乱问题

在 WebGIS 开发中&#xff0c;坐标系统不统一是最常见的 “坑”—— 同样的地理位置&#xff0c;在高德地图、百度地图、OpenStreetMap 上的坐标值却完全不同&#xff0c;导致地图要素偏移、定位不准等问题。这背后的核心原因是不同平台采用了不同的坐标系&#xff1a;WGS84&am…

作者头像 李华
网站建设 2026/7/1 22:38:05

PHP大马分析:短小精悍的后门程序

PHP大马分析&#xff1a;短小精悍的后门程序 在一次常规的安全巡检中&#xff0c;WAF&#xff08;Web应用防火墙&#xff09;捕获到一个看似普通的文件上传请求。表面上看只是个简单的PHP脚本&#xff0c;但触发了多条高危规则——这引起了我的警觉。 <?php $password a…

作者头像 李华
网站建设 2026/7/1 10:55:16

CALIPSO激光雷达333米云层数据解析

IndexTTS 2.0&#xff1a;让每个声音都有性格&#xff0c;让每句话都带情绪 你有没有遇到过这种情况&#xff1a;精心剪辑的视频卡在最后一环——配音不贴脸&#xff1f;找真人录音成本高、周期长&#xff0c;用传统AI语音又“机械感”十足&#xff0c;情绪平平&#xff0c;节…

作者头像 李华
网站建设 2026/7/1 10:55:14

Open-AutoGLM邀请码哪里找?3个高成功率渠道+申请模板免费送

第一章&#xff1a;Open-AutoGLM邀请码获取 获取 Open-AutoGLM 的访问权限是使用该开源框架的第一步&#xff0c;目前系统采用邀请码机制控制用户注册&#xff0c;以保障服务稳定性和社区质量。 官方渠道申请 用户可通过 Open-AutoGLM 官方网站提交申请表单&#xff0c;填写真…

作者头像 李华