该用户从未签到
|
6 J& V; u% C. }! X) C1 r发表日期:2003-10-30作者:tomh[] 出处:
4 t; Z. k2 A" v/ z. X) K; N9 c. C' \8 [Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 2 ^$ A( }" O+ Z3 p0 z! i& S) @) P1 g
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, , X9 z5 K+ h/ _) `
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
# |1 Y8 N o2 `. ?7 ` BOOL VirtualProtectEx( 2 K! z/ { H6 L; c% W* h+ Z2 U8 r
HANDLE hProcess, // 要修改内存的进程句柄 0 Q: T+ G9 O$ z4 V5 _; }1 n
LPVOID lpAddress, // 要修改内存的起始地址 + M. f# H% q5 E2 H+ O
DWORD dwSize, // 修改内存的字节 6 k2 X% p5 n8 x! w" ~ H% ~! F
DWORD flNewProtect, // 修改后的内存属性
6 ?0 H3 M8 R% { F PDWORD lpflOldProtect // 修改前的内存属性的地址
! R* v2 g& X: @ n* v: O5 `+ X ); , e y( ]4 f- _' C5 I- i) k* p- Y
BOOL WriteProcessMemory(
) y4 X1 }9 \( p0 X$ l( S/ t+ l HANDLE hProcess, // 要写进程的句柄 ( ], Z1 t1 {& ]3 [! e. }3 c
LPVOID lpBaseAddress, // 写内存的起始地址
. F: Y' f6 t* |# v, A; y LPVOID lpBuffer, // 写入数据的地址 6 V3 E, C0 g6 |, v% G/ V
DWORD nSize, // 要写的字节数 @$ \: O4 ^, j! o
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
- b: Y; j+ J c0 B );
/ g; x" t* O0 M3 l BOOL ReadProcessMemory(
f5 v: q8 \' o HANDLE hProcess, // 要读进程的句柄 x$ ]9 [2 z6 n, D8 S
LPCVOID lpBaseAddress, // 读内存的起始地址 2 E4 _; b5 y3 s- C8 l
LPVOID lpBuffer, // 读入数据的地址 ) @6 _" B( ?' E
DWORD nSize, // 要读入的字节数
/ K( ~: y" @/ {- A6 A+ c2 o+ c LPDWORD lpNumberOfBytesRead // 实际读入的子节数 5 X' f& `4 L! ^7 D) S2 E" f
); * f( G% p* c- [5 f% w
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, . ]( p/ R7 O) P' X% G
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:
5 {- P# l' U* T# W4 R" e6 U其中Dll文件为: ' }' _% N9 X2 V2 Y
HHOOK g_hHook; 4 n' i, W) h% D8 r) q/ m( }* E
HINSTANCE g_hinstDll;
" |+ f3 C' _" f: Y FARPROC pfMessageBoxA;
& c( k. G: M6 {, ~2 u/ u8 C9 a( H int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
4 w( N, ?+ b; d" F" b' X5 @ BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
1 X7 n8 Y$ D" T" X HMODULE hModule ; 4 }/ Y+ G S3 {. \
DWORD dwIdOld,dwIdNew; 8 P; @# j3 l! j6 h; h* N
BOOL bHook=false;
. l# O$ f7 P; \! Q3 i: N4 a# f7 Q7 [8 N void HookOn(); 3 W& O& {9 d! K: B
void HookOff(); 7 r3 {% u" a B/ S8 Z. A
BOOL init(); w, z- Q( h6 r8 p5 y3 T& O
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam); % `3 ^+ Q+ v' ?( u) \# ?+ E+ P
BOOL APIENTRY DllMain( HANDLE hModule,
/ N6 T/ c! X+ J* U9 x' m DWORD ul_reason_for_call, l" l1 A3 p$ x# O
LPVOID lpReserved 7 B M% O4 p0 m% i8 F" Y
)
# ^6 r: f! h ^' C- y{ ) A! e5 K3 ~/ k( K7 W! ^+ I* ]
switch (ul_reason_for_call)
) o: H$ \; s& d; c { $ ]; u, ~7 h; J8 b! d- h/ a
case DLL_PROCESS_ATTACH:
- ~' M$ I/ y9 C+ P if(!init())
- N' G5 j) d" ]4 Z: ^( V { 7 K$ P! a0 y9 w1 w6 N
MessageBoxA(NULL,"Init","ERROR",MB_OK);
9 W# r3 s* j9 U! \ return(false);
[1 I) N( Y+ o# L' a% w } # |$ r' |% I4 x. t0 |2 d
case DLL_THREAD_ATTACH:
4 d6 ?: N8 F. e, j+ E. j case DLL_THREAD_DETACH: 3 p0 a" v7 c; U- X8 Q# O
case DLL_PROCESS_DETACH: / |. q0 I3 ^& ^: L6 x# m
if(bHook) UnintallHook(); 3 {6 Y) i1 ?7 l( d, @; j
break;
, p5 S3 f- O8 O9 _ }
. I4 |: n0 T: U$ B* [ return TRUE; & ]1 n: H% g* i) }
} % U" e$ \1 e2 W6 E d( r" z8 n* R
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
1 X* g% c% W; l; n0 m- @{ 0 u/ u6 h2 v7 j9 N
8 H$ T5 X1 R5 W2 T/ ]; _* M return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); G1 V( E1 e2 G5 Q9 S5 c9 {$ ^
} ; b8 ^8 A4 z v) ^
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
! n0 G4 y d! [+ r5 d& c{ 1 S: \! D$ {: _2 M5 |
g_hinstDll=LoadLibrary("HookApi2.dll"); 1 |7 c# J0 D% E l$ L/ a
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
5 a& `5 u& n! f1 ~# _% lif (!g_hHook) 7 Z0 Q. C4 X) d6 v5 |) E$ b
{
( |& Z: U/ T9 m% g MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
+ `) m, r* L0 R- d4 H! Z return(false);
1 M9 _% ?) m8 V* T1 S7 f E }
, @# l( o4 |* O4 i& F; S" U
- A9 R4 _% w$ V9 x1 V2 i
2 v9 a2 O6 ~. q! H6 w( d$ t return(true);
2 y' K: N! a$ Y}
$ V/ N: }4 F/ |6 S7 L! W" LHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
9 s/ ^0 [; J) g1 l% t5 C{ . P4 K3 b; Z. K2 `. X& f8 V
: F% v4 ^' F# j
return(UnhookWindowsHookEx(g_hHook));
# v+ q# M7 w4 |% G} 1 W4 `! `7 o! p0 k3 f W. Z0 F
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
4 D3 g% z) e% _5 _{
7 T: J$ y2 R# t, a* C3 r, k# u hModule=LoadLibrary("user32.dll"); & N/ S/ e0 \9 ^
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 8 n1 O! h) k5 Y/ _) j/ l, Y
if(pfMessageBoxA==NULL)
$ \7 {; o- I1 x/ z* N return false; . M/ ^) j V3 a1 I5 y% f* d- |7 x
_asm
( l( O# G- T: H3 h8 S* Y" o7 j) D {
% j& M/ ]/ I/ R) y Z- S/ [# L3 T) c4 T5 P lea edi,OldMessageBoxACode : A% m8 @% P0 y `4 @6 n
mov esi,pfMessageBoxA
# D0 z; Z5 B/ {) ]1 V, O cld . i% Y% u% X# c8 `/ j
movsd - a( N( B( w% o( a
movsb + j0 l9 [2 O# ?3 A. G
}
# G2 B1 v& O O2 M' L& a NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
+ e5 t8 c$ S6 Z/ E1 R _asm w* G* B) p0 X
{ ( ~! I/ [4 p" q# K( W4 N* @4 R
lea eax,MyMessageBoxA 5 x3 z5 w) U( I; a8 q8 W+ C
mov ebx,pfMessageBoxA
4 i+ q' g+ v7 c! J7 C sub eax,ebx 2 v0 P% W$ ]7 F# g7 @) k6 i0 e/ C$ A
sub eax,5
/ E+ I: p# W; K' c mov dword ptr [NewMessageBoxACode+1],eax # I0 b% ]8 W. x( b+ [
} % @' c0 }" J( I8 u
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID 8 g/ e0 N5 M. n5 W4 C+ Q, T
dwIdOld=dwIdNew;
! t; _" h8 c: d$ |' X# I HookOn();//开始拦截 + x! ~1 y2 X" |" c1 i+ c$ z! G! h
return(true); 1 M& G& {' B( q+ t- i& ^# O
} ; t& Y9 I" y# l/ o
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
: _: G, \/ k, u* ]. T; _& X{ " ~$ ^- d& v7 w
int nReturn=0;
% X2 ^; q, i8 q w7 |) A HookOff(); 0 ?3 e4 i! S( c' B( X- M% _5 X
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); : U* y) I7 B' @ `) |
HookOn(); 5 u6 d8 i; Q( [* O
return(nReturn);
% M- r1 S+ ^* `1 s} ! N$ [/ J9 ` y j# C4 g
void HookOn() 8 S3 J% f# T+ M1 |2 y1 n" d
{
3 g: @: f" U0 w7 F) O$ W: ?, n# m HANDLE hProc;
* y- ]# ^1 _$ Z- v2 a7 D$ R/ W2 H dwIdOld=dwIdNew; % l5 F! ?' W1 J& ^8 T% s( G7 f
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
' A4 j1 g9 B0 `% R VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
$ L) i4 Z0 P4 R& V" i WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
3 P; U0 q4 \: [6 V6 v+ A VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
) b# @1 s. W( D! U- G/ m% |3 b bHook=true; # v) `) u7 W9 C! }) \
}
( `7 [& t- z- R; yvoid HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
4 x/ x; R2 ?. m{
6 A6 O; y5 n: p- G, F [ HANDLE hProc;
- L7 j @' k4 v6 Y dwIdOld=dwIdNew;
, K- N+ I: u9 c3 y hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
2 s# y4 i# Y$ D7 k VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
: R8 J* w* b5 u- K WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); : B0 R& ]6 y m0 Q
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
# M. z# s2 U c: J- d u" S bHook=false; 5 ?, T. \! h0 Q; Y
}
) {+ t3 @! A1 t p/ e+ \) j9 w//测试文件: 8 u8 k8 ?+ H2 Q( J1 w: h
int APIENTRY WinMain(HINSTANCE hInstance, 9 _: u- X* ]* H! Z
HINSTANCE hPrevInstance, 4 z8 V; i& j1 W
LPSTR lpCmdLine,
. Y& `" z! L4 F4 s/ `: c- M: I int nCmdShow)
6 _) b! S8 N* U3 R1 ?! c g{
. n% y" l: Q0 y2 Z: i7 g& i: a F - t% q1 d4 P6 n! M; h# G
if(!InstallHook())
. H4 ~0 d7 y* ?; I0 |" @ { ; ^8 `! |9 R4 X' F: [, L7 Y8 T W' m
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);
0 a7 D* ~- c- ?% v% V: ~ return 1; & V; J s; K6 |
} 7 L: a& v3 f( R6 U
MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 & i# [! h Q J& ~4 v+ c
if(!UninstallHook())
6 |! o5 o' ?6 A: \( B {
0 L) ~% Q$ s; s$ z MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); 1 k5 P$ a" d3 T$ {! b- r
return 1; * x% P# Y, g; z5 x. M
}
% Z5 J- N; j: C0 g# U5 k: Z) s return 0; * ~8 [/ t5 [3 z4 }: ^: T5 [, q E0 _
}
& O( _6 o' r- l" w7 `[此贴子已经被作者于2004-11-5 18:12:27编辑过]
( ?: E9 K I% [% F# R' ?; o |
|