SEH in ASM 研究(一) (7千字)

看雪資料發表於2001-12-29

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    繼續深入
                            ....(待續,睡個覺先)

相關文章