程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi研究之驅動開發篇(六)--利用Section與用戶模式程序通訊(上)

Delphi研究之驅動開發篇(六)--利用Section與用戶模式程序通訊(上)

編輯:Delphi

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved