【问题标题】:Avoid an application to have access to disk operations避免应用程序访问磁盘操作
【发布时间】:2011-03-20 16:11:50
【问题描述】:

假设在我的应用程序中,我允许使用 LoadLibrary WIN32 加载 DLL。由于我不知道该 DLL 的代码,它可能是恶意的。所以我的问题是,有什么方法可以告诉 Windows 对该 DLL 应用一些限制(例如磁盘访问、读取密码或其他潜在的危险数据读/写访问)?

这样,每当 DLL 代码尝试访问磁盘时,就会生成异常或调用的方法返回一些错误。避免使用 javascript 或其他脚本解释代码而不是编译 & 链接 & 高效的代码可能很有用。

是否存在任何我可以使用的类似机制?

ex1: RestrictAccess(GetProcAdress( ... ), size ); // 通过代码访问内存

ex2:thread1.loadLibrary(file); 限制访问(线程 1); // 通过线程访问

等等……

【问题讨论】:

  • 沙盒可以做到这一点,但我不知道它们如何与 Windows 一起工作,我不知道您是否可以将它们用于特定的 DLL 而不是整个进程。也就是说,没有办法阻止应用程序提示输入密码(除非完全阻止它显示窗口)。

标签: winapi dll source-code-protection


【解决方案1】:

没有简单的解决方案,例如您可以调用 API 来限制进程或线程。

IE 在保护模式下(在 Vista 和 Windows 7 上)所做的是将插件加载到低 integrity level 的单独进程中。在低完整性模式下运行的进程对系统资源的访问较少,并且与更高完整性级别的进程更加隔离。您还可以在文件系统对象和注册表项等内容上设置 ACL,以控制低完整性进程是否可以访问它们。这限制了他们可以造成的伤害。这是一种沙盒形式或(取决于您对其定义的严格程度)虚拟化。

要做到这一点需要做很多工作。一个低完整性的过程可能会受到如此限制,以至于它需要帮助才能做很多事情。当 IE 启动保护模式进程时,它会为其提供与主 IE 进程通信的通道。然后,插件可以通过此通道发出请求,以执行诸如更改注册表和写入文件系统之类的操作。 IE 考虑请求,如果确定应该允许,则 IE 进程将代表插件执行此操作。

另一种方法(可用于补充沙盒)是要求使用有效证书对 DLL 进行签名。签名允许您对 DLL 有更多的信任,因为证书标识了责任方。签名还确保没有人篡改 DLL。

另一种方法是挂钩您要限制的所有操作系统 API 调用。对此有libraries,但该技术依赖于一点操作系统黑客,可能会因任何更新而中断。这个想法是用你的一些代码创建一个进程,为你想要限制的每个 API 设置一个钩子,然后加载不受信任的代码并执行它。如果 DLL 调用挂钩 API(例如,CreateFile),您的代码将被调用,它可以决定是返回错误还是将调用传递给真正的 OS API。这很困难,因为您必须挂钩的 API 数量可能很大。此外,如果 DLL 知道这是正在使用的技术,它可以做一些事情来颠覆它。

最后,您可以通过完全不运行本机代码来实现真正的沙盒。您无需加载不受信任的 DLL,而是加载已编译为某种中间形式的代码并对其进行解释。这使您的解释器可以完全控制程序可以做什么。这也很难实现,并且会大大降低性能。

如果您要运行不受信任的代码,这些是您必须经历的极端情况。

【讨论】:

  • 不要依赖钩子。任何可以从用户模式挂钩的东西都可以从用户模式绕过,方法是包含挂钩函数的副本。
【解决方案2】:

典型的解决方案是只允许使用可以被沙盒化的解释语言或编译字节码的插件(例如 Lua)。一些操作系统有这样的限制(例如 iOS 和 Android),但我不相信在加载原生 Windows DLL 时你会发现这样的功能。

【讨论】:

  • 从某种意义上说,每个 Windows 进程都是一个沙盒。如果没有强制访问控制检查的内核服务的帮助,它无法控制自己进程之外的任何内容。 (我本来想说,没有内核帮助就无法在进程外进行通信,但后来我记得这不是真的——共享资源(如 CPU 缓存)为进程创建了一个通道,以相互影响彼此的时间,理论上这可能是用于交流)
【解决方案3】:

可以使用模拟在每个线程的基础上增加权限,但不能减少(因为不受信任的代码总是可以做到RevertToSelf)。

较低权限的最小单位是进程。是的,有一个 API:CreateProcessAsUser。您可以使用管道向/从不受信任的进程传输数据。

或者您可以使用 DCOM 调用 DLL 中对象的方法。您可以指定凭据,然后操作系统将使用这些凭据设置帮助程序进程并来回封送数据。

【讨论】:

  • 从来没有听说过,我现在读了一点...所以顺序必须类似于... process = Start process app() codeDLL = loadDLL() thread = createThread(); // 处于挂起模式 SetThreadToken(thread, token); // 具有较低权限的令牌 process.revertToSelf(); // 文档说在模拟后执行 startThread(thread, codeDLL); // 线程开始以类似的低权限执行 DLL 代码?
  • @Tonatiuh:SetThreadToken 的问题是,正如我所提到的,恶意代码可以执行RevertToSelf 并越狱。您需要一个单独的过程来防止这种情况发生。
  • 我已经删除了当前线程的所有权限 result = AdjustTokenPrivileges( hToken, TRUE, NULL, 0, NULL, NULL ); (结果== 1)但它仍然允许我创建一个文件......我做错了什么?没有避免磁盘修改的TokenPrivilegies?
  • @Tonatiuh:你没听我的。你不能希望限制一个线程,它可以随意取消限制。不,文件创建不是“特权”,它取决于在创建文件的目录上设置的访问控制列表。
  • 我在听,只是想学习,我发现了疑问。顺便说一句,在我所做的主要问题中,我要求限制磁盘访问。在您的回答中,您提出了有关特权的建议,现在您说文件创建不是特权,因此,如果我使用线程甚至使用单独的进程来执行此操作,我将如何使其工作?
【解决方案4】:

您可以从 DLL 文件中读取名称。通过这种方式,您可以确定它链接到的其他 DLL 以及它使用的外部函数(例如 Windows API)。您可以创建一个白名单,只允许从该 DLL 调用您的函数,这样您就必须为插件可以合法访问的所有内容创建包装函数。

【讨论】:

  • 不,DLL 仍然可以使用LoadLibraryGetProcAddress 来调用不在其导入表中的函数。或者它可以使用sysenter 指令来访问操作系统服务,而无需其他库的帮助。
  • @Ben 我特别提到了whitelist,你回答了两个 Windows API 调用:LoadLibraryGetProcAddress,你认为 OP 为什么会将这些列入白名单?跨度>
  • @vbence:是什么阻止了他们对这两个 API 的函数指针进行硬编码,因此它们不会出现在导入表中?
  • @Ben 我承认我有一点白点,但如果这些是固定的地址,我会感到惊讶。即使Kernel32.dll 显然是在程序之前加载的,你也无法知道哪个段包含它等等。但话又说回来,我可能是错的。
  • @vbence: kernel32.dll 总是加载到每个进程中,并且同一台计算机上的所有进程都使用相同的基地址。但是,它可以在重新启动时随机化,因此硬编码地址不起作用。尽管如此,如何找到这些函数是众所周知的。 google.com/search?q=shellcode+kernel32+base+address
猜你喜欢
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 2011-06-17
  • 1970-01-01
  • 2014-01-07
  • 1970-01-01
  • 2017-05-30
  • 2010-10-20
相关资源
最近更新 更多