|
9 `2 D! [; H4 c: W- @发表日期:2003-10-30作者:tomh[] 出处: # Q, W, t5 R6 d( Y1 @# h0 N
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
' j$ ^8 {9 u% I! k2 i+ k 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
, k" c( d, o& j3 B' H其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
& F0 F. C# T0 T1 H. o" ~. B BOOL VirtualProtectEx(
: w8 g. Q, _0 Z- i* p/ L HANDLE hProcess, // 要修改内存的进程句柄 " X- P4 s2 K) V6 k$ x: d
LPVOID lpAddress, // 要修改内存的起始地址
- E1 v3 |2 N5 k) Z' n: R DWORD dwSize, // 修改内存的字节
( ] b7 l/ [, a" ], T0 ^9 H DWORD flNewProtect, // 修改后的内存属性
( T' l2 f& {; b& P; n PDWORD lpflOldProtect // 修改前的内存属性的地址 I4 ]+ ]0 {' s4 W
);
' b4 D: c( e4 i3 P BOOL WriteProcessMemory( ) Q. ]" n& Y$ V3 L2 \) z; n
HANDLE hProcess, // 要写进程的句柄
5 o: \+ x- x9 w; C7 Z3 X LPVOID lpBaseAddress, // 写内存的起始地址
( Y7 i# c4 p3 g( M* X Q+ b LPVOID lpBuffer, // 写入数据的地址 * o$ E- k3 n& d- @+ J7 w
DWORD nSize, // 要写的字节数 t1 y: l! y( D p9 [- a2 E" X- B
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 6 C% [& r/ e: K8 b: ^
);
8 ? o, m1 E' n3 k& M; q5 X BOOL ReadProcessMemory(
% P9 S& ` G/ v5 _9 h( g& u HANDLE hProcess, // 要读进程的句柄 : g9 o2 z; q" y' Y# J! E5 e; l
LPCVOID lpBaseAddress, // 读内存的起始地址 - O: |3 D' C, i
LPVOID lpBuffer, // 读入数据的地址
: } _" n' D6 a. A1 f% ], o5 t DWORD nSize, // 要读入的字节数
+ m0 f+ G! @( Q( U LPDWORD lpNumberOfBytesRead // 实际读入的子节数 8 j( O/ z: |1 e0 j* B% J0 L0 v7 K
); 3 W+ h: V% _: s, c
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, 8 P9 v) ^! F/ k9 D% E6 Z( Q: Q
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: % [5 C% m) z7 D8 Y* Z
其中Dll文件为:
; ^% L% C1 S+ [' E6 ^0 Z HHOOK g_hHook; * k' d) ^/ x7 G& t1 m; k
HINSTANCE g_hinstDll;
' u) t8 e# B* Q FARPROC pfMessageBoxA; ! L8 D' O w2 W1 T
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
* e2 [& m4 ]; z! C1 i BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; $ }, z- H. l. r8 _) K
HMODULE hModule ;
- r7 D2 [6 j& i2 I# q% V DWORD dwIdOld,dwIdNew;
6 S/ U, ~6 ]* J% I6 J$ | BOOL bHook=false; ) F4 s) X: l7 T7 d% L; A0 ^
void HookOn(); 3 C7 N4 s; f/ [6 i6 y
void HookOff(); 8 D3 c& B6 H/ _# t$ O
BOOL init();
3 ?" Q; b( C$ a" KLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
) B' q0 X) z, o) P+ Y8 O }BOOL APIENTRY DllMain( HANDLE hModule, # X* _5 [2 m$ E, P# j0 p# i9 Y' D
DWORD ul_reason_for_call, ( D |% E+ g' t+ U3 T6 d; v
LPVOID lpReserved
1 t# ]9 y5 l/ }, V$ \: T3 G )
# H, Y# Q, c) S7 T( l) Q{ 3 c6 K0 s! ]3 L
switch (ul_reason_for_call) ) W" |9 P2 f) V! s
{
/ s9 d: O1 ~4 u. U" |( p% M" C case DLL_PROCESS_ATTACH:
% y# \3 ~' s4 y1 O! D* p if(!init()) 1 E9 c2 X" Q, u) h
{ # g' u% R. K* V; J1 k& ]
MessageBoxA(NULL,"Init","ERROR",MB_OK);
, F3 N1 ^/ }; N0 {2 K9 g3 p return(false);
" y- z2 \7 N1 G } 2 m) N2 y6 k9 C, p" v/ o3 D
case DLL_THREAD_ATTACH: : ?" ~5 b9 o: a, q# Q
case DLL_THREAD_DETACH: ' u, F, U: q X4 c- f
case DLL_PROCESS_DETACH: : r0 H! _" p7 q+ q- |* V
if(bHook) UnintallHook(); 5 v* Y+ U! c( g* B+ W' F! u
break;
4 |: n; r8 r4 b0 F } " i5 B2 l8 j1 e0 f
return TRUE; 3 L$ C# H0 E" E
}
# a$ ~+ J! u! k# @( |( h; bLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 ) e! K0 j5 |5 B# f
{ . ~& {7 x( }" y' b' j1 ] Q* e+ D
- ?3 V) s7 X* [: l
return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); . d) d+ r6 V* n$ f
}
* |" b* _8 I2 u/ K. A6 `- DHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 9 u& K, s% b4 z% N; v9 ~
{ 1 ?& ^* \$ [. [" j
g_hinstDll=LoadLibrary("HookApi2.dll"); 5 ~% K p% q- j, e1 [: p; T/ D4 P% n
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
3 V3 R) g" w- f, Y0 O6 Bif (!g_hHook)
# w/ A/ \& ]& P0 K4 {{ 0 f k* p9 i+ u! I" w5 a: ?
MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
p6 D0 ]/ l9 D3 b+ G: @- x# V. L" _$ l return(false);
# [& b* G6 K4 g5 R }
/ w" v8 V6 a, K: `7 p
; Z6 g9 E: ]2 b9 o, P / k7 V" J: U0 b+ p2 `! u8 I6 u% Q1 O
return(true); : Q* F9 d! H7 [ G* Z
} 1 C( J5 p+ O( z! Y2 ?! S
HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数 4 r- x! ` B4 o4 i( v3 p
{
, ]9 w/ V; P- O" v8 a! z * U/ t. Q, M4 N9 U U' H
return(UnhookWindowsHookEx(g_hHook)); * n# G# n% ^9 l$ d$ D# b
} " T/ F; z$ P' t8 P1 |
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令 I" T' Q+ K/ W; x
{
7 o( b4 M9 f5 Q. _1 _" F. Q hModule=LoadLibrary("user32.dll");
4 ~# ~9 R8 u, V3 E pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
3 W5 [% G7 y- `5 p" c, z if(pfMessageBoxA==NULL) ) I I' I6 ]! {: t( m* L
return false; , B$ R8 y3 G0 T: n* C; b, ^
_asm 6 \3 z3 w% A; d5 C* B- Z8 [
{
: }* A' U8 I" ?! N. u5 {$ h; W) D lea edi,OldMessageBoxACode
' A, r8 W4 e9 U mov esi,pfMessageBoxA
* S0 }% O( j/ q, S; \ cld . y# C, ?; |( Y# ^. q7 K# ^; }
movsd
1 v, B8 K: Y7 _" R3 E% w" r2 P) p movsb
+ D& R# y- E/ \' k8 Z! W7 J5 m } + Q! Y. X9 n7 ^6 f; N
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 ; l) M5 m4 Z+ _* U
_asm 6 K1 E9 K `9 T! ?; `
{
6 H* j: \% O) L* Z2 C; ^+ i lea eax,MyMessageBoxA 9 i* W0 ~: X7 ~6 X$ k4 K
mov ebx,pfMessageBoxA
F# V1 X" ^! a# h" o0 o" ^ sub eax,ebx 4 M; h* N/ t2 T3 l$ U' S1 [" }
sub eax,5 9 i0 ]8 z) d8 Y' z% }
mov dword ptr [NewMessageBoxACode+1],eax
2 [4 R) J5 u1 n5 f9 a5 L } * m2 ~0 x7 U# l" k7 n
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID 4 y* H) I5 p% }5 V7 s9 b, b _
dwIdOld=dwIdNew;
. m; S" @5 C5 J5 k3 R+ P4 R/ `" u HookOn();//开始拦截
, p, W4 m7 }, f) Z5 \ return(true);
$ E: `0 V% X! B- q: r}
! U1 N" U; Q! m. \- h5 W7 vint WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 & J; M) Y3 g5 g
{
5 h) P1 v$ A: S, W int nReturn=0;
k) \/ K0 p% K0 U: L HookOff(); - C+ D* B! F9 g! c9 F: {
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); / b# U- l" {/ Z- U( a
HookOn();
$ Y, ]# X1 T3 M/ N9 F3 E, j: l, ` return(nReturn);
( _. C) h+ v* @0 ^1 c} ) @! V7 T; [ s. N" W. `6 m j
void HookOn() $ ^* F. m1 P$ K7 ^& X
{ 0 q3 l0 F) S F, [) K: _) V# H
HANDLE hProc; \9 q# d2 D$ i% J+ ~
dwIdOld=dwIdNew;
- | a+ P2 |4 u3 a5 F* x3 A& v hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
5 O( O6 K% D& `# w X" O VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 0 r5 W6 _8 V0 x
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
' |8 F0 P2 `4 A2 H8 o- B VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
w& g: @) \- v, @$ X) [ bHook=true;
0 E5 c0 O8 `4 U2 s! h( J' b% J} 8 w. B) U5 K: X/ @
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA " m3 Y, d: [/ C2 F1 n& e5 D+ K
{ 0 ?. c9 t: E9 ] j
HANDLE hProc; 3 ?% B7 j) [. V; N/ g$ M$ j
dwIdOld=dwIdNew;
. q: b4 ? v# U1 g) g7 z# n1 w/ W hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); ' Y4 c4 @9 u; [: G
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
, E; _1 m$ r# @2 h) q/ s WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); 8 ?, L3 A9 S5 |! c2 p/ \' P
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); " \0 O8 b. G5 K/ ^
bHook=false; $ I0 X0 F! f9 F, v/ _
}
5 o4 L# v6 W- v( y//测试文件: ; I/ w0 c/ l& o5 i
int APIENTRY WinMain(HINSTANCE hInstance, 2 { w4 f1 c3 r* w# y+ B/ s
HINSTANCE hPrevInstance, ( _% F+ \) D9 Q! c3 s" O2 _% \
LPSTR lpCmdLine,
4 ^" }+ K/ p( ^& z. e8 r' h int nCmdShow) 5 ~0 i6 V3 _, }0 T/ B" i: |
{
. u) ?$ ?$ j4 P! y0 B4 N T8 s
4 m: f7 L% l8 Z8 u0 V: H if(!InstallHook())
3 ^1 k) J0 V: ]/ i3 P8 c2 S: H4 D- Q { 9 E( f2 i8 i. M0 x
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);
: C) i; x& p3 l2 f% j9 T( U return 1; 0 F% v8 J! z; x* ` j
}
$ l/ _' [0 { s MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 4 k/ T! S( f- G
if(!UninstallHook()) ' `9 v. F* b# ~% H1 ]! h
{
& j) C/ ^$ O5 ]/ C9 n MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); 5 h- E/ R0 v/ r" X' y! F
return 1; ; K2 W3 p: x: _: A
}
# o+ E- B+ j4 T: m6 j4 x return 0; ; y8 ^! _9 ]+ n8 q4 ]( t
} 0 L1 B. r7 l4 Z( ]6 G6 R# T
[此贴子已经被作者于2004-11-5 18:12:27编辑过]
' F" t4 y4 R7 f, \/ O4 u1 Q9 M5 ~ |
|