|
3 D# x( Q& I( t
发表日期:2003-10-30作者:tomh[] 出处:
- j6 f0 P3 M$ N2 c4 U# qApi拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
; n) B3 R4 `* a9 J9 T( e 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
8 g: D$ A. v. H其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: 3 \0 u( O2 m8 v0 W, |2 v; G- f% x9 L
BOOL VirtualProtectEx( / P1 Q' f( C4 c+ Q2 t+ m; N, l
HANDLE hProcess, // 要修改内存的进程句柄 & `" m6 U* h1 ?" H/ C* c
LPVOID lpAddress, // 要修改内存的起始地址
0 U9 \. F2 D' _9 G" F DWORD dwSize, // 修改内存的字节
8 P+ G) {! `3 N# }& o* g DWORD flNewProtect, // 修改后的内存属性
7 u" ^ d- V: ?' k PDWORD lpflOldProtect // 修改前的内存属性的地址
/ W8 l# N2 P0 ^2 } );
5 e; i! r6 M5 R" ^ BOOL WriteProcessMemory(
2 f, Y* a$ E# m$ S R, N HANDLE hProcess, // 要写进程的句柄 5 d2 I5 W6 A% f/ P1 R! h8 k+ `+ C
LPVOID lpBaseAddress, // 写内存的起始地址
' W1 O* J1 `1 \9 Q5 [* ]) g- X9 z LPVOID lpBuffer, // 写入数据的地址
: Q7 _2 H4 p+ ^; f, D/ U DWORD nSize, // 要写的字节数
* Q- o D3 d: q9 x% I LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 % e/ S B! I- g* V9 L; B
); + m) T$ i }: ^5 h) ]5 S
BOOL ReadProcessMemory(
o! W I- q b c4 r HANDLE hProcess, // 要读进程的句柄 ' b8 r' d0 D4 Q* a5 K4 z
LPCVOID lpBaseAddress, // 读内存的起始地址 , ?, W/ k) M0 H
LPVOID lpBuffer, // 读入数据的地址 + a* Y) ~) ?6 }$ K
DWORD nSize, // 要读入的字节数
9 x* J" w0 ]/ \* a( A4 q LPDWORD lpNumberOfBytesRead // 实际读入的子节数 & v; d- G: ?! V) V- E. b& k) X* j( N
); 5 \2 D* `7 M7 ^# F+ i2 O! ]
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, 0 }3 U6 p6 p @- W
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: ) K o4 \7 t; I: b; n
其中Dll文件为:
4 l) D7 B* @& N( w1 q HHOOK g_hHook; ) y' `( D6 L7 N( f. r& ]
HINSTANCE g_hinstDll; 2 q' w+ P# }! V0 B8 V+ z
FARPROC pfMessageBoxA;
: S3 t l: s o int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
: H8 e- i7 a9 b% z: f BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; # d; [5 E F! y0 Z9 g) ^( l ]
HMODULE hModule ; ( T9 q% T, |2 p, l7 N- F9 O, i! d
DWORD dwIdOld,dwIdNew;
' v1 o. d) J5 ]& n6 _0 F5 M BOOL bHook=false;
5 Z, `4 P' O! p9 R+ s$ \% W8 G6 Z void HookOn();
% V& E2 z1 q; P/ U$ H b& f2 k7 O1 d void HookOff();
2 l& p ?8 |, E+ Z BOOL init();
0 x/ W9 r& u& r4 \6 rLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam); ) i6 |0 P0 ?; i5 v0 H. }
BOOL APIENTRY DllMain( HANDLE hModule, ; t8 k" d1 R" J% y3 q x
DWORD ul_reason_for_call, 7 F. G8 c& [) F' f
LPVOID lpReserved
$ G" |7 ~9 {/ Y ]$ O) o3 s ) ! C9 D. l! ^' X6 ^
{
% c& g- H$ |) p, B* l) {2 E4 S* J# P switch (ul_reason_for_call)
' u2 T0 d2 t. E9 k { 6 B+ j/ f, R+ j- G' `
case DLL_PROCESS_ATTACH: & g9 t0 I) C$ X+ N" _; i, `+ K+ J6 G. |
if(!init()) 1 \& L. Z2 v6 n, e' c
{
- M6 }" ?/ T- w6 A% a; p MessageBoxA(NULL,"Init","ERROR",MB_OK); * d+ `8 {- ]5 \: q
return(false); # n2 J" y1 G) { I
} 3 v. N. B5 e q2 p
case DLL_THREAD_ATTACH:
* T( c# F( M' U case DLL_THREAD_DETACH:
6 j5 p) V8 Q } case DLL_PROCESS_DETACH:
) C" i( E; w. F( x; c' }8 c6 ] if(bHook) UnintallHook();
0 h8 K$ ?% s0 V0 W+ S9 g break; 2 f" j, S6 r: Q' a0 @
}
4 ]* k9 E8 d( p5 c. @$ t return TRUE;
1 B* B! o9 X9 O* s: w/ D2 ~}
}4 B( a' C# R F, WLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 9 p z* K8 d: x& R" O( J6 k
{ ' ]4 w3 [; z/ X; m: b7 A) ]. b
% v4 ] d: B5 }2 F* D
return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); ' k- G) U, h2 N
} , E5 F* a: R; ]1 R, C4 r* c
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 ) ?1 B. k# n$ g, r) S& d: y, L
{
9 R( O9 @. E- B' |5 S g_hinstDll=LoadLibrary("HookApi2.dll");
0 E# F1 Z7 |' u1 x: ~ g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
( I( z1 S( M% D! j/ R zif (!g_hHook) 4 k" X- E J# \. Y! {
{ $ t: x& s* k5 u- ~. r. q# s
MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
5 j, m; N4 {0 K J& Y return(false); . G- C0 @+ q- ^. F* F2 P4 ~! g! v
} 8 g, |" P, F; V6 T A6 Q/ z* k
9 \ W2 z$ `. T7 C; O5 |
, L i8 X) w t8 k
return(true);
: u, \$ ], g" V& \: L, I' U} 8 j) {) e& x' k6 C; G7 }
HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
/ M8 k+ }; a. E* A% X4 ]{
! f4 z) N( W3 d* O0 S e! W
' j1 F* p: a" t return(UnhookWindowsHookEx(g_hHook)); 7 d+ s" v1 B* {4 u( E* I) v0 A
}
8 m" e2 z% \, }% GBOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令 ! u d/ d4 m5 H$ e# _" J
{
- k& G: f8 l% @. j9 Y3 U hModule=LoadLibrary("user32.dll"); 6 k! o# v# J/ Z& I' g& o- }
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
) v. k3 g! ]: L* k3 c, Y; h3 Y if(pfMessageBoxA==NULL)
1 k! w. b" S [% x. p% } return false;
+ h# ? O* W5 w: M _asm
/ C: p' {/ c6 y, n. M6 j( {( g {
8 S: E- X; T; |' T/ m lea edi,OldMessageBoxACode
' h3 R* ]8 F( B8 I! ` mov esi,pfMessageBoxA . v) e8 {. I: r2 T
cld 6 F/ I z" s% K
movsd
8 Q' t, E# l; i9 J/ H movsb - \& ^9 O9 [* f
} , e+ ~) T2 X9 n0 J1 b
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
4 e/ E4 Z6 Z p. v _asm + v0 E* f+ e- n7 C; q7 s- Y
{
" [, H; a+ @: |% |3 D lea eax,MyMessageBoxA
; Q1 t* |& W6 [ w$ L$ o4 {/ b mov ebx,pfMessageBoxA 6 r% l: L& k+ ?
sub eax,ebx
9 q Z8 T/ w+ B! [& w, b sub eax,5 # L ~" r( |* a
mov dword ptr [NewMessageBoxACode+1],eax
$ Z9 L0 V8 f$ `! ^8 n# X. I) }8 ` }
9 h+ \/ ~' r C. H dwIdNew=GetCurrentProcessId(); //得到所属进程的ID / F, @# a/ O) M! ?
dwIdOld=dwIdNew;
6 e, m: I( Q6 U7 \' N& h" a HookOn();//开始拦截
+ E% F3 a0 v* q, Y5 ^; E0 ^ return(true);
* H* [+ [4 u! n7 U8 s% W2 x; W! o} % I9 \( M2 _% u& I- s
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
% y3 x% M) C/ y{ 2 @: `- U2 g+ d0 C* J
int nReturn=0;
; _& ~7 N$ ]) c, P$ P HookOff();
8 `: f |* h' `7 p nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); ! Z- a# _1 C) s1 _. K; X. P; k
HookOn(); + N- U. G! [- I1 E
return(nReturn);
) K, g6 E. ^/ s" ^; E4 F}
8 n5 y, p; C0 e G) R* O7 dvoid HookOn()
+ \% S$ y( }6 M0 G! i{ 4 X1 ]& [, U/ ^
HANDLE hProc;
, g1 s5 Q/ p* E$ F$ o; f" f dwIdOld=dwIdNew;
6 o n7 _# F6 i, [ hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 ; B2 e' W# ^9 A; }$ Y
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 - V+ |! \! P! @. s, `
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA ! A. l5 W8 P& ~3 s S; n/ e. ]
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 : d2 O* p. T9 m7 D7 E
bHook=true;
# D* G$ p3 {; x# A" E6 A} 2 d/ ?" A$ z) L. ?7 n7 z3 L! K* w# K u
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA % m+ f0 G: H. m$ z
{
+ I4 A5 X7 k; z' M HANDLE hProc; , g! e% h+ \! C5 X: |& e+ K
dwIdOld=dwIdNew;
$ J a9 K& U) R* ~0 m0 C4 y hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); ! }* K. _2 W8 |0 u! ]
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 7 e7 N @" }! T- I3 T* t
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
% Q" n+ |: G* l: R: D( Z1 c VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
; i4 A0 u& \+ M( x5 S- b bHook=false; 9 ~% T) ]4 B: \
} # w0 a/ d) G, G1 o: F
//测试文件:
. A. o- P7 q( o+ t/ zint APIENTRY WinMain(HINSTANCE hInstance, . u, M8 a- P% M N5 D9 W6 M* ^1 K3 x
HINSTANCE hPrevInstance, 5 l$ C+ I+ G7 `2 U
LPSTR lpCmdLine, 3 Y E* c! q$ \% V, D$ `) C; O
int nCmdShow)
: v- B: o4 m( ^5 {8 ?8 }{ / K3 H& a" m3 o& s s
0 t3 s# j( F, Q if(!InstallHook())
# W6 T) e0 {6 T8 N6 K. T+ e {
0 m' C) j' _& Z7 } MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); - |. z! e( G5 d( Z' {5 T' M w1 H; s
return 1;
6 r% ]- j$ d8 y* A3 k3 {! @ }
7 p5 Y3 [' M( N/ z" m* a* l MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 5 H: E5 h9 G; T! K
if(!UninstallHook()) 5 I G+ H* d/ w3 r% v
{ 8 {- _; R- ?% N, f8 \- C
MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK);
( o, }0 E5 A5 ? return 1; 7 z$ J6 t3 x5 X& I3 X& B
}
: l. f8 ]* f0 x Z return 0;
! ^+ {- s2 j' j6 }' m}
$ @. ] n6 ` j! c+ {7 }[此贴子已经被作者于2004-11-5 18:12:27编辑过] ! B/ i6 S% G8 H% V5 \4 {2 @
|
|