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

汉化资料 API Hook的几种实现

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

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

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

API Hook的几种实现

原文
+ j; S8 A  V' k0 [2 w5 z% `4 X: zhttp://www.cnblogs.com/rogeryu/archive/2009/06/04/1496538.html) Q. q0 T3 z8 z& X9 z. Y
7 P/ n+ m1 x3 g& U/ s+ X5 b( i' g
所谓的API Hook,就是利用某种技术将API的调用转为我们自己定义的函数的调用。这种技术在实际项目里面的应用也是很广泛的。最近,我在做关于我们项目的自动化测试的时候,就遇到了这种情况。在写测试代码之前,我们对测试代码有一些要求。1. 不能因为测试代码而修改原代码。2. 原有的模块是以dll格式输出的,在做测试的时候,要测的类和函数也只能使用dll的导出类或者函数,而不能将源文件重新编译。由于这些限制,导致测试用例往往不能在普通的机器上运行。比如这样一个函数:2 j; r5 M4 K9 e! }

9 U3 y: O: m+ Z/ T, eint func()
; Z, \* \7 `$ @6 j{
& I9 P  A1 t3 y6 K  b' F# d; o5 k    //Some initializing codes2 |% A4 T- D' _  }
    int hardware_code = get_hardware_code();
% z8 q3 L+ n' {+ J* B3 V4 R    if (is_valid_code(hardware_code))+ A! W& f- z1 U
    {; c* Z3 X, S; y
        /// O. [) J( Y! I# Z# n% h( S1 Q
    }- r" ^, Q: {1 S8 a
    //, _# ^3 |& {1 {% a- G# Q. T
    return ret;% G# Z- F# p2 K$ p0 u  M
}4 G* D6 A4 W( k4 i/ O" ~& c
此处,函数get_hardware_code()是与特定平台相关的,在普通PC上运行肯定无法获得正确的结果。如果拿不到正确的结果,也就不能对函数func()进行测试了。于是,我们就可以利用API Hook技术,在测试代码里面,把所有对get_hardware_code()的调用换成我们自定义的函数mock_get_hardware_code()的调用,这样,在我们自己定义的函数里面,可以返回一个有效的代码以保证原代码能够正确的往下执行。7 J. r' K: c6 M1 \0 A

9 |/ Q) \! K, P) D2 {5 q经过研究,API Hook有这么几种方法。9 F8 k& {6 ]1 |( T$ g4 B/ n
/ @+ q# W9 U1 f( H+ ]7 \
1. 改写函数的首地址。
6 c4 N* B/ s" m1 ^% h* K/ s3 y- k1 U+ z2 `0 D* Q. r1 z+ K
这个是在《Windows核心编程》里面大师提到的API Hook的方法之一。原理就是,首先获得要被Hook的函数的地址(比如get_hardware_code()),然后将其首地址之后的若干字节(通常是5个字节)改成一条jmp指令,而jmp的目标地址就是自定义函数的地址(此处为mock_get_hardware_code())。这样,当函数每次执行目标函数的时候,就会跳转到我们自定义的函数里面去。这种方法很简洁,据说在Win16的年代经常被使用。但是大师并不推荐,好像是因为这种方法在多线程的环境下会有什么问题(具体的我忘记了,大家可以翻书看看)。' g6 a" V% g& _/ Z4 V

: |" F/ z/ q8 _* p3 [  q; y这样的话,只要我们能得到被调函数的地址,我们就可以随心所欲的修改。当然,由于大师的不推荐,我这种方法只是实现了一下,并未真正应用。/ a/ c5 W3 D  B' h; ]* x' \
$ X: I+ z: E% e' }8 w
2. 改写导入表5 i9 t! G8 u# e3 K$ e

