下沙论坛

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

QQ登录

QQ登录

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

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

[复制链接]

该用户从未签到

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

& y4 V$ H+ v( o# X5 r发表日期:2003-10-30作者:tomh[] 出处: 7 Z( L6 y3 L' k- u2 S0 P$ w
Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
8 P" R. n! Z' F  本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, 7 y& r6 K2 A$ @* d) ~. C% u# x' g
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: & b. I& R9 V7 K8 G/ `
     BOOL VirtualProtectEx( ' o0 r1 G" j" m1 |* M6 Q
                HANDLE hProcess,   // 要修改内存的进程句柄 6 O6 l1 b3 V( d$ x* D; Z/ t0 d
                LPVOID lpAddress,  // 要修改内存的起始地址
. z4 v4 O/ O+ l. N& _4 o/ ^                DWORD dwSize,    // 修改内存的字节 # Y) u: h" q, O  n
                DWORD flNewProtect, // 修改后的内存属性
/ ?- ?) M/ s1 k" b                PDWORD lpflOldProtect // 修改前的内存属性的地址 6 o4 a8 H; v: l" s; x
                ); 5 T  g! L, S  L5 t  y
    BOOL WriteProcessMemory(
0 _' i, F+ E0 q6 Z/ {                HANDLE hProcess, // 要写进程的句柄
  A0 }  P7 x& x9 d: K- v3 W$ x                LPVOID lpBaseAddress, // 写内存的起始地址
5 {6 M( e6 t0 K; u0 b0 T  n                LPVOID lpBuffer, // 写入数据的地址 / v; _$ [- C. b8 a
                DWORD nSize,   // 要写的字节数
6 c! _1 }% |0 m" r- _4 V                LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 ( j: f0 b1 x4 K$ m+ E
                ); ! b8 M% X" q5 z; `
    BOOL ReadProcessMemory( * A# ~; z! \+ g3 t" U
                HANDLE hProcess, // 要读进程的句柄 , m* j! X% n; h& _7 u4 o; G8 z0 R
                LPCVOID lpBaseAddress,  // 读内存的起始地址
" [8 }+ c) v& C0 C: W: A                LPVOID lpBuffer, // 读入数据的地址   L8 ^6 o% i5 x& O* b: u
                DWORD nSize,   // 要读入的字节数 - ?2 H+ C0 X8 c, ?
                LPDWORD lpNumberOfBytesRead  // 实际读入的子节数 : x* x) q7 p6 \& ]4 @8 i
                ); 1 R: Z* `: a0 k& ^" m. d/ K
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同, 6 F5 }! B7 \" T! j' f
因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明: 5 M- Y/ B! x$ a$ m3 X
其中Dll文件为: 9 b  r9 b4 y0 ~4 K8 |
     HHOOK g_hHook; % B# P( f& N$ J9 l1 F
     HINSTANCE g_hinstDll; 2 ?( B1 t  M2 d
     FARPROC pfMessageBoxA;
5 J* f, X8 ~# x' c     int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); 1 ^% O2 e0 G* R* @5 x) X# D6 I
     BYTE OldMessageBoxACode[5],NewMessageBoxACode[5];
. \4 F' V5 J' E     HMODULE hModule ; 9 G' R0 p# M' h& P8 x5 r* |
     DWORD dwIdOld,dwIdNew; ) j8 b4 ]# Y! X7 t2 G) B' X- a
     BOOL bHook=false;
! R2 q& Q; }2 Q: w4 {( p$ ^! k     void HookOn(); $ z3 i) v4 ~0 C' y5 l, c( F0 V
     void HookOff(); 7 d/ G" C6 ^! T1 _
     BOOL init(); 8 Y- b! o8 Y# I  {6 R/ f* ]' p" Y
LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam); $ v: @# z4 f4 i7 M
BOOL APIENTRY DllMain( HANDLE hModule, & h0 a& v& D( A8 F) }( [, o- O- d
            DWORD ul_reason_for_call,
- t. M5 Z; D9 b* g* Q2 @/ ?1 h            LPVOID lpReserved
0 y  }" S( G3 A8 O           )
: J, A; {5 y3 h+ t) K/ u$ h{ ' ?" Y. S; x1 r* s7 I4 S9 `. k
  switch (ul_reason_for_call) + l  W. f4 c  G% c! i  B4 E( x
  {
2 U6 o+ r& G. X( Y# p8 S! @    case DLL_PROCESS_ATTACH: ' z9 c+ i, l1 K# k& X/ h! H
      if(!init()) 9 P" N& O/ ~& n4 t( @
      { 1 v+ u- u! P5 G1 ^! H7 x
             MessageBoxA(NULL,"Init","ERROR",MB_OK); ; T- k# K3 c9 m1 @8 h. P  ]. a3 m# C
             return(false);
/ R- ~) ^$ o3 O" w6 n. U* D      } ) X2 f$ N  C0 b, |* q. Z
    case DLL_THREAD_ATTACH:
8 i; c! q- f: x" [. N0 y    case DLL_THREAD_DETACH:
# N; C1 n$ Z$ z0 m8 f  h    case DLL_PROCESS_DETACH:   w, Z; e0 G/ N7 @- b- T( j& F
           if(bHook) UnintallHook();  
. w6 |: g& J$ |          break;
4 z7 `, Y8 R/ d7 S; G" `  {) T  } % g, f/ `* J1 w% P3 B# ]
  return TRUE; 8 I: w) m; O0 P. _) n' V2 ^
}
, ~4 `+ S) ~, ~! V' nLRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数 ( a; U3 H; M- {
{ 9 n' O8 m0 n5 W3 i4 _
   - L+ p6 n7 `. _: p
  return(CallNextHookEx(g_hHook,nCode,wParam,lParam));
- A' i; b  n3 r) O( Q1 V" I2 S}
; Z! e& \7 b; t- t1 }% DHOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数
9 e! H! `! k) P. U7 e; d# y{  
' d% A( l# l( `$ U; J; t  g_hinstDll=LoadLibrary("HookApi2.dll");
4 O5 T& Z6 K1 a( T5 B; W  g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); , J/ m! ~4 e4 B3 c, G  N3 a$ Y' f
if (!g_hHook)
4 @( @* ?% S( J; q( x7 C3 u{
. r) W$ S5 F4 C5 T    MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
5 F1 I7 }% ]( v. h  W3 m    return(false); # q: |1 h0 }  Y7 d
  } " R$ E6 w2 L' @
  7 `( U) |" c0 Z+ u1 p, `; u" O
      
: w, I8 d$ L% _# S, X  return(true);
, q' d( v5 t* ^- {9 q0 |}
) V: m7 [" S. T9 pHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
/ n8 x1 W  {" t' H+ m{ 1 s& P5 @+ d; K8 G( i
  $ Z7 B- s4 b$ ~
  return(UnhookWindowsHookEx(g_hHook));
, g  m8 O% Y# C8 D9 }' B} 6 v. x& {" N" y! W. |- w, K: j
BOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
5 t0 }2 V7 F" b3 U9 D; _{ # Y: V4 @: h' N
  hModule=LoadLibrary("user32.dll"); ' Q- e) H8 p6 ?# y# j( X6 [
  pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA");
6 a5 G) f0 u4 i5 i% L) A  if(pfMessageBoxA==NULL) & d$ d& I9 j/ h; X) r( d
   return false;
, a1 G9 T& |. y1 Q' a+ S& G5 j  _asm   A! p9 b0 o$ x
  { / }# Z/ t# H# r* w$ b
    lea edi,OldMessageBoxACode 1 ~3 _6 E: ~4 g7 O* X/ O
    mov esi,pfMessageBoxA
6 O% J! Z* _, P1 r1 t" I    cld
0 V0 J$ J" [0 I, k. F" [    movsd
" k/ q. c3 [  o5 }# C. _7 L- W    movsb $ t9 w' J" E7 [: U
  } " T" g/ N1 h5 P) |
  NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令 2 M  t1 N3 }1 S5 h# t+ B
  _asm % i0 D- V: f4 m% N8 ^) x4 S' m5 ?  p
  {
. y( o; m+ ~7 ?1 S    lea eax,MyMessageBoxA . n0 x3 v" Y1 M" Y2 }5 W* i; C
    mov ebx,pfMessageBoxA
  b4 f2 z$ T' ~! g, H5 b    sub eax,ebx ' u* c* _/ X2 P) \; y9 G
    sub eax,5 # T/ }0 V: J4 @' [' y: z2 t) l
    mov dword ptr [NewMessageBoxACode+1],eax
, G! s6 W% f; f: p  } + ?5 w2 ^' U8 J$ r6 j0 n
  dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
: t. e/ D3 {& a# c; w  dwIdOld=dwIdNew; 4 W% ?. N- p, Y) X7 C) g
  HookOn();//开始拦截 4 @$ Z! R% ~: J# h) A' F$ L+ w' I
  return(true); 1 r$ W% ~; k+ O9 J! r+ U2 E
} , H  C( a5 m  `# ?+ q
int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
8 W8 }  O  @3 j9 E4 T{  
5 C- n) O2 W% z. x# G- A9 Q  int nReturn=0; ) @" y8 t, M5 N. `8 q; D
  HookOff();
6 @8 s  F, i& S9 \  nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType); ) C2 _! ~8 `  @; h
  HookOn(); 9 m1 A/ C* ~$ s# @; g: e4 c
  return(nReturn); : |5 m* N7 h4 R2 Y% ?
}
4 X: j+ N3 i' H1 d! ^% L9 _void HookOn()
+ o- S8 E* a3 ]{
3 h8 A. q" v; i: R; d6 t: i% ?  HANDLE hProc;
! ]1 g+ p9 p; t  U$ f# |% _  dwIdOld=dwIdNew;
* u0 h/ U& x  N( _4 g. b  hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 : p' F! T& o; _4 t
  VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 ; ^1 `$ P9 u! C& D5 q% W" s4 f' l
  WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA * f( k7 [2 l# e5 Y' w
  VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 ( y& W( l2 |" e, ]/ a1 @
  bHook=true;
% m) T2 t" x6 j7 i# p" Y}   W9 w4 h7 |) P1 C$ k- q
void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA 3 v& v& e6 x9 @
{
: Y5 z2 P: l5 q8 l0 C% l4 n$ @  HANDLE hProc;
5 S4 w3 ]( O2 |9 m  dwIdOld=dwIdNew;
+ G+ K1 |$ L) [( R8 f) `$ |  hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);
% h# K. s- f! R: H- ^8 Y) r7 ]  VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld); 1 R6 Z% Q9 X2 u7 r4 m
  WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0); , F1 T- s3 _& F1 J
  VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld); ; V- u7 {# n* g8 k+ O$ v' F9 b
  bHook=false;
5 a7 x& T; O) H) V' t) S} 6 X' g$ i$ d5 c# Z! U; u  c# x  p
//测试文件:
; t0 I+ @6 r$ O" y0 \( zint APIENTRY WinMain(HINSTANCE hInstance, : v- d& F# s* _2 W, i& X- N% f
           HINSTANCE hPrevInstance,
0 [$ x/ f% K6 a. u( e& L           LPSTR   lpCmdLine, . p& T- I& x3 I7 \& v* h: a4 ?
           int    nCmdShow) : ?$ k" L7 f! j" R; {
{
5 [! r3 O. O, H' z6 ^( j   
4 u2 I% e9 F7 T- ^# R( w) n  if(!InstallHook())
% v0 d" L- Z0 e4 g  { $ S" M8 M- {7 O: O: R8 C
    MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); # a1 s" O( d4 u' A, m. u
    return 1; % P; S0 v. h; {: c0 a" S
  } % j0 ~0 }- m# _4 K  L4 j3 o; {6 l1 S% `
   MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见
! H* Q: {. Q0 j3 N. `. s; Y  if(!UninstallHook())
" I8 b5 ~0 P* f( c1 J  { - G3 K3 _$ K* {+ F  e0 X4 V
    MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); ' W$ \2 V- l2 y! ?5 o
    return 1;
* V3 c9 B$ M8 ?6 s; D4 A  } 1 @% b: x- I6 I
  return 0;
, m3 \0 x. i6 ~8 s7 p( [& z. \% I}
' N3 Q' @3 G, v8 k% W3 G5 B
[此贴子已经被作者于2004-11-5 18:12:27编辑过]

% L& Y8 c: ?5 p& b9 e4 J; d
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 顶 踩

该用户从未签到

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

好眼熟……

该用户从未签到

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

本版积分规则

关闭

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

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