|
' g$ e$ z; w, b; c$ a3 R- P发表日期:2003-10-30作者:tomh[] 出处:
1 g/ }, V' k% i0 UApi拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
: X4 Z" X/ ~. ?4 ^7 I 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, . }% e+ j* [! L3 K5 d# C
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: - B# T1 m R% B, F p9 V% O) |
BOOL VirtualProtectEx( ' ~! t& H0 u( j, {5 [
HANDLE hProcess, // 要修改内存的进程句柄
1 j2 f, e' Z* p& G3 B LPVOID lpAddress, // 要修改内存的起始地址 ! E, D3 Y" ~' \& ~7 ]% l, l t
DWORD dwSize, // 修改内存的字节 ; Z) {0 x. A" R+ F
DWORD flNewProtect, // 修改后的内存属性
/ N9 B' z# N( T' d' ^) t7 i W PDWORD lpflOldProtect // 修改前的内存属性的地址
( |% ^& B8 I% @0 J9 ?5 |. M" l" b ); / ?: w; K O5 A7 s9 O t
BOOL WriteProcessMemory(
' p R, u6 ?! z HANDLE hProcess, // 要写进程的句柄
% Y7 K2 l7 k7 z* g: g" @ LPVOID lpBaseAddress, // 写内存的起始地址
' Q% ^- t. a$ `5 g# x7 G; W LPVOID lpBuffer, // 写入数据的地址 " c ?% l7 g T6 E5 v& M
DWORD nSize, // 要写的字节数
( F/ @% C& i7 F( c6 n! i5 J LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
: s% Q# i/ ]3 W7 B% c5 U ); u0 p G( u+ @! k% H
BOOL ReadProcessMemory(
4 o% S2 O6 D% Y7 E0 q HANDLE hProcess, // 要读进程的句柄
, u/ U! e& [8 A9 Z LPCVOID lpBaseAddress, // 读内存的起始地址 ' h, S% }( g! `! y3 I: N
LPVOID lpBuffer, // 读入数据的地址
; ]; o3 B: g% W- p# G5 [: ? DWORD nSize, // 要读入的字节数 ' R, G8 Y4 _9 H0 o( H
LPDWORD lpNumberOfBytesRead // 实际读入的子节数 / D6 G; y1 F1 Z- O4 |
);
# p5 S+ @' P# K I7 H( n具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
b. S+ n* w, f6 W8 g& K因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: 5 u" C+ [' _4 s$ ~& R$ v
其中Dll文件为: ' Z g" `% z" [& o2 e Z7 G3 ?
HHOOK g_hHook; - M9 V9 O( h! o( e1 m6 c/ K1 [! @
HINSTANCE g_hinstDll; " ]4 m: j' [) ?" q. H- M: l- U
FARPROC pfMessageBoxA; . P8 J/ W+ m& ~# e, T, s5 ?
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); 4 _" F' d3 ^ d; @1 Y8 |# x" U) b' ?
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
( I# w7 ^* M* b1 r5 F6 m HMODULE hModule ;
, B6 F, K4 G! L+ M# _8 b DWORD dwIdOld,dwIdNew;
* \+ K" p! ^& g* ^! T2 M BOOL bHook=false;
1 t2 a1 s/ C3 s' ]+ I void HookOn();
+ P: k6 ] Q/ Y void HookOff();
8 B3 b1 G, ~9 |; k- h BOOL init(); - U. A0 P- d+ I/ V' U% ~" N
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
& u7 h+ ?; [, J2 A" w/ DBOOL APIENTRY DllMain( HANDLE hModule,
, }- O/ p( J/ B2 p, F0 u DWORD ul_reason_for_call,
6 A: {/ l8 G9 ]" v0 w" S LPVOID lpReserved
6 s- h: v3 X3 h: R )
' w6 }# i9 j$ K; Z# x+ y{
; N4 U8 }. N, N6 q% A+ e0 L$ C switch (ul_reason_for_call) + S4 n, q" P8 G4 n
{
7 m8 Y1 t6 k" ?4 o9 O, r case DLL_PROCESS_ATTACH: " p9 X. d0 c$ H8 o X- \% ?
if(!init()) 5 x. V2 ]$ W4 a! t* ?5 a5 `
{ 6 U" S; k/ z7 S1 f
MessageBoxA(NULL,"Init","ERROR",MB_OK);
/ c" c7 I7 M( E% \& M8 y return(false);
7 ^+ \2 n; [$ r1 [. O! k. [. ~. ~ }
) {/ Z- K/ `5 B2 }$ k8 K2 w# v* K case DLL_THREAD_ATTACH: ' ^( s: }# m7 t, G5 P: h3 I+ E
case DLL_THREAD_DETACH: . f; W# F; i* ~
case DLL_PROCESS_DETACH: ! X4 g' u( {6 M' `$ J
if(bHook) UnintallHook(); ! ~2 ~& v- q0 c0 h- i }9 }1 x
break;
. d3 e% a9 I9 u* {/ [: l } , r4 J, R: A6 ]' y, J
return TRUE; " R5 [/ |( l* @" b) }8 }+ n
}
; {# s" Q' @7 ~( Q4 B9 oLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 9 i' N0 H7 Y' F5 j# A m3 r
{ * b# M- X% a2 `1 z, K
% o( z0 j/ t" }' z/ D return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); . Y* }) \: Q9 B8 V8 w
} - h* p- e* Q# e
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 5 f9 v, j2 ^/ ]
{ ! z! ?& j1 A& ^) T' t( |- d$ L- {
g_hinstDll=LoadLibrary("HookApi2.dll"); # ~( E$ [* l( {& p4 u
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
! [% }# v _( T- U& L3 g( L- ~6 \if (!g_hHook) 0 E( G% p3 C3 g/ v b
{ ) z! a) O5 R4 J2 p2 V
MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
$ |8 l# u8 H) C5 b6 A# p return(false); * b2 P/ X2 d5 y5 ~# \* r/ ^4 B) O: l
} & ?9 r5 s0 t( O# z; V
! D y8 K6 |4 L
1 b5 V; C4 h* q( r8 E y$ ^" Z1 K return(true); 4 x% H& v" G$ N2 m+ l' ]" d
}
5 s" p0 v( n" {- SHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数 $ P8 p! j: P4 x0 `6 J, E8 f
{
9 F9 P$ K8 Z3 }
6 }$ w- S4 L! h return(UnhookWindowsHookEx(g_hHook)); $ p# |6 O! e3 A7 o& m$ o( t
}
?6 K1 B) m$ V! b& M j+ |8 e3 S4 pBOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令 * t4 P6 d9 i" G; B& H) E% d. S
{
, ?' x9 d) I0 I+ T" e9 B( b hModule=LoadLibrary("user32.dll"); & L: X! `. P# q' [0 x/ t
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
C2 E& k4 j6 y: N. W+ B if(pfMessageBoxA==NULL)
/ K* K5 m7 G, o; d. J1 Q return false;
& l; m4 F+ P* R4 M& i( r9 Q _asm 8 t G+ P1 X& M* H$ ]
{
. R8 H. n8 v* n* F, k- [# @ lea edi,OldMessageBoxACode
& t: H; G) \5 t mov esi,pfMessageBoxA : T9 @; M% ~, w' {" I, a8 H
cld
/ Y9 K* q+ g7 R9 Q movsd ) h# Y6 J9 t, u$ r, M
movsb ( N5 ^+ _* W: Z
} - A0 P; } S* P+ V
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
" ~4 k: A1 h6 M P% H: @' Y& ? _asm ; k# y- _2 M3 H( W: J0 a
{
# C) G/ Z$ O7 w" M) W% } lea eax,MyMessageBoxA - n8 ]4 F# f2 S0 v
mov ebx,pfMessageBoxA
" P7 b2 I8 b3 m1 o& } sub eax,ebx
H# i; F) J6 R; S sub eax,5 : M! T% S0 Q" y1 ]8 L
mov dword ptr [NewMessageBoxACode+1],eax
5 E! H" l: z: c3 W* D }
$ ^) I4 y" n; r7 x, o8 q- J& G7 J dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
- h$ i2 B- v! m- x' R dwIdOld=dwIdNew; / ]9 n- H% g1 G+ {1 R% V+ W
HookOn();//开始拦截
3 O7 O; u0 s& p; X3 M- M/ s return(true);
/ G* _5 k) j- a' B* l( L}
* _. c' K$ X3 }1 O9 Y1 o/ ^& g! uint WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 ) d, U) V5 }; S: ?
{
4 c- g7 |9 g- n( `, R- J, L& I int nReturn=0;
+ H" r" z/ }0 C( J( e9 s HookOff(); $ L) ~* x- Z6 y
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
% \7 u3 k* F! K% @, ?! m6 N HookOn();
7 q; }3 u9 j2 o/ C/ R* y% B' Q return(nReturn); 5 ?* `4 ]+ o- o$ K
}
* O# M5 C) c. F+ v7 C* ?0 qvoid HookOn() / ?2 u/ o8 J: X2 y
{
9 N* _& a4 U% A9 v HANDLE hProc;
# J% Q8 }$ O' v% o7 e+ Z dwIdOld=dwIdNew; , o5 _& g& T* P0 k
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
$ I9 U- _ V: j# c VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 , Q9 _9 w$ V2 \( C: @% _
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
) _3 S/ s" D( X) @5 a VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
: G7 y% Y- M: g4 ` _; H bHook=true; ) P; U0 S+ _! H4 r( W4 @3 V
}
3 G1 N! d9 k$ j3 ^, }void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
9 A( @7 G# `# y{
' p6 y$ M6 g) V4 v8 W' E HANDLE hProc;
: V% P7 [6 V7 D3 s, M5 h dwIdOld=dwIdNew;
3 k7 s4 L/ W+ G1 X, c H4 F hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
+ Y; _- d9 A9 ]4 ]! [8 p% D VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
* B/ k b# b* u WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); 1 X3 k/ ~( G" o& K
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
/ M/ _( Y+ `1 m% e bHook=false; ; h# N5 S1 f9 n' ?
}
/ Q9 i& r! P5 l) ^5 q( {6 [. P, e//测试文件: 4 g% J$ V# P' d" }2 |( w
int APIENTRY WinMain(HINSTANCE hInstance,
# N- l8 W; n) O- G( r HINSTANCE hPrevInstance,
4 p* P8 |4 o& g5 X LPSTR lpCmdLine,
: ^$ P- c2 @+ ]* K int nCmdShow)
p( b( x+ B- [" Y* r }. Q{ / z4 ~: m4 w) e( \
# ^" K* {! N3 }6 h5 `( c, @* d
if(!InstallHook())
" ?. u1 q, I9 Y$ S! h2 A& \7 U% x { 5 U5 b% G/ F9 z; `3 v
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); 5 _1 o- F" h9 G) N3 g
return 1;
7 F" U" C2 x: `5 j" I }
5 i. O: V( \3 ?* T7 \3 } MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 # _; o2 A: v, I5 P6 E2 L
if(!UninstallHook())
5 i/ G9 V% N4 }1 g8 N( x { ' ~4 G5 {7 n) @+ K `) Z
MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); $ O7 ~: S0 I, a) l0 p% @
return 1; 9 a3 f0 m9 M) L# p2 b( @* v
} , m+ K4 u5 r: c% w# H3 i
return 0;
# w3 i T# }' A- r+ @( n3 b}
" [2 y. f* B5 E! k8 t: X[此贴子已经被作者于2004-11-5 18:12:27编辑过]
5 D1 ?2 l& b4 h- ? |
|