拦截win32 API

原文出处:http://www.codeproject.com/system/hooksys.asp
    拦 截win32 API 调用对于多数windows开发人员来说都一直是很有挑战性的课题,我承认,这也是我感兴趣的一个课题。钩子机制就是用一种底层技 术控制特定代码段的执行,它同时提供了一种直观的方法,很容易就能改变操作系统的行为,而并不需要涉及到代码。这跟一些第三方产品类似。
    许多系统都通过拦截技术(spying techniques)利用现有windows应用程序。而拦截的一个重要目的,并不只是为应用程序提供更高级功能,而是为完成调试。
    与 老式操作系统(如dos,win3.xx)不同,现有操作系统(如WINNT/2K和win9X)使用了成熟的机制来分隔各进程的地址空间。这种架构提供 了真正的内存保护,因此任何应用程序都不能破坏属于其它进程的地址空间,更不可能破坏操作系统本身。这使得开发系统相关的钩子(system- aware hooks)变得十分困难。
    我写这篇文章就是要探讨一种简单实用的钩子机制,它提供了一个简单的接口,用来拦截不同的API 调用。它也示范了一些技巧,可以帮助你开发出自己的api拦截程序(spying system)。同时它还提供了一系列在WIN2K/NT和WIN98 /ME(下面简称9X)等windows上拦截WIN32 API 的方法。为了简化我的描述,我没有引入UNICODE的相关内容。但你只需对代码作一 些微小改动就能支持UNICODE。

拦截应用程序(Spying of applications)有许多好处:
1.监视API函数
    有 助于控制API调用,也让开发人员在API调用期间跟踪到应用程序特定的“不可见”动作。它有助于开发人员全面掌握程序的细节 (comprehensive validation of parameters),也有助于发现潜在问题。例如,有时候,它能便于监视内存管理API 引起的资源泄漏。
2.调试和逆向工程
    除了一般的调试方法,API钩子也是一种值得称道的非常流行的调试方式。许多开发人员用钩子来区分不同组件的执行以及它们之间的关联。因此它也用于获取二进制可执行文件的信息。
3.深入操作系统内部
    通常开发人员都热衷于深入了解操作系统并扮演着“调试者”的角色。钩子机制也是用于解码未公开的或不为人知的API的有力技术。
4.扩展已有功能
    可 以向外部的windows应用程序嵌入自定义模块、增强原有函数的功能,这需要借助钩子来重定向原有代码的执行序列(让系统在执行原有代码过程中执行用户 自定义代码),从而扩展现有模块的功能。例如,许多第三方软件产品并不遵循指定的安全规则而只满足用户特定的使用需求。拦截应用程序允许开发者在原有 API执行之前或之后添加属于用户自己的代码。这有助于改变已经编译好的代码的行为。
对拦截系统的功能需求 
    在实现任何形式的 API拦截系统之前,都必须先做一些慎重考虑。首先,你要决定是开发对单个程序的钩子还是全局钩子。例如,假设你只希望拦截一个程序,就不必安装全局钩子 了;但如果要监视一切对TerminateProcess() 和WriteProcessMemory()的调用,唯一的办法就是使用全局钩子。选用何 种方法都取决于特定的环境和要解决的问题。

API拦截架构的概要设计
    通常拦截系统由至少两部分组成——一个钩子服务器 (Hook Server)和一个驱动(Driver)。钩子服务器用于在合适时机把驱动注入目标进程,它也可以管理驱动,甚至可以通过注入点获取驱动的 工作情况。这样的设计比较粗略,很明显它并未涉及所有可能的实现方式。但这已经能够描述API拦截的框架了。

    如果需要实现特定的钩子架构,应该慎重考虑下面几点:
    a 要拦截什么程序
    b 如何向目标进程注入DLL或者说应用何种注入技术
    c 使用何种拦截机制
    希望读者可以从以下章节找到答案。

注入技术
1.注册表
如果要向加载了USER32.DLL的进程注入DLL,只需向如下注册表键写入DLL的名称:
HKEY_LOCAL_MACHINE/Software/Microsoft/Windows NT/CurrentVersion/Windows/AppInit_DLLs
    上 述表键的值可包含单个或成组用逗号(,)或空格分隔的DLL名称。根据MSDN文档[参考7],所有包含在上述键值内的DLL,都会被任何运行在当前用户 登陆空间(current logon session)的windows应用程序所加载。有趣的是,实际上,这些DLL的加载过程其实是USER32初 始化过程的一部分。USER32读取上述键值并为这些DLL的入口调用LoadLibrary()。但这种方法只适用于那些加载了USER32.DLL的 程序。另外一种限制是,这种内置的机制只适用于windows2k/nt系统。这是一种安全的DLL注入方法,但有以下缺点:
    a. 激活或撤销进程注入必须重启windows
    b. 被注入的DLL只被映射到那些加载了USER32.DLL的进程,所以这种方法至少不能注入控制台程序,因为它们根本不必导入USER32的函数。
    c. 另外一方面,注入方不可能控制注入过程。就是说,DLL被注入了所有GUI程序,不管注入方是否有这样的需求。在只需要拦截少量程序的情况下,这样会显得多余。更多信息请参考[参考2]“利用注册表注入DLL”。

2.全局Windows钩子
    的确,另外一种很流行的DLL注入方法来自windows钩子。MSDN指出这种钩子是系统消息处理机制中添加的陷阱。应用程序可以通过安装钩子来监视系统中的消息流(message traffic),并在消息到达特定窗口过程之前处理它们。
    根 据系统底层要求,这种全局钩子一般在DLL内实现。它的基本原理是,钩子回调过程在被拦截进程的地址空间内被调用。通过调用 SetWindowHookEx()并加入合适的参数来安装一个钩子。一旦这种全局钩子安装好,操作系统就会把DLL映射到目标进程的地址空间。此 时,DLL内的全局变量就变成局限于单个进程(per-process),不能被各目标进程共享。因此,所有需要共享的变量应该被放置在共享数据段。下图 展示了一个例子:钩子服务器注册一个钩子并将其注入到名为“Application one”和“Application two”的进程的地址空间。

