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

汉化资料 API Hook的几种实现

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

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

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

API Hook的几种实现

原文
- X7 T3 c. }( ohttp://www.cnblogs.com/rogeryu/archive/2009/06/04/1496538.html5 ^  O$ R  B7 Y1 b
! W7 K' {) F1 O/ D9 ?2 F! B4 E
所谓的API Hook,就是利用某种技术将API的调用转为我们自己定义的函数的调用。这种技术在实际项目里面的应用也是很广泛的。最近,我在做关于我们项目的自动化测试的时候,就遇到了这种情况。在写测试代码之前,我们对测试代码有一些要求。1. 不能因为测试代码而修改原代码。2. 原有的模块是以dll格式输出的,在做测试的时候,要测的类和函数也只能使用dll的导出类或者函数,而不能将源文件重新编译。由于这些限制,导致测试用例往往不能在普通的机器上运行。比如这样一个函数:
$ Q4 L) `" X1 h0 d% N: |$ x0 q3 B: k1 x" I0 U& g8 R
int func()  g) K& E6 D6 b8 C4 G1 N
{/ ~* }, c) j0 C& a
    //Some initializing codes
1 H7 ]& I8 \' A- ~. y: I0 ]    int hardware_code = get_hardware_code();
3 m8 ~! U! c# v$ i& L    if (is_valid_code(hardware_code))
5 h- S$ i4 O: Z  m2 M" ^& t" ]1 A    {
( |. @# e1 F5 X9 x/ _+ s7 x$ G        //
2 O7 G* Y  w; T2 Q  V    }
) t; N7 t  p, v* L/ @" i. x) e    //, ]9 W% x* o* t# L7 G6 L# l6 s, t  b
    return ret;
8 q; r3 O6 [2 e/ @2 t6 @}
( A" B* J- {! ?此处,函数get_hardware_code()是与特定平台相关的,在普通PC上运行肯定无法获得正确的结果。如果拿不到正确的结果,也就不能对函数func()进行测试了。于是,我们就可以利用API Hook技术,在测试代码里面,把所有对get_hardware_code()的调用换成我们自定义的函数mock_get_hardware_code()的调用,这样,在我们自己定义的函数里面,可以返回一个有效的代码以保证原代码能够正确的往下执行。
1 N, g0 o# c8 \- U# Q6 i( p$ `: j9 b& t! s9 B& U* }' C
经过研究,API Hook有这么几种方法。# W4 I+ j! y% u! M/ J6 M, B* R  T) H2 d

2 Y- L7 M/ ~6 h1 r1. 改写函数的首地址。
& ]( Y3 E; N# L* `* @- Z
- g# @6 ?' H+ D: C" z0 w' M这个是在《Windows核心编程》里面大师提到的API Hook的方法之一。原理就是,首先获得要被Hook的函数的地址(比如get_hardware_code()),然后将其首地址之后的若干字节(通常是5个字节)改成一条jmp指令,而jmp的目标地址就是自定义函数的地址(此处为mock_get_hardware_code())。这样,当函数每次执行目标函数的时候,就会跳转到我们自定义的函数里面去。这种方法很简洁,据说在Win16的年代经常被使用。但是大师并不推荐,好像是因为这种方法在多线程的环境下会有什么问题(具体的我忘记了,大家可以翻书看看)。; h' o( P+ {% T& `4 K

* i' _% P/ O( P% t( A+ ~这样的话,只要我们能得到被调函数的地址,我们就可以随心所欲的修改。当然,由于大师的不推荐,我这种方法只是实现了一下,并未真正应用。8 y! v" v, l! B- T- n3 ~% a" w

5 e$ I- Z2 _  u) e+ F$ {& _- U2. 改写导入表: M& I4 J* ]) m' U