6 }0 o3 @# y3 @% I- q- u+ E这个也是《Windows核心编程》里面提到的,也是大师所推荐的。具体来说,就是遍历当前进程里面的所有模块,对其中每一个模块查找它的导入表。如果找到被测函数所在的dll,并且发现这个函数,那么就把这个地址修改成自定义函数的地址。关于如何从导入表中发现被测函数,我也总结了两种方式。1)对于一般的C导出函数,可以直接通过比较地址的方式去找,这个也在核心编程上面有一个小例子。2)对于C++中的导出的类成员函数而言,由于C++的指向成员函数的指针和普通的指针有所差别(我没仔细研究过,从网上查的),在将一个成员函数指针转化成普通的函数指针的时候编译通不过,因此我采取了第二种查找方式,也就是查找函数名。这还有一个问题,由于C++的导出成员函数名都进行了修饰,类似于?MethodName@ClassName@...@Z这种怪异的名字,不过,只要知道类名和方法名,然后查找MethodName@ClassName字符串就行。如果找到了这样的函数,然后在修改它的地址就行了。
) A+ c: e* r) W) u. t
9 N9 @: D" _: N$ K4 }9 c' T- ]另,关于导入表,大家可以去看雪论坛上有关Windows PE文件格式的介绍。此处就不多说了。6 s; L& }) L  }# F& s' M
9 U, j3 T7 P5 p  X1 n1 I3 e; J- I5 d; y
3. 改写虚函数表。! W0 c+ u2 \4 G; G

" ]7 }) [- ?8 F3 Y0 e本来以为通过方法2就能hook住所有的导出类成员函数和普通函数,但还是出现了一个问题,因为我在尝试hook一个成员函数的时候,发现这个函数根本没有在导入表里面。后通过反汇编发现,由于那个导出类成员函数是一个虚函数,因为在通过指针调用的时候,它实际上是从虚函数表里面获得的函数地址进行调用的。因此对于hook这类函数,就需要改写它的虚函数表了。关于这个需要对C++的内存布局有所了解。我在这里就说一种比较简单的方式吧。6 K: G/ b) U3 B; L

  R$ P! `& O2 E7 k* n一般来说,对于某个含有虚函数表的C++类,this指针指向的地址,取值就是虚函数表指针。虚函数表指针指向了虚函数表,里面的每一个元素都指向了实际要调用的函数的地址。因此,可以按照这样的方式访问虚函数表指针:% r1 i) C3 l! }5 \
5 F- s% B! K- k- B7 L
int** pVTable = (int**)this;
+ q: w6 \) U  _, o. S# `6 {5 R9 E
: k# I6 H& G2 N# w3 u. f也就是将指向对象的指针强制转化成指针的指针,这样就可以通过取值就可以访问虚函数表:" ]0 ~6 K. Y1 h& G

# A/ W* j, k  m, E* O* q& Z* `6 w- \(*pVTable)[0] = address of virtual function 1;% y; m& t8 I1 y7 p% Y4 `7 l6 K

3 H" V- s! e4 `(*pVTable)[1] = address of virtual function 2;0 y8 \: G; |2 [: m! ~: ?1 v
2 y+ M9 O; V% R6 m, ]
...
" c1 ~! C, C: _* |! G
9 K, |8 c5 C; k4 U3 {# x因此,我们就可以改写虚函数的地址了,从而达到hook的目的。这种技术来源于网上。当然,我对C++的内存布局也不是十分的清楚,如果一个类进行了多重继承,它的虚函数表是什么样子我也不太明白,这里只是说明了这样一种技术。
% F. }: ?1 R! K' ~6 ~+ Z2 F! w/ s9 E. O
以上就是目前为止我应用到的三种API Hook的技术,其实实际应用到的也就是后两种,这两种技术能够满足我目前项目的需要了。如果还有其他关于API Hook技术的话大家也可以交流。
6 ?9 I# u% A6 L) @# \1 a5 T0 T! `$ m% g: N7 {( h
另外需要说明的一点是,上述三种方法中不管哪一种在改写地址的时候,由于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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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