说到HOOK,我看了很多的资料和教程,无奈就是学不会HOOK,不懂是我的理解能力差,还是你们说的
不够明白,直到我看了以下这篇文章,终于学会了HOOK:
http://blog.sina.com.cn/s/blog_628821950100xmuc.html //感谢文章作者的分享,让我学会了HOOK
文章出处,好像是这篇:http://blog.csdn.net/glliuxueke/article/details/2702608 //后来才看到
----------------------------------------------------------------------------------------------------------------------------------------------
既然窝已经入门了HOOK,窝会写几篇关于HOOK的文章,让同样想入门HOOK,却难以入门的童鞋
有个参考,这篇是第一篇,希望帮助到有此需要的盆友,我测试的环境都是:Win7+VS2008+MFC
--------------------------------------------------------------------------------------------------------------------------------------------------
第一篇说的是HOOK自己程序的MessageBoxW,诚然HOOK自己程序用到的API在实际应用中没有什么
大的用处,不过我认为对于我们理解HOOK却有莫大的帮助,因此我的HOOK文章就从HOOK自己的程序
开始,文章后面附有本例子程序的VS2008源码下载地址。
---------------------------------------------------------------------------------------------------------------------------------------------------
//先看下我写的例子程序及运行效果截图,后面再对其进行分析
//未钩MessageBoxW前
//钩MessageBoxW后
---------------------------------------------------------------------------------------------------------------------
根据我的理解,先说一下HOOK API的一般思路和步骤。
HOOK API的思路就是修改原API的入口,使其跳转到我们的假API入口,
然后执行我们的假API函数,为什么说是假API函数呢?
因为我们的假API,除了函数名称和真实API的名称不一样之外,其它都是相同的,即
它们的函数参数和返回值和调用形式都是一样的。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
HOOK API的一般步骤:
1.定义假API函数
注意假API函数,除了函数名称和真实API不一样之外,其它的都要跟真实API的定义相同,如参数类型和返回值、调用形式等。
如我们可以这样定义假的MessageBoxW:
至于我们如何知道真实API的原型定义呢?很简单,查看MSDN即可,或者你也可以在VS2008开发环境中,
写下该真实API,然后选中该API,再点鼠标右键,选择【转到定义】,就可以看到其原型声明了。
...........................................................................................................................................................................
2.定义API函数类型
因为我们要动态获取原API函数的地址,获取到后,我们要将其保存起来,保存在哪里呢?
这就是定义API函数类型的原因了,有了API函数类型的定义后,我们就可以用其定义一个变量来 保存获取到的
真实API函数的地址了,例如,我定义的MessageBoxW函数类型的语句如下:
上面就是定义了API函数类型MsgBoxW,这跟我们常见的int、char、float等类型,用法是一样的,
实际上,我们完全可以把MsgBoxW当成int类型来使用,这样一说,API函数类型也不过如此嘛。
有了API函数类型MsgBoxW,我们就可以用其来定义变量,从而为保存原API地址做准备了。
如:
远指针的信息,我现在也不是很清楚,有兴趣的盆友,不妨百度一下。系统已经给我们定义好了
远指针类型:FARPROC,我们直接拿来用即可,如:
..................................................................................................................................................................................................................
3.获取API函数入口有了保存原API函数地址的变量OldMsgBox和指向原API函数的远指针,我们就可以获取真实API的地址了。
如:
注意,上面我们将原API地址OldMsgBoxW强制转换成了远指针pfOldMsgBoxW,至于为什么要强制转换,
我现在也不是很清楚,想知道的童鞋,可以百度一下。
................................................................................................................................................................................................................
4.保存原API入口的前5个字节
保存的目的是为了恢复用的,毕竟我们HOOK了API后,还需要调用真实的API嘛,
如何保存一个函数入口的前5个字节呢?这里用到了汇编代码,至于不用汇编可以吗?我想是可以的。
有空时,我再试一下,不用汇编是否能保存一个API入口的前5个字节,这里就先用别人写的汇编代码吧,
代码如下:
5.获取新入口的前5个字节
因为我们修改真实API入口的前5个字节,使其跳转到我们假API函数的入口地址,即改成Jmp xxxxxxxx,其中xxxxxxxx就是我们
假API的入口地址,那么我们如何得到该地址呢?
前人已经总结出了一条公式:
int nAddr= UserFunAddr – SysFunAddr - (我们定制的这条指令的大小);
Jmp nAddr; //我们要获取的就是nAddr的值
既然已经有了公式,我们拿来用即可,UserFunAddr相当于我们的假API,SysFunAddr相当于真实API,这里指令的大小为5,
实现以上公式的汇编代码如下:
6.修改真实API入口的前5个字节
前面我们已经保存了真实API入口的前5个字节,也已经计算出了新入口的前5个字节,
可谓万事俱备,只欠东风,现在可以修改真实API入口的前5个字节了。
代码如下:
注:hProcess是进程句柄,我们可以这样获取它:
DWORD dwPid=::GetCurrentProcessId();
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);
..........................................................................................................................................................................................................
有修改,就有恢复嘛,恢复函数代码如下:
注:hProcess是进程句柄,我们可以这样获取它:
DWORD dwPid=::GetCurrentProcessId();
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);
希望有助于你们的理解。
源码下载地址:Hook自己程序的MessageBoxW.zip
学会了HOOK自己的程序,下篇我们再接再厉,HOOK系统所有程序的MessageBoxA和MessageBoxW
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面贴一下以上这个程序的主要代码,算是有个整体印象吧: