这是学习kernel model driver(KMD)时翻译的一篇文章,大体意思差不多,但表达不好,欢迎指出其中的不足。。源码是用汇编写的。
翻译的比较匆忙,没有校对。希望不会有太多的错误。
;@echo off
;goto make
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; S T R U C T U R E S
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; U N I N I T I A L I Z E D D A T A
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.data?
seh SEH <>
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; C O D E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; BuggyReader
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
BuggyReader proc
xor eax, eax
mov eax, [eax] ; !!! Without SEH this causes BSOD !!!
ret
BuggyReader endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; BuggyWriter
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
BuggyWriter proc
mov eax, MmUserProbeAddress
mov eax, [eax]
mov eax, [eax]
mov byte ptr [eax], 0 ; !!! Without SEH this causes BSOD !!!
ret
BuggyWriter endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; ExceptionHandler
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ExceptionHandler proc uses esi pExcept:DWORD, pFrame:DWORD, pContext:DWORD, pDispatch:DWORD
mov esi, pExcept
invoke DbgPrint, $CTA0("/nSEH: An exception %08X has occured/n"), /
[esi][EXCEPTION_RECORD.ExceptionCode]
.if [esi][EXCEPTION_RECORD.ExceptionCode] == 0C0000005h
; EXCEPTION_ACCESS_VIOLATION
; if EXCEPTION_ACCESS_VIOLATION we have some additional info
invoke DbgPrint, $CTA0(" Access violation at address: %08X/n"), /
[esi][EXCEPTION_RECORD.ExceptionAddress]
.if [esi][EXCEPTION_RECORD.ExceptionInformation][0]
; Read or write ?
invoke DbgPrint, $CTA0("The code tried to write to address %08X/n/n"), /
[esi][EXCEPTION_RECORD.ExceptionInformation][4]
.else
invoke DbgPrint, $CTA0(" The code tried to read from address %08X/n/n"), /
[esi][EXCEPTION_RECORD.ExceptionInformation][4]
.endif
.endif
lea eax, seh
push (SEH PTR [eax]).SafeEip
push (SEH PTR [eax]).PrevEsp
push (SEH PTR [eax]).PrevEbp
mov eax, pContext
pop (CONTEXT PTR [eax]).regEbp
pop (CONTEXT PTR [eax]).regEsp
pop (CONTEXT PTR [eax]).regEip
xor eax, eax ; return ExceptionContinueExecution
ret
ExceptionHandler endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; DriverEntry
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
invoke DbgPrint, $CTA0("/nSEH: Entering DriverEntry/n")
;::::::::::::::::::::::::::::::::
; Manually set/remove seh-frame :
;::::::::::::::::::::::::::::::::
assume fs:nothing
push offset ExceptionHandler
push fs:[0]
mov fs:[0], esp
assume fs:error
mov seh.SafeEip, offset SafePlace
mov seh.PrevEbp, ebp
mov seh.PrevEsp, esp
invoke BuggyReader
SafePlace:
; Remove seh-frame
assume fs:nothing
pop fs:[0]
add esp, sizeof DWORD
assume fs:error
;:::::::::::::::::::::::::::::::::::::::::::::::
; SEH works using macro. It's a bit easier ;-) :
;:::::::::::::::::::::::::::::::::::::::::::::::
_try
invoke BuggyWriter
_finally
invoke DbgPrint, $CTA0("/nSEH: Leaving DriverEntry/n")
; Remove driver from the memory.
mov eax, STATUS_DEVICE_CONFIGURATION_ERROR
ret
DriverEntry endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
end DriverEntry
:make
set drv=seh
/masm32/bin/ml /nologo /c /coff %drv%.bat
/masm32/bin/link /nologo /driver /base:0x10000 /align:32 /out:%drv%.sys /subsystem:native %drv%.obj
del %drv%.obj
echo.
Pause
8.1.2注册SHE结构
assume fs:nothing
由于MASM编译器默认是禁止使用fs寄存器,所以通过assume来启用fs。
push offset ExceptionHandler
push fs:[0]
mov fs:[0], esp
设置SHE结构回调函数,即当异常发生时进行处理的地址。然后异常发生时通过异常链(每个定义的SHE结构,都要自己的异常处理函数)激发系统异常处理。例如ExceptionHandler异常处理函数的代码稍后进行解释。可以通过调试器SoftIce提供的命令xframe得到所有当前异常链中以注册的异常处理。
assume fs:error
使fs寄存器为不可用状态
mov seh.SafeEip, offset SafePlace
mov seh.PrevEbp, ebp
mov seh.PrevEsp, esp
为了通过异常处理使我们的程序能够继续运行,必须保留寄存器esp和ebp的值,在结构中保存这三个的值,调用会发生读错误的函数BuggyReader,函数试着读四个字节在地址0处。
BuggyReader proc
xor eax, eax
mov eax, [eax]
ret
BuggyReader endp
对空指针的处理是个经常发生的错误,因为Microsoft规定范围从00000000-0000FFFFh的64k大小内存是不可访问的,对这个范围任何字节进行存取都会导致一个EXCEPTION_ACCESS_VIOLATION类型的异常。
8.1.3异常处理
BuggyReader函数中试着读数据从地址00000000处激发异常,进入我们设置的异常处理函数
进入异常处理函数内,首先显示一个异常发生类型信息,如果是EXCEPTION_ACCESS_VIOLATION类型异常,显示更多的信息,继续进行合适的异常处理。
lea eax, seh
push (SEH PTR [eax]).SafeEip
push (SEH PTR [eax]).PrevEsp
push (SEH PTR [eax]).PrevEbp
mov eax, pContext
pop (CONTEXT PTR [eax]).regEbp
pop (CONTEXT PTR [eax]).regEsp
pop (CONTEXT PTR [eax]).regEip
在这个例子中只是简单的恢复继续正常运行的esp,ebp的值,和eip地址。恢复的寄存器值来自于注册SHE回调函数是保存在she结构中的值,并改变CONTEXT 结构中寄存器的值。
xor eax, eax
ret
修改ExceptionContinueExecution的值为零返回,告诉系统程序继续正常执行,改变eip为SafePlace的地址,并恢复esp和ebp的值,程序从SafePlace处开始执行。
8.1.4 恢复原来的SHE框架
SafePlace:
assume fs:nothing
pop fs:[0]
add esp, sizeof DWORD
assume fs:error
使fs:[0]恢复为原来的值,并且调整堆栈结构指针(要了解详细情况请看上面提到的文章)。
8.1.5定义宏进行SHE结构的注册和恢复
对于一些相同的操作,定义宏可以简化程序,我定义一个简单的宏来操作SHE,seh0.inc文件中有宏的具体定义,我不会解释他们,因为他们的作用和我们刚刚说明的一样。如果异常处理没有特别的要求,用宏调用_try / _finally代替上面对寄存器处理的代码,其中SafePlace地址就是宏调用的_finally。
_try
invoke BuggyWriter
_finally
这次我们调用BuggyWriter函数来触发异常,这个函数企图向地址7FFF0000h处写入四字节的数据。
BuggyWriter proc
mov eax, MmUserProbeAddress
mov eax, [eax]
mov eax, [eax]
mov byte ptr [eax], 0
ret
BuggyWriter endp
从范围7FFF0000h - 7FFFFFFFh大小64k的内存区域,保留作为用户和系统空间交换数据的缓冲边界。这个范围的开始地址在内核变量MmUserProbeAddress中输出。
有了这些结构化异常处理的知识我们继续进行下一个例子。这个例子中我们用驱动请求用户模式地址范围的内存。这样的处理必须要注册SHE结构。
;@echo off
;goto make
.386
.model flat, stdcall
option casemap:none
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; I N C L U D E F I L E S
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
include /masm32/include/windows.inc
include /masm32/include/w2k/native.inc
include /masm32/include/w2k/ntstatus.inc
include /masm32/include/winioctl.inc
include /masm32/include/kernel32.inc
include /masm32/include/user32.inc
include /masm32/include/advapi32.inc
include /masm32/include/w2k/ntdll.inc
includelib /masm32/lib/kernel32.lib
includelib /masm32/lib/user32.lib
includelib /masm32/lib/advapi32.lib
includelib /masm32/lib/w2k/ntdll.lib
include /masm32/Macros/Strings.mac
include ../common.inc
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; C O D E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; CallDriver
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
CallDriver proc
local fOk:BOOL
local hSCManager:HANDLE
local hService:HANDLE
local acModulePath[MAX_PATH]:CHAR
local _ss:SERVICE_STATUS
local hDevice:HANDLE
local abyOutBuffer[4]:BYTE
local dwBytesReturned:DWORD
and fOk, FALSE ; assume error
invoke OpenSCManager, NULL, NULL, SC_MANAGER_ALL_ACCESS
.if eax != NULL
mov hSCManager, eax
push eax
invoke GetFullPathName, $CTA0("SharedSection.sys"), sizeof acModulePath, addr acModulePath, esp
pop eax
invoke CreateService, hSCManager, $CTA0("SharedSection"), $CTA0("One way to share section"), /
SERVICE_START + SERVICE_STOP + DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, /
SERVICE_ERROR_IGNORE, addr acModulePath, NULL, NULL, NULL, NULL, NULL
.if eax != NULL
mov hService, eax
invoke StartService, hService, 0, NULL
.if eax != 0
invoke CreateFile, $CTA0("////.//SharedSection"), 0, /
0, NULL, OPEN_EXISTING, 0, NULL
.if eax != INVALID_HANDLE_VALUE
mov hDevice, eax
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
invoke DeviceIoControl, hDevice, IOCTL_SHARE_MY_SECTION, NULL, 0, NULL, 0, addr dwBytesReturned, NULL addr dwBytesReturned, NULL
.if eax != 0
inc fOk
.else
invoke MessageBox, NULL, $CTA0("Can't send control code to device."), NULL, MB_OK + MB_ICON
.endif
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
invoke CloseHandle, hDevice
.else
invoke MessageBox, NULL, $CTA0("Device is not present."), NULL, MB_ICONSTOP
.endif
invoke ControlService, hService, SERVICE_CONTROL_STOP, addr _ss
.else
invoke MessageBox, NULL, $CTA0("Can't start driver."), NULL, MB_OK + MB_ICONSTOP
.endif
invoke DeleteService, hService
invoke CloseServiceHandle, hService
.else
invoke MessageBox, NULL, $CTA0("Can't register driver."), NULL, MB_OK + MB_ICONSTOP
.endif
invoke CloseServiceHandle, hSCManager
.else
invoke MessageBox, NULL, $CTA0("Can't connect to Service Control Manager."), /
NULL, MB_OK + MB_ICONSTOP
.endif
mov eax, fOk
ret
CallDriver end
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; start
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
start proc
local hSection:HANDLE
local liSectionSize:_LARGE_INTEGER
local oa:OBJECT_ATTRIBUTES
local pSectionBaseAddress:PVOID
local liViewSize:_LARGE_INTEGER
and liSectionSize.HighPart, 0
mov liSectionSize.LowPart, SECTION_SIZE
lea ecx, oa
InitializeObjectAttributes ecx, offset g_usSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL
invoke ZwCreateSection, addr hSection, SECTION_MAP_WRITE + SECTION_MAP_READ, addr oa, /
addr liSectionSize, PAGE_READWRITE, SEC_COMMIT, NULL
.if eax == STATUS_SUCCESS
and pSectionBaseAddress, NULL ; The system itself should choose the address
and liViewSize.HighPart, 0 ; Map whole section
and liViewSize.LowPart, 0
; NtCurrentProcess equ -1
invoke ZwMapViewOfSection, hSection, NtCurrentProcess, addr pSectionBaseAddress, 0, SECTION_SIZE, /
NULL, addr liViewSize, ViewShare, 0, PAGE_READWRITE
.if eax == STATUS_SUCCESS
; The reversed string you will able to read if everithing goes fine
CTA ".revird ecived a dna sessecorp resu neewteb yromem ", g_szStrToReverse
CTA "erahs ot euqinhcet emas eht esu nac uoy ,revewoH "
CTA ".sessecorp resu gnoma yromem gnirahs rof desu euqinhcet "
CTA0 "nommoc a si elif gnigap eht yb dekcab elif deppam-yromem A"
invoke strcpy, pSectionBaseAddress, addr g_szStrToReverse
invoke CallDriver
.if eax == TRUE
invoke MessageBox, NULL, pSectionBaseAddress, /
$CTA0("HOWTO: Share Memory Between User Mode and Kernel Mode"), /
MB_OK + MB_ICONINFORMATION
.endif
invoke ZwUnmapViewOfSection, NtCurrentProcess, pSectionBaseAddress
.else
invoke MessageBox, NULL, $CTA0("Can't map section."), NULL, MB_OK + MB_ICONSTOP
.endif
invoke ZwClose, hSection
.else
invoke MessageBox, NULL, $CTA0("Can't create section."), NULL, MB_OK + MB_ICONSTOP
.endif
invoke ExitProcess, 0
ret
start endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
end start
:make
set exe=SharedSection
if exist ../%exe%.exe del ../%exe%.exe
/masm32/bin/ml /nologo /c /coff %exe%.bat
/masm32/bin/link /nologo /subsystem:windows %exe%.obj
del %exe%.obj
move %exe%.exe ..
if exist %exe%.exe del %exe%.exe
echo.
Pause
下面只说明关键点,许多应该是清楚的即使没有注释。
and liSectionSize.HighPart, 0
mov liSectionSize.LowPart, SECTION_SIZE
内存区必须说明大小。他的数量可以扩展到4GB大小,也就是LARGE_INTEGER类型变量的范围,我们初始化SECTION_SIZE大小的值等于一页的大小(4KB),SECTION_SIZE常量在文件common.inc中定义。
lea ecx, oa
InitializeObjectAttributes ecx, offset g_usSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL
通过我们已经熟悉的一个宏调用InitializeObjectAttributes,初始化ZwCreateSection所要用的 OBJECT_ATTRIBUTES结构。
对共享内存区进行命名,这样我们就可以通过名字打开,命名内存区定义在文件common.inc中
.const
CCOUNTED_UNICODE_STRING
"//BaseNamedObjects//UserKernelSharedSection", g_usSectionName, 4
内存区对象存放在目录BaseNamedObjects,命名空间控制对象通常存放用户进程创建的命名对象。
invoke ZwCreateSection, addr hSection, SECTION_MAP_WRITE + SECTION_MAP_READ, addr oa, /
addr liSectionSize, PAGE_READWRITE, SEC_COMMIT, NULL
调用ZwCreateSection函数创建一个命名内存区对象,大小为SECTION_SIZE,读写访问权限,如果创建成功,变量hSection描述这个内存区。
and pSectionBaseAddress, NULL
and liViewSize.HighPart, 0
and liViewSize.LowPart, 0
invoke ZwMapViewOfSection, hSection, NtCurrentProcess, addr pSectionBaseAddress, 0, SECTION_SIZE, /
NULL, addr liViewSize, ViewShare, 0, PAGE_READWRITE
内存区对象映射到内存地址空间中,有许多参数在DDK中有详细的描述。由于pSectionBaseAddress变量初始值为零,系统会自动在一个地址映射,并且返回这个地址给pSectionBaseAddress变量。LiViewSize变量初始化为零表示内存区对象会被完全映射。
CTA ".revird ecived a dna sessecorp resu neewteb yromem ", g_szStrToReverse
CTA "erahs ot euqinhcet emas eht esu nac uoy ,revewoH "
CTA ".sessecorp resu gnoma yromem gnirahs rof desu euqinhcet "
CTA0 "nommoc a si elif gnigap eht yb dekcab elif deppam-yromem A"
invoke strcpy, pSectionBaseAddress, addr g_szStrToReverse
复制这些被翻转的字符串,驱动的作用就是把这些字符串翻转。
invoke ZwUnmapViewOfSection, NtCurrentProcess, pSectionBaseAddress
.endif
invoke ZwClose, hSection
8.2.2 SharedSection驱动程序源码
;@echo off
;goto make
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; SharedSection - How to share section between kernel-mode driver and its user-mode client
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::::::::::::::::::::::::::::::
.386
.model flat, stdcall
option casemap:none
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; I N C L U D E F I L E S
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::::::::::::::::::::::::::::::
include /masm32/include/w2k/ntstatus.inc
include /masm32/include/w2k/ntddk.inc
include /masm32/include/w2k/ntoskrnl.inc
include /masm32/include/w2k/native.inc
includelib /masm32/lib/w2k/ntoskrnl.lib
include /masm32/Macros/Strings.mac
include ../common.inc
include seh0.inc
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; R E A D O N L Y D A T A
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.const
CCOUNTED_UNICODE_STRING "//Device//SharedSection", g_usDeviceName, 4
CCOUNTED_UNICODE_STRING "//DosDevices//SharedSection", g_usSymbolicLinkName, 4
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; C O D E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; DispatchCreateClose
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
mov eax, pIrp
mov (_IRP PTR [eax]).IoStatus.Status, STATUS_SUCCESS
and (_IRP PTR [eax]).IoStatus.Information, 0
fastcall IofCompleteRequest, pIrp, IO_NO_INCREMENT
mov eax, STATUS_SUCCESS
ret
DispatchCreateClose endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; DispatchControl
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DispatchControl proc uses esi edi pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
local hSection:HANDLE
local oa:OBJECT_ATTRIBUTES
local pSectionBaseAddress:PVOID
local liViewSize:LARGE_INTEGER
invoke DbgPrint, $CTA0("/nSharedSection: Entering DispatchControl/n")
mov esi, pIrp
assume esi:ptr _IRP
; Assume unsuccess
mov [esi].IoStatus.Status, STATUS_UNSUCCESSFUL
; We copy nothing
and [esi].IoStatus.Information, 0
IoGetCurrentIrpStackLocation esi
mov edi, eax
assume edi:ptr IO_STACK_LOCATION
.if [edi].Parameters.DeviceIoControl.IoControlCode == IOCTL_SHARE_MY_SECTION
invoke DbgPrint, $CTA0("SharedSection: Opening section object/n")
lea ecx, oa
InitializeObjectAttributes ecx, offset g_usSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL
invoke ZwOpenSection, addr hSection, SECTION_MAP_WRITE + SECTION_MAP_READ, addr oa
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("SharedSection: Section object opened/n")
and pSectionBaseAddress, NULL
; The system itself should choose the address
and liViewSize.HighPart, 0
and liViewSize.LowPart, 0
; NtCurrentProcess equ -1
invoke ZwMapViewOfSection, hSection, NtCurrentProcess, addr pSectionBaseAddress, 0, SECTION_SIZE, /
NULL, addr liViewSize, ViewShare, 0, PAGE_READWRITE
.if eax == STATUS_SUCCESS
invoke DbgPrint, $CTA0("SharedSection: Section mapped at address %08X/n"), pSectionBaseAddress
_try
invoke _strrev, pSectionBaseAddress
mov [esi].IoStatus.Status, STATUS_SUCCESS
invoke DbgPrint, $CTA0("SharedSection: String reversed/n")
_finally
invoke ZwUnmapViewOfSection, NtCurrentProcess, pSectionBaseAddress
invoke DbgPrint, $CTA0("SharedSection: Section at address %08X unmapped /n"), pSectionBaseAddress
.else
invoke DbgPrint, $CTA0("SharedSection: Couldn't map view of section. Status: %08X/n"), eax
.endif
invoke ZwClose, hSection
invoke DbgPrint, $CTA0("SharedSection: Section object handle closed/n")
.else
invoke DbgPrint, $CTA0("SharedSection: Couldn't open section. Status: %08X/n"), eax
.endif
.else
mov [esi].IoStatus.Status, STATUS_INVALID_DEVICE_REQUEST
.endif
assume edi:nothing
fastcall IofCompleteRequest, esi, IO_NO_INCREMENT
invoke DbgPrint, $CTA0("SharedSection: Leaving DispatchControl/n")
mov eax, [esi].IoStatus.Status
assume esi:nothing
ret
DispatchControl endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; DriverUnload
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DriverUnload proc pDriverObject:PDRIVER_OBJECT
invoke IoDeleteSymbolicLink, addr g_usSymbolicLinkName
mov eax, pDriverObject
invoke IoDeleteDevice, (DRIVER_OBJECT PTR [eax]).DeviceObject
ret
DriverUnload endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; D I S C A R D A B L E C O D E
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
.code INIT
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
; DriverEntry
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
local status:NTSTATUS
local pDeviceObject:PDEVICE_OBJECT
mov status, STATUS_DEVICE_CONFIGURATION_ERROR
invoke IoCreateDevice, pDriverObject, 0, addr g_usDeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, addr pDeviceObject
.if eax == STATUS_SUCCESS
invoke IoCreateSymbolicLink, addr g_usSymbolicLinkName, addr g_usDeviceName
.if eax == STATUS_SUCCESS
mov eax, pDriverObject
assume eax:ptr DRIVER_OBJECT
mov [eax].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)], offset DispatchCreateClose
mov [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)], offset DispatchCreateClose
mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*(sizeof PVOID)], offset DispatchControl
mov [eax].DriverUnload, offset DriverUnload
assume eax:nothing
mov status, STATUS_SUCCESS
.else
invoke IoDeleteDevice, pDeviceObject
.endif
.endif
mov eax, status
ret
DriverEntry endp
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
end DriverEntry
:make
set drv=SharedSection
/masm32/bin/ml /nologo /c /coff %drv%.bat
/masm32/bin/link /nologo /driver /base:0x10000 /align:32 /out:%drv%.sys /subsystem:native /ignore:4078 %drv%.obj
del %drv%.obj
move %drv%.sys ..
echo.
pause
一般当处理共享资源的时候,要求必须是同步的,如果对共享资源的写和读不能同时访问,流操作不能进行。
lea ecx, oa
InitializeObjectAttributes ecx, offset g_usSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL
invoke ZwOpenSection, addr hSection, SECTION_MAP_WRITE + SECTION_MAP_READ, addr oa
接收IOCTL_SHARE_MY_SECTION控制代码后,驱动程序试着打开一个内存区对象通过g_usSectionName,作为内存区对象名。
.if eax == STATUS_SUCCESS
and pSectionBaseAddress, NULL
and liViewSize.HighPart, 0
and liViewSize.LowPart, 0
invoke ZwMapViewOfSection, hSection, NtCurrentProcess, addr pSectionBaseAddress, 0, SECTION_SIZE, /
NULL, addr liViewSize, ViewShare, 0, PAGE_READWRITE
.if eax == STATUS_SUCCESS
如果映射的内存区成功打开,跟从程序的地址空间中的读数据是没有区别的。但是...
通过调用ZwMapViewOfSection函数,变量pSectionBaseAddress被赋予用户地址范围的一个值,而不是内核地址范围。因为在这个地址仅内存区映射的进程地址空间环境中用到。当共享内存区处于驱动平台(传入IRP_MJ_DEVICE_CONTROL控制码到驱动环境中流操作会被触发),然后在程序环境中。
虚拟地址是不同的在内核模式和我们的用户程序环境中,但是被映射的内存区物理页面是相同的。在我们的例子中就是一页和要翻转的数据。
_try
invoke _strrev, pSectionBaseAddress
mov [esi].IoStatus.Status, STATUS_SUCCESS
_finally
通过设置SHE结构,调用_strrev转换字符串,现在很容易被读出来。
invoke ZwUnmapViewOfSection, NtCurrentProcess, pSectionBaseAddress
.endif
invoke ZwClose, hSection
.endif
释放被分配的资源,在驱动管理程序中返回代码表示DeviceIoControl成功,并且显示翻转后的行。