该用户从未签到
|
# A# e2 |: K( a+ n发表日期:2003-10-30作者:tomh[] 出处: ' Y$ t% s9 O3 j( F1 B" w: K0 X
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
3 S" j4 {, o) Q O0 q3 B 本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
9 ^ j+ V0 b; M其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
3 h9 T& M6 U* u7 Z( j; l- R BOOL VirtualProtectEx( ) b# o# _- E5 w* W6 P
HANDLE hProcess, // 要修改内存的进程句柄 . M9 N1 P: c5 J3 I
LPVOID lpAddress, // 要修改内存的起始地址 ; t0 `: L' t# b. c3 Q7 J
DWORD dwSize, // 修改内存的字节
$ q$ L( i% V: {+ o4 `% r% B DWORD flNewProtect, // 修改后的内存属性 5 _7 R% U" Y) N h ]
PDWORD lpflOldProtect // 修改前的内存属性的地址
+ _) ?6 E0 c& j9 ~0 l ); , Z9 l; c; ^( N2 H' A4 ?/ r% ~
BOOL WriteProcessMemory( 4 X, X0 ]. t5 I6 S3 X
HANDLE hProcess, // 要写进程的句柄 - N: K3 t0 U* ~) w' G- M+ O* `7 D2 i
LPVOID lpBaseAddress, // 写内存的起始地址 2 o L- z0 ?. o, I
LPVOID lpBuffer, // 写入数据的地址
3 k8 d; N, O2 [- _ DWORD nSize, // 要写的字节数 , F0 r1 T2 [- r7 l8 S e# S
LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 & } k: k8 U$ n- v7 k- C/ }/ j0 x
);
# f; |8 H2 n% Y5 ~ BOOL ReadProcessMemory(
A3 [. b' q' A- _: v X HANDLE hProcess, // 要读进程的句柄 * n ^: @1 w* E( X( ?5 `( P
LPCVOID lpBaseAddress, // 读内存的起始地址
9 F/ v* {' V) J \3 T' } LPVOID lpBuffer, // 读入数据的地址
$ }1 S* T" f7 }% b DWORD nSize, // 要读入的字节数
5 x; t. O! o3 c' h t4 i: ^, Y$ m LPDWORD lpNumberOfBytesRead // 实际读入的子节数 K9 ^1 G4 m& L" I
); 3 l, b4 H& A* F; M- h
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, , a- A! J& L. D H
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: ( a" g% T W! ]
其中Dll文件为: * }# W+ U. ?% {/ v1 s3 M
HHOOK g_hHook; - V8 r! r* B! {4 L0 {
HINSTANCE g_hinstDll;
7 d; [$ o, X% d/ z FARPROC pfMessageBoxA; ) m6 n0 ~( L G) {
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
3 l" o, [+ _* q5 L BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
3 E0 T" v: e- o! v \2 R8 a HMODULE hModule ; 1 c* {7 s, J0 M, H
DWORD dwIdOld,dwIdNew; 4 e3 S# C$ v3 z) ~: x. a0 D
BOOL bHook=false;
+ t5 ]9 v- H8 G void HookOn(); " X, G9 l$ d' G- N6 V9 S
void HookOff();
( i. J2 g6 t4 |4 Y, S BOOL init();
# s& b, ]5 N( K" L/ iLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
. {$ F8 ]5 ?% BBOOL APIENTRY DllMain( HANDLE hModule,
5 P9 P _7 [2 G+ i @" o5 ?6 @ DWORD ul_reason_for_call, . a( E/ h$ p% S' ^$ @
LPVOID lpReserved . S& ]8 J- X! M7 S: B0 f
)
9 A$ @$ m, u) h) R- a/ m{ # K8 \) a+ S; Y
switch (ul_reason_for_call) & d* l; Y e" {5 ? X0 s: K/ k) c) ?
{ 4 H4 a9 K' j" H* Z
case DLL_PROCESS_ATTACH: - _" M6 _" j+ Y4 w! N' k9 h: `6 I* e
if(!init()) ; ]% M) w; \: y2 R, w) q3 `3 j2 i
{
0 v. J ], F+ j! b/ o9 C2 ^ MessageBoxA(NULL,"Init","ERROR",MB_OK);
/ l9 o! Y9 b O- b1 X7 [& d' k+ y return(false); ; W- _* H9 t' g. n {" a
} 3 a$ u+ n2 I/ Z* \% B1 x6 j1 {
case DLL_THREAD_ATTACH:
" c5 S5 T9 ?" i( n3 A case DLL_THREAD_DETACH: $ q0 x4 {9 \# \" y
case DLL_PROCESS_DETACH: 8 W- X. W1 a6 z- w" H# {9 V
if(bHook) UnintallHook();
0 C T8 Y) F8 U2 R break;
0 Q! W- r4 V- x1 O' Z6 b1 [) y }
0 ^- X% Z k# \; a5 G5 o* | return TRUE; % g$ _/ z, U8 z: W- `0 s% i1 N0 g
} 0 `2 m+ l! s2 n
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 ' r, c# w( r. w* N( s1 M
{
& d- q/ T0 Y$ u
7 l( ]2 A* P3 ~5 ?% u) o3 P return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); ) h/ C7 j1 n& d# Z# _
} , y' C1 ~4 W3 O O! ~% l- s# o
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
+ q/ b3 A! }; ~6 P) E9 o{
; v3 P, \; K! p9 |2 ?" h3 q g_hinstDll=LoadLibrary("HookApi2.dll"); , |% S" h/ c" v* E! ]3 n Q% e
g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); & W2 j. L" e' y+ e5 _" x- u+ E
if (!g_hHook) % a" U8 g' y: ] q; v9 G; G
{
: w: X# Q4 F# J7 o MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
( [/ F/ X1 L: V2 m return(false); : M% p* j2 ?) K% R( E8 ]+ _
} 3 {* W! z( e0 \5 x1 U& k* @+ n( I* k
. l7 S% y+ j4 N: }
4 }/ m: S6 i' `: x$ q) j
return(true); 9 W$ ?* }/ S0 |5 H$ p. x+ |2 Z
} # o) O' O. J7 r/ O
HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数 , _% X8 p7 _! r- q& S' n& \
{
* {1 r3 j: I5 x( z' m- S! C/ ?
) u0 y) m) I. G return(UnhookWindowsHookEx(g_hHook)); ) l# f- D1 Q9 D% @5 o2 U0 _5 n- Y' g
} 4 k' I: q0 c+ m! Y
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令 % ^1 Y2 f- ^) p; H m3 J3 y
{ * b" W) t, r4 T
hModule=LoadLibrary("user32.dll"); " ?4 w. S! G$ C2 E$ O
pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
$ Q0 D4 U/ D0 N& @# y, Y( L if(pfMessageBoxA==NULL) 7 i7 N) F/ y* G1 E
return false; " e2 Y: n: P& L8 M
_asm
- C `; j$ S: F { / E* V( B5 @. d8 b
lea edi,OldMessageBoxACode u9 W* s, L! W0 C
mov esi,pfMessageBoxA
- z: o' s1 ?) K' b cld / a2 \8 s. \$ y) n4 F c
movsd : u2 o) [# M$ i5 l
movsb
7 U+ U6 P0 Z, X8 C } * T, Q) |8 ~5 d- _! i0 ~
NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 , l3 o$ b% V N+ G; A2 @
_asm ( v* C4 C; Z: C
{ ) q! n! p# d& J0 p1 P! o
lea eax,MyMessageBoxA 2 E. F6 v5 d7 d+ d+ g
mov ebx,pfMessageBoxA
8 Y( j7 h5 u/ U7 C4 d* e sub eax,ebx " G4 }" L# S N7 i, z! ~% B! H
sub eax,5
) P' F# s2 a) m7 w mov dword ptr [NewMessageBoxACode+1],eax
5 z1 u. t' O7 B1 ~ }
) I& b' @6 d- {. p, T dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
4 K0 g" H, l& r' r# r. {$ U0 u dwIdOld=dwIdNew; 1 U: t; r: S! S1 y' g7 K' T7 O) e
HookOn();//开始拦截
6 K8 [1 }- k4 ~4 J return(true); . Z: f7 x o% }* Q% p4 \, p
} 8 S3 l9 ?6 I3 r, {8 o
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
5 H4 l# H1 f8 q: n) Q V2 D. e( a{
% Z4 A0 F: U9 u int nReturn=0; : G: }( L8 s2 ^1 n2 ^" o2 i
HookOff(); * h+ B5 J7 r* t# g1 [/ q& ^+ n
nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
1 T9 E+ X4 i- j) r* n" \ HookOn(); 7 C- @3 E+ ~4 s) ?( J" F
return(nReturn); " w0 u m8 C9 l) j
}
4 ?; k# p) C/ }. [5 }void HookOn()
$ Z/ p5 g! a1 @( w' r{ & a; p, y" K- b1 r: \9 r7 R
HANDLE hProc; 7 Z0 a( Q( d$ z2 p
dwIdOld=dwIdNew; : ]! ?( e/ E1 X( s5 P! R
hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 5 L7 N j) S2 y; j o& m5 q
VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
: N4 Q4 n+ J, F6 w6 Z/ Y WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA / Z# H1 B9 D0 u. A. e( i
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 % j9 ^( j$ j+ d2 H
bHook=true; + W4 T( F( E, ^$ S
} * v1 M' _/ y3 P
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA ' [0 S4 P4 j" F# z' ]% s
{
0 b3 M1 B, {+ w, z2 ~$ i9 r HANDLE hProc;
' p8 V6 e. N) @* Y" Y3 a3 h4 f! W dwIdOld=dwIdNew;
+ ^6 T! z% M% Q0 u- S! F; H hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
7 Q) P; M0 x) r+ J( O% ~0 U VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); ! I# R: y3 p$ o/ a" b$ b" H; J6 s
WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); ; G8 p, N1 q( g7 @3 ~
VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); ! l% D% A/ m5 i. B
bHook=false;
, i; v: N, h+ X3 C}
6 ~2 j" O7 I7 F; r* Q, n//测试文件: ; ^" v$ I5 A* o# N) v
int APIENTRY WinMain(HINSTANCE hInstance,
- \ H' A' E' G) S. t( `+ q6 N+ _" ? HINSTANCE hPrevInstance, # k6 k9 J) r- V6 @2 y
LPSTR lpCmdLine,
% m/ m# D( ]8 V int nCmdShow) $ o& q+ S% Y- D
{
6 i+ G/ `( d1 C7 H: b3 Y$ [% X
/ a6 j( W# D2 {: o5 ^2 B if(!InstallHook())
6 ~7 ~9 S& b$ q' @; V { ' c O. Y* _ p6 R0 Y/ X4 J- x
MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);
8 T, `! F5 [- R1 U% t$ x return 1;
$ I- x$ Z* k5 o0 a; Q: b \9 K: u }
# P4 b; B/ m2 k% f+ |9 C MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见
" v; ^6 w8 Q# I6 E0 d9 U6 t if(!UninstallHook())
$ v- Q9 P# x# ]2 Q' ? { # j* ?, H5 ?" j9 N3 R
MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); ' o' q5 n- i: ?
return 1; & Q" [* f5 @9 w( R5 y0 g
} ! C C' g" W! h0 ~
return 0;
! `8 ^; F/ J( d( a! T3 L! o} + d( c- w, A: C/ E: _3 o# @
[此贴子已经被作者于2004-11-5 18:12:27编辑过]
. |$ p& i$ o. Y) |% B7 m |
|