|
$ T) d" c' s( k发表日期:2003-10-30作者:tomh[] 出处: + J6 [0 O" m% a) @; b) [& h
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
( j0 e N7 u, O! O) ` 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
5 Q0 T( L: V E& [3 E+ q l3 b8 c其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
( g8 W3 b! S" |5 u# n BOOL VirtualProtectEx(
: }9 U/ Q6 l& e9 k7 G7 T HANDLE hProcess, // 要修改内存的进程句柄
, \3 e; H! K m1 s+ p; @( { LPVOID lpAddress, // 要修改内存的起始地址 9 t8 G) n) s. O. F
DWORD dwSize, // 修改内存的字节
* ^- |: p5 V( O" \: ~! j- F8 k" Q DWORD flNewProtect, // 修改后的内存属性 & j j7 I2 N. F9 g8 c9 I4 @
PDWORD lpflOldProtect // 修改前的内存属性的地址 2 {3 X. |7 Q, X. z
); $ I8 e+ K' ^0 D
BOOL WriteProcessMemory(
6 q! u4 M$ x% K2 C HANDLE hProcess, // 要写进程的句柄
2 b; k7 Q( ]( ^, ~ LPVOID lpBaseAddress, // 写内存的起始地址
" o% q6 g! E8 |9 S# ?: g& ` LPVOID lpBuffer, // 写入数据的地址 3 ]) _7 q( g) ]# V0 s
DWORD nSize, // 要写的字节数
$ e/ Q6 t3 L, _9 ^$ }6 Y5 H1 E LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
: }. N4 \( ^1 P2 C& I );
; T- B& u- z& X5 V1 x' A% H5 U BOOL ReadProcessMemory( 9 x7 w+ m+ Y4 v0 s) v
HANDLE hProcess, // 要读进程的句柄
" J/ d9 C% c5 G* i8 T q6 U LPCVOID lpBaseAddress, // 读内存的起始地址
3 J! D C* z& p6 i& x G LPVOID lpBuffer, // 读入数据的地址 : l( [5 K6 | T2 p) u8 j. b
DWORD nSize, // 要读入的字节数
/ R7 Z2 x1 @# n7 t8 B) r- Z! L LPDWORD lpNumberOfBytesRead // 实际读入的子节数
8 B' t" E, q7 ^1 R \ ); ! C# e! K; m6 P% ~" A! Z
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
( V! x, T3 N/ h4 \. v因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:
3 G% I/ T" u2 L- d% U0 a, ]其中Dll文件为:
' N1 u, y! \6 ^0 I0 r/ R1 U HHOOK g_hHook;
/ S% \9 O2 f* ?- C1 X* k3 S HINSTANCE g_hinstDll;
7 J, X+ M0 L- p; \! ^& Z2 C FARPROC pfMessageBoxA; / S+ T4 |7 M# V) q) N' M F. f& d
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); - G% ?: T* X; l, t' q- Y
BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; % m/ l# [( o" C& B; ]
HMODULE hModule ; " I. B/ [0 A8 V Y E
DWORD dwIdOld,dwIdNew;
& c# k& _. f# h* T. L BOOL bHook=false;
% M' [; O2 H7 d! o; v void HookOn(); ) b, z K4 d3 r- G6 ]& k
void HookOff(); ' Q! x _# _4 t5 w# c7 e9 w ^1 K3 i
BOOL init();
: r" b0 Q. l6 oLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam); ( c& G6 Y1 H2 r' Z& e6 W- ~- i
BOOL APIENTRY DllMain( HANDLE hModule,
& l+ R( b8 P: K8 |# n DWORD ul_reason_for_call, + T/ k3 O- L. t+ c. v9 X6 v7 {% P" E
LPVOID lpReserved + k+ d) m- d ^4 j+ P
)
7 n; c/ _% }- D- e+ \) X6 ~; q{ ! f* o! e% E/ ~5 X
switch (ul_reason_for_call)
9 ~' x: e7 O8 f2 [" n v! Z, ^ G {
0 x- [8 q- ]. }$ P case DLL_PROCESS_ATTACH: $ x1 a0 x8 F2 N' |2 r7 G
if(!init())
9 o8 P X6 i3 Y { / r, |. l y+ z7 r# Y) a
MessageBoxA(NULL,"Init","ERROR",MB_OK);
- L [7 D9 C% y* I4 }- v return(false);
2 T1 _. z3 i9 G! F! D# {8 ^8 ? }
/ w8 S. V' L: u; X$ l0 I case DLL_THREAD_ATTACH: % O/ t+ ^' f4 E' q. I, t
case DLL_THREAD_DETACH:
+ k& `5 E/ J* w: I) C! s case DLL_PROCESS_DETACH: 8 f1 n7 ~2 G$ w2 I- z/ ?9 d
if(bHook) UnintallHook();
' @1 w% h4 X- F% r6 H1 d0 P' W5 I break;
! J, R4 z( x p6 D- o } . x" k7 }2 X# r; F8 A
return TRUE;
/ r% {/ D7 Q u6 X [} 1 @: H: K8 D/ A+ z4 v6 d
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 ) O4 c. a( o$ U; _1 @ a. Z
{
% a1 G* \ \+ K' |! k
+ {; J" t9 g+ V7 M( G return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); ! `+ H2 w& m( p- p9 T
}
0 u. J% s R! m+ J" I9 i! tHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
2 n% @4 L! x% A8 E0 h{
+ a& Y k2 v$ d/ E) \ g_hinstDll=LoadLibrary("HookApi2.dll");
: z$ ^+ I; u% R- a8 w g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); % Y/ F9 B( m0 _6 M
if (!g_hHook) ! Z" C6 N& r; L0 \7 V4 j/ m
{
: i* t* \/ U$ F5 E* ^% M3 y/ y MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK); 0 e+ p6 m+ `) P5 N
return(false);
' b9 g* F# w5 d4 z+ d! f- \9 F+ X }
4 q( |/ h# w9 s7 @- r. _
* j' B& N* \" G5 ? # o; w8 _6 x& L
return(true); , |6 G3 ]6 J9 o/ ?* d
}
# o+ A. M* A: U- c; t& e% {; _! w8 BHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
8 m# m1 c9 v3 J3 L; k: ?1 w! |{
# y% _5 n! Q$ N8 Z6 e% {) U
- k# I: @' k n" l5 L: e, _ s) ] return(UnhookWindowsHookEx(g_hHook));
9 _ v8 ]! ^7 t n0 x}
6 }- C0 C1 J. t# l* u8 cBOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令 3 j% [) J, d) Q- S
{ 7 V+ t0 S, j* x
hModule=LoadLibrary("user32.dll"); i8 e. W* I1 S6 x1 f& A% ^
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
% b( d o0 E3 \8 X$ F( k if(pfMessageBoxA==NULL)
+ y H, ]( j; G& S2 o return false; 1 t+ w' ]( z. @/ A' a/ m! p0 a
_asm / c1 ] @) I; |6 z# r6 V7 g
{
7 `- p9 C4 ~- z4 X" X/ @9 c lea edi,OldMessageBoxACode
5 c8 F7 F$ F- ?- q mov esi,pfMessageBoxA
6 f+ \2 ]7 _- { cld ' G4 a3 m1 P2 J7 M- j+ `
movsd 5 [/ D' ] p/ K4 r6 t9 \, _+ J0 A
movsb
9 u% q) \& ~: Y2 v" a }
6 h' a3 g7 n( H7 N' H0 I NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 / L; t( ?4 t9 h1 F) D
_asm ! J( D5 I. _- \7 G1 A4 g
{
2 d+ m7 I% l* D) E L* l lea eax,MyMessageBoxA
" \ H h# Q! U# y3 L; T' N9 | mov ebx,pfMessageBoxA
6 t+ h$ D' v2 x$ G* k# G5 P- K sub eax,ebx / R) O: ]# G8 J3 M3 C2 T4 }
sub eax,5 4 _# O k. y$ A; \; b2 W
mov dword ptr [NewMessageBoxACode+1],eax + Y5 P* t. R6 d# P5 X5 j
}
" O6 \2 \! M' V4 F dwIdNew=GetCurrentProcessId(); //得到所属进程的ID ! ^, }& y* t* M- G
dwIdOld=dwIdNew; ; v. | e9 r8 h
HookOn();//开始拦截 / \9 }! J# o0 T! L: ]& e1 M0 R) D" u
return(true); + l: A3 A6 U8 @, [# v/ O7 F
}
( _- v/ I! c( S0 ?- lint WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
- D, ?3 T) H: a' N5 {{
- ~$ q5 C! m/ x- _* @: Q int nReturn=0;
# o" \7 {, T8 c4 {: r# s: ? HookOff(); 9 S- W3 r! W: V+ T" M1 w6 Z+ U4 R
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
) j/ c1 e \2 g HookOn();
0 o* m/ Y* q" L( T return(nReturn);
4 }+ R5 P% w+ M( K L; T}
- h& R- }6 B( W5 dvoid HookOn()
0 Y$ S; Z0 v2 _. t7 `{ 6 l% i7 d# ^" H# B
HANDLE hProc; 7 p& p4 W+ I1 {# H- d8 V
dwIdOld=dwIdNew;
6 {4 Q0 V; l, Z% @2 _+ h6 s hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 % ?+ E- W) @1 @7 ~3 i% d% h
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 8 _2 C4 p- S/ F" j1 v
WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
4 X0 T$ p1 Y* U# M5 l" ]6 y VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
! S' ^: w8 {# q3 J3 W6 d( ? bHook=true; # w; i' o4 v0 k5 K$ t
}
5 I' t7 I) r \0 P4 Z* Y4 k+ tvoid HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
0 s" w4 q) o- {9 j{ " M3 d5 D: o& ?
HANDLE hProc; 9 r! o3 B( k6 d( e
dwIdOld=dwIdNew;
- ]3 G7 v0 m/ E7 m( V$ {$ v' v hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); " e/ i4 O$ N6 Q0 T9 E9 @
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
) k3 m/ f/ |# R( ^# F9 _! `$ | WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); , z/ x' X0 R2 E* g' o
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); , \( ?, Z z$ o
bHook=false; " a- m s t, e& @1 o V# H. {9 v
}
" I8 K- [- O: b" Z. E//测试文件:
% `& p$ ^9 R( \/ Tint APIENTRY WinMain(HINSTANCE hInstance, ; v3 ~8 P, Y/ r+ P
HINSTANCE hPrevInstance,
/ i! j4 y; ?2 M LPSTR lpCmdLine,
; D+ P' [* p+ J+ A int nCmdShow) & S0 E0 x" J3 y( U
{ . ?& Y- a8 f4 r$ I. k
: j" y$ _: Y0 E+ g9 T! X# _( E+ @
if(!InstallHook())
$ K, A6 a3 M! p, S3 D' S" s6 M8 h { * l, h( P! ~5 p" t: b- Y( h4 H2 A
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); $ n) m/ T u2 B/ f; Q& Z: _+ I
return 1; ' K1 G: ~$ l# f$ ]+ P2 J- q9 `: Q# n
} Y0 K0 c6 u& V6 F: B
MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 . Q e4 o9 |- U' J; s
if(!UninstallHook())
0 T& C2 E4 ?/ G$ s- |1 _9 C! h {
9 b# U5 @4 p) M0 T' Z MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); & i" s6 Z- h0 v0 R" n9 p
return 1; / G: Y/ s0 p& q
} $ U4 C& s7 F4 O+ r7 n% J6 l
return 0;
5 X: k& X, ] w} ) d5 Q9 N9 v3 P, @6 V
[此贴子已经被作者于2004-11-5 18:12:27编辑过]
! L0 z H% p& N) k6 y6 Q |
|