使用 C++ 执行特权操作

特殊的客户端应用程序可能会调用特权操作。 例如,应用程序可允许管理员重启无响应的办公计算机。 通过使用 Windows Management Instrumentation (WMI),可以通过为特权操作调用 WMI 提供程序来执行特权操作。

以下过程介绍如何为特权操作调用提供程序。

为特权操作调用提供程序

  1. 获取客户端进程权限以执行特权操作。

    通常在运行进程之前,管理员会使用系统管理工具设置权限。

  2. 获取提供程序进程权限以启用特权操作。

    通常,可以通过调用 AdjustTokenPrivileges 函数来设置提供程序权限。

  3. 获取客户端进程权限以启用特权操作。

    仅当提供程序是客户端的本地提供程序时,才需要执行此步骤。 如果客户端和提供程序位于同一台计算机上,客户端必须使用以下技术之一专门启用特权操作:

    • 如果客户端拥有进程,则在调用 WMI 之前,客户端可使用 AdjustTokenPrivileges 调整进程令牌。 在这种情况下,无需进一步编码。
    • 如果客户端无法访问客户端令牌,客户端可按照以下过程创建线程令牌并对该令牌使用 AdjustTokenPrivileges

以下过程介绍如何创建线程令牌并对该令牌使用 AdjustTokenPrivileges

创建线程令牌并对该令牌使用 AdjustTokenPrivileges

  1. 通过调用 ImpersonateSelf 创建进程令牌的副本。

  2. 通过调用 GetTokenInformation 检索新创建的线程令牌。

  3. 通过对新令牌调用 AdjustTokenPrivileges 启用特权操作。

  4. 获取指向 IWbemServices 的指针。

  5. 通过调用 CoSetProxyBlanket 掩蔽指向 IWbemServices 的指针。

  6. 每次调用 WMI 时都重复步骤 1 到 5。

    注意

    必须重复这些步骤,因为 COM 错误地缓存了令牌。

     

本主题中的代码示例需要以下 #include 语句才能正确编译。

#include <wbemidl.h>

以下代码示例演示如何在本地计算机上启用特权。

// Get the privileges 
// The token has been obtained outside the scope of this code sample
// ================== 
DWORD dwLen;
bool bRes;
HANDLE hToken;

// obtain dwLen
bRes = GetTokenInformation(
  hToken, 
  TokenPrivileges, 
  NULL, 
  0,
  &dwLen
); 

BYTE* pBuffer = new BYTE[dwLen];
if(pBuffer == NULL)
{
  CloseHandle(hToken);
  return WBEM_E_OUT_OF_MEMORY;
} 

bRes = GetTokenInformation(
  hToken, 
  TokenPrivileges, 
  pBuffer,     
  dwLen,        
  &dwLen
);

if (!bRes)
{
  CloseHandle(hToken);
  delete [] pBuffer;
  return WBEM_E_ACCESS_DENIED;
} 

// Iterate through all the privileges and enable them all
// ====================================================== 
TOKEN_PRIVILEGES* pPrivs = (TOKEN_PRIVILEGES*)pBuffer;
for (DWORD i = 0; i < pPrivs->PrivilegeCount; i++)
{
  pPrivs->Privileges[i].Attributes |= SE_PRIVILEGE_ENABLED;
} 
// Store the information back in the token
// ========================================= 
bRes = AdjustTokenPrivileges(
  hToken, 
  FALSE, 
  pPrivs, 
  0, NULL, NULL
);

delete [] pBuffer;
CloseHandle(hToken); 

if (!bRes)
  return WBEM_E_ACCESS_DENIED;
else
  return WBEM_S_NO_ERROR;