SEH in ASM 研究(一)
生活随笔
收集整理的這篇文章主要介紹了
SEH in ASM 研究(一)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
SEH? in ASM 研究(一)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? By Hume/冷雨飄心
為什么老調重彈:
? ? SEH出現已絕非一日,但很多人可能還不徹底了解Seh的運行機制;有關seh的知識資料不是很多,asm級的詳細資料就
更少!seh不僅可以簡化程序錯誤處理,使你的程序更加健壯,還被廣泛應用于反跟蹤以及加解密中,因此,了解seh非常必要,
但遺憾的是關于seh詳細介紹的中文資料非常少,在實踐的基礎上,把自己學習的一點筆記奉獻給大家,希望對喜歡ASM的朋
友有所幫助.如有錯誤,請高手不吝指正.
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? PART? I? 簡單接觸
一、SEH背景知識
SEH("Structured Exception Handling"),即結構化異常處理.是操作系統提供給程序設計者的強有力的處理程序錯
誤或異常的武器.在VISUAL C++中你或許已經熟悉了_try{} _finally{} 和_try{} _except {} 結構,這些并不是
編譯程序本身所固有的,本質上只不過是對windows內在提供的結構化異常處理的包裝,不用這些高級語言編譯器所提供
的包裝 ,照樣可以利用系統提供的強大seh處理功能,在后面你將可以看到,用系統本身提供seh結構和規則以及ASM語言,
我們將對SEH的機制以及實現有一個徹底的了解.
發生異常時系統的處理順序(by Jeremy Gordon):
? ??1.系統首先判斷異常是否應發送給目標程序的異常處理例程,如果決定應該發送,并且目標程序正在被調試,則系統
? ??掛起程序并向調試器發送EXCEPTION_DEBUG_EVENT消息.呵呵,這不是正好可以用來探測調試器的存在嗎?
? ??2.如果你的程序沒有被調試或者調試器未能處理異常,系統就會繼續查找你是否安裝了線程相關的異常處理例程,如果
? ??你安裝了線程相關的異常處理例程,系統就把異常發送給你的程序seh處理例程,交由其處理.
? ??3.每個線程相關的異常處理例程可以處理或者不處理這個異常,如果他不處理并且安裝了多個線程相關的異常處理例程,
? ? ? ? 可交由鏈起來的其他例程處理.
? ??4.如果這些例程均選擇不處理異常,如果程序處于被調試狀態,操作系統仍會再次掛起程序通知debugger.
? ??5.如果程序未處于被調試狀態或者debugger沒有能夠處理,并且你調用SetUnhandledExceptionFilter安裝了最后異
? ??常處理例程的話,系統轉向對它的調用.
? ??6.如果你沒有安裝最后異常處理例程或者他沒有處理這個異常,系統會調用默認的系統處理程序,通常顯示一個對話框,
? ??你可以選擇關閉或者最后將其附加到調試器上的調試按鈕.如果沒有調試器能被附加于其上或者調試器也處理不了,系統
? ??就調用ExitProcess終結程序.
? ??7.不過在終結之前,系統仍然對發生異常的線程異常處理句柄來一次展開,這是線程異常處理例程最后清理的機會.
如果你看了上面的步驟一頭霧水的話,別著急,化點時間慢慢理解或者進入下一部分實例操作.
二.初步實戰演習:
? 安裝異常處理句柄.
?
? 有兩種類型的異常處理句柄,一種是final型的,這是在你的異常未能得到線程相關處理例程處理操作系統在即將關閉程序之前會
? 回調的例程,這個例程是進程相關的而不是線程相關的,因此無論是哪個線程發生異常未能被處理,都會調用這個例程.
? ? I. 見下面的例子1:
;//================================例子1---final型的異常處理=================
;// ex. 1,by Hume,2001,just copy make your own hd.h and compile&link
;//========================================================================
.386
.model flat, stdcall
option casemap :none? ; case sensitive
include hd.h? ? ? ? ? ;//相關的頭文件,你自己維護一個吧
;//============================
.data
szCap? ??db "By Hume[AfO],2001...",0
szMsgOK db "OK,the exceptoin was handled by final handler!",0
szMsgERR1 db "It would never Get here!",0
buff? ? db 200 dup(0)
.code
_start:
;//========prog begin====================
? ??lea? ??eax,Final_Handler
? ??invoke? ??SetUnhandledExceptionFilter,eax? ;//調用SetUnhandledExceptionFilter來安裝final SEH
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;//原型很簡單SetUnhandledExceptionFilter proto
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;//pTopLevelExceptionFilter:DWORD
? ? ? ? xor? ? ecx,ecx
? ? ? ? mov? ? eax,200? ??
? ? ? ? cdq
? ??div? ??ecx
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;//以下永遠不會被執行
? ? ? ? invoke? ??MessageBox,NULL,addr szMsgERR1,addr szCap,MB_OK+MB_ICONEXCLAMATION
? ? ? ? invoke? ??ExitProcess,NULL
? ? ? ?
;//============================
Final_Handler:
? ??invoke? ??MessageBox,NULL,addr szMsgOK,addr szCap,MB_OK+MB_ICONEXCLAMATION
? ??mov? ??eax,EXCEPTION_EXECUTE_HANDLER? ? ? ? ;//==1 這時不出現非法操作的討厭對話框
? ??;mov? ??eax,EXCEPTION_CONTINUE_SEARCH? ? ;//==0 出現,這時是調用系統默認的異常處理過程,程序被終結了
? ? ;mov? ? eax,EXCEPTION_CONTINUE_EXECUTION? ;//==-1 不斷出現對話框,你將陷入死循環,可別怪我
? ??ret? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;因為我們并沒有修復ecx,所以不斷產生異常,然后不斷調用這個例程
;//=============================Prog Ends==============
end _start
COMMENT $
? 簡單來解釋幾句,windows根據你的異常處理程序的返回值來決定如何進一步處理
? ? ? ? EXCEPTION_EXECUTE_HANDLER? ? ? ? ? ? equ 1? ? 表示我已經處理了異常,可以優雅地結束了
? ? ? ? EXCEPTION_CONTINUE_SEARCH? ? ? ? ? ? equ 0? ? 表示我不處理,其他人來吧,于是windows調用默認的處理程序
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 顯示一個錯誤框,并結束
? ? ? ? EXCEPTION_CONTINUE_EXECUTION? ? ? ? equ -1? 表示錯誤已經被修復,請從異常發生處繼續執行
? ? ? ? 你可以試著讓程序返回0和-1然后編譯程序,就會理解我所有蒼白無力的語言...
$
;//========================================================================
? ? II.另一種是per_Thread Exception Handler->線程相關的異常處理,通常每個線程初始化準備好運行時fs指向一個TIB結構
? ? (THREAD INFORMATION BLOCK),這個結構的第一個元素fs:[0]指向一個_EXCEPTION_REGISTRATION結構
? ? 后面_EXCEPTION_REGISTRATION為了簡化,用ERR來代替這個結構...不要說沒見過啊...
? ? fs:[0]->
? ? _EXCEPTION_REGISTRATION struc
? ? prev dd ?? ? ? ? ? ? ? ? ? ? ? ;前一個_EXCEPTION_REGISTRATION結構
? ? handler dd ?? ? ? ? ? ? ? ? ? ;異常處理例程入口....呵呵,現在明白該怎么作了吧
? ? _EXCEPTION_REGISTRATION ends
? ? 我們可以建立一個ERR結構然后將fs:[0]換成指向他的指針,當然最常用的是堆棧,如果你用靜態內存區也可以,沒有人阻止你
? ? 在asm世界,放心地干吧,除了多S幾次之外,通常不會有更大的損失
? ? 把handler域換成你的程序入口,就可以在發生異常時調用你的代碼了,好馬上實踐一下,見例子2
;//========================================================================
;// ex. 2,by Hume,2001? 線程相關的異常處理
;//========================================================================
.386
.model flat, stdcall
option casemap :none? ; case sensitive
include hd.h? ? ? ? ? ;//相關的頭文件,你自己維護一個吧
;//============================
.data
szCap? ??db "By Hume[AfO],2001...",0
szMsgOK db "It's now in the Per_Thread handler!",0
szMsgERR1 db "It would never Get here!",0
buff? ? db 200 dup(0)
.code
_start:
;//========prog begin====================
? ASSUME FS:NOTHING
? ? ? ? push? ? offset perThread_Handler
? ??push? ? fs:[0]? ? ?
? ? ? ? mov? ? fs:[0],esp? ? ? ? ? ? ? ? ? ? ? ;//建立SEH的基本ERR結構,如果不明白,就仔細研究一下吧
? ? ? ? xor? ? ecx,ecx? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? mov? ? eax,200? ??
? ? ? ? cdq
? ??div? ??ecx
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;//以下永遠不會被執行
? ? ? ? invoke? ??MessageBox,NULL,addr szMsgERR1,addr szCap,MB_OK+MB_ICONINFORMATION
? ? ? ? pop? ? fs:[0]
? ? ? ? add? ? esp,4
? ? ? ? invoke? ??ExitProcess,NULL? ? ? ?
;//============================
perThread_Handler:
? ? ? ? invoke? ??MessageBox,NULL,addr szMsgOK,addr szCap,MB_OK+MB_ICONINFORMATION
? ? ? ? mov? ? eax,1? ? ? ? ? ;//ExceptionContinueSearch,不處理,由其他例程或系統處理
? ? ? ? ;mov? ? eax,0? ? ? ? ? ;//ExceptionContinueExecution,表示已經修復CONTEXT,可從異常發生處繼續執行
? ??ret? ? ? ? ? ? ? ? ? ? ? ? ;//這里如果返回0,你會陷入死循環,不斷跳出對話框....
;//=============================Prog Ends==============
end _start
COMMENT $
? 嘿嘿,這個簡單吧,我們由于沒有足夠的資料,暫時還不能修復ecx的值使之從異常發生處繼續執行,只是簡單顯示一個MSG,然后
? 讓系統處理,自然跳出討厭的對話框了....
? 注意和final返回值的含義不同...
$
;//==================================================================================================
好像到此為止,我們并沒有從異常處理中得到任何好處,除了在異常發生后可以執行一點我們微不足道的代碼,事實上SEH可以修復這些
異常或者干我們想干的事情然后從希望的地方繼續執行,嘿嘿,很爽吧,可惜我們沒有足夠的信息,那里找到我們所需要的信息?
欲知后事如何,且看下回分解...
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? PARTII? ? 繼續深入
? ? ? ? ? ? ? ? ? ? ? ? ? ? ....(待續,睡個覺先)
三、傳遞給異常處理句柄的參數
? ? ? 要想明白seh處理例程如何得到感興趣的信息,首先要明白SEH的作用機制.事實上,當異常
發生時,系統給了我們一個處理異常的機會,他首先會調用我們自定義的seh處理例程,當然也包括
了相關信息,在調用之前,系統把包含這些信息結構的指針壓入stack,供我們的異常處理例程調用,
傳遞給例程的參數通常是四個,其中只有三個有明確意義,另一個到現在為止還沒有發現有什么作用,
這些參數是:pExcept:DWORD,pErr:DWORD,pContext:DWORD,pDispatch意義如下:
pExcept:? ---? EXCEPTION_RECORD結構的指針
pErr:? ? ---? 前面ERR結構的指針
pContext: --- CONTEXT結構的指針
pDispatch:---沒有發現有啥意義
? ? ERR結構是前面介紹的_EXCEPTION_REGISTRATION結構,往前翻翻,Dispatch省略,下面介紹
EXCEPTION_RECORD和CONTEXT結構的定義:
?
;//================================以下是兩個成員的詳細結構========================================
? ??? ??EXCEPTION_RECORD STRUCT
? ??? ??? ExceptionCode? ? ? ? DWORD? ? ? ?? ? ? ;//異常碼
? ??? ??? ExceptionFlags? ? ? ? DWORD? ? ? ?? ??? ;//異常標志
? ??? ??? pExceptionRecord? ? ? DWORD? ? ? ?? ? ? ;//指向另外一個EXCEPTION_RECORD的指針
? ??? ??? ExceptionAddress? ? ? DWORD? ? ? ?? ? ? ;//異常發生的地址
? ??? ??? NumberParameters? ? ? DWORD? ? ? ?? ? ? ;//下面ExceptionInformation所含有的dword數目
? ??? ??? ExceptionInformation? DWORD EXCEPTION_MAXIMUM_PARAMETERS dup(?)
? ??? ??EXCEPTION_RECORD ENDS? ? ? ? ? ? ? ? ? ? ? ;//EXCEPTION_MAXIMUM_PARAMETERS ==15
;//================================具體解釋========================================
ExceptionCode 異常類型,SDK里面有很多類型,你可以在windows.inc里查找STATUS_來找到更多
的異常類型,下面只給出hex值,具體標識定義請查閱windows.inc,你最可能遇到的幾種類型如下:
? ? ? ? ? ? ? C0000005h----讀寫內存沖突
? ? ? ? ? ? ? C0000094h----非法除0
? ? ? ? ? ? ? C00000FDh----堆棧溢出或者說越界
? ? ? ? ? ? ? 80000001h----由Virtual Alloc建立起來的屬性頁沖突
? ? ? ? ? ? ? C0000025h----不可持續異常,程序無法恢復執行,異常處理例程不應處理這個異常
? ? ? ? ? ? ? C0000026h----在異常處理過程中系統使用的代碼,如果系統從某個例程莫名奇妙的返回,則出現此代碼,
? ? ? ? ? ? ? ? ? ? ? ? ? 如果RtlUnwind時沒有Exception Record參數也同樣會填入這個代碼
? ? ? ? ? ? ? 80000003h----調試時因代碼中int3中斷
? ? ? ? ? ? ? 80000004h----處于被單步調試狀態
? ? ? ? ? ? ? 注:也可以自己定義異常代碼,遵循如下規則:
? ? ? ? ? ? ? _____________________________________________________________________+
? ? ? ? ? ? ? 位:? ? ? 31~30? ? ? ? ? ? 29~28? ? ? ? ? 27~16? ? ? ? ? 15~0
? ? ? ? ? ? ? _____________________________________________________________________+
? ? ? ? ? ? ? 含義:? ? 嚴重程度? ? ? ? ? 29位? ? ? ? ? ? 功能代碼? ? ? ? 異常代碼
? ? ? ? ? ? ? ? ? ? ? ? 0==成功? ? ? ? 0==Mcrosoft? ? MICROSOFT定義? 用戶定義
? ? ? ? ? ? ? ? ? ? ? ? 1==通知? ? ? ? 1==客戶
? ? ? ? ? ? ? ? ? ? ? ? 2==警告? ? ? ? ? 28位
? ? ? ? ? ? ? ? ? ? ? ? 3==錯誤? ? ? ? 被保留必須為0
ExceptionFlags 異常標志
? ? ? ? ? ? ? 0----可修復異常
? ? ? ? ? ? ? 1----不可修復異常
? ? ? ? ? ? ? 2----正在展開,不要試圖修復什么,需要的話,釋放必要的資源
pExceptionRecord 如果程序本身導致異常,指向那個異常結構
ExceptionAddress 發生異常的eip地址
ExceptionInformation 附加消息,在調用RaiseException可指定或者在異常號為C0000005h即內存異常時含義如下
? ? ? ? ? ? ? 第一個dword 0==讀沖突 1==寫沖突
? ? ? ? ? ? ? 第二個dword 讀寫沖突地址
;//================================解釋結束========================================
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? off.
? ??? ??CONTEXT STRUCT? ? ? ? ? ? ? ? ? ? ; _
? ??? ??? ContextFlags? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +0
? ??? ??? iDr0? ? ? ? ? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +4
? ??? ??? iDr1? ? ? ? ? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +8
? ??? ??? iDr2? ? ? ? ? DWORD? ? ? ?? ? ? ;? >調試寄存器? +C
? ??? ??? iDr3? ? ? ? ? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +10
? ??? ??? iDr6? ? ? ? ? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +14
? ??? ??? iDr7? ? ? ? ? DWORD? ? ? ?? ? ? ; _|? ? ? ? ? ? +18
? ??? ??? FloatSave? ? FLOATING_SAVE_AREA <>? ;浮點寄存器區 +1C~~~88h
? ??? ??? regGs? ? ? ? DWORD? ? ? ?? ? ? ;--|? ? ? ? ? ? +8C
? ??? ??? regFs? ? ? ? DWORD? ? ? ?? ? ? ;? |/段寄存器? ? +90?
? ??? ??? regEs? ? ? ? DWORD? ? ? ?? ? ? ;? |/? ? ? ? ? ? +94? ? ? ? ? ?
? ??? ??? regDs? ? ? ? DWORD? ? ? ?? ? ? ;--|? ? ? ? ? ? +98
? ??? ??? regEdi? ? ? ? DWORD? ? ? ?? ? ? ;____________? ? +9C
? ??? ??? regEsi? ? ? ? DWORD? ? ? ?? ? ? ;? ? ? |? 通用? +A0
? ??? ??? regEbx? ? ? ? DWORD? ? ? ?? ? ? ;? ? ? |? 寄? ? +A4
? ??? ??? regEdx? ? ? ? DWORD? ? ? ?? ? ? ;? ? ? |? 存? ? +A8
? ??? ??? regEcx? ? ? ? DWORD? ? ? ?? ? ? ;? ? ? |? 器? ? +AC
? ??? ??? regEax? ? ? ? DWORD? ? ? ?? ? ? ;_______|___組_? +B0? ? ?
? ??? ??? regEbp? ? ? ? DWORD? ? ? ?? ? ? ;++++++++++++++++ +B4
? ??? ??? regEip? ? ? ? DWORD? ? ? ?? ? ? ;? ? |控制? ? ? ? +B8
? ??? ??? regCs? ? ? ? DWORD? ? ? ?? ? ? ;? ? |寄存? ? ? ? +BC
? ??? ??? regFlag? ? ? DWORD? ? ? ?? ? ? ;? ? |器組? ? ? ? +C0
? ??? ??? regEsp? ? ? ? DWORD? ? ? ?? ? ? ;? ? |? ? ? ? ? ? +C4
? ??? ??? regSs? ? ? ? DWORD? ? ? ?? ? ? ;++++++++++++++++ +C8
? ??? ??? ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
? ??? ??CONTEXT ENDS
;//================================以上是兩個成員的詳細結構========================================
? ?
? ? ? ? I、傳遞給final句柄的參數,只有兩個可描述為EXCEPTION_POINTERS結構,定義如下:
? ? ? ? ? ? EXCEPTION_POINTERS STRUCT
? ? ? ? ? ? ? pExceptionRecord? DWORD? ? ? ?? ? ? ? ? ? ?
? ? ? ? ? ? ? ContextRecord? ? DWORD? ? ? ?
? ? ? ? ? ? EXCEPTION_POINTERS ENDS
? ? ? ? ? ? 在call xHandler之前,堆棧結構如下:
? ? ? ? ? ? esp? ? -> *EXCEPTION_RECORD
? ??? ? ? ? esp+4? -> *CONTEXT record? ;//具體結構見下面
? ? ? ? ? ? ? ? 然后執行call _Final_Handler,這樣在程序里要調用什么不輕而易舉了嗎?
? ?
? ? II、 傳遞給per_thread句柄的參數,如下:
? ? 在call xHandler之前,在堆棧中形成如下結構
? ? ? ? ? ? esp? ? -> *EXCEPTION_RECORD
? ??? ? ? ? esp+4? -> *ERR? ? ? ? ? ? ? ? ? ? ;//注意這也就是fs:[0]的指向
? ??? ? ? ? esp? ? -> *CONTEXT record? ? ? ? ? ;//point to registers
? ??? ? ? ? esp? ? -> *Param? ? ? ? ? ? ? ? ? ? ;//呵呵,沒有啥意義
? ? ? ? ? 然后執行 call _Per_Thread_Handler
調用handler的原型是這樣
? ??? ??invoke HANDLER,*EXCEPTION_RECORD,*_EXCEPTION_REGISTRATION,*CONTEXT record,*Param
? ??? ??即編譯代碼如下:
? ??? ??PUSH *Param? ? ? ? ? ? ? ? ? ? ;//通常不重要,沒有什么意義
? ??? ??push *CONTEXT record? ? ? ? ? ? ;//上面的結構
? ??? ??push *ERR? ? ? ? ? ? ? ? ? ? ? ;//the struc above
? ??? ??push *EXCEPTION_RECORD? ? ? ? ? ;//see above
? ??? ??CALL HANDLER
? ??? ??ADD ESP,10h
好現在你明白了應該如何訪問具體有關系統信息的細節了吧,下一部分,讓我們來看看如何應用...(待續)
SEH不僅僅是加殼者的寶刀,也是脫殼者的利箭。 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? By Hume/冷雨飄心
為什么老調重彈:
? ? SEH出現已絕非一日,但很多人可能還不徹底了解Seh的運行機制;有關seh的知識資料不是很多,asm級的詳細資料就
更少!seh不僅可以簡化程序錯誤處理,使你的程序更加健壯,還被廣泛應用于反跟蹤以及加解密中,因此,了解seh非常必要,
但遺憾的是關于seh詳細介紹的中文資料非常少,在實踐的基礎上,把自己學習的一點筆記奉獻給大家,希望對喜歡ASM的朋
友有所幫助.如有錯誤,請高手不吝指正.
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? PART? I? 簡單接觸
一、SEH背景知識
SEH("Structured Exception Handling"),即結構化異常處理.是操作系統提供給程序設計者的強有力的處理程序錯
誤或異常的武器.在VISUAL C++中你或許已經熟悉了_try{} _finally{} 和_try{} _except {} 結構,這些并不是
編譯程序本身所固有的,本質上只不過是對windows內在提供的結構化異常處理的包裝,不用這些高級語言編譯器所提供
的包裝 ,照樣可以利用系統提供的強大seh處理功能,在后面你將可以看到,用系統本身提供seh結構和規則以及ASM語言,
我們將對SEH的機制以及實現有一個徹底的了解.
發生異常時系統的處理順序(by Jeremy Gordon):
? ??1.系統首先判斷異常是否應發送給目標程序的異常處理例程,如果決定應該發送,并且目標程序正在被調試,則系統
? ??掛起程序并向調試器發送EXCEPTION_DEBUG_EVENT消息.呵呵,這不是正好可以用來探測調試器的存在嗎?
? ??2.如果你的程序沒有被調試或者調試器未能處理異常,系統就會繼續查找你是否安裝了線程相關的異常處理例程,如果
? ??你安裝了線程相關的異常處理例程,系統就把異常發送給你的程序seh處理例程,交由其處理.
? ??3.每個線程相關的異常處理例程可以處理或者不處理這個異常,如果他不處理并且安裝了多個線程相關的異常處理例程,
? ? ? ? 可交由鏈起來的其他例程處理.
? ??4.如果這些例程均選擇不處理異常,如果程序處于被調試狀態,操作系統仍會再次掛起程序通知debugger.
? ??5.如果程序未處于被調試狀態或者debugger沒有能夠處理,并且你調用SetUnhandledExceptionFilter安裝了最后異
? ??常處理例程的話,系統轉向對它的調用.
? ??6.如果你沒有安裝最后異常處理例程或者他沒有處理這個異常,系統會調用默認的系統處理程序,通常顯示一個對話框,
? ??你可以選擇關閉或者最后將其附加到調試器上的調試按鈕.如果沒有調試器能被附加于其上或者調試器也處理不了,系統
? ??就調用ExitProcess終結程序.
? ??7.不過在終結之前,系統仍然對發生異常的線程異常處理句柄來一次展開,這是線程異常處理例程最后清理的機會.
如果你看了上面的步驟一頭霧水的話,別著急,化點時間慢慢理解或者進入下一部分實例操作.
二.初步實戰演習:
? 安裝異常處理句柄.
?
? 有兩種類型的異常處理句柄,一種是final型的,這是在你的異常未能得到線程相關處理例程處理操作系統在即將關閉程序之前會
? 回調的例程,這個例程是進程相關的而不是線程相關的,因此無論是哪個線程發生異常未能被處理,都會調用這個例程.
? ? I. 見下面的例子1:
;//================================例子1---final型的異常處理=================
;// ex. 1,by Hume,2001,just copy make your own hd.h and compile&link
;//========================================================================
.386
.model flat, stdcall
option casemap :none? ; case sensitive
include hd.h? ? ? ? ? ;//相關的頭文件,你自己維護一個吧
;//============================
.data
szCap? ??db "By Hume[AfO],2001...",0
szMsgOK db "OK,the exceptoin was handled by final handler!",0
szMsgERR1 db "It would never Get here!",0
buff? ? db 200 dup(0)
.code
_start:
;//========prog begin====================
? ??lea? ??eax,Final_Handler
? ??invoke? ??SetUnhandledExceptionFilter,eax? ;//調用SetUnhandledExceptionFilter來安裝final SEH
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;//原型很簡單SetUnhandledExceptionFilter proto
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;//pTopLevelExceptionFilter:DWORD
? ? ? ? xor? ? ecx,ecx
? ? ? ? mov? ? eax,200? ??
? ? ? ? cdq
? ??div? ??ecx
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;//以下永遠不會被執行
? ? ? ? invoke? ??MessageBox,NULL,addr szMsgERR1,addr szCap,MB_OK+MB_ICONEXCLAMATION
? ? ? ? invoke? ??ExitProcess,NULL
? ? ? ?
;//============================
Final_Handler:
? ??invoke? ??MessageBox,NULL,addr szMsgOK,addr szCap,MB_OK+MB_ICONEXCLAMATION
? ??mov? ??eax,EXCEPTION_EXECUTE_HANDLER? ? ? ? ;//==1 這時不出現非法操作的討厭對話框
? ??;mov? ??eax,EXCEPTION_CONTINUE_SEARCH? ? ;//==0 出現,這時是調用系統默認的異常處理過程,程序被終結了
? ? ;mov? ? eax,EXCEPTION_CONTINUE_EXECUTION? ;//==-1 不斷出現對話框,你將陷入死循環,可別怪我
? ??ret? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;因為我們并沒有修復ecx,所以不斷產生異常,然后不斷調用這個例程
;//=============================Prog Ends==============
end _start
COMMENT $
? 簡單來解釋幾句,windows根據你的異常處理程序的返回值來決定如何進一步處理
? ? ? ? EXCEPTION_EXECUTE_HANDLER? ? ? ? ? ? equ 1? ? 表示我已經處理了異常,可以優雅地結束了
? ? ? ? EXCEPTION_CONTINUE_SEARCH? ? ? ? ? ? equ 0? ? 表示我不處理,其他人來吧,于是windows調用默認的處理程序
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 顯示一個錯誤框,并結束
? ? ? ? EXCEPTION_CONTINUE_EXECUTION? ? ? ? equ -1? 表示錯誤已經被修復,請從異常發生處繼續執行
? ? ? ? 你可以試著讓程序返回0和-1然后編譯程序,就會理解我所有蒼白無力的語言...
$
;//========================================================================
? ? II.另一種是per_Thread Exception Handler->線程相關的異常處理,通常每個線程初始化準備好運行時fs指向一個TIB結構
? ? (THREAD INFORMATION BLOCK),這個結構的第一個元素fs:[0]指向一個_EXCEPTION_REGISTRATION結構
? ? 后面_EXCEPTION_REGISTRATION為了簡化,用ERR來代替這個結構...不要說沒見過啊...
? ? fs:[0]->
? ? _EXCEPTION_REGISTRATION struc
? ? prev dd ?? ? ? ? ? ? ? ? ? ? ? ;前一個_EXCEPTION_REGISTRATION結構
? ? handler dd ?? ? ? ? ? ? ? ? ? ;異常處理例程入口....呵呵,現在明白該怎么作了吧
? ? _EXCEPTION_REGISTRATION ends
? ? 我們可以建立一個ERR結構然后將fs:[0]換成指向他的指針,當然最常用的是堆棧,如果你用靜態內存區也可以,沒有人阻止你
? ? 在asm世界,放心地干吧,除了多S幾次之外,通常不會有更大的損失
? ? 把handler域換成你的程序入口,就可以在發生異常時調用你的代碼了,好馬上實踐一下,見例子2
;//========================================================================
;// ex. 2,by Hume,2001? 線程相關的異常處理
;//========================================================================
.386
.model flat, stdcall
option casemap :none? ; case sensitive
include hd.h? ? ? ? ? ;//相關的頭文件,你自己維護一個吧
;//============================
.data
szCap? ??db "By Hume[AfO],2001...",0
szMsgOK db "It's now in the Per_Thread handler!",0
szMsgERR1 db "It would never Get here!",0
buff? ? db 200 dup(0)
.code
_start:
;//========prog begin====================
? ASSUME FS:NOTHING
? ? ? ? push? ? offset perThread_Handler
? ??push? ? fs:[0]? ? ?
? ? ? ? mov? ? fs:[0],esp? ? ? ? ? ? ? ? ? ? ? ;//建立SEH的基本ERR結構,如果不明白,就仔細研究一下吧
? ? ? ? xor? ? ecx,ecx? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? mov? ? eax,200? ??
? ? ? ? cdq
? ??div? ??ecx
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;//以下永遠不會被執行
? ? ? ? invoke? ??MessageBox,NULL,addr szMsgERR1,addr szCap,MB_OK+MB_ICONINFORMATION
? ? ? ? pop? ? fs:[0]
? ? ? ? add? ? esp,4
? ? ? ? invoke? ??ExitProcess,NULL? ? ? ?
;//============================
perThread_Handler:
? ? ? ? invoke? ??MessageBox,NULL,addr szMsgOK,addr szCap,MB_OK+MB_ICONINFORMATION
? ? ? ? mov? ? eax,1? ? ? ? ? ;//ExceptionContinueSearch,不處理,由其他例程或系統處理
? ? ? ? ;mov? ? eax,0? ? ? ? ? ;//ExceptionContinueExecution,表示已經修復CONTEXT,可從異常發生處繼續執行
? ??ret? ? ? ? ? ? ? ? ? ? ? ? ;//這里如果返回0,你會陷入死循環,不斷跳出對話框....
;//=============================Prog Ends==============
end _start
COMMENT $
? 嘿嘿,這個簡單吧,我們由于沒有足夠的資料,暫時還不能修復ecx的值使之從異常發生處繼續執行,只是簡單顯示一個MSG,然后
? 讓系統處理,自然跳出討厭的對話框了....
? 注意和final返回值的含義不同...
$
;//==================================================================================================
好像到此為止,我們并沒有從異常處理中得到任何好處,除了在異常發生后可以執行一點我們微不足道的代碼,事實上SEH可以修復這些
異常或者干我們想干的事情然后從希望的地方繼續執行,嘿嘿,很爽吧,可惜我們沒有足夠的信息,那里找到我們所需要的信息?
欲知后事如何,且看下回分解...
? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? PARTII? ? 繼續深入
? ? ? ? ? ? ? ? ? ? ? ? ? ? ....(待續,睡個覺先)
標 題:SEH in ASM 研究(二) (6千字)
發信人:hume
時 間:2001-12-29 11:54:47
詳細信息:
三、傳遞給異常處理句柄的參數
? ? ? 要想明白seh處理例程如何得到感興趣的信息,首先要明白SEH的作用機制.事實上,當異常
發生時,系統給了我們一個處理異常的機會,他首先會調用我們自定義的seh處理例程,當然也包括
了相關信息,在調用之前,系統把包含這些信息結構的指針壓入stack,供我們的異常處理例程調用,
傳遞給例程的參數通常是四個,其中只有三個有明確意義,另一個到現在為止還沒有發現有什么作用,
這些參數是:pExcept:DWORD,pErr:DWORD,pContext:DWORD,pDispatch意義如下:
pExcept:? ---? EXCEPTION_RECORD結構的指針
pErr:? ? ---? 前面ERR結構的指針
pContext: --- CONTEXT結構的指針
pDispatch:---沒有發現有啥意義
? ? ERR結構是前面介紹的_EXCEPTION_REGISTRATION結構,往前翻翻,Dispatch省略,下面介紹
EXCEPTION_RECORD和CONTEXT結構的定義:
?
;//================================以下是兩個成員的詳細結構========================================
? ??? ??EXCEPTION_RECORD STRUCT
? ??? ??? ExceptionCode? ? ? ? DWORD? ? ? ?? ? ? ;//異常碼
? ??? ??? ExceptionFlags? ? ? ? DWORD? ? ? ?? ??? ;//異常標志
? ??? ??? pExceptionRecord? ? ? DWORD? ? ? ?? ? ? ;//指向另外一個EXCEPTION_RECORD的指針
? ??? ??? ExceptionAddress? ? ? DWORD? ? ? ?? ? ? ;//異常發生的地址
? ??? ??? NumberParameters? ? ? DWORD? ? ? ?? ? ? ;//下面ExceptionInformation所含有的dword數目
? ??? ??? ExceptionInformation? DWORD EXCEPTION_MAXIMUM_PARAMETERS dup(?)
? ??? ??EXCEPTION_RECORD ENDS? ? ? ? ? ? ? ? ? ? ? ;//EXCEPTION_MAXIMUM_PARAMETERS ==15
;//================================具體解釋========================================
ExceptionCode 異常類型,SDK里面有很多類型,你可以在windows.inc里查找STATUS_來找到更多
的異常類型,下面只給出hex值,具體標識定義請查閱windows.inc,你最可能遇到的幾種類型如下:
? ? ? ? ? ? ? C0000005h----讀寫內存沖突
? ? ? ? ? ? ? C0000094h----非法除0
? ? ? ? ? ? ? C00000FDh----堆棧溢出或者說越界
? ? ? ? ? ? ? 80000001h----由Virtual Alloc建立起來的屬性頁沖突
? ? ? ? ? ? ? C0000025h----不可持續異常,程序無法恢復執行,異常處理例程不應處理這個異常
? ? ? ? ? ? ? C0000026h----在異常處理過程中系統使用的代碼,如果系統從某個例程莫名奇妙的返回,則出現此代碼,
? ? ? ? ? ? ? ? ? ? ? ? ? 如果RtlUnwind時沒有Exception Record參數也同樣會填入這個代碼
? ? ? ? ? ? ? 80000003h----調試時因代碼中int3中斷
? ? ? ? ? ? ? 80000004h----處于被單步調試狀態
? ? ? ? ? ? ? 注:也可以自己定義異常代碼,遵循如下規則:
? ? ? ? ? ? ? _____________________________________________________________________+
? ? ? ? ? ? ? 位:? ? ? 31~30? ? ? ? ? ? 29~28? ? ? ? ? 27~16? ? ? ? ? 15~0
? ? ? ? ? ? ? _____________________________________________________________________+
? ? ? ? ? ? ? 含義:? ? 嚴重程度? ? ? ? ? 29位? ? ? ? ? ? 功能代碼? ? ? ? 異常代碼
? ? ? ? ? ? ? ? ? ? ? ? 0==成功? ? ? ? 0==Mcrosoft? ? MICROSOFT定義? 用戶定義
? ? ? ? ? ? ? ? ? ? ? ? 1==通知? ? ? ? 1==客戶
? ? ? ? ? ? ? ? ? ? ? ? 2==警告? ? ? ? ? 28位
? ? ? ? ? ? ? ? ? ? ? ? 3==錯誤? ? ? ? 被保留必須為0
ExceptionFlags 異常標志
? ? ? ? ? ? ? 0----可修復異常
? ? ? ? ? ? ? 1----不可修復異常
? ? ? ? ? ? ? 2----正在展開,不要試圖修復什么,需要的話,釋放必要的資源
pExceptionRecord 如果程序本身導致異常,指向那個異常結構
ExceptionAddress 發生異常的eip地址
ExceptionInformation 附加消息,在調用RaiseException可指定或者在異常號為C0000005h即內存異常時含義如下
? ? ? ? ? ? ? 第一個dword 0==讀沖突 1==寫沖突
? ? ? ? ? ? ? 第二個dword 讀寫沖突地址
;//================================解釋結束========================================
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? off.
? ??? ??CONTEXT STRUCT? ? ? ? ? ? ? ? ? ? ; _
? ??? ??? ContextFlags? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +0
? ??? ??? iDr0? ? ? ? ? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +4
? ??? ??? iDr1? ? ? ? ? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +8
? ??? ??? iDr2? ? ? ? ? DWORD? ? ? ?? ? ? ;? >調試寄存器? +C
? ??? ??? iDr3? ? ? ? ? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +10
? ??? ??? iDr6? ? ? ? ? DWORD? ? ? ?? ? ? ;? |? ? ? ? ? ? +14
? ??? ??? iDr7? ? ? ? ? DWORD? ? ? ?? ? ? ; _|? ? ? ? ? ? +18
? ??? ??? FloatSave? ? FLOATING_SAVE_AREA <>? ;浮點寄存器區 +1C~~~88h
? ??? ??? regGs? ? ? ? DWORD? ? ? ?? ? ? ;--|? ? ? ? ? ? +8C
? ??? ??? regFs? ? ? ? DWORD? ? ? ?? ? ? ;? |/段寄存器? ? +90?
? ??? ??? regEs? ? ? ? DWORD? ? ? ?? ? ? ;? |/? ? ? ? ? ? +94? ? ? ? ? ?
? ??? ??? regDs? ? ? ? DWORD? ? ? ?? ? ? ;--|? ? ? ? ? ? +98
? ??? ??? regEdi? ? ? ? DWORD? ? ? ?? ? ? ;____________? ? +9C
? ??? ??? regEsi? ? ? ? DWORD? ? ? ?? ? ? ;? ? ? |? 通用? +A0
? ??? ??? regEbx? ? ? ? DWORD? ? ? ?? ? ? ;? ? ? |? 寄? ? +A4
? ??? ??? regEdx? ? ? ? DWORD? ? ? ?? ? ? ;? ? ? |? 存? ? +A8
? ??? ??? regEcx? ? ? ? DWORD? ? ? ?? ? ? ;? ? ? |? 器? ? +AC
? ??? ??? regEax? ? ? ? DWORD? ? ? ?? ? ? ;_______|___組_? +B0? ? ?
? ??? ??? regEbp? ? ? ? DWORD? ? ? ?? ? ? ;++++++++++++++++ +B4
? ??? ??? regEip? ? ? ? DWORD? ? ? ?? ? ? ;? ? |控制? ? ? ? +B8
? ??? ??? regCs? ? ? ? DWORD? ? ? ?? ? ? ;? ? |寄存? ? ? ? +BC
? ??? ??? regFlag? ? ? DWORD? ? ? ?? ? ? ;? ? |器組? ? ? ? +C0
? ??? ??? regEsp? ? ? ? DWORD? ? ? ?? ? ? ;? ? |? ? ? ? ? ? +C4
? ??? ??? regSs? ? ? ? DWORD? ? ? ?? ? ? ;++++++++++++++++ +C8
? ??? ??? ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
? ??? ??CONTEXT ENDS
;//================================以上是兩個成員的詳細結構========================================
? ?
? ? ? ? I、傳遞給final句柄的參數,只有兩個可描述為EXCEPTION_POINTERS結構,定義如下:
? ? ? ? ? ? EXCEPTION_POINTERS STRUCT
? ? ? ? ? ? ? pExceptionRecord? DWORD? ? ? ?? ? ? ? ? ? ?
? ? ? ? ? ? ? ContextRecord? ? DWORD? ? ? ?
? ? ? ? ? ? EXCEPTION_POINTERS ENDS
? ? ? ? ? ? 在call xHandler之前,堆棧結構如下:
? ? ? ? ? ? esp? ? -> *EXCEPTION_RECORD
? ??? ? ? ? esp+4? -> *CONTEXT record? ;//具體結構見下面
? ? ? ? ? ? ? ? 然后執行call _Final_Handler,這樣在程序里要調用什么不輕而易舉了嗎?
? ?
? ? II、 傳遞給per_thread句柄的參數,如下:
? ? 在call xHandler之前,在堆棧中形成如下結構
? ? ? ? ? ? esp? ? -> *EXCEPTION_RECORD
? ??? ? ? ? esp+4? -> *ERR? ? ? ? ? ? ? ? ? ? ;//注意這也就是fs:[0]的指向
? ??? ? ? ? esp? ? -> *CONTEXT record? ? ? ? ? ;//point to registers
? ??? ? ? ? esp? ? -> *Param? ? ? ? ? ? ? ? ? ? ;//呵呵,沒有啥意義
? ? ? ? ? 然后執行 call _Per_Thread_Handler
調用handler的原型是這樣
? ??? ??invoke HANDLER,*EXCEPTION_RECORD,*_EXCEPTION_REGISTRATION,*CONTEXT record,*Param
? ??? ??即編譯代碼如下:
? ??? ??PUSH *Param? ? ? ? ? ? ? ? ? ? ;//通常不重要,沒有什么意義
? ??? ??push *CONTEXT record? ? ? ? ? ? ;//上面的結構
? ??? ??push *ERR? ? ? ? ? ? ? ? ? ? ? ;//the struc above
? ??? ??push *EXCEPTION_RECORD? ? ? ? ? ;//see above
? ??? ??CALL HANDLER
? ??? ??ADD ESP,10h
好現在你明白了應該如何訪問具體有關系統信息的細節了吧,下一部分,讓我們來看看如何應用...(待續)
標 題:一家之言,一種利用SEH技術脫殼的思路。 (699字)
發信人:idtemu
時 間:2001-12-29 17:30:24
詳細信息:
SEH不僅僅是加殼者的寶刀,也是脫殼者的利箭。 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔為你收集整理的SEH in ASM 研究(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 菜鸟也能搞定C++内存泄漏
- 下一篇: linux卸载python3.6,当py