下沙论坛

 找回密码
 注册论坛(EC通行证)

QQ登录

QQ登录

下沙大学生网QQ群8(千人群)
群号:6490324 ,验证:下沙大学生网。
用手机发布本地信息严禁群发,各种宣传贴请发表在下沙信息版块有问必答,欢迎提问 提升会员等级,助你宣传
新会员必读 大学生的论坛下沙新生必读下沙币获得方法及使用
查看: 4089|回复: 2
打印 上一主题 下一主题

[资料库]Win2K下的Api函数的拦截

[复制链接]

该用户从未签到

跳转到指定楼层
1
发表于 2004-11-5 18:09:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

9 `2 D! [; H4 c: W- @发表日期:2003-10-30作者:tomh[] 出处: # Q, W, t5 R6 d( Y1 @# h0 N
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
' j$ ^8 {9 u% I! k2 i+ k  本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
, k" c( d, o& j3 B' H其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
& F0 F. C# T0 T1 H. o" ~. B     BOOL VirtualProtectEx(
: w8 g. Q, _0 Z- i* p/ L                HANDLE hProcess,   // 要修改内存的进程句柄 " X- P4 s2 K) V6 k$ x: d
                LPVOID lpAddress,  // 要修改内存的起始地址
- E1 v3 |2 N5 k) Z' n: R                DWORD dwSize,    // 修改内存的字节
( ]  b7 l/ [, a" ], T0 ^9 H                DWORD flNewProtect, // 修改后的内存属性
( T' l2 f& {; b& P; n                PDWORD lpflOldProtect // 修改前的内存属性的地址   I4 ]+ ]0 {' s4 W
                );
' b4 D: c( e4 i3 P    BOOL WriteProcessMemory( ) Q. ]" n& Y$ V3 L2 \) z; n
                HANDLE hProcess, // 要写进程的句柄
5 o: \+ x- x9 w; C7 Z3 X                LPVOID lpBaseAddress, // 写内存的起始地址
( Y7 i# c4 p3 g( M* X  Q+ b                LPVOID lpBuffer, // 写入数据的地址 * o$ E- k3 n& d- @+ J7 w
                DWORD nSize,   // 要写的字节数   t1 y: l! y( D  p9 [- a2 E" X- B
                LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 6 C% [& r/ e: K8 b: ^
                );
8 ?  o, m1 E' n3 k& M; q5 X    BOOL ReadProcessMemory(
% P9 S& `  G/ v5 _9 h( g& u                HANDLE hProcess, // 要读进程的句柄 : g9 o2 z; q" y' Y# J! E5 e; l
                LPCVOID lpBaseAddress,  // 读内存的起始地址 - O: |3 D' C, i
                LPVOID lpBuffer, // 读入数据的地址
: }  _" n' D6 a. A1 f% ], o5 t                DWORD nSize,   // 要读入的字节数
+ m0 f+ G! @( Q( U                LPDWORD lpNumberOfBytesRead  // 实际读入的子节数 8 j( O/ z: |1 e0 j* B% J0 L0 v7 K
                ); 3 W+ h: V% _: s, c
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, 8 P9 v) ^! F/ k9 D% E6 Z( Q: Q
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: % [5 C% m) z7 D8 Y* Z
其中Dll文件为:
; ^% L% C1 S+ [' E6 ^0 Z     HHOOK g_hHook; * k' d) ^/ x7 G& t1 m; k
     HINSTANCE g_hinstDll;
' u) t8 e# B* Q     FARPROC pfMessageBoxA; ! L8 D' O  w2 W1 T
     int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
* e2 [& m4 ]; z! C1 i     BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; $ }, z- H. l. r8 _) K
     HMODULE hModule ;
