技術(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)容還不錯,歡迎將生活随笔推薦給好友。