API Hook基本原理和实现
2009-03-14 20:09
windows系统下的编程,消息message的传递是贯穿其始终的。这个消息我们可以简单理解为一个有特定意义的整数,正如我们看过的老故事片中的“ 长江长江,我是黄河”一个含义。windows中定义的消息给初学者的印象似乎是“不计其数”的,常见的一部分消息在winuser.h头文件中定义。 hook与消息有着非常密切的联系,它的中文含义是“钩子”,这样理解起来我们不难得出“hook是消息处理中的一个环节,用于监控消息在系统中的传递,并在这些消息到达最终的消息处理过程前,处 理某些特定的消息”。这也是hook分为不同种类的原因。 
hook的这个本领,使它能够将自身的代码“融入”被hook住的程序的进程中,成为目标进程的一个部分。我们也知道,在windows2000以后的系 统中,普通用户程序的进程空间都是独立的,程序的运行彼此间都不受干扰。这就使我们希望通过一个程序改变其他程序的某些行为的想法不能直接实现,但是 hook的出现给我们开拓了解决此类问题的道路。

api hook是什么? 
在windows系统下编程,应该会接触到api函数的使用,常用的api函数大概有2000个左右。今天随着控件,stl等高效编程技术的出现,api 的使用概率在普通的用户程序上就变得越来越小了。当诸如控件这些现成的手段不能实现的功能时,我们还需要借助api。最初有些人对某些api函数的功能不 太满意,就产生了如何修改这些api,使之更好的服务于程序的想法,这样api hook就自然而然的出现了。我们可以通过api hook,改变一个系统api的原有功能。基本的方法就是通过hook“接触”到需要修改的api函数入口点,改变它的地址指向新的自定义的函数。api hook并不属于msdn上介绍的13类hook中的任何一种。所以说,api hook并不是什么特别不同的hook,它也需要通过基本的hook提高自己的权限,跨越不同进程间访问的限制,达到修改api函数地址的目的。对于自身进程空间下使用到的api函数地址的修改,是不需要用到api hook技术就可以实现的。

api hook和pe格式的关系 
api hook技术的难点,并不在于hook技术,初学者借助于资料“照葫芦画瓢”能够很容易就掌握hook的基本使用技术。但是如何修改api函数的入口地 址?这就需要学习pe可执行文件(.exe,.dll等)如何被系统映射到进程空间中,这就需要学习pe格式的基本知识。windows已经提供了很多数 据结构struct帮助我们访问pe格式,借助它们,我们就不要自己计算格式的具体字节位置这些繁琐的细节。但是从api hook的实现来看,pe格式的访问部分仍然是整个编程实现中最复杂的一部分,对于经常crack的朋友不在此列。 
假设我们已经了解了pe格式,那么我们在哪里修改api的函数入口点比较合适呢?这个就是输入符号表imported symbols table(间接)指向的输入符号地址。 
下面对于pe格式的介绍这一部分,对于没有接触过pe格式学习的朋友应该是看不太明白的,但我已经把精华部分提取出来了,学习了pe格式后再看这些就很容易了。

pe格式的基本组成 
+-------------------+ 
| DOS-stub | --DOS-头 
+-------------------+ 
| file-header | --文件头 
+-------------------+ 
| optional header | --可选头 
|- - - - - - - - - -| 
| | 
| data directories | --(可选头尾的)数据目录 
| | 
+-------------------+ 
| | 
| section headers | --节头 
| | 
+-------------------+ 
| | 
| section 1 | --节1 
| | 
+-------------------+ 
| | 
| section 2 | --节2 
| | 
+-------------------+ 
| | 
| ... | 
| | 
+-------------------+ 
| | 
| section n | --节n 
| | 
+-------------------+ 
在上图中,我们需要从“可选头”尾的“数据目录”数组中的第二个元素——输入符号表的位置,它是一个IMAGE_DATA_DIRECTORY结构,从它中的VirtualAddress地址,“顺藤摸瓜”找到api函数的入口地点。 
下图的简单说明如下: 
OriginalFirstThunk 指向IMAGE_THUNK_DATA结构数组,为方便只画了数组的一个元素,AddressOfData 指向IMAGE_IMPORT_BY_NAME结构。 
IMAGE_IMPORT_DESCRIPTOR数组:每个引入的dll文件都对应数组中的一个元素,以全0的元素(20个bytes的0)表示数组的结束 
IMAGE_THUNK_DATA32数组:同一组的以全0的元素(4个bytes的0)表示数组的结束,每个元素对应一个IMAGE_IMPORT_BY_NAME结构 
IMAGE_IMPORT_BY_NAME:如..@Consts@initialization$qqrv. 表示 
Unmangled Borland C++ Function: qualified function __fastcall Consts::initialization() 
 
