Windows Vista/Windows 7 权限:SeDebugPrivilege和OpenProcess

25

我所找到的有关提升权限以满足我的需求的所有信息都与我的当前方法相符,但问题仍然存在。我希望也许有人对Windows Vista / Windows 7内部有一些经验可以在黑暗中照亮一些光芒。我相信这会变得很长,请耐心等待。

我正在开发一个需要访问当前计算机上其他进程内存的应用程序。这显然需要管理员权限。它还需要SeDebugPrivilege(不,这不是SetDebugPrivilege的拼写错误),我认为自己正确地获取了这个权限,尽管我怀疑是否需要更多的权限,因此导致了我的问题。代码迄今为止已成功运行在所有版本的Windows XP上,并且在我的测试Vista 32位和Windows 7 64位环境中也成功运行。

在整个过程中:

  • 程序将始终使用管理员权限运行。这可以在本文中假定。
  • 提升当前进程的访问令牌以包括SeDebugPrivilege权限。
  • 使用EnumProcesses创建系统上当前PID的列表。
  • 使用OpenProcessPROCESS_ALL_ACCESS访问权限打开一个句柄。
  • 使用ReadProcessMemory读取其他进程的内存。

问题:

在开发和个人测试期间,一切都运行良好(包括Windows XP 32位和64位、Windows Vista 32位和Windows 7 x64)。然而,在同事的Windows Vista(32位)和Windows 7(64位)机器上进行测试部署时,OpenProcess似乎存在特权/权限问题,并出现通用的访问被拒绝错误。这会在作为有限用户(预期)运行时和显式作为管理员运行(右键单击→以管理员身份运行)以及从管理员级别命令提示符中运行时发生。

但是,在我的测试环境中,这个问题是无法再现的。我亲眼目睹了这个问题,所以我相信它确实存在。我所能分辨的实际环境和我的测试环境之间唯一的区别是,实际错误是在UAC提示框内使用域管理员帐户时发生的,而我的测试(没有错误)在UAC提示框内使用本地管理员帐户。

看起来使用的凭据虽然允许UAC“以管理员身份运行”,但该进程仍未获得正确的权限,无法在另一个进程上调用OpenProcess。我对Vista/Windows 7的内部不熟悉,不知道可能是什么问题,希望有人能想到可能的原因。

重点

报告此错误的人,并且可以定期复制此错误的环境,拥有一个名为RunWithDebugEnabled的小应用程序,它是一个小型引导程序,似乎升级了自己的权限,然后启动传递给它的可执行文件(从而继承了提升的权限)。当使用相同的域管理员凭据在UAC提示时运行此程序时,程序可以正确工作并成功调用OpenProcess并按预期操作。

因此,这明显是获取正确权限的问题,并且已知域管理员帐户确实是应该能够访问正确权限的管理员帐户。(显然,如果可以获取此源代码,那将很好,但如果可能的话,我就不会在这里了)。

注释

如上所述,失败的OpenProcess尝试报告的错误为“访问被拒绝”。根据OpenProcess的MSDN文档:

如果调用方启用了SeDebugPrivilege特权,则无论安全描述符的内容如何,都将授予请求的访问权限。

这使我相信,在这些情况下可能存在问题,或者(1)获取SeDebugPrivilege或(2)需要其他未在任何MSDN文档中提及并且可能在域管理员帐户和本地管理员帐户之间存在差异的权限。

示例代码:

void sample()
{
   /////////////////////////////////////////////////////////
   //   Note: Enabling SeDebugPrivilege adapted from sample
   //     MSDN @ http://msdn.microsoft.com/en-us/library/aa446619%28VS.85%29.aspx
   // Enable SeDebugPrivilege
   HANDLE hToken = NULL;
   TOKEN_PRIVILEGES tokenPriv;
   LUID luidDebug;
   if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != FALSE)
   {
      if(LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidDebug) != FALSE)
      {
         tokenPriv.PrivilegeCount           = 1;
         tokenPriv.Privileges[0].Luid       = luidDebug;
         tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
         if(AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, 0, NULL, NULL) != FALSE)
         {
            // Always successful, even in the cases which lead to OpenProcess failure
            cout << "SUCCESSFULLY CHANGED TOKEN PRIVILEGES" << endl;
         }
         else
         {
            cout << "FAILED TO CHANGE TOKEN PRIVILEGES, CODE: " << GetLastError() << endl;
         }
      }
   }
   CloseHandle(hToken);
   // Enable SeDebugPrivilege
   /////////////////////////////////////////////////////////

   vector<DWORD> pidList = getPIDs();  // Method that simply enumerates all current process IDs

   /////////////////////////////////////////////////////////
   // Attempt to open processes
   for(int i = 0; i < pidList.size(); ++i)
   {
      HANDLE hProcess = NULL;
      hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pidList[i]);
      if(hProcess == NULL)
      {
         // Error is occurring here under the given conditions
         cout << "Error opening process PID(" << pidList[i] << "): " << GetLastError() << endl;
      }
      CloseHandle(hProcess);
   }
   // Attempt to open processes
   /////////////////////////////////////////////////////////
}

