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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Delphi - SEH研究

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

技術(shù)交流,DH講解.

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

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


這樣是會發(fā)生異常的吧,我們下斷點,然后調(diào)試的時候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模塊的代碼了吧.好的自己來寫個函數(shù).

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

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

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

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

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


測試中恢復(fù)異常還是有問題.

終于在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; ///恢復(fù)CONTEXT里的寄存器環(huán)境,繼續(xù)執(zhí)行EXCEPTION_CONTINUE_SEARCH= 1; ///拒絕處理這個異常,請調(diào)用下個異常處理函數(shù)EXCEPTION_NESTED_EXCEPTION= 2; ///函數(shù)中出發(fā)了新的異常EXCEPTION_COLLIDED_UNWIND= 3; ///發(fā)生了嵌套展開操作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; //看這個回調(diào)函數(shù),和我們那個有點兒區(qū)別,第二個參數(shù)的作用原來是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( '發(fā)現(xiàn)異常為非法內(nèi)存訪問,嘗試修復(fù)EBX,繼續(xù)執(zhí)行' );ExceptionHandler.Context.Ebx := DWORD( @G_TEST );Result := EXCEPTION_CONTINUE_EXECUTION;End;ElseLog( '這個異常我無法處理,請讓別人處理吧' );End;EndElseIf ExceptionHandler.ExceptionRecord.ExceptionFlags= EH_UNWINDING ThenLog( '異常展開操作' );End;BeginAsm///設(shè)置SEHXOR EAX, EAXPUSH OFFSET ExceptionHandlerPUSH FS:[EAX]MOV FS:[EAX], ESP///產(chǎn)生內(nèi)存訪問錯誤XOR EBX, EBXMOV [EBX], 0///取消SEHXOR EAX, EAX//這里用的這個 而不是我們用的那個pop eax呀..哈哈.一切正常了MOV ECX, [ESP]MOV FS:[EAX], ECXADD ESP, 8End;Readln; End.

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

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

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。