|
- p$ r3 Y* m0 y7 F, ? Z
发表日期:2003-10-30作者:tomh[] 出处:
5 ?) k5 d" \* p8 K' aApi拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
" K( m* W) {: {* C5 u: a 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, , _ G& i; D. N7 b
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
) H |" w2 t% g6 ], v5 l3 ^, n BOOL VirtualProtectEx(
( B, {& _: F4 K/ w5 `1 E4 h HANDLE hProcess, // 要修改内存的进程句柄
2 d5 K% g- ]7 G. [9 ^/ s7 A LPVOID lpAddress, // 要修改内存的起始地址
& ?6 |7 d* c7 o! U DWORD dwSize, // 修改内存的字节
; M6 S2 g [8 D1 f9 u DWORD flNewProtect, // 修改后的内存属性
, X1 r" h! c! W& w PDWORD lpflOldProtect // 修改前的内存属性的地址
$ }3 K r. T# q' V& T ); 5 F& V9 w- f5 \' |' g7 {
BOOL WriteProcessMemory( ! m5 G* n& L, P" s( @5 C$ T3 X
HANDLE hProcess, // 要写进程的句柄
' ]5 s, C; P- [, Z3 W! E LPVOID lpBaseAddress, // 写内存的起始地址 $ i) C0 G& G! o
LPVOID lpBuffer, // 写入数据的地址
, o, O3 @. C8 f' e DWORD nSize, // 要写的字节数 " W/ _1 q. j. ^) v8 X0 D H
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
/ l+ Z1 n2 z6 ^! S; b2 x$ X ); 7 h: R' Z; I; o5 T9 X
BOOL ReadProcessMemory( ) s. ~" y1 }3 O! H) @
HANDLE hProcess, // 要读进程的句柄 3 t5 g* t% q4 ~4 G9 X! b, l, M% U: Y( m
LPCVOID lpBaseAddress, // 读内存的起始地址 9 G2 E' K: f/ d! c
LPVOID lpBuffer, // 读入数据的地址 , a) O( q' s/ C: a4 S
DWORD nSize, // 要读入的字节数
, t5 g7 y4 X2 k! u! ? LPDWORD lpNumberOfBytesRead // 实际读入的子节数
5 n7 I% N# `7 Q ?- l* U );
: P7 Q& Q" S3 \" Q% d9 k% ^具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
: l9 l4 Z3 x+ H& T* [; A4 @因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:
9 v, h a, i6 F+ d. a其中Dll文件为: ) Z' C% _6 N# J6 }2 B# H; G
HHOOK g_hHook;
6 q4 X# R( P& D# o* t1 y: {% ?+ h/ f. ? HINSTANCE g_hinstDll;
8 D4 `. i) Z. @( m" g FARPROC pfMessageBoxA; + W4 ?$ a% { s$ N$ D
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); 5 F& \* r: P$ i' [; S8 \/ T0 S
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; # O7 ~- j3 m& ?' e
HMODULE hModule ;
1 k) A" @, s' n DWORD dwIdOld,dwIdNew; , S1 Q' r3 N' t3 ^
BOOL bHook=false; / d, u1 v! C# L; n' s
void HookOn();
! P) r" b5 g/ s2 K' K/ Z void HookOff();
# S- F9 E7 D# ^7 \7 X" f BOOL init(); & h$ i+ u$ ]3 Z4 A) x0 ] y
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
* v, v0 V: P' ?BOOL APIENTRY DllMain( HANDLE hModule, ) S* s' w5 U! C1 z% s
DWORD ul_reason_for_call, 0 P/ E* a+ b ^ }( K
LPVOID lpReserved
! R$ A! J5 H2 }5 C" |% ~( C% a ) G' F7 }7 i3 a
{ - f! p% b% l1 y3 q0 e
switch (ul_reason_for_call) 4 v# J" q/ d S# \1 s: Z) n, `
{ 6 U( ~, l2 Z o. W6 Z- E$ R
case DLL_PROCESS_ATTACH:
; H O' p; A* P" j* ~* V7 U if(!init())
" u; I. \ k+ Z: ? { ) V% T5 u0 \/ d, o2 L/ ]) v/ z
MessageBoxA(NULL,"Init","ERROR",MB_OK);
) e) Q% R7 {, a# Z return(false); * i# F9 h. q% {- r6 F4 f" w9 ~
} : X; H6 F" f6 D# i/ l: B1 r/ C
case DLL_THREAD_ATTACH:
' ]% G; i) F0 n. y case DLL_THREAD_DETACH: 7 ^, t: z+ ]3 |# u% Z4 Z, f
case DLL_PROCESS_DETACH:
( Q3 n7 S1 _) { if(bHook) UnintallHook(); ) T3 C6 M' q( a( Q3 h
break;
l0 M% X% A7 r0 k! ]+ @' d1 E2 O }
- H8 L8 q$ @- W return TRUE;
! u! z: y# N. c- E R& c3 q} " e, W' y8 r7 X* X. o
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
( r* [- f) {8 i" k8 w{
' [1 U: {1 K6 ]
: m# _/ Q* p8 \: y return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
- n/ t, I5 s# b& ^) x) D} & [" A/ W; s" m3 k. A
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
4 }+ l; J8 b/ `* S O r: F{
$ b4 B: C8 G: I g_hinstDll=LoadLibrary("HookApi2.dll"); ( N8 l- g* m/ p" a p) P: C
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); & S: v) }5 G* j
if (!g_hHook) + a; Z" y2 ]2 i$ t- \
{
2 W2 Z. R7 N/ f4 Q MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
# W3 p% R% M( k6 r2 u return(false);
8 M7 s+ H! D$ E( o1 H/ `. K8 A }
# M9 Q$ Z1 P ?+ a* ^' E! x1 q : `4 {! X! j3 w
* [4 }% b# K" c: K3 p$ L j return(true);
- Q5 S: }3 o2 X( J# n b2 @} / l. f& K$ t& y6 A
HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
8 B1 D6 p/ ^9 t) b# S{ 3 F. C1 w! n1 x
+ L9 k& F) N, P: ^, T9 g, V% p' E return(UnhookWindowsHookEx(g_hHook));
2 e7 `4 B! p6 Q+ {/ b3 N} * [/ r# N& M' U. T: \
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
# W1 `. w {! \2 h% M{ 1 f b* F/ W' B% Z
hModule=LoadLibrary("user32.dll");
) V2 z2 Y- r+ a% `, c9 `2 R' X9 x pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 9 S' c" h6 h- H0 o# i# a. T7 w4 e! t
if(pfMessageBoxA==NULL) 1 A g" }5 a& B
return false;
3 L. x% `5 c3 r* ~ V _asm # I5 p, t; d$ H9 b# \
{
) r8 \7 N7 \$ A$ i# T lea edi,OldMessageBoxACode 3 @% E: ]0 r+ i/ G
mov esi,pfMessageBoxA
1 |$ C6 C# W& s% O cld : l3 k. M5 {/ ]: q! m0 J0 k
movsd ( k F, f6 @0 x, t" |
movsb
2 H) m- e+ j# V' X+ t } 8 @& s7 n" x4 b/ g) r
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 3 [* a' i+ o" ?- c+ e5 r
_asm
0 s3 _& ^% U* [1 K- J8 O* o5 `! L0 [0 M { 0 I$ P+ _; x( V( D8 t+ p# ?
lea eax,MyMessageBoxA 9 M5 t$ y2 K8 K. }6 q
mov ebx,pfMessageBoxA 9 d+ Q2 A0 j5 P. l
sub eax,ebx
2 }) _! m7 _& I& J/ r( ?6 }, x sub eax,5
! C( ]- D: n; [0 M& B. H! b0 V0 J* a mov dword ptr [NewMessageBoxACode+1],eax . {4 M1 t- m Y! g- g0 _* o/ e
} 6 w. r5 v( |" a8 L* I1 I. t# i% @( i- }
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID 9 }2 j) y+ p4 W9 m$ R: a& z% x
dwIdOld=dwIdNew;
; G0 x$ g% T4 O- z9 \6 H0 T9 z HookOn();//开始拦截
6 B5 S: T* {, x. Z5 @% s3 @, T return(true); : j; f1 I% O' `! C; }( `
} ; F+ Q' L$ v3 G# I
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
- |" e3 w2 y% W+ V* ?+ \9 `{ " n9 i( r+ I7 N' k% {, |( u3 k- l
int nReturn=0;
$ C9 U3 f/ q5 B+ t2 V HookOff();
8 f9 f4 @6 |$ j: a$ F u nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
' g# v/ z, {8 S7 ^0 B$ Q HookOn();
) A0 a; z! {5 m! q( n. V return(nReturn); 4 @+ l! F$ g+ Z8 L1 A. Y8 s* p
} 8 Q$ C3 S+ ?4 L9 \, ^7 C- Q! o2 Z' @
void HookOn()
2 U+ y+ q7 }' \7 m6 d7 _{
/ |0 Q9 F2 M% ?1 _2 i+ O HANDLE hProc;
7 v8 X3 O i% p/ ?6 f4 |& t9 d$ L dwIdOld=dwIdNew; % B, K: z& C6 V
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
- K6 X8 n9 z: @2 l8 l# `) A( { VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
' D8 O2 F1 W1 D4 R+ R WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA $ `! Z" M. I7 H2 D; R1 {% R, `
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 " [/ G6 @; V$ V; i! C
bHook=true;
: G9 S. K' o' T} 8 m: M6 ~2 e% t4 y( j
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
. [# @ S5 }2 v7 @* h* N; a+ j7 V- T{ & {- g1 z5 E" G8 `. N) r. [ ^, w
HANDLE hProc;
/ {: N' A5 u% F0 N/ J/ H dwIdOld=dwIdNew; 3 j9 l1 a( y9 n0 B: @' J8 i
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); ' e) d+ c0 N) b2 V0 y" Y# D2 ^
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
8 v: r5 g3 v3 j3 r WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
9 v$ B" i- t, ?& F$ `8 n7 K7 b VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); - s( @: T0 y2 M+ N7 u8 N8 N
bHook=false; * a, ?5 b; J- q+ L
} & V6 D9 z* w0 ` k3 @8 _2 M! c! o; O
//测试文件: 2 B, f6 j* i0 v" r
int APIENTRY WinMain(HINSTANCE hInstance, 3 V1 }: E: n& U0 D, _
HINSTANCE hPrevInstance,
i* O. C/ M& K2 g; y! q9 b: ~8 n LPSTR lpCmdLine,
. r9 p1 j% j u9 x [8 J# }0 \ X int nCmdShow) 7 u$ l) @8 I- Z: g b
{
3 S# R+ l" m% n# i) U! M) d0 c 1 C& @% b- g1 A! t9 K
if(!InstallHook())
2 V: j" Z) \' i8 v3 X {
. q; N* Z- W% R MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);
, ]2 ?: k3 x6 ~+ N* P; L return 1;
2 `- u" h Y6 l" C2 R7 Y, ~3 i8 \0 @ }
2 O0 b" o% o0 K8 `% k6 c: U; }8 z MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 . z0 a4 g" I( d o" z( M7 x$ d
if(!UninstallHook()) 9 T* L, m% Z" o. ]5 D
{
. Y9 }9 y+ S h) { MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK);
( [ W# \3 v0 H return 1; 6 D% m) h4 B) C7 l4 s, Z# f8 w
} + S; a3 D/ s0 v' j, e, z" T( M
return 0;
o; q/ [9 f& d2 N} 7 Q: o* Y# ^$ q/ i7 ~8 D9 g* d: n
[此贴子已经被作者于2004-11-5 18:12:27编辑过]
" X1 V4 Y4 {; k& ? |
|