当前位置:编程学习 > Delphi >>

Delphi研究之驱动开发篇(六)--利用Section与用户模式程序通讯(上)

作 者: mickeylan
时 间: 2008-06-10,00:45
链 接: http://bbs.pediy.com/showthread.php?t=66291

在进入主题之前,先来简单地看一下结构化异常处理(Structured Exception Handling, SEH),本篇的程序需要这个东东。
结构化异常处理
这里我并不打算详细讲结构化异常处理,关于SEH,在网上你能找到相关的内容,SHE能用于所有的异常处理,也就是说,SEH既能用于用户模式又能用于内核模式。但这两种模式下的异常处理有一个本质上的差别:
在内核模式下,借助于seh,并非所有的异常都能得到处理!比如说,即使使用了seh,用零作除数作除法也会使系统崩溃。最为可怕的是,引用未定义的内核内存也会导致蓝屏死机BSOD。而对未定义的用户模式内存的引用异常,seh却可以轻松处理。因此避免系统崩溃的唯一办法就是所编写的代码不要导致无法处理的异常。
以下是个使用结构化异常的例子:
代码:unit seh;

interface

uses
    nt_status;

function _DriverEntry(pDriverObject:PDRIVER_OBJECT;
                        pusRegistryPath:PUNICODE_STRING): NTSTATUS; stdcall;   

implementation

uses
    ntoskrnl;

const
    SEH_SafePlaceCounter    = 0;
    SEH_INSTALLED            = 0;

type
    _SEH = record
      SafeEip: DWORD; { 线程继续执行的地方 }
      PrevEsp: DWORD; { 以前esp的值 }
      PrevEbp: DWORD; { 以前ebp的值 }
    end;

var
    sseh: _SEH;

function DefaultExceptionHandler(pExcept:PEXCEPTION_RECORD;
                                   pFrame:DWORD;
                                   pContext:PCONTEXT;
                                   pDispatch:DWORD): DWORD; cdecl;
begin
    DbgPrint(#13#10SEH: An exception %08X has occured#13#10,
             pExcept^.ExceptionCode);
    if pExcept^.ExceptionCode = $0C0000005 then
    begin
      {如果发生了EXCEPTION_ACCESS_VIOLATION类型的异常,}
      {则输出以下信息.}
      DbgPrint( Access violation at address: %08X#13#10,
               pExcept^.ExceptionAddress);
      if pExcept^.ExceptionInformation[0] <> nil then    {试图读还是写?}
      begin
        DbgPrint( The code tried to write to address %08X#13#10#13#10,
                 DWORD(pExcept^.ExceptionInformation[4]));
      end else
      begin
        DbgPrint( The code tried to read from address %08X#13#10#13#10,
                 DWORD(pExcept^.ExceptionInformation[4]));
      end;
    end;
    asm
      lea eax, sseh
      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
    end;
    result := 0;
end;

procedure BuggyReader; assembler;
asm
    xor eax, eax
    mov eax, [eax]    {!!! 没有SEH的话 - BSOD !!!}
end;

procedure BuggyWriter; assembler;
asm
    mov eax, offset MmUserProbeAddress
    mov eax, [eax]
    mov eax, [eax]

    mov byte ptr [eax], 0 {!!!没有SEH的话 - BSOD !!!}
end;

function _DriverEntry(pDriverObject:PDRIVER_OBJECT;
                        pusRegistryPath:PUNICODE_STRING): NTSTATUS; stdcall;
label
    SafePlace;
begin
    DbgPrint(#13#10SEH: Entering DriverEntry#13#10);
    { "手工"安装SEH }
    asm
      push offset DefaultExceptionHandler    {我们的SEH程序}
      push fs:[0]
      mov fs:[0], esp

      mov sseh.SafeEip, offset SafePlace    {SafePlace是处理完异常后继续执行的地方}
      mov sseh.PrevEbp, ebp
      mov sseh.PrevEsp, esp
    end;
    BuggyReader;
    BuggyWriter;

SafePlace:
    asm
      pop fs:[0]
      add esp, 4
    end;
   
    DbgPrint(#13#10SEH: Leaving DriverEntry#10#13);
    result := STATUS_DEVICE_CONFIGURATION_ERROR;
end;

end.
安装SHE-Frame
   由于在内核模式下我们无法直接使用Delphi自身的异常处理机制,因为在驱动程序中我们要自己手工安装SHE,这里我们使用Delphi的BASM来做这件事情,了解SHE的朋友都知道,做这件事情是非常简单的。

代码:asm
      push offset DefaultExceptionHandler    {我们的SEH程序}
      push fs:[0]
      mov fs:[0], esp

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

代码:procedure BuggyReader; assembler;
asm
    xor eax, eax
    mov eax, [eax]    {!!! 没有SEH的话 - BSOD !!!}
end;
nil指针引用是一个十分常见的错误,微软在00000000-0000FFFFh划出了64k字节的内存区,并使此区域无法访问。访问此区域中的任何一个字节都会导致EXCEPTION_ACCESS_VIOLATION类型的异常。
异常处理
   函数BuggyReader从地址00000000读取引发了异常,我们就进入了我们指定的处理程序。
代码:function DefaultExceptionHandler(pExcept:PEXCEPTION_RECORD;
                                   pFrame:DWORD;
        

补充:软件开发 , Delphi ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,