下沙论坛

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

用新浪微博连接

一步搞定

QQ登录

QQ登录

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

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

[复制链接]

该用户从未签到

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

7 `! {  q; n% V6 o4 G9 w发表日期:2003-10-30作者:tomh[] 出处: 0 P, q0 v- S! t0 E$ M: W
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。 5 D' j4 n# B. c( k
  本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现,
2 G9 A6 h" U% k$ T其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为:
3 f5 [; }4 Q+ d7 P     BOOL VirtualProtectEx(
! O9 A1 |! X6 T% |6 u                HANDLE hProcess,   // 要修改内存的进程句柄 & x+ M- x+ U' V" z" M
                LPVOID lpAddress,  // 要修改内存的起始地址
! X0 t2 `7 n! t7 ]& t+ m; R                DWORD dwSize,    // 修改内存的字节 ( P) G' l7 ?  s& D. H7 r2 w( d9 e4 W
                DWORD flNewProtect, // 修改后的内存属性
0 ^" U; r% U! {: y' N                PDWORD lpflOldProtect // 修改前的内存属性的地址 3 e/ m$ P2 k, @% q! Y
                ); 0 @. o" X" [8 E- e8 ^' e+ ?
    BOOL WriteProcessMemory(
6 {5 w3 H. o( I  D  T+ U1 B  X3 |                HANDLE hProcess, // 要写进程的句柄 , ^4 A# o0 S" L- V6 n
                LPVOID lpBaseAddress, // 写内存的起始地址
9 Y5 p8 E! _3 h                LPVOID lpBuffer, // 写入数据的地址   e' V: o- n- u/ y
                DWORD nSize,   // 要写的字节数
0 j6 E" U4 U% A# j1 K# {0 q% @, S                LPDWORD lpNumberOfBytesWritten // 实际写入的子节数
- a- w: `1 u+ h  C% c! b4 q4 |                );
! V, l9 z% k' _) Z! L    BOOL ReadProcessMemory( : ?; [' D. n( ^
                HANDLE hProcess, // 要读进程的句柄
- b* L1 k8 j4 i* S% _4 C" U                LPCVOID lpBaseAddress,  // 读内存的起始地址 " q" Y( H& G& f
                LPVOID lpBuffer, // 读入数据的地址
* \) N) `6 K3 ^; P% E/ g                DWORD nSize,   // 要读入的字节数 1 r# n, p: |$ l0 J" L2 F
                LPDWORD lpNumberOfBytesRead  // 实际读入的子节数 2 h  D' y: ~+ \' s
                );   _- x# F6 N0 E1 H3 G2 |
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, * m+ t# k2 o) I( \8 Q& W9 X# f- c
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: : R! o& Q" y# n2 k* B) i
其中Dll文件为:
# {- `  o% o2 W% y( c" n! l     HHOOK g_hHook;
) H; N' q0 r" B# k7 t     HINSTANCE g_hinstDll;
3 k4 ?9 v5 R! ]3 s/ V  f     FARPROC pfMessageBoxA;
' B3 Y# y/ L: g# {! f5 E     int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
* O/ ]$ N- g. {8 Y+ o. C/ J9 s/ T     BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; : q* x( i8 a, o) M# Q1 @
     HMODULE hModule ;
7 j) f" w( n& b     DWORD dwIdOld,dwIdNew; ; h( C! k7 Y+ E
     BOOL bHook=false;
' y% j1 e4 G8 ]' p/ N$ v# x7 ^     void HookOn(); , X) j( r8 D. I1 {9 ]( T+ [
     void HookOff();
' ~* h0 l$ a5 Z+ |     BOOL init(); $ M1 [0 D7 [/ F1 h/ a
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
% A! V+ ?0 B/ h- }' y3 ABOOL APIENTRY DllMain( HANDLE hModule,
6 B+ l8 V! `/ [' C            DWORD ul_reason_for_call, / A: o( A9 J$ T5 @
            LPVOID lpReserved
9 v$ S* m% U2 B1 L. w( F           )
2 f2 N+ L2 Y. H/ p. |' B8 u( Q{ 5 k" `+ O* [5 H7 o/ q# r5 W3 I
  switch (ul_reason_for_call)
7 g" Z! ]" v8 y7 X2 G# D3 J: H  { # v; v. A# x3 i  Z
    case DLL_PROCESS_ATTACH:
% M' K# `' _4 |* I/ \9 Y      if(!init())
9 w. t- v- S  u      {
9 a" \- R" F9 k5 m             MessageBoxA(NULL,"Init","ERROR",MB_OK); 7 ~( N3 q, h: n: T8 f
             return(false);
0 l) ^* I) S+ \! g3 h9 k; h      } ; N6 @. x) \* w3 i# y& W
    case DLL_THREAD_ATTACH:
; T* y7 g6 P& S5 M+ R4 s- g1 U    case DLL_THREAD_DETACH:
! [  I; F4 B3 x; H# \) g    case DLL_PROCESS_DETACH: % v) U. ~2 P' u$ G" j( U7 n& \
           if(bHook) UnintallHook();  
. F+ G" q4 `* _          break; 5 u' {% ?* W& q2 t
  } # V8 [- j1 N% H: K
  return TRUE;
0 r% ?& K, B9 m/ h/ X! Q6 P} 9 j6 a8 f8 x. r1 O; u5 A9 g1 z4 x
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
1 ~8 X0 k) C2 Z2 J{ 7 B! Q9 Z: A8 l, F8 [2 J3 y
   
+ L  u" |* S2 j# N& d& |7 c' T4 [  return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); + w0 G5 x# c4 W; ?+ ?- p! n
}
3 r& s3 ]+ r  E8 MHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 : u9 z) {$ H2 Y0 m7 E% k
{  $ W/ }% A8 V4 m+ {& i, S
  g_hinstDll=LoadLibrary("HookApi2.dll"); # E* `& H2 p  n+ U# w
  g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); , n+ G8 G  y6 v9 W: g  b- N9 u) y$ A
if (!g_hHook) ( u0 g! E* C- Y5 m
{ 1 ?* Y5 ~9 ~8 k2 p8 G2 A, z7 h
    MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
8 C) ^4 ]3 k! m- T% G( Q    return(false); # I7 W( A# ]: e4 k4 B# y! [* O
  }
) M. d+ `0 s: z% f0 @$ z& t# \  
, e: z" Z' \7 \7 e$ S      $ s5 w2 l4 a5 [- g2 }1 S
  return(true);
0 I7 b( U, D6 v  r}
% u7 l8 J; U- `/ M( fHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
7 a7 \$ s8 @" c) \! |6 I/ q{ $ a% {7 A- y$ E, w
  / D" s7 z( W8 M0 M/ J
  return(UnhookWindowsHookEx(g_hHook));
3 V' H7 O: m& Z2 r& m0 t' d} ( N+ ?6 s3 b3 o
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令   ~, d  r2 I* @" c4 F
{
1 U% K3 P5 ~% e/ h6 [  hModule=LoadLibrary("user32.dll"); : k" V; A# R' X# A( O" J
  pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
2 d3 w; C7 W+ J: M( f  if(pfMessageBoxA==NULL)
( |, [: O# K. ^* r7 X   return false; " U! x  F, o* c: S$ }2 F' P
  _asm   R& _- p* e( H, u
  { ! N" h4 G% [! W& F$ g
    lea edi,OldMessageBoxACode
# b" ?, X( C% ^6 a' ?' f# s+ i    mov esi,pfMessageBoxA * K3 k2 _3 \7 J2 k1 e
    cld
: E' a) N. l2 Z- j& w    movsd ' w8 E  `4 h0 L9 i  D' ]- J/ z
    movsb 3 p. Q& O; U( ]) z/ ~  |' I" ]' z
  } : w1 `  \" }6 w% }( I+ H8 t2 ]8 {
  NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
- q0 F" I9 f" E  _asm
+ N, V! m, S- `; S: \3 S. c  {
2 V. Z" G- e# J! [) v    lea eax,MyMessageBoxA
+ `8 M9 m) T: b9 v" c; V. y% h9 X    mov ebx,pfMessageBoxA
* Y9 z0 ^: \3 D2 w+ Y$ J7 }' E    sub eax,ebx
: ~/ m& h* a+ ]* S: a    sub eax,5 , E/ T' r7 W, `( }! K3 P9 R4 I2 ~
    mov dword ptr [NewMessageBoxACode+1],eax ' o2 P/ O6 W, ~+ R, A/ J4 g9 O
  }
2 z7 C. j+ u. X5 o9 E  dwIdNew=GetCurrentProcessId(); //得到所属进程的ID , w7 ]( A+ G5 ^% [7 S# J4 }
  dwIdOld=dwIdNew; + c5 |% j- z, c5 B( E9 }; c# }, G
  HookOn();//开始拦截 8 u2 ]0 U7 n5 f
  return(true); + O1 I2 H5 Y  H. z; i) a2 U
} 5 S& E7 m, A4 Z; v( i1 q
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
( _$ q- X6 I' v{  * C( G/ Z3 m- g. Q# Y( Y
  int nReturn=0; - @$ ]0 c8 U# @; u* b+ |! J
  HookOff(); & r6 O2 `: K8 S* I0 ]) {
  nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); ; E7 n$ ?* N+ q2 s8 @
  HookOn();
9 m: o8 u5 s2 ~+ \1 X  return(nReturn); 0 J" @, [0 b+ K  E
} 2 L3 C) ^( j3 g! K) S; K; V) G
void HookOn() ( l( f5 h. j  X, t
{
) D: _: s1 ~) H, S  HANDLE hProc; - V1 M, a$ G6 k* W( W& x2 \
  dwIdOld=dwIdNew;
: Z" S2 H9 h4 t" @5 @) w+ w. ]- v( a  hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄
9 ]- R" X' c- t, D5 p  VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写
+ D  ?6 l5 C! ]# a& `9 L; W; Z& O  WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
" D/ I) Q3 v% X! t( a+ Z+ @% U  VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性
" ]' a. C, L+ G( c* |  bHook=true; 9 ~3 U4 r% H2 ~& R# k' t
} % L" ]: ]8 i  }8 Q9 ?
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA # u: N( @" Y6 O8 N: _
{ ! ~: y3 C' h) R
  HANDLE hProc; ( P% G' O% o5 u( ]% j. o" {
  dwIdOld=dwIdNew;
: L2 |; K, a$ w3 B) M  hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); 2 m+ S" Q& f$ a( f$ _
  VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 6 H; V0 S& d( {9 M- ]
  WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
3 n- K1 M, V$ Q0 y- g  VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); . O2 ~& r. a, n
  bHook=false;
2 X4 t/ y! L" E}
; M( x% |% k3 b5 J//测试文件: 7 t9 h* H; j; E- u- \
int APIENTRY WinMain(HINSTANCE hInstance,
# I: X/ c( K2 [& B2 x8 U0 k# p           HINSTANCE hPrevInstance,
" |8 ]1 b* Z8 n4 k$ ^: w  y' K           LPSTR   lpCmdLine,
6 r/ G" i6 O0 a$ [; |9 N; T( G/ M" f           int    nCmdShow) . e( N- l  d& j- U, ~
{
! z) R3 G  \- ]" Q   * U% L9 h1 t7 E9 }
  if(!InstallHook())
6 F# E- H) U$ W: I2 S  { - u/ a) P, i  P& ^0 }
    MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); 3 _! S+ `( p& H. R/ o3 y  S# a
    return 1; 4 G+ L, n4 `6 |0 H3 i
  } & @5 R' ?' c8 y
   MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 ( \' g3 v& H1 e& B
  if(!UninstallHook())
* z+ L7 m: g( m; ~6 u: U: o6 F. d  E  { 6 p. M. Y9 z* Q$ ]- {3 O! g7 H, T
    MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); , v4 r6 i; d" M: t/ a# \. t
    return 1; 0 L6 D9 `7 P& x' b
  } 3 w+ B+ `: a  o& S2 c2 S. ~
  return 0;
- r1 m' }5 ~+ b. O$ e}
8 y: w- t) G0 I; U
[此贴子已经被作者于2004-11-5 18:12:27编辑过]
. h, B( M5 x' w* G" y# H
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 顶 踩 转发到微博

该用户从未签到

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

好眼熟……

该用户从未签到

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

本版积分规则

关闭

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

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