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

汉化资料 API Hook的几种实现

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

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

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

API Hook的几种实现

原文
. _- U' Z. p6 ^& dhttp://www.cnblogs.com/rogeryu/archive/2009/06/04/1496538.html* ?: p* _/ Q; U% `8 c5 v! t+ n; j
; B7 T5 K5 b) z
所谓的API Hook,就是利用某种技术将API的调用转为我们自己定义的函数的调用。这种技术在实际项目里面的应用也是很广泛的。最近,我在做关于我们项目的自动化测试的时候,就遇到了这种情况。在写测试代码之前,我们对测试代码有一些要求。1. 不能因为测试代码而修改原代码。2. 原有的模块是以dll格式输出的,在做测试的时候,要测的类和函数也只能使用dll的导出类或者函数,而不能将源文件重新编译。由于这些限制,导致测试用例往往不能在普通的机器上运行。比如这样一个函数:, y. Z9 y8 d# G* F: A7 f
8 \  K$ q$ c/ M# Q, X$ u8 G- _
int func()- _9 ]8 o! i) f# L$ ]9 R: b$ ?
{
! T  p3 T& K9 a: D. q2 Y  `    //Some initializing codes
: K- U: G) |$ j. H; F& z    int hardware_code = get_hardware_code();( R3 P/ m" E. M) g: \
    if (is_valid_code(hardware_code))' }% v) Z8 t  ]& {7 ^8 R
    {8 H- h8 y3 \; ~$ v
        //
/ C$ y- S/ }% f1 x    }
  [+ p  m" y- B$ ?' d& e. l    //8 J9 ~! J0 A$ j( P1 z$ f4 s' h: s( u
    return ret;
* ^# \' t( t' ]: {; S" x}$ Q1 h: x% C# @- N
此处,函数get_hardware_code()是与特定平台相关的,在普通PC上运行肯定无法获得正确的结果。如果拿不到正确的结果,也就不能对函数func()进行测试了。于是,我们就可以利用API Hook技术,在测试代码里面,把所有对get_hardware_code()的调用换成我们自定义的函数mock_get_hardware_code()的调用,这样,在我们自己定义的函数里面,可以返回一个有效的代码以保证原代码能够正确的往下执行。6 @) h; ?4 X5 ?; S  x: g  W
1 c7 O( S$ d2 l0 ]* G/ y
经过研究,API Hook有这么几种方法。# {# R" T! k- J9 v" p$ E

2 t9 e+ X" f# k, [& ?" u" p6 e1. 改写函数的首地址。5 X- j7 \9 k* x+ u* `0 m# u# `
0 H# R6 f+ S( Y9 S6 @- |1 e, v
这个是在《Windows核心编程》里面大师提到的API Hook的方法之一。原理就是,首先获得要被Hook的函数的地址(比如get_hardware_code()),然后将其首地址之后的若干字节(通常是5个字节)改成一条jmp指令,而jmp的目标地址就是自定义函数的地址(此处为mock_get_hardware_code())。这样,当函数每次执行目标函数的时候,就会跳转到我们自定义的函数里面去。这种方法很简洁,据说在Win16的年代经常被使用。但是大师并不推荐,好像是因为这种方法在多线程的环境下会有什么问题(具体的我忘记了,大家可以翻书看看)。
, O/ a( o& {# j0 w" W7 v5 e- R
( s4 x$ Q- R* X  X+ G; Y5 u$ z这样的话,只要我们能得到被调函数的地址,我们就可以随心所欲的修改。当然,由于大师的不推荐,我这种方法只是实现了一下,并未真正应用。2 A1 Q( ]& c. I+ r1 V8 d
! h1 h( I6 K" H  |5 I* C
2. 改写导入表
5 ?6 T3 m/ J1 z# k/ C4 w9 O3 m" y
- }7 L  g6 d% d) w# y. k这个也是《Windows核心编程》里面提到的,也是大师所推荐的。具体来说,就是遍历当前进程里面的所有模块,对其中每一个模块查找它的导入表。如果找到被测函数所在的dll,并且发现这个函数,那么就把这个地址修改成自定义函数的地址。关于如何从导入表中发现被测函数,我也总结了两种方式。1)对于一般的C导出函数,可以直接通过比较地址的方式去找,这个也在核心编程上面有一个小例子。2)对于C++中的导出的类成员函数而言,由于C++的指向成员函数的指针和普通的指针有所差别(我没仔细研究过,从网上查的),在将一个成员函数指针转化成普通的函数指针的时候编译通不过,因此我采取了第二种查找方式,也就是查找函数名。这还有一个问题,由于C++的导出成员函数名都进行了修饰,类似于?MethodName@ClassName@...@Z这种怪异的名字,不过,只要知道类名和方法名,然后查找MethodName@ClassName字符串就行。如果找到了这样的函数,然后在修改它的地址就行了。
# C- B, q/ R) H4 B6 ~% n' j' h
/ w- D% b( X) k, u) J' v3 f' C2 C另,关于导入表,大家可以去看雪论坛上有关Windows PE文件格式的介绍。此处就不多说了。
9 i/ m! r, [' U+ m: B1 M( R; `" I5 A/ V% x8 C! K
3. 改写虚函数表。4 y# c) ?: j. K3 q

% F2 n7 Z+ _1 t+ I- M" M+ Q7 ]" \本来以为通过方法2就能hook住所有的导出类成员函数和普通函数,但还是出现了一个问题,因为我在尝试hook一个成员函数的时候,发现这个函数根本没有在导入表里面。后通过反汇编发现,由于那个导出类成员函数是一个虚函数,因为在通过指针调用的时候,它实际上是从虚函数表里面获得的函数地址进行调用的。因此对于hook这类函数,就需要改写它的虚函数表了。关于这个需要对C++的内存布局有所了解。我在这里就说一种比较简单的方式吧。) g  t2 W  _8 ~/ o6 l

+ M6 {. ]( {+ [0 T4 I一般来说,对于某个含有虚函数表的C++类,this指针指向的地址,取值就是虚函数表指针。虚函数表指针指向了虚函数表,里面的每一个元素都指向了实际要调用的函数的地址。因此,可以按照这样的方式访问虚函数表指针:, R% g  G) {8 U3 D  i6 o- v) C
( G4 J; c! W/ T. l0 j' M5 M
int** pVTable = (int**)this;
5 u$ U9 |8 v( N" T( Z/ d
9 Z7 a; u- r- \% R. s也就是将指向对象的指针强制转化成指针的指针,这样就可以通过取值就可以访问虚函数表:2 o1 F; R8 q# @+ o

8 H1 i9 e/ H" e( V: _; z(*pVTable)[0] = address of virtual function 1;
% A* v3 r5 @  ?) D- _3 v8 n8 R! Z6 @- O- n0 [
(*pVTable)[1] = address of virtual function 2;
5 D2 G# k2 Z+ E" p( {+ S2 k; ]' h; C5 [! T& u0 M) v$ ^3 ~
...
9 C3 p" w- }, f" n. \0 h# Z0 @, w
9 T6 D' I1 ?2 }/ ?" W2 S  m因此,我们就可以改写虚函数的地址了,从而达到hook的目的。这种技术来源于网上。当然,我对C++的内存布局也不是十分的清楚,如果一个类进行了多重继承,它的虚函数表是什么样子我也不太明白,这里只是说明了这样一种技术。
( g( w6 x0 |8 k& b! D, b
0 e* n8 N; J2 N& S/ ^以上就是目前为止我应用到的三种API Hook的技术,其实实际应用到的也就是后两种,这两种技术能够满足我目前项目的需要了。如果还有其他关于API Hook技术的话大家也可以交流。
2 |. f) ?4 ?  w1 s! A$ a6 i( s+ i
# @' K% ?3 f$ y: \4 Y另外需要说明的一点是,上述三种方法中不管哪一种在改写地址的时候,由于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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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