如何在服务和用户进程之间共享内存?

时间:2009-05-22 16:12:41

标签: c security winapi windows-vista

我有一组Win32应用程序,它们使用由CreateFileMapping()MapViewOfFile()创建的共享内存段共享信息。其中一个应用是系统服务;其余部分由登录用户启动。在Windows XP上,没有问题。我们将我们的片段命名为“Global \ Something”,一切都很好。

Vista中的附加安全性(以及假设的Windows 7)似乎阻止了这种架构的运行。不允许普通用户在全局命名空间中创建(Win32错误5)对象。 MSDN表明,如果该帐户具有“创建全局”权限,那么一切都应该很好,但实际上似乎并非如此。 此外,Vista的“完整性”功能似乎可以防止“低完整性”用户进程访问“高完整性”服务创建的共享内存对象。看起来我应该可以通过一些神奇的SetSecurityDescriptorSacl()咒语解决这个问题,但是我很难学会说出来。

所以问题是:在服务和普通用户进程之间使用共享内存段的正确方法是什么?

为了取代“只是关闭UAC”的简单回答,我们处于一个相当封锁的环境中,这是不可能的。

编辑:服务和用户进程都需要对段进行读/写访问。

1 个答案:

答案 0 :(得分:10)

最简单的方法是让您的服务创建共享内存并在CreateFileMapping中指定一个DACL,授予常规用户对共享内存的读访问权。

普通用户没有create global特权,但服务可以拥有此特权。如果您必须让您的用户创建共享内存然后让服务探测它,您可以使用IPC方案,其中您的用户代码向包含文件映射句柄的服务发送消息,然后该服务将调用DuplicateHandle以获取参考它。这将要求您的服务以调试权限运行。

创建DACL的最简单方法是使用ConvertStringSecurityDescriptorToSecurityDescriptor,它采用称为SDDL的格式的字符串来指定ACL。

Writing Secure Code包含了使用SDDL创建DACL的精彩章节。

// Error handling removed for brevity
SECURITY_ATTRIBUTES attributes;
ZeroMemory(&attributes, sizeof(attributes));
attributes.nLength = sizeof(attributes);
ConvertStringSecurityDescriptorToSecurityDescriptor(
         L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GR;;;IU)",
         SDDL_REVISION_1,
         &attributes.lpSecurityDescriptor,
         NULL);

CreateFileMapping(INVALID_HANDLE_VALUE, &attributes,
              PAGE_READWRITE, sizeHigh, sizeLow, L"Global\\MyObject");

LocalFree(attributes.lpSecurityDescriptor);

“D:P(A; OICI; GA ;;; SY)(A; OICI; GA ;;; BA)(A; OICI; GR ;;; IU)”指定DACL。 D:P表示这是一个DACL(而不是SACL ......你很少使用SACL),后面是几个控制谁可以访问的ACE字符串。每一个都是A(允许)并允许对象并包含继承(OICI)。第一个授予系统(SY)和管理员(BA,内置管理员)的所有访问权限(GA - 全部授予)。最后一次授予读取(GR)给交互式用户(IU),这些用户实际登录到会话。

完成此操作后,普通用户应该能够调用OpenFileMapping来获取共享映射的句柄,并能够将其映射到其进程中。由于普通用户对该对象拥有有限的权限,因此他们必须确保将其打开并将其映射为仅供读取访问。

如果用户需要write-acccess,则用GWGR替换GR。请注意,这不安全 - 有限的用户可以在您的服务正在阅读并尝试解析信息时修改共享内存,从而导致服务崩溃。