判断指定进程是否具有管理员权限

lonelyperson

发布日期: 2018-12-20 12:31:59 浏览量: 1511
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

背景

某天,一个小伙伴突然问我,用什么程序或者软件可以查看计算机上进程是否具有管理员或者管理员以上的权限。我一下子懵了,印象中好像还真没有遇到过可以判断进程是否有管理员权限的软件。我运行了我电脑上的 Process Explorer 进行查看,好像确实没有检测管理员权限的功能。

但是,作为一个动手能力较强的程序员,没有的程序可以自己写。于是,自己上网搜索了判断进程是否具有管理员权限的实现原理。原来,就是通过获取进程令牌的令牌特权提升信息,令牌特权提升信息中就专门有一个标志表示进程权限是否提升。如果进程权限已经提升,则说明是具有管理员或者管理员以上的权限,否则,只是普通权限。

现在,我就把程序实现的过程及其原理进行整理,形成文档,分享给大家。

函数介绍

OpenProcess 函数

打开一个已存在的进程对象,并返回进程的句柄。

函数声明

  1. HANDLE OpenProcess(
  2. DWORD dwDesiredAccess, //渴望得到的访问权限(标志)
  3. BOOL bInheritHandle, // 是否继承句柄
  4. DWORD dwProcessId // 进程标示符
  5. );

参数

  • dwDesiredAccess [in]
    访问进程对象。 此访问权限将针对进程的安全描述符进行检查。 此参数可以是一个或多个进程访问权限。如果调用者启用了SeDebugPrivilege权限,则无论安全描述符的内容如何,都会授予所请求的访问权限。
  • bInheritHandle [in]
    如果此值为TRUE,则此进程创建的进程将继承该句柄。 否则,进程不会继承此句柄。
  • dwProcessId [in]
    要打开的本地进程的标识符。

返回值

  • 如果函数成功,则返回值是指定进程的打开句柄。
  • 如果函数失败,返回值为NULL。要获取扩展错误信息,请调用GetLastError。

OpenProcessToken 函数

打开与进程关联的访问令牌。

函数声明

  1. BOOL WINAPI OpenProcessToken(
  2. _In_ HANDLE ProcessHandle,
  3. _In_ DWORD DesiredAccess,
  4. _Out_ PHANDLE TokenHandle
  5. );

参数

  • ProcessHandle [in]
    要打开访问令牌的进程的句柄。 该进程必须具有PROCESS_QUERY_INFORMATION访问权限。
  • DesiredAccess [in]
    指定一个访问掩码,指定访问令牌的请求类型。 这些请求的访问类型与令牌的自由访问控制列表(DACL)进行比较,以确定哪些访问被授予或拒绝。
  • TokenHandle [出]
    指向一个句柄的指针,用于标识当函数返回时新打开的访问令牌。

返回值

  • 如果函数成功,则返回值不为零。
  • 如果函数失败,返回值为零。 要获取扩展错误信息,请调用GetLastError。

GetTokenInformation 函数

获取有关访问令牌的指定类型的信息。 调用进程必须具有获取信息的适当访问权限。

函数声明

  1. BOOL WINAPI GetTokenInformation(
  2. _In_ HANDLE TokenHandle,
  3. _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
  4. _Out_opt_ LPVOID TokenInformation,
  5. _In_ DWORD TokenInformationLength,
  6. _Out_ PDWORD ReturnLength
  7. );

参数

  • TokenHandle [in]
    检索信息的访问令牌的句柄。如果TokenInformationClass指定TokenSource,则该句柄必须具有TOKEN_QUERY_SOURCE访问权限。对于所有其他TokenInformationClass值,句柄必须具有TOKEN_QUERY权限。
  • TokenInformationClass[in]
    指定来自TOKEN_INFORMATION_CLASS枚举类型的值,以识别函数检索的信息类型。检查TokenIsAppContainer并返回0的任何呼叫者也应该验证呼叫者令牌不是识别级别的模拟令牌。如果当前令牌不是应用程序容器,而是身份级别令牌,则应返回AccessDenied。
  • TokenInformation[out]
    指向缓冲区的指针,该函数填充所请求的信息。放入此缓冲区的结构取决于由TokenInformationClass参数指定的信息类型。
  • TokenInformationLength[in]
    指定由TokenInformation参数指向的缓冲区的大小(以字节为单位)。如果TokenInformation为NULL,则此参数必须为 0。
  • ReturnLength [out]
    指向一个变量的指针,该变量接收TokenInformation参数指向的缓冲区所需的字节数。如果该值大于TokenInformationLength参数中指定的值,则该函数将失败,并且不将数据存储在缓冲区中。
    如果TokenInformationClass参数的值为TokenDefaultDacl,并且令牌没有默认DACL,则该函数将ReturnLength指向的变量设置为sizeof(TOKEN_DEFAULT_DACL),并将TOKEN_DEFAULT_DACL结构的DefaultDacl成员设置为NULL。

