为 Windows 设计沙盒

信息安全 视窗 操作系统 虚拟化 沙盒
2021-09-02 05:54:36

我正在考虑设计一个沙盒,它能够执行任意未修改、不受信任的二进制文件。目标是实现一个应用程序

不像 Google Chrome 的沙箱之类的东西,它必须提供额外的隔离,这是 Windows 中的安全机制无法提供的。但是,它还应该能够在一台物理机器上运行大量沙箱,因此完全成熟的 VM 是不可能的。

它应该是这样工作的:不受信任的代码进行的任何系统调用都应该首先被沙箱代码拦截,以便在传递给系统之前可以阻止或修改它。如果方便的话,沙盒还应该能够挂钩高级 API。不受信任的代码不应该能够与沙箱代码(包括它的导入库)和数据(它的堆栈和堆)进行调和。但是,沙盒代码应该可以完全访问沙盒代码的地址空间。

考虑到这些限制,如果沙盒包含尽可能少的内核模式代码(因为安全性和可测试性问题),它会尽可能简单(因此没有像二进制翻译这样的特技)并且沙盒代码将合理运行快速地。

沙盒将在我自己的服务器上运行,因此可以接受底层操作系统的调整,并且不同版本的 Windows 之间的可移植性不是硬性要求。目标架构是 x86 - 64 位支持并不重要,因此允许使用分段。但是,它应该能够在 VM 中运行;所以如果可能的话,没有硬件虚拟化(VT-x 或它的 AMD 等价物)。

你将如何实现这样的沙箱?有这样的沙盒设计记录在案吗?有没有我忽略的重要点?鉴于这些要求,您可能已经有了一个合理的想法,我想到了什么样的设计,但是我对任何想法都持开放态度。

编辑:目标是提供一个应用程序虚拟化层(参见http://en.wikipedia.org/wiki/Application_virtualization),虚拟化应用程序无法脱离该层。

3个回答

我同意建议确定什么是和不是一个好的系统调用的整体设计的答案可能很困难。事实上,单独来看,单个系统调用可能没有足够的信息。

就 Windows 的工作方式而言,实际上有两个级别的操作:

  • NT 级调用。这些是您期望通过在内核模式例程sysenter中编码的典型系统调用。ntdll.dll
  • Win32 子系统级别。这些是在 、 和其他中实现advapi32.dllkernel32.dll功能user32.dll其中一些直接起作用,其他可能会根据需要自行调用上述函数。

除此之外,作为一项广泛的调查,在 Win32 子系统之上还有两个抽象层:

  • COM和朋友,也称为COM、COM+、DCOM、ActiveX、SuperDuper(好吧,开玩笑的)等。
  • .Net 和朋友。.net 可执行文件是经过修改的 PE 二进制文件,可以加载mscoree.dll其他内容,并且可以使用其他 .net 二进制文件或 Win32 中的 API,或通过 COM 接口。

现在,对于挂钩技术,您有:

  • 核心。如今,ISR Hooking 无异于稳定性自杀,除非您想对 PatchGuard 进行逆向工程并禁用它,或者在调试器下永久运行您的操作系统。但是,过滤器驱动程序提供了在 Windows 中实现的过滤选项。这通常是防病毒产品扫描网络活动并实施防火墙的方式。
  • 用户。你有几个选择:
    • 在启动时修补二进制文件。@Poly 谈到了代码洞穴和重定向——给定一个目标二进制文件,一种选择是覆盖其函数中的代码,或者重写有趣 API 的函数以重定向到您的代码。通常,您没有足够的空间来修补跳转到地址空间中的任何旧位置,因此您需要在函数附近有一个“代码洞穴”来放置您的调用/全尺寸跳转。
    • 对此的替代方案包括 IAT Hooking,这是一种修改二进制文件的导入表以拉入您的函数而不是原始目标的方法。
    • 另一种选择是使用 DLL 重定向。在 Linux 下,您会知道这是LD_PRELOAD, - 在简单的英语中,您会在所需的 API dll 之前加载具有相同名称和匹配符号的 DLL,并以这种方式窃取调用。它甚至是 MSVC 的一个功能,您可以在 DLL 中生成重定向链接函数,而不必为您不关心的事情实现自己的存根!
    • 您可以通过覆盖结果接口类的 vtable 中的相关条目来修补 COM 调用。
    • 还有其他技术,例如 DLL 注入等。

因此,如果您希望实现符合您的标准的沙箱,则需要考虑以下几点:

  • 首先,你在哪里和什么挂钩。如果您将所有这些都挂钩,kernel32.dll那么如果 API 调用不调用这些函数,它们仍然是可行的。我不知道任何这样的 COM 或 .net 代码,但我敢打赌有一些。
  • 由于 PatchGuard,您需要小心内核修补。过滤器管理器提供了您想要做的大部分防病毒(因此可能是沙箱)明智的事情,但是,如果您离开过滤器管理器,您很快就会进入不稳定的领域。您可以做的事情可能会受到限制。
  • 然后,假设您不使用二进制翻译,沙箱几乎可以肯定地检测到您在用户空间中放置的任何钩子。例如,让我们选择 patching CreateFile不受信任的代码可以简单地读取此函数的内存并检查序言是否符合预期。同样,有一些方法可以检测注入的 dll、IAT 挂钩等。
  • 这同样适用于沙盒内核模式代码。如果您让不受信任的代码安装驱动程序,那么您将再次处于与它的公平竞争环境中。

这种工作已经完成——Sandboxie 是一种尝试在这种级别实现沙箱的产品,尽管它可能具有比您想要的更多的内核级别的东西。当我对这类事情知之甚少时,我只是简要回顾了 Sandboxie,但我怀疑核心组件是内核级别的,因为如果您知道预期它几乎可以撤消任何数量的用户模式挂钩。唯一的防御是拥有更高级别的权限。

您已经提到没有二进制翻译——出于这个原因,我没有介绍 Windows 中的各种调试 API。使用这些,您基本上可以像单步执行程序一样运行程序,并在进行任何调用或跳转之前对其进行分析。但是,这基本上是二进制翻译,调试无论如何都会影响性能。不仅如此,如果我正在编写一个程序来抵抗你的沙箱,还有许多已知的检测调试器的技巧(一个是你不能调试调试器,所以如果你重新启动自己并尝试调试那个新进程和不能,您正在调试。这绝对适用于ptrace),这会使程序在沙箱中无法使用。

积极的一面是,大多数非恶意软件产品很可能与您使用的任何一种技术配合得很好,因为它们可能不会试图抵制在这些环境下运行。这可能是一个非常有用的事实。

最后但并非最不重要的一点是,我为过度使用要点表示歉意!而且,我列出的挂接电话的技术清单并不详尽——肯定还有其他技术。

我刚刚找到了 Featherweight Virtual Machine,这是一个开源的 windows 沙箱实现:

http://static.usenix.org/events/vee06/full_papers/p24-yu.pdf

http://sourceforge.net/projects/fvm-rni/

沙丘也很有趣:

http://dune.scs.stanford.edu/

它实现了一个概念验证沙箱,就像我在 linux 下使用 VT-x 描述的那样(不幸的是,这意味着它不能在大多数虚拟机下工作)。

您的计划是基于一个有缺陷的假设,即您可以通过某种系统调用筛选来识别“不良”行为。你不能。Windows 充满了错误、隐藏的功能和未公开的依赖项。一旦您将控制权交给您未提供的其他代码,您绝对不能保证它只会执行您认可的事情。