|
l1 m) f2 i2 J4 x" X+ }发表日期:2003-10-30作者:tomh[] 出处:
7 C+ F2 r9 d; q2 GApi拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
/ P# C4 d8 h2 f 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
2 M z/ }) N% j5 p0 J其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
: G% Q7 k- Z$ e! K' N BOOL VirtualProtectEx( ; K. @& ~& O2 ^
HANDLE hProcess, // 要修改内存的进程句柄
7 g8 J1 m3 M6 k7 O# `/ E+ Y5 x LPVOID lpAddress, // 要修改内存的起始地址
+ z; P# w1 p8 f. k DWORD dwSize, // 修改内存的字节
. a* ]3 i) \* y+ l# B DWORD flNewProtect, // 修改后的内存属性
. A6 Q2 W2 u; V* m PDWORD lpflOldProtect // 修改前的内存属性的地址
3 a2 r3 R$ u( g0 a8 k ); ( W1 {/ ], P1 z2 v8 q
BOOL WriteProcessMemory( : L$ V2 y' I+ V4 o: Y
HANDLE hProcess, // 要写进程的句柄
( H, {1 w; l5 h7 W LPVOID lpBaseAddress, // 写内存的起始地址
9 q6 D- M1 ~! ] D; L2 Z4 N LPVOID lpBuffer, // 写入数据的地址 ( z5 e* ]- [" d' _- ]
DWORD nSize, // 要写的字节数
p$ G" Y' i q5 N* t: z% r LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
. d6 O) Z9 X N: m );
! S+ {; n, H4 q1 Y' P BOOL ReadProcessMemory( 9 P$ m5 b3 H1 T" r, }# H
HANDLE hProcess, // 要读进程的句柄 & \) A X! F' O7 o5 ^0 y8 M i
LPCVOID lpBaseAddress, // 读内存的起始地址
, z0 S% t5 Y& S6 B LPVOID lpBuffer, // 读入数据的地址
! e+ u9 ] f- E7 t, L6 ^* A DWORD nSize, // 要读入的字节数
7 @9 @- X, v3 S% Z2 A5 E) n LPDWORD lpNumberOfBytesRead // 实际读入的子节数
o4 k- D3 U# k, x- S* q: U8 Q& M ); & M$ w* s f. t% @7 y
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
8 x5 o9 R6 V. I2 U8 G5 ~' I2 b5 K因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:
. J, J+ Z# K$ L, ~- w) E9 t其中Dll文件为: 6 R$ m9 T1 ^: E' E$ B
HHOOK g_hHook;
2 `( H. l6 L8 v1 b- C+ V HINSTANCE g_hinstDll; 4 I9 N& J) K* T5 A: }& A! a0 P
FARPROC pfMessageBoxA;
2 h& t" c4 P" [3 B+ z int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
. t# m) a: E1 a+ y2 x" S BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
$ e8 i+ ]- p$ M; ~1 H8 ~2 s HMODULE hModule ; , Y+ b; z, R/ f/ i# a" W! a
DWORD dwIdOld,dwIdNew;
! q$ U' r9 [2 G6 [7 [ BOOL bHook=false;
, [, ~& [3 T. S3 }: F8 m. ` void HookOn();
1 ^; f. {( i ^ void HookOff(); 3 Z* i- L& T7 k
BOOL init();
$ N4 w: J0 S: ` K a7 gLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
: X. R8 T* Y( @4 p, XBOOL APIENTRY DllMain( HANDLE hModule,
7 G$ p/ g: O! k1 y& P0 R DWORD ul_reason_for_call, 8 F) e* `6 h' j% P3 G
LPVOID lpReserved / |# @4 R6 ~: f9 x" n; l- i
)
4 [4 r* B0 e: l{ 0 D& }0 n$ l5 j) _5 ?6 f: G
switch (ul_reason_for_call)
" x0 W% v- C) S# ^3 l( s { / B2 K# Y' \* Z! g) M6 @ [7 Y
case DLL_PROCESS_ATTACH: / N5 g! [; Y; f4 _! u! n: O6 W' f
if(!init())
/ o+ [9 @( E" x' d/ Q7 K9 g8 o8 F { ; J. d# F+ Z! m& i5 c/ |0 y
MessageBoxA(NULL,"Init","ERROR",MB_OK); ; Y% K; ]5 d. q; q& m0 D/ A) G+ r' `
return(false); % B( |8 B: l) I2 p; l' Q" `& U) N
} * w! E. f% v0 o/ F
case DLL_THREAD_ATTACH:
, C% d% a4 ]1 O case DLL_THREAD_DETACH: ) u% ]- ^9 {: m# |* i* p. |& p
case DLL_PROCESS_DETACH: + N0 e* k4 a3 Y- S# Q/ A
if(bHook) UnintallHook(); ) K# `/ a, D' @
break; ' |0 _ y- R9 Q& q, l. l/ t
} 5 P5 ?9 l/ }0 A. Z' c
return TRUE;
8 l8 i- ^5 S5 L0 d} $ y& w9 L# t: E2 C
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
$ l& |( X+ N# I5 G{
) U, Y: X( n$ A ?$ s9 h" d5 P 3 I. l5 v- i) y( X% O
return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); # k' c$ i- v" D' g$ G X' p
} 9 y8 k3 B2 L" O( U' M
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 / F: }' ^) j: v1 S" Z
{
1 z5 F! n. T0 _" M& Z% S" @# r g_hinstDll=LoadLibrary("HookApi2.dll"); " @- L' ~7 s8 r; w2 ]
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); ) n2 W2 O4 U( l6 G$ F
if (!g_hHook)
7 i3 {% i! c; B* k* B{ ) O( C. H& x% Z6 g6 E% K' ]8 f
MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK); 8 q B% N& t+ h( f& s
return(false);
0 r2 P, e' \, P! B2 l! H }
0 h v6 N# h( m ? . ~/ q9 H" B. n1 x1 N1 Z( ^
' {7 x( c! ~$ s$ x return(true); + t& x+ l a* Q2 r, ^8 a4 `
}
2 A8 K/ E( x, O4 u- EHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
+ P- z; |* E. b7 w{
% `" ^) @5 F8 K; @& x7 f% u
/ z$ D+ H( G3 z* C2 ^8 t9 s1 v return(UnhookWindowsHookEx(g_hHook));
5 @7 Z7 f ~9 I* E' \- a} : M- o. G$ A' ?$ l: u
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令 9 L7 g) K2 q V% U4 h
{ ( R4 p* H' y5 C' ^, n+ J$ ?
hModule=LoadLibrary("user32.dll"); ; E H. I2 J2 M
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 6 w3 G% r" w, ?+ Q% w
if(pfMessageBoxA==NULL)
& g: ?# [/ r5 g. I5 ` y$ T' [ return false;
; X H; W& e7 v _asm
, ]. h) X% B. G! f { . z1 H8 q# I2 l: C1 N
lea edi,OldMessageBoxACode
, Z( V' z4 |8 n7 E7 E" v$ ~. `9 Q% ]$ W mov esi,pfMessageBoxA # X e& B5 F( Y' v; z
cld
2 F' {6 y* S* s$ q movsd " g# }$ X. O% J0 j V
movsb ; L8 ?% ]9 N: v4 u# l
} . ?. z2 Y9 }, |, F8 O- {" i
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
( p) I9 X1 w; ?6 e! U0 h, e _asm
) V* y8 ]* [. C, w) L {
4 ~, p* } S( w- e5 B# a8 I lea eax,MyMessageBoxA 1 @6 A3 f" Y4 N4 u; O
mov ebx,pfMessageBoxA
& k: G% a) x3 E& Z3 S* @ sub eax,ebx
^, U$ Z6 H; x X- F sub eax,5
8 ]4 n. k6 ?9 N mov dword ptr [NewMessageBoxACode+1],eax * T2 p% A6 r0 a3 Y3 L5 u
}
$ A$ l8 v/ o L$ U dwIdNew=GetCurrentProcessId(); //得到所属进程的ID % E; f0 F# I$ b6 p: X
dwIdOld=dwIdNew;
- z' \$ K6 T7 M HookOn();//开始拦截 1 R& o% h# n. l% w- O- I
return(true); # I4 C2 a1 t! r* A" W7 P2 k4 Z% r
} 5 o1 K T \" E+ f3 f/ n3 f, D
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 0 }( G. Q3 \/ @* D, T+ j# b! ]
{
7 x& F: K* h0 L7 s+ a& y) w' I int nReturn=0; " u1 @6 t0 J+ l, ~6 V- b
HookOff(); - [! y! k$ L% a
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); 6 e' G: d7 g+ o# ]* ^1 Q8 m4 f
HookOn();
8 h, T* F) Q% f# o% o return(nReturn);
5 ?1 t' u: z z2 F0 z, X" p} , D$ V; O5 U4 K+ r3 X2 \) {
void HookOn()
& v: \0 p5 z g. E* ^{
% ^, f7 @, x& j* x2 H! X HANDLE hProc;
& V+ f) |+ z" ?# w5 H2 ^ dwIdOld=dwIdNew;
, X- a6 x0 o1 r: p3 d' N# c hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
; K2 {: v/ F$ ?( ~( Y VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
6 H# c9 L- k8 |, w3 p4 w WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA 4 n& W F' l% d6 @5 D+ `( X# P( M
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 - P5 W |0 ]' Y x3 M
bHook=true;
) s/ r* J% O/ p} v* B) l4 G$ g) H, `+ p
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
Z" q( V/ Z. G H{
+ \0 Y5 j" j- |% p HANDLE hProc; , l! Q5 N8 {8 r- i3 p8 @
dwIdOld=dwIdNew; , l5 ~) E( C6 P* C4 C" H4 l
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); 6 z" u# F$ [3 z3 k6 j% {! `
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 3 X( V* S" h" h
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); 1 ^: S0 t0 Z9 c( \( Z7 O0 W
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
- s/ K7 K$ d- C; c% ?. @ bHook=false;
* T2 [8 C4 K/ |8 L} - f; F/ K" \! k( N% y' f( Z
//测试文件:
0 g, V* U( l( Iint APIENTRY WinMain(HINSTANCE hInstance, 9 i7 S( C( D0 s* F$ Y+ w
HINSTANCE hPrevInstance, , c/ g4 ]0 [% _* ~4 V
LPSTR lpCmdLine,
& w3 M; O. d; O+ _/ \1 H int nCmdShow)
: z) N6 b6 R- `. y+ `2 q. O{ # l \! K8 ~: M' k. A& C
6 m7 f- y, t. k4 p if(!InstallHook()) & a7 T5 D9 ?0 X, m, L/ \" \3 D7 r
{ 6 a/ L, G8 f! z6 g* F, V; p
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);
% c0 l- m% `3 R1 @0 n return 1;
1 ^+ ^& c8 s/ T, a2 z' z } & T+ \& [+ V6 `9 V9 M
MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 ( }! \, j9 i. w; b- M
if(!UninstallHook()) . h( q& l; Y! D: W9 k; S( ~
{ * U+ Q' w, c- G1 W! `3 r# V! x
MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK);
1 T& g! o, |/ k6 n4 P return 1; 9 S2 V5 h R- Y( ?/ O% Y
}
- B# m! Y; G, p b, n return 0;
7 k0 ^9 {9 }1 T& J" I$ T) r}
5 `( i+ [3 Q4 H1 h5 Z[此贴子已经被作者于2004-11-5 18:12:27编辑过]
3 k' @* L. t, c, M3 ` l |
|