返回值

  • 如果函数成功,则返回值不为零。
  • 如果函数失败,返回值为零。 要获取扩展错误信息,请调用GetLastError。

实现原理

判断一个进程是否具有管理员权限,可以分成 4个步骤:

  • 首先,使用 OpenProcess 打开进程,并获取 PROCESS_ALL_ACCESS 权限的进程句柄

  • 然后,根据进程句柄,可以调用 OpenProcessToken 函数打开进程令牌,并获取具有 TOKEN_QUERY 权限的进程令牌。因为下面我们需要查询进程令牌的权限提升信息,所以要求进程令牌必须具有 TOKEN_QUERY 权限

  • 接着,我们就可以调用 GetTokenInformation 函数,获取令牌权限提信息 TokenElevation,获取的信息存储在 TOKEN_ELEVATION 结构体缓冲区里。TOKEN_ELEVATION 结构体的成员 TokenIsElevated 就表示进程令牌权限是否提升。TRUE,表示已经提升,则是管理员或者管理员以上的权限;FALSE,表示没有提升,则表示普通权限

  • 最后,我们关机进程句柄,返回判断结果

编码实现

  1. // 判断指定进程是否具有管理员或者管理员以上的权限
  2. BOOL IsProcessRunAsAdmin(DWORD dwProcessId)
  3. {
  4. HANDLE hProcess = NULL;
  5. HANDLE hToken = NULL;
  6. TOKEN_ELEVATION tokenEle = {0};
  7. BOOL bElevated = FALSE;
  8. DWORD dwRet = 0;
  9. BOOL bRet = FALSE;
  10. // 打开进程, 获取进程句柄
  11. hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
  12. if (NULL == hProcess)
  13. {
  14. ShowError("OpenProcess");
  15. return FALSE;
  16. }
  17. // 打开进程令牌, 获取进程令牌句柄
  18. bRet = ::OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
  19. if (FALSE == bRet)
  20. {
  21. ShowError("OpenProcessToken");
  22. return FALSE;
  23. }
  24. // 获取进程令牌特权提升信息
  25. bRet = ::GetTokenInformation(hToken, TokenElevation, &tokenEle, sizeof(tokenEle), &dwRet);
  26. if (FALSE == bRet)
  27. {
  28. ShowError("GetTokenInformation");
  29. return FALSE;
  30. }
  31. // 获取进程是否提升的结果
  32. bElevated = tokenEle.TokenIsElevated;
  33. // 关闭进程句柄
  34. ::CloseHandle(hToken);
  35. return bElevated;
  36. }

程序测试

我们以普通权限运行 520.exe 程序,然后使用我们的程序进行判断,结果判断正确:

然后,我们以管理员权限运行 520.exe 程序,并使用我们的程序进行判断,结果正确:

总结

要注意一点就是,我们运行自己的判断程序的时候,建议使用管理员权限运行。因为我们判断一个程序是否具有管理员权限之前,先调用 OpenProcess 函数打开进程,那么,低权限程序打开高权限的程序,执行这个函数就会因为权限不足而报错。所以,如果一开始我们就以管理员权限运行我们的判断程序,就可以避免这种情况的发生。

参考

参考自《Windows黑客编程技术详解》一书

上传的附件 cloud_download IsProcessRunAsAdmin_Test.7z ( 1.61mb, 26次下载 )

发送私信

曾经输掉的东西,只要你想,就一定可以再一点一点赢回来

15
文章数
25
评论数
最近文章
eject