【问题标题】:Check if another process has admin privileges检查另一个进程是否具有管理员权限
【发布时间】:2018-11-24 14:23:43
【问题描述】:

我写了一个代码来检查在同一台机器上运行的进程是否具有管理员权限。但它总是返回 false。

你能告诉我它有什么问题吗?

private static bool HasAdminPrivileges(int processId)
{
    var hProcess = WinApi.OpenProcess(ProcessAccessFlags.QueryInformation, false, processId);
    var opened = WinApi.OpenProcessToken(hProcess, WinApi.TOKEN_QUERY, out IntPtr hToken);
    if (opened)
    {
        var token = new IntPtr(hProcess.ToInt64() + hToken.ToInt64()); // 64 bit machine only

        WinApi.CreateWellKnownSid(WELL_KNOWN_SID_TYPE.WinBuiltinAdministratorsSid, IntPtr.Zero, IntPtr.Zero, out uint cbSidUint);
        var cbSid = new IntPtr(cbSidUint);

        var succeed = WinApi.CheckTokenMembership(token, cbSid, out bool isMember);

        return succeed && isMember;
    }
    return false;
}

public class WinApi
{
    public const int TOKEN_QUERY = 0X00000008;

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);    

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType, IntPtr DomainSid, IntPtr pSid, out uint cbSid);    

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool CheckTokenMembership(IntPtr TokenHandle, IntPtr SidToCheck, out bool IsMember);
}

public enum ProcessAccessFlags : uint
{
    QueryInformation = 0x00000400
}

public enum WELL_KNOWN_SID_TYPE
{
    WinBuiltinAdministratorsSid = 26
}

【问题讨论】:

  • 错误:1您必须打开具有访问权限PROCESS_QUERY_LIMITED_INFORMATION 而不是PROCESS_QUERY_INFORMATION 的进程(如果您不是以管理员身份运行,则会在此处拒绝访问)2 CheckTokenMembership 仅适用于模拟令牌。但您尝试将主令牌传递给它。 3 您没有创建管理员 sid - 在对CreateWellKnownSid 的单次调用中,您没有将指针传递给可以存储此 sid 的内存。 4 你没有关闭打开的句柄。 5你没有检查任何错误
  • 6你根本不调试自己的代码

标签: windows winapi process system32 advapi32


【解决方案1】:

你不能一起添加句柄(new IntPtr(hProcess.ToInt64() + hToken.ToInt64());),这没有任何意义。

您需要进程句柄来获取进程令牌句柄,然后将令牌句柄传递给CheckTokenMembership

您还需要使用CloseHandle 关闭这些句柄。

using System;
using System.Runtime.InteropServices;
...
public class WinApi
{
    public const int TOKEN_DUPLICATE = 0x0002;
    public const int TOKEN_QUERY = 0x00000008;
    public const int SecurityImpersonation = 2;
    public const int TokenImpersonation = 2;

    [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);
    [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DuplicateTokenEx(IntPtr hTok, UInt32 DesiredAccess, IntPtr SecAttPtr, int ImpLvl, int TokType, out IntPtr TokenHandle);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);

    [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType, IntPtr DomainSid, IntPtr pSid, ref uint cbSid);

    [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool CheckTokenMembership(IntPtr TokenHandle, IntPtr SidToCheck, out bool IsMember);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern int GetCurrentProcessId();
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern int CloseHandle(IntPtr h);
}

public enum ProcessAccessFlags : uint
{
    QueryInformation = 0x00000400,
    QueryLimitedInformation = 0x1000
}

public enum WELL_KNOWN_SID_TYPE
{
    WinBuiltinAdministratorsSid = 26
}

private static bool IsAdminGroupMember(int processId)
{
    IntPtr hPriToken = IntPtr.Zero, hImpToken = IntPtr.Zero;
    var hProcess = WinApi.OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, processId);
    if (hProcess == IntPtr.Zero) hProcess = WinApi.OpenProcess(ProcessAccessFlags.QueryInformation, false, processId); // < Vista
    var haveToken = WinApi.OpenProcessToken(hProcess, WinApi.TOKEN_DUPLICATE, out hPriToken);
    if (haveToken) 
    {
        haveToken = WinApi.DuplicateTokenEx(hPriToken, WinApi.TOKEN_QUERY, IntPtr.Zero, WinApi.SecurityImpersonation, WinApi.TokenImpersonation, out hImpToken);
        WinApi.CloseHandle(hPriToken);
    }
    if (hProcess != IntPtr.Zero) WinApi.CloseHandle(hProcess);
    if (haveToken)
    {
        uint cbSid = 0;
        bool isMember = false;
        WinApi.CreateWellKnownSid(WELL_KNOWN_SID_TYPE.WinBuiltinAdministratorsSid, IntPtr.Zero, IntPtr.Zero, ref cbSid);
        IntPtr pSid = Marshal.AllocCoTaskMem(Convert.ToInt32(cbSid));
        var succeed = pSid != IntPtr.Zero && WinApi.CreateWellKnownSid(WELL_KNOWN_SID_TYPE.WinBuiltinAdministratorsSid, IntPtr.Zero, pSid, ref cbSid);
        succeed = succeed && WinApi.CheckTokenMembership(hImpToken, pSid, out isMember);
        Marshal.FreeCoTaskMem(pSid);
        WinApi.CloseHandle(hImpToken);
        return succeed && isMember;
    }
    return false;
}


[STAThread]static void Main(/*string[] args*/) 
{

    bool admin = IsAdminGroupMember(WinApi.GetCurrentProcessId());
    Console.WriteLine(string.Format("IsAdminGroupMember={0}", admin));
}

【讨论】:

  • 必须不是ProcessAccessFlags.QueryInformation,但只要求PROCESS_QUERY_LIMITED_INFORMATION(不是管理进程不能用ProcessAccessFlags.QueryInformation打开管理(我猜这等于PROCESS_QUERY_INFORMATION。我们也可以调用@ 987654329@ 此处没有 Ex,如果想要正确,请检查对 CreateWellKnownSid 的首次调用是否失败并显示 ERROR_INSUFFICIENT_BUFFER
  • @RbMM:它首先尝试有限的信息,然后再尝试 XP 的旧信息。从技术上讲,文档没有说 CreateWellKnownSid 失败并出现特定错误。无论哪种方式,如果 cbSid 不正确,则内存分配将失败或下一次调用 CreateWellKnownSid 将失败,无论哪种方式,代码都是安全的。
  • 它首先尝试有限的信息,然后再尝试 XP 的旧信息 - 抱歉 - 请不要在代码中注意这一点。 CreateWellKnownSid - 是的,如果我们传递 0 指针和 0 大小未记录,则返回哪个错误,但从另一方面不检查 api 调用的错误,只是尝试分配 cbSid 也是错误的。可能是 sid 类型未知?无论如何检查这个错误更正确,即使没有明确记录
  • 关于访问 - 我将使用 dwAccess = ver &lt; 6.0 ? QueryInformation : QueryLimitedInformation 并且只调用一次 OpenProcess
  • 微软说你不应该做版本检查。反正只有在
【解决方案2】:

我使用 Anders 提供的解决方案创建了 Process.Extensions.dll 扩展

using System;
using ProcessExtensions;
using System.Diagnostics;
static void Main(string[] args)
{
    bool isAdminGroupMember = Process.GetCurrentProcess().IsAdminGroupMember();
    Console.WriteLine(string.Format("IsAdminGroupMember={0}", isAdminGroupMember));
}

https://github.com/IamhereTeam/Process.Extensions.git

Process.Extensions.dll

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 2011-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    相关资源
    最近更新 更多