How to Check If a Process Has the Administrative Rights

Check if another process has admin privileges

You cannot add handles together (new IntPtr(hProcess.ToInt64() + hToken.ToInt64()); ), that makes no sense.

You need the process handle to get the process token handle, then pass the token handle to CheckTokenMembership.

You also need to close these handles with 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));
}

Check if a different process is running with elevated privileges

Thanks to RbMm (and Hantalyte indirectly) I've been made aware that the Microsoft documentation for OpenProcessToken is incorrect in its assertion that the provided handle must have the PROCESS_QUERY_INFORMATION access permission, as it actually only requires that the handle have PROCESS_QUERY_LIMITED_INFORMATION (I have confirmed this with my own testing).

It is possible to get a handle to an elevated process from within a non-elevated process with the permission PROCESS_QUERY_LIMITED_INFORMATION, as long as both were started from the same account, meaning that one can check other processes for elevation using the procedure in my question that I original though didn't work due to the errant documentation.

As Hantalyte/RbMm point out, if the process being checked is owned by a different account the checking process needs the SE_DEBUG_NAME privilege to be enabled.

Hopefully the MS docs should be corrected soon.

UPDATE:
The correction PR has been merged.

UPDATE 2:
The correction is now live: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken

How can I tell if my process is running as Administrator?

Technically, if you want to see if the member is the local administrator account, then you can get the security identifier (SID) of the current user through the User property on the WindowsIdentity class, like so (the static GetCurrent method gets the current Windows user):

WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();

string sid = windowsIdentity.User.ToString();

The User property returns the SID of the user which has a number of predefined values for various groups and users.

Then you would check to see if the SID has the following pattern, indicating it is the local administrator account (which is a well-known SID):

S-1-5-{other SID parts}-500

Or, if you don't want to parse strings, you can use the SecurityIdentifier class:

// Get the built-in administrator account.
var sid = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid,
null);

// Compare to the current user.
bool isBuiltInAdmin = (windowsIdentity.User == sid);

However, I suspect that what you really want to know is if the current user is a member of the administrators group for the local machine. You can get this SID using the WellKnownSidType of BuiltinAdministratorsSid:

// Get the SID of the admin group on the local machine.
var localAdminGroupSid = new SecurityIdentifier(
WellKnownSidType.BuiltinAdministratorsSid, null);

Then you can check the Groups property on the WindowsIdentity of the user to see if that user is a member of the local admin group, like so:

bool isLocalAdmin = windowsIdentity.Groups.
Select(g => (SecurityIdentifier) g.Translate(typeof(SecurityIdentifier))).
Any(s => s == localAdminGroupSid);

Check if another process has admin privileges in .NET

OpenProcess(PROCESS_QUERY_[LIMITED_]INFORMATION)+OpenProcessToken(TOKEN_DUPLICATE) to get the token, then DuplicateTokenEx(TOKEN_QUERY,SecurityImpersonation,TokenImpersonation) to get the impersonation token, then pass that token and the SID from CreateWellKnownSid(WinBuiltinAdministratorsSid) to CheckTokenMembership.

To be able to open (almost) every process for PROCESS_QUERY_INFORMATION access you need to be running as administrator and with debug privileges. On Vista and later you can use PROCESS_QUERY_LIMITED_INFORMATION.

Example code available in this answer.



Related Topics



Leave a reply



Submit