看了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)是透明的了。
最后转跳,是一个近转跳,所以还要计算相对位移。
效果:
#include <stdio.h>
#include <windows.h>
4:
,off)
6:
void hook()
8: {
);
10: }
11:
int main()
13: {
14: detourInit();
//---------------------------------------------------------
16:
17: detour( Sleep,hook );
18:
19: Sleep(1);
20:
);
return 0;
23: }
PS: detour.h 即我自己实现的源码。(代码在下面)
结果:
Sleep就被勾住了。但是再次调用Sleep就是正常的。
具体代码:
detour.h ( 其实应该起名hook的 )
#ifndef __DETOUR_H__
#define __DETOUR_H__
3:
once
5:
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
9:
char u8;
11:
//push (下标) + push (traceBack地址) + jmp (hook) 覆盖15个字节
#define TBSIZE 15
#define INFOSIZE 5
#define REPSIZE 15
16:
//machine code
#define MC_FARJMP 0xE9
#define MC_PUSH 0x68
20:
struct s_detour
22: {
void *oldFunc;
void *hook;
25: u8 backUp[TBSIZE];
26: };
27:
28: s_detour gInfo[INFOSIZE];
29:
void detourInit()
31: {
sizeof(s_detour) );
sizeof(gInfo) );
34: }
35:
new DWORD;
37: BOOL ftb_res;
void* ftb_addr;
int tn )
40: {
//restore
//ps:只能jmp不能return
43: __asm
44: {
//假装地址填充.使得tn能够正确访问
46: push ebp
47: mov ebp,esp
48: }
49:
50: assert( tn >= 1 && tn < INFOSIZE );
51:
//#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:
//ready to back
void*)gInfo[tn].oldFunc;
63: gInfo[tn].oldFunc = NULL;
64: __asm
65: {
66: mov esp,ebp
67: pop ebp
//pop 0x1
//balance stack pop tn
70:
71: mov eax,ftb_addr
72: jmp eax
73: }
74: }
75:
//register
void *hook )
78: {
if( oldFunc == NULL || hook == NULL )
return false;
81:
int tn;
for( tn = 1;tn < INFOSIZE;++tn )
84: {
//could be used
break;
87: }
if( tn == INFOSIZE )
return false;
90:
91: gInfo[tn].oldFunc = oldFunc;
92: gInfo[tn].hook = hook;
93:
new DWORD;
95: BOOL res = VirtualProtect( oldFunc,REPSIZE,PAGE_EXECUTE_READWRITE,lpOld );
96: assert( res );
97:
//back up
99:
//replace
101: u8 *pf = (u8*)oldFunc;
102: pf[0] = MC_PUSH;
//压入标记
104:
int)pf + 5 );
106: pf[0] = MC_PUSH;
//压入traceBack地址
108:
int)pf + 5 );
110: pf[0] = MC_FARJMP;
//near jmp 相对地址
112:
113: res = VirtualProtect( oldFunc,REPSIZE,*lpOld,lpOld );
114: assert( res );
115: free( lpOld );
116:
return true;
118: }
119:
#endif