|
2 S" o# r& C; b# z' B
发表日期:2003-10-30作者:tomh[] 出处: 7 D/ X W" ?8 }5 K O
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
3 c# g5 U: T! W- T 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
( S/ o" {; M* h0 L其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: ' }& r4 _: e9 X3 q
BOOL VirtualProtectEx( 0 e: a0 X5 N' E3 ]$ X
HANDLE hProcess, // 要修改内存的进程句柄 " a( l5 ^4 c7 V9 k. x
LPVOID lpAddress, // 要修改内存的起始地址
6 e: o- c2 e# d6 r# D0 a DWORD dwSize, // 修改内存的字节
8 b* a% h; c9 L& n DWORD flNewProtect, // 修改后的内存属性 $ ?$ ]+ R: d# r& b
PDWORD lpflOldProtect // 修改前的内存属性的地址 5 y3 }/ l* |2 H0 i3 q
);
3 ?+ Y# Q# _* A. _( \ L BOOL WriteProcessMemory(
! { t1 F: U5 A6 B; \3 i0 [ HANDLE hProcess, // 要写进程的句柄
/ e$ W+ T8 _& k. O, X7 X: G LPVOID lpBaseAddress, // 写内存的起始地址
6 ]& w$ K9 z4 \( u9 {( r! u! ^. Z LPVOID lpBuffer, // 写入数据的地址 L1 c6 c6 N8 ] T$ [
DWORD nSize, // 要写的字节数
j7 w) x3 R0 s LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 + ~; p% Z/ J8 c. P
);
6 o/ h' M$ j6 w3 X: @ BOOL ReadProcessMemory(
; h. s' ]' q/ k: Q/ ^ HANDLE hProcess, // 要读进程的句柄
5 C/ S$ O" ]& d8 C: x+ y LPCVOID lpBaseAddress, // 读内存的起始地址
9 r, I0 R: D% P5 o2 V) ^8 _ LPVOID lpBuffer, // 读入数据的地址 # M5 ?8 v1 q, \. p1 z
DWORD nSize, // 要读入的字节数 : U1 n6 d; Q9 m3 s( a' N; Y/ {$ |
LPDWORD lpNumberOfBytesRead // 实际读入的子节数 # K( F- @6 m5 H+ L" {) W
); 6 y' F, U" K; }( Y
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, 9 F+ h& {" l! \$ Z1 C
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: & u6 [- S6 j" M
其中Dll文件为:
* Z7 _1 p. t& ~& q4 N HHOOK g_hHook;
; w; d" T' o' V" j8 ^ u! ~: w HINSTANCE g_hinstDll;
, |& n t2 c" O& ^6 U. K4 I i FARPROC pfMessageBoxA; 8 n: Y1 T6 \, S! ~+ _
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); - R+ ]2 E6 {3 O U+ Q; l' \6 U
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; + R" f1 F4 _3 r8 _( b) n7 y
HMODULE hModule ;
0 D) ^! F2 C: p3 U& J9 [& | DWORD dwIdOld,dwIdNew; " O" d J% T' ~# X M; c; q+ H- p3 Y
BOOL bHook=false; 8 n- s( M1 Y/ o; R/ Q" v* Y
void HookOn();
) z) x9 a, I' y9 r' U5 | void HookOff(); / F9 m0 k6 P1 E- H/ p; A
BOOL init(); 2 \$ ?+ [( _- z. O* j
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
* ~3 \. V) V I9 I2 SBOOL APIENTRY DllMain( HANDLE hModule, 5 L9 P' |- V4 _, I, [1 @
DWORD ul_reason_for_call,
+ L( T9 d" \7 F LPVOID lpReserved 3 f: v* M4 |/ |1 R! [( c1 ^# ?3 `
)
3 ~/ O6 ?9 I# L( O{ & J& z+ S3 Q& N+ S
switch (ul_reason_for_call)
, g, |1 X d9 x4 `% e {
# W" ~& z$ Q( l case DLL_PROCESS_ATTACH: % V# T$ }6 ^& y* j1 ^
if(!init()) 1 g7 B' {5 o) a+ {# G
{ ?3 M& G" C/ l
MessageBoxA(NULL,"Init","ERROR",MB_OK);
5 k, E( y- M# g1 `- ]0 E) l+ E return(false);
. ^& X1 Q4 }3 B. Q$ ^6 z } 5 I6 `5 C/ M7 G8 D* g4 g* g. V7 {
case DLL_THREAD_ATTACH: 8 }0 u& h: z! d7 }" [' U3 X
case DLL_THREAD_DETACH: ; O0 j! P( H( W5 J
case DLL_PROCESS_DETACH:
& |4 E9 d9 P( ^9 k+ n% b if(bHook) UnintallHook(); ' N" V7 t/ h" `; d' ^5 {) Q. {$ T v
break; . I$ A( D% _, L
}
* R* T+ a5 d% q return TRUE;
" F/ D- L3 m" V/ S" R; w}
1 C$ g. Y4 Z8 \3 }: T' fLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 # k# K$ L/ c! n- F% K% p5 t
{ + l; Y+ b7 Z& i- C4 s$ i
, b/ @, a* Z# H' w& j6 }: { return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
8 N# n. ?, P1 P: ~1 L# @} / |2 j% f0 b) }4 o" h! t
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
9 h# d0 X+ \7 V0 n2 h5 {{
( z, m2 v; H- W" A g_hinstDll=LoadLibrary("HookApi2.dll"); 5 L1 B$ D5 f Z" t! L& U
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); . Z, x( E. F; w
if (!g_hHook)
& r9 P8 u+ S$ j/ b& U' a$ e{
7 ?9 Q% s4 J6 Q! R, \8 z MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
L( @, h% ?& N. }# d return(false);
7 }+ E$ G2 k: {9 B& i, P }
, g/ b0 V# _( ?+ X' r1 z. n
4 y* P3 s8 j+ x+ b" H1 x
2 [! e+ j8 N( u' `/ D return(true); 4 l- L2 j n* o- `2 u2 {$ x0 T
} 8 A4 }; H, a5 H' d; a b6 `( r
HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数 ' @' Z: u( D8 |, n% w
{ % s$ _# r! @6 s$ B' R' J9 M
+ W6 _5 b# R% o) J3 u
return(UnhookWindowsHookEx(g_hHook));
* B9 _: C2 d' M; \" k1 g5 {. ?% U, K' l}
+ [, v$ Q4 r0 yBOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
6 `! z. V- E( ^$ x. z{ 8 B, u! D& ^! g% F1 ^( K, w
hModule=LoadLibrary("user32.dll");
' J" C9 S, {- K* {+ W* b* i1 t& a pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 4 r9 T, i# n, v
if(pfMessageBoxA==NULL) ! g& o) F6 U' R, k5 d2 S$ S
return false;
1 H; c. S1 Z5 U+ F# I R* ~8 g _asm , X- v7 M; U, @6 Z7 {: P" K
{
+ Q* b; a- J$ Y lea edi,OldMessageBoxACode
! e( r4 Y' u. B' \% T# l9 O' U* ? mov esi,pfMessageBoxA * v- a+ u1 H/ Q9 h/ i) M8 J) ?
cld 1 k8 v" Z: f, w! D' S3 X9 r
movsd
( y; b4 x2 U+ M movsb ( ]2 q. k2 F$ Q2 l4 L( k9 K
} + _9 r8 ^! B6 @: j' K" t( O
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
0 _# [5 _# W/ w0 E4 _2 `* e _asm
: b3 o/ l! q9 z. D" R l1 l: Y/ s { : ~( U& s p, q; ]
lea eax,MyMessageBoxA
$ i$ {+ m4 L* m# ~- Y mov ebx,pfMessageBoxA " d" E# u! ^5 J7 ~) K* w
sub eax,ebx ) Y; r. S7 p, |+ ]8 z4 ~+ ^
sub eax,5 # q2 h7 ^* Y5 U" x7 A6 s
mov dword ptr [NewMessageBoxACode+1],eax
$ v7 C# B& y0 u1 T) Y) ^ } $ u" M ^2 T) l5 v
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
; M) x A; g& ]* Y' @& K, P5 b% C4 B! c dwIdOld=dwIdNew; 5 D% b1 t1 A1 r8 d: D" U" b
HookOn();//开始拦截 4 I/ ^$ m1 G/ ]' L
return(true); 5 L9 a! j4 q* T {; K; e
} i5 n3 @6 r) V& L
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
* a+ N% @6 d9 L5 @2 {{ # ?3 z9 g3 y9 a7 i/ E4 [7 O) L. }+ }
int nReturn=0;
! a; m g2 |# k4 u2 c( w HookOff();
) T9 I8 [' g/ } nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); 6 ^' K+ A' P$ Y
HookOn();
6 o" ^5 V8 V/ o. e& q6 w return(nReturn); 6 k& j! V: B! _( e
} * Y" f0 t5 C8 f5 F+ E6 r3 u
void HookOn() 4 J# p% {) D: H1 |% i1 G+ f
{ * d+ ^0 _" J: m3 w# G; E4 u9 q
HANDLE hProc;
3 m" r* r/ v* P+ _4 l dwIdOld=dwIdNew;
7 ?! ~. P2 ?2 c% v8 E5 p% ] hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
2 w% \* Y% x6 R$ N+ u$ P' p0 F VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 5 I7 n3 R7 X v$ d4 n
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
! K/ q4 V4 v Q1 X VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
+ A0 N2 Z) U: y) y1 \5 P bHook=true;
+ n- `0 Z$ P' x9 T: H}
8 ]' {6 X2 v: r5 h. qvoid HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
. a8 U3 B. D# |- S7 w1 p{ / _% u) a* H! w; I* b+ v1 W
HANDLE hProc; ' I9 k; `) {' W% r
dwIdOld=dwIdNew; M/ U7 z. @, L# r5 t) N
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
/ X2 [5 Y- ~' A" `2 P VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 1 }6 J) Z+ _9 [ M
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); " b9 I. B+ z% T+ t" }: g
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); + [* d- l+ d% o- r: W; ` j2 K/ G
bHook=false; 0 {8 y: y8 V1 i0 k% \+ T
}
7 \" [- O# I& a. o6 o7 c F" r, K//测试文件: + Q2 j( V; x! ^
int APIENTRY WinMain(HINSTANCE hInstance,
4 b% {4 J6 T t$ T4 ]7 [ HINSTANCE hPrevInstance, 2 b* Z5 V; Q0 C$ U2 _
LPSTR lpCmdLine, . o2 {" ?% M4 M& s. Z/ }
int nCmdShow)
0 m+ h6 g. N/ ^8 c; q) X! A{ # g/ y& J+ z; I
/ X% |: O: j9 X, W/ I5 Y( Z# v" h if(!InstallHook())
: |: C) @2 i0 G2 M0 \* s6 I {
/ b7 g. g& s) k( @; b+ b- T- b MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); ' `( B4 Y/ L# q# X9 y8 k0 s
return 1;
/ r2 i6 l8 f# I' [ }
! D0 O# y; K6 L1 M MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见
4 j( i( {+ `! z if(!UninstallHook()) " |* B' ~! U3 O! b0 i8 ^$ a
{
w0 b' U! I8 F8 [* c$ v$ c MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); 7 u0 }$ F& \! n( `' P1 [/ s
return 1;
* ~3 `0 F7 z, q( x( f }
- K( B" T) S+ X P" C( X4 u/ q return 0; % D- F1 U! X) q; X" ?, |1 e
} 6 ^5 l+ A; N( N
[此贴子已经被作者于2004-11-5 18:12:27编辑过]
+ z6 @3 ~, \5 C# O0 v! z0 D" Y |
|