为了减少这个图的大小,不得已将汇编和c++的结构都用上了。这个图是输入符号表初始化的情形,此时两个IMAGE_THUNK_DATA结构数组的对应元素都指向同一个IMAGE_IMPORT_BY_NAME结构。 
程序加载到进程空间后,两个IMAGE_THUNK_DATA结构数组指向有所不同了。看下图:

 
始化的,“两个结构都指向同一个IMAGE_IMPORT_BY_NAME”,此时还没有api函数地址

 
当PE文件准备执行时,前图已转换成上图。一个结构指向不变,另一个出现api函数地址

如果PE文件从kernel32.dll中引入10个函数,那么IMAGE_IMPORT_DESCRIPTOR 结构的 Name1域包含指向字符串"kernel32.dll"的RVA,同时每个IMAGE_THUNK_DATA 数组有10个元素。(RVA是指相对地址,每一个可执行文件在加载到内存空间前,都以一个基址作为起点,其他地址以基址为准,均以相对地址表示。这样系统 加载程序到不同的内存空间时,都可以方便的算出地址) 
上述这些结构可以在winnt.h头文件里查到。

具体编程实现 
我将手上的vc示例代码进行了适当修正,修改了一些资源泄漏的小问题,移植到c++builder6 & update4上,经过测试已经可以完成基本的api hook功能。有几个知识点说明一下: 
1、 dll中共享内存变量的实现 
正常编译下的dll,它的变量使用到的内存是独立的。比如你同时运行两个调用了某个dll的用户程序,试图对某一个在dll中定义的全局变量修改赋值的时候,两个程序里的变量值仍然是不同的。 
共享的方法为:在.cpp文件(.h文件里如此设置会提示编译错误)的头部写上如上两行: 
#pragma option -zRSHSEG // 改变缺省数据段名 
#pragma option -zTSHCLASS // 改变缺省数据类名

HINSTANCE hdll = NULL; // 用来保存该动态连接库的句柄 
HHOOK hApiHook = NULL; // 钩子句柄 
HHOOK hWndProc = NULL; // 窗口过程钩子用来拦截SendMessage 
int threadId = 0;

另外建立一个与dll同名,不同后缀的def文件,如HookDll.def文件,写上: 
LIBRARY HookDll.dll 
EXPORTS 
;... 
SEGMENTS 
SHSEG CLASS 'SHCLASS' SHARED 
;end

这样设置后在.cpp文件中定义的变量,如果进行了初始化,将进入“SHCLASS”共享内存段(如果不初始化,将不改变其默认段属性)。 
 
上述的共享对于本示例代码并不是必须的,只是稍微演示了一下。

2、 api hook修改api函数入口点地址的时机 
很显然,我们必须通过hook进入目标进程的地址空间后,再在位于该地址空间里的hook消息处理过程里修改输入符号表“指向”的api函数入口点地址, 退出hook前也必须在这个消息处理过程里恢复原来的地址。只要我们牢记修改的过程发生在目标进程的地址空间中,就不会发生访问违例的错误了。 
示例代码使用了WH_GETMESSAGE、WH_CALLWNDPROC两中hook来演示如何hook api,但WH_GETMESSAGE实际上并没有完成具体的功能。 
为了让初学者尽快的掌握重点,我将代码进行了简化,是一个不健壮、不灵活的演示示例。