- r7 D2 [6 j& i2 I# q% V     DWORD dwIdOld,dwIdNew;
6 S/ U, ~6 ]* J% I6 J$ |     BOOL bHook=false; ) F4 s) X: l7 T7 d% L; A0 ^
     void HookOn(); 3 C7 N4 s; f/ [6 i6 y
     void HookOff(); 8 D3 c& B6 H/ _# t$ O
     BOOL init();
3 ?" Q; b( C$ a" KLRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
) B' q0 X) z, o) P+ Y8 O  }BOOL APIENTRY DllMain( HANDLE hModule, # X* _5 [2 m$ E, P# j0 p# i9 Y' D
            DWORD ul_reason_for_call, ( D  |% E+ g' t+ U3 T6 d; v
            LPVOID lpReserved
1 t# ]9 y5 l/ }, V$ \: T3 G           )
# H, Y# Q, c) S7 T( l) Q{ 3 c6 K0 s! ]3 L
  switch (ul_reason_for_call) ) W" |9 P2 f) V! s
  {
/ s9 d: O1 ~4 u. U" |( p% M" C    case DLL_PROCESS_ATTACH:
% y# \3 ~' s4 y1 O! D* p      if(!init()) 1 E9 c2 X" Q, u) h
      { # g' u% R. K* V; J1 k& ]
             MessageBoxA(NULL,"Init","ERROR",MB_OK);
, F3 N1 ^/ }; N0 {2 K9 g3 p             return(false);
" y- z2 \7 N1 G      } 2 m) N2 y6 k9 C, p" v/ o3 D
    case DLL_THREAD_ATTACH: : ?" ~5 b9 o: a, q# Q
    case DLL_THREAD_DETACH: ' u, F, U: q  X4 c- f
    case DLL_PROCESS_DETACH: : r0 H! _" p7 q+ q- |* V
           if(bHook) UnintallHook();  5 v* Y+ U! c( g* B+ W' F! u
          break;
4 |: n; r8 r4 b0 F  } " i5 B2 l8 j1 e0 f
  return TRUE; 3 L$ C# H0 E" E
}
# a$ ~+ J! u! k# @( |( h; bLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 ) e! K0 j5 |5 B# f
{ . ~& {7 x( }" y' b' j1 ]  Q* e+ D
   - ?3 V) s7 X* [: l
  return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); . d) d+ r6 V* n$ f
}
* |" b* _8 I2 u/ K. A6 `- DHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 9 u& K, s% b4 z% N; v9 ~
{  1 ?& ^* \$ [. [" j
  g_hinstDll=LoadLibrary("HookApi2.dll"); 5 ~% K  p% q- j, e1 [: p; T/ D4 P% n
  g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0);
3 V3 R) g" w- f, Y0 O6 Bif (!g_hHook)
# w/ A/ \& ]& P0 K4 {{ 0 f  k* p9 i+ u! I" w5 a: ?
    MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
  p6 D0 ]/ l9 D3 b+ G: @- x# V. L" _$ l    return(false);
# [& b* G6 K4 g5 R  }
/ w" v8 V6 a, K: `7 p  
; Z6 g9 E: ]2 b9 o, P      / k7 V" J: U0 b+ p2 `! u8 I6 u% Q1 O
  return(true); : Q* F9 d! H7 [  G* Z
} 1 C( J5 p+ O( z! Y2 ?! S
HOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数 4 r- x! `  B4 o4 i( v3 p
{
, ]9 w/ V; P- O" v8 a! z  * U/ t. Q, M4 N9 U  U' H
  return(UnhookWindowsHookEx(g_hHook)); * n# G# n% ^9 l$ d$ D# b
} " T/ F; z$ P' t8 P1 |
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令   I" T' Q+ K/ W; x
{
7 o( b4 M9 f5 Q. _1 _" F. Q  hModule=LoadLibrary("user32.dll");
4 ~# ~9 R8 u, V3 E  pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
3 W5 [% G7 y- `5 p" c, z  if(pfMessageBoxA==NULL) ) I  I' I6 ]! {: t( m* L
   return false; , B$ R8 y3 G0 T: n* C; b, ^
  _asm 6 \3 z3 w% A; d5 C* B- Z8 [
  {
: }* A' U8 I" ?! N. u5 {$ h; W) D    lea edi,OldMessageBoxACode
' A, r8 W4 e9 U    mov esi,pfMessageBoxA
* S0 }% O( j/ q, S; \    cld . y# C, ?; |( Y# ^. q7 K# ^; }
    movsd
1 v, B8 K: Y7 _" R3 E% w" r2 P) p    movsb
+ D& R# y- E/ \' k8 Z! W7 J5 m  } + Q! Y. X9 n7 ^6 f; N
  NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 ; l) M5 m4 Z+ _* U
  _asm 6 K1 E9 K  `9 T! ?; `
  {
6 H* j: \% O) L* Z2 C; ^+ i    lea eax,MyMessageBoxA 9 i* W0 ~: X7 ~6 X$ k4 K
    mov ebx,pfMessageBoxA
  F# V1 X" ^! a# h" o0 o" ^    sub eax,ebx 4 M; h* N/ t2 T3 l$ U' S1 [" }
    sub eax,5 9 i0 ]8 z) d8 Y' z% }
    mov dword ptr [NewMessageBoxACode+1],eax
2 [4 R) J5 u1 n5 f9 a5 L  } * m2 ~0 x7 U# l" k7 n
  dwIdNew=GetCurrentProcessId(); //得到所属进程的ID 4 y* H) I5 p% }5 V7 s9 b, b  _
  dwIdOld=dwIdNew;
. m; S" @5 C5 J5 k3 R+ P4 R/ `" u  HookOn();//开始拦截
, p, W4 m7 }, f) Z5 \  return(true);
$ E: `0 V% X! B- q: r}
! U1 N" U; Q! m. \- h5 W7 vint WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数 & J; M) Y3 g5 g
{  
5 h) P1 v$ A: S, W  int nReturn=0;
  k) \/ K0 p% K0 U: L  HookOff(); - C+ D* B! F9 g! c9 F: {
  nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); / b# U- l" {/ Z- U( a
  HookOn();
$ Y, ]# X1 T3 M/ N9 F3 E, j: l, `  return(nReturn);
( _. C) h+ v* @0 ^1 c} ) @! V7 T; [  s. N" W. `6 m  j
void HookOn() $ ^* F. m1 P$ K7 ^& X
{ 0 q3 l0 F) S  F, [) K: _) V# H
  HANDLE hProc;   \9 q# d2 D$ i% J+ ~
  dwIdOld=dwIdNew;
- |  a+ P2 |4 u3 a5 F* x3 A& v  hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
5 O( O6 K% D& `# w  X" O  VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 0 r5 W6 _8 V0 x
  WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
' |8 F0 P2 `4 A2 H8 o- B  VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
  w& g: @) \- v, @$ X) [  bHook=true;
0 E5 c0 O8 `4 U2 s! h( J' b% J} 8 w. B) U5 K: X/ @
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA " m3 Y, d: [/ C2 F1 n& e5 D+ K
{ 0 ?. c9 t: E9 ]  j
  HANDLE hProc; 3 ?% B7 j) [. V; N/ g$ M$ j
  dwIdOld=dwIdNew;
. q: b4 ?  v# U1 g) g7 z# n1 w/ W  hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); ' Y4 c4 @9 u; [: G
  VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
, E; _1 m$ r# @2 h) q/ s  WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); 8 ?, L3 A9 S5 |! c2 p/ \' P
  VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); " \0 O8 b. G5 K/ ^
  bHook=false; $ I0 X0 F! f9 F, v/ _
}
5 o4 L# v6 W- v( y//测试文件: ; I/ w0 c/ l& o5 i
int APIENTRY WinMain(HINSTANCE hInstance, 2 {  w4 f1 c3 r* w# y+ B/ s
           HINSTANCE hPrevInstance, ( _% F+ \) D9 Q! c3 s" O2 _% \
           LPSTR   lpCmdLine,
4 ^" }+ K/ p( ^& z. e8 r' h           int    nCmdShow) 5 ~0 i6 V3 _, }0 T/ B" i: |
{
. u) ?$ ?$ j4 P! y0 B4 N  T8 s   
4 m: f7 L% l8 Z8 u0 V: H  if(!InstallHook())
3 ^1 k) J0 V: ]/ i3 P8 c2 S: H4 D- Q  { 9 E( f2 i8 i. M0 x
    MessageBoxA(NULL,"Hook Error!","Hook",MB_OK);
: C) i; x& p3 l2 f% j9 T( U    return 1; 0 F% v8 J! z; x* `  j
  }
$ l/ _' [0 {  s   MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 4 k/ T! S( f- G
  if(!UninstallHook()) ' `9 v. F* b# ~% H1 ]! h
  {
& j) C/ ^$ O5 ]/ C9 n    MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); 5 h- E/ R0 v/ r" X' y! F
    return 1; ; K2 W3 p: x: _: A
  }
# o+ E- B+ j4 T: m6 j4 x  return 0; ; y8 ^! _9 ]+ n8 q4 ]( t
} 0 L1 B. r7 l4 Z( ]6 G6 R# T
[此贴子已经被作者于2004-11-5 18:12:27编辑过]

' F" t4 y4 R7 f, \/ O4 u1 Q9 M5 ~
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 顶 踩

该用户从未签到

2
发表于 2004-11-19 00:12:00 | 只看该作者

好眼熟……

该用户从未签到

3
 楼主| 发表于 2004-11-19 00:36:00 | 只看该作者
大家转来转去就这么一片。大概……

本版积分规则

关闭

下沙大学生网推荐上一条 /1 下一条

快速回复 返回顶部 返回列表