日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Delphi - SEH研究

發布時間:2024/4/11 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Delphi - SEH研究 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

技術交流,DH講解.

前幾天一個朋友在弄游戲外掛想帶NP調試,就像自己來捕獲游戲的異常.
好像就要用到SEH這方面的知識.
一起研究了一下,這里看下研究 和 在網上找的資料吧.
SEH就是Structure Exception Handling.結構化異常處理,具體可以看下MSDN.
MSDN在手,走遍天下無敵手.哈哈.
當時先自己看下Delphi 怎么實現try..except..end的吧.我們寫段程序然后調試就知道了.

Procedure TForm1.Button1Click( Sender: TObject ); Vara: TForm1; Begina := Nil;Trya.Show;ExceptShowMessage( '1111' );End; End;


這樣是會發生異常的吧,我們下斷點,然后調試的時候ctrl + alt + c進入CPU窗口.

Unit1.pas.38: a := Nil; 00452702 33C0 xor eax,eax Unit1.pas.39: Try 00452704 33D2 xor edx,edx 00452706 55 push ebp 00452707 6821274500 push $00452721 0045270C 64FF32 push dword ptr fs:[edx] 0045270F 648922 mov fs:[edx],esp Unit1.pas.40: a.Show; 00452712 E811B3FFFF call TCustomForm.Show 00452717 33C0 xor eax,eax 00452719 5A pop edx 0045271A 59 pop ecx 0045271B 59 pop ecx 0045271C 648910 mov fs:[eax],edx 0045271F EB14 jmp +$14 00452721 E91E12FBFF jmp @HandleAnyException Unit1.pas.42: ShowMessage( '1111' ); 00452726 B844274500 mov eax,$00452744 0045272B E85C8DFDFF call ShowMessage 00452730 E87715FBFF call @DoneExcept Unit1.pas.44: End;


我們看見了try模塊的代碼了吧.好的自己來寫個函數.

Procedure SetExceptionProc( Proc: Pointer ); Asm//將回調函數指針壓入堆棧push eax//保護 原來的處理函數push fs:[0]mov fs:[0],esp End;

你看和Delphi代碼里面Try反編譯出來的一樣吧.
至于為什么要這樣寫?我也不知道,所以我們現在需要去找資料了.
發生異常時系統的處理順序(by Jeremy Gordon):
?? 1.系統首先判斷異常是否應發送給目標程序的異常處理例程,如果決定應該發送,并且目標程序正在被調試,則系統
?? 掛起程序并向調試器發送EXCEPTION_DEBUG_EVENT消息.呵呵,這不是正好可以用來探測調試器的存在嗎?
?? 2.如果你的程序沒有被調試或者調試器未能處理異常,系統就會繼續查找你是否安裝了線程相關的異常處理例程,如果
?? 你安裝了線程相關的異常處理例程,系統就把異常發送給你的程序seh處理例程,交由其處理.
?? 3.每個線程相關的異常處理例程可以處理或者不處理這個異常,如果他不處理并且安裝了多個線程相關的異常處理例程,
可交由鏈起來的其他例程處理.
?? 4.如果這些例程均選擇不處理異常,如果程序處于被調試狀態,操作系統仍會再次掛起程序通知debugger.
?? 5.如果程序未處于被調試狀態或者debugger沒有能夠處理,并且你調用SetUnhandledExceptionFilter安裝了最后異
?? 常處理例程的話,系統轉向對它的調用.
?? 6.如果你沒有安裝最后異常處理例程或者他沒有處理這個異常,系統會調用默認的系統處理程序,通常顯示一個對話框,
?? 你可以選擇關閉或者最后將其附加到調試器上的調試按鈕.如果沒有調試器能被附加于其上或者調試器也處理不了,系統
?? 就調用ExitProcess終結程序.
?? 7.不過在終結之前,系統仍然對發生異常的線程異常處理句柄來一次展開,這是線程異常處理例程最后清理的機會.
事實上,當異常發生時,系統給了我們一個處理異常的機會,他首先會調用我們自定義的seh處理例程,當然也包括
了相關信息,在調用之前,系統把包含這些信息結構的指針壓入stack,供我們的異常處理例程調用,
傳遞給例程的參數通常是四個,其中只有三個有明確意義,另一個到現在為止還沒有發現有什么作用,
這些參數是:pExcept:DWORD,pErr:DWORD,pContext:DWORD,pDispatch意義如下:
pExcept: --- EXCEPTION_RECORD結構的指針
pErr: --- 前面ERR結構的指針
pContext: --- CONTEXT結構的指針 ,里面都是我們寄存器的值.
pDispatch:---沒有發現有啥意義
Delphi里面已經定義好了這些結構體指針了,我就不多說了.
我們來把回調函數寫出來吧.

Function ExceptionProc( pExcept: PExceptionRecord;pError: Pointer;pContxt: PContext;pDispatch: Pointer ): Integer; Stdcall; BeginShowMessage( '1111' );Result:=0; End;

