该用户从未签到
|
3 @: K2 d+ D- U; \- c9 _% {发表日期:2003-10-30作者:tomh[] 出处:
; W: w+ @8 o5 [Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 ! v0 ^/ k* q7 L7 j6 w/ Q
本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, ; P* S F8 m/ k1 V
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: " Z- ~" l! b$ j2 y3 o+ q# P) @& ^
BOOL VirtualProtectEx( 9 ^+ [- p% |. n
HANDLE hProcess, // 要修改内存的进程句柄 1 w, F* J" p5 B3 Z5 a+ _" C' @' ~3 {
LPVOID lpAddress, // 要修改内存的起始地址 + n0 ? x: V0 G9 f! [- \+ G
DWORD dwSize, // 修改内存的字节 # ^ ~6 c6 t$ J
DWORD flNewProtect, // 修改后的内存属性
. }# g/ T3 P& n0 c/ w PDWORD lpflOldProtect // 修改前的内存属性的地址
" {7 f" O5 g0 a) E2 \( g. g );
8 w' J( E8 {9 Y7 F BOOL WriteProcessMemory( 7 m% [3 O' j6 X+ K
HANDLE hProcess, // 要写进程的句柄
; |- G# `2 Q( E/ n. x( R/ Z LPVOID lpBaseAddress, // 写内存的起始地址
$ O6 {3 U+ N7 r, w$ } LPVOID lpBuffer, // 写入数据的地址
/ ^, { ~3 i: n b DWORD nSize, // 要写的字节数 ! y) R0 Y6 i( I2 M6 W4 e( c& h
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
5 e) `; D1 t3 P# y0 G ); 5 }2 \2 ^' K1 E8 L
BOOL ReadProcessMemory(
, Y2 }8 d; s+ X, `- R HANDLE hProcess, // 要读进程的句柄
) ], H1 v+ }# M LPCVOID lpBaseAddress, // 读内存的起始地址 ) L1 ~, M, |# J9 A8 D, J
LPVOID lpBuffer, // 读入数据的地址
& r W3 ~' W7 a8 V! { L DWORD nSize, // 要读入的字节数
. k F7 Q+ G& a" U LPDWORD lpNumberOfBytesRead // 实际读入的子节数 2 F2 i+ D$ K% m q8 L; Z* J8 Z
); ! e& U% X. h$ N
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, ) K" Z: o/ l; h
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: # u, R, P: D5 ]4 S3 J
其中Dll文件为: ' f, }5 V f% p) v
HHOOK g_hHook; + A, R; m$ N" F8 t# a
HINSTANCE g_hinstDll;
8 {4 p- F% F4 H( t" _2 e1 F FARPROC pfMessageBoxA;
9 k5 G# t; `8 O5 g/ q4 C" Y int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
* [) ^" M6 }7 E4 a A BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; 7 u) Q5 }# Y- I& m' D' v
HMODULE hModule ; 4 ?7 ?5 B7 s3 T2 e$ A6 G# N9 n* ^8 _
DWORD dwIdOld,dwIdNew;
5 [4 c' R( U3 `3 [1 t( ] BOOL bHook=false;
) x+ _! n% l! x void HookOn(); . c& l; `; u; z* b5 y' i2 b
void HookOff(); 1 L5 n9 i# a! B9 ^2 D& R: m- H
BOOL init();
3 q, B" U) g6 HLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
. V# v9 `1 \* ]3 X) d7 DBOOL APIENTRY DllMain( HANDLE hModule,
- k% `- D7 q, R1 Y( ^ DWORD ul_reason_for_call,
6 H4 U, ~( V/ T( V- @4 S! z LPVOID lpReserved | U3 X' j2 N3 }$ Q8 J6 @
) 3 r4 s5 g6 L$ C" @; N6 H1 S# u5 l
{
& i0 u9 l3 N" }; j) f: U switch (ul_reason_for_call) . ~- j: k! h& o) t: u; V
{ ( S: }" R) N% z2 |+ c
case DLL_PROCESS_ATTACH:
/ |7 g6 }% @! c; _' Q0 U* { if(!init()) 9 i- _% i1 G0 Q0 N+ s' L
{
( L" V) p7 B$ ~: Y MessageBoxA(NULL,"Init","ERROR",MB_OK);
( q# p6 i! `# B( g* S" @6 T return(false);
0 F% G) }6 O6 r G; w4 H$ V }
% N* S" P( ~% h; J* i7 C E case DLL_THREAD_ATTACH: + G3 w f/ `: G0 S
case DLL_THREAD_DETACH:
( z4 K( ?! @' n6 ~% l0 ]& ~9 U5 Z: | case DLL_PROCESS_DETACH:
$ R/ n, `+ \9 x+ y if(bHook) UnintallHook(); ' N" s9 N$ Q4 r0 U! a
break; $ P- B- a, n( n% h8 X; O Q9 o4 X# N
}
* f- f4 g3 [3 w1 ^: a+ j return TRUE;
% N- K' ]4 h3 Q8 ]} 2 |. u' `5 g% j4 X0 x3 _+ J" _
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
7 K6 V6 X. y, P q{ - L+ F3 `& j9 e: v* K9 i
# w( t# S- f8 |3 R( Z9 { return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
2 r' ]' [9 B! ~- q}
3 O! }+ Q5 K' l9 W& OHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 ! A; q' t- ]* s9 m% ]' {
{
0 U, z+ [2 \" a! Z4 D g_hinstDll=LoadLibrary("HookApi2.dll"); 3 r9 S) `( u! {( p7 y! ~
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
" v+ v; j( y/ l5 F9 n2 jif (!g_hHook) % `7 n& z( R9 _ r1 S+ v4 I' u8 ^/ X0 r
{
) @9 K, p6 X! m" w' l% y MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK); ) {' J6 q/ u8 n: ~7 x+ h+ `% {
return(false);
3 f! a0 Q; ? `: m" ?$ b } 8 t: @" |! L( y; a+ H
) `" I# F& g+ W" M ]
# i0 U" R0 q6 m/ v8 x5 V1 u return(true);
6 Y3 `/ ]6 z3 o3 J; H, D$ `' G} & X" U4 U5 l- r7 M4 ]
HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数 + Y4 P. x0 L1 x; _7 Y" Q) d
{
, |& H$ J, G" Y0 ]/ p: I + H% Y0 i7 v+ \5 |6 V1 R
return(UnhookWindowsHookEx(g_hHook));
9 W2 i* J; v1 }% G5 o6 F7 T# @} 4 C+ ?; u0 m& j. P1 S
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
' P$ J" ^* X6 v3 A8 m# T9 L{ + B# d# e) W/ Y% n* Y
hModule=LoadLibrary("user32.dll"); : X, `2 U' H3 z: ]$ o \% o6 P
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
5 b/ N$ P4 J) `& s0 d* _& X if(pfMessageBoxA==NULL)
8 Q; o% v, p+ K& D/ T' j. P4 H4 i return false;
h) M6 l' |/ u' p$ h. Z _asm
& h* ~2 }! u, G6 @9 Q {
' U% v/ {7 o+ s* |5 q# b. d' H% R+ p lea edi,OldMessageBoxACode
. }6 d& p2 U9 `: ^ mov esi,pfMessageBoxA
0 a* U8 n, U I, z cld 0 Y1 \4 \$ H, \# X
movsd $ Q/ s! V' b8 M
movsb
8 p: m" ~ K( j- ~# q! T7 u; Q& S }
* Y# H, Q7 \1 _4 m* ~1 e4 h# {, S0 A NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 + d8 n$ C5 J4 U+ M- S$ H
_asm
1 c5 u, e. j G* N3 u8 y {
7 Z% `. @& F9 L. X& m- S; \ lea eax,MyMessageBoxA 8 B0 l$ i- `4 `5 W- j `2 g6 h
mov ebx,pfMessageBoxA " V; h9 l/ {1 o: a. R
sub eax,ebx 1 Q" _9 v5 | ^3 n& W8 m# c! e
sub eax,5
1 C) G: C1 A' k0 @) h: J* O! O mov dword ptr [NewMessageBoxACode+1],eax 5 ?: U2 y4 a* t0 a
} ) U1 G% i! g$ u" Q w: u* o
dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
; i& \8 }; f0 z% \ dwIdOld=dwIdNew; - r3 Q0 ~5 U/ N0 Y% j
HookOn();//开始拦截 $ ^3 T: m3 H5 R6 U( a% u
return(true);
& u/ D' Y3 p! S3 ~; S% ~} ' B( I, x9 H% F& Q# \3 }$ }
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
: S4 ]7 ^$ d" z' j; ]{ 4 Q0 R, ?% \4 I
int nReturn=0; . ` q; v' |+ u* |" \% L& z3 Z
HookOff(); - F" j- B- T% E6 h
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
9 s D# x2 E" H$ W6 k% ?# e% ? HookOn(); 6 f6 P3 ]; A( H; I5 f
return(nReturn); + r }% ?$ @% ?- M
}
+ M0 P0 @' q2 |0 M' E+ \, Vvoid HookOn()
a, Y+ |' K [! B! n{ / _& |' k1 J( y" J
HANDLE hProc;
' m9 e( S% Y! F dwIdOld=dwIdNew; 0 X8 d' l8 y4 ?+ G
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
; B- H6 E" L4 z9 U! v) U* ]% c VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
. u5 J/ c! d; n. ~3 N WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA 5 S4 E* Z s& m( c1 y+ s* o
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
/ h# W9 Q Y: Z bHook=true;
: Y" j* W4 v: e- V2 C}
r6 B0 [+ @8 H) w$ nvoid HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA ( a# m% b, H, ]3 G4 R
{ L# N" F4 E3 B8 @# S
HANDLE hProc;
6 Q @4 m/ c) c dwIdOld=dwIdNew;
: k5 a0 V" c; a) S: v8 Q* q hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); : o, Q1 ?( v& [" e9 ]
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
9 [7 F7 j- U D WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
% f- M" { m* b5 ~ VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); 4 u5 w& }; ^; @- K
bHook=false;
# t5 x6 }3 H1 d& o}
" S$ {7 i" @5 A! {( F//测试文件: , y3 W7 O% p4 n/ }6 b' L
int APIENTRY WinMain(HINSTANCE hInstance, & c/ a# ^. a- Y7 w+ I
HINSTANCE hPrevInstance, , b/ H2 u( Z7 T7 [
LPSTR lpCmdLine, $ h- a, @1 Y) R; ^+ Y
int nCmdShow)
j1 r B! @3 N3 d4 ?{
8 B3 I4 r, y2 D$ z# A t* M$ |1 O
9 Y1 I7 |, V. p' n* Z8 o7 g if(!InstallHook()) m- T, D3 J' v* p" [
{
! p# [5 H; V. P# Z8 q( z MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);
, Z7 U% O5 f& A7 |; T* L return 1;
2 _ c/ X# M- I: I& Y: \, u }
3 A: f; G/ f, k) W8 T: M9 q0 _ MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见
. _3 y7 F* }, B4 y& d if(!UninstallHook()) 6 d$ Q& O$ b% u! }
{
6 u5 W& e6 y1 F! c4 a MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); : \2 z+ q/ U: b3 J
return 1; 2 E! Y( h* B. q4 C# P( L- ]
}
. y: E; M6 ? Z# F# s# m5 l return 0; 3 I( x6 T; ?/ L' H6 y
}
% g+ l. {7 _% X( @" A+ ][此贴子已经被作者于2004-11-5 18:12:27编辑过]
4 M/ y/ h# G' y/ o C O |
|