设为首页收藏本站官方微博

汉化资料 API Hook的几种实现

[复制链接]
查看: 1808|回复: 0
打印 上一主题 下一主题

[汉化资料] API Hook的几种实现

跳转到指定楼层
楼主
发表于 2009-11-24 17:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

API Hook的几种实现

原文
; q0 W5 O) q  \( ^4 d& |http://www.cnblogs.com/rogeryu/archive/2009/06/04/1496538.html+ N2 a. u3 [9 ~2 E3 H
9 [3 j# f* ]  ]) Z2 V4 @- G
所谓的API Hook,就是利用某种技术将API的调用转为我们自己定义的函数的调用。这种技术在实际项目里面的应用也是很广泛的。最近,我在做关于我们项目的自动化测试的时候,就遇到了这种情况。在写测试代码之前,我们对测试代码有一些要求。1. 不能因为测试代码而修改原代码。2. 原有的模块是以dll格式输出的,在做测试的时候,要测的类和函数也只能使用dll的导出类或者函数,而不能将源文件重新编译。由于这些限制,导致测试用例往往不能在普通的机器上运行。比如这样一个函数:6 b5 ~0 ?4 l/ a* g

5 V: v* F, v: u7 X" L9 Bint func()
! L3 @3 E6 E& I, ]: _( Z7 ?2 i+ T% x{( ]: o( P1 a# H! J# c$ J, J
    //Some initializing codes
  G4 \% C3 z' H' c3 t0 n, o2 @    int hardware_code = get_hardware_code();3 `% x& H7 y9 X( }
    if (is_valid_code(hardware_code))
1 y' a. s4 L$ Z- S2 U2 m    {
. V+ Q/ G. O! w, ?        //, t3 o$ t$ k+ I& a+ X7 y' H. j$ c0 `
    }
" f& V! a. }4 l9 S5 K    //
: h( p# ^2 q1 {4 V) J6 E" {( a' b    return ret;
) {  `9 z2 q+ ]% @}
2 u! q2 Q; C' q% l( j4 g  B此处,函数get_hardware_code()是与特定平台相关的,在普通PC上运行肯定无法获得正确的结果。如果拿不到正确的结果,也就不能对函数func()进行测试了。于是,我们就可以利用API Hook技术,在测试代码里面,把所有对get_hardware_code()的调用换成我们自定义的函数mock_get_hardware_code()的调用,这样,在我们自己定义的函数里面,可以返回一个有效的代码以保证原代码能够正确的往下执行。& C% q1 p; I$ r+ p  u! C
! C+ b& F- c4 t2 [
经过研究,API Hook有这么几种方法。
( @0 }5 o! r3 P- u/ |4 R1 n
% T! ^$ d' G8 x: T0 @1. 改写函数的首地址。% x: X# w0 U" G: \
" O) c- j5 S% o  P# l8 Q: q$ L
这个是在《Windows核心编程》里面大师提到的API Hook的方法之一。原理就是,首先获得要被Hook的函数的地址(比如get_hardware_code()),然后将其首地址之后的若干字节(通常是5个字节)改成一条jmp指令,而jmp的目标地址就是自定义函数的地址(此处为mock_get_hardware_code())。这样,当函数每次执行目标函数的时候,就会跳转到我们自定义的函数里面去。这种方法很简洁,据说在Win16的年代经常被使用。但是大师并不推荐,好像是因为这种方法在多线程的环境下会有什么问题(具体的我忘记了,大家可以翻书看看)。
1 f% {8 T4 q: h# B# Z
0 _* l$ [+ ?9 I4 E- f- Y这样的话,只要我们能得到被调函数的地址,我们就可以随心所欲的修改。当然,由于大师的不推荐,我这种方法只是实现了一下,并未真正应用。5 [' V5 P) a- C4 e9 l" P, T

1 J- _+ j* ~" h7 @+ W% v2. 改写导入表5 q0 h& I! B3 x) s- y& i- ]" H' `

9 F) Y4 A- y5 n6 S; n. @2 U6 O这个也是《Windows核心编程》里面提到的,也是大师所推荐的。具体来说,就是遍历当前进程里面的所有模块,对其中每一个模块查找它的导入表。如果找到被测函数所在的dll,并且发现这个函数,那么就把这个地址修改成自定义函数的地址。关于如何从导入表中发现被测函数,我也总结了两种方式。1)对于一般的C导出函数,可以直接通过比较地址的方式去找,这个也在核心编程上面有一个小例子。2)对于C++中的导出的类成员函数而言,由于C++的指向成员函数的指针和普通的指针有所差别(我没仔细研究过,从网上查的),在将一个成员函数指针转化成普通的函数指针的时候编译通不过,因此我采取了第二种查找方式,也就是查找函数名。这还有一个问题,由于C++的导出成员函数名都进行了修饰,类似于?MethodName@ClassName@...@Z这种怪异的名字,不过,只要知道类名和方法名,然后查找MethodName@ClassName字符串就行。如果找到了这样的函数,然后在修改它的地址就行了。) y, B' w: J/ z5 a

