|
& a1 l i+ Z6 Z3 S: a/ L% K4 F5 g发表日期:2003-10-30作者:tomh[] 出处: % o' S& I' h8 a0 M
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 3 p7 H5 k% S: T, d' d; e
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
0 l+ H6 ]' H: Y& a其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
0 k3 L' c4 q# u BOOL VirtualProtectEx(
/ W( t/ {2 d# F7 F) V: v0 f HANDLE hProcess, // 要修改内存的进程句柄
* q" k) \5 z; a LPVOID lpAddress, // 要修改内存的起始地址
/ ~& v# ?; o- K' f; i$ D1 G! r4 k DWORD dwSize, // 修改内存的字节
& A5 s# a2 I: h# D: x DWORD flNewProtect, // 修改后的内存属性
2 M7 Z4 e0 v' J- B' q" a t7 @ PDWORD lpflOldProtect // 修改前的内存属性的地址
0 o! k$ g8 N6 A" m( v ); ! j* R* U! {' t' {0 w: k0 n/ [
BOOL WriteProcessMemory(
$ m& ]/ K Z/ l HANDLE hProcess, // 要写进程的句柄 , ?" Q q- ~5 e
LPVOID lpBaseAddress, // 写内存的起始地址
- N$ H; [! B2 U' r! t+ K LPVOID lpBuffer, // 写入数据的地址 * P# I( a% N2 ]; l9 w
DWORD nSize, // 要写的字节数 / j8 i9 J4 a8 l3 m0 D, \
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 l& s& ~5 o$ g, M
); : M, w% l0 N# W2 W8 E
BOOL ReadProcessMemory( * S' e& d+ m, F
HANDLE hProcess, // 要读进程的句柄
$ q$ T$ ^1 i5 n. j: R7 { LPCVOID lpBaseAddress, // 读内存的起始地址
& H4 w8 r( ]3 j1 s8 ?# _4 E LPVOID lpBuffer, // 读入数据的地址
$ T/ p* T* l b/ n" r) \2 K* Q DWORD nSize, // 要读入的字节数
/ E( D# x1 d2 v3 v) C LPDWORD lpNumberOfBytesRead // 实际读入的子节数 7 Q' Y' G( H) W& f5 v
);
# S/ o b' n. I' [具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
$ j9 l; X. l8 E9 q3 Y因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: 7 M7 a& e4 A* [
其中Dll文件为:
; g5 @% c, {$ x HHOOK g_hHook; {" y0 j: m' ?/ b, ~
HINSTANCE g_hinstDll;
3 ]" h. ~. N/ B8 e' Y0 w' J" D* b FARPROC pfMessageBoxA;
5 _8 e% D; E3 s int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
. @% l4 W: ]& |# F BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; ( b% |- Q3 [1 K; d
HMODULE hModule ;
( u1 ~1 |8 b) f, Z DWORD dwIdOld,dwIdNew; ( R, n0 [- q- T2 t' J! G3 [7 L
BOOL bHook=false;
, T" D+ A' \) K0 _ void HookOn();
4 i8 f+ V; g- C8 ?% D void HookOff(); ( c0 [) K3 j7 H1 f* q( t
BOOL init(); 2 @0 n+ i g# o5 R4 D
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam); ' e# X+ k; j: s7 O B. d8 E0 s
BOOL APIENTRY DllMain( HANDLE hModule,
5 X( T( M# P% u; D7 Y9 S DWORD ul_reason_for_call, ( j5 b& w" T; P7 R$ W# O$ f
LPVOID lpReserved 5 H8 G. A$ s* Q# q
) 1 W% p# g7 P, U6 L- g
{
$ ]% Y) A& u" D switch (ul_reason_for_call)
2 G2 K1 v+ b5 e/ v: h7 W# j { : m# ]0 Z8 b3 y; K6 W
case DLL_PROCESS_ATTACH: 7 R- n! A1 w' c" S& j8 R. n m
if(!init())
6 p9 e( X% j% n {
/ D) p8 I/ y% i4 a! y6 a' ? MessageBoxA(NULL,"Init","ERROR",MB_OK);
$ H9 x! \! ]8 R5 w% Y. b) ~, H% _, F return(false);
% o d- Y, f. s' u6 r }
4 X5 B" _% W* [4 ^( p case DLL_THREAD_ATTACH: & O) I/ k8 E! s% {! T
case DLL_THREAD_DETACH:
7 b9 I! \% X+ f! [) ^3 F# i case DLL_PROCESS_DETACH:
* p1 E( L, l% L if(bHook) UnintallHook(); " K' y: f1 }7 h( g& c1 }
break;
2 M- u0 o2 U( s% k9 b* }+ u } ! j+ U" V* x( S- z+ ]
return TRUE; ( i5 ? w# t% }
}
: w) J$ F( E" vLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
$ W3 z& C+ v t$ t{
9 q) C2 o7 S/ \ " p8 i/ F/ Q. W) `
return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
( u; R0 u# G% M3 Q1 V) t}
' b# i- E1 O- |% F) i+ @0 NHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 w+ I; O: ]$ S8 R( ?* Q0 |
{
* {) d; W+ ^$ U g_hinstDll=LoadLibrary("HookApi2.dll");
, C- }; f" `! W, s: D- B9 n g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); * K C% _' T( t& X: y
if (!g_hHook) & _0 `/ K6 ~9 T: q2 d6 I A
{
! z) S! }5 Y& J4 |4 l' d3 w: W MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
" p6 k7 s* R) k; R: ^3 p$ n return(false);
' ^5 x% M' K. A# C, h4 M$ r }
7 K& a' c+ n. W5 R7 C& g9 z ^( X6 @! n L+ B; a5 S1 G5 \! U0 U
$ P1 W0 H% q9 w+ t9 ~4 w9 W
return(true);
1 ~' Q9 F2 i+ D0 l}
0 c3 \! J1 w* MHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
: k* o& f. ^4 I- n7 a0 _# Q2 J$ K{ ( {6 o$ F2 e" E. ], f
5 _, T& ]- p6 ]. C" S2 R& g1 y
return(UnhookWindowsHookEx(g_hHook)); ! j) o& h' z' x Y& }* C/ l% L
}
6 Q# P9 h: r# l2 y" pBOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
, C! v, W7 W$ O5 f{
' }% b8 g0 ]3 t hModule=LoadLibrary("user32.dll");
7 u! [: x' H, i& c/ z pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
! E, K6 e" r9 r, o% R if(pfMessageBoxA==NULL) * }% d; J( k+ |" M2 ~( Q$ l
return false;
7 \& _) U/ Y) r) L/ a _asm & A) {- B) J3 g; r9 l
{ 4 r) E& B9 c2 R
lea edi,OldMessageBoxACode
% X! c- {& S7 n, g mov esi,pfMessageBoxA : R5 I6 @5 c9 a- l" t f
cld 4 f' {& C, M, h/ U r
movsd
. h# p( Y7 [" G* ?9 D. N v movsb
* b( h" w; X* G V1 O }
7 W3 y' b- h. P0 K NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 # a2 B5 P5 C+ h3 V8 O$ e
_asm ) W) u( i/ w8 I
{
! t" z' ]% y/ z lea eax,MyMessageBoxA
( `( X7 ?9 s8 l1 g mov ebx,pfMessageBoxA $ I; M: e0 `! [2 r0 m! L
sub eax,ebx & f" v0 B& a$ }, z& h
sub eax,5
0 l0 a. |& F, S' ?4 y) K5 t( K+ O mov dword ptr [NewMessageBoxACode+1],eax 1 Y% d# `0 ?# h% ^ q
} , e" q+ ^- o8 \6 K
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID 4 q+ w4 w* E+ E
dwIdOld=dwIdNew;
! u" d3 h; V; }! E2 R HookOn();//开始拦截 8 W2 h: C4 R% \2 ` A
return(true); ) Y; N9 y$ |# C8 G. b) Q
}
5 j' E, z) C. a) g% n( Kint WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
- F9 J b8 Y) S1 \1 ?{
8 u, ?. F: W# a8 C; f1 p int nReturn=0; 6 j; e8 _2 g W6 O( g3 N- y
HookOff(); # m& p$ X) H5 }& b' _
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
/ o# }) \5 g, R9 h! I/ H6 X HookOn(); * v9 w. P. R4 `2 Y$ h9 j% J( I- i# ~
return(nReturn); " {" e1 P+ g9 o X7 e
} 2 v+ ]5 a% @& @2 ~# r
void HookOn()
( c8 Y7 O/ b3 X: A4 t0 O! Q6 O e{
1 R4 o/ ~# z& W2 e& J* J6 ~ HANDLE hProc;
0 l4 |5 Y0 b5 A& _* b dwIdOld=dwIdNew; 0 J7 u# a. j% C8 |. I% k: B7 n
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 8 K- M8 h) G ~" g% ^1 F2 Z% _
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
6 C' T; G1 h: O3 B1 P WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
' J& k0 k+ X& D7 T VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
' C$ w; E+ e$ J" B3 P' @" l) L9 T' | bHook=true; ( h; G! G& ^1 T2 W8 [" d2 }
} ( O" q0 ?6 i8 O0 U _) M$ m
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA ; M. @) D$ ~( L: |# y
{
$ J& K- K9 \" t- G$ d$ w! h HANDLE hProc; ( z r0 K, T a* J
dwIdOld=dwIdNew;
5 j2 C: h; i' Q7 R$ V: ?" U5 M& z8 y hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); 0 O# y) q# s" N5 H5 c6 v
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); & n' x- S6 _, i/ i
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); $ x2 x: f( ?) H2 Q
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
5 K% C* W) ?( r- O# m4 @9 {1 y: Q bHook=false;
" b6 z& i/ L2 j}
; p# E2 c' M; _* c9 Q//测试文件:
4 g: j5 C- Y; _8 ~, mint APIENTRY WinMain(HINSTANCE hInstance, 2 c) @2 R% v# ]$ t
HINSTANCE hPrevInstance,
0 \2 ?' r% k/ H* [) p. J! Z& @ x LPSTR lpCmdLine, , ` L3 `' W3 U3 w
int nCmdShow) 8 d3 ]7 D$ M. l$ {3 Z
{ 0 g0 n% r9 |( K* Z9 E
# F6 Z M% F; T+ P- a9 E if(!InstallHook())
/ r/ G5 P9 E$ _2 K* r { ( q, Z2 U# J9 M* M; y( Z# V
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); / B* C7 [, r! D2 K
return 1; * P3 F3 [7 n. l8 z& l" E
} * T4 Q1 g7 a% V7 h; {) T4 ?
MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见
# ]( m9 }; c" u/ p$ k& T1 u4 T) G: w if(!UninstallHook()) G$ e3 E" k( r3 y
{
* W) j7 a7 m9 R. x MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); ) i, B8 I3 j5 V+ E2 x/ }% N5 _+ J6 @
return 1; # M: D4 U7 D+ V1 H, I3 G
} 1 D0 i4 x' }5 O
return 0;
2 w$ u2 F$ Y; z7 h' S} 2 E; O: u: R$ y) v& t- f
[此贴子已经被作者于2004-11-5 18:12:27编辑过] ; l' I) v. r5 J; j4 }9 e6 T
|
|