|
2 P8 }% q) p- t7 F发表日期:2003-10-30作者:tomh[] 出处:
1 K! k) f$ M s" E/ F" V3 MApi拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 1 W6 p5 o/ N* P( s! `0 ^+ F2 B5 }
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, & ?# J( O" Z( U; N
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: - a q/ {' r- z3 {' W
BOOL VirtualProtectEx( ! z% W4 |* Z K9 i! J- @7 Z2 O
HANDLE hProcess, // 要修改内存的进程句柄
* v( B- `3 w, Q8 ]; v0 H4 z( \ LPVOID lpAddress, // 要修改内存的起始地址 , E. U( [/ P6 S5 i1 d
DWORD dwSize, // 修改内存的字节
- j" n/ I) X2 _% a- V DWORD flNewProtect, // 修改后的内存属性 8 r4 `2 k3 ] k9 P+ L$ a
PDWORD lpflOldProtect // 修改前的内存属性的地址 ; D8 i |; A1 p3 D
);
2 M7 U+ @! u$ b. A BOOL WriteProcessMemory(
9 H) {% r. V$ p& u! Y* ] HANDLE hProcess, // 要写进程的句柄
- C1 m+ r" S7 f7 ^( \ LPVOID lpBaseAddress, // 写内存的起始地址
* d: x' \( ^ ]- |/ F6 ^ LPVOID lpBuffer, // 写入数据的地址 2 \( \, N2 z3 }& `. o0 Y1 ~% R! T1 u7 |
DWORD nSize, // 要写的字节数 ) G5 Y0 U. V1 }+ P7 b$ p3 U7 h k
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
' z5 f8 k8 p& a1 K1 M ); ! h$ E0 a. X, Z6 a) ? d
BOOL ReadProcessMemory(
8 i7 O' m" l- V% l, }# s% Y HANDLE hProcess, // 要读进程的句柄 ; U" ~3 l/ i' W- z( |" e
LPCVOID lpBaseAddress, // 读内存的起始地址
. c" Y2 u3 @' ^; f! m LPVOID lpBuffer, // 读入数据的地址 2 x% E! X& \( w+ {! |& u7 ]( v
DWORD nSize, // 要读入的字节数 7 p1 |' w8 I ?" a& l
LPDWORD lpNumberOfBytesRead // 实际读入的子节数
6 ~4 k1 L2 t2 }6 ? ); 9 S- N! z7 i$ d4 `5 C, X
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
6 t8 t2 f( s; c, b( c- w' \因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: 9 `- Q. e2 f; e( ^' u: Z/ d
其中Dll文件为: - r2 [; X0 h7 ]
HHOOK g_hHook; 6 V/ r Y5 \9 d7 r: o8 U+ x. K5 L* O
HINSTANCE g_hinstDll; 2 u/ m& Z9 U# S6 a, G" z4 B& Y+ Q
FARPROC pfMessageBoxA; & R/ f! P- N; r# F# P
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); 9 F* J) i4 f% y6 x" { e. M
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; 2 q; Z2 X/ \# ]1 n h7 k
HMODULE hModule ;
* D3 o4 v: q! V4 f" T DWORD dwIdOld,dwIdNew; , T% X7 j1 M1 D3 X' Y* |
BOOL bHook=false;
# m+ J2 q" N; R8 k void HookOn(); 0 d" u- T8 H j. m* x
void HookOff();
* n) s+ F! W, p BOOL init();
3 r( i3 V" o2 d9 ULRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam); - I, W u# n5 W4 _
BOOL APIENTRY DllMain( HANDLE hModule, + s" B$ f N3 A. r
DWORD ul_reason_for_call, ; p9 Y* B% l5 H4 }! N
LPVOID lpReserved 9 t1 G( z, [' D P2 y( w+ @7 ~
) ) a" M$ h' O9 b# C8 r" Y
{
d' G9 }. c+ u8 o; s1 P switch (ul_reason_for_call)
# O4 s% g" m9 {1 z' j { # K' Y+ z+ h- s6 I1 D% a& D
case DLL_PROCESS_ATTACH: " j- J4 r( H* H7 D; D6 s
if(!init()) 5 G+ x" c+ W& z3 j/ ^2 t+ l E
{
+ ~, s! e5 H' C MessageBoxA(NULL,"Init","ERROR",MB_OK);
1 `. H( W( z# Z) C$ x3 A return(false);
, I: M, Q7 Y' ^* E } ! o5 V8 h o7 _# Y6 J
case DLL_THREAD_ATTACH: ; W& v I }" c/ \/ y9 r" t7 s" V% h
case DLL_THREAD_DETACH:
5 n5 j" ~& |* f/ j6 M% T case DLL_PROCESS_DETACH: ' |9 T1 [2 m2 f& p7 B6 K+ `6 d& |0 }* c
if(bHook) UnintallHook(); 4 s4 G) {) y) N& X* I1 ~
break; 6 i9 w/ U& g$ u+ @
} ! Y! S; h/ V- N6 c* `
return TRUE;
4 ` B" Q* N \$ ~! _}
8 a/ c5 s9 g7 [0 tLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 : n, M4 O" D8 ?3 E& \+ K% k
{ % U5 k1 f- _0 v8 C
5 b! o# w" R: G; U4 S
return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
# D8 |, h6 H" X3 g0 R( I( I} : I2 g. w& Z0 v) q- o
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 6 G, N: z! m% `1 O! O0 R
{ : j! D' l) B6 H: h- Z
g_hinstDll=LoadLibrary("HookApi2.dll");
; ]1 e" r. U* r6 ]" n/ Y& {9 V g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); 0 \1 |9 Z5 o: ]# `
if (!g_hHook) ! L0 E( }. ~+ v
{ 6 k6 q$ i. h/ a% i+ {
MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK); : y5 O. q0 \% D0 B
return(false); + V6 @ x& W. t8 t9 R
} * p1 V g5 Q1 f5 s2 R
+ r: Z B0 Y. V% X) G/ O+ ~ ; s5 ~ m( M1 L; |+ @, O
return(true); 3 w- b, m0 Q- k, o0 j+ j
}
7 p$ w& T% g$ F* z3 kHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
( U. H9 e0 l6 Z F/ l{
8 E' L9 v/ n* J: V" `0 `5 [
( n3 _. u, @! Y* A return(UnhookWindowsHookEx(g_hHook));
* K$ s$ K4 k+ i* N$ m} ! H- ]! u: Y0 T
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
6 A" l+ C2 D0 z{ " o E0 C* f! V8 e" k
hModule=LoadLibrary("user32.dll");
2 x: a- `( g4 Q, f pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
( i0 x0 I/ l0 r& M1 j) u if(pfMessageBoxA==NULL)
3 d0 ~) ^! |% ~2 }: K1 t* {) l return false; % B. X8 P' z5 B1 _
_asm
9 j4 S. G8 _' n# e& C9 V {
0 B4 B0 S$ N/ R; W lea edi,OldMessageBoxACode & Z$ Q( O/ y8 Z4 `1 n& q
mov esi,pfMessageBoxA
( d( Z, h* M" L' q+ ^2 o# v cld + j% X- K; c' ` D8 ]2 C; Q
movsd 6 E: f0 Z2 m; Y1 j" U& X* M
movsb . l9 x+ z8 R; S8 {" n) o3 f& Z& n
} / O7 q9 z( h) u9 j
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 2 s2 y$ _# R& D
_asm 3 r5 ], n' s* l/ p- W
{ + j: e' R2 D9 [
lea eax,MyMessageBoxA
5 o1 ]$ {' x. z' m0 w mov ebx,pfMessageBoxA 4 l; x; l0 U" {0 b9 B6 n
sub eax,ebx + `! M% k: J S. F9 M
sub eax,5
3 B$ `9 K6 m6 W6 e) _3 l mov dword ptr [NewMessageBoxACode+1],eax ; \# u, c( F0 V; T5 e0 X
}
: {, }" V1 a) a# e dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
( b! {8 p; L: f" h dwIdOld=dwIdNew; 8 h/ M& Y$ S7 ]* V: z7 L1 ~
HookOn();//开始拦截
2 H. [9 l! g7 T8 r return(true); # s2 k [, v6 [) ~' }, ^7 o
}
; u% L/ t; O3 o; \4 i" {int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 5 @% D' D- O% M7 g( X9 C) F9 \/ t. |
{ ! y% [$ x$ k! z* x, @& m# w' f9 Z/ R
int nReturn=0; 4 S/ h% C- c$ q$ g. U
HookOff(); ! x2 Z( o- ^4 ]; @- x K
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); 8 `) s' y, W5 l0 c9 b
HookOn();
{* `9 ]" Q- s return(nReturn);
9 Z# K8 ?8 _ u' i* ?* y6 Z5 Z} % `6 m7 P: t m: w" f! l
void HookOn()
/ h: `7 Y" R/ F; d3 ?- r/ d{ , L, n, A+ V. O+ T5 \
HANDLE hProc;
% b4 H; V$ V Z1 y7 ~4 M% R dwIdOld=dwIdNew; 5 S3 ?, ^( _$ i8 r0 D
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 % G! h0 k# T2 Q" Y
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 & z) a- r$ M4 [- t$ E- r# Q# |) g6 T+ @
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA / R5 T4 j" y/ T' u1 V) T% f
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 2 `/ l) E' o) X( q, j
bHook=true;
) c! N/ y- c# k0 }) S( ]}
2 {4 O7 z5 H" z! Ovoid HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA 5 b8 H8 \+ H9 G/ z+ u
{
) U( [* ?- [$ j1 L; A% o3 } HANDLE hProc; ) }: B% }6 | }
dwIdOld=dwIdNew; " l- ~8 S4 d# H R4 ?- u0 D
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); 7 m+ }* Q/ C% [ t \3 Q
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
1 [, q( T. q$ g4 x) o, l WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); ' j3 I( J& Y, ?( w. N2 u7 Q
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); : ]1 x! K# ~# D$ h
bHook=false;
: {/ o* G9 g. Y; u5 h9 \/ g}
! O8 t3 [+ p7 a$ a2 C2 G//测试文件: * d* s5 v" ]( l& r
int APIENTRY WinMain(HINSTANCE hInstance, , L, G7 E0 }6 Q1 l O) w
HINSTANCE hPrevInstance,
1 C+ E' q# L/ S8 z) b3 G6 p LPSTR lpCmdLine,
1 k5 X# b7 U1 F- U+ l: L: m4 p int nCmdShow) % F* z) A6 _3 H2 ~# r# K. A4 F
{ . l7 i$ j; i. S s/ R# N
9 G1 N3 n1 X+ T) E$ `& H- g4 O if(!InstallHook())
" V4 s3 ?8 ~7 v' i3 a, `' I {
. @' g! G# a5 b8 V+ h! X6 d* e MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);
. S0 q3 V- c3 L/ F return 1;
: p6 n8 k+ F7 O, D- h }
9 b2 V+ w" G0 C$ j- O MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 % g! W0 C% c) E+ O7 U* X, P3 p
if(!UninstallHook())
( D- j, O/ i+ o0 @6 \) s1 p {
. }, L% F, ~6 p' D MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); ( d# w7 _( l) S( p; Q
return 1;
1 b9 e$ ]- B" ?; ?" [ } 3 O; _" o4 l1 q
return 0;
9 d/ F7 a; ?4 O* j# P6 f% e}
* u2 X" _9 h) |9 @3 K7 e[此贴子已经被作者于2004-11-5 18:12:27编辑过]
2 F. H {# k- y7 G. X8 j4 h% c |
|