64位系統的Detours

來源:互聯網
上載者:User

 我假設讀者已經非常熟悉detours,閱讀此文只是為了增強對detours的理解以及為了實現x64 hook。有關detours原理部分不再多講。

X86 Kernel Hook
早些年,我把detours1.5移植到x86核心層,工作的不錯,我一直用它來hook系統一些內部函
數,有時候也用來hook
IoCreateFile這類匯出函數。讓detours1.5在核心工作穩定並不是一件困難的事情。可能有些c/c++的麻煩,但是很快就可以解決。唯
一需要注意的地方是detours1.5用VirtualProtect來讓記憶體READ_WRITE_EXECUTE,在核心層有2種方法,第一種是群
眾所喜聞樂見的清除cr0,第二種是在核心層通過調用native api做VirtualProtect的事情。
detours的方法對比import/export方法有一些很明顯的好處,其最大的好處是可以用來hook內建函式。而且由於hook的方法是直接修改函數體,所以不管調用者怎麼玩花樣,都很難繞過hook。
detours的缺點主要如下:
1,detours x86無法hook小於5位元組的函數
2,detours x86需要一個完備的反組譯碼器和解譯器,實際上detours代碼中並不包含這個,因此,如果需要寫一個函數阻止他人hook,可以這麼寫:
  proc near
      xor eax,eax
      jeax 1
      int 3
      ... // do something
    proc end

意到這裡的這個jmp,因為eax肯定為0,所以該int3不會被調用,而被detours過的代碼則很可能走到int3上去了,為了讓detours的
代碼不走到int3,detours必須能夠解析出前面3行代碼的意思,並且修正jeax 1為jeax
1+(trampoline-function)。用類似的技術,也可以欺騙detours。
3,detours x86無法處理如下函數:
  proc near
flag: ... // 函數前5個位元組
    .... //do something
    jmp flag
    .... // do something
    proc end
該函數執行體中有一個jmp,跳到前5個位元組。可是被detours過之後,該函數的前5個位元組被修改了,而且改成了jmp trampoline。為了能夠讓detours可以處理此操作,必須反組譯碼解析整個函數體,用2種所描述的方法修改jmp flag。

綜上述,detours思路很好,但是存在缺陷,要搞定這些缺陷,需要完整反組譯碼器。

X64 Kernel Hook
最近有一個需求要在x64下實作類別似的hook模組,我找到了detours2.1,給MS發了email,MS的回覆是,包含64bit的detours2.1,需要10000 USD。
於是我就刪掉了MS的email,開始自己動手來做這個事情了。我大致說一下原理和需要注意的地方。

x64 hook和x86 hook的原理相似,都是修改原函數的首地址。不同的是,x64下不存在
jmp
64_address這種指令,x86下要跨4G跳轉,必須是jmp [64_address],對應的彙編碼不再是e9
xxxxxxxx,而是ff15
[xxxxxxxx],其中xxxxxxxx儲存的是一個64_address。注意xxxxxxxx依然是32位,所以,該記憶體也必須和
function處於同一個4G。

這個限制對於普通的代碼編譯來說,並不存在太大的問題,因為很少有exe超過4G的。所以編譯器產生的程式碼依然使用e9
xxxxxxxx。對於import的dll來說,通常都是call
[xxxxxxxx],以前是這樣,現在還是這樣,不同的是,[xxxxxxxx]以前指向32位的地址,現在指向64位的地址。這樣一來,dll載入的
位置和exe所在的位置不在同一個4G也沒有關係了。

對於detours來說,受上面所述特性影響的是,trampoline通常位於heap memory/nonpaged
pool,new_function位於我們自己所寫代碼的dll/driver中,old_function位於我們所需要hook的那個模組中。這裡
面存在一個基本矛盾是,new_function通常和old_function分別處於2個不同dll或者.sys中,系統很可能把他們載入到了距離很
遠的空間中,也即abs(new_function-old_function)>4G。這樣一來,就無法使用e9
xxxxxxxx,而必須使用ff15
[xxxxxxxx]了,而且xxxxxxxx是一個32的位移,所以[xxxxxxxx]還不能位於我們的dll/sys中。

根據以上的分析,最後可以得出如下演算法:
1,找到需要hook的函數地址
2,解析從函數起始地址開始,至少6+8=14個位元組的代
碼。代碼不能斷開。以上2個過程和detourx86一樣,不同的是,detoursx86之需要e9
xxxxxxxx,也就是說只需要5個位元組,而我們必須用ff15
[xxxxxxxx]。如果函數體小於14個位元組,這意味著該函書無法detours。
不過函數體小於14位元組多半是因為裡面執行了一個call或者jmp,那麼解析該代碼,把函數起始地址設定為jmp之後的地址,重新進行2過程。
3,把這14或者15,16...個位元組拷貝到預先分配的一塊記憶體中,我們叫它trampoline。
4,把前6個位元組改為ff15 [0],也即ff15 00000000
5,在隨後的8個位元組中儲存new_function的起始地址
6,修正trampoline中的14位元組的代碼,如果裡面有jmp,call等跳躍陳述式,修改位移量,這時候通常又需要跨4G的跳轉,那麼按照上面的方法修改之,trampoline的位元組數可能會增加。
7,在trampoline的代碼之後,插入ff15 [0],並且在隨後的8個位元組中填充old_function+14。

trampoline可以預先分配一個100位元組的buffer,初始化全部填充為nop,在進行7的時候,可以從trampoline的底部,也
即100-14的位置開始填入ff,15,00,00,00,00, 64_bit_old_function+14(15,16...)。

以上演算法的缺點和x86 detours的缺點一樣,第一條為無法hook函數體小於14位元組的函數。

14個位元組相當大,有時候這個缺陷不可忍受,為此,介紹一種更為骯髒的手段。

代碼載入到記憶體中時,通常有很多廢空間,也即,在這些空間中,只有nop,或者永遠不會執行。用IDA可以找到這些空間。如果能夠找到足夠大到,以
至於可以儲存一個64位地址的空間的話,那麼可以只修改前5個位元組為jmp
[xxxxxxxx],同時只拷貝5個位元組到trampoline。trampoline的底部14個位元組照舊。

以上就是x64下的detours過程。

有一個x64下需要注意的問題,vc8不支援x64下的_asm關鍵字,所以
_asm{
cli
mov eax,cr0
and eax,not 1000h
mov cr0,eax }不能再用
取而代之的是
_disable();
uint64 cr0=__readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
當然還可以繼續用native api,不過以上方法簡潔而且為廣大群眾所喜聞樂見。有關於_disable等函數,請查閱新版msdn。

至於IA64,我對此一無所知。

順便說幾點:
1,EM64T的cpu上可以run
win64os,但是,不知為何,vmware無法在EM64T的cpu上install/run win64os。而amd64
cpu上即便安裝的是win32 os,也可以在其上的vmware裡install/run win64os。
2,softice已經停止開發,而且不支援x64,只有virtual模式才支援。鑒於其已經停止開發,建議大家都使用windbg。
3,idapro 5.0反組譯碼x64的代碼,錯誤百出,一團亂麻,基本上需要先U再C。

因為14位元組的限制太大,以至於始終覺得不爽。後來想到了一個解決方案。

假設原函數是old_func,新函數是new_func,那麼分配trampoline的時候,用某些技術方法,限定分配出的記憶體和
old_func在同一個4G。可以通過VirtualAlloc實現,具體方法可以是多次改變第一個參數,調用VirtualAlloc,直到傳回值不
為NULL為止。

這樣一來,detours的邏輯改變為:

1,首先把old_func的前5個位元組拷貝到trampoline+14,然後修改為jmp offset,也即e9 trampoline-5-old
2,trampoline的前6位元組為ff15 [0],接下來的8個位元組為new_func_address
3,trampoline+14+5之後的5個位元組為jmp (trampoline+14+5+5 - (old_func_addr+5))

這樣調用old的時候,會首先執行jmp offset到trampoline,trampoline又jmp到了new_func,new_func調用old的時候,會直接跳到trampoline+14處,執行原來的前5個位元組,然後再jmp會原函數體。

如此,一切都完美了

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/zzw315/archive/2009/04/23/4102488.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.