逆向實用干貨分享,Hook技術第一講,之Hook Windows API


             逆向實用干貨分享,Hook技術第一講,之Hook Windows API

作者:IBinary
出處:http://www.cnblogs.com/iBinary/
版權所有,歡迎保留原文鏈接進行轉載:)

一丶什么是Hook,以及Hook能干啥

首先這一個小標題主要介紹神馬是Hook,如果知道的,則不用看了.

這里我偷襲啊懶,貼出Hook的意思  https://baike.baidu.com/item/%E9%92%A9%E5%AD%90%E7%A8%8B%E5%BA%8F

Hook,英文單詞中成為鈎子,鐵鈎的意思,在我們編程中就是掛鈎的意思

我們要HookApi,則是要把這個API進行掛鈎,讓其執行我們的代碼,然后執行完我們的代碼之后,在執行API的代碼,當然執行不執行使我們說了算.

二丶Hook API的原理,以及思路

現在我們要知道我們要怎么Hook API

假設我們程序現在要調用一個MessageBox函數,那么我們把這個API Hook了,變為我們的API去執行,執行完我們的代碼之后再去執行它的的函數.

具體看下我們的草圖:

其實相當於就是我們在這個API之前,跳轉到我們的函數執行了,然后跳轉之后,我們執行完畢之后,可以選擇是否在跳轉回去,但是這里注意,跳轉回去則跳轉到msg的return處位置即可.

eax可以給一個值,讓它返回.

利用這個技術,我們可以監控API,比如應用程序會調用loadLibrary,那我們把它Hook了,把Dll路徑改成我們的,那加載的就是我們的dll了,當然 Hook的API很多,因為只要是Windows的API都能HOOK

因為JMP的時候占五個字節,而WindowsAPI也是頭部弄了五個字節,猜想可能是Windows自己留作Hook的.

三丶Hook的步驟(Hook自己)

首先說下步驟

/*
思路:
    我們要獲取MessageBoxA的函數地址,在獲取之前我們要進行下面幾個步驟
1.調用GetModuleHandlle,獲取Dll模塊(user32.dll的)的基地址
2.通過基地址,調用GetProcAddress獲得Msg的函數地址
3.修改Msg函數地址的保護屬性,調用virtualProtect
4.重定位跳轉地址 Dest - MsgCode = offset -5 
    jmp 跳轉到這個偏移即可
5.跳轉回來的時候則是 dest + offset + 5 = Msgcode +5的位置

*/

看上面,很暈,一步一步代碼實現.

注意: 這里只是簡單實現,並且說下思路,代碼復制過去你不能運行,因為比如下方,我寫 offset g_szUser32...等等的,

其實都是在.const中定義的,最下面會貼出完整代碼,那么是可以運行的.

第一步,獲得Msg的地址,首先調用GetModuleHandle

;1.獲得Msg的地址,先調用GetmoudulHandle
    invoke GetModuleHandle,offset g_szUser32        ;獲得模塊地址
   mov @hUserHand,eax                     ;返回值給局部變量保存
;其中g_szUser32在常量區是 user32.dll的字符串

第二步:通過模塊地址,獲得Msg函數的地址

invoke GetProcAddress,@hUserHand,offset g_szMsgName
mov @MsgProcAddrs,eax
;代碼同上

第三步:修改Msg函數地址的內存保護屬性,方便一會我們把JMP的二進制寫進去好修改

invoke VirtualProtect,@MsgProcAddrs,1000h,PAGE_EXECUTE_READWRITE,addr @hOldProtect
修改大小是1000(4096)個字節
權限是 可讀可寫可執行
是否保存舊的權限屬性: 是 ,這里必須保存,雖然你不用,否則API會失敗
還有就是,因為要保存以前的,所以我們必須把地址給他,要加上Addr才可以

第四步: OD查看Msg位置,尋找5個字節位置

這個時候我們可以在我們的代碼中寫個int 3,打開的時候OD會斷下,我們在GetprocAddress的位置下斷點,

看下獲取到的Msg的地址是多少

我們在反匯編窗口中跟隨到Msg的位置.

可以看到上圖的位置,剛好五個字節, mov edi,edi是沒用的指令,但是windows還是保留了

也就是說可能就是以為了自己去監控API留下的.那么這個時候我們可以在這個位置,寫入

JMP的指令  JMP  我們的API位置

我們如果跳轉到我們API的位置后,執行的代碼前邊這三條還是這個,因為一會我們還要在跳轉到當前的MSG + 5

的位置處繼續執行,(當然,隨你便,你也可以跳轉到Msg的Return位置)

第五步: 寫入Jmp,JMP到我們的函數的位置

首先我們知道 JMP的二進制是 E9 

所以我們要 E9  xxxxxx   xxx使我們函數的地址

但是JMP 的時候,這個地方是個偏移

那么我們要JMP到我們函數的偏移位置,就要進行地址重定位了.

怎么重定位,很簡單,小學數學

計算Msg的下一條執行的位置

code + offset = dest  當前的Msg的下條位置計算 帶入則是  7595FDAE + 5 = 7595FDB3 也正好是我們跳轉回來的位置

計算跳轉到我們函數地址

dest - code = offset  目標地址我們知道,就是我們的函數地址,開始跳轉的地址也知道了,所以帶入帶

我們的函數地址 - Code(當前的Msg地址) = offset 偏移,那么 JMP 這個偏移即可.

定義我們的函數

函數寫成下面的那樣

最下面的label中的內容則是 JMP 00000000 其中這個地址是我們要重定位寫進去的

第六步:實現代碼,寫入JMP

從這里開始我直接寫實現代碼了

   mov eax,@MsgProcAddrs       ;code
    mov ebx,NewMsgBox           ;dest
    sub ebx,eax                 ;dest - code = offset
    sub ebx,5                   ;得出的偏移需要-5,別忘了jmp占五個字節,這樣才可以跳轉到你的地址執行
    mov [eax],byte ptr 0e9h     ;寫入Jmp
    mov [eax +1],ebx            ;寫入跳轉的地址

首先獲得msg的位置,也就是Code

然后獲得 自己函數的位置,也就是Dest

現在我們要求出中間的偏移是多少 dest - code = offset

然后因為JMP跳轉要占五個字節,所以接着-5個字節大小

現在我們要把Msg函數的位置,改為JMP,我們要JMP我們的地址,我們看下OD分析

1.首先找到Msg函數位置,看下數據窗口中跟隨

2.單步走,然后執行到第一個把二進制改為E9H的地址

現在我們接着反匯編窗口中去看看Msg的地址,看下是否改為了JMP了

現在是改為了JMP,但是偏移是不對了,不過我們的偏移已經計算出了了,所以寫到E9后面即可

3.修改偏移OD查看.

,反匯編窗口中看下Msg

,現在顯示不知是否正確,那么我們現在去反匯編窗口中看下00401000是不是我們的NewMsg位置

可以看出,代碼正是我們寫的.

 

也正好是JMP 000000000的位置,那么我們就可以在我們的代碼中寫了,劫持真正的MsgBox函數的執行

我們知道, 因為是jmp過來的,所以ebp - c 還是Msg的第二個參數,我們把里面的內容改了

注意,這個在劫持代碼里面寫.

四丶我們還有修改跳轉回來的位置,這個是同理了

看下代碼:

 invoke VirtualProtect,label1,1000h,PAGE_EXECUTE_READWRITE,addr @hOldProtect
    mov eax,offset label1           ;code 我們要修改的地址是標號的地址,所以他是code
    mov ebx,@MsgProcAddrs           ;dest 我們要跳轉到Msg的地址,所以他是Dest
    sub ebx,eax                     ;dest - code = offset  帶入公式咋得到ebx是偏移
    mov [eax +1],ebx                ;eax標號的位置+1后面,也就是JMP 00 00 00 00 把00 00 00 00 寫成偏移,咋跳轉回來Msg的位置繼續執行
    invoke MessageBoxA,NULL,offset g_szMsgTitle,NULL,MB_OK 

第一,我們要修改的跳轉位置是標號1的位置,所以他是code

第二,我們要跳轉到哪里,所以他是dest

第三,根據公式, dest - code = offset 求得了偏移

第四,我們把dset +1的位置,也就是JMP 00 00 00 00  修改位了偏移,咋又跳轉回來了.

看下OD分析

看下OD,我們也可以看出,我們單步走,單步走到 mov dword ptr[eax +0x1]的位置,看下是否把標號1的偏移修改了

在內存中我們已經看到了,我們的偏移修改了.

那么我們反匯編窗口看下,當前我們的API ,也就是JMP 00 00 00 00 的位置是否修改了

可以看出,確實修改了,那么我們看下JMP 后面的地址是哪里把

正好使我們調用MsgBox的位置 +5的下面,也就是說,上面JMP到我們的API執行了,下面咋通過JMP有跳轉回來了,此時因為我們已經保存了 棧底環境,所以運行是沒有出錯的

看下不調試,正常運行

通過HOOK技術,我們把本來應該輸出 Hello 看雪,變成了我們自己想要的字符串.

四丶總結

  總結來說. HOOK 需要記住一個公式以及硬編碼即可. 公式  目的地址 - 源地址 -指令長度(如果是JMP則是5) 

  JMP 硬編碼是E9  E9 00000000 后邊四個0我們定位到我們要執行代碼的位置. 用公式計算機課. 目的 - 源 - JMP(5) == 偏移. 偏移寫入這里即可.

  HOOK 別人程序也是這樣去做.

因為代碼是RadAsm工程的,所以這里打包發到百度雲盤

 

鏈接:http://pan.baidu.com/s/1kVBWalp 密碼:luz8

作者:IBinary
出處:http://www.cnblogs.com/iBinary/
版權所有,歡迎保留原文鏈接進行轉載:)

如果覺着好,請推薦,加關注,如果覺着哪里寫的不好,請批評改正.謝謝大家.如果看不懂,請評論一下給點動力,其實寫博客最主要的還是自己整理,每天都堅持.把最好的獻給大家.


免責聲明!

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



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