API Hooking是一项实用的Windows的系统编程技术,应用领域十分广泛,在桌面虚拟化技术兴起之前,主要应用于屏幕取词、网络防火墙以及病毒***等安全领域。但是在桌面虚拟化兴起之后,因为桌面虚拟化架构的原因,需要大量截获同时重定向一些操作,大量采用API Hooking技术实现。

一、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的框架:

wKioL1cSIkny4VZkAACN8b5YULk743.jpg

要实现上述的API Hooking的功能,分别涉及两个关键关键技术的实现:DLL注入技术和API拦截技术。

1.1DLL注入技术

使用DLL注入技术主要三种实现方式,在这里我们只介绍Citrix采用的技术,别的两种不做介绍,感兴趣可以咨询开发人员或者查看MSDN上的文档。这三种技术分别是:

  • 注册表

  • 全局Windows函数钩子

  • 远程线程技术

Citrix使用注册表的方式实现Citrix API Hooking技术的DLL注入。当准备拦截的目标进程连接了 User32.dll(User32.dllWindows用户界面相关应用程序接口,用于包括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的稳定性有很大要求,稍有错误就会导致系统崩溃,所以这种***一旦有问题就把我们的系统搞崩溃了。

 

1.2API拦截技术

将一个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提出,接着由JefferyRitcherJohn Robbins详细阐述。这种技术的原理依赖于Windows PE文件格式的良好结构。要了解这种方法如何工作,你需要对PE文件格式(COFF的扩展)的一些基础知识很熟悉。

 

二、Citrix API Hooking

从技术上讲,AppInit_DLLs是位于HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Windows中的注册表值。在安装了操作系统后默认情况下它是空的。当User32.dll初始化时,它读取AppInit_DLLs注册表值和并加载发该值列表所以DLL名称到内存中。

2.1Citrix API Hooking框架

Citrix的应用和桌面虚拟化是一个非常具有创新性的技术,为了将应用程序和桌面拦截发送到远端,Citrix需要许多不同的Hook来实现。其API Hooking主要架构如下图所示:

wKiom1cSIduz3_A9AAAiW7motoI735.png

XenAppXenDesktop中安装VDA组件时,会将一个DLL:mfaphook.dll添加到appinit_dlls注册表值中。

wKiom1cSIejCTVHkAACBvckHE9c370.png

事实上,增加了两个钩子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读取CitrixHook列表。

wKioL1cSIrvQW7ZgAABe_VbJHa0166.png

如图,我们可以看到上面有一个注册表项appinit_dlls,下面有许多的钩子键值。每个钩子的关键值有一个FilePathName,该值包含要加载的DLL的路径和名称。其中我们看见有一个标志值,这个标志值主要有4个参数:

  • 0x80000000     -     表示所有进程

  • 0x00000000       -    表示禁用这个Hook

  • 0x00000002       -     只针对特定进程 (子进程)

  • 0x00000004       -     只针对远程会话

  • 2.2、禁用API Hooking测试问题

有时候我们在解决Citrix应用程序的问题时,常常找不到很好的解决办法,如果这个应用程序是在我们CitrixAppInit_Dlls里面,那么就可以尝试禁用这个Citrixhook,测试解决问题。

  • 禁用API hooks

禁用API Hook需要在以下注册表位置设置loadappinit_dlls 的值为0reg_dword)。

HKLM\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Windows\LoadAppInit_DLLs = 0 [REG_DWORD]

  • 禁用Citrix Hooks

禁用特定Citrix hooks需要在以下的注册表位置设置标志值为0reg_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,以使得在使用打印时Citrixhook不用去拦截API和注入CitrixDLL

三、所有Citrix Hooks列表

3.1XenApp 7.x:64Hooks

下面的表列出了所有加载到64位进程的钩子。

wKiom1cSIlTziVxiAAB1MaKFeDQ805.png

wKioL1cSIxjRQAXMAAAWqzxd5WE643.png

 

3.2XenApp 7.x: 32Hooks

下面的表列出了所有加载到32位进程的钩子。

wKioL1cSI3ODcVNBAABkrazRPq0688.png

wKiom1cSIsbzmfU-AAAytph-q7s931.png

 

3.3XenDesktop 7.x:64Hooks

下面的表列出了所有加载到64位进程的钩子。

wKioL1cSI8bA6sI-AABt-8jS2aQ635.png

wKiom1cSIxfQ1HP6AAA15IJSNms823.png

wKiom1cSIyLT-iqbAAA87YRc4Z4784.png

 

3.4XenDesktop 7.x:32Hooks

下面的表列出了所有加载到32位进程的钩子。

wKioL1cSJBvwpaHgAABZEzMZvjg951.png

wKioL1cSJCqz52y-AABXnDTm658695.png

wKiom1cSI3mRfkeNAABGgjAYMwI380.png