|
& y4 V$ H+ v( o# X5 r发表日期:2003-10-30作者:tomh[] 出处: 7 Z( L6 y3 L' k- u2 S0 P$ w
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
8 P" R. n! Z' F 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, 7 y& r6 K2 A$ @* d) ~. C% u# x' g
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: & b. I& R9 V7 K8 G/ `
BOOL VirtualProtectEx( ' o0 r1 G" j" m1 |* M6 Q
HANDLE hProcess, // 要修改内存的进程句柄 6 O6 l1 b3 V( d$ x* D; Z/ t0 d
LPVOID lpAddress, // 要修改内存的起始地址
. z4 v4 O/ O+ l. N& _4 o/ ^ DWORD dwSize, // 修改内存的字节 # Y) u: h" q, O n
DWORD flNewProtect, // 修改后的内存属性
/ ?- ?) M/ s1 k" b PDWORD lpflOldProtect // 修改前的内存属性的地址 6 o4 a8 H; v: l" s; x
); 5 T g! L, S L5 t y
BOOL WriteProcessMemory(
0 _' i, F+ E0 q6 Z/ { HANDLE hProcess, // 要写进程的句柄
A0 } P7 x& x9 d: K- v3 W$ x LPVOID lpBaseAddress, // 写内存的起始地址
5 {6 M( e6 t0 K; u0 b0 T n LPVOID lpBuffer, // 写入数据的地址 / v; _$ [- C. b8 a
DWORD nSize, // 要写的字节数
6 c! _1 }% |0 m" r- _4 V LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 ( j: f0 b1 x4 K$ m+ E
); ! b8 M% X" q5 z; `
BOOL ReadProcessMemory( * A# ~; z! \+ g3 t" U
HANDLE hProcess, // 要读进程的句柄 , m* j! X% n; h& _7 u4 o; G8 z0 R
LPCVOID lpBaseAddress, // 读内存的起始地址
" [8 }+ c) v& C0 C: W: A LPVOID lpBuffer, // 读入数据的地址 L8 ^6 o% i5 x& O* b: u
DWORD nSize, // 要读入的字节数 - ?2 H+ C0 X8 c, ?
LPDWORD lpNumberOfBytesRead // 实际读入的子节数 : x* x) q7 p6 \& ]4 @8 i
); 1 R: Z* `: a0 k& ^" m. d/ K
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, 6 F5 }! B7 \" T! j' f
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: 5 M- Y/ B! x$ a$ m3 X
其中Dll文件为: 9 b r9 b4 y0 ~4 K8 |
HHOOK g_hHook; % B# P( f& N$ J9 l1 F
HINSTANCE g_hinstDll; 2 ?( B1 t M2 d
FARPROC pfMessageBoxA;
5 J* f, X8 ~# x' c int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); 1 ^% O2 e0 G* R* @5 x) X# D6 I
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
. \4 F' V5 J' E HMODULE hModule ; 9 G' R0 p# M' h& P8 x5 r* |
DWORD dwIdOld,dwIdNew; ) j8 b4 ]# Y! X7 t2 G) B' X- a
BOOL bHook=false;
! R2 q& Q; }2 Q: w4 {( p$ ^! k void HookOn(); $ z3 i) v4 ~0 C' y5 l, c( F0 V
void HookOff(); 7 d/ G" C6 ^! T1 _
BOOL init(); 8 Y- b! o8 Y# I {6 R/ f* ]' p" Y
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam); $ v: @# z4 f4 i7 M
BOOL APIENTRY DllMain( HANDLE hModule, & h0 a& v& D( A8 F) }( [, o- O- d
DWORD ul_reason_for_call,
- t. M5 Z; D9 b* g* Q2 @/ ?1 h LPVOID lpReserved
0 y }" S( G3 A8 O )
: J, A; {5 y3 h+ t) K/ u$ h{ ' ?" Y. S; x1 r* s7 I4 S9 `. k
switch (ul_reason_for_call) + l W. f4 c G% c! i B4 E( x
{
2 U6 o+ r& G. X( Y# p8 S! @ case DLL_PROCESS_ATTACH: ' z9 c+ i, l1 K# k& X/ h! H
if(!init()) 9 P" N& O/ ~& n4 t( @
{ 1 v+ u- u! P5 G1 ^! H7 x
MessageBoxA(NULL,"Init","ERROR",MB_OK); ; T- k# K3 c9 m1 @8 h. P ]. a3 m# C
return(false);
/ R- ~) ^$ o3 O" w6 n. U* D } ) X2 f$ N C0 b, |* q. Z
case DLL_THREAD_ATTACH:
8 i; c! q- f: x" [. N0 y case DLL_THREAD_DETACH:
# N; C1 n$ Z$ z0 m8 f h case DLL_PROCESS_DETACH: w, Z; e0 G/ N7 @- b- T( j& F
if(bHook) UnintallHook();
. w6 |: g& J$ | break;
4 z7 `, Y8 R/ d7 S; G" ` {) T } % g, f/ `* J1 w% P3 B# ]
return TRUE; 8 I: w) m; O0 P. _) n' V2 ^
}
, ~4 `+ S) ~, ~! V' nLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 ( a; U3 H; M- {
{ 9 n' O8 m0 n5 W3 i4 _
- L+ p6 n7 `. _: p
return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
- A' i; b n3 r) O( Q1 V" I2 S}
; Z! e& \7 b; t- t1 }% DHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
9 e! H! `! k) P. U7 e; d# y{
' d% A( l# l( `$ U; J; t g_hinstDll=LoadLibrary("HookApi2.dll");
4 O5 T& Z6 K1 a( T5 B; W g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); , J/ m! ~4 e4 B3 c, G N3 a$ Y' f
if (!g_hHook)
4 @( @* ?% S( J; q( x7 C3 u{
. r) W$ S5 F4 C5 T MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
5 F1 I7 }% ]( v. h W3 m return(false); # q: |1 h0 } Y7 d
} " R$ E6 w2 L' @
7 `( U) |" c0 Z+ u1 p, `; u" O
: w, I8 d$ L% _# S, X return(true);
, q' d( v5 t* ^- {9 q0 |}
) V: m7 [" S. T9 pHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
/ n8 x1 W {" t' H+ m{ 1 s& P5 @+ d; K8 G( i
$ Z7 B- s4 b$ ~
return(UnhookWindowsHookEx(g_hHook));
, g m8 O% Y# C8 D9 }' B} 6 v. x& {" N" y! W. |- w, K: j
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
5 t0 }2 V7 F" b3 U9 D; _{ # Y: V4 @: h' N
hModule=LoadLibrary("user32.dll"); ' Q- e) H8 p6 ?# y# j( X6 [
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
6 a5 G) f0 u4 i5 i% L) A if(pfMessageBoxA==NULL) & d$ d& I9 j/ h; X) r( d
return false;
, a1 G9 T& |. y1 Q' a+ S& G5 j _asm A! p9 b0 o$ x
{ / }# Z/ t# H# r* w$ b
lea edi,OldMessageBoxACode 1 ~3 _6 E: ~4 g7 O* X/ O
mov esi,pfMessageBoxA
6 O% J! Z* _, P1 r1 t" I cld
0 V0 J$ J" [0 I, k. F" [ movsd
" k/ q. c3 [ o5 }# C. _7 L- W movsb $ t9 w' J" E7 [: U
} " T" g/ N1 h5 P) |
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 2 M t1 N3 }1 S5 h# t+ B
_asm % i0 D- V: f4 m% N8 ^) x4 S' m5 ? p
{
. y( o; m+ ~7 ?1 S lea eax,MyMessageBoxA . n0 x3 v" Y1 M" Y2 }5 W* i; C
mov ebx,pfMessageBoxA
b4 f2 z$ T' ~! g, H5 b sub eax,ebx ' u* c* _/ X2 P) \; y9 G
sub eax,5 # T/ }0 V: J4 @' [' y: z2 t) l
mov dword ptr [NewMessageBoxACode+1],eax
, G! s6 W% f; f: p } + ?5 w2 ^' U8 J$ r6 j0 n
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
: t. e/ D3 {& a# c; w dwIdOld=dwIdNew; 4 W% ?. N- p, Y) X7 C) g
HookOn();//开始拦截 4 @$ Z! R% ~: J# h) A' F$ L+ w' I
return(true); 1 r$ W% ~; k+ O9 J! r+ U2 E
} , H C( a5 m `# ?+ q
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
8 W8 } O @3 j9 E4 T{
5 C- n) O2 W% z. x# G- A9 Q int nReturn=0; ) @" y8 t, M5 N. `8 q; D
HookOff();
6 @8 s F, i& S9 \ nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); ) C2 _! ~8 ` @; h
HookOn(); 9 m1 A/ C* ~$ s# @; g: e4 c
return(nReturn); : |5 m* N7 h4 R2 Y% ?
}
4 X: j+ N3 i' H1 d! ^% L9 _void HookOn()
+ o- S8 E* a3 ]{
3 h8 A. q" v; i: R; d6 t: i% ? HANDLE hProc;
! ]1 g+ p9 p; t U$ f# |% _ dwIdOld=dwIdNew;
* u0 h/ U& x N( _4 g. b hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 : p' F! T& o; _4 t
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 ; ^1 `$ P9 u! C& D5 q% W" s4 f' l
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA * f( k7 [2 l# e5 Y' w
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 ( y& W( l2 |" e, ]/ a1 @
bHook=true;
% m) T2 t" x6 j7 i# p" Y} W9 w4 h7 |) P1 C$ k- q
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA 3 v& v& e6 x9 @
{
: Y5 z2 P: l5 q8 l0 C% l4 n$ @ HANDLE hProc;
5 S4 w3 ]( O2 |9 m dwIdOld=dwIdNew;
+ G+ K1 |$ L) [( R8 f) `$ | hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
% h# K. s- f! R: H- ^8 Y) r7 ] VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 1 R6 Z% Q9 X2 u7 r4 m
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); , F1 T- s3 _& F1 J
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); ; V- u7 {# n* g8 k+ O$ v' F9 b
bHook=false;
5 a7 x& T; O) H) V' t) S} 6 X' g$ i$ d5 c# Z! U; u c# x p
//测试文件:
; t0 I+ @6 r$ O" y0 \( zint APIENTRY WinMain(HINSTANCE hInstance, : v- d& F# s* _2 W, i& X- N% f
HINSTANCE hPrevInstance,
0 [$ x/ f% K6 a. u( e& L LPSTR lpCmdLine, . p& T- I& x3 I7 \& v* h: a4 ?
int nCmdShow) : ?$ k" L7 f! j" R; {
{
5 [! r3 O. O, H' z6 ^( j
4 u2 I% e9 F7 T- ^# R( w) n if(!InstallHook())
% v0 d" L- Z0 e4 g { $ S" M8 M- {7 O: O: R8 C
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); # a1 s" O( d4 u' A, m. u
return 1; % P; S0 v. h; {: c0 a" S
} % j0 ~0 }- m# _4 K L4 j3 o; {6 l1 S% `
MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见
! H* Q: {. Q0 j3 N. `. s; Y if(!UninstallHook())
" I8 b5 ~0 P* f( c1 J { - G3 K3 _$ K* {+ F e0 X4 V
MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); ' W$ \2 V- l2 y! ?5 o
return 1;
* V3 c9 B$ M8 ?6 s; D4 A } 1 @% b: x- I6 I
return 0;
, m3 \0 x. i6 ~8 s7 p( [& z. \% I}
' N3 Q' @3 G, v8 k% W3 G5 B[此贴子已经被作者于2004-11-5 18:12:27编辑过]
% L& Y8 c: ?5 p& b9 e4 J; d |
|