3、 函数的内外部表现形式 
例如api函数MessageBox,这个形式是我们通常用到的,但到了dll里,它的名字很可能出现了两个形式,一个是MessageBoxA,另一个 是MessageBoxW,这是因为系统需要适应Ansi和Unicode编码的两种形式,我们不在函数尾端添加“A”或“W”,是不能hook到需要的 函数的。

4、 辅助pe格式查看工具 
PE Explorer是一个非常好的查看pe资源的工具,通过它可以验证自己手工计算的pe地址,可以更快的掌握pe格式。 
调试器ollydbg也是非常好的辅助工具,例如查看输入符号表中的api函数。

5、 程序文件列表 
dll基本文件:Hook.h,Hook.cpp,HookDll.def 
client验证方基本文件:HookTest.h,HookTest.cpp,ApiHookTest.cpp 
 

6、 实现的功能 
对记事本的MessageBoxW函数进行了hook,先执行自定义的 
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR M1, LPCWSTR M2, UINT M3) 

return oldMessageBoxW(hWnd, M1, L"my api hook", M3); 

从这里可以看到,由于目标进程空间中的执行线程并不知道你已经改变了api函数的实际入口地址,它在调用时仍旧将参数一成不变的压入堆栈(这个说法是汇编代码时看到的等价情形),事实上你已经提前接收到了函数调用的所有参数。这里就是篇首帖子的回复了。

 
hook之前

 
hook以后

示例代码 
1、client验证方的代码非常简单。建立一个Application工程,在窗体上放一个memo(提示信息),两个button(一个SetHook,另一个RemoveHook)。 
void __fastcall TForm1::Button1Click(TObject *Sender) 

DWORD dwProcessId, dwThreadID;

HWND hWnd = FindWindow("Notepad", NULL); 
if (!hWnd) 

Memo1->Lines->Add("Nodepad is not found"); 

else 

dwThreadID = GetWindowThreadProcessId(hWnd, &dwProcessId); 
Memo1->Lines->Add(dwThreadID); 
SetHook(dwThreadID); 


//--------------------------------------------------------------------------- 
void __fastcall TForm1::Button2Click(TObject *Sender) 

RemoveHook(); 

//---------------------------------------------------------------------------

2、api hook dll稍微复杂些,建立一个dll工程之后,修改之。代码中有一些函数并未用上,ReplaceApiAddress是核心函数,完整代码参见附件。
参考文献 
1、《iczelion汇编程序设计教程》pe专题部分 
2、《WINDOWS核心编程》第22章 
3、《PE文件格式 1.9版》汉译版,原著B. Luevelsmeyer 
4、《跨进程API Hook》,出自http://blog.csdn.net/detrox/archive/2004/01/29/17511.aspx,作者detrox 
5、《DLL木马注入程序》,出自http://www.mydown.com/code/245/245731.html 
6、另有两vc6下的源代码包,APIHOOK与pw,因时间久远,出处不明。在此对原作者的辛勤工作表示真挚的谢意。

http://blog.csdn.net/hack_wg/article/details/4568419

