该用户从未签到
|
& D q1 f8 b& }# f! S2 z' q
发表日期:2003-10-30作者:tomh[] 出处:
$ T6 V. V: T* p( e* pApi拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 ; h) G: X* H; r
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, 0 @$ e& o# q" t
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: . O, K) p8 A+ E2 C
BOOL VirtualProtectEx( ) |+ m# Q3 ^' F9 I
HANDLE hProcess, // 要修改内存的进程句柄
8 l4 V+ D6 i+ x s; G, g4 I7 s LPVOID lpAddress, // 要修改内存的起始地址
2 \- N1 ?% f+ I9 j' L1 ] DWORD dwSize, // 修改内存的字节
3 G) @3 E4 ~( l$ a- w; r/ t% N0 y DWORD flNewProtect, // 修改后的内存属性
, v4 ~0 k, E; z, i. U7 d+ l PDWORD lpflOldProtect // 修改前的内存属性的地址
/ j( V Z8 m+ P2 C' {; Q0 @! T) }- V9 J );
+ R" D3 l' N, d# _9 ~ w BOOL WriteProcessMemory( & x8 _2 t1 W8 y! ?2 }
HANDLE hProcess, // 要写进程的句柄
' G" [. d+ H G: M$ _! ? LPVOID lpBaseAddress, // 写内存的起始地址 3 K- v9 X# ]' J1 L m8 ~
LPVOID lpBuffer, // 写入数据的地址
1 `* g) C# ?" b. F4 J/ F DWORD nSize, // 要写的字节数 1 v; e7 f& t- n% j; X
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
+ y, v( q. e& a ]2 b" f& Q );
% u2 C0 f! n, K& |2 x BOOL ReadProcessMemory( " v3 e; T% z; w% Z7 {& C# c
HANDLE hProcess, // 要读进程的句柄
( g; T1 |, H: K. a LPCVOID lpBaseAddress, // 读内存的起始地址
+ m% `0 F: d9 `' j LPVOID lpBuffer, // 读入数据的地址
. S0 S, t/ d! p$ h7 ~, y3 N7 M. b DWORD nSize, // 要读入的字节数 5 s z! r1 Y5 ] B0 V
LPDWORD lpNumberOfBytesRead // 实际读入的子节数 3 ]2 W2 Y2 ]& z7 l% f9 g
);
5 A; |) Y& x& r, n D! k具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, 3 n/ M0 ?" s. @8 ?( ~5 a$ F
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:
: R, s+ Z. h$ \& F其中Dll文件为: H. m) _1 Z2 E& M* U) S2 a t
HHOOK g_hHook; ! S. F, R( i: j6 Q/ O4 a- j8 D) Y+ P
HINSTANCE g_hinstDll; . k( ~. G1 x2 X' v* m
FARPROC pfMessageBoxA; $ Y/ P, ~8 Q/ m3 E; t$ R' b1 S
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); 9 w2 n# F) f6 A' K/ r4 @7 R
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
2 Z& j9 {& K# \' b HMODULE hModule ;
! K3 U8 U) @" ]4 E e DWORD dwIdOld,dwIdNew; 5 v0 M0 }$ q3 U
BOOL bHook=false;
; c3 `3 s% G1 i7 y+ f2 u* F void HookOn(); I6 u, {+ i# v
void HookOff(); ( s! T" m) {+ u% E( `6 v
BOOL init();
/ f( T" |/ G/ x6 t- c1 A( E6 F |) YLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
! t6 P3 N: d* n! F3 v: L) eBOOL APIENTRY DllMain( HANDLE hModule, ' a1 M2 b* l1 ]6 O3 y k# z5 e
DWORD ul_reason_for_call,
" v9 d, B7 n0 l+ ` LPVOID lpReserved
2 D) j2 M l% h D- E" ^. I" G9 r ) % {3 ]9 l( i8 q' c3 \. R
{
$ l. H6 t$ ]- y! C1 l3 H9 z; D switch (ul_reason_for_call) : r& {7 s) W1 j j
{ m& z& w2 N- }( U i8 H' V" v
case DLL_PROCESS_ATTACH: + R/ u( p8 Q% v- p4 i0 c/ A9 c
if(!init()) G# c8 ^7 g2 H- t+ H
{ % e7 M% m3 W" p: |5 k+ D
MessageBoxA(NULL,"Init","ERROR",MB_OK); 9 \8 z' M# B9 ~: r1 H F
return(false);
3 n3 Z; w( Y1 n# m2 V! ]$ K }
6 ?' v8 s: t5 L" @# v case DLL_THREAD_ATTACH: . v: W% ?* P- n9 i) K; b
case DLL_THREAD_DETACH:
1 j6 R! A A9 I9 T case DLL_PROCESS_DETACH:
3 c. q& W. n5 p if(bHook) UnintallHook(); $ `7 _; A$ r. T9 F) J4 J6 z3 `7 _, N
break; ' x5 s0 E8 z" P& a( f5 x/ q
} + V- \9 `5 ?( B0 X) a5 q) ` f
return TRUE; . R! ]+ T) c0 M. L! S; Q5 l
} 1 p6 w2 G" s3 m, @
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 : p8 ]6 m# e1 k4 z" w: q4 e7 b
{
: R- H) ]) j) {; R- k1 {( r
( m+ Z. e U4 M G7 O: x7 q return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); " L; x! Z) ^# F( |3 T
} u }0 V. g, \+ ?/ ^' m3 ?
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
" U3 {$ E* ~3 ?6 o$ ?) w{ & e8 _; |) p/ d6 Q7 d1 ~
g_hinstDll=LoadLibrary("HookApi2.dll");
& r- C7 N$ y# t: G4 J) g# M g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
, p M2 c" Z8 R: N. q* r# Wif (!g_hHook)
5 U b. A$ h7 ~- B# P{ # W& m) ?( X' |7 p; ]/ Z4 S; O0 ^
MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
8 U8 ^4 x5 d- r$ k, J9 g return(false);
$ J1 c# `+ Z, B* p2 A } + P8 o. @0 f" P6 c2 F
/ k8 @1 C$ a# R: i7 W {: }1 Z
( @) i- R/ f$ C; s/ h return(true);
0 Y5 g. d( X1 s' e}
8 d0 ~ `& z8 U: h3 FHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数 I! x9 @6 w5 B. f
{
) {' c P# c, ]. d2 S
4 P' d+ w4 u' S0 Z/ |4 Q j( c return(UnhookWindowsHookEx(g_hHook));
1 {8 p% H; ?" j9 s1 `& \; t% O} + I5 R9 Z" M! |! ~% X
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
; N8 T& E& h2 H# u3 h{
* u: Z+ K9 c+ K4 C" s. W hModule=LoadLibrary("user32.dll");
3 z; d# m \# ~ pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 1 ]: o' M' f) y+ b5 G
if(pfMessageBoxA==NULL)
$ d) E& N% P6 W2 N' Q9 @1 m1 O& w return false; ! {4 d3 u+ R( {* ?' f/ b) v
_asm
/ j" U: O& h1 {$ V {
7 {0 x) B$ v/ S lea edi,OldMessageBoxACode ) L2 y& y9 I7 j
mov esi,pfMessageBoxA
1 @0 g; d4 D; u1 [9 h; H cld
5 M0 _! X% g" D movsd
- \! @8 s# r# ]- p) ^" {) @ movsb + B* g1 f+ _% G
} 5 E' I7 z- l" J4 Q, Z' p; z2 t
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 + M N s5 J k
_asm
4 ]/ t6 L! r4 I& M6 a4 _+ g4 h {
! N7 E, k5 w1 a) C# i# y6 R lea eax,MyMessageBoxA 3 Y& P3 d7 t: k3 i( G
mov ebx,pfMessageBoxA 3 v* x) \2 b& N! M5 J
sub eax,ebx # f$ l. {0 V* S7 Y5 ]% A
sub eax,5 # f3 J$ M% U- e. Z1 a
mov dword ptr [NewMessageBoxACode+1],eax . \' X1 g; L) ~. @4 y
} ; M( t6 Y" H4 S! Y
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID ( V: @/ K: ?7 l: h8 T r) p6 J @* j
dwIdOld=dwIdNew; 1 i4 O' t; d6 y: U7 U
HookOn();//开始拦截
/ Q* \- [) o& ?* j; e/ H return(true);
' m1 y8 W4 {' [7 K$ E* w} , ]: U T' e$ h( u5 d
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 4 z! _$ B* |/ A! X+ z* c
{ 8 A3 M' K. {! y
int nReturn=0; }& ~0 F1 t! s0 y
HookOff();
" F' l3 [2 d& Y1 a6 B+ G nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
9 g0 ], d2 X: d( \) j6 d HookOn();
* A9 z; p( G' C/ D; j( v. _ return(nReturn);
1 J. p8 t9 y$ i- k: x% w; ]} / U8 P' B) M b$ ^! E
void HookOn()
+ q0 q, \$ G- `0 a: d% r{
7 P0 m4 o! j! f! y* H HANDLE hProc;
0 B( Q2 Y' w0 \ dwIdOld=dwIdNew; * u8 B+ J! V0 X. ~) a
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
9 c6 t# w5 ^$ M" N) R, ^4 E VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 5 _- o, s6 S) @" y3 e# d; ?$ x
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA 8 R4 w7 p7 A5 K* U, n) q5 k1 J
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 ' W# j- z$ j u
bHook=true;
0 b) H+ H% k" I: a: q3 f} # S ?; O* ~! I/ i3 ~0 N. V c
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA 6 u- w5 m; g# I' y0 B5 [
{
3 I# m7 |% k* V! v c HANDLE hProc; 6 R/ P. h& S _8 d
dwIdOld=dwIdNew; . w) |* f4 }7 W+ `8 m$ g7 h
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); # b, j- Y. h$ }; Z. {, Q3 X6 f% }
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
. E( i2 [( M. b I1 h WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
" H' ?) K P$ p0 ]6 H1 R VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
/ {* D6 e* Z7 I: V6 {5 i$ k bHook=false;
5 X6 m$ }% A" d8 p% {7 ]# X}
/ k2 T' O1 P- p j/ S//测试文件:
* G7 z2 X# H6 E6 wint APIENTRY WinMain(HINSTANCE hInstance,
& l* E3 k/ ?- B HINSTANCE hPrevInstance, 4 g- k0 `4 A' l8 k0 n1 P
LPSTR lpCmdLine, . L ~6 I" s* y2 S
int nCmdShow) - |. ~6 N- F* Q: B2 u( D! N
{ + G( E6 Y& |( C7 q1 [+ T5 B
# `! V4 \0 W6 {; g3 n. \: J4 ]; s
if(!InstallHook())
# n0 }/ s" b5 k- ~" O1 _# _ {
) o( A! f. a( v, f$ e* f MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); * f6 a2 p4 n5 c% o* |; p3 T
return 1;
& `/ H# ]/ J+ e7 V/ b l8 E }
- d! }; H' J% g6 r9 L1 E" G! ? MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 k+ Y9 C ]3 k3 c0 N8 _
if(!UninstallHook())
& E# I9 j X1 _ {
0 ~ D# V: G- Q. A2 ? MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK);
1 `8 E$ [. P5 p6 o return 1;
: d; q0 R; B7 q- h3 R; O } 2 K3 R/ B' ]$ n. ?: I% q8 w0 q
return 0;
/ D# Z( u, g! [) Y3 d}
# \* l, @) \5 V% O[此贴子已经被作者于2004-11-5 18:12:27编辑过] ( |9 z3 d- z* L' V$ I* J* d
|
|