# }2 `3 [( W+ v5 H这个也是《Windows核心编程》里面提到的,也是大师所推荐的。具体来说,就是遍历当前进程里面的所有模块,对其中每一个模块查找它的导入表。如果找到被测函数所在的dll,并且发现这个函数,那么就把这个地址修改成自定义函数的地址。关于如何从导入表中发现被测函数,我也总结了两种方式。1)对于一般的C导出函数,可以直接通过比较地址的方式去找,这个也在核心编程上面有一个小例子。2)对于C++中的导出的类成员函数而言,由于C++的指向成员函数的指针和普通的指针有所差别(我没仔细研究过,从网上查的),在将一个成员函数指针转化成普通的函数指针的时候编译通不过,因此我采取了第二种查找方式,也就是查找函数名。这还有一个问题,由于C++的导出成员函数名都进行了修饰,类似于?MethodName@ClassName@...@Z这种怪异的名字,不过,只要知道类名和方法名,然后查找MethodName@ClassName字符串就行。如果找到了这样的函数,然后在修改它的地址就行了。
5 {4 T0 c  P# R( P2 m: `3 `4 O% `% M
  u3 I' [2 I5 G# j% t5 r1 r另,关于导入表,大家可以去看雪论坛上有关Windows PE文件格式的介绍。此处就不多说了。
7 M/ f& ?: a" P7 [- ~7 Z6 x% t# z! ]1 Y# W) f7 ?) k+ C# ]
3. 改写虚函数表。1 Y( Z% `# N& u; t( }
1 [. Z* ?# G& V' G( K6 M" M
本来以为通过方法2就能hook住所有的导出类成员函数和普通函数,但还是出现了一个问题,因为我在尝试hook一个成员函数的时候,发现这个函数根本没有在导入表里面。后通过反汇编发现,由于那个导出类成员函数是一个虚函数,因为在通过指针调用的时候,它实际上是从虚函数表里面获得的函数地址进行调用的。因此对于hook这类函数,就需要改写它的虚函数表了。关于这个需要对C++的内存布局有所了解。我在这里就说一种比较简单的方式吧。
2 P1 M' a/ ]$ x# b/ N, S) _0 q- K3 [6 E7 l( q8 x
一般来说,对于某个含有虚函数表的C++类,this指针指向的地址,取值就是虚函数表指针。虚函数表指针指向了虚函数表,里面的每一个元素都指向了实际要调用的函数的地址。因此,可以按照这样的方式访问虚函数表指针:
( \' t' k3 j$ d# V( K4 f1 |  o- |+ Z0 n$ h+ R( {
int** pVTable = (int**)this;) g; n* c$ D- c0 P' e

* u0 W5 B+ o$ [# h也就是将指向对象的指针强制转化成指针的指针,这样就可以通过取值就可以访问虚函数表:5 B4 B2 M  r6 {

4 G/ V; A  x# e$ c; }" ]# o(*pVTable)[0] = address of virtual function 1;
$ f* u# y3 c, r; F3 J
& q& V5 e1 \4 K- i  n(*pVTable)[1] = address of virtual function 2;, L/ o6 X5 f8 \: @8 x# g' B5 ?
) L% v6 q, s6 C$ k2 W
...0 e  J# k! F# e: a. {( U
) J6 k8 X8 |5 Z/ n3 [0 |1 j- @
因此,我们就可以改写虚函数的地址了,从而达到hook的目的。这种技术来源于网上。当然,我对C++的内存布局也不是十分的清楚,如果一个类进行了多重继承,它的虚函数表是什么样子我也不太明白,这里只是说明了这样一种技术。' l+ A" C: X. V

, M2 o' o8 B! l) D, A以上就是目前为止我应用到的三种API Hook的技术,其实实际应用到的也就是后两种,这两种技术能够满足我目前项目的需要了。如果还有其他关于API Hook技术的话大家也可以交流。
, k% X& Z% s) e" O8 y0 M6 O. a) @
6 w. ~# u1 Z6 \7 g* a9 \另外需要说明的一点是,上述三种方法中不管哪一种在改写地址的时候,由于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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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