|
5 j- n1 Y8 v% h2 l& v; a* z8 o0 l6 E发表日期:2003-10-30作者:tomh[] 出处:
! [) L) {4 l" w: @0 V) y2 C) G# f$ }Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
$ ^5 E& S ~, w9 @5 ? 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, 9 l! {, S* f6 N" \8 _+ F
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: - b. I1 Q/ B1 g- ` ^4 h$ Y0 y
BOOL VirtualProtectEx( 9 e. {7 Q# E& X
HANDLE hProcess, // 要修改内存的进程句柄
& f4 w4 K& x- n+ V+ Y/ S LPVOID lpAddress, // 要修改内存的起始地址 ( ]- D. ~- `$ c3 [# {3 S( J$ N0 x
DWORD dwSize, // 修改内存的字节
+ Z, y# R) V# `2 V% T DWORD flNewProtect, // 修改后的内存属性
. q4 ]' x; ^* {, t4 Z- k& L# y7 r) l PDWORD lpflOldProtect // 修改前的内存属性的地址 8 H! Y6 ^, H: c
); ! D [( q$ S* Q5 @5 K3 q! Z$ q
BOOL WriteProcessMemory( 2 C- X1 E% y' O- l, X; F* v& q1 V* |
HANDLE hProcess, // 要写进程的句柄 ) I; j0 v/ \8 Q& Y( r! E
LPVOID lpBaseAddress, // 写内存的起始地址
$ ~* @! g8 {1 I4 R7 E# ] LPVOID lpBuffer, // 写入数据的地址
9 w" y& j+ U; `7 \+ m, M DWORD nSize, // 要写的字节数 $ Y$ Z' A3 I. O! t& `
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 1 h7 M$ E1 L* h3 L) W; m7 ?7 G
); % b# P7 z% G/ }2 P
BOOL ReadProcessMemory( 1 G6 e( ~% Q1 H( l+ q$ a
HANDLE hProcess, // 要读进程的句柄 ; D5 t" O( i6 b+ |; ^- s% r) K3 A
LPCVOID lpBaseAddress, // 读内存的起始地址 ( ?, V2 H6 r# R: o, t# @
LPVOID lpBuffer, // 读入数据的地址 6 X" y% \4 q1 \& u. V
DWORD nSize, // 要读入的字节数 , r6 u" \& ^# ?% o8 w
LPDWORD lpNumberOfBytesRead // 实际读入的子节数 0 }% X* p1 |. h( N/ x, h
); " @1 v/ c2 c) R& B X" C
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
; ~) ~1 B9 ]7 L( I( p) C5 h因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:
) | L( ^, f( U3 J4 V# L其中Dll文件为:
3 T3 l* l( D# l3 N8 }: Y* S HHOOK g_hHook; 9 {) H. F3 ` C1 i8 _# p. k- L/ I
HINSTANCE g_hinstDll;
5 j6 v: [" O4 Q j+ k* t* ^ FARPROC pfMessageBoxA; , D; @, @3 D$ p( F% e: W
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); 5 x+ Y" ~( j( a2 `+ F7 r4 a0 v
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; 9 O' t! [, i! O* \! W2 i+ `
HMODULE hModule ;
1 F6 X3 t1 E+ t7 l8 F! ? DWORD dwIdOld,dwIdNew;
) J' Q# D. ]4 j* G' @0 t! Y5 o BOOL bHook=false;
' D+ B4 q d1 D void HookOn(); 6 c" k5 O; c0 j
void HookOff();
/ u- P( ~% k& Q/ H( v BOOL init();
+ q1 s" Y+ q' [: H/ G) c( U5 [LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
' a- u9 y6 N1 v, h1 c0 L, X, `BOOL APIENTRY DllMain( HANDLE hModule,
& \, u5 w% N) Y; C DWORD ul_reason_for_call,
3 i0 ^$ a3 A3 D. _1 U LPVOID lpReserved 9 M5 F B7 t6 A/ T
)
4 E$ z7 i+ @/ t9 n, X2 Q{ $ K& j; D! E2 J4 X
switch (ul_reason_for_call)
. U/ h j2 N. r1 o0 K { $ i( s% r/ T6 c9 u
case DLL_PROCESS_ATTACH:
9 X# i& d# @. v5 a! z if(!init()) G4 R, ^+ Y$ R- v- S3 \
{ ' u" ~" V3 m# o* ]. j
MessageBoxA(NULL,"Init","ERROR",MB_OK); ; e6 O8 O; \ H" e
return(false);
% e% L$ Z# E: P" g } , ^% E5 K* ?$ h. t. Z2 @1 k) H
case DLL_THREAD_ATTACH:
! c v0 F( Z* U7 h: S. j7 }" y case DLL_THREAD_DETACH:
; ?: C* e( L1 k- v5 C! v! ^ case DLL_PROCESS_DETACH:
0 i( J/ W5 ~% ^& l, E& \ if(bHook) UnintallHook();
$ S6 O& I6 R* ] y. C break; & G' c4 Z4 c' H, \3 L% p! L
}
( H# c5 X2 Y7 ^8 \# r7 C: W return TRUE;
3 L" x, ?. e4 p0 x} 5 U( F9 b7 S8 n9 t5 P+ w
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
5 `) B. Y/ |9 w5 K5 a{
1 b% E7 ]. r8 s+ u# \ 7 f3 T: q0 O- p9 y; M
return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); - k2 _# q# c2 J. g" o1 v$ q2 X
} 3 ~, V' H3 v% g+ Y( |2 ]
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 , n* }% {; X& E/ j5 }9 L
{ 1 O/ [8 E2 ~ _: G
g_hinstDll=LoadLibrary("HookApi2.dll"); ) k' f+ e8 p+ a) v3 B) C
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); ! {; m1 _8 }6 H1 X5 W+ \
if (!g_hHook) 3 Z2 B+ v# {# C5 q7 g2 s2 P G- n3 g
{ ' \" u7 {" f( n' i* [' ]* t
MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
$ K' J$ q3 ~1 |' Y' ]) P8 U return(false);
, @ |7 f8 Q+ I8 X* c2 w7 ? } 9 l7 }$ {0 p h3 T
8 G" X' J/ c2 o( J
2 [# y6 _4 P1 D( G
return(true);
. r6 W4 D1 D* n3 n* c5 s}
9 d8 h3 C5 |) C2 \: }) h7 u2 oHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
$ ]- A& w+ _8 P" Z{ - q# A8 v2 @6 l# h- I e+ J- s1 a
# y8 ~6 G1 X! f q% g/ [1 n
return(UnhookWindowsHookEx(g_hHook)); 4 z& a/ E4 t$ ^8 R1 p, K
}
8 p% C0 V. k% A+ t' mBOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
2 v3 f. @7 `0 r; X, K* X{
* m: |6 N6 ^+ _ hModule=LoadLibrary("user32.dll");
8 t4 M. K3 _1 x5 W% X. R# z- T& w pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 1 a2 S- G, K6 X) w8 M4 t6 X' O
if(pfMessageBoxA==NULL) 8 G0 ~9 ]6 p! k
return false; ( ?+ v- n! Z' o
_asm ) v% K' l% _- N4 e. V
{
8 t6 w& ^. l2 B+ A' r- z5 a; i lea edi,OldMessageBoxACode # m$ I6 J9 \/ _& E
mov esi,pfMessageBoxA
9 _4 Y5 `9 W0 ]) S9 y9 C2 K cld
/ M% r; @% b1 ?6 O movsd " m7 P! m! n, s. e* ^, m) J
movsb - M z' s4 \- {4 `' ?( q3 `
} 6 G" _* r6 _* P2 S
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
8 C' q: k, r( Z8 V _asm * H) a6 O2 E$ _) T% G/ ^$ n
{ ! g7 I) F( o/ k+ X- \3 z( J% ]
lea eax,MyMessageBoxA " l( |3 N# S& X. E# |% S3 _0 m
mov ebx,pfMessageBoxA % e! e9 Q# I4 {7 T! f6 M
sub eax,ebx ! X' N- I1 G" k. m+ u
sub eax,5 4 s# D9 z, D! k
mov dword ptr [NewMessageBoxACode+1],eax
) o0 N) y* z$ \ } 3 \: u' B$ h1 C# O3 A7 M. O
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
. e, M- j) f, A1 Y dwIdOld=dwIdNew;
0 D) }6 ]( i( P! o4 [" S! Q2 N4 K HookOn();//开始拦截 6 h2 o2 v0 F, U. t" G. r
return(true);
: p' v. [2 T& C$ r& F" O b( m9 z' n}
7 V9 K, O& O. q: j! _- z" @$ O! t# wint WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
' ]+ w4 |7 \; J8 W$ l; m/ g{
4 y- w6 b# t8 Y9 C0 Y int nReturn=0;
- _' B6 r3 \& q; `* H9 j HookOff();
. e1 e6 i5 y. i1 `5 T nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
2 T$ }; a" S" ^; s! L' K HookOn(); # i/ R$ _7 [6 j {0 T, V
return(nReturn);
% n: n4 f" T5 }3 C, v# o}
9 l! @4 e' r y& }( m+ E+ {void HookOn()
- T7 y, y) f! x! l{ 0 m& j$ s ^6 B* y# n, T4 S
HANDLE hProc; # E X3 ?6 N7 O
dwIdOld=dwIdNew;
& L& b& x: O ~3 Y$ U! m hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 + S, r1 ]5 S! M: S
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 6 ]+ `* _. b4 e; D# c( t- ]
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
$ [3 M( L, x. q# u4 `5 U0 x4 } VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 6 {2 c* x D0 w! \6 a# Q4 T
bHook=true;
3 c- Z1 Y4 I3 q# u, v0 e}
2 h8 T/ b. O4 S0 \void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
4 R/ D' s H7 G9 {' M{ - J; t3 [8 ]4 X, u
HANDLE hProc; 1 F8 |) A3 O& {4 P) J
dwIdOld=dwIdNew;
# [- S4 `/ ]. P: M1 X+ d* K2 U, U hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); 9 ]3 [- v( \1 d7 p4 e* a6 _& i1 h! |2 F
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
' i4 D' B% P3 n) S" T$ T0 R WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
0 N& @9 s( J { VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
7 W: ^% ^( m7 U! U bHook=false; t1 M# p; W3 E3 e
}
8 e) Q" C6 \7 z- ?* b% I//测试文件: ( Z7 l8 ]( W# }( B' a" ? ]
int APIENTRY WinMain(HINSTANCE hInstance,
: L7 H# e4 Y4 L* k8 n0 k3 Y: ^ HINSTANCE hPrevInstance, , T" y$ T. v# i5 @. L2 a& m
LPSTR lpCmdLine, 1 [6 C9 W- i1 k& C
int nCmdShow)
2 L5 L3 E+ p, g) Y7 i; g{
) d ^8 m, Q+ y- u/ L% ~8 k a1 e1 R0 z0 h3 ~
if(!InstallHook())
3 P, n# C2 m0 U8 [ { 7 n% q* c4 M/ Q2 d
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); # a6 K# t, C1 p8 C- K5 m6 Y
return 1;
7 E* @3 q3 k$ X; i) e) z h } & h% ^+ U2 \9 x: c0 c/ t$ Z
MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 8 @% D) d7 ^+ g, Y; Y
if(!UninstallHook()) & i6 s0 d# x2 Q# U$ F$ {! j
{
5 l7 R/ p# J6 O9 g4 L; o' p MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); & V$ R& H Z1 k6 N
return 1;
, d0 N3 f( p( I }
* G/ u0 t5 x, R return 0;
! g3 Z; I2 x: w: O6 v. `# ~} 2 ~% f- f, j9 K; l
[此贴子已经被作者于2004-11-5 18:12:27编辑过]
, E3 R. }+ r( Y A. Q. s h7 J3 q |
|