|
4 Q5 p5 N/ V- @
发表日期:2003-10-30作者:tomh[] 出处: 8 D Q) X# Q- d# b" Y
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 ) x" Z0 c. x! [
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, ! V! f x, B6 |7 M" `1 @* f, A7 ]% U
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
/ Z3 e4 B( {+ L: `9 d5 b" d; L/ Y8 K BOOL VirtualProtectEx(
9 o: N' I% q3 O HANDLE hProcess, // 要修改内存的进程句柄 1 q. o1 C' W- f: \8 n! \5 y# D0 A
LPVOID lpAddress, // 要修改内存的起始地址 * A9 d/ H4 E2 z0 ~9 n4 d
DWORD dwSize, // 修改内存的字节 5 E4 l8 S& I) D `
DWORD flNewProtect, // 修改后的内存属性
& {0 _8 T0 e( U" N& g- Z& B( `4 v0 } PDWORD lpflOldProtect // 修改前的内存属性的地址
) J" N* _! @7 k ); ; Y0 |: Q# U' G6 r5 o
BOOL WriteProcessMemory(
# w) A/ y5 R8 u) L3 x HANDLE hProcess, // 要写进程的句柄
7 X/ o! {7 Q9 l LPVOID lpBaseAddress, // 写内存的起始地址 " S( o8 t8 K) `( }$ c9 ^
LPVOID lpBuffer, // 写入数据的地址
, N6 v0 L3 c: ? DWORD nSize, // 要写的字节数 ' f7 L4 h3 l2 K8 E+ h; I
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 % A( A, [2 v/ l$ ]; f7 L
);
; V2 e0 K3 d2 r BOOL ReadProcessMemory(
0 g1 U8 o- g, d3 N$ {3 m( ]! { HANDLE hProcess, // 要读进程的句柄
* | {1 [) p' j+ M M% i+ y4 P LPCVOID lpBaseAddress, // 读内存的起始地址 ! [) o/ k( B. C, ?& C" ?# ~$ X
LPVOID lpBuffer, // 读入数据的地址 . i% w5 a7 K" A- S. h
DWORD nSize, // 要读入的字节数 # F$ P3 F% \6 [' a$ {- h4 N6 k; ^
LPDWORD lpNumberOfBytesRead // 实际读入的子节数
) c0 M( a6 p1 y/ |0 N. O! H/ Y* j );
: f5 f6 v& {1 W具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
) ^$ t3 {2 j' @+ e) y因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: 9 O% r- W2 t$ |# o' C( f
其中Dll文件为:
7 H% p* [& n! p& O HHOOK g_hHook;
' d6 j! k& ]- e& e# w7 S# I HINSTANCE g_hinstDll; # s# N0 S* [6 Z c
FARPROC pfMessageBoxA; + R; c6 f/ X+ r# E* S( ]
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); 8 y- Y- b9 ^1 w9 y+ }! {, E
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
9 x7 i$ x- h% D% V' V HMODULE hModule ;
% i! w- ~# X* d DWORD dwIdOld,dwIdNew;
. v% y% y8 p6 G1 @4 k BOOL bHook=false; : r; v4 }: q) U3 m
void HookOn();
! ^" b5 _! b- g, a5 b& e void HookOff(); 4 a( P! H' b6 `8 @2 m4 c& _6 a
BOOL init();
" X( O1 V! S) k: s( b, }LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
3 o V, W" r% x5 c1 RBOOL APIENTRY DllMain( HANDLE hModule,
4 G+ B( a. k7 \( e0 s" T) f DWORD ul_reason_for_call, 9 e6 C* i7 A% l7 Z9 M% X+ x
LPVOID lpReserved " ~1 f6 [8 r8 i( O
)
5 M- F$ b) k4 q/ q1 J{ * T' r+ [6 S) O6 z; u( b
switch (ul_reason_for_call)
+ b) u* ^7 y1 F& w( x( {" q# n { 9 B6 D) k$ e6 w7 g% _1 ~, r+ L7 d
case DLL_PROCESS_ATTACH: - e3 o0 z3 J7 H( O* d
if(!init())
, [ @8 U/ G' b3 n! J4 y8 F! `, x { ) P4 t- `# \2 m: U# p3 u, S7 e. D
MessageBoxA(NULL,"Init","ERROR",MB_OK); 9 B5 U. M" z$ L, N# ~( h; l# l
return(false);
" h2 J( v" h6 t$ w- m) @ }
# \' E K6 `' y9 x case DLL_THREAD_ATTACH: 7 P1 f: a, a6 P: X2 V7 p H
case DLL_THREAD_DETACH: - `+ k) t5 k, A p
case DLL_PROCESS_DETACH: * u1 L' _; t/ H# }6 y6 y
if(bHook) UnintallHook(); . a1 v! ~6 p2 g- T+ o3 w
break; ) x$ s3 v4 c- v! g& [
}
$ f2 k, e$ l9 O: V return TRUE; # F. [3 x( {/ E7 q9 ~0 A
}
" K) O- H' O. sLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
6 T: R9 A5 `7 Z. y{ / l' w4 x6 L* ^* g @9 @4 m- c
: }. y1 [6 T' ]( ~9 [& I
return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
+ `: F( F( a: q& q/ P0 N}
6 j5 |! {5 g; VHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 3 ?7 L1 u6 H5 H& V3 c% [
{ - ~8 E2 v: P9 a* P: \* u$ B
g_hinstDll=LoadLibrary("HookApi2.dll"); / n' ^9 t; f- C- S2 g
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
) T" I$ Q; m! V! h# M8 Uif (!g_hHook)
- O) s3 B: b4 M$ d _( f7 W{
1 M* G$ B4 T+ d' y. y MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
: b% S& H' f% h3 O$ F return(false); " h& O4 I2 y0 h3 s
}
1 I1 _( h- h# m9 w0 h6 }1 Y 8 ]' ~* ~3 O! b/ u E
7 t! o c$ K' X- }6 g return(true); 3 x7 h# ?2 N) I y4 h/ P& l
}
& ?9 F! t* ?+ @- G' Q: T) t& VHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
0 @( ], ?6 y9 M{
3 _9 C- ^( P l4 [3 R
: Y' h' V0 D9 ` return(UnhookWindowsHookEx(g_hHook));
2 F; {6 W* T4 a0 j$ a' E7 W}
6 U; n/ ^: t }! `! ZBOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令 $ z; q, Z/ z8 |+ z( u: O& n- {+ Y
{
6 c4 }) I# g, i& H hModule=LoadLibrary("user32.dll"); ' T: H0 j$ Z8 m3 }
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); + |0 q, z4 W6 r+ E& E
if(pfMessageBoxA==NULL)
3 c) d. J9 }9 f return false; x6 i3 S$ u0 w- ^( l
_asm
2 ?. D' |' J1 P {
8 t$ S1 U, P, a6 t, ?0 o- N lea edi,OldMessageBoxACode
% Y. X; n/ u9 q7 a# h% M% E2 j mov esi,pfMessageBoxA 8 g% t) F1 x$ q5 f( i, ^" k
cld " v4 V! Z) g4 i4 R) n- \+ }" C+ z- x
movsd " |$ K7 Z$ n' S3 l
movsb - o8 N* E: T0 C- ?" X6 V: i4 O4 B. P9 l
} & T0 Z" |5 l5 Z. v8 X
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 7 K4 G7 Q: M6 i5 H. l" {8 u9 Y
_asm
; P9 z4 H' |: A, E! D/ x: [4 h% a) N {
4 J% y- m; x3 {; I% b3 R lea eax,MyMessageBoxA ! O7 ]( m* m8 ^
mov ebx,pfMessageBoxA & W6 G4 [6 s! T" w! b6 }, `
sub eax,ebx 3 s- t' c( g5 U8 R9 l
sub eax,5 2 ?: Y* ?* B% i! V2 j! O
mov dword ptr [NewMessageBoxACode+1],eax
6 a7 b" d1 G; `9 c8 o }
; U, u2 L# c1 j' j dwIdNew=GetCurrentProcessId(); //得到所属进程的ID 5 D2 s) s% }. S! |
dwIdOld=dwIdNew;
# a6 h+ t+ \% R! D' s* G: q HookOn();//开始拦截 & X) M6 d3 \& r
return(true);
6 B, v, i; ?" G" _} : P9 O! ]+ @7 R8 E) m& a( o
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 0 J3 H* q# W, F- L8 |; q J
{ ! j3 P/ Y. U1 J2 B% [- O8 k+ ?6 H
int nReturn=0; X$ s0 Q* j7 t+ t6 f* t
HookOff(); 0 X8 `# T4 ~( d1 H4 \% W2 _) x
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); [4 q" q( }, G' B
HookOn(); . }" \! m% y! a* _: a, p
return(nReturn);
: D) q+ {% e. [1 |! Z" l} 5 P& L0 Z8 v7 e5 O% z7 [$ K
void HookOn() ! E& m' T; d1 j6 g& N5 W8 b5 Q
{ ! u$ y3 J# h( ~% Q
HANDLE hProc; . P) s/ |# }3 Y, h
dwIdOld=dwIdNew;
/ J8 M- D7 ], m+ \ hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 0 |# `( y7 o8 K8 Q7 F5 p, q8 ^
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
: t+ O" ]4 R. W" E6 \ WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA * \* x: H. i& w# o
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 : K/ r- ?+ c( P3 v( L0 h
bHook=true; 5 ^( H/ s/ n8 B( c9 u) i
} - s/ n2 O) }9 n2 p4 y* A a
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA % _( F9 S( [) l) w1 v5 j. J2 F7 \- T
{
9 c: z3 Y) z' E- w+ S; D HANDLE hProc;
' c! _5 r( v) ~: @; W4 o/ f" e4 b dwIdOld=dwIdNew;
7 o, ~# R6 y% j% e' i9 z T hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); . b$ C/ n) C& B" ~0 H$ t
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
- B3 d. A! K4 h WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
5 e) x8 L( l6 d& F. n! q VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
, J2 D8 q w( `9 y bHook=false; 7 m- C6 y) U" {: O5 J6 ]: N; L( P
}
) q6 ]- c* R. X//测试文件:
5 _; E' f& B# @; ^! `4 _int APIENTRY WinMain(HINSTANCE hInstance,
5 G% o" T! X& |6 n1 L HINSTANCE hPrevInstance, ) \4 z2 O. O1 v( x
LPSTR lpCmdLine, ) u8 u# P V; O, `# Z0 _
int nCmdShow) 6 r O& r1 l) y9 }; r. I
{
|8 a9 O3 s9 [3 Q O+ W# q6 H) ^; _9 L! h1 {
if(!InstallHook()) 3 Y0 b4 U$ z4 W6 R
{
' m3 `" U( [7 ^ MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); % ~9 N8 @- k5 S2 ~3 t6 c
return 1; 1 c9 ~6 N9 i7 W+ }
} ) ], P+ Y/ J9 v
MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见
2 A/ H; x2 F& |1 R2 Q5 L: J if(!UninstallHook())
# n* ?7 t1 N" P& [7 o {
! ]0 v7 q0 t& s7 _1 j6 v& F Q8 [: O MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); 7 p5 V1 b) A+ {
return 1; : D! D' b: K6 Z( _# U8 c
} 8 ?3 @( t( N8 d3 {- t' G
return 0;
# y, a! F) `# h* p$ n" Q} ( Y% O1 n6 `0 A: i0 f0 z
[此贴子已经被作者于2004-11-5 18:12:27编辑过]
4 ~% |4 E4 U7 t |
|