/// <summary> /// The function checks whether the primary access token of the process belongs /// to user account that is a member of the local Administrators group, even if /// it currently is not elevated. /// </summary> /// <returns> /// Returns true if the primary access token of the process belongs to user /// account that is a member of the local Administrators group. Returns false /// if the token does not. /// </returns> /// <exception cref="System.ComponentModel.Win32Exception"> /// When any native Windows API call fails, the function throws a Win32Exception /// with the last error code. /// </exception> public static bool IsUserInAdminGroup() { bool fInAdminGroup = false; SafeTokenHandle hToken = null; SafeTokenHandle hTokenToCheck = null; IntPtr pElevationType = IntPtr.Zero; IntPtr pLinkedToken = IntPtr.Zero; int cbSize = 0; try { // Open the access token of the current process for query and duplicate. if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethods.TOKEN_QUERY | NativeMethods.TOKEN_DUPLICATE, out hToken)) { throw new Win32Exception(); } // Determine whether system is running Windows Vista or later operating // systems (major version >= 6) because they support linked tokens, but // previous versions (major version < 6) do not. if (Environment.OSVersion.Version.Major >= 6) { // Running Windows Vista or later (major version >= 6). // Determine token type: limited, elevated, or default. // Allocate a buffer for the elevation type information. cbSize = sizeof(TOKEN_ELEVATION_TYPE); pElevationType = Marshal.AllocHGlobal(cbSize); if (pElevationType == IntPtr.Zero) { throw new Win32Exception(); } // Retrieve token elevation type information. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType, cbSize, out cbSize)) { throw new Win32Exception(); } // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET. TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE) Marshal.ReadInt32(pElevationType); // If limited, get the linked elevated token for further check. if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited) { // Allocate a buffer for the linked token. cbSize = IntPtr.Size; pLinkedToken = Marshal.AllocHGlobal(cbSize); if (pLinkedToken == IntPtr.Zero) { throw new Win32Exception(); } // Get the linked token. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken, cbSize, out cbSize)) { throw new Win32Exception(); } // Marshal the linked token value from native to .NET. IntPtr hLinkedToken = Marshal.ReadIntPtr(pLinkedToken); hTokenToCheck = new SafeTokenHandle(hLinkedToken); } } // CheckTokenMembership requires an impersonation token. If we just got // a linked token, it already is an impersonation token. If we did not // get a linked token, duplicate the original into an impersonation // token for CheckTokenMembership. if (hTokenToCheck == null) { if (!NativeMethods.DuplicateToken(hToken, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, out hTokenToCheck)) { throw new Win32Exception(); } } // Check if the token to be checked contains admin SID. WindowsIdentity id = new WindowsIdentity(hTokenToCheck.DangerousGetHandle()); WindowsPrincipal principal = new WindowsPrincipal(id); fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator); } finally { // Centralized cleanup for all allocated resources. if (hToken != null) { hToken.Close(); hToken = null; } if (hTokenToCheck != null) { hTokenToCheck.Close(); hTokenToCheck = null; } if (pElevationType != IntPtr.Zero) { Marshal.FreeHGlobal(pElevationType); pElevationType = IntPtr.Zero; } if (pLinkedToken != IntPtr.Zero) { Marshal.FreeHGlobal(pLinkedToken); pLinkedToken = IntPtr.Zero; } } return(fInAdminGroup); }
/// <summary> /// The function gets the integrity level of the current process. Integrity /// level is only available on Windows Vista and newer operating systems, thus /// GetProcessIntegrityLevel throws a C++ exception if it is called on systems /// prior to Windows Vista. /// </summary> /// <returns> /// Returns the integrity level of the current process. It is usually one of /// these values: /// /// SECURITY_MANDATORY_UNTRUSTED_RID - means untrusted level. It is used /// by processes started by the Anonymous group. Blocks most write access. /// (SID: S-1-16-0x0) /// /// SECURITY_MANDATORY_LOW_RID - means low integrity level. It is used by /// Protected Mode Internet Explorer. Blocks write acess to most objects /// (such as files and registry keys) on the system. (SID: S-1-16-0x1000) /// /// SECURITY_MANDATORY_MEDIUM_RID - means medium integrity level. It is /// used by normal applications being launched while UAC is enabled. /// (SID: S-1-16-0x2000) /// /// SECURITY_MANDATORY_HIGH_RID - means high integrity level. It is used /// by administrative applications launched through elevation when UAC is /// enabled, or normal applications if UAC is disabled and the user is an /// administrator. (SID: S-1-16-0x3000) /// /// SECURITY_MANDATORY_SYSTEM_RID - means system integrity level. It is /// used by services and other system-level applications (such as Wininit, /// Winlogon, Smss, etc.) (SID: S-1-16-0x4000) /// /// </returns> /// <exception cref="System.ComponentModel.Win32Exception"> /// When any native Windows API call fails, the function throws a Win32Exception /// with the last error code. /// </exception> public static int GetProcessIntegrityLevel() { int IL = -1; SafeTokenHandle hToken = null; int cbTokenIL = 0; IntPtr pTokenIL = IntPtr.Zero; try { // Open the access token of the current process with TOKEN_QUERY. if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethods.TOKEN_QUERY, out hToken)) { throw new Win32Exception(); } // Then we must query the size of the integrity level information // associated with the token. Note that we expect GetTokenInformation // to return false with the ERROR_INSUFFICIENT_BUFFER error code // because we've given it a null buffer. On exit cbTokenIL will tell // the size of the group information. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, IntPtr.Zero, 0, out cbTokenIL)) { int error = Marshal.GetLastWin32Error(); if (error != NativeMethods.ERROR_INSUFFICIENT_BUFFER) { // When the process is run on operating systems prior to // Windows Vista, GetTokenInformation returns false with the // ERROR_INVALID_PARAMETER error code because // TokenIntegrityLevel is not supported on those OS's. throw new Win32Exception(error); } } // Now we allocate a buffer for the integrity level information. pTokenIL = Marshal.AllocHGlobal(cbTokenIL); if (pTokenIL == IntPtr.Zero) { throw new Win32Exception(); } // Now we ask for the integrity level information again. This may fail // if an administrator has added this account to an additional group // between our first call to GetTokenInformation and this one. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, pTokenIL, cbTokenIL, out cbTokenIL)) { throw new Win32Exception(); } // Marshal the TOKEN_MANDATORY_LABEL struct from native to .NET object. TOKEN_MANDATORY_LABEL tokenIL = (TOKEN_MANDATORY_LABEL) Marshal.PtrToStructure(pTokenIL, typeof(TOKEN_MANDATORY_LABEL)); // Integrity Level SIDs are in the form of S-1-16-0xXXXX. (e.g. // S-1-16-0x1000 stands for low integrity level SID). There is one // and only one subauthority. IntPtr pIL = NativeMethods.GetSidSubAuthority(tokenIL.Label.Sid, 0); IL = Marshal.ReadInt32(pIL); } finally { // Centralized cleanup for all allocated resources. if (hToken != null) { hToken.Close(); hToken = null; } if (pTokenIL != IntPtr.Zero) { Marshal.FreeHGlobal(pTokenIL); pTokenIL = IntPtr.Zero; cbTokenIL = 0; } } return(IL); }
/// <summary> /// The function gets the elevation information of the current process. It /// dictates whether the process is elevated or not. Token elevation is only /// available on Windows Vista and newer operating systems, thus /// IsProcessElevated throws a C++ exception if it is called on systems prior /// to Windows Vista. It is not appropriate to use this function to determine /// whether a process is run as administartor. /// </summary> /// <returns> /// Returns true if the process is elevated. Returns false if it is not. /// </returns> /// <exception cref="System.ComponentModel.Win32Exception"> /// When any native Windows API call fails, the function throws a Win32Exception /// with the last error code. /// </exception> /// <remarks> /// TOKEN_INFORMATION_CLASS provides TokenElevationType to check the elevation /// type (TokenElevationTypeDefault / TokenElevationTypeLimited / /// TokenElevationTypeFull) of the process. It is different from TokenElevation /// in that, when UAC is turned off, elevation type always returns /// TokenElevationTypeDefault even though the process is elevated (Integrity /// Level == High). In other words, it is not safe to say if the process is /// elevated based on elevation type. Instead, we should use TokenElevation. /// </remarks> public static bool IsProcessElevated() { bool fIsElevated = false; SafeTokenHandle hToken = null; int cbTokenElevation = 0; IntPtr pTokenElevation = IntPtr.Zero; try { // Open the access token of the current process with TOKEN_QUERY. if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethods.TOKEN_QUERY, out hToken)) { throw new Win32Exception(); } // Allocate a buffer for the elevation information. cbTokenElevation = Marshal.SizeOf(typeof(TOKEN_ELEVATION)); pTokenElevation = Marshal.AllocHGlobal(cbTokenElevation); if (pTokenElevation == IntPtr.Zero) { throw new Win32Exception(); } // Retrieve token elevation information. if (!NativeMethods.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevation, pTokenElevation, cbTokenElevation, out cbTokenElevation)) { // When the process is run on operating systems prior to Windows // Vista, GetTokenInformation returns false with the error code // ERROR_INVALID_PARAMETER because TokenElevation is not supported // on those operating systems. throw new Win32Exception(); } // Marshal the TOKEN_ELEVATION struct from native to .NET object. TOKEN_ELEVATION elevation = (TOKEN_ELEVATION)Marshal.PtrToStructure( pTokenElevation, typeof(TOKEN_ELEVATION)); // TOKEN_ELEVATION.TokenIsElevated is a non-zero value if the token // has elevated privileges; otherwise, a zero value. fIsElevated = (elevation.TokenIsElevated != 0); } finally { // Centralized cleanup for all allocated resources. if (hToken != null) { hToken.Close(); hToken = null; } if (pTokenElevation != IntPtr.Zero) { Marshal.FreeHGlobal(pTokenElevation); pTokenElevation = IntPtr.Zero; cbTokenElevation = 0; } } return(fIsElevated); }
/// <summary> /// 即使在还没有为当前用户提升权限的前提下,此函数检测拥有此进程的主访 /// 问令牌的用户是否是本地管理员组的成员。 /// </summary> /// <returns> /// 如果拥有主访问令牌的用户是管理员组成员则返回TRUE,反之则返回FALSE。 /// </returns> /// <exception cref="System.ComponentModel.Win32Exception"> /// 如果任何原生的Windows API函数出错,此函数会抛出一个包含最后错误代码的Win32Exception。 /// </exception> internal bool IsUserInAdminGroup() { bool fInAdminGroup = false; SafeTokenHandle hToken = null; SafeTokenHandle hTokenToCheck = null; IntPtr pElevationType = IntPtr.Zero; IntPtr pLinkedToken = IntPtr.Zero; int cbSize = 0; try { // 打开此进程的主访问令牌(使用TOKEN_QUERY | TOKEN_DUPLICATE) if (!NativeMethod.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethod.TOKEN_QUERY | NativeMethod.TOKEN_DUPLICATE, out hToken)) { throw new Win32Exception(); } // 检测是否此系统是Windows Vista或后续版本(主版本号 >= 6)。这是由于自 // Windows Vista开始支持链接令牌(LINKED TOKEN),而之前的版本不支持。 // (主版本 < 6) if (Environment.OSVersion.Version.Major >= 6) { // 运行于Windows Vista 或后续版本(主版本 >= 6). // 检测令牌类型:受限(limited),(已提升)elevated, // 或者默认(default) // 为提升类别信息对象分配内存 cbSize = sizeof(TOKEN_ELEVATION_TYPE); pElevationType = Marshal.AllocHGlobal(cbSize); if (pElevationType == IntPtr.Zero) { throw new Win32Exception(); } // 获取令牌提升类别信息 if (!NativeMethod.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType, cbSize, out cbSize)) { throw new Win32Exception(); } // 转换TOKEN_ELEVATION_TYPE枚举类型(从原生到.Net) TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE) Marshal.ReadInt32(pElevationType); // 如果为受限的,获取相关联的已提升令牌以便今后使用。 if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited) { // 为连接令牌分配内存 cbSize = IntPtr.Size; pLinkedToken = Marshal.AllocHGlobal(cbSize); if (pLinkedToken == IntPtr.Zero) { throw new Win32Exception(); } // 获取连接令牌 if (!NativeMethod.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken, cbSize, out cbSize)) { throw new Win32Exception(); } // 转换连接令牌的值(从原生到.Net) IntPtr hLinkedToken = Marshal.ReadIntPtr(pLinkedToken); hTokenToCheck = new SafeTokenHandle(hLinkedToken); } } // CheckTokenMembership要求一个伪装令牌。如果我们仅得到一个链接令牌,那 // 它就是一个伪装令牌。如果我们没有得到一个关联式令牌,我们需要复制当前 // 令牌以便得到一个伪装令牌。 if (hTokenToCheck == null) { if (!NativeMethod.DuplicateToken(hToken, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, out hTokenToCheck)) { throw new Win32Exception(); } } // 检测是否被检测的令牌包含管理员组SID WindowsIdentity id = new WindowsIdentity(hTokenToCheck.DangerousGetHandle()); WindowsPrincipal principal = new WindowsPrincipal(id); fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator); } finally { // 集中清理所有已分配的内存资源 if (hToken != null) { hToken.Close(); hToken = null; } if (hTokenToCheck != null) { hTokenToCheck.Close(); hTokenToCheck = null; } if (pElevationType != IntPtr.Zero) { Marshal.FreeHGlobal(pElevationType); pElevationType = IntPtr.Zero; } if (pLinkedToken != IntPtr.Zero) { Marshal.FreeHGlobal(pLinkedToken); pLinkedToken = IntPtr.Zero; } } return(fInAdminGroup); }
/// <summary> /// 此函数获取当前线程的完整性级别。完整性级别只有在Windows Vista及后 /// 续版本的Windows中有效。所以在Windows Vista之前的版本中执行GetProcessIntegrityLevel, /// 它会抛出一个C++异常。 /// </summary> /// <returns> /// 返回当前进程的完整性级别。它可能是以下某一个值。 /// /// SECURITY_MANDATORY_UNTRUSTED_RID (SID: S-1-16-0x0) /// 表示不被信任的级别。它被用于一个匿名组成员起动的进程。这时大多数 /// 写入操作被禁止。 /// /// SECURITY_MANDATORY_LOW_RID (SID: S-1-16-0x1000) /// 表示低完整性级别。它被用于保护模式下的IE浏览器。这时大多数系统中对 /// 象(包括文件及注册表键值)的写入操作被禁止。 /// /// SECURITY_MANDATORY_MEDIUM_RID (SID: S-1-16-0x2000) /// 表示中完整性级别。它被用于在UAC开启时启动普通应用程序。 /// /// /// SECURITY_MANDATORY_HIGH_RID (SID: S-1-16-0x3000) /// 表示高完整性级别。它被用于用户通过UAC提升权限启动一个管理员应用程序。 /// 或则当UAC关闭时,管理员用户启动一个普通程序。 /// /// /// SECURITY_MANDATORY_SYSTEM_RID (SID: S-1-16-0x4000) /// 表示系统完整性级别。它被用于服务或则其他系统级别的应用程序(比如 /// Wininit, Winlogon, Smss,等等) /// /// </returns> /// <exception cref="System.ComponentModel.Win32Exception"> /// 如果任何原生的Windows API函数出错,此函数会抛出一个包含最后错误代码的Win32Exception。 /// </exception> internal int GetProcessIntegrityLevel() { int IL = -1; SafeTokenHandle hToken = null; int cbTokenIL = 0; IntPtr pTokenIL = IntPtr.Zero; try { // 使用TOKEN_QUERY打开线程的主访问令牌。 if (!NativeMethod.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethod.TOKEN_QUERY, out hToken)) { throw new Win32Exception(); } // 然后我们必须查询令牌完整性级别信息的大小。注意:我们预期得到一个FALSE结果及错误 // ERROR_INSUFFICIENT_BUFFER, 这是由于我们在GetTokenInformation输入一个 // 空缓冲。同时,在cbTokenIL中我们会得知完整性级别信息的大小。 if (!NativeMethod.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, IntPtr.Zero, 0, out cbTokenIL)) { int error = Marshal.GetLastWin32Error(); if (error != NativeMethod.ERROR_INSUFFICIENT_BUFFER) { // 当进程运行于Windows Vista之前的系统中,GetTokenInformation返回 // FALSE和错误码ERROR_INVALID_PARAMETER。这是由于这些操作系统不支 // 持TokenElevation。 throw new Win32Exception(error); } } // 现在我们为完整性级别信息分配一个缓存。 pTokenIL = Marshal.AllocHGlobal(cbTokenIL); if (pTokenIL == IntPtr.Zero) { throw new Win32Exception(); } // 现在我们需要再次查询完整性级别信息。如果在第一次调用GetTokenInformation // 和本次之间一个管理员把当前账户加到另外一个组中,此次调用会失败。 if (!NativeMethod.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, pTokenIL, cbTokenIL, out cbTokenIL)) { throw new Win32Exception(); } // 转换TOKEN_MANDATORY_LABEL结构(从原生到.Net) TOKEN_MANDATORY_LABEL tokenIL = (TOKEN_MANDATORY_LABEL) Marshal.PtrToStructure(pTokenIL, typeof(TOKEN_MANDATORY_LABEL)); // 完整性级别SID为S-1-16-0xXXXX形式。(例如:S-1-16-0x1000表示为低完整性 // 级别的SID)。而且有且仅有一个次级授权信息。 IntPtr pIL = NativeMethod.GetSidSubAuthority(tokenIL.Label.Sid, 0); IL = Marshal.ReadInt32(pIL); } finally { // 集中清理所有已分配的内存资源 if (hToken != null) { hToken.Close(); hToken = null; } if (pTokenIL != IntPtr.Zero) { Marshal.FreeHGlobal(pTokenIL); pTokenIL = IntPtr.Zero; cbTokenIL = 0; } } return(IL); }
/// <summary> /// 此函数获取当前进程的权限提升信息。它由此进程是否进行了权限提升所 /// 决定。令牌权限提升只有在Windows Vista及后续版本的Windows中有效。所以在 /// Windows Vista之前的版本中执行IsProcessElevated, 它会抛出一个C++异常。 /// 此函数并不适用于检测是否此进程以管理员身份运行。 /// </summary> /// <returns> /// 如果此进程的权限已被提升,返回TRUE,反之则返回FALSE。 /// </returns> /// <exception cref="System.ComponentModel.Win32Exception"> /// 如果任何原生的Windows API函数出错,此函数会抛出一个包含最后错误代码的Win32Exception。 /// </exception> /// <remarks> /// TOKEN_INFORMATION_CLASS提供了TokenElevationType以便对当前进程的提升 /// 类型(TokenElevationTypeDefault / TokenElevationTypeLimited / /// TokenElevationTypeFull)进行检测。 它和TokenElevation的不同之处在于:当UAC /// 关闭时,即使当前进程已经被提升(完整性级别 == 高),权限提升类型总是返回 /// TokenElevationTypeDefault。换而言之,以此来确认当前线程的提升类型是不安全的。 /// 相对的,我们应该使用TokenElevation。 /// </remarks> internal bool IsProcessElevated() { bool fIsElevated = false; SafeTokenHandle hToken = null; int cbTokenElevation = 0; IntPtr pTokenElevation = IntPtr.Zero; try { // 使用TOKEN_QUERY打开进程主访问令牌 if (!NativeMethod.OpenProcessToken(Process.GetCurrentProcess().Handle, NativeMethod.TOKEN_QUERY, out hToken)) { throw new Win32Exception(); } // 为提升信息分配内存 cbTokenElevation = Marshal.SizeOf(typeof(TOKEN_ELEVATION)); pTokenElevation = Marshal.AllocHGlobal(cbTokenElevation); if (pTokenElevation == IntPtr.Zero) { throw new Win32Exception(); } // 获取令牌提升信息 if (!NativeMethod.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevation, pTokenElevation, cbTokenElevation, out cbTokenElevation)) { // 当进程运行于Windows Vista之前的系统中,GetTokenInformation返回 // FALSE和错误码ERROR_INVALID_PARAMETER。这是由于这些操作系统不支 // 持TokenElevation。 throw new Win32Exception(); } // 转换TOKEN_ELEVATION结构(从原生到.Net) TOKEN_ELEVATION elevation = (TOKEN_ELEVATION)Marshal.PtrToStructure( pTokenElevation, typeof(TOKEN_ELEVATION)); // 如果令牌权限已经被提升,TOKEN_ELEVATION.TokenIsElevated是一个非0值 // 反之则为0 fIsElevated = (elevation.TokenIsElevated != 0); } finally { // 集中清理所有已分配的内存资源 if (hToken != null) { hToken.Close(); hToken = null; } if (pTokenElevation != IntPtr.Zero) { Marshal.FreeHGlobal(pTokenElevation); pTokenElevation = IntPtr.Zero; cbTokenElevation = 0; } } return(fIsElevated); }