史萊姆論壇

返回   史萊姆論壇 > 教學文件資料庫 > 作業系統操作技術文件
忘記密碼?
論壇說明 標記討論區已讀

歡迎您來到『史萊姆論壇』 ^___^

您目前正以訪客的身份瀏覽本論壇,訪客所擁有的權限將受到限制,您可以瀏覽本論壇大部份的版區與文章,但您將無法參與任何討論或是使用私人訊息與其他會員交流。若您希望擁有完整的使用權限,請註冊成為我們的一份子,註冊的程序十分簡單、快速,而且最重要的是--註冊是完全免費的!

請點擊這裡:『註冊成為我們的一份子!』

Google 提供的廣告


 
 
主題工具 顯示模式
舊 2006-02-10, 09:04 AM   #1
psac
榮譽會員
 
psac 的頭像
榮譽勳章
UID - 3662
在線等級: 級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時
註冊日期: 2002-12-07
住址: 木柵市立動物園
文章: 17381
現金: 5253 金幣
資產: 33853 金幣
預設 詳談HOOK API的技術

詳談HOOK API的技術

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指令的長度是灌水限制節,因此你只有取代API裡超過灌水限制節長度的機器碼(或者取代幾條指令長度加起來是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開頭的灌水限制節,但是現在很多殺毒軟體用這樣的方法檢查API是否被HOOK,或其他病毒木馬在你之後又改了前灌水限制節,這樣就會互相覆蓋,最後一個HOOK API的操作才是有效的,所以提倡用第3和第4種方法。
__________________
http://bbsimg.qianlong.com/upload/01/08/29/68/1082968_1136014649812.gif
psac 目前離線  
送花文章: 3, 收花文章: 1631 篇, 收花: 3205 次
向 psac 送花的會員:
rabbit64031 (2013-01-15)
感謝您發表一篇好文章
 


主題工具
顯示模式

發表規則
不可以發文
不可以回覆主題
不可以上傳附加檔案
不可以編輯您的文章

論壇啟用 BB 語法
論壇啟用 表情符號
論壇啟用 [IMG] 語法
論壇禁用 HTML 語法
Trackbacks are 禁用
Pingbacks are 禁用
Refbacks are 禁用


所有時間均為台北時間。現在的時間是 05:27 PM


Powered by vBulletin® 版本 3.6.8
版權所有 ©2000 - 2024, Jelsoft Enterprises Ltd.


SEO by vBSEO 3.6.1