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

汉化资料 API Hook的几种实现

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

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

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

API Hook的几种实现

原文
3 j" |& A# n& p- rhttp://www.cnblogs.com/rogeryu/archive/2009/06/04/1496538.html
) R* O. E: p- [" I, S3 u* T
, {+ p1 Y) Q: n* C8 M* P所谓的API Hook,就是利用某种技术将API的调用转为我们自己定义的函数的调用。这种技术在实际项目里面的应用也是很广泛的。最近,我在做关于我们项目的自动化测试的时候,就遇到了这种情况。在写测试代码之前,我们对测试代码有一些要求。1. 不能因为测试代码而修改原代码。2. 原有的模块是以dll格式输出的,在做测试的时候,要测的类和函数也只能使用dll的导出类或者函数,而不能将源文件重新编译。由于这些限制,导致测试用例往往不能在普通的机器上运行。比如这样一个函数:
: g5 c- K. _; M0 {' z! D5 N( n& g' n
int func()
2 |& k' V! M& `' W. Q& e: ~9 m7 F4 k{
$ b% [6 N2 t! e3 D0 M& W" E6 b    //Some initializing codes/ F+ N$ n- W4 b( Q4 z! D
    int hardware_code = get_hardware_code();- R9 v/ T& d, d5 [+ e/ i$ ~/ c
    if (is_valid_code(hardware_code))+ R2 |. p5 j1 P3 N8 A
    {
$ Y7 w! P9 l; b+ Z& W' P        /// C  Y7 @2 Y/ s$ v
    }
/ }1 H/ L* v/ ?) _    //( v/ B" L5 t4 w, }! L  l$ \
    return ret;
' U) W3 _; F7 y8 n& [}4 L: N3 }% K- [/ X/ r
此处,函数get_hardware_code()是与特定平台相关的,在普通PC上运行肯定无法获得正确的结果。如果拿不到正确的结果,也就不能对函数func()进行测试了。于是,我们就可以利用API Hook技术,在测试代码里面,把所有对get_hardware_code()的调用换成我们自定义的函数mock_get_hardware_code()的调用,这样,在我们自己定义的函数里面,可以返回一个有效的代码以保证原代码能够正确的往下执行。* F  ^* I; T3 Z
! V/ E: P" F3 K; R* T
经过研究,API Hook有这么几种方法。
4 e( O9 ?1 ]& f$ S4 E# z+ N! w3 E9 n/ J; f9 Z' j- e
1. 改写函数的首地址。
5 m7 q+ O" s# ~
' h2 [" v, d) x6 B) v# N, T( N这个是在《Windows核心编程》里面大师提到的API Hook的方法之一。原理就是,首先获得要被Hook的函数的地址(比如get_hardware_code()),然后将其首地址之后的若干字节(通常是5个字节)改成一条jmp指令,而jmp的目标地址就是自定义函数的地址(此处为mock_get_hardware_code())。这样,当函数每次执行目标函数的时候,就会跳转到我们自定义的函数里面去。这种方法很简洁,据说在Win16的年代经常被使用。但是大师并不推荐,好像是因为这种方法在多线程的环境下会有什么问题(具体的我忘记了,大家可以翻书看看)。6 n) ]) |2 M( q) X/ ^
0 L; {! l5 {% ]/ n& n
这样的话,只要我们能得到被调函数的地址,我们就可以随心所欲的修改。当然,由于大师的不推荐,我这种方法只是实现了一下,并未真正应用。: Z1 Q: B! s# v. e

: O$ i6 ?5 A" C* W% C2. 改写导入表
7 H7 j7 C  Z  v% W+ X, W
% ~9 G; h- D' {  _8 Q1 `这个也是《Windows核心编程》里面提到的,也是大师所推荐的。具体来说,就是遍历当前进程里面的所有模块,对其中每一个模块查找它的导入表。如果找到被测函数所在的dll,并且发现这个函数,那么就把这个地址修改成自定义函数的地址。关于如何从导入表中发现被测函数,我也总结了两种方式。1)对于一般的C导出函数,可以直接通过比较地址的方式去找,这个也在核心编程上面有一个小例子。2)对于C++中的导出的类成员函数而言,由于C++的指向成员函数的指针和普通的指针有所差别(我没仔细研究过,从网上查的),在将一个成员函数指针转化成普通的函数指针的时候编译通不过,因此我采取了第二种查找方式,也就是查找函数名。这还有一个问题,由于C++的导出成员函数名都进行了修饰,类似于?MethodName@ClassName@...@Z这种怪异的名字,不过,只要知道类名和方法名,然后查找MethodName@ClassName字符串就行。如果找到了这样的函数,然后在修改它的地址就行了。
! p/ p$ w) L- {$ Q' O  D% {
% p3 H# [6 y- }7 n另,关于导入表,大家可以去看雪论坛上有关Windows PE文件格式的介绍。此处就不多说了。$ m' w& ], Q2 @$ I

5 P  C) h8 X" Y; H7 V) G3. 改写虚函数表。" m$ p6 P" }# ]( }9 S

, G1 W) l* p+ k6 N本来以为通过方法2就能hook住所有的导出类成员函数和普通函数,但还是出现了一个问题,因为我在尝试hook一个成员函数的时候,发现这个函数根本没有在导入表里面。后通过反汇编发现,由于那个导出类成员函数是一个虚函数,因为在通过指针调用的时候,它实际上是从虚函数表里面获得的函数地址进行调用的。因此对于hook这类函数,就需要改写它的虚函数表了。关于这个需要对C++的内存布局有所了解。我在这里就说一种比较简单的方式吧。
8 c. {: y! n2 k3 Z" R. I4 P4 Q! k9 g" w3 t# g6 f& F
一般来说,对于某个含有虚函数表的C++类,this指针指向的地址,取值就是虚函数表指针。虚函数表指针指向了虚函数表,里面的每一个元素都指向了实际要调用的函数的地址。因此,可以按照这样的方式访问虚函数表指针:* b$ q  s3 \' d6 \
/ X( E  J9 f8 |( G9 m
int** pVTable = (int**)this;
: U) x( ~' E. H$ V9 [* _( \$ J$ r
也就是将指向对象的指针强制转化成指针的指针,这样就可以通过取值就可以访问虚函数表:
$ q) X! |3 e5 S- H, R
8 E) ?+ e; x* o; K& @3 I; {4 R% {+ \(*pVTable)[0] = address of virtual function 1;
6 q2 E/ K. ~* F# q" B6 `0 L1 F& j1 H, Z! _+ }  g6 a7 f
(*pVTable)[1] = address of virtual function 2;$ q0 Y5 V9 @8 u( e! b1 J3 q
! {# \# z5 ], a1 u6 L8 S5 a) k) V
...$ E6 V8 p9 N# [- y! o, ~

! H2 p# [9 {8 [' j# C7 M因此,我们就可以改写虚函数的地址了,从而达到hook的目的。这种技术来源于网上。当然,我对C++的内存布局也不是十分的清楚,如果一个类进行了多重继承,它的虚函数表是什么样子我也不太明白,这里只是说明了这样一种技术。8 t& w% h2 Q* Q) T, i8 ^% n, ?
8 E* Z+ H* C& z) X) l4 k
以上就是目前为止我应用到的三种API Hook的技术,其实实际应用到的也就是后两种,这两种技术能够满足我目前项目的需要了。如果还有其他关于API Hook技术的话大家也可以交流。
8 V8 W2 i  V* K' Z5 k5 c9 \( i  ?7 X6 g) L; [
另外需要说明的一点是,上述三种方法中不管哪一种在改写地址的时候,由于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日,是全球华人共同的冒险解谜类游戏家园。我们致力于提供各类冒险游戏资讯供大家学习交流。本站所有资源均不用于商业用途。

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