|
9 t0 [ A* y; }$ Y8 E
发表日期:2003-10-30作者:tomh[] 出处: & x+ D0 [. ~) ?' Y, ]) S
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 % e _% l$ d2 i; e3 M
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
$ M5 g5 D/ i6 j6 s. Y9 @1 s其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
J" `/ s; q _; p8 ~ BOOL VirtualProtectEx(
/ K4 n! @) s) U' _4 Z W HANDLE hProcess, // 要修改内存的进程句柄
" @4 ^( o/ @' [; G LPVOID lpAddress, // 要修改内存的起始地址
9 t) M' P' t& U, A9 Y/ s- l DWORD dwSize, // 修改内存的字节 4 l9 D/ ]. T2 {, A( z
DWORD flNewProtect, // 修改后的内存属性
, v1 F' e6 s% F- {5 f j PDWORD lpflOldProtect // 修改前的内存属性的地址
: V- ~. R- w. C3 L$ L* U1 b: N );
3 h+ w* m& i. V" O" J0 c BOOL WriteProcessMemory( ; z' N* J! I( T" `8 Y# m& O
HANDLE hProcess, // 要写进程的句柄 * _6 s4 w: c! N: b5 a
LPVOID lpBaseAddress, // 写内存的起始地址
2 j4 f+ B. g$ d( Q C( w7 Z LPVOID lpBuffer, // 写入数据的地址 : O A6 j' Z0 M! B
DWORD nSize, // 要写的字节数 2 } ?6 \2 \$ a1 x6 C6 q
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 8 G$ [ p+ t5 k
);
) J- b; l+ Y! g; s1 K8 h BOOL ReadProcessMemory( ; r$ M' U; S/ _) V) A- ~0 v
HANDLE hProcess, // 要读进程的句柄
9 P/ j D c) P; H1 a LPCVOID lpBaseAddress, // 读内存的起始地址
8 o+ f% o2 ]# J; ]7 y2 f I" c LPVOID lpBuffer, // 读入数据的地址
! ^$ K9 G) p' P3 t- c7 \$ g DWORD nSize, // 要读入的字节数 4 o. Y# ^" p O/ z B2 i+ f
LPDWORD lpNumberOfBytesRead // 实际读入的子节数 c0 R# ^3 o6 ~
); , b) b' L) }4 E! R' Y- ?8 @
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
$ T% ? k$ R) t% T9 U( G2 v$ Q因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: * i+ ^$ q$ K* D% X" w C
其中Dll文件为:
: \6 [4 F" J! ?( n$ O HHOOK g_hHook; 0 F0 ` [9 g; v* b5 y. s
HINSTANCE g_hinstDll;
, d: f+ z- M2 J$ G FARPROC pfMessageBoxA; 5 O& f0 k) @8 S5 C; X+ f: t
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
6 V3 ?7 I$ g( q- y& l; c/ Q BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
7 b$ ]0 W1 |" G# v+ U. N% g2 M HMODULE hModule ;
l# R! S6 C' o' h1 r5 Y DWORD dwIdOld,dwIdNew;
$ z( A" W+ ]0 N7 p, | BOOL bHook=false;
/ v* w/ X: o' J- s5 v7 R$ ?4 @ void HookOn();
5 h j* J: J0 x7 d2 J. O" @ void HookOff();
5 D' n7 O- M6 [9 S BOOL init();
2 |. O b6 J# C* aLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
/ Y; [, d# S0 f. m1 x7 R* XBOOL APIENTRY DllMain( HANDLE hModule,
+ \ d& ^1 o M" V! M5 _/ w DWORD ul_reason_for_call,
& z- z/ ^2 }' J* n! } LPVOID lpReserved
* r% a8 \9 C2 s! @' p" {) s% P ) 0 [0 g5 q( Q0 \9 Z
{
+ k, z$ G$ v& k6 R" _, b switch (ul_reason_for_call)
+ q }6 E- f5 M) T; ]( V {
3 N- s! H( S3 D case DLL_PROCESS_ATTACH: - H4 g$ d) d6 c" h: V6 |
if(!init()) - I9 t; |, P; P- K
{ ( W6 ~" Y& @7 I; i. \
MessageBoxA(NULL,"Init","ERROR",MB_OK);
4 v. [; A0 _8 [! ]# n3 y1 V% h return(false);
. e! O* R* y2 e2 b R3 P }
; b B% ?- F' w: o case DLL_THREAD_ATTACH:
& V* P8 F3 u* L* F" t- S0 t case DLL_THREAD_DETACH: 5 X+ l; D, T+ N0 L2 o( l
case DLL_PROCESS_DETACH:
& [( w0 H# l+ @ if(bHook) UnintallHook(); 7 d' e2 K$ T2 P' a; F- M. m
break;
4 A% v* n2 x0 H; ?. J } 4 l' U5 t) u, B F3 {- c
return TRUE;
8 O$ Q5 j% X3 n- H}
: g% j! q y' w/ qLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
& y4 P- v( X' d$ `$ r: n: g{ 4 D6 U# r/ N+ W6 H; _. ~% ?
% `, K6 e5 M5 v, F; T P6 ?% R
return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
& t6 i5 z3 k% G: ?} 5 Z- G0 x. e: G! j8 X' W
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 9 w( m2 _7 E8 g% g8 ~2 ?; H
{ 2 w, \$ k& M" H# [$ X
g_hinstDll=LoadLibrary("HookApi2.dll");
# ?- W D. [0 ]) V g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
* h: C' F; K( b/ Y7 V. u- Xif (!g_hHook)
7 }' u4 V' Q( t{
, i% h2 |9 P& f; O: H7 @ MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
* g: W" C* k( Q' X7 I. h return(false); ( A+ \& K: x5 C
} ' X: h7 _" ]+ r% I; o; r) a* B# m2 F
% V5 |; o+ t- |, M& V& m' a
. B: q) E. i% E/ W8 e
return(true); $ l: D$ ~1 R0 Q$ L+ Y$ ^5 e0 C
}
. t8 ~4 W1 j2 ZHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数 1 p3 v5 P; A) W+ [- p: [; b
{
2 }& G9 U0 z, o) |; x
4 w$ d t( O1 A8 {2 `. X/ ^ return(UnhookWindowsHookEx(g_hHook)); : x' h& }7 k$ X' ]8 _
}
$ V3 V" N0 p. r5 _# C6 MBOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
- h9 b/ @) q" F8 I! h6 D8 S7 d{
2 H7 i* Z0 Z# g% \% O, i; d) | hModule=LoadLibrary("user32.dll"); 7 q: \; @& i- ^% E# |- d2 l
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 6 G0 p& H1 p$ r% p
if(pfMessageBoxA==NULL) ) \, f& w0 i9 t
return false;
" j8 p0 {2 Q/ d- F _asm
/ D5 ]1 e0 x- G! J { / i+ U0 B) |1 p8 c% K: K1 `3 H. g
lea edi,OldMessageBoxACode # u) `( X! b% r( P
mov esi,pfMessageBoxA " J; B# n9 i- [' m
cld
9 G: x; r, N* Z movsd
/ O0 l @! ~- V% C9 b1 D# [ movsb 5 y, y( M$ L$ M0 M$ f; ]% j; H
}
1 f0 n1 n0 N, l+ M' y NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 ! Z1 D0 {8 O; D
_asm 7 z( u& l- e. x: ~% I/ H6 o
{
) \7 G/ B. O1 w! Q3 M ^: C, S9 m lea eax,MyMessageBoxA
$ h) u( A# x0 b5 ~5 K mov ebx,pfMessageBoxA
5 J+ ?" l+ h+ t; o7 B; U sub eax,ebx 7 H/ ^9 u. R/ I' B# t4 W
sub eax,5 6 C4 d% H p; s, r+ a( z
mov dword ptr [NewMessageBoxACode+1],eax
* c% \) u& `# o* M9 W, C }
4 h7 p3 l; x* A1 w& t dwIdNew=GetCurrentProcessId(); //得到所属进程的ID ; m( O0 o3 H4 ? s3 L: S
dwIdOld=dwIdNew;
; p5 j0 e" q2 g% |7 X4 d3 C HookOn();//开始拦截
% U6 I! A8 v( e' e/ T return(true);
% u$ Q$ d9 @) s* g2 C}
" u& Q& |7 r* p6 h; Hint WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 U: T" P5 e2 q$ N8 Q5 ]
{
( R9 }1 O' y9 U5 D4 ~2 k- v/ B int nReturn=0;
: z8 k# ^2 ?( N6 ]; H T HookOff(); $ y- E7 Z/ x1 \/ P0 i
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); : A% I5 L5 o. {# J/ b
HookOn();
- m+ ], {/ Y7 x$ ?' @% y6 _ return(nReturn); 7 j1 ?8 e# H: H) f' t7 i9 B
}
$ h" `+ b: G7 q( A6 n& }void HookOn()
$ H' R" q Y! V/ W' T; b7 Z1 }{
; |1 Z3 r& D6 Y% E, F HANDLE hProc;
# u# J0 C- i8 L dwIdOld=dwIdNew;
9 p" l3 k" ~9 V4 ?$ [- F- { hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
0 A2 k" H* }2 ~# u VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 + N! T5 h* [3 p. \
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA % k9 H0 w5 j3 i# _ e' N( q6 s: r
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 0 n5 ~1 ]/ `6 `$ Z& x
bHook=true; * M+ X) R0 W2 A, `* v, ^, w3 w
}
3 Q ?. i4 M) C: O" Svoid HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
6 L4 V" j# ]1 b& H6 t. f{ 5 F' N, p' a8 D
HANDLE hProc; 8 K) I! }! L4 R n
dwIdOld=dwIdNew; $ z: [5 a7 |* I6 L1 C: S O
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
: L; w9 B- i- V8 ] VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); ) y! `0 ]- `5 Z
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
" i5 L5 H4 K! Y" L+ k5 _' u VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); % a0 I* M+ [# R0 p
bHook=false;
% }/ w" \# x* b: X7 S}
7 U7 \# @/ ~4 z* x2 N) g- H) Y//测试文件: # m! C! Q, Q+ I1 T* w! q& n @
int APIENTRY WinMain(HINSTANCE hInstance,
$ ]' [" _6 ^, t% D0 F- @ HINSTANCE hPrevInstance, ! ^% E" ]# ?8 J0 _, d
LPSTR lpCmdLine,
( k9 F, a$ {2 L6 k+ N; @ int nCmdShow)
+ j& w. B' ]5 t; |/ A) ~5 B{ 8 k# p8 w% h- F- o& V1 | w
. u* ?: I) Y0 k* u4 @6 m
if(!InstallHook())
* r0 i& E5 j& W; M { * C6 o+ g2 [: ]
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); & k" u; K5 O/ L. W% X" x4 z2 e% r8 R' o
return 1; 8 J- e N" {7 u* m ?# d+ d9 \- z
}
+ F& {& W9 L& a MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 9 U/ W1 p6 q; y1 H$ j: i
if(!UninstallHook()) 4 {: D! g* h4 v! }1 M+ p
{ 6 v, m% @& K! ~
MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK);
3 U) ~9 p& E! e# y1 h& W- n return 1;
w" Z7 H. M/ _$ |8 c2 P- H } + W1 E9 t3 m& [- y7 h8 ]0 O' A7 K
return 0;
2 X9 X* p" f2 ^} 2 l( v: V8 N5 t( Z3 A8 H7 F
[此贴子已经被作者于2004-11-5 18:12:27编辑过]
; q7 k4 w1 B6 |+ V |
|