Inline Hook需要注意的問題


指令碎片化

在Inline Hook時一般在需要HOOK的函數頭部寫入jmp指令,然后jmp指令跳轉到Detour函數中。但是因為inline hook函數的頭部代碼形式多樣,寫入jmp指令需要5個字節,但是有可能修改5個字節后會出現指令碎屑。這樣如果執行完Detour函數后接着hook后的代碼執行就會使程序崩潰。

inline hook前

inline hook后,0x12345678為Detour函數地址,填充jmp指令后產生指令碎屑

使用反匯編引擎

在需要inline hook時,使用輕量級的反匯編引擎對函數頭部的代碼進行反匯編,修改完整的一條指令,碎屑用nop填充。
但是又產生了新的問題,如果需要修改的代碼為jmp指令或者 call指令(0xE8)指令如果在Detour函數中調用原函數呢?因為需要解決jmp指令偏移的問題,需要進行重定位很麻煩
例如:下圖中函數頭部為jmp 0x77799933,對應的機器碼偏移為0xFB。如果在Detour函數中執行jmp 0x77799933指令,那么偏移的機器碼就得重新計算。

恢復hook修改的代碼

為了解決指令碎屑所帶來的一系列問題,可以在Detour函數調用原函數前將hook是修改的代碼恢復,然后在調用完之后Detour函數在將hook設置好。
例如:下圖中在MessageBox的Detour函數中在調用原MessageBox前,先將inline Hook修改的代碼恢復,在調用原MessageBox函數后在重新設置inline hook。

HOOK操作的線程安全

inline hook操作需要修改大於機器最大處理長度的字節,這時就有可能在設置hook的過程中代碼被執行從而造成程序crash。

應用層暫停其他無關線程

對於應用層的inline hook,為了防止hook操作外的其他線程執行hook的函數,可以將其他無關線程全部Suspend,hook操作完之后在Resume

內核層提升中斷請求級別(IRQL)

因為內核中線程調度內核代碼所在的IRQL為DpcLevel,而處理器不接受同等級別或低級別的請求。所以可以將inline hook操作代碼的IRQL級別提升到DpcLevel級別。
另外如果存在多個CPU的話還需將其他cpu投遞特定DPC,是其他CPU進入一種“准空轉”狀態。

用Lock xchg/cmpxchg

xchg為數據交換指令,加上lock前綴可以保證此指令是一個原子操作,對應的API函數為InterlockedExchange/64()。

堆棧平衡和環境保護

因為inline hook會使代碼直接jmp到Detour函數中,所以需要保證Detour函數與hook的函數調用約定和參數一致從而保證堆棧平衡。在Detour函數中調用原函數前需要將寄存器環境還原以免影響原函數則正確調用。

避免重入

HOOK A函數
Detour函數調用B函數,B函數中又會調用A函數,(接着A函數又會調用Detour函數),如此會形成一個無限遞歸也就是重入問題。

還原A函數

在Detour函數調用B函數前先還原A函數,在B函數調用后,Detour函數再將設置A函數的inline hook。

加入特定標志

在A函數調用參數中加入特殊標記,可以在Detour函數頭部進行判斷,如果此次A函數調用參數中有我們的特殊標記就證明此次調用是我們的調用繼續執行就好了,如果沒有說明是系統調用的直接調用原函數就好了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM