自己實現函數鉤子

來源:互聯網
上載者:User

看了detour的原理,心裡想著自己能不能動手類比一個。

比劃的時候發現了一些細節問題。detour將函數的前幾個位元組(剛開始看文檔的時候說5個位元組)替換成jmp __

。但是發生機器碼截斷整麼辦?可以在vs的反組譯碼視窗看到每條彙編指令的機器碼,每條指令的機器碼長度並不是固定的,我想detour並不是固定複製5個位元組這麼簡單(目前還沒研究detour源碼)。所以退而求其次(這是一個學習性質的實驗),改變設計。

我選擇在自己定義的函數執行完之後將修改的代碼再改回去,跳回原函數運行。看起來是這樣的:

而且自訂函數是不知道自己返回到的是traceBack的。

即原函數總是會被執行。這就變成了鉤子,而且只能鉤住一次,因為我把被修改地區複原了。

不過暫且就不計較這個了(這是一個學習性質的實驗)。

真正自己實現的時候才發現一些有趣的細節問題,比如jmp對應有多個機器碼,選擇哪一個,字碼頁原來是不允許寫的,要VirtualProtect函數修改,traceBack不能return只能jmp,為了保證棧平衡需要寫成__declspec(naked)之類。

還有我修改了15個位元組,三個句子:

push __

push __

jmp __

第一個push壓入的資訊提供給traceBack,好讓他能找到修改前的代碼拷回去。

第二個push壓入traceBack的地址,這樣跳轉到traceBack就對自訂函數(hook)是透明的了。

最後轉跳,是一個近轉跳,所以還要計算相對位移。

效果:

   1: #include "detour.h"

   2: #include <stdio.h>

   3: #include <windows.h>

   4:  

   5: #pragma optimize("",off)

   6:  

   7: void hook()

   8: {

   9:     printf("detoured\n");

  10: }

  11:  

  12: int main()

  13: {

  14:     detourInit();

  15: //---------------------------------------------------------

  16:  

  17:     detour( Sleep,hook );

  18:  

  19:     Sleep(1);

  20:  

  21:     system("pause");

  22:     return 0;

  23: }

PS: detour.h 即我自己實現的源碼。(代碼在下面)

結果:

Sleep就被勾住了。但是再次調用Sleep就是正常的。

 

具體代碼:

detour.h ( 其實應該起名hook的 )

   1: #ifndef __DETOUR_H__

   2: #define __DETOUR_H__

   3:  

   4: #pragma once

   5:  

   6: #include <windows.h>

   7: #include <assert.h>

   8: #include <stdlib.h>

   9:  

  10: typedef unsigned char u8;

  11:  

  12: //push (下標) + push (traceBack地址) + jmp (hook) 覆蓋15個位元組

  13: #define TBSIZE 15

  14: #define INFOSIZE 5

  15: #define REPSIZE 15

  16:  

  17: //machine code

  18: #define MC_FARJMP    0xE9

  19: #define MC_PUSH        0x68

  20:  

  21: struct s_detour

  22: {

  23:     void *oldFunc;

  24:     void *hook;

  25:     u8 backUp[TBSIZE];

  26: };

  27:  

  28: s_detour gInfo[INFOSIZE];

  29:  

  30: void detourInit()

  31: {

  32:     assert( sizeof(gInfo) > sizeof(s_detour) );

  33:     memset( gInfo,0,sizeof(gInfo) );

  34: }

  35:  

  36: LPDWORD ftb_old = new DWORD;

  37: BOOL ftb_res;

  38: void* ftb_addr;

  39: __declspec(naked) void traceBack( int tn )

  40: {

  41:     //restore

  42:     //ps:只能jmp不能return

  43:     __asm

  44:     {

  45:         push 0x1        //假裝地址填充.使得tn能夠正確訪問

  46:         push ebp

  47:         mov ebp,esp

  48:     }

  49:  

  50:     assert( tn >= 1 && tn < INFOSIZE );

  51:  

  52:     //#the return would work?

  53:     ftb_res = VirtualProtect( gInfo[tn].oldFunc,REPSIZE,PAGE_EXECUTE_READWRITE,ftb_old );

  54:     assert( ftb_res );

  55:  

  56:     memcpy( gInfo[tn].oldFunc,gInfo[tn].backUp,REPSIZE );

  57:  

  58:     ftb_res = VirtualProtect( gInfo[tn].oldFunc,REPSIZE,*ftb_old,ftb_old );

  59:     assert( ftb_res );

  60:  

  61:     //ready to back

  62:     ftb_addr = (void*)gInfo[tn].oldFunc;

  63:     gInfo[tn].oldFunc = NULL;

  64:     __asm

  65:     {

  66:         mov esp,ebp

  67:         pop ebp

  68:         pop eax        //pop 0x1

  69:         pop eax        //balance stack  pop tn

  70:  

  71:         mov eax,ftb_addr

  72:         jmp eax

  73:     }

  74: }

  75:  

  76: //register

  77: bool detour( void *oldFunc,void *hook )

  78: {

  79:     if( oldFunc == NULL || hook == NULL )

  80:         return false;

  81:  

  82:     int tn;

  83:     for( tn = 1;tn < INFOSIZE;++tn )

  84:     {

  85:         if( gInfo[tn].oldFunc == NULL )        //could be used

  86:             break;

  87:     }

  88:     if( tn == INFOSIZE )

  89:         return false;

  90:  

  91:     gInfo[tn].oldFunc = oldFunc;

  92:     gInfo[tn].hook = hook;

  93:  

  94:     LPDWORD lpOld = new DWORD;

  95:     BOOL res = VirtualProtect( oldFunc,REPSIZE,PAGE_EXECUTE_READWRITE,lpOld );

  96:     assert( res );

  97:  

  98:     memcpy( gInfo[tn].backUp,oldFunc,REPSIZE );    //back up

  99:  

 100:     //replace

 101:     u8 *pf = (u8*)oldFunc;

 102:     pf[0] = MC_PUSH;

 103:     *((int*)((int)pf+1)) = tn;                //壓入標記

 104:  

 105:     pf = (u8*)( (int)pf + 5 );

 106:     pf[0] = MC_PUSH;

 107:     *((int*)((int)pf+1)) = (int)traceBack;    //壓入traceBack地址

 108:  

 109:     pf = (u8*)( (int)pf + 5 );

 110:     pf[0] = MC_FARJMP;

 111:     *((int*)((int)pf+1)) = (int)((int)hook - ((int)pf) - 5 );        //near jmp 相對位址

 112:  

 113:     res = VirtualProtect( oldFunc,REPSIZE,*lpOld,lpOld );

 114:     assert( res );

 115:     free( lpOld );

 116:  

 117:     return true;

 118: }

 119:  

 120: #endif

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.