注意是stdcall調用方式,貌似有些資料上面是cdecl.這里我們先不管這么多了.
現在我們看看系統是怎么調用我們回調函數的.
關鍵的 Win32 數據結構——線程信息塊(即 TEB 和 TIB)。
該數據結構的某些域在 Windows NT、Windows 95、Win32s 和 OS/2 平臺上是一樣的。
TIB 中的第一個 DWORD 是指向線程 EXCEPTION_REGISTRATION 結構的指針。
在 Intel Win32 平臺上,FS 寄存器總是指向當前的 TIB。
因此,在 FS:[0]位置,你能找到 EXCEPTION_REGISTRATION 結構的指針。
這里也就解釋了 我們SetExceptionProc函數了.
好的我們自己寫段代碼來測試一下了:

Procedure TestException( ); Begin//trySetExceptionProc( @ExceptionProc );//make a exceptionAsmxor edx,edxmov [edx],0End;//恢復異常Asmpop eaxmov fs:[0],eaxadd esp,8End; End; Procedure TForm1.Button2Click( Sender: TObject ); BeginTestException; End;


測試中恢復異常還是有問題.

終于在CSDN的書呆子的博客上面找到了答案.

Program Project2; {$APPTYPE CONSOLE} UsesSysUtils,Windows; TypePExecption_Handler= ^Exception_Handler;PException_Registration= ^Exception_Registration;_ExceptionHandler= RecordExceptionRecord: PExceptionRecord;SEH: PException_Registration;Context: PContext;DispatcherContext: Pointer;End;Exception_Handler= _ExceptionHandler;_ExceptionRegistration= RecordPrev: PException_Registration;Handler: PExecption_Handler;End;Exception_Registration= _ExceptionRegistration; ConstEXCEPTION_CONTINUE_EXECUTION= 0; ///恢復CONTEXT里的寄存器環境,繼續執行EXCEPTION_CONTINUE_SEARCH= 1; ///拒絕處理這個異常,請調用下個異常處理函數EXCEPTION_NESTED_EXCEPTION= 2; ///函數中出發了新的異常EXCEPTION_COLLIDED_UNWIND= 3; ///發生了嵌套展開操作EH_NONE= 0;EH_NONCONTINUABLE= 1;EH_UNWINDING= 2;EH_EXIT_UNWIND= 4;EH_STACK_INVALID= 8;EH_NESTED_CALL= 16;STATUS_ACCESS_VIOLATION= $C0000005; ///訪問非法地址STATUS_ARRAY_BOUNDS_EXCEEDED= $C000008C;STATUS_FLOAT_DENORMAL_OPERAND= $C000008D;STATUS_FLOAT_DIVIDE_BY_ZERO= $C000008E;STATUS_FLOAT_INEXACT_RESULT= $C000008F;STATUS_FLOAT_INVALID_OPERATION= $C0000090;STATUS_FLOAT_OVERFLOW= $C0000091;STATUS_FLOAT_STACK_CHECK= $C0000092;STATUS_FLOAT_UNDERFLOW= $C0000093;STATUS_INTEGER_DIVIDE_BY_ZERO= $C0000094; ///除0錯誤STATUS_INTEGER_OVERFLOW= $C0000095;STATUS_PRIVILEGED_INSTRUCTION= $C0000096;STATUS_STACK_OVERFLOW= $C00000FD;STATUS_CONTROL_C_EXIT= $C000013A; VarG_TEST: DWORD; Procedure Log( LogMsg: String ); BeginWriteln( LogMsg ); End; //看這個回調函數,和我們那個有點兒區別,第二個參數的作用原來是ExceptionRegistration,原來秘密在它身上 Function ExceptionHandler( ExceptionHandler: EXCEPTION_HANDLER ): LongInt; Cdecl; BeginResult := EXCEPTION_CONTINUE_SEARCH;If ExceptionHandler.ExceptionRecord.ExceptionFlags= EH_NONE ThenBeginCase ExceptionHandler.ExceptionRecord.ExceptionCode OfSTATUS_ACCESS_VIOLATION:BeginLog( '發現異常為非法內存訪問,嘗試修復EBX,繼續執行' );ExceptionHandler.Context.Ebx := DWORD( @G_TEST );Result := EXCEPTION_CONTINUE_EXECUTION;End;ElseLog( '這個異常我無法處理,請讓別人處理吧' );End;EndElseIf ExceptionHandler.ExceptionRecord.ExceptionFlags= EH_UNWINDING ThenLog( '異常展開操作' );End;BeginAsm///設置SEHXOR EAX, EAXPUSH OFFSET ExceptionHandlerPUSH FS:[EAX]MOV FS:[EAX], ESP///產生內存訪問錯誤XOR EBX, EBXMOV [EBX], 0///取消SEHXOR EAX, EAX//這里用的這個 而不是我們用的那個pop eax呀..哈哈.一切正常了MOV ECX, [ESP]MOV FS:[EAX], ECXADD ESP, 8End;Readln; End.

牛人拜讀了.大家可以去CSDN上面看下.

好了我是DH.大家想了解更多可以看看雪的加密解密 以及 那個 什么軟件漏洞分析 書上面都有SEH的章節.

總結

以上是生活随笔為你收集整理的Delphi - SEH研究的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。