65.9K
CodeProject 正在变化。 阅读更多。
Home

如何制作自己的沙箱:虚拟化技术简介

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (9投票s)

2015年4月12日

CPOL

7分钟阅读

viewsIcon

34182

Windows 虚拟化入门

引言

如果您曾经编写过大型系统软件,您可能会用到某种虚拟机——可能是 VMWare、Virtual PC 或其他任何工具。您是否曾经想过这些机器是如何工作的?我一直对这些神奇的技术着迷了很长时间。它们在我看来就像是魔法。而揭开魔法、理解细节的最佳方法就是从零开始编写一个虚拟化解决方案。现在,我有了自己的虚拟化解决方案——一个沙箱工具。这是一项艰巨的任务。在编写这样的产品时,您需要回答很多问题,而且对于大多数这些问题,网上几乎找不到现成的答案。因此,我想与大家分享我的经验。这将是一系列关于虚拟化的文章。

背景

开发虚拟机——不是一项新手程序员的任务,所以我假设您有 Windows 编程经验,特别是掌握了以下技能:擅长 C/C++ 编程,有 Win32 API 编程经验,阅读过一些关于 Windows Internals 的书籍,例如 Mark Russionovich 的著作,具备一些基础的汇编知识。如果您为 Windows 编写过内核模式驱动程序,那将是一个巨大的优势,但尽管沙箱解决方案需要一些内核模式代码,我假设您在这方面经验很少或没有。我将在本教程中详细讲解驱动程序开发的主题。

虚拟机和沙箱工具——区别

虚拟机可以分为两大类——“硬核”虚拟机,它完全模拟硬件,例如 VMWare;以及轻量级虚拟机,它则模拟关键的操作系统操作,例如文件系统操作、注册表操作以及其他一些操作系统原语,例如互斥量。这类轻量级虚拟机的一些例子包括 Featherweight Virtual Machine、Sandboxie 和 Cybergenic Shade。Featherweight Virtual Machine 是一个开源项目,但它有一些缺点,例如它拦截内核模式调用的方式。它使用了钩子技术,这意味着它修改了操作系统内核代码——这在 Vista 及以后的 x64 操作系统上是被禁止的。这种补丁会导致 Patch Guard,一种特殊的操作系统组件,使操作系统蓝屏,因为微软现在认为这些补丁是恶意的。因此,FVM 可以作为一个很好的起点来了解虚拟化,但与现代操作系统不完全兼容。大多数挑战出现在保持与 Patch Guard 的兼容性上,我们将在后面的文章中详细探讨。许多程序员发明了绕过 Patch Guard 的技术,但实际上,这种绕过会削弱操作系统,使其更容易受到那些原本无法在打了 Patch Guard 的操作系统上运行的旧式内核模式感染的攻击。所以我们的目标是保持与 Patch Guard 的兼容性,而不是禁用或绕过它。我们的沙箱应该为操作系统增加一些保护,使其更能抵御恶意软件攻击,因此,从另一方面来说,禁用或绕过 Patch Guard 会削弱它,这是犯罪。在本教程中,我们将专注于开发一个轻量级虚拟化解决方案。主要思想是拦截操作系统对关键系统操作的请求,并将它们重定向到某种虚拟存储,例如,对于文件系统操作,重定向到一个专用文件夹。例如,某个我们想要模拟的应用程序想要修改名为 C:\Myfile 的文件。我们必须在虚拟文件夹中复制这个文件,例如 C:\Sandbox\C\Myfile,并将应用程序对 C:\Myfile 执行的所有操作重定向到其虚拟“同胞” C:\Sandbox\C\Myfile。对于注册表操作和其他一些系统机制,也执行相同的操作。

什么应该被虚拟化以及如何虚拟化?

让我们总结一下虚拟化操作到底意味着什么。让我们从文件系统虚拟化开始。正如您应该已经知道的,当应用程序想要访问文件时,它首先打开它。从 Windows 的角度来看,它调用 CreateFile() 这样的 API。如果调用成功,它就可以读取和写入文件。完成工作后,文件需要用 CloseHandle() API 关闭。因此,我们可以拦截 CreateFile(),修改其参数,例如程序想要打开的文件名。这样做,我们可以强制应用程序打开另一个文件。但是,出于几个原因,精确地拦截 CreateFile() 是一个坏主意:首先,应用程序还有其他方法可以打开文件。例如,它可以调用 NtCreateFile(),一个原生 API,实际上 CreateFile() 调用的是它。因此,如果我们拦截 NtCreateFile(),我们也将拦截上面的 CreateFile(),因为它最终会调用 NtCreateFile(),而 NtCreateFile() 又会调用我们。但 NtCreateFile() 也不是最底层的。那么,所有希望打开/创建文件的应用程序都会调用的“最低层”的 CreateFile() 等效调用在哪里?它在内核模式代码中。所有文件系统操作都由文件系统驱动程序驱动。Windows 支持所谓的文件系统过滤器,更具体地说,是迷你过滤器,它们用于过滤文件系统操作。因此,通过编写一个迷你过滤器驱动程序,我们可以拦截所有我们需要的文件系统操作。所以我们的第一个目标——通过编写迷你过滤器驱动程序,从内核模式拦截文件系统操作。这样做,我们可以强制操作系统打开一个完全不同的文件,在我们的例子中,它将是一个同胞文件,是原始文件的副本。但是,细心的读者可能会注意到,复制是一项非常消耗资源的操作,所以我们应该应用一些优化。首先,我们可以检查文件是仅用于 ReadOnly 访问还是可以修改。如果是前者,则无需复制。由于文件不会被修改,可以访问原始文件。但是,如果文件有修改,因为应用程序被虚拟化了,可能会产生一个沙箱副本作为修改的结果。所以,总的来说,我们应该首先检查沙箱同胞文件是否存在。如果存在,则应提供对它的访问。只有在没有虚拟同胞的情况下,我们才可以禁用对该特定创建/打开请求的虚拟化,从而允许访问原始文件。

正如您所见,我们不需要拦截读取或写入请求——只需拦截 CreateFile() OpenFile())的内核模式等效调用,就可以将所有文件工作重定向到我们的虚拟模式文件夹,这已经足够了。但是,虚拟化文件系统还不够。我们还应该虚拟化注册表和其他一些操作系统原语。但现在,让我们只关注文件系统虚拟化。

在我的下一篇文章中,我们将简要讨论文件系统架构,介绍内核模式驱动程序及其分类,并查看迷你过滤器驱动程序的示例。
现在,我建议您尝试一下市面上已有的沙箱工具。Featherweight Virtual Machine 是一个很好的例子,值得一看,尤其是它的源代码和架构。尽管它有严重的缺点,使其与 Patch Guard 不兼容,但对于想要了解沙箱工作原理的人来说,它是一个很好的起点。正如我之前所说,我们将走一条稍微不同的道路,并着眼于一个与 Patch Guard 兼容的解决方案。特别是,我们将研究 Cybergenic Shade,这是我和我的团队编写的一个解决方案。在讨论开发沙箱解决方案的关键主题时,我们将深入研究它的源代码。

© . All rights reserved.