windows hook (转)
原文对我的帮助极大,正是因为看了原文,我才学会了HOOK,鉴于原文的排版不是很好,
又没有原工程例子源码下载,因此我决定对其重新整理,文章后面附有我测试时的工程源码下载地址。
注:我测试的环境为Win7+VS2008+MFC
原文出处,好像是这篇: //后来才看到的
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
前言
本文主要介绍了如何实现替换Windows上的API函数,实现Windows API Hook
(当然,对于socket的Hook只是其中的一种特例)。这种Hook API技术被广泛的采用在一些领域中,
如屏幕取词,个人防火墙等。这种API Hook技术并不是很新,但是涉及的领域比较宽广,
要想做好有一定的技术难度。本文是采集了不少达人的以前资料并结合自己的实验得出的心得体会,
在这里进行总结发表,希望能够给广大的读者提供参考,达到抛砖引玉的结果。
-------------------------------------------------------------------------------------------------------------------------------------------------------------
问题
最近和同学讨论如何构建一个Windows上的简单的个人防火墙。后来讨论涉及到了如何让进程关联套接字端口,
替换windows API,屏幕取词等技术。其中主要的问题有:
1) 采用何种机制来截获socket的调用?
一般来说,实现截获socket的方法有很多很多,最基本的,可以写驱动,驱动也有很多种,TDI驱动, NDIS驱动,Mini port驱动…
由于我使用的是Win2000系统,所以截获socket也可以用Windows SPI来进行。另外一种就是Windows API Hook技术。
由于我没什么硬件基础,不会写驱动,所以第一种方法没有考虑,而用SPI相对比较简单。
但是后来觉得Windows API Hook适应面更广,而且觉得自己动手能学到不少东西,
就决定用Windows API Hook来尝试做socket Hook.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2) API Hook的实现方法?
实际上就是对系统函数的替换,当然实现替换的方法大概不下5,6种吧,可以参考《Windows核心编程》第22章。
不过我使用的方法与其不近相同,应该相对比较简单易懂。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
原理
我们知道,系统函数都是以DLL封装起来的,应用程序应用到系统函数时,应首先把该DLL加载到当前的进程空间中,
调用的系统函数的入口地址,,可以通过 GetProcAddress函数进行获取。当系统函数进行调用的时候,
首先把所必要的信息保存下来(包括参数和返回地址,等一些别的信息),然后就跳转到函数的入口地址,继续执行。
其实函数地址,就是系统函数“可执行代码”的开始地址。那么怎么才能让函数首先执行我们的函数呢?
呵呵,应该明白了吧,把开始的那段可执行代码替换为我们自己定制的一小段可执行代码,这样系统函数调用时,
不就按我们的意图乖乖行事了吗?其实,就这么简单。Very very简单。 :P
实际的说,就可以修改系统函数入口的地方,让他调转到我们的函数的入口点就行了。
采用汇编代码就能简单的实现Jmp XXXX, 其中XXXX就是要跳转的相对地址。
我们的做法是:把系统函数的入口地方的内容替换为一条Jmp指令,目的就是跳到我们的函数进行执行。
而Jmp后面要求的是相对偏移,也就是我们的函数入口地址到系统函数入口地址之间的差异,再减去我们这条指令的大小。
用公式表达如下:(1)int nDelta = UserFunAddr – SysFunAddr - (我们定制的这条指令的大小);(2)Jmp nDleta;
为了保持原程序的健壮性,我们的函数里做完必要的处理后,要回调原来的系统函数,然后返回。
所以调用原来系统函数之前必须先把原来修改的系统函数入口地方给恢复,否则,
系统函数地方被我们改成了Jmp XXXX就会又跳到我们的函数里,死循环了。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
那么说一下程序执行的过程。
我们的dll“注射”入被hook的进程 -> 保存系统函数入口处的代码 -> 替换掉进程中的系统函数入口指向我们的函数 -> 当系统函数被
调用,立即跳转到我们的函数 -> 我们函数进行处理 -> 恢复系统函数入口的代码 -> 调用原来的系统函数 -> 再修改系统函数入口指向
温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/64909.html
- 上一篇:C#与USBHID间的通信
- 下一篇:C#中的索引器原理