API Hook基本原理和实现的更多相关文章

  1. 转 BHO API HOOK Wininet基于IE编程的一些资料

      BHO原理:推荐vc base中的文章: 如何使用BHO定制你的Internet Explorer浏览器 API HOOK的基本原理:推荐C++ builder 研究中的文章: API Hook基 ...

  2. API HOOK技术

    API HOOK技术是一种用于改变API执行结果的技术,Microsoft 自身也在Windows操作系统里面使用了这个技术,如Windows兼容模式等. API HOOK 技术并不是计算机病毒专有技 ...

  3. API Hook完全手册

    文章来源: http://blog.csdn.net/atfield 原文作者: ATField 整理日期: 2008-07-16 发表评论 字体大小: 小 中 大   注:本文是根据我两年前写的一个 ...

  4. 10分钟API Hook MessageBox

    10分钟API Hook MessageBox 分类: C++2012-04-12 22:52 877人阅读 评论(4) 收藏 举报 hookwinapidllthreadpython编程 转载注明出 ...

  5. 程序破解之 API HOOK技术 z

    API HOOK,就是截获API调用的技术,在程序对一个API调用之前先执行你的函数,然后根据你的需要可以执行缺省的API调用或者进行其他处理,假设如果想截获一个进程对网络的访问,一般是几个socke ...

  6. API HOOK

    API HOOK技术是一种用于改变API执行结果的技术,Microsoft 自身也在Windows操作系统里面使用了这个技术,如Windows兼容模式等. API HOOK 技术并不是计算机病毒专有技 ...

  7. API HOOK库

    API HOOK库 API HOOK有两种做法,一种是SetWindowHookEx,简单易用,但如果做其它的HOOK,如HOOK OpenProcess,就需要修改内存地址了,内存地址可以通过Wri ...

  8. 我的API HOOK库

    API HOOK有两种做法,一种是SetWindowHookEx,简单易用,但如果做其它的HOOK,如HOOK OpenProcess,就需要修改内存地址了,内存地址可以通过WriteProcessM ...

  9. API HOOK和PE文件的关系

    api hook技术的难点,并不在于hook技术,而在于对PE结构的学习和理解.如何修改api函数的入口地址?这就需要学习pe可执行文件(.exe,.dll等)如何被系统映射到进程空间中,这需要学习p ...

随机推荐

  1. js字符串转换为数字的三种方法。(转换函数)(强制类型转换)(利用js变量弱类型转换)

    js字符串转换为数字的三种方法.(转换函数)(强制类型转换)(利用js变量弱类型转换) 一.总结 js字符串转换为数字的三种方法(parseInt("1234blue"))(Num ...

  2. Opencv Surf算子特征提取与最优匹配

    Opencv中Surf算子提取特征,生成特征描述子,匹配特征的流程跟Sift是完全一致的,这里主要介绍一下整个过程中需要使用到的主要的几个Opencv方法. 1. 特征提取 特征提取使用SurfFea ...

  3. EM12C 安装及卸载 注意点整理

    版本号:  em12c 12.1.0.4          OS :  redhat 5.7 x86_64bit (CentOS6.2,測试过,当时因glibc*.i686包安装一直报错.所以放弃了) ...

  4. jQuery Mobile手机网站案例

    jQuery Mobile手机网站案例 一.总结 一句话总结:jQuery Mobile是纯手机框架,和amazeui和bootstrap都可以做手机网站. 1.另一款文本编辑器? jd编辑器 二.j ...

  5. 深度学习框架 —— tflearn 的学习

    1. tflearn.data_utils from tflearn.data_utils import to_categorical one_hot 编码: 第一个参数为属性列,第二个参数接受类别个 ...

  6. ionic新手教程第三课-在项目中使用requirejs分离controller文件和server文件

    继上篇教程中提到的,我们新建一个简单的tabs类型的Ionic项目. 依据文件夹文件我们知道,系统自己主动创建了一个controller文件和server文件,而且把全部的控制器和服务都写到这两个文件 ...

  7. Java NIO(6)----NIO与IO

    当学习了Java NIO和IO的API后,一个问题立即涌入脑海: 我应该何时使用IO.何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们怎样影响您的代 ...

  8. XMPP之ios即时通讯客户端开发-配置XMPP基本信息(四)

    前文已经有配置open fire,接下来要通过XMPP框架链接到open fire的服务器: 1.首先要在系统偏好设置里面打开open fire的服务器 2.代码中设置xmpp的myJID 有几个名词 ...

  9. WIN10+QT5.9+VS2015编译RedisDesktopManager

    原文:WIN10+QT5.9+VS2015编译RedisDesktopManager 官方源码编译安装说明地址:http://docs.redisdesktop.com/en/latest/insta ...

  10. Java网络编程注意事项1

    网络编程的基础知识 什么是计算机网络,就是把分布在不同地理区域的计算机与专门的外部设备通信线路互连成一个规模大.功能强的网络系统. 计算机网络主要能做些下面功能: 1)资源共享 2)信息传输与集中处理 ...