图1
 
    每 当SetWindowsHookEx()执行,全局钩子就会被注册一次。一切正确时函数将返回该钩子的句柄。在用户自定义的钩子回调过程末尾调用 CallNextHookEx()时将要用到上述句柄。成功调用SetWindowsHookEx()后,操作系统就会自动把这个DLL注入到符合要求的 所有进程的地址空间,但并不一定是立即注入。下面具体来看过滤WH_GETMESSAGE消息的函数体:
//---------------------------------------------------------------------------
// GetMsgProc
//
// Filter function for the WH_GETMESSAGE - it's just a dummy function
//---------------------------------------------------------------------------
LRESULT CALLBACK GetMsgProc(
 int code,       // hook code
 WPARAM wParam,  // removal option
 LPARAM lParam   // message
 )
...{
 // We must pass the all messages on to CallNextHookEx.
 return ::CallNextHookEx(sg_hGetMsgHook, code, wParam, lParam);
}
     全 局钩子被多个不共享相同地址空间的进程加载。例如,钩子句柄sg_hGetMsgHook会被SetWindowsHookEx()函数获取并作为参数用 于CallNextHookEx(),它必须在各进程的地址空间中使用。就是说,该句柄的值必须被客户进程和拦截服务器共享。因此,钩子句柄应该放置在共 享数据段中。
     以下例子调用了#pragma data_seg()编译预处理语句(使用共享数据段)。在此,我要提醒一下,共享数据段内的变量必须初始化,否则它们将会被放置在默认数据段,同时#pragma data_seg()语句也会失效。
//---------------------------------------------------------------------------
// Shared by all processes variables
//---------------------------------------------------------------------------
#pragma data_seg(".HKT")
HHOOK sg_hGetMsgHook       = NULL;
BOOL sg_bHookInstalled    = FALSE;
// We get this from the application who calls SetWindowsHookEx()'s wrapper
HWND sg_hwndServer        = NULL; 
#pragma data_seg()

同时应该添加SECTIONS语句到DLL的DEF文件,如下所示:
SECTIONS
         .HKT   Read Write Shared
或使用 
#pragma comment(linker, "/section:.HKT, rws")

    一 旦钩子DLL被加载到目标进程的地址空间,要卸载该钩子的话除了拦截服务器调用UnhookWindowHookEx()函数或客户进程退出就没有其他办 法了。当拦截服务器调用UnhookWindowHookEx()函数时,操作系统就会扫描一个列表,这个列表包含了所有加载了钩子dll的进程。这时操 作系统会(根据列表内进程数量)相应递减钩子DLL的锁定计数,当这个计数变为0,DLL就会从对应进程的地址空间删除。
     下面列举了上述方法的一些好处。
     a.这种机制都被WINNT/2K和9X系列的操作系统所支持,后继版本的windows系统也有望支持这种机制。
  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "精通Win32 API编程"是一本讲解Windows操作系统下API编程的书籍。该书的主要内容围绕Win32 API以及如何使用API来开发Windows应用程序展开。 Win32 API是一套应用程序接口,它提供了访问Windows操作系统的功能和资源的一系列函数和服务。精通Win32 API编程的PDF为读者提供了全面而深入的知识和技巧,使他们能够充分利用Win32 API来创建强大、高效、功能丰富的Windows应用程序。 该书的内容包括Win32 API的核心组件、常用编程概念和技术、消息处理、图形界面设计、内存管理、多线程编程、网络编程等。不仅介绍了基础知识,还着重讲解了高级和复杂的编程技术与技巧。 读者通过学习该书可以掌握使用Win32 API进行窗口和控件的创建、消息的处理、内存的管理、图形的绘制,以及文件和网络的操作等重要内容。此外,书中还介绍了调试和优化Windows应用程序的方法,帮助读者解决日常开发过程中遇到的各种问题。 "精通Win32 API编程"的PDF不仅对想要深入了解Windows编程的开发者有很大帮助,也适合计算机科学相关专业的学生学习。通过阅读该书,读者能够提升Windows应用程序开发的技能和水平,实现更高效、更稳定、更灵活的应用程序。 ### 回答2: 精通Win32 API编程是一本覆盖广泛的书籍,它涵盖了使用Win32 API进行Windows操作系统编程的方方面面。该书的主要目标是帮助读者深入理解Win32 API的用法和原理,并掌握在Windows平台上开发应用程序的技巧。 在这本书中,读者将学习如何使用Win32 API来创建窗口、处理窗口消息、绘制图形、处理文件I/O操作、实现多线程等。此外,该书还详细介绍了常见的Win32 API函数和结构体,以及它们的用法和参数。 这本书的特色之一是它深入探讨了Win32 API的内部工作原理。它解释了消息循环、窗口过程、消息处理机制等概念,并提供了大量的代码示例和实践案例,帮助读者更好地理解和应用这些概念。 此外,这本书还介绍了一些高级的Win32 API编程技巧,比如使用API Hooking进行函数的拦截和修改,通过定时器实现定时任务,以及使用消息队列实现进程间通信等。这些技巧可以帮助读者更好地定制和优化Windows应用程序。 总的来说,精通Win32 API编程是一本非常全面和深入的书籍,它适合那些已经具备一定编程基础的读者,并且想要深入学习和掌握Win32 API编程技术的人。通过学习这本书,读者可以充分利用Win32 API的强大功能,开发出高效、功能丰富的Windows应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值