API Hooking是一项实用的Windows的系统编程技术,应用领域十分广泛,在桌面虚拟化技术兴起之前,主要应用于屏幕取词、网络防火墙以及病毒木马等安全领域。但是在桌面虚拟化兴起之后,因为桌面虚拟化架构的原因,需要大量截获同时重定向一些操作,大量采用API Hooking技术实现。
术语“Hooking”是一种控制特定代码段的执行的基础技术。它提供了一种简单的机制,使得不需要源代码就能轻易地改变操作系统的行为。Citrix使用Hooking技术提供易用的接口和拦截各种API,在定制的模块中使用Hooking,将模块加载到现有应用中可以轻松改变和扩展现有功能。因为桌面虚拟化的很多东西Windows并不满足特定的要求,因此Citrix不得不进行调整以满足这些要求。Hooking允许Citrix围绕Windows原始的API,在其处理前或处理后增加其他处理。这种能力对改变已编译代码的行为非常有用。
通常一个Hooking系统至少由两部分组成--HookServer(钩子服务端)和Driver(钩子驱动)。Hook Server负责在适当的时候将Driver注入到目标进程,以便子模块中的代码运行在目标进程的地址空间中。同时它对Driver进行管理,并从中获取Driver的活动信息,而Driver实现真正的拦截,实现Citrix所期望的功能。Hook Server(钩子服务端)为主程序,在Windows中一般为EXE形式;Driver(钩子驱动)为钩子模块,在Windows中一般为DLL形式。下图展示了API Hook的框架:
要实现上述的API Hooking的功能,分别涉及两个关键关键技术的实现:DLL注入技术和API拦截技术。
使用DLL注入技术主要三种实现方式,在这里我们只介绍Citrix采用的技术,别的两种不做介绍,感兴趣可以咨询开发人员或者查看MSDN上的文档。这三种技术分别是:
注册表
全局Windows函数钩子
远程线程技术
Citrix使用注册表的方式实现Citrix API Hooking技术的DLL注入。当准备拦截的目标进程连接了 User32.dll(User32.dll是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息),即使用了User32.dll中的API(一般图形界面的应用程序都符合这个条件),因为Citrix主要实现对Windows桌面GUI的拦截,因此Citrix采用注册表启动的方法注入DLL。
为了注入一个DLL到链接了USER32.DLL的进程,你可以简单地在下面的注册表键中添加DLL的名称作为值:
HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Windows\AppInit_DLLs
它的值应该包含一个单独的DLL的名称或者一组以逗号或者空格分隔的DLLs的名称。MSDN文档指出,该键值指定的DLLs将被每一个基于窗口的(Windows-based)应用程序加载。有趣的是这些DLLs实际上被当作USER32初始化的一部分被加载。USER32读取这些键值,并在它的DllMain中通过调用LoadLibrary()来加载这些DLLs。但这种方法只能用在使用了USER32.DLL的应用程序上。尽管这是一种无害的DLL注入方式,但它依然有如下缺点:
需要重启来激活
你想注入的DLL仅能映射到使用了USER32.DLL的进程。你不能期望它能注入到控制台应用程序,因为它们通常不用从USER32.DLL中导入函数。
AppInit_DLLs 启动项是初始化动态链接库。注册表的系统设置项“AppInit_DLLs”可以为任一个进程调用一个dll列表。早期的进程插入式木马的伎俩,通过修改注册表中的[HKEY_LOCAL_MACHINE/Software/Microsoft/WindowsNT/CurrentVersion/Windows/AppInit_DLLs] 来达到插入进程的目的。缺点是不实时,修改注册表后需要重新启动才能完成进程插入。利用注册表启动,就是让系统执行DllMain来达到启动木马的目的。因为它是kernel调入的,对这个DLL的稳定性有很大要求,稍有错误就会导致系统崩溃,所以这种木马一旦有问题就把我们的系统搞崩溃了。
将一个DLL注入到外部进程的地址空间是监控系统的关键一步。它提供了控制进程的线程活动的很好的机会。但拦截进程的API调用仅仅注入DLL是不够的。
根据钩子应用在哪个层次,有两种API拦截机制——内核层和用户层拦截。为了更好的理解这两种层次,你必须了解Win32子系统API和原生API的关系。内核级的钩子主要是通过一个内核模式的驱动程序来实现,能捕捉到系统活动的任何细节,不在本文的探讨范圈之内。而用户级的钩子则通常是在普通的DLL巾实现整个API的拦截。它们在实现上的主要区别在于内核层钩子的拦截引擎被封装成驱动,而用户层钩子通常使用用户模式的DLL。
本文探讨的是Citrix利用的用户层拦截技术,主要有三种实现方式:
代理DLL
代码重写
通过修改导出地址表拦截
代理DLL就是用一个相同名字、导出符号相同的DLL替换原有的DLL。这种技术可以很容易的通过函数转发器来实现。函数转发器简单来说就是DLL导出段里的一个项,它代表一个函数去调用其他DLL中的函数。实质上代理DLL技术就是木马技术,以前的木马技术就是通过替换正常的DLL来达到目的的,但是现在的Windows操作系统都有了一个技术叫做数字签名技术,一旦操作系统发现被保护的DLL文件被篡改,就会提示你进行修复或着从备份目录拷贝原来的DLL文件覆盖掉被篡改的DLL文件。
对于代码重写技术来说,有好几种方法基于代码重写。其中有一种是通过CALL指令改变函数地址。这种方法有点难,并且容易出错。它的底层思想是跟踪内存中的全部CALL指令,用用户提供的函数地址来替换原来的函数地址。
通过修改导出地址表拦截,这种技术最初由Matt Pietrek提出,接着由JefferyRitcher和John Robbins详细阐述。这种技术的原理依赖于Windows PE文件格式的良好结构。要了解这种方法如何工作,你需要对PE文件格式(COFF的扩展)的一些基础知识很熟悉。
从技术上讲,AppInit_DLLs是位于HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Windows中的注册表值。在安装了操作系统后默认情况下它是空的。当User32.dll初始化时,它读取AppInit_DLLs注册表值和并加载发该值列表所以DLL名称到内存中。
Citrix的应用和桌面虚拟化是一个非常具有创新性的技术,为了将应用程序和桌面拦截发送到远端,Citrix需要许多不同的Hook来实现。其API Hooking主要架构如下图所示:
在XenApp和XenDesktop中安装VDA组件时,会将一个DLL:mfaphook.dll添加到appinit_dlls注册表值中。
事实上,增加了两个钩子DLL:
Mfaphook.dll 注册在32bit :HKLM\SOFTWARE\Wow6432Node\Microsoft\WindowsNT\CurrentVersion\Windows\AppInit_DLLs
Mfaphook64.dll 注册在 64bit:HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs
这两appinit_dlls注册表值确保mfaphook [64].DLL加载到XenApp / XenDesktop机器中。mfaphook [64].DLL从注册表HKLM\SOFTWARE\Citrix\CtxHook\AppInit_Dlls读取Citrix的Hook列表。
如图,我们可以看到上面有一个注册表项appinit_dlls,下面有许多的钩子键值。每个钩子的关键值有一个FilePathName,该值包含要加载的DLL的路径和名称。其中我们看见有一个标志值,这个标志值主要有4个参数:
0x80000000 - 表示所有进程
0x00000000 - 表示禁用这个Hook
0x00000002 - 只针对特定进程 (子进程)
0x00000004 - 只针对远程会话
有时候我们在解决Citrix应用程序的问题时,常常找不到很好的解决办法,如果这个应用程序是在我们Citrix的AppInit_Dlls里面,那么就可以尝试禁用这个Citrix还hook,测试解决问题。
禁用API hooks
禁用API Hook需要在以下注册表位置设置loadappinit_dlls 的值为0(reg_dword)。
HKLM\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Windows\LoadAppInit_DLLs = 0 [REG_DWORD]
禁用Citrix Hooks
禁用特定Citrix hooks需要在以下的注册表位置设置标志值为0(reg_dword),例如禁用多监视器hook:
HKLM\SOFTWARE\Citrix\CtxHook\AppInit_Dlls\MultipleMonitor Hook\Flag = 0 [REG_DWORD]
要禁用所有特定的可执行文件的CitrixHook,需要创建一个逗号分隔的字符串值ExcludedImageNames,例如可执行名称的列表:
HKLM\SOFTWARE\Citrix\CtxHook\ExcludedImageNames= calc.exe,notepad.exe [REG_SZ]
最为典型的问题还是智能卡和打印等等,就比如打印问题来说,如果我们采用的打印解决方案是ThinPrint等第三方云打印解决方案,那么我们就不在需要使用Citrix的默认打印解决方案,为了不至于相互冲突,我们就可以在注册表中禁用掉打印的Citrix Hook,以使得在使用打印时Citrix的hook不用去拦截API和注入Citrix的DLL。
下面的表列出了所有加载到64位进程的钩子。
下面的表列出了所有加载到32位进程的钩子。
下面的表列出了所有加载到64位进程的钩子。
下面的表列出了所有加载到32位进程的钩子。
本文出自 “我拿流年乱了浮生” 博客,请务必保留此出处http://tasnrh.blog.51cto.com/4141731/1764560
原文地址:http://tasnrh.blog.51cto.com/4141731/1764560