该用户从未签到
|
7 `! { q; n% V6 o4 G9 w发表日期:2003-10-30作者:tomh[] 出处: 0 P, q0 v- S! t0 E$ M: W
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 5 D' j4 n# B. c( k
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
2 G9 A6 h" U% k$ T其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
3 f5 [; }4 Q+ d7 P BOOL VirtualProtectEx(
! O9 A1 |! X6 T% |6 u HANDLE hProcess, // 要修改内存的进程句柄 & x+ M- x+ U' V" z" M
LPVOID lpAddress, // 要修改内存的起始地址
! X0 t2 `7 n! t7 ]& t+ m; R DWORD dwSize, // 修改内存的字节 ( P) G' l7 ? s& D. H7 r2 w( d9 e4 W
DWORD flNewProtect, // 修改后的内存属性
0 ^" U; r% U! {: y' N PDWORD lpflOldProtect // 修改前的内存属性的地址 3 e/ m$ P2 k, @% q! Y
); 0 @. o" X" [8 E- e8 ^' e+ ?
BOOL WriteProcessMemory(
6 {5 w3 H. o( I D T+ U1 B X3 | HANDLE hProcess, // 要写进程的句柄 , ^4 A# o0 S" L- V6 n
LPVOID lpBaseAddress, // 写内存的起始地址
9 Y5 p8 E! _3 h LPVOID lpBuffer, // 写入数据的地址 e' V: o- n- u/ y
DWORD nSize, // 要写的字节数
0 j6 E" U4 U% A# j1 K# {0 q% @, S LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
- a- w: `1 u+ h C% c! b4 q4 | );
! V, l9 z% k' _) Z! L BOOL ReadProcessMemory( : ?; [' D. n( ^
HANDLE hProcess, // 要读进程的句柄
- b* L1 k8 j4 i* S% _4 C" U LPCVOID lpBaseAddress, // 读内存的起始地址 " q" Y( H& G& f
LPVOID lpBuffer, // 读入数据的地址
* \) N) `6 K3 ^; P% E/ g DWORD nSize, // 要读入的字节数 1 r# n, p: |$ l0 J" L2 F
LPDWORD lpNumberOfBytesRead // 实际读入的子节数 2 h D' y: ~+ \' s
); _- x# F6 N0 E1 H3 G2 |
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, * m+ t# k2 o) I( \8 Q& W9 X# f- c
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: : R! o& Q" y# n2 k* B) i
其中Dll文件为:
# {- ` o% o2 W% y( c" n! l HHOOK g_hHook;
) H; N' q0 r" B# k7 t HINSTANCE g_hinstDll;
3 k4 ?9 v5 R! ]3 s/ V f FARPROC pfMessageBoxA;
' B3 Y# y/ L: g# {! f5 E int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
* O/ ]$ N- g. {8 Y+ o. C/ J9 s/ T BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; : q* x( i8 a, o) M# Q1 @
HMODULE hModule ;
7 j) f" w( n& b DWORD dwIdOld,dwIdNew; ; h( C! k7 Y+ E
BOOL bHook=false;
' y% j1 e4 G8 ]' p/ N$ v# x7 ^ void HookOn(); , X) j( r8 D. I1 {9 ]( T+ [
void HookOff();
' ~* h0 l$ a5 Z+ | BOOL init(); $ M1 [0 D7 [/ F1 h/ a
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
% A! V+ ?0 B/ h- }' y3 ABOOL APIENTRY DllMain( HANDLE hModule,
6 B+ l8 V! `/ [' C DWORD ul_reason_for_call, / A: o( A9 J$ T5 @
LPVOID lpReserved
9 v$ S* m% U2 B1 L. w( F )
2 f2 N+ L2 Y. H/ p. |' B8 u( Q{ 5 k" `+ O* [5 H7 o/ q# r5 W3 I
switch (ul_reason_for_call)
7 g" Z! ]" v8 y7 X2 G# D3 J: H { # v; v. A# x3 i Z
case DLL_PROCESS_ATTACH:
% M' K# `' _4 |* I/ \9 Y if(!init())
9 w. t- v- S u {
9 a" \- R" F9 k5 m MessageBoxA(NULL,"Init","ERROR",MB_OK); 7 ~( N3 q, h: n: T8 f
return(false);
0 l) ^* I) S+ \! g3 h9 k; h } ; N6 @. x) \* w3 i# y& W
case DLL_THREAD_ATTACH:
; T* y7 g6 P& S5 M+ R4 s- g1 U case DLL_THREAD_DETACH:
! [ I; F4 B3 x; H# \) g case DLL_PROCESS_DETACH: % v) U. ~2 P' u$ G" j( U7 n& \
if(bHook) UnintallHook();
. F+ G" q4 `* _ break; 5 u' {% ?* W& q2 t
} # V8 [- j1 N% H: K
return TRUE;
0 r% ?& K, B9 m/ h/ X! Q6 P} 9 j6 a8 f8 x. r1 O; u5 A9 g1 z4 x
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
1 ~8 X0 k) C2 Z2 J{ 7 B! Q9 Z: A8 l, F8 [2 J3 y
+ L u" |* S2 j# N& d& |7 c' T4 [ return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); + w0 G5 x# c4 W; ?+ ?- p! n
}
3 r& s3 ]+ r E8 MHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 : u9 z) {$ H2 Y0 m7 E% k
{ $ W/ }% A8 V4 m+ {& i, S
g_hinstDll=LoadLibrary("HookApi2.dll"); # E* `& H2 p n+ U# w
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); , n+ G8 G y6 v9 W: g b- N9 u) y$ A
if (!g_hHook) ( u0 g! E* C- Y5 m
{ 1 ?* Y5 ~9 ~8 k2 p8 G2 A, z7 h
MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
8 C) ^4 ]3 k! m- T% G( Q return(false); # I7 W( A# ]: e4 k4 B# y! [* O
}
) M. d+ `0 s: z% f0 @$ z& t# \
, e: z" Z' \7 \7 e$ S $ s5 w2 l4 a5 [- g2 }1 S
return(true);
0 I7 b( U, D6 v r}
% u7 l8 J; U- `/ M( fHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
7 a7 \$ s8 @" c) \! |6 I/ q{ $ a% {7 A- y$ E, w
/ D" s7 z( W8 M0 M/ J
return(UnhookWindowsHookEx(g_hHook));
3 V' H7 O: m& Z2 r& m0 t' d} ( N+ ?6 s3 b3 o
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令 ~, d r2 I* @" c4 F
{
1 U% K3 P5 ~% e/ h6 [ hModule=LoadLibrary("user32.dll"); : k" V; A# R' X# A( O" J
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
2 d3 w; C7 W+ J: M( f if(pfMessageBoxA==NULL)
( |, [: O# K. ^* r7 X return false; " U! x F, o* c: S$ }2 F' P
_asm R& _- p* e( H, u
{ ! N" h4 G% [! W& F$ g
lea edi,OldMessageBoxACode
# b" ?, X( C% ^6 a' ?' f# s+ i mov esi,pfMessageBoxA * K3 k2 _3 \7 J2 k1 e
cld
: E' a) N. l2 Z- j& w movsd ' w8 E `4 h0 L9 i D' ]- J/ z
movsb 3 p. Q& O; U( ]) z/ ~ |' I" ]' z
} : w1 ` \" }6 w% }( I+ H8 t2 ]8 {
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
- q0 F" I9 f" E _asm
+ N, V! m, S- `; S: \3 S. c {
2 V. Z" G- e# J! [) v lea eax,MyMessageBoxA
+ `8 M9 m) T: b9 v" c; V. y% h9 X mov ebx,pfMessageBoxA
* Y9 z0 ^: \3 D2 w+ Y$ J7 }' E sub eax,ebx
: ~/ m& h* a+ ]* S: a sub eax,5 , E/ T' r7 W, `( }! K3 P9 R4 I2 ~
mov dword ptr [NewMessageBoxACode+1],eax ' o2 P/ O6 W, ~+ R, A/ J4 g9 O
}
2 z7 C. j+ u. X5 o9 E dwIdNew=GetCurrentProcessId(); //得到所属进程的ID , w7 ]( A+ G5 ^% [7 S# J4 }
dwIdOld=dwIdNew; + c5 |% j- z, c5 B( E9 }; c# }, G
HookOn();//开始拦截 8 u2 ]0 U7 n5 f
return(true); + O1 I2 H5 Y H. z; i) a2 U
} 5 S& E7 m, A4 Z; v( i1 q
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
( _$ q- X6 I' v{ * C( G/ Z3 m- g. Q# Y( Y
int nReturn=0; - @$ ]0 c8 U# @; u* b+ |! J
HookOff(); & r6 O2 `: K8 S* I0 ]) {
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); ; E7 n$ ?* N+ q2 s8 @
HookOn();
9 m: o8 u5 s2 ~+ \1 X return(nReturn); 0 J" @, [0 b+ K E
} 2 L3 C) ^( j3 g! K) S; K; V) G
void HookOn() ( l( f5 h. j X, t
{
) D: _: s1 ~) H, S HANDLE hProc; - V1 M, a$ G6 k* W( W& x2 \
dwIdOld=dwIdNew;
: Z" S2 H9 h4 t" @5 @) w+ w. ]- v( a hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
9 ]- R" X' c- t, D5 p VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
+ D ?6 l5 C! ]# a& `9 L; W; Z& O WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
" D/ I) Q3 v% X! t( a+ Z+ @% U VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
" ]' a. C, L+ G( c* | bHook=true; 9 ~3 U4 r% H2 ~& R# k' t
} % L" ]: ]8 i }8 Q9 ?
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA # u: N( @" Y6 O8 N: _
{ ! ~: y3 C' h) R
HANDLE hProc; ( P% G' O% o5 u( ]% j. o" {
dwIdOld=dwIdNew;
: L2 |; K, a$ w3 B) M hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); 2 m+ S" Q& f$ a( f$ _
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 6 H; V0 S& d( {9 M- ]
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
3 n- K1 M, V$ Q0 y- g VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); . O2 ~& r. a, n
bHook=false;
2 X4 t/ y! L" E}
; M( x% |% k3 b5 J//测试文件: 7 t9 h* H; j; E- u- \
int APIENTRY WinMain(HINSTANCE hInstance,
# I: X/ c( K2 [& B2 x8 U0 k# p HINSTANCE hPrevInstance,
" |8 ]1 b* Z8 n4 k$ ^: w y' K LPSTR lpCmdLine,
6 r/ G" i6 O0 a$ [; |9 N; T( G/ M" f int nCmdShow) . e( N- l d& j- U, ~
{
! z) R3 G \- ]" Q * U% L9 h1 t7 E9 }
if(!InstallHook())
6 F# E- H) U$ W: I2 S { - u/ a) P, i P& ^0 }
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); 3 _! S+ `( p& H. R/ o3 y S# a
return 1; 4 G+ L, n4 `6 |0 H3 i
} & @5 R' ?' c8 y
MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 ( \' g3 v& H1 e& B
if(!UninstallHook())
* z+ L7 m: g( m; ~6 u: U: o6 F. d E { 6 p. M. Y9 z* Q$ ]- {3 O! g7 H, T
MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); , v4 r6 i; d" M: t/ a# \. t
return 1; 0 L6 D9 `7 P& x' b
} 3 w+ B+ `: a o& S2 c2 S. ~
return 0;
- r1 m' }5 ~+ b. O$ e}
8 y: w- t) G0 I; U[此贴子已经被作者于2004-11-5 18:12:27编辑过] . h, B( M5 x' w* G" y# H
|
|