为什么在内核模式下调用 ZwCreateKey 似乎规避了 Windows 安全性?
我合作的团队最近面临着使我们的软件与第三方虚拟化软件兼容的挑战。该软件使用内核驱动程序来执行 Windows 本机注册表 API(ZwCreateKey
等)的挂钩。它通过挂钩 Ntdll 中的调用来工作。我们的软件水平也相当低,在某些情况下需要访问真实的注册表而不被挂钩。
我们正在探索使用我们自己的内核驱动程序来调用 ZwCreateKey
等的可能性,代表我们规避它们的挂钩。这本质上意味着创建一个 NT Legacy 驱动程序和一个提供我们自己的本机注册表功能的用户模式库。库和驱动程序非常简单,我们只需使用 IOCTL 将 ZwCreateKey
等的所有参数传递到我们的驱动程序中,然后我们调用内核版本的调用并返回结果。
该方法效果很好,我们现在似乎拥有一个在虚拟化时读取/写入真实注册表的系统。唯一的问题是我们的新系统似乎绕过了注册表对象上的 Windows 安全性。
ZwCreateKey
采用如下访问掩码:
NTSTATUS ZwCreateKey(
__out PHANDLE KeyHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__reserved ULONG TitleIndex,
__in_opt PUNICODE_STRING Class,
__in ULONG CreateOptions,
__out_opt PULONG Disposition
);
我的理解是,虽然我们现在在内核模式下运行,但我们仍然拥有用户令牌的上下文。这应该意味着 ZwCreateKey
的内核版本将失败,就像访问掩码测试失败时用户版本一样。实际发生的情况是,即使使用有限的令牌,当调用我们的驱动程序时,它也能够在受限用户调用时在受限部分 HKLM 中创建密钥。什么给?我们应该自己执行 ACL 检查吗?我们是否需要做一些事情来限制我们自己在内核模式下的权限?非常感谢任何帮助。
The team I work with has recently been faced with the challenge of making our software compatible with a third party peice of virtualization software. This software uses a kernel driver to perform hooking of the Windows native registry API (ZwCreateKey
, etc). It works by hooking the calls in Ntdll. Our software is also fairly low level and in some contexts requires access to the real registry without being hooked.
We're exploring the possibility of using our own kernel driver to call ZwCreateKey
, etc, on our behalf circumventing their hooking. This essentially has meant creating an NT Legacy driver and a user mode library which provides our own native registry functions. The library and driver are very simple, we simply use an IOCTL to pass all the parameters for ZwCreateKey
, etc into our driver then we call the kernel version of the call and return the results.
The approach has worked well, and we appear to now have a system of reading/writing to the real registry when virtualized. The only problem is that our new system appears to circument Windows security on registry objects.
ZwCreateKey
takes an access mask like so:
NTSTATUS ZwCreateKey(
__out PHANDLE KeyHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__reserved ULONG TitleIndex,
__in_opt PUNICODE_STRING Class,
__in ULONG CreateOptions,
__out_opt PULONG Disposition
);
My understanding was that although we were now running in kernel mode, we still had the context of the user's token. This should mean that the kernel version of ZwCreateKey
will fail just as the user one would have if the access mask test fails. What's actually happening is that even with a limited token, when our driver is called, it's able to create keys in restricted parts HKLM when invoked by a limited user. What gives? Should we be performing the ACL checks ourselves? Do we need to do something to limit our own privileges in kernel mode? Any help much appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
检查此了解说明。基本上,用户模式 (ntdll) 中的 Nt/Zw 是相同的东西 - 它们在实际执行操作之前首先执行广泛的检查。当从内核模式调用 Zw 函数时(如设备驱动程序的情况),这些检查被忽略,因为默认情况下假定来自内核模式组件(例如驱动程序)的信息是可信的
Check this for explanation. Basically Nt/Zw in User-mode (ntdll) are the same thing - they first perform extensive checks before actually performing the action. Where as when calling Zw functions from kernel-mode ( as is the case with a device driver) those checks are ommitted because it is assumed information coming from kernel-mode component (e.g. a driver) is to be trusted by default