• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            xiaoguozi's Blog
            Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習(xí)慣原本生活的人不容易改變,就算現(xiàn)狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無(wú)法預(yù)料,人們需要更細(xì)心的觀察別人,要隨時(shí)注意才能保護(hù)別人,因?yàn)樗麄兾幢刂雷约阂裁础ぁぁぁぁ?/span>
            前一段時(shí)間,在看異常處理一章內(nèi)容的時(shí)候,發(fā)現(xiàn)這一部分還真的挺有尿水:)所以上網(wǎng)搜了一下有關(guān)內(nèi)容,呦嗬,還挺豐富的。當(dāng)然有些自己還是看不懂,現(xiàn)在就將這些寶貝拿出來跟大家共享一下。
            首先我們看一下使用異常處理的幾種情況:
            A. 用來處理非致命的錯(cuò)誤
            B. 對(duì)API函數(shù)的參數(shù)合法性的檢驗(yàn)(假設(shè)參數(shù)都是合法的,只有遇到異常的時(shí)候進(jìn)行合法性檢驗(yàn))
            C. 處理致命錯(cuò)誤(退出時(shí)最好的選擇,但是有的時(shí)候可以用異常處理函數(shù)在程序退出前釋放資源,刪除臨時(shí)文件等,甚至可以詳細(xì)記錄產(chǎn)生異常的指令位置和環(huán)境)
            D. 處理“計(jì)劃內(nèi)”的異常(我們可能更關(guān)心這種情況,因?yàn)榭梢宰龊芏嗟氖帜_,哈哈)
            接著我們看看Windows下異常處理的兩種方式:1使用篩選器2 SEH異常處理
            一、 使用篩選器
            因?yàn)檫@里我要重點(diǎn)關(guān)注的是SEH的處理方式,所以還是簡(jiǎn)單的提一下篩選器處理方式。篩選器異常處理是通過異?;卣{(diào)函數(shù)來指定程序處理異常。這種方式的回調(diào)函數(shù)必須是唯一的,設(shè)置新的回調(diào)函數(shù)后以前的將失效。適用于進(jìn)程范圍??匆幌逻@個(gè)函數(shù)的定義
            Invoke SetUnhandledExecpionFilter,offset_Handler
            Mov lpPrevHandler,eax
            (先到這里吧有些難受,明天接著來)
            ######題外話:想起“司令”的一句話,覺得挺有道理:明天不一定美好,但是更美好的明天一定會(huì)到來!祝福所有的朋友。######

            上午有會(huì),什么也沒有做,下午?還有會(huì),我tm暈了,中午不睡覺了,不把事情做不完心里不踏實(shí)。
            回調(diào)函數(shù)的格式:
            _Handlerproc pExecptionInfo
            看看pExecptionInfo這個(gè)指針參數(shù)指向的一個(gè)數(shù)據(jù)結(jié)構(gòu)
            EXCEPTION_POINTERS STRUCT 
                          pExceptionRecord  DWORD      ?              
                          ContextRecord    DWORD      ? 
                        EXCEPTION_POINTERS ENDS
            下面介紹 EXCEPTION_RECORD和CONTEXT結(jié)構(gòu)的定義: 
              
            ;//===================== 以下是兩個(gè)成員的詳細(xì)結(jié)構(gòu)=========================

                    EXCEPTION_RECORD STRUCT 
                      ExceptionCode        DWORD      ?      ;//異常碼 
                      ExceptionFlags        DWORD      ?      ;//異常標(biāo)志 
                      pExceptionRecord      DWORD      ?      ;//指向另外一個(gè)EXCEPTION_RECORD的指針 
                      ExceptionAddress      DWORD      ?      ;//異常發(fā)生的地址 
                      NumberParameters      DWORD      ?      ;//下面ExceptionInformation所含有的dword數(shù)目 
                      ExceptionInformation  DWORD EXCEPTION_MAXIMUM_PARAMETERS dup(?) 
               EXCEPTION_RECORDENDS            ;//EXCEPTION_MAXIMUM_PARAMETERS ==15 

            ;//=============================具體解釋================================

            ExceptionCode 異常類型,SDK里面有很多類型,你可以在windows.inc里查找STATUS_來找到更多的異常類型,下面只給出hex值,具體標(biāo)識(shí)定義請(qǐng)查閱windows.inc,你最可能遇到的幾種類型如下: 

                          C0000005h----讀寫內(nèi)存沖突 
                          C0000094h----非法除0 
                          C00000FDh----堆棧溢出或者說越界 
                          80000001h----由Virtual Alloc建立起來的屬性頁(yè)沖突 
                          C0000025h----不可持續(xù)異常,程序無(wú)法恢復(fù)執(zhí)行,異常處理例程不應(yīng)處理這個(gè)異     常 
                          C0000026h----在異常處理過程中系統(tǒng)使用的代碼,如果系統(tǒng)從某個(gè)例程莫名奇妙的返回,則出現(xiàn)此代碼, 如果RtlUnwind時(shí)沒有Exception Record參數(shù)也同樣會(huì)填入這個(gè)代碼 
                          80000003h----調(diào)試時(shí)因代碼中int3中斷 
                          80000004h----處于被單步調(diào)試狀態(tài) 

                          注:也可以自己定義異常代碼,遵循如下規(guī)則: 
                          ____________________________________________________________________

                          位:      31~30            29~28          27~16          15~0 
                          ____________________________________________________________________
                          含義:    嚴(yán)重程度          29位            功能代碼        異常代碼 
                                    0==成功        0==Mcrosoft    MICROSOFT定義  用戶定義 
                                    1==通知        1==客戶 
                                    2==警告          28位 
                                    3==錯(cuò)誤        被保留必須為0 
            ExceptionFlags 異常標(biāo)志 
                          0----可修復(fù)異常 
                          1----不可修復(fù)異常 
                          2----正在展開,不要試圖修復(fù)什么,需要的話,釋放必要的資源 
            pExceptionRecord 如果程序本身導(dǎo)致異常,指向那個(gè)異常結(jié)構(gòu) 
            ExceptionAddress 發(fā)生異常的eip地址 
            ExceptionInformation 附加消息,在調(diào)用RaiseException可指定或者在異常號(hào)為C0000005h即內(nèi)存異常時(shí)含義如下 
                          第一個(gè)dword 0==讀沖突 1==寫沖突 
                          第二個(gè)dword 讀寫沖突地址 
            ;//================================解釋結(jié)束============================
                                                                      off. 
                    CONTEXT STRUCT                   ; _ 
                      ContextFlags  DWORD      ?     ;  |            +0 
                      iDr0          DWORD      ?       ;  |            +4 
                      iDr1          DWORD      ?      ;  |            +8 
                      iDr2          DWORD      ?      ;  >調(diào)試寄存器  +C 
                      iDr3          DWORD      ?      ;  |            +10 
                      iDr6          DWORD      ?      ;  |            +14 
                      iDr7          DWORD      ?      ; _|            +18 
                      FloatSave    FLOATING_SAVE_AREA <>  ;浮點(diǎn)寄存器區(qū) +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 
            ;//============================以上是兩個(gè)成員的詳細(xì)結(jié)構(gòu)============        
            程序使用篩選器異常處理時(shí)可以通過查看上面結(jié)構(gòu)中的regEip來找到產(chǎn)生異常的地址!調(diào)試的時(shí)候可以改變EIP的值以達(dá)到越過異常程序,轉(zhuǎn)到“安全”的地方。
            最后看一下篩選器異常處理回調(diào)函數(shù)的返回值
            EXECPTION_EXECUTE_HANDLER           1;進(jìn)程被終止,終止前不會(huì)出現(xiàn)提示錯(cuò)誤的對(duì)話框
            EXECPTION_CONTINUE_SEARCH 0;同樣終止程序,顯示錯(cuò)誤對(duì)話框
            EXECPTION_CONTINUE_EXECUTION -1;系統(tǒng)將CONTECT設(shè)置回去,繼續(xù)執(zhí)行程序

            使用篩選器程序是最簡(jiǎn)單的處理異常方法,不足:1 不便于封裝。2 處理是全局性的也就是無(wú)法對(duì)每個(gè)線程或子程序設(shè)置一個(gè)私有的異常處理程序進(jìn)行異常處理。
            進(jìn)入正題:SEH異常處理
            首先解釋一下什么是SEH異常處理:SEH("Structured Exception Handling",即結(jié)構(gòu)化異常處理.是操作系統(tǒng)提供給程序設(shè)計(jì)者的強(qiáng)有力的處理程序錯(cuò)誤或異常的武器。
            下面結(jié)合冷雨飄心的一個(gè)SEH異常處理程序來說明具體的用法:
            ;//====================================================================
            ;// ex. 2,by Hume,2001  線程相關(guān)的異常處理 
            ;//====================================================================
            .386 
            .model flat, stdcall 
            option casemap :none  ; case sensitive 
            include hd.h          ;//相關(guān)的頭文件,你自己維護(hù)一個(gè)吧 
            ;//============================ 
            .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結(jié)構(gòu),如果不明白,就仔細(xì)研究一下吧 
                    xor    ecx,ecx                          
                    mov    eax,200     
                    cdq                ;//雙字?jǐn)U展到四個(gè)字節(jié),因?yàn)槭浅?br />       div    ecx 
                                                              ;//以下永遠(yuǎn)不會(huì)被執(zhí)行 
             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,不處理,由其他例程或系統(tǒng)處理 
                    ;mov    eax,0          ;//ExceptionContinueExecution,表示已經(jīng)修復(fù)CONTEXT,可從異常發(fā)生處繼續(xù)執(zhí)行 
                ret                        ;//這里如果返回0,你會(huì)陷入死循環(huán),不斷跳出對(duì)話框.... 

            ;//=============================Prog Ends============== 
            end _start
            程序本身很簡(jiǎn)單,注釋也很詳細(xì)。我們來看看是如何注冊(cè)回調(diào)函數(shù)的
            push    offset perThread_Handler 
                   push    fs:[0]      
                    mov    fs:[0],esp 
            僅僅三個(gè)語(yǔ)句就解決了~那么為什么要用fs這個(gè)段寄存器呢?這里又涉及一個(gè)重要的內(nèi)容:TIB(Thread Information Block線程信息塊)。我們來看看這個(gè)重要的數(shù)據(jù)結(jié)構(gòu)(引用了《羅聰淺談利用SEB實(shí)現(xiàn)反跟蹤》的部分內(nèi)容)
            TEB(Thread Environment Block) 在 Windows 9x 系 列中被稱為 TIB(Thread Information Block),它記錄了線程的重要信息,而且每一個(gè)線程都會(huì)對(duì)應(yīng)一個(gè) TEB 結(jié) 構(gòu)。 Matt Pietrek 大牛已經(jīng)給我們列出了它的結(jié)構(gòu),我就不多說啦,見下:(摘 自 Matt Pietrek 的 Under The Hood - MSJ 1996) 

            //=========================================================== 
            // file: TIB.H 
            // Author: Matt Pietrek 
            // From: Microsoft Systems Journal "Under the Hood", May 1996 
            //=========================================================== 
            #pragma pack(1) 

            typedef struct _EXCEPTION_REGISTRATION_RECORD 

              struct _EXCEPTION_REGISTRATION_RECORD * pNext; 
              FARPROC                                pfnHandler; 
            } EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD; 

            typedef struct _TIB 

            PEXCEPTION_REGISTRATION_RECORD pvExcept; // 00h Head of exception record list 
            PVOID  pvStackUserTop;        // 04h Top of user stack 
            PVOID  pvStackUserBase;        // 08h Base of user stack 

            union                          // 0Ch (NT/Win95 differences) 

              struct  // Win95 fields 
              { 
                  WORD    pvTDB;          // 0Ch TDB 
                  WORD    pvThunkSS;      // 0Eh SS selector used for thunking to 16 bits 
                  DWORD  unknown1;      // 10h 
              } WIN95; 

              struct  // WinNT fields 
              { 
                  PVOID SubSystemTib;    // 0Ch 
                  ULONG FiberData;        // 10h 
              } WINNT; 
            } TIB_UNION1; 

            PVOID  pvArbitrary;            // 14h Available for application use 
            struct _tib *ptibSelf;          // 18h Linear address of TIB structure 

            union                          // 1Ch (NT/Win95 differences) 

              struct  // Win95 fields 
              { 
                  WORD    TIBFlags;          // 1Ch 
                  WORD    Win16MutexCount;    // 1Eh 
                  DWORD  DebugContext;      // 20h 
                  DWORD  pCurrentPriority;  // 24h 
                  DWORD  pvQueue;            // 28h Message Queue selector 
              } WIN95; 

              struct  // WinNT fields 
              { 
                  DWORD unknown1;            // 1Ch 
                  DWORD processID;            // 20h 
                  DWORD threadID;            // 24h 
                  DWORD unknown2;            // 28h 
              } WINNT; 
            } TIB_UNION2; 

            PVOID*  pvTLSArray;            // 2Ch Thread Local Storage array 

            union                          // 30h (NT/Win95 differences) 

              struct  // Win95 fields 
              { 
                  PVOID*  pProcess;      // 30h Pointer to owning process database 
              } WIN95; 
            } TIB_UNION3; 

            } TIB, *PTIB; 
            #pragma pack()
            讓我們抬頭看看上面的 Matt Pietrek 的代碼,其中有這么一行: 

            PEXCEPTION_REGISTRATION_RECORD pvExcept; // 00h Head of exception record list 

            注 意到 PEXCEPTION_REGISTRATION_RECORD 這個(gè)定義,它表示 pvExcept 這個(gè)變量正 是 exception record list 的入口,這個(gè)入口位于整個(gè)結(jié)構(gòu)的 0 偏移處。同時(shí), 在 M 的 Intel i386 Windows NT/2K/XP 內(nèi)核中,每當(dāng)創(chuàng)建一個(gè)線程,OS 均會(huì)為每個(gè)線程分配 TEB ,而 且 TEB 永遠(yuǎn)放在 fs 段選擇器指定的數(shù)據(jù)段的 0 偏移處。 
            這樣一來,你就明白了 SEH 注冊(cè)的偏移為什么是在 fs:[0] 了吧? 
            事實(shí)上 Windows 系統(tǒng)都是通過這種方法來為應(yīng)用程序提供信息的,比如有這樣的例子: 
            struct _tib *ptibSelf;          // 18h Linear address of TIB structure 
            DWORD threadID;                // 24h 

            Windows 提供了一個(gè) API :GetCurrentThreadID(),它的內(nèi)部工作原理其實(shí)是這樣的:(利用了上面的這兩個(gè)地址) 

            mov eax, fs:[18h]    ;因?yàn)?nbsp;18h 偏移處是 TIB 結(jié)構(gòu)的線性偏移地址 
            mov eax, [eax + 24h] ;因?yàn)?nbsp;24h 偏移處是 threadID 的地址 
            ret                  ;把 eax 中儲(chǔ)存的 threadID 地址返回
            注:為什么要聲明assume fs:nothing?因?yàn)閙asm編譯器默認(rèn)將fs段寄存器定義為error,所以程序在使用fs前必須將它啟動(dòng)!
            接下來看看SEH的回調(diào)函數(shù)
            _Handler proc _lpExecptionRecord, _lpSEH,lp_context,lp_DispatcherContext
             
            _lpExecptionRecord指向一個(gè)EXECPTION_RECORD結(jié)構(gòu)。
            lp_context 指向一個(gè)CONTEXT結(jié)構(gòu)。
            _lpSEH  指向注冊(cè)回調(diào)函數(shù)時(shí)使用的EXXCEPTION_REGISTRATION結(jié)構(gòu)的地址。
            返回值有四種取值:
            ExecptionContinueExecution ( 0 :系統(tǒng)將線程環(huán)境設(shè)置為_lpContext指向的CONTEXT結(jié)構(gòu)并繼續(xù)執(zhí)行。
            ExceptionContinueSearch(1):回調(diào)函數(shù)拒絕處理這個(gè)異常,系統(tǒng)通過EXECPTION_REGISTRATION結(jié)構(gòu)的prev字段得到前一個(gè)回調(diào)函數(shù)的地址并調(diào)用它。
            ExecptionNestedExecption (2):發(fā)生異常嵌套。
            ExecptionCollidedUnwind  (3):異常展開操作。這一個(gè)部分不做多講,有興趣的可以看看羅云彬的書,其實(shí)是很重要的一部分。
            如果一個(gè)程序既有篩選器異常處理又有SEH異常處理,而且系統(tǒng)還有默認(rèn)的異常處理機(jī)制,那么他們被調(diào)用的先后次序是怎么樣的呢?
            發(fā)生異常時(shí)系統(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消息.呵呵,這不是正好可以用來探測(cè)調(diào)試器的存在嗎? 
                2.如果你的程序沒有被調(diào)試或者調(diào)試器未能處理異常,系統(tǒng)就會(huì)繼續(xù)查找你是否安裝了線程相關(guān)的異常處理例程,如果你安裝了線程相關(guān)的異常處理例程,系統(tǒng)就把異常發(fā)送給你的程序seh處理例程,交由其處理.
                3.每個(gè)線程相關(guān)的異常處理例程可以處理或者不處理這個(gè)異常,如果他不處理并且安裝了多個(gè)線程相關(guān)的異常處理例程,可交由鏈起來的其他例程處理. 
                4.如果這些例程均選擇不處理異常,如果程序處于被調(diào)試狀態(tài),操作系統(tǒng)仍會(huì)再次掛起程序通知debugger. 
                5.如果程序未處于被調(diào)試狀態(tài)或者debugger沒有能夠處理,并且你調(diào)用SetUnhandledExceptionFilter安裝了最后異 常處理例程的話,系統(tǒng)轉(zhuǎn)向?qū)λ恼{(diào)用. 
            6.如果你沒有安裝最后異常處理例程或者他沒有處理這個(gè)異常,系統(tǒng)會(huì)調(diào)用默認(rèn)的系統(tǒng)處理程序,通常顯示一個(gè)對(duì)話框, 你可以選擇關(guān)閉或者最后將其附加到調(diào)試器上的調(diào)試按鈕.如果沒有調(diào)試器能被附加于其上或者調(diào)試器也處理不了,系統(tǒng)就調(diào)用ExitProcess終結(jié)程序. 
                7.不過在終結(jié)之前,系統(tǒng)仍然對(duì)發(fā)生異常的線程異常處理句柄來一次展開,這是線程異常處理例程最后清理的機(jī)會(huì).

            說了這么多你也許會(huì)問SEH異常處理到底有什么用處呢?呵呵,且聽小生慢慢道來~~~
            第一道菜:病毒程序巧用SEH
            這里簡(jiǎn)單的說一下如何利用SEH異常處理程序來躲避下毒軟件的反病毒引擎。一個(gè)反病毒引擎在一個(gè)程序運(yùn)行的時(shí)候會(huì)模擬程序的代碼,當(dāng)發(fā)現(xiàn)程序代碼的疑點(diǎn)比較多的時(shí)候會(huì)報(bào)告成病毒。看看下面這段程序:
            start:call Set_SEH;這句其實(shí)就是 push offset CONTINUE
            ;      JMP Set_SEH
            CONTINUE:mov esp, [esp+8]; [ESP+8]存儲(chǔ)的是舊的堆棧地址。
            push offset Start_Virus ;----_ 把Start_Virus 的地址壓棧,當(dāng)作返回地址
            ret;----跳到Start_Virus去,是不是很magic? 

            Set_SEH:sub edx, edx            ;Edx =0 
            Assume fs:nothing 
            push dword ptr fs:[edx];把指去 _EXCEPTIONAL_REGISTRATION_RECORD 結(jié)構(gòu)的指針入棧
            mov fs:[edx], esp;安裝一個(gè)seh
            mov [edx],edx;引起一個(gè)內(nèi)存讀寫沖突,發(fā)生異常因?yàn)閑dx=0 
            ;如果反病毒引擎不處理異常,不進(jìn)入seh 處理程序(即 CONTINUE: ,繼續(xù)模 
            ;擬下個(gè)指令,也就是jmp start,那么就進(jìn)入一個(gè)死循環(huán),可能會(huì)引起死機(jī)。               
            jmp start       
            Start_Virus:    .....
            是不是很簡(jiǎn)單呢?就是讓反病毒引擎不處理這個(gè)人為的異常時(shí)進(jìn)入死循環(huán)~??!
            第二道菜:TEB反跟蹤初探
            如果你的記性夠好的話一定記得上面介紹過的TEB(TIB)線程信息塊結(jié)構(gòu)中有這么一句:
            PVOID*  pProcess;      // 30h Pointer to owning process database 
            這 個(gè)偏移地址處的內(nèi)容非常有用,它指向本線程的擁有者的 PDB(Process Database) 的線性地址。當(dāng)你用動(dòng)態(tài)調(diào)試器,例 如 OllyDbg 的時(shí)候,調(diào)試器是把調(diào)試的對(duì)象作為一個(gè)子線程進(jìn)行跟蹤的,在這種情況下,被調(diào)試的對(duì)象的“擁有者”就是調(diào)試器本身,也就是說,它 的 TEB 的 30h 處的偏移指向的內(nèi)容肯定不為 0 ,這樣,我們就可以利用這一點(diǎn),判斷 30h 偏移指向的內(nèi)容,來判斷是否有調(diào)試器跟蹤。 
            最后給出一個(gè) Anti-Debug 的例子程序,用 MASM 編譯完成后,請(qǐng)用 OllyDbg 來加載調(diào)試一下,看看與正常的運(yùn)行結(jié)果有什么不同。 
            ;********************************************************* 
            ;程序名稱:演示利用 TEB 結(jié)構(gòu)進(jìn)行 Anti-Debug 
            ;          請(qǐng)用 OllyDbg 進(jìn)行調(diào)試 
            ;適用OS:Windows NT/2K/XP 
            ;作者:羅聰 
            ;日期:2003-2-9 
            ;出處:::URL::http://www.LuoCong.com(老羅的繽紛天地)  
            ;注意事項(xiàng):如欲轉(zhuǎn)載,請(qǐng)保持本程序的完整,并注明: 
            ;轉(zhuǎn)載自“老羅的繽紛天地”(::URL::http://www.LuoCong.com)  
            ;********************************************************* 

            .386 
            .model flat, stdcall 
            option casemap:none 

            include /masm32/include/windows.inc 
            include /masm32/include/kernel32.inc 
            include /masm32/include/user32.inc 
            includelib /masm32/lib/kernel32.lib 
            includelib /masm32/lib/user32.lib 

            .data 
            szCaption  db  "Anti-Debug Demo by LC, 2003-2-9", 0 
            szDebugged  db  "Hah, let me guess... U r dEBUGGINg me! ", 0 
            szFine      db  "Good boy, no dEBUGGEr detected!", 0 

            .code 
            main: 
              assume  fs:nothing
              mov    eax, fs:[30h]              ;指向 PDB(Process Database)
              movzx  eax, byte ptr [eax + 2h];無(wú)符號(hào)數(shù)帶零擴(kuò)展
              or      al, al
              jz      _Fine
            _Debugged:
              push    MB_OK or MB_ICONHAND
              push    offset szCaption
              push    offset szDebugged
              jmp    _Output
            _Fine:
              push    MB_OK or MB_ICONINformATION
              push    offset szCaption
              push    offset szFine
            _Output: 
              push    NULL
              call    MessageBoxA
              invoke  ExitProcess, 0
             end main
            第三道菜:利用SEH執(zhí)行shellcode
            假設(shè)異常處理例程入口00401053,程序剛開始執(zhí)行時(shí)esp是0012ffc4,以前的fs:[0]是0012ffe0
            建立了TIB結(jié)構(gòu)的第一個(gè)成員后堆棧的情況如下:

              內(nèi)存低地址
              
            | E0 |12ffbc(esp)
            | FF |
            | 12 |  --ERR結(jié)構(gòu)的第一個(gè)成員
            |_00_|
            | 53 |12ffc0
            | 10 |
            | 40 |  --ERR結(jié)構(gòu)的第二個(gè)成員
            | 00 |

              內(nèi)存高地址

              好了然后程序CALL一個(gè)函數(shù),函數(shù)里面有一個(gè)局部變量并且在往其分配的空間中寫入的數(shù)據(jù)時(shí)產(chǎn)生溢出.這時(shí)堆棧如下

            ____
            |    |12f000 局部變量分配的空間,并且向12ffc0方向溢出了.
            |    |
            ....
            ....
            |_EBP|12ffb4 函數(shù)中保存老的EBP
            | xx |
            | xx |
            | xx |
            |_EIP|12ffb8 call函數(shù)時(shí)EIP進(jìn)棧
            | xx |
            | xx |
            |_xx_|
            | E0 |12ffbc(esp)   {當(dāng)SEH起作用的時(shí)候EBX剛好指向這個(gè)地址(也可說總是指向當(dāng)前ERR結(jié)構(gòu))}
            | FF |
            | 12 |  --ERR結(jié)構(gòu)的第一個(gè)成員
            |_00_|
            | 53 |12ffc0
            | 10 |
            | 40 |  --ERR結(jié)構(gòu)的第二個(gè)成員
            |_00_|
            |    |12ffc4
               繼 續(xù)看,假設(shè)溢出代碼一直到了12ffc4,然后call的函數(shù)該返回了,因?yàn)楸4娴腅IP被溢出代碼代替所以程序出錯(cuò)(不會(huì)不出錯(cuò)吧?),這樣ESH開始 起作用了(注:在這期間系統(tǒng)要執(zhí)行一些操作,所以EBX才會(huì)指向當(dāng)前ERR).這樣一來程序就會(huì)跳到12ffc0里的地址去執(zhí)行!而12ffc0里的東東 早已不是原來的00401053了.這樣我們不就改變了程序的流向了么.12ffc0中該寫入什么內(nèi)容呢?應(yīng)是內(nèi)存中JMP EBX的代碼的地址.這樣跳 了3下后最終就會(huì)跳到12ffbc去執(zhí)行.這個(gè)四字節(jié)可是寶貴的啊現(xiàn)在假設(shè)JMP EBX這個(gè)指令在內(nèi)存中的地址是0x77e33f4d
            那下具體看一下現(xiàn)在堆棧的情況:

            | EB |12ffbc(esp)   {當(dāng)ESH起作用的時(shí)候EBX剛好指向這個(gè)地址(也可說總是指向當(dāng)前ERR結(jié)構(gòu))}
            | 06 |
            | 90 |  --ERR結(jié)構(gòu)的第一個(gè)成員,執(zhí)行JMP EBX后就到這兒來執(zhí)行了(EB 06是短跳轉(zhuǎn)JMP 12FFC4的機(jī)器碼)
            |_90_|  后面的90是nop空指令的機(jī)器碼.
            | 4D |12ffc0
            | 3F |
            | E3 |  --ERR結(jié)構(gòu)的第二個(gè)成員,出錯(cuò)處理函數(shù)的入口地址(現(xiàn)在成了JMP EBX的地址)
            |_77_|
            |    |12ffc4
            ....

              好現(xiàn)在來看看12ffc4里面有些什么代碼.(簡(jiǎn)單的說這段代碼的作用是計(jì)算真正的shellcode的起始地址,然后跳過去執(zhí)行.

            低地址

            |    |12f000(shellcode開始地址)
            ....
            ....
            | 81 |12ffc4
            | C3 |  add ebx,FFFFF03Ch(ebx=12ffc4,指令長(zhǎng)度6,作用計(jì)算計(jì)算shellcode地址)
            | 3C |
            | F0 |
            | FF |
            | FF |
            | FF |12ffca jmp ebx
            | D3 |  

            高地址

             
            測(cè)試程序

            -------------------------SEH.ASM------------------
            .386
            .model flat,stdcall
            option casemap:none

            include        ../include/user32.inc
            includelib    ../lib/user32.lib
            include        ../include/kernel32.inc
            includelib    ../lib/kernel32.lib



            .data
            hello        db '利用一個(gè)讀INI文件的API來演示W(wǎng)IN2000本地溢出',0
            lpFileName    db './seh.ini',0            
            lpAppName    db 'iam',0
            lpKeyName    db 'czy',0            
            lpDefault    db 'ddd',0
            szCap     db "SEH TEST",0
            szMsgOK db "OK,the exceptoin was handled by final handler!",0
            szMsgERR1 db "It would never Get here!",0

            .code

            testov    proc
                local   lpReturnedString[2224] : byte    ;返回的字串搞成本地變量這樣就和C語(yǔ)言一樣了,它是在棧中    
                invoke    GetPrivateProfileString,offset    lpAppName,offset,lpKeyName,offset lpDefault,ADDR lpReturnedString,2249,offset lpFileName    
                invoke    MessageBox,0,addr lpReturnedString,addr lpReturnedString,1
                ret 
            testov    endp
                
            start:
                ASSUME fs:NOTHING
                invoke  MessageBox,0,addr szMsgERR1,addr szCap,30h+1000h ;下斷點(diǎn)    
                push    offset Final_Handler    ;壓入正常的出錯(cuò)處理程序入口地址
                push    FS:[0]                  ;把前一個(gè)TIB的地址壓入
                mov    fs:[0],esp
                call    testov    
                pop     fs:[0]                     ;還原FS:[0]     
                
            Final_Handler:   ;由于溢出了下面的代碼不會(huì)被執(zhí)行.
                   invoke       MessageBox,0,addr szMsgOK,addr szCap,30h
                   invoke       ExitProcess,0
                   mov       eax,1
                   ret
            end start

            -----------------end-------------

            1如何更好的在內(nèi)存中找JMP EBX的代碼:
                 在softice中執(zhí)行S 10:0 L FFFFFFFF FF D3就可以了,但實(shí)際上這樣找到的
            地址可能不能執(zhí)行代碼.所以用下面的方法:
               map32 kernel32(在當(dāng)前進(jìn)程中查找映射的kernel32 DLL的信息)   
            一般有如下顯示:
              Owner        Obj Name    Obj#    Address        Size     TYPE
            kernel32    .text        0001    001b:77b61000    0005d1ae code RO
            ......
              然后
            S 77b61000 L 5d1ae FF D3
            如果顯示如下說明找到了:
              Pattern Found at 0023:77e61674 ....

            2)關(guān)于緩沖區(qū)的大小的問題:
              利用SEH的辦法就起碼要設(shè)成1000個(gè)字節(jié)多,你的shellcode才不會(huì)被不知哪來的數(shù)據(jù)覆蓋!
            這道菜czy做的不好吃:(我感覺理解起來有些困難~!因?yàn)殛P(guān)于緩沖區(qū)溢出自己接觸的太少,不過好東西要保留的,以后回過頭看!
            第四道菜:用 SEH 技術(shù)實(shí)現(xiàn) API Hook
            這一部分不想展開了,給大家一個(gè)鏈接吧。

            ::URL::http://www.luocong.com/articles/show_article.asp?Article_ID=25

            最后作為結(jié)束語(yǔ)說說的缺點(diǎn)吧:)一個(gè)人只有正視自己的缺點(diǎn)才能不斷地進(jìn)步!呵呵
            在 SEH異常處理鏈中最后一個(gè)被裝載的SEH異常處理程序總是被第一個(gè)調(diào)用,想想如果自己花了一個(gè)星期才寫出來一個(gè)異常處理程序,能夠完美處理所有異常,并 希望異常全部由你來處理,但很不幸,比如你調(diào)用了一個(gè)外部模塊,而這個(gè)模塊自己安裝了一個(gè)ugly的seh處理例程,他的動(dòng)作是只要有異常發(fā)生就簡(jiǎn)單地終 止程序,哈哈,那就死悄悄了。又比如你想在你的加殼程序里面加密目標(biāo)程序代碼段,然后發(fā)生無(wú)效指令異常的時(shí)候用你自己安裝的處理句柄來解密代碼段繼續(xù)執(zhí) 行,聽起來這的確是一個(gè)好主意,但遺憾的是大多數(shù)C/C++代碼都用_try{}_except{}塊來保證其正確運(yùn)行,而這些異常處理例程是在你殼注冊(cè) 的例程之后安裝的,因而也就在鏈的前面,無(wú)效指令一執(zhí)行,首先是C/C++編譯器本身提供的處理例程或者程序其他的異常處理例程來處理,可能簡(jiǎn)單結(jié)束程序 或者....
            好累!~~~~~~
            寫了兩天,錯(cuò)了,應(yīng)該是剪接+消化了兩天,有很多的程序和文字是從hume,老羅,還有czy那里“剽竊”的:)希望高手們不要生氣~~天下書籍一大抄。你們的必將是我的,當(dāng)然我的也會(huì)共享給你們的。呵呵,現(xiàn)在還不行,級(jí)別不夠啊。
            轉(zhuǎn)自:
            http://blog.csdn.net/toberooter/article/details/308365
            posted on 2013-03-21 15:43 小果子 閱讀(7332) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 學(xué)習(xí)筆記Windows
            久久综合九色综合网站| 久久国产欧美日韩精品免费| 国产麻豆精品久久一二三| 东京热TOKYO综合久久精品| 久久精品国产一区二区三区日韩| 婷婷综合久久中文字幕| 久久激情五月丁香伊人| 亚洲人成网亚洲欧洲无码久久| 久久精品中文騷妇女内射| 久久精品www| 中文精品99久久国产| 国产精品久久久久久福利69堂| Xx性欧美肥妇精品久久久久久| 色8激情欧美成人久久综合电| 人妻少妇久久中文字幕| 91久久成人免费| 久久精品无码一区二区WWW| 久久九九青青国产精品| 合区精品久久久中文字幕一区 | 精品熟女少妇AV免费久久| 91精品国产综合久久精品| 亚洲成av人片不卡无码久久| 91视频国产91久久久| 香蕉99久久国产综合精品宅男自 | 久久99精品久久久久久噜噜| 无码八A片人妻少妇久久| 久久91精品久久91综合| 亚洲日韩欧美一区久久久久我 | 97久久国产综合精品女不卡 | 久久精品www| 国产成年无码久久久免费| 久久久久国色AV免费观看| 国产成人久久精品一区二区三区| 一本综合久久国产二区| 99久久无码一区人妻| 国产精品99久久99久久久| 久久亚洲精品国产亚洲老地址| 亚洲国产成人久久综合一| 国产欧美一区二区久久| 久久久噜噜噜www成人网| 亚洲精品美女久久777777|