• <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>

            旅途

            如果想飛得高,就該把地平線忘掉

            淺談API HOOK技術

            HOOK API是一個永恒的話題,如果沒有HOOK,許多技術將很難實現,也許根本不能實現。這里所說的API,是廣義上的API,它包括DOS下的中斷, WINDOWS里的API、中斷服務、IFS和NDIS過濾等。比如大家熟悉的即時翻譯軟件,就是靠HOOK TextOut()或ExtTextOut()這兩個函數實現的,在操作系統用這兩個函數輸出文本之前,就把相應的英文替換成中文而達到即時翻譯;IFS 和NDIS過濾也是如此,在讀寫磁盤和收發數據之前,系統會調用第三方提供的回調函數來判斷操作是否可以放行,它與普通HOOK不同,它是操作系統允許 的,由操作系統提供接口來安裝回調函數。

            甚至如果沒有HOOK,就沒有病毒,因為不管是DOS下的病毒或WINDOWS里的病毒,都是靠HOOK系統服務來實現自己的功能的:DOS下的病毒靠 HOOK INT 21來感染文件(文件型病毒),靠HOOK INT 13來感染引導扇區(引導型病毒);WINDOWS下的病毒靠HOOK系統API(包括RING0層的和RING3層的),或者安裝IFS(CIH病毒所 用的方法)來感染文件。因此可以說“沒有HOOK,就沒有今天多姿多彩的軟件世界”。

            由于涉及到專利和知識產權,或者是商業機密,微軟一直不提倡大家HOOK它的系統API,提供IFS和NDIS等其他過濾接口,也是為了適應殺毒軟件和防火墻的需要才開放的。所以在大多數時候,HOOK API要靠自己的力量來完成。

            HOOK API有一個原則,這個原則就是:被HOOK的API的原有功能不能受到任何影響。就象醫生救人,如果把病人身體里的病毒殺死了,病人也死了,那么這個 “救人”就沒有任何意義了。如果你HOOK API之后,你的目的達到了,但API的原有功能失效了,這樣不是HOOK,而是REPLACE,操作系統的正常功能就會受到影響,甚至會崩潰。

            HOOK API的技術,說起來也不復雜,就是改變程序流程的技術。在CPU的指令里,有幾條指令可以改變程序的流程:JMP,CALL,INT,RET, RETF,IRET等指令。理論上只要改變API入口和出口的任何機器碼,都可以HOOK,但是實際實現起來要復雜很多,因為要處理好以下問題:

            1,CPU指令長度問題,在32位系統里,一條JMP/CALL指令的長度是5個字節,因此你只有替換API里超過5個字節長度的機器碼(或者替換幾條指 令長度加起來是5字節的指令),否則會影響被更改的小于5個字節的機器碼后面的數條指令,甚至程序流程會被打亂,產生不可預料的后果;
            2,參數問題,為了訪問原API的參數,你要通過EBP或ESP來引用參數,因此你要非常清楚你的HOOK代碼里此時的EBP/ESP的值是多少;
            3,時機的問題,有些HOOK必須在API的開頭,有些必須在API的尾部,比如HOOK CreateFilaA(),如果你在API尾部HOOK API,那么此時你就不能寫文件,甚至不能訪問文件;HOOK RECV(),如果你在API頭HOOK,此時還沒有收到數據,你就去查看RECV()的接收緩沖區,里面當然沒有你想要的數據,必須等RECV()正常 執行后,在RECV()的尾部HOOK,此時去查看RECV()的緩沖區,里面才有想要的數據;
            4,上下文的問題,有些HOOK代碼不能執行某些操作,否則會破壞原API的上下文,原API就失效了;
            5,同步問題,在HOOK代碼里盡量不使用全局變量,而使用局部變量,這樣也是模塊化程序的需要;
            6,最后要注意的是,被替換的CPU指令的原有功能一定要在HOOK代碼的某個地方模擬實現。

            下面以ws2_32.dll里的send()為例子來說明如何HOOK這個函數:

            Exported fn(): send - Ord:0013h
            地址      機器碼              匯編代碼
            :71A21AF4 55                push ebp //將被HOOK的機器碼(第1種方法)
            :71A21AF5 8BEC              mov ebp, esp //將被HOOK的機器碼(第2種方法)
            :71A21AF7 83EC10              sub esp, 00000010
            :71A21AFA 56                push esi
            :71A21AFB 57                push edi
            :71A21AFC 33FF              xor edi, edi
            :71A21AFE 813D1C20A371931CA271    cmp dword ptr [71A3201C], 71A21C93 //將被HOOK的機器碼(第4種方法)
            :71A21B08 0F84853D0000          je 71A25893
            :71A21B0E 8D45F8              lea eax, dword ptr [ebp-08]
            :71A21B11 50                push eax
            :71A21B12 E869F7FFFF          call 71A21280
            :71A21B17 3BC7              cmp eax, edi
            :71A21B19 8945FC              mov dword ptr [ebp-04], eax
            :71A21B1C 0F85C4940000          jne 71A2AFE6
            :71A21B22 FF7508              push [ebp+08]
            :71A21B25 E826F7FFFF          call 71A21250
            :71A21B2A 8BF0              mov esi, eax
            :71A21B2C 3BF7              cmp esi, edi
            :71A21B2E 0F84AB940000          je 71A2AFDF
            :71A21B34 8B4510              mov eax, dword ptr [ebp+10]
            :71A21B37 53                push ebx
            :71A21B38 8D4DFC              lea ecx, dword ptr [ebp-04]
            :71A21B3B 51                push ecx
            :71A21B3C FF75F8              push [ebp-08]
            :71A21B3F 8D4D08              lea ecx, dword ptr [ebp+08]
            :71A21B42 57                push edi
            :71A21B43 57                push edi
            :71A21B44 FF7514              push [ebp+14]
            :71A21B47 8945F0              mov dword ptr [ebp-10], eax
            :71A21B4A 8B450C              mov eax, dword ptr [ebp+0C]
            :71A21B4D 51                push ecx
            :71A21B4E 6A01              push 00000001
            :71A21B50 8D4DF0              lea ecx, dword ptr [ebp-10]
            :71A21B53 51                push ecx
            :71A21B54 FF7508              push [ebp+08]
            :71A21B57 8945F4              mov dword ptr [ebp-0C], eax
            :71A21B5A 8B460C              mov eax, dword ptr [esi+0C]
            :71A21B5D FF5064              call [eax+64]
            :71A21B60 8BCE              mov ecx, esi
            :71A21B62 8BD8              mov ebx, eax
            :71A21B64 E8C7F6FFFF          call 71A21230 //將被HOOK的機器碼(第3種方法)
            :71A21B69 3BDF              cmp ebx, edi
            :71A21B6B 5B                pop ebx
            :71A21B6C 0F855F940000          jne 71A2AFD1
            :71A21B72 8B4508              mov eax, dword ptr [ebp+08]
            :71A21B75 5F                pop edi
            :71A21B76 5E                pop esi
            :71A21B77 C9                leave
            :71A21B78 C21000              ret 0010

            下面用4種方法來HOOK這個API:

            1,把API入口的第一條指令是PUSH EBP指令(機器碼0x55)替換成INT 3(機器碼0xcc),然后用WINDOWS提供的調試函數來執行自己的代碼,這中方法被SOFT ICE等DEBUGER廣泛采用,它就是通過BPX在相應的地方設一條INT 3指令來下斷點的。但是不提倡用這種方法,因為它會與WINDOWS或調試工具產生沖突,而匯編代碼基本都要調試;

            2,把第二條mov ebp,esp指令(機器碼8BEC,2字節)替換為INT F0指令(機器碼CDF0),然后在IDT里設置一個中斷門,指向我們的代碼。我這里給出一個HOOK代碼:

            lea ebp,[esp+12] //模擬原指令mov ebp,esp的功能
            pushfd          //保存現場
            pushad          //保存現場

            //在這里做你想做的事情

            popad          //恢復現場
            popfd          //恢復現場
            iretd          //返回原指令的下一條指令繼續執行原函數(71A21AF7地址處)

            這種方法很好,但缺點是要在IDT設置一個中斷門,也就是要進RING0。

            3,更改CALL指令的相對地址(CALL分別在71A21B12、71A21B25、71A21B64,但前面2條CALL之前有一個條件跳轉指令,有 可能不被執行到,因此我們要HOOK 71A21B64處的CALL指令)。為什么要找CALL指令下手?因為它們都是5字節的指令,而且都是CALL指令,只要保持操作碼0xE8不變,改變 后面的相對地址就可以轉到我們的HOOK代碼去執行了,在我們的HOOK代碼后面再轉到目標地址去執行。

            假設我們的HOOK代碼在71A20400處,那么我們把71A21B64處的CALL指令改為CALL 71A20400(原指令是這樣的:CALL 71A21230)
            而71A20400處的HOOK代碼是這樣的:

            71A20400:
            pushad

            //在這里做你想做的事情

            popad
            jmp 71A21230    //跳轉到原CALL指令的目標地址,原指令是這樣的:call 71A21230

            這種方法隱蔽性很好,但是比較難找這條5字節的CALL指令,計算相對地址也復雜。

            4,替換71A21AFE地址上的cmp dword ptr [71A3201C], 71A21C93指令(機器碼:813D1C20A371931CA271,10字節)成為
            call 71A20400
            nop
            nop
            nop
            nop
            nop
            (機器碼:E8 XX XX XX XX 90 90 90 90 90,10字節)

            在71A20400的HOOK代碼是:
            pushad
            mov edx,71A3201Ch            //模擬原指令cmp dword ptr [71A3201C], 71A21C93
            cmp dword ptr [edx],71A21C93h    //模擬原指令cmp dword ptr [71A3201C], 71A21C93
            pushfd

            //在這里做你想做的事

            popfd
            popad
            ret
            這種方法隱蔽性最好,但不是每個API都有這樣的指令,要具體情況具體操作。

            以上幾種方法是常用的方法,值得一提的是很多人都是改API開頭的5個字節,但是現在很多殺毒軟件用這樣的方法檢查API是否被HOOK,或其他病毒木馬 在你之后又改了前5個字節,這樣就會互相覆蓋,最后一個HOOK API的操作才是有效的,所以提倡用第3和第4種方法。

            posted on 2007-07-29 10:32 旅途 閱讀(1399) 評論(0)  編輯 收藏 引用 所屬分類: 深入windows

            99精品久久精品| 久久av无码专区亚洲av桃花岛| 久久国产精品久久精品国产| 久久精品国产亚洲AV麻豆网站| 久久婷婷久久一区二区三区| 国产精品内射久久久久欢欢| 久久伊人五月天论坛| 久久婷婷人人澡人人爽人人爱| 人妻久久久一区二区三区| 91精品国产色综久久 | 欧美牲交A欧牲交aⅴ久久| 久久精品中文闷骚内射| 久久久久久无码国产精品中文字幕| 色狠狠久久AV五月综合| 久久九九久精品国产| 久久AV高清无码| 综合久久给合久久狠狠狠97色| 欧美黑人激情性久久| 久久亚洲色一区二区三区| 嫩草影院久久99| 亚洲精品乱码久久久久久蜜桃图片| 久久久久久a亚洲欧洲aⅴ| 色综合久久中文字幕无码| 人妻少妇精品久久| 观看 国产综合久久久久鬼色 欧美 亚洲 一区二区 | 亚洲国产天堂久久久久久| 99久久精品费精品国产一区二区| 亚洲精品无码久久不卡| 国内精品久久久久影院网站| 久久精品国产亚洲欧美| 久久99国产综合精品女同| 伊人久久无码精品中文字幕| 久久播电影网| 亚洲国产成人久久精品动漫| 99久久人妻无码精品系列| 久久久久久久波多野结衣高潮 | 久久久久久久久久免免费精品| 老司机国内精品久久久久| 九九久久99综合一区二区| 久久久综合九色合综国产| 精品久久久久久久久中文字幕|