7 U8 A8 x9 Q, t7 h% `另,关于导入表,大家可以去看雪论坛上有关Windows PE文件格式的介绍。此处就不多说了。2 Y" X; W. h; F- q6 \1 l# q

+ }. t4 [/ A* S- ]0 [& w3. 改写虚函数表。. Y0 M1 n0 a. x' o' F2 s2 Q

" {5 J* q' E" Z) R0 K" U; D2 x本来以为通过方法2就能hook住所有的导出类成员函数和普通函数,但还是出现了一个问题,因为我在尝试hook一个成员函数的时候,发现这个函数根本没有在导入表里面。后通过反汇编发现,由于那个导出类成员函数是一个虚函数,因为在通过指针调用的时候,它实际上是从虚函数表里面获得的函数地址进行调用的。因此对于hook这类函数,就需要改写它的虚函数表了。关于这个需要对C++的内存布局有所了解。我在这里就说一种比较简单的方式吧。
1 ^7 b( u5 |0 V: ~1 h& c) f
, _) ~& P5 D& O1 Q一般来说,对于某个含有虚函数表的C++类,this指针指向的地址,取值就是虚函数表指针。虚函数表指针指向了虚函数表,里面的每一个元素都指向了实际要调用的函数的地址。因此,可以按照这样的方式访问虚函数表指针:# Y  S; O6 n" Q1 Z
. ?4 S& k1 {  i4 t3 a2 z: t
int** pVTable = (int**)this;
  e) Y" }: [# f8 `, D6 @2 [3 M* ^. m7 l  ~1 C1 p
也就是将指向对象的指针强制转化成指针的指针,这样就可以通过取值就可以访问虚函数表:
/ f3 C/ ^/ y! r( d2 x
* _9 }8 Y# O5 C  s(*pVTable)[0] = address of virtual function 1;
4 T! {! R0 X) B2 M$ ?7 i( b+ Z3 s* r! E0 r  @
(*pVTable)[1] = address of virtual function 2;
8 b. F- O% q- i$ A" v. \1 w: ^# H1 F( A/ ]0 h* O* v* A
...
6 A8 `# |; ^5 b% w' z: n( Y# ]1 T3 p
因此,我们就可以改写虚函数的地址了,从而达到hook的目的。这种技术来源于网上。当然,我对C++的内存布局也不是十分的清楚,如果一个类进行了多重继承,它的虚函数表是什么样子我也不太明白,这里只是说明了这样一种技术。
/ _/ l/ S' p" h" E2 B# Z! b: k" X" ?, E! o
以上就是目前为止我应用到的三种API Hook的技术,其实实际应用到的也就是后两种,这两种技术能够满足我目前项目的需要了。如果还有其他关于API Hook技术的话大家也可以交流。* h" Q# ~4 ^3 j3 [& |

6 O& k# {6 x  Z/ v0 X1 x另外需要说明的一点是,上述三种方法中不管哪一种在改写地址的时候,由于Windows一般将那个地址所在的页面设置了保护属性,因为你需要用VirtualProtect函数将页面改为可读可写的属性才能改写,否则会有异常的。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 很美好很美好 很差劲很差劲
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

冒险解谜游戏中文网 ChinaAVG

官方微博官方微信号小黑屋 微信玩家群  

(C) ChinaAVG 2004 - 2019 All Right Reserved. Powered by Discuz! X3.2
辽ICP备11008827号 | 桂公网安备 45010702000051号

冒险,与你同在。 冒险解谜游戏中文网ChinaAVG诞生于2004年9月9日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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