KMD驱动教程续-8

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.
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值