下沙论坛

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

QQ登录

QQ登录

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

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

[复制链接]

该用户从未签到

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

5 j- n1 Y8 v% h2 l& v; a* z8 o0 l6 E发表日期:2003-10-30作者:tomh[] 出处:
! [) L) {4 l" w: @0 V) y2 C) G# f$ }Api拦截并不是一个新的技术,很多商业软件都采用这种技术。对windows的Api函数的拦截,不外乎两种方法,第一种是Mr. Jeffrey Richter 的修改exe文件的模块输入节,种方法,很安全,但很复杂,而且有些exe文件,没有Dll的输入符号的列表,有可能出现拦截不到的情况。第二种方法就是常用的JMP XXX的方法,虽然很古老,却很简单实用。
$ ^5 E& S  ~, w9 @5 ?  本文一介绍第二种方法在Win2k下的使用。第二种方法,Win98/me 下因为进入Ring0级的方法很多,有LDT,IDT,Vxd等方法,很容易在内存中动态修改代码,但在Win2k下,这些方法都不能用,写WDM太过复杂,表面上看来很难实现, 9 l! {, S* f6 N" \8 _+ F
其实不然。Win2k为我们提供了一个强大的内存Api操作函数---VirtualProtectEx,WriteProcessMemeory,ReadProcessMemeory,有了它们我们就能在内存中动态修改代码了,其原型为: - b. I1 Q/ B1 g- `  ^4 h$ Y0 y
     BOOL VirtualProtectEx( 9 e. {7 Q# E& X
                HANDLE hProcess,   // 要修改内存的进程句柄
& f4 w4 K& x- n+ V+ Y/ S                LPVOID lpAddress,  // 要修改内存的起始地址 ( ]- D. ~- `$ c3 [# {3 S( J$ N0 x
                DWORD dwSize,    // 修改内存的字节
+ Z, y# R) V# `2 V% T                DWORD flNewProtect, // 修改后的内存属性
. q4 ]' x; ^* {, t4 Z- k& L# y7 r) l                PDWORD lpflOldProtect // 修改前的内存属性的地址 8 H! Y6 ^, H: c
                ); ! D  [( q$ S* Q5 @5 K3 q! Z$ q
    BOOL WriteProcessMemory( 2 C- X1 E% y' O- l, X; F* v& q1 V* |
                HANDLE hProcess, // 要写进程的句柄 ) I; j0 v/ \8 Q& Y( r! E
                LPVOID lpBaseAddress, // 写内存的起始地址
$ ~* @! g8 {1 I4 R7 E# ]                LPVOID lpBuffer, // 写入数据的地址
9 w" y& j+ U; `7 \+ m, M                DWORD nSize,   // 要写的字节数 $ Y$ Z' A3 I. O! t& `
                LPDWORD lpNumberOfBytesWritten // 实际写入的子节数 1 h7 M$ E1 L* h3 L) W; m7 ?7 G
                ); % b# P7 z% G/ }2 P
    BOOL ReadProcessMemory( 1 G6 e( ~% Q1 H( l+ q$ a
                HANDLE hProcess, // 要读进程的句柄 ; D5 t" O( i6 b+ |; ^- s% r) K3 A
                LPCVOID lpBaseAddress,  // 读内存的起始地址 ( ?, V2 H6 r# R: o, t# @
                LPVOID lpBuffer, // 读入数据的地址 6 X" y% \4 q1 \& u. V
                DWORD nSize,   // 要读入的字节数 , r6 u" \& ^# ?% o8 w
                LPDWORD lpNumberOfBytesRead  // 实际读入的子节数 0 }% X* p1 |. h( N/ x, h
                ); " @1 v/ c2 c) R& B  X" C
具体的参数请参看MSDN帮助。在Win2k下因为Dll和所属进程在同一地址空间,这点又和Win9x/me存在所有进程存在共享的地址空间不同,
; ~) ~1 B9 ]7 L( I( p) C5 h因此,必须通过钩子函数和远程注入进程的方法,现以一个简单采用钩子函数对MessageBoxA进行拦截例子来说明:
) |  L( ^, f( U3 J4 V# L其中Dll文件为:
3 T3 l* l( D# l3 N8 }: Y* S     HHOOK g_hHook; 9 {) H. F3 `  C1 i8 _# p. k- L/ I
     HINSTANCE g_hinstDll;
5 j6 v: [" O4 Q  j+ k* t* ^     FARPROC pfMessageBoxA; , D; @, @3 D$ p( F% e: W
     int WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption,UINT uType); 5 x+ Y" ~( j( a2 `+ F7 r4 a0 v
     BYTE OldMessageBoxACode[5],NewMessageBoxACode[5]; 9 O' t! [, i! O* \! W2 i+ `
     HMODULE hModule ;
1 F6 X3 t1 E+ t7 l8 F! ?     DWORD dwIdOld,dwIdNew;
) J' Q# D. ]4 j* G' @0 t! Y5 o     BOOL bHook=false;
' D+ B4 q  d1 D     void HookOn(); 6 c" k5 O; c0 j
     void HookOff();
/ u- P( ~% k& Q/ H( v     BOOL init();
+ q1 s" Y+ q' [: H/ G) c( U5 [LRESULT WINAPI MousHook(int nCode,WPARAM wParam,LPARAM lParam);
' a- u9 y6 N1 v, h1 c0 L, X, `BOOL APIENTRY DllMain( HANDLE hModule,
& \, u5 w% N) Y; C            DWORD ul_reason_for_call,
3 i0 ^$ a3 A3 D. _1 U            LPVOID lpReserved 9 M5 F  B7 t6 A/ T
           )
4 E$ z7 i+ @/ t9 n, X2 Q{ $ K& j; D! E2 J4 X
  switch (ul_reason_for_call)
. U/ h  j2 N. r1 o0 K  { $ i( s% r/ T6 c9 u
    case DLL_PROCESS_ATTACH:
9 X# i& d# @. v5 a! z      if(!init())   G4 R, ^+ Y$ R- v- S3 \
      { ' u" ~" V3 m# o* ]. j
             MessageBoxA(NULL,"Init","ERROR",MB_OK); ; e6 O8 O; \  H" e
             return(false);
% e% L$ Z# E: P" g      } , ^% E5 K* ?$ h. t. Z2 @1 k) H
    case DLL_THREAD_ATTACH:
! c  v0 F( Z* U7 h: S. j7 }" y    case DLL_THREAD_DETACH:
; ?: C* e( L1 k- v5 C! v! ^    case DLL_PROCESS_DETACH:
0 i( J/ W5 ~% ^& l, E& \           if(bHook) UnintallHook();  
$ S6 O& I6 R* ]  y. C          break; & G' c4 Z4 c' H, \3 L% p! L
  }
( H# c5 X2 Y7 ^8 \# r7 C: W  return TRUE;
3 L" x, ?. e4 p0 x} 5 U( F9 b7 S8 n9 t5 P+ w
LRESULT WINAPI Hook(int nCode,WPARAM wParam,LPARAM lParam)//空的钩子函数
5 `) B. Y/ |9 w5 K5 a{
1 b% E7 ]. r8 s+ u# \   7 f3 T: q0 O- p9 y; M
  return(CallNextHookEx(g_hHook,nCode,wParam,lParam)); - k2 _# q# c2 J. g" o1 v$ q2 X
} 3 ~, V' H3 v% g+ Y( |2 ]
HOOKAPI2_API BOOL InstallHook()//输出安装空的钩子函数 , n* }% {; X& E/ j5 }9 L
{  1 O/ [8 E2 ~  _: G
  g_hinstDll=LoadLibrary("HookApi2.dll"); ) k' f+ e8 p+ a) v3 B) C
  g_hHook=SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)Hook,g_hinstDll,0); ! {; m1 _8 }6 H1 X5 W+ \
if (!g_hHook) 3 Z2 B+ v# {# C5 q7 g2 s2 P  G- n3 g
{ ' \" u7 {" f( n' i* [' ]* t
    MessageBoxA(NULL,"SET ERROR","ERROR",MB_OK);
$ K' J$ q3 ~1 |' Y' ]) P8 U    return(false);
, @  |7 f8 Q+ I8 X* c2 w7 ?  } 9 l7 }$ {0 p  h3 T
  8 G" X' J/ c2 o( J
      2 [# y6 _4 P1 D( G
  return(true);
. r6 W4 D1 D* n3 n* c5 s}
9 d8 h3 C5 |) C2 \: }) h7 u2 oHOOKAPI2_API BOOL UninstallHook()//输出御在钩子函数
$ ]- A& w+ _8 P" Z{ - q# A8 v2 @6 l# h- I  e+ J- s1 a
  # y8 ~6 G1 X! f  q% g/ [1 n
  return(UnhookWindowsHookEx(g_hHook)); 4 z& a/ E4 t$ ^8 R1 p, K
}
8 p% C0 V. k% A+ t' mBOOL init()//初始化得到MessageBoxA的地址,并生成Jmp XXX(MyMessageBoxA)的跳转指令
2 v3 f. @7 `0 r; X, K* X{
* m: |6 N6 ^+ _  hModule=LoadLibrary("user32.dll");
8 t4 M. K3 _1 x5 W% X. R# z- T& w  pfMessageBoxA=GetProcAddress(hModule,"MessageBoxA"); 1 a2 S- G, K6 X) w8 M4 t6 X' O
  if(pfMessageBoxA==NULL) 8 G0 ~9 ]6 p! k
   return false; ( ?+ v- n! Z' o
  _asm ) v% K' l% _- N4 e. V
  {
8 t6 w& ^. l2 B+ A' r- z5 a; i    lea edi,OldMessageBoxACode # m$ I6 J9 \/ _& E
    mov esi,pfMessageBoxA
9 _4 Y5 `9 W0 ]) S9 y9 C2 K    cld
/ M% r; @% b1 ?6 O    movsd " m7 P! m! n, s. e* ^, m) J
    movsb - M  z' s4 \- {4 `' ?( q3 `
  } 6 G" _* r6 _* P2 S
  NewMessageBoxACode[0]=0xe9;//jmp MyMessageBoxA的相对地址的指令
8 C' q: k, r( Z8 V  _asm * H) a6 O2 E$ _) T% G/ ^$ n
  { ! g7 I) F( o/ k+ X- \3 z( J% ]
    lea eax,MyMessageBoxA " l( |3 N# S& X. E# |% S3 _0 m
    mov ebx,pfMessageBoxA % e! e9 Q# I4 {7 T! f6 M
    sub eax,ebx ! X' N- I1 G" k. m+ u
    sub eax,5 4 s# D9 z, D! k
    mov dword ptr [NewMessageBoxACode+1],eax
) o0 N) y* z$ \  } 3 \: u' B$ h1 C# O3 A7 M. O
  dwIdNew=GetCurrentProcessId(); //得到所属进程的ID
. e, M- j) f, A1 Y  dwIdOld=dwIdNew;
0 D) }6 ]( i( P! o4 [" S! Q2 N4 K  HookOn();//开始拦截 6 h2 o2 v0 F, U. t" G. r
  return(true);
: p' v. [2 T& C$ r& F" O  b( m9 z' n}
7 V9 K, O& O. q: j! _- z" @$ O! t# wint WINAPI MyMessageBoxA(HWND hWnd, LPCTSTR lpText,LPCTSTR lpCaption, UINT uType )//首先关闭拦截,然后才能调用被拦截的Api 函数
' ]+ w4 |7 \; J8 W$ l; m/ g{  
4 y- w6 b# t8 Y9 C0 Y  int nReturn=0;
- _' B6 r3 \& q; `* H9 j  HookOff();
. e1 e6 i5 y. i1 `5 T  nReturn=MessageBoxA(hWnd,"Hook",lpCaption,uType);
2 T$ }; a" S" ^; s! L' K  HookOn(); # i/ R$ _7 [6 j  {0 T, V
  return(nReturn);
% n: n4 f" T5 }3 C, v# o}
9 l! @4 e' r  y& }( m+ E+ {void HookOn()
- T7 y, y) f! x! l{ 0 m& j$ s  ^6 B* y# n, T4 S
  HANDLE hProc; # E  X3 ?6 N7 O
  dwIdOld=dwIdNew;
& L& b& x: O  ~3 Y$ U! m  hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld);//得到所属进程的句柄 + S, r1 ]5 S! M: S
  VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为可写 6 ]+ `* _. b4 e; D# c( t- ]
  WriteProcessMemory(hProc,pfMessageBoxA,NewMessageBoxACode,5,0);//将所属进程中MessageBoxA的前5个字节改为JMP 到MyMessageBoxA
$ [3 M( L, x. q# u4 `5 U0 x4 }  VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);//修改所属进程中MessageBoxA的前5个字节的属性为原来的属性 6 {2 c* x  D0 w! \6 a# Q4 T
  bHook=true;
3 c- Z1 Y4 I3 q# u, v0 e}
2 h8 T/ b. O4 S0 \void HookOff()//将所属进程中JMP MyMessageBoxA的代码改为Jmp MessageBoxA
4 R/ D' s  H7 G9 {' M{ - J; t3 [8 ]4 X, u
  HANDLE hProc; 1 F8 |) A3 O& {4 P) J
  dwIdOld=dwIdNew;
# [- S4 `/ ]. P: M1 X+ d* K2 U, U  hProc=OpenProcess(PROCESS_ALL_ACCESS,0,dwIdOld); 9 ]3 [- v( \1 d7 p4 e* a6 _& i1 h! |2 F
  VirtualProtectEx(hProc,pfMessageBoxA,5,PAGE_READWRITE,&dwIdOld);
' i4 D' B% P3 n) S" T$ T0 R  WriteProcessMemory(hProc,pfMessageBoxA,OldMessageBoxACode,5,0);
0 N& @9 s( J  {  VirtualProtectEx(hProc,pfMessageBoxA,5,dwIdOld,&dwIdOld);
7 W: ^% ^( m7 U! U  bHook=false;   t1 M# p; W3 E3 e
}
8 e) Q" C6 \7 z- ?* b% I//测试文件: ( Z7 l8 ]( W# }( B' a" ?  ]
int APIENTRY WinMain(HINSTANCE hInstance,
: L7 H# e4 Y4 L* k8 n0 k3 Y: ^           HINSTANCE hPrevInstance, , T" y$ T. v# i5 @. L2 a& m
           LPSTR   lpCmdLine, 1 [6 C9 W- i1 k& C
           int    nCmdShow)
2 L5 L3 E+ p, g) Y7 i; g{
) d  ^8 m, Q+ y- u/ L% ~8 k     a1 e1 R0 z0 h3 ~
  if(!InstallHook())
3 P, n# C2 m0 U8 [  { 7 n% q* c4 M/ Q2 d
    MessageBoxA(NULL,"Hook Error!","Hook",MB_OK); # a6 K# t, C1 p8 C- K5 m6 Y
    return 1;
7 E* @3 q3 k$ X; i) e) z  h  } & h% ^+ U2 \9 x: c0 c/ t$ Z
   MessageBoxA(NULL,"TEST","TEST",MB_OK);//可以看见Test变成了Hook,也可以在其他进程中看见 8 @% D) d7 ^+ g, Y; Y
  if(!UninstallHook()) & i6 s0 d# x2 Q# U$ F$ {! j
  {
5 l7 R/ p# J6 O9 g4 L; o' p    MessageBoxA(NULL,"Uninstall Error!","Hook",MB_OK); & V$ R& H  Z1 k6 N
    return 1;
, d0 N3 f( p( I  }
* G/ u0 t5 x, R  return 0;
! g3 Z; I2 x: w: O6 v. `# ~} 2 ~% f- f, j9 K; l
[此贴子已经被作者于2004-11-5 18:12:27编辑过]

, E3 R. }+ r( Y  A. Q. s  h7 J3 q
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 顶 踩

该用户从未签到

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

好眼熟……

该用户从未签到

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

本版积分规则

关闭

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

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