|
0 @: w" U5 ~% a* Q. S0 k2 F' O5 S发表日期:2003-10-30作者:tomh[] 出处:
0 r5 r8 ~6 g5 |9 a" UApi拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 ( w' D6 U3 ]% h
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, # w- y+ O$ ?9 v
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
0 L: Y4 ~1 y1 w5 l3 f BOOL VirtualProtectEx(
. ^" K+ N* ]1 r: w0 j HANDLE hProcess, // 要修改内存的进程句柄
& r8 F, _3 u) E; P" z+ Z LPVOID lpAddress, // 要修改内存的起始地址 : c& }5 F1 K% o2 u7 M |
DWORD dwSize, // 修改内存的字节 . k' S6 K$ G% K9 g& C5 q( K+ \2 ?
DWORD flNewProtect, // 修改后的内存属性 ; @' G+ T5 m; Z2 R9 ?7 f8 D4 p9 d
PDWORD lpflOldProtect // 修改前的内存属性的地址
1 o4 X- U. `9 X$ L" R( t );
! Q3 w' {, e' C; {& I- [6 Z' M BOOL WriteProcessMemory(
l$ h3 e6 c, a$ @; [$ o HANDLE hProcess, // 要写进程的句柄
+ \/ k% ~6 `) d" [, Q! v LPVOID lpBaseAddress, // 写内存的起始地址 * _. Z2 U+ a4 L& b$ P
LPVOID lpBuffer, // 写入数据的地址 0 X$ C. u. }, Z% k+ b2 R
DWORD nSize, // 要写的字节数
, _; J) p$ t p& Z/ P LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 ; f( l/ {3 G/ H4 x
); ( J9 O) y6 Q5 Y
BOOL ReadProcessMemory( , t+ \0 ~+ z3 r/ W# e
HANDLE hProcess, // 要读进程的句柄 4 O. o3 a5 Z4 h+ j$ C7 d
LPCVOID lpBaseAddress, // 读内存的起始地址 0 C9 Y' E! o; @8 o6 I4 ?# h# V
LPVOID lpBuffer, // 读入数据的地址
5 C6 m2 u4 A% _* |- K. X/ J DWORD nSize, // 要读入的字节数 ' |2 P1 y3 g( A0 W1 w
LPDWORD lpNumberOfBytesRead // 实际读入的子节数 7 q0 o( R1 @3 I8 k0 S
); . [/ h0 a+ h5 j& l6 V- o' @
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, - ?& b9 r, o% P
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: , Y$ v# w% C; [/ I8 N8 } U
其中Dll文件为:
9 ^+ Q# c0 k, b, n/ @# ^" E HHOOK g_hHook; : S! @4 d3 V5 ]/ w9 v
HINSTANCE g_hinstDll; 5 M$ o7 p) _& ?; K$ s3 r
FARPROC pfMessageBoxA;
3 n K9 }! o" c8 e int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
* R4 Q/ c0 w9 C# c# H0 y BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
0 S+ i: h+ K" [3 Z% A HMODULE hModule ;
/ z0 @" S/ ~6 P& ] DWORD dwIdOld,dwIdNew;
. j0 ]0 ~$ u/ K' e) N4 ?% K BOOL bHook=false; ; J# h6 z; H/ F: b g7 w
void HookOn();
* T6 [( u* l' V void HookOff();
0 w* J4 {0 b/ j( L+ W BOOL init();
0 B+ A. o9 D5 bLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam); * N" l3 s% j8 q5 \
BOOL APIENTRY DllMain( HANDLE hModule,
6 N" b4 L6 S7 N; D! T; m DWORD ul_reason_for_call, 5 \4 V5 U$ `( j5 |9 p
LPVOID lpReserved # H% x- b. b( |9 X9 ?6 ~- `4 r
)
+ o6 d/ e: V0 z{
- n# Z5 i) N4 k/ H7 f# d% b switch (ul_reason_for_call) + h/ U: M9 f) D: ^5 M$ `% |
{ 2 u& U9 J( J' B/ ] f% k
case DLL_PROCESS_ATTACH:
" `; @: j; L4 ?2 K if(!init())
/ D* v0 L. m, Y7 x8 m! W {
4 Q- {2 R: k# U' C6 Y& i0 O4 ]0 W; }( O MessageBoxA(NULL,"Init","ERROR",MB_OK);
; t% u' q% I _& ]% C5 k6 } return(false);
9 v- Q# k. M8 K& X! x+ f }
4 K, \% C) s% b+ f$ N7 w case DLL_THREAD_ATTACH:
! v+ J% B6 s, h, k3 q# Y' V case DLL_THREAD_DETACH:
+ R( c. H0 M; u- T case DLL_PROCESS_DETACH: 9 ~8 L% k! c- Y* l+ M% K" F
if(bHook) UnintallHook(); 9 ~1 y% ^$ G- D( w- E9 N0 j
break; & u- F) {0 D- n- z+ \
}
4 A; p2 a# F5 h$ H. K1 `/ E* d return TRUE;
/ b. H- p: R: `4 W} B+ ^6 y0 V8 i) T" ^8 t0 N
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 ) H" u, _) w" }' B% ~! c# @
{ ' b( P: j. S+ u/ d- q- e& Z3 ]
: J4 G! z; Z; X4 w- x
return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
; e1 q) W6 @5 ~- T$ v# e} ' F: u" C1 M% K- d6 d" Z0 _
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
2 t Y) ~( d" g4 B4 x3 f{
4 ^* B) M( W$ ~+ `0 C g_hinstDll=LoadLibrary("HookApi2.dll"); $ {2 [: G. H5 C7 {! q! p
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
# ^% f) `$ |7 M! E4 M7 D$ {if (!g_hHook)
/ U# _; {, g, V' F/ b# \/ V{ ' ]" I; i3 Q8 w' E
MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
! y1 _) Q/ F3 n# U return(false);
3 J2 m9 K7 ^& f# ?; R' n# g: l1 z+ ] } & |* w% D9 I- F |
0 P* ?2 \( w2 Q" J- L _
: ~9 k% a2 W8 u- O4 Y# l* S return(true); . D* y6 B/ T' p7 C' z J2 _6 l
}
/ b+ o: Q4 G- @* E0 JHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数 ; W# f* Y$ L& ^5 t0 v) Q
{
8 q, x4 Y* W v . D- @) Q6 p/ }) y
return(UnhookWindowsHookEx(g_hHook)); $ ]) e( H7 w% H+ M. n
} , [: P# G5 Y$ Y: x) P$ o
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
" w3 o# g1 r9 c( T* J7 c{
w+ i9 i" z. F2 K6 A) K hModule=LoadLibrary("user32.dll");
. }& k3 G& Y8 X pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
2 l! e: r! o; d: k8 f if(pfMessageBoxA==NULL) u0 W* w* H) L1 D; N, S5 ~
return false;
5 _3 D0 n" P- e# M3 } _asm 7 n9 O* X! _5 E# h4 M: C
{ ! v; w2 k/ _1 ~" j, S- K, i
lea edi,OldMessageBoxACode
& _$ P h# t9 S. K* k mov esi,pfMessageBoxA
% r5 P5 p8 M( Z4 N7 h cld
, `5 C0 A, C6 c D8 v$ Y7 s! B movsd
, m H; X/ c$ N0 h u( k" t! t movsb
. N. z9 W' D4 R: r1 Z. d$ F# F }
$ O& n4 g- K+ n NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 : k- A/ ~, j9 N( J
_asm ; }2 m# Y6 G# j7 O, e
{
. h0 _; h/ U" J, {/ F. u+ V lea eax,MyMessageBoxA " a9 b+ v% y8 w2 _2 V
mov ebx,pfMessageBoxA
; E5 S `$ Y; c+ n. e* Y5 \ sub eax,ebx $ \6 V/ O" `! v' @* y
sub eax,5 ; [ K1 }; @4 n6 K
mov dword ptr [NewMessageBoxACode+1],eax
/ d) |3 b# |2 ~, J' J2 ^2 _' } } % J3 A z X1 t1 h/ g( z# U4 l F
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
8 _9 C8 i ?: m* G( a+ {, s dwIdOld=dwIdNew;
. I) y8 G: r$ N1 C# Z HookOn();//开始拦截 % ]- \& |) S9 V4 ?, O
return(true); 8 O$ p( A8 Y$ T; P5 f8 r7 T
}
# ?# {; J- X6 d9 xint WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 / Y. P# X1 j g& Y' P, ]
{ 2 G5 A2 \ p% C- W
int nReturn=0; ) Z8 m- K5 N4 }% a1 P
HookOff(); ) C& y, S/ H' m u' h
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); 9 M# t, s: u' d
HookOn();
% h' f1 h" x1 N c7 h- n; C- L return(nReturn); " x+ s( i' t4 _. e( n- }7 r, z
}
7 s: e) d2 r: \2 N" y+ W2 jvoid HookOn() % \& k- i) g+ h# P
{
& l% x* \3 f" o; T$ `' ~2 M HANDLE hProc; & c$ @) J8 A) C* A1 V! [
dwIdOld=dwIdNew; 4 b' D2 F- t; A- `6 X, m) h
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 0 q! } J, n+ N4 A1 K8 @, G
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
) j( d/ @1 N( _# }! h WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA 7 I; b0 e# `' k' j# d1 [0 ^
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 8 Y4 x% A9 h; G+ {8 w2 g
bHook=true; , T) v! ?# @# g8 E
} 9 \" D8 |9 b1 T7 H# Z* S4 Z# A
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
2 [; C: D8 ^: a5 _/ h{ 2 y+ q" \7 o- r
HANDLE hProc;
6 Y8 [% k& M2 I dwIdOld=dwIdNew;
8 J/ M, K `; G6 i- C hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
' i- a% b2 t4 A. U VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 7 Z1 g3 Y3 N( `. L
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
9 @; k! J' [1 K; e3 Q: i VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
# ]. \' m9 w7 G/ f5 b% Z' T% G bHook=false; ! [( G }3 I+ ~4 w7 n
}
3 Z! }7 {3 N7 Q# Y//测试文件:
8 {( G2 y* k% F5 {; ^int APIENTRY WinMain(HINSTANCE hInstance, 9 M7 k/ M3 N4 M* O1 D+ y/ @. y
HINSTANCE hPrevInstance, , r% @: \( B- r) z8 n; C
LPSTR lpCmdLine, ! C! s+ ~4 h Z9 |
int nCmdShow)
/ E, m, y" H+ C( _7 ~ S{ ) Y" ?: R* x' \) _1 g8 C0 F
3 S7 X6 t* m( H" B) F
if(!InstallHook()) 6 v: o- X, I7 N I" A) g d
{ ! Q. N5 B/ M1 q7 d
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);
( H# S0 X& V6 Q6 p' E0 | return 1;
/ v7 h+ c6 W. s' Y0 f9 ?$ u }
& ^2 i8 [" H' |" r: j MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见
+ Z( h6 n0 V* N. m$ d' q9 y if(!UninstallHook()) * M. N9 {1 z5 e. q& d1 D' W" g/ F
{ ( E" f2 Y' k! A2 l
MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK);
2 @* G( _) \: V return 1;
$ d- [1 \. g* Y; w& f8 T }
% s; w# @9 l! L: F$ K0 y return 0;
9 E3 R& ]0 M2 D, E" B* B} % W9 l; p! T( V( h! V) @6 C
[此贴子已经被作者于2004-11-5 18:12:27编辑过] $ {% m! N8 ~9 w
|
|