谢谢!

如果有人能够提供一些关于在Windows Vista和Windows 7下以管理员身份运行可执行文件后正确打开另一个进程所需的权限、特权、权限等方面的见解,将不胜感激。

我来这里是因为我完全被卡住了,但我希望团队的经验和知识再次闪耀。感谢您抽出时间阅读这篇长文。单凭好意就足以令人感激,非常感谢您成为使Stack Overflow对所有人如此有用的人!


7
好的,现在这才是一个问题。 - CMircea
1
如果您只想从进程内存中读取数据,您可能可以请求特定的权限,而不仅仅是 PROCESS_ALL_ACCESS(我知道这不是问题的重点)。 - Anders
1
根据MSDN的说法,OpenProcess应该可以工作,无论请求的访问权限如何,只要基本进程启用了SeDebugPrivilege。为了将其减少到必要的访问权限,PROCESS_VM_READ仍需要SeDebugPrivilege才能工作,因此我不确定结果是否会有任何不同(除非MSDN文档是错误的,这并非不可能)。 - KevenK
1
你无法打开哪些进程?很多安全软件使用内核模式钩子来阻止访问它们的进程。如果不是这个原因,可能有些东西正在干扰问题进程令牌中的SIDs。你需要在有问题的机器上运行Process Explorer来获得一些答案。 - Luke
2
AdjustTokenPrivileges是否成功?如果是,则仍需检查GetLastError,因为它可能返回ERROR_NOT_ALL_ASSIGNED。如果发生这种情况,则由于某种原因,进程令牌中不存在SeDebugPrivilege。您在代码中是否进行了任何模拟?请确保在本地安全策略中授予管理员组Debug特权(默认情况下)。 - Luke
显示剩余5条评论
1个回答

14

经过大量的调试,并向许多人询问信息,我终于找到了编写 RunWithDebugEnabled 应用程序的人,并了解了它的运行方式。

问题在于,域管理员的本地策略中已删除了“调试程序”特权,因此进程的访问令牌中没有 SeDebugPrivilege 令牌。如果根本不存在该令牌,则无法启用该令牌,我仍然不知道如何将该特权添加到现有的访问令牌中。


当前魔术的工作原理:
因此,RunWithDebugEnabled 魔法应用程序将使用其管理员权限将其自身安装为服务并启动自身,因此运行于 SYSTEM 用户帐户而不是域管理员账户下。使用 SYSTEM 特权,该应用程序会创建一个新的访问令牌,该令牌与管理员令牌相同,只是具有 SeDebugPrivilege 令牌。使用该新令牌的 CreateProcessAsUser() 会以先前缺少的新启用的 SeDebugPrivilege 来运行程序。

实际上,我不喜欢这个“解决方案”,并一直在继续寻找一个更“干净”的方法来获取该特权。我将在 Stack Overflow 上发布这个问题,并尝试记得在这里链接,以帮助其他人跟进和将来参考。

编辑: 从管理员帐户模拟 SYSTEM(或等效)



感谢大家花费时间和精力协助调试并解决这个问题。真的非常感谢!


你说你不知道如何将权限添加到现有令牌中:难道不应该使用AdjustTokenPrivileges吗?显然,这仅在启用特权并且现有令牌没有它的情况下才有效。 - Roman Starkov
1
根据我的了解,AdjustTokenPrivileges只允许在访问令牌中启用、禁用或删除特权。但是,如果访问令牌本身完全缺少(或已被删除)该特权,则AdjustTokenPrivileges无法添加缺失的特权。 - KevenK
1
你能发给我一份RunWithDebugEnabled的副本吗?源代码可获得吗?听起来很酷,可以节省我一些时间。 - loop
1
可能我的问题和你的一样。尽管我设置了SeDebugPrivilege并使用了PROCESS_ALL_ACCESS权限,但在读取以管理员身份运行的应用程序的内存时,我始终会遇到“访问被拒绝”的错误。我不熟悉你所说的内容。什么是RunWithDebugEnabled应用程序?我搜索了一下,什么都没找到。我同意@test的观点。你能和我们分享一下吗? - Ahmet DAL
我意识到我来晚了。如果你正在寻找一个类似于RunWithDebugEnabled的粗略等效方法,但想要将新进程作为原始进程的子进程启动(即不是系统服务的子进程),现在有一种方法可以实现:https://github.com/cubiclesoft/createprocess-windows - CubicleSoft

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接