该用户从未签到
|
' c. O" ^" `$ z3 a发表日期:2003-10-30作者:tomh[] 出处:
5 f8 g; N9 q h7 z) T# tApi拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 U7 K# \6 L) K" P( H8 a( Y9 `
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, 9 V( E' w/ K; l8 {$ E/ a1 R; x
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: 2 Y5 ?- I) k* y1 T' l9 x
BOOL VirtualProtectEx( - ^: R7 Z, i# B/ j3 A
HANDLE hProcess, // 要修改内存的进程句柄
$ U9 F; I) M9 S6 r+ v4 ]4 b) T LPVOID lpAddress, // 要修改内存的起始地址
* f( T: k6 D) x4 H- G DWORD dwSize, // 修改内存的字节 * ?8 Q4 E- F! y: Q3 G6 T
DWORD flNewProtect, // 修改后的内存属性
$ k. `0 S+ j+ A, t7 U PDWORD lpflOldProtect // 修改前的内存属性的地址 # C' n9 d+ ]9 p: H- q: I
); 6 N( |; y6 J) M
BOOL WriteProcessMemory(
* O* N6 u# ^; r1 Q0 \1 f( S HANDLE hProcess, // 要写进程的句柄
' s( H @$ C/ h! s LPVOID lpBaseAddress, // 写内存的起始地址 ! I4 _; a+ a1 A
LPVOID lpBuffer, // 写入数据的地址 % x8 r( J: x- x* D+ {# Z
DWORD nSize, // 要写的字节数 # t9 `4 P0 s+ W: }
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
1 ~0 R' N* h' y4 e );
# |! }0 \% F8 J/ ~ BOOL ReadProcessMemory( * l2 d! v1 U6 @" k- F) g% K/ H
HANDLE hProcess, // 要读进程的句柄 - m7 E' A* N, ?0 ^8 @+ { O+ t
LPCVOID lpBaseAddress, // 读内存的起始地址 * F) @5 d5 e3 n7 k% N
LPVOID lpBuffer, // 读入数据的地址 - p- v: C+ M; Q& L' M( z h
DWORD nSize, // 要读入的字节数
& A4 n2 Y$ z1 K" o/ y, r4 s LPDWORD lpNumberOfBytesRead // 实际读入的子节数
1 G4 W" h$ I9 j4 y# H4 _, z. T );
0 ^7 v( G8 F- {# f具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, / T/ U3 l; P3 w/ ~* g. ]& V1 K
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:
# [/ O" C+ W+ D2 e! k其中Dll文件为: A. G% f' y4 a: t5 x
HHOOK g_hHook; " G6 G2 ?9 k: L; e( g5 w
HINSTANCE g_hinstDll; 9 }; Z, D- { x
FARPROC pfMessageBoxA;
* J0 ]2 l# R( V+ G% h Q: E int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
# h5 l+ v2 D, h7 E6 |3 W BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
, O l* o3 k4 e0 o% E HMODULE hModule ; 3 k' t0 B1 j# N/ e8 |% |
DWORD dwIdOld,dwIdNew; 0 k3 j2 c' H8 D$ |
BOOL bHook=false; 8 Y. n6 I- b" q
void HookOn();
* G' H- |; e8 d void HookOff(); 8 `% J8 A1 B+ I. e8 U
BOOL init(); ) C) L9 A- E5 N2 L- F0 D+ `
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam); # b! K% ]( ~: @. z* N# t/ N* G& _% V& e
BOOL APIENTRY DllMain( HANDLE hModule,
) k) \: G* v6 |, A7 o% e( n DWORD ul_reason_for_call,
/ H7 X0 `' a% K7 s6 S LPVOID lpReserved
" r# ]9 z6 J& a9 l( x- `" ?% ]( ?( J, ^" v ) 3 |- m/ }. j2 f7 Y4 s: u4 B
{ + q0 W) e: N8 M, N, T9 v) M( }/ [
switch (ul_reason_for_call) # v5 \. Y' J; t
{
4 |. ]/ P4 J( ]. C4 m6 a8 C case DLL_PROCESS_ATTACH:
" }' V* K4 {6 K) i) R3 ~' ? if(!init()) 3 e7 ~$ h7 E- d) s
{
& a8 k- H, [- ?2 \5 F5 o$ d MessageBoxA(NULL,"Init","ERROR",MB_OK); + i* k. w! e; O" i8 ^
return(false); ; H+ n0 C: @, z3 a1 E
}
8 H+ y$ E5 d ?; j7 K3 p case DLL_THREAD_ATTACH:
" k& C8 o1 }# k case DLL_THREAD_DETACH: : \0 p7 e+ U0 ]1 n
case DLL_PROCESS_DETACH:
7 U9 L" g4 ?$ {) F# F; i# ] if(bHook) UnintallHook();
' [, ~: x$ M7 i. Z' M2 S8 x' _ break;
$ q, C, E" } L; W } $ [ E5 f! W3 m* M4 i
return TRUE; . k- s; Y/ \! j8 M' Y, \' j
} + s9 w3 Z0 B" J3 x7 N) v
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
5 h# T+ b* `2 m! m( Q/ k{
1 d7 s% s7 w* q8 c
~6 F8 [. d: j" } return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); 8 u. ]6 o. l9 {7 b
}
" D( g2 S8 g9 U, ^0 \' tHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
+ r1 u6 U( T% M' _! I$ T{
0 ~* ` H; A+ \$ R7 q6 M g_hinstDll=LoadLibrary("HookApi2.dll"); - t+ c+ Q( I4 Z) h" a
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); + W. t0 U% N5 O
if (!g_hHook) % S0 s6 P% `( U+ V5 W
{
5 x& e: Y0 u: n! k: H- c- D MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK); 9 s$ P7 A+ N- m! d4 X# q1 q0 i
return(false); 2 i, F, q0 l# T0 z
}
9 A# [; W* l) e: |
3 N2 h' t. @7 r4 s1 G % I+ ]( b7 h2 y
return(true); 7 N# ?% Z4 U q8 ^; C* _3 f
} 9 G1 Q4 ] T- u3 s8 c9 ]
HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
3 C- L! O) e. X! a s& J{
1 |8 a6 l7 \- z# u, P
5 s( @4 a7 f; S8 I. z- U4 F return(UnhookWindowsHookEx(g_hHook));
& A3 n [8 K7 S- y; v} 8 d* u# R' C% b/ w% S+ r# _
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
$ G( Z: B! ^) \+ a" P/ O0 q{
+ q% v% z% s; m3 e/ y$ W5 Q3 W) M hModule=LoadLibrary("user32.dll"); ! w, i3 X, b% n2 H1 W, F; B
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 8 e. M+ Z% m5 y7 x2 G8 w. X2 e
if(pfMessageBoxA==NULL) & ^" V0 [! m& `) D; l5 f. ]2 ^
return false; 7 {3 H$ Q* x" j* B/ Z5 ^
_asm
4 ], [! q! ~0 @2 R9 h2 c& \ { - Y( \8 y: ?3 b" i5 a. m
lea edi,OldMessageBoxACode 9 g, z* k' l' P/ ~3 p# H: n8 a3 t3 C
mov esi,pfMessageBoxA ' k0 D h! }( p! V: r& t% E) I) C) J! y
cld
" M0 i+ i) x! t8 Q2 O, t4 z movsd ( S6 q0 d8 S5 P) ^6 W. v
movsb
# H8 ]5 {6 N+ `1 Y. m+ l } 6 X6 A5 b% E; j( v, ~9 z P
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 0 T+ Z3 n& P, k1 I
_asm ' T" G5 l! ~( [. A+ R* `
{ # G2 K0 L3 {8 L8 C+ c
lea eax,MyMessageBoxA 4 S% [- j" j+ e5 ?
mov ebx,pfMessageBoxA
2 M( J( n; A1 j! E sub eax,ebx + q W6 _. x* l% S" t5 H4 s( P r
sub eax,5 % r( f3 }5 } r6 [ u$ _! N9 ^
mov dword ptr [NewMessageBoxACode+1],eax
/ p% P) @% K9 Q; N. [1 q } # W |0 y8 o1 i
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID 5 J B* Q X ]' u Q2 `
dwIdOld=dwIdNew; + i7 z7 o* G3 {% X: D0 K- t
HookOn();//开始拦截 & k# D1 E. b. E# Q# F* H
return(true); 0 v$ s& S$ V; T5 y1 Z1 C
} + s& K8 A; Y Q0 ]" V$ d* x1 I$ a" L
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 4 x* o3 N5 U4 |" D# r+ C
{ ) \ x1 k, }+ Y1 a% \+ T8 y
int nReturn=0; 7 {; t% g( D) s/ ~2 K: k9 X1 [5 e
HookOff();
b0 r; o" {/ G' z5 d5 C& M& x nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
; a$ q+ M7 c# R$ P( U5 [8 I( B& X6 \ HookOn();
% X. P3 l! _ f7 E5 q return(nReturn);
$ z1 R- I H: \: n- ~0 M2 k$ q3 f} / ?; u* A* D7 ^: {3 b6 q" U9 X4 ~
void HookOn()
- s0 P% ]: x! z* G9 }% Z{
% G$ y! j1 W& l HANDLE hProc; # y6 A' x* V# i6 o
dwIdOld=dwIdNew;
. u9 Y! Z2 Z% J' M ^, Z; c d' A( z hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 + K- k$ p" k2 c7 A$ ]
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
% F1 h7 o' h' w+ c* y WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
* B8 j: ]1 H ^ VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 . c6 n" Y+ o/ D" Z8 V0 T" w1 [
bHook=true;
" {4 Y1 D8 j- B- }) V}
' v( `( |( ]/ d1 yvoid HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA ; o" g8 v9 R, o4 B g, b
{ ) s6 }1 v8 R+ w
HANDLE hProc;
# V; s! r$ B8 ^; w/ ^! |$ C dwIdOld=dwIdNew; $ S; w! e9 ^+ a& F# |6 J* M, ?
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); + @$ |* s# _) T+ V; C9 F; X/ i$ P
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
: Q2 U+ \3 ^$ Y/ _/ _ R WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
: L% { D& V) O8 ] VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); 1 G! M& R* O- m a) d: F3 }/ i; f1 B& A' R
bHook=false;
' r1 S$ `$ S3 A d7 v0 S} ! d# y U4 F/ ?! t( V6 ^
//测试文件:
" A, ~3 ]' o7 L% {9 R! L0 F& `int APIENTRY WinMain(HINSTANCE hInstance, * K6 L( `3 H% b: F% E
HINSTANCE hPrevInstance,
8 Q6 l5 ?. @6 s. ^ LPSTR lpCmdLine, " ~7 x1 p% q# Z6 Z$ C
int nCmdShow) 8 k. J! w7 l7 q' r
{ & [0 T( w& e! n8 w
" D4 ^4 _: T/ h) j3 B if(!InstallHook()) ' J- B2 E6 X! P2 D
{
1 j- P% w0 U6 _ MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); ; I- b8 r1 u# s/ c# d
return 1;
4 v, Q# F: s( P" B+ Z }
+ ]2 t: r% \; S' N$ r* Q5 C MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见
# I0 L' {5 s$ r8 S$ [8 ^ if(!UninstallHook())
. ~2 @+ F. J' }8 W {
0 @! I: ?. d& I& H, } [ MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); + S( t/ x! ]% X# W7 |, e3 f
return 1; " b9 ?# m1 f5 z& S" I
}
0 b. _. ]6 b/ O. \9 e return 0; 3 u; b$ Y* s% W6 P+ A4 X, h0 V
}
/ ]- Z% _6 _" `6 o2 Q6 j[此贴子已经被作者于2004-11-5 18:12:27编辑过]
6 I, h8 ~1 [& k9 U0 b |
|