|
|
@ -0,0 +1,506 @@ |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.ComponentModel; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.IO; |
|
|
|
using System.Linq; |
|
|
|
using System.Reflection; |
|
|
|
using System.Runtime.ConstrainedExecution; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
using System.Security; |
|
|
|
using System.Text; |
|
|
|
using System.Threading; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using Microsoft.Win32.SafeHandles; |
|
|
|
using TrustedUninstaller.Shared.Actions; |
|
|
|
|
|
|
|
namespace TrustedUninstaller.Shared |
|
|
|
{ |
|
|
|
public class ProcessPrivilege |
|
|
|
{ |
|
|
|
private static Win32.TokensEx.SafeTokenHandle userToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
private static Win32.TokensEx.SafeTokenHandle elevatedUserToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
private static Win32.TokensEx.SafeTokenHandle systemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
private static Win32.TokensEx.SafeTokenHandle impsersonatedSystemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
private static Win32.TokensEx.SafeTokenHandle lsassToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
|
|
|
|
internal static void ResetTokens() |
|
|
|
{ |
|
|
|
elevatedUserToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
lsassToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
systemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
impsersonatedSystemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
userToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero); |
|
|
|
} |
|
|
|
|
|
|
|
public static void StartPrivilegedTask(AugmentedProcess.Process process, Privilege privilege) |
|
|
|
{ |
|
|
|
var tcs = StartThread(process, privilege); |
|
|
|
tcs.Task.Wait(); |
|
|
|
for (int i = 0; tcs.Task.Result != null && i <= 3; i++) |
|
|
|
{ |
|
|
|
ErrorLogger.WriteToErrorLog("Error launching privileged process: " + tcs.Task.Result.Message, tcs.Task.Result.StackTrace, "PrivilegedProcess Warning", |
|
|
|
Path.GetFileName(process.StartInfo.FileName)); |
|
|
|
ResetTokens(); |
|
|
|
Thread.Sleep(500 * i); |
|
|
|
tcs = StartThread(process, privilege); |
|
|
|
tcs.Task.Wait(); |
|
|
|
} |
|
|
|
|
|
|
|
if (tcs.Task.Result != null) |
|
|
|
throw new SecurityException("Error launching privileged process.", tcs.Task.Result); |
|
|
|
} |
|
|
|
|
|
|
|
private static TaskCompletionSource<Exception> StartThread(AugmentedProcess.Process process, Privilege privilege) |
|
|
|
{ |
|
|
|
var tcs = new TaskCompletionSource<Exception>(); |
|
|
|
var thread = new Thread(() => |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
switch (privilege) |
|
|
|
{ |
|
|
|
case (Privilege.System): |
|
|
|
GetSystemToken(); |
|
|
|
process.Start(AugmentedProcess.Process.CreateType.RawToken, ref systemToken); |
|
|
|
break; |
|
|
|
case (Privilege.CurrentUser): |
|
|
|
GetUserToken(true); |
|
|
|
process.Start(AugmentedProcess.Process.CreateType.UserToken, ref userToken); |
|
|
|
break; |
|
|
|
case (Privilege.CurrentUserElevated): |
|
|
|
GetElevatedUserToken(); |
|
|
|
process.Start(AugmentedProcess.Process.CreateType.RawToken, ref elevatedUserToken); |
|
|
|
break; |
|
|
|
default: |
|
|
|
throw new ArgumentException("Unexpected."); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception e) |
|
|
|
{ |
|
|
|
tcs.SetResult(e); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
tcs.SetResult(null); |
|
|
|
}); |
|
|
|
thread.Start(); |
|
|
|
return tcs; |
|
|
|
} |
|
|
|
|
|
|
|
private static uint GetUserSession() |
|
|
|
{ |
|
|
|
var sessionId = Win32.WTS.WTSGetActiveConsoleSessionId(); |
|
|
|
if (sessionId != 0xFFFFFFFF) return sessionId; |
|
|
|
IntPtr pSessionInfo = IntPtr.Zero; |
|
|
|
Int32 count = 0; |
|
|
|
if (Win32.WTS.WTSEnumerateSessions((IntPtr)null, 0, 1, ref pSessionInfo, ref count) == 0) |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error enumerating user sessions."); |
|
|
|
Int32 dataSize = Marshal.SizeOf(typeof(Win32.WTS.WTS_SESSION_INFO)); |
|
|
|
Int64 current = (Int64)pSessionInfo; |
|
|
|
for (int i = 0; i < count; i++) |
|
|
|
{ |
|
|
|
Win32.WTS.WTS_SESSION_INFO si = |
|
|
|
(Win32.WTS.WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, |
|
|
|
typeof(Win32.WTS.WTS_SESSION_INFO)); |
|
|
|
current += dataSize; |
|
|
|
if (si.State == Win32.WTS.WTS_CONNECTSTATE_CLASS.WTSActive) |
|
|
|
{ |
|
|
|
sessionId = (uint)si.SessionID; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
Win32.WTS.WTSFreeMemory(pSessionInfo); |
|
|
|
return sessionId; |
|
|
|
} |
|
|
|
|
|
|
|
private static void GetUserToken(bool getPrivileges) |
|
|
|
{ |
|
|
|
if (getPrivileges) |
|
|
|
{ |
|
|
|
GetSystemToken(); |
|
|
|
var result = Win32.Tokens.ImpersonateLoggedOnUser(systemToken); |
|
|
|
if (!result) |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error impersonating system process token."); |
|
|
|
|
|
|
|
Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_ASSIGNPRIMARYTOKEN_NAME); |
|
|
|
Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_INCREASE_QUOTA_NAME); |
|
|
|
} |
|
|
|
|
|
|
|
if (userToken.DangerousGetHandle() != IntPtr.Zero) |
|
|
|
return; |
|
|
|
|
|
|
|
var sessionId = GetUserSession(); |
|
|
|
|
|
|
|
if (Win32.WTS.WTSQueryUserToken(sessionId, out Win32.TokensEx.SafeTokenHandle wtsToken)) |
|
|
|
{ |
|
|
|
if (!Win32.Tokens.DuplicateTokenEx(wtsToken, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, |
|
|
|
IntPtr.Zero, |
|
|
|
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, |
|
|
|
Win32.Tokens.TOKEN_TYPE.TokenPrimary, out userToken)) |
|
|
|
{ |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), |
|
|
|
"Failed to duplicate process token for lsass."); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error fetching active user session token."); |
|
|
|
} |
|
|
|
|
|
|
|
private static void GetElevatedUserToken() |
|
|
|
{ |
|
|
|
GetSystemToken(); |
|
|
|
var result = Win32.Tokens.ImpersonateLoggedOnUser(systemToken); |
|
|
|
|
|
|
|
if (!result) |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error impersonating system process token."); |
|
|
|
|
|
|
|
if (lsassToken.DangerousGetHandle() == IntPtr.Zero) |
|
|
|
{ |
|
|
|
var processHandle = Win32.Process.OpenProcess(Win32.Process.ProcessAccessFlags.QueryLimitedInformation, false, Process.GetProcessesByName("lsass").First().Id); |
|
|
|
if (!Win32.Tokens.OpenProcessToken(processHandle, |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE | |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_ASSIGN_PRIMARY | |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_QUERY | Win32.Tokens.TokenAccessFlags.TOKEN_IMPERSONATE, |
|
|
|
out var tokenHandle)) |
|
|
|
{ |
|
|
|
Win32.CloseHandle(processHandle); |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token for lsass."); |
|
|
|
} |
|
|
|
|
|
|
|
if (!Win32.Tokens.DuplicateTokenEx(tokenHandle, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, |
|
|
|
IntPtr.Zero, |
|
|
|
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, |
|
|
|
Win32.Tokens.TOKEN_TYPE.TokenImpersonation, out lsassToken)) |
|
|
|
{ |
|
|
|
Win32.CloseHandle(processHandle); |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), |
|
|
|
"Failed to duplicate process token for lsass."); |
|
|
|
} |
|
|
|
|
|
|
|
Win32.CloseHandle(processHandle); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
result = Win32.Tokens.ImpersonateLoggedOnUser(lsassToken); |
|
|
|
if (!result) |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error impersonating lsass process token."); |
|
|
|
|
|
|
|
|
|
|
|
Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_ASSIGNPRIMARYTOKEN_NAME); |
|
|
|
Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_INCREASE_QUOTA_NAME); |
|
|
|
|
|
|
|
|
|
|
|
if (elevatedUserToken.DangerousGetHandle() != IntPtr.Zero) |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
var privileges = new[] |
|
|
|
{ |
|
|
|
Win32.Tokens.SE_INCREASE_QUOTA_NAME, |
|
|
|
Win32.Tokens.SE_MACHINE_ACCOUNT_NAME, Win32.Tokens.SE_SECURITY_NAME, |
|
|
|
Win32.Tokens.SE_TAKE_OWNERSHIP_NAME, Win32.Tokens.SE_LOAD_DRIVER_NAME, |
|
|
|
Win32.Tokens.SE_SYSTEM_PROFILE_NAME, Win32.Tokens.SE_SYSTEMTIME_NAME, |
|
|
|
Win32.Tokens.SE_PROFILE_SINGLE_PROCESS_NAME, Win32.Tokens.SE_INCREASE_BASE_PRIORITY_NAME, |
|
|
|
Win32.Tokens.SE_CREATE_PERMANENT_NAME, |
|
|
|
Win32.Tokens.SE_BACKUP_NAME, Win32.Tokens.SE_RESTORE_NAME, Win32.Tokens.SE_SHUTDOWN_NAME, |
|
|
|
Win32.Tokens.SE_DEBUG_NAME, Win32.Tokens.SE_AUDIT_NAME, Win32.Tokens.SE_SYSTEM_ENVIRONMENT_NAME, |
|
|
|
Win32.Tokens.SE_CHANGE_NOTIFY_NAME, |
|
|
|
Win32.Tokens.SE_UNDOCK_NAME, Win32.Tokens.SE_SYNC_AGENT_NAME, |
|
|
|
Win32.Tokens.SE_ENABLE_DELEGATION_NAME, Win32.Tokens.SE_MANAGE_VOLUME_NAME, |
|
|
|
Win32.Tokens.SE_IMPERSONATE_NAME, Win32.Tokens.SE_CREATE_GLOBAL_NAME, |
|
|
|
Win32.Tokens.SE_TRUSTED_CREDMAN_ACCESS_NAME, Win32.Tokens.SE_RELABEL_NAME, |
|
|
|
Win32.Tokens.SE_TIME_ZONE_NAME, |
|
|
|
Win32.Tokens.SE_CREATE_SYMBOLIC_LINK_NAME, Win32.Tokens.SE_DELEGATE_SESSION_USER_IMPERSONATE_NAME |
|
|
|
}; |
|
|
|
var authId = Win32.Tokens.SYSTEM_LUID; |
|
|
|
|
|
|
|
GetUserToken(false); |
|
|
|
|
|
|
|
Win32.Tokens.DuplicateTokenEx(userToken, |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, IntPtr.Zero, |
|
|
|
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, Win32.Tokens.TOKEN_TYPE.TokenPrimary, |
|
|
|
out Win32.TokensEx.SafeTokenHandle dupedUserToken); |
|
|
|
|
|
|
|
Win32.SID.AllocateAndInitializeSid( |
|
|
|
ref Win32.SID.SECURITY_MANDATORY_LABEL_AUTHORITY, |
|
|
|
1, |
|
|
|
(int)Win32.SID.SECURITY_MANDATORY_LABEL.High, |
|
|
|
0, |
|
|
|
0, |
|
|
|
0, |
|
|
|
0, |
|
|
|
0, |
|
|
|
0, |
|
|
|
0, |
|
|
|
out IntPtr integritySid); |
|
|
|
|
|
|
|
var tokenMandatoryLabel = new Win32.Tokens.TOKEN_MANDATORY_LABEL() { |
|
|
|
Label = default(Win32.SID.SID_AND_ATTRIBUTES) |
|
|
|
}; |
|
|
|
|
|
|
|
tokenMandatoryLabel.Label.Attributes = (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_INTEGRITY; |
|
|
|
tokenMandatoryLabel.Label.Sid = integritySid; |
|
|
|
|
|
|
|
var integritySize = Marshal.SizeOf(tokenMandatoryLabel); |
|
|
|
var tokenInfo = Marshal.AllocHGlobal(integritySize); |
|
|
|
|
|
|
|
Marshal.StructureToPtr(tokenMandatoryLabel, tokenInfo, false); |
|
|
|
|
|
|
|
Win32.Tokens.SetTokenInformation( |
|
|
|
dupedUserToken, |
|
|
|
Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, |
|
|
|
tokenInfo, |
|
|
|
integritySize + Win32.SID.GetLengthSid(integritySid)); |
|
|
|
|
|
|
|
|
|
|
|
var pTokenUser = Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenUser); |
|
|
|
var pTokenOwner = |
|
|
|
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenOwner); |
|
|
|
var pTokenPrivileges = |
|
|
|
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenPrivileges); |
|
|
|
var pTokenGroups = |
|
|
|
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenGroups); |
|
|
|
var pTokenPrimaryGroup = |
|
|
|
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenPrimaryGroup); |
|
|
|
var pTokenDefaultDacl = |
|
|
|
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenDefaultDacl); |
|
|
|
var pTokenSource = |
|
|
|
Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenSource); |
|
|
|
|
|
|
|
var tokenUser = |
|
|
|
(Win32.Tokens.TOKEN_USER)Marshal.PtrToStructure(pTokenUser, typeof(Win32.Tokens.TOKEN_USER)); |
|
|
|
if (!Win32.TokensEx.CreateTokenPrivileges(privileges, out var tokenPrivileges)) |
|
|
|
tokenPrivileges = |
|
|
|
(Win32.Tokens.TOKEN_PRIVILEGES)Marshal.PtrToStructure(pTokenPrivileges, |
|
|
|
typeof(Win32.Tokens.TOKEN_PRIVILEGES)); |
|
|
|
var tokenGroups = (Win32.Tokens.TOKEN_GROUPS)Marshal.PtrToStructure( |
|
|
|
pTokenGroups, typeof(Win32.Tokens.TOKEN_GROUPS)); |
|
|
|
var tokenOwner = |
|
|
|
(Win32.Tokens.TOKEN_OWNER)Marshal.PtrToStructure(pTokenOwner, typeof(Win32.Tokens.TOKEN_OWNER)); |
|
|
|
var tokenPrimaryGroup = |
|
|
|
(Win32.Tokens.TOKEN_PRIMARY_GROUP)Marshal.PtrToStructure(pTokenPrimaryGroup, |
|
|
|
typeof(Win32.Tokens.TOKEN_PRIMARY_GROUP)); |
|
|
|
var tokenDefaultDacl = (Win32.Tokens.TOKEN_DEFAULT_DACL)Marshal.PtrToStructure( |
|
|
|
pTokenDefaultDacl, typeof(Win32.Tokens.TOKEN_DEFAULT_DACL)); |
|
|
|
var tokenSource = (Win32.Tokens.TOKEN_SOURCE)Marshal.PtrToStructure( |
|
|
|
pTokenSource, typeof(Win32.Tokens.TOKEN_SOURCE)); |
|
|
|
/* |
|
|
|
for (var idx = 0; idx < tokenPrivileges.PrivilegeCount - 1; idx++) |
|
|
|
{ |
|
|
|
if ((tokenPrivileges.Privileges[idx].Attributes & |
|
|
|
(uint)Win32.Tokens.SE_PRIVILEGE_ATTRIBUTES.SE_PRIVILEGE_ENABLED) != 0) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
if ((tokenPrivileges.Privileges[idx].Attributes & |
|
|
|
(uint)Win32.Tokens.SE_PRIVILEGE_ATTRIBUTES.SE_PRIVILEGE_ENABLED_BY_DEFAULT) != 0) |
|
|
|
{ |
|
|
|
} |
|
|
|
} |
|
|
|
*/ |
|
|
|
|
|
|
|
IntPtr adminsSid = IntPtr.Zero; |
|
|
|
IntPtr localAndAdminSid = IntPtr.Zero; |
|
|
|
|
|
|
|
bool adminsFound = false; |
|
|
|
bool localAndAdminFound = false; |
|
|
|
|
|
|
|
for (var idx = 0; idx < tokenGroups.GroupCount - 1; idx++) |
|
|
|
{ |
|
|
|
Win32.SID.ConvertSidToStringSid(tokenGroups.Groups[idx].Sid, out string strSid); |
|
|
|
if (string.Compare(strSid, Win32.SID.DOMAIN_ALIAS_RID_ADMINS, StringComparison.OrdinalIgnoreCase) == 0) |
|
|
|
{ |
|
|
|
adminsFound = true; |
|
|
|
tokenGroups.Groups[idx].Attributes = (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED | |
|
|
|
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES |
|
|
|
.SE_GROUP_ENABLED_BY_DEFAULT | (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_MANDATORY | (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_OWNER; |
|
|
|
} else if (string.Compare(strSid, Win32.SID.DOMAIN_ALIAS_RID_LOCAL_AND_ADMIN_GROUP, StringComparison.OrdinalIgnoreCase) == 0) |
|
|
|
{ |
|
|
|
localAndAdminFound = true; |
|
|
|
tokenGroups.Groups[idx].Attributes = (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED | |
|
|
|
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES |
|
|
|
.SE_GROUP_ENABLED_BY_DEFAULT | (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_MANDATORY; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!adminsFound) |
|
|
|
{ |
|
|
|
Win32.SID.ConvertStringSidToSid(Win32.SID.DOMAIN_ALIAS_RID_ADMINS, out adminsSid); |
|
|
|
tokenGroups.Groups[tokenGroups.GroupCount].Sid = adminsSid; |
|
|
|
tokenGroups.Groups[tokenGroups.GroupCount].Attributes = |
|
|
|
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED | |
|
|
|
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED_BY_DEFAULT; |
|
|
|
tokenGroups.GroupCount++; |
|
|
|
} |
|
|
|
if (!localAndAdminFound) |
|
|
|
{ |
|
|
|
Win32.SID.ConvertStringSidToSid(Win32.SID.DOMAIN_ALIAS_RID_LOCAL_AND_ADMIN_GROUP, out localAndAdminSid); |
|
|
|
tokenGroups.Groups[tokenGroups.GroupCount].Sid = localAndAdminSid; |
|
|
|
tokenGroups.Groups[tokenGroups.GroupCount].Attributes = |
|
|
|
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED | |
|
|
|
(uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED_BY_DEFAULT; |
|
|
|
tokenGroups.GroupCount++; |
|
|
|
} |
|
|
|
|
|
|
|
var expirationTime = new Win32.LARGE_INTEGER() { QuadPart = -1L }; |
|
|
|
var sqos = new Win32.Tokens.SECURITY_QUALITY_OF_SERVICE( |
|
|
|
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, Win32.Tokens.SECURITY_STATIC_TRACKING, |
|
|
|
0); |
|
|
|
var oa = new Win32.Tokens.OBJECT_ATTRIBUTES(string.Empty, 0) { }; |
|
|
|
var pSqos = Marshal.AllocHGlobal(Marshal.SizeOf(sqos)); |
|
|
|
Marshal.StructureToPtr(sqos, pSqos, true); |
|
|
|
oa.SecurityQualityOfService = pSqos; |
|
|
|
|
|
|
|
var status = Win32.Tokens.ZwCreateToken(out elevatedUserToken, |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, ref oa, Win32.Tokens.TOKEN_TYPE.TokenPrimary, |
|
|
|
ref authId, ref expirationTime, ref tokenUser, ref tokenGroups, ref tokenPrivileges, ref tokenOwner, |
|
|
|
ref tokenPrimaryGroup, ref tokenDefaultDacl, ref tokenSource); |
|
|
|
|
|
|
|
Win32.LocalFree(pTokenUser); |
|
|
|
Win32.LocalFree(pTokenOwner); |
|
|
|
Win32.LocalFree(pTokenGroups); |
|
|
|
Win32.LocalFree(pTokenDefaultDacl); |
|
|
|
Win32.LocalFree(pTokenPrivileges); |
|
|
|
Win32.LocalFree(pTokenPrimaryGroup); |
|
|
|
|
|
|
|
if (adminsSid != IntPtr.Zero) |
|
|
|
Win32.SID.FreeSid(adminsSid); |
|
|
|
if (localAndAdminSid != IntPtr.Zero) |
|
|
|
Win32.SID.FreeSid(localAndAdminSid); |
|
|
|
if (integritySid != IntPtr.Zero) |
|
|
|
Win32.SID.FreeSid(integritySid); |
|
|
|
|
|
|
|
if (status != 0) |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error creating elevated user token: " + status); |
|
|
|
} |
|
|
|
|
|
|
|
public static void GetSystemToken() |
|
|
|
{ |
|
|
|
if (systemToken.DangerousGetHandle() != IntPtr.Zero) |
|
|
|
return; |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
var processHandle = Win32.Process.OpenProcess(Win32.Process.ProcessAccessFlags.QueryLimitedInformation, false, Process.GetProcessesByName("winlogon").First().Id); |
|
|
|
if (!Win32.Tokens.OpenProcessToken(processHandle, |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE | Win32.Tokens.TokenAccessFlags.TOKEN_ASSIGN_PRIMARY | |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_QUERY | Win32.Tokens.TokenAccessFlags.TOKEN_IMPERSONATE, |
|
|
|
out var tokenHandle)) |
|
|
|
{ |
|
|
|
Win32.CloseHandle(processHandle); |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token for winlogon."); |
|
|
|
} |
|
|
|
|
|
|
|
if (!Win32.Tokens.DuplicateTokenEx(tokenHandle, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, IntPtr.Zero, |
|
|
|
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, |
|
|
|
Win32.Tokens.TOKEN_TYPE.TokenPrimary, out systemToken)) |
|
|
|
{ |
|
|
|
Win32.CloseHandle(processHandle); |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), |
|
|
|
"Failed to duplicate process token for winlogon."); |
|
|
|
} |
|
|
|
|
|
|
|
Win32.CloseHandle(processHandle); |
|
|
|
} |
|
|
|
catch (Exception e) |
|
|
|
{ |
|
|
|
var sessionId = GetUserSession(); |
|
|
|
int dwLsassPID = -1; |
|
|
|
int dwWinLogonPID = -1; |
|
|
|
Win32.WTS.WTS_PROCESS_INFO[] pProcesses; |
|
|
|
IntPtr pProcessInfo = IntPtr.Zero; |
|
|
|
int dwProcessCount = 0; |
|
|
|
if (Win32.WTS.WTSEnumerateProcesses((IntPtr)null, 0, 1, ref pProcessInfo, ref dwProcessCount)) |
|
|
|
{ |
|
|
|
IntPtr pMemory = pProcessInfo; |
|
|
|
pProcesses = new Win32.WTS.WTS_PROCESS_INFO[dwProcessCount]; |
|
|
|
for (int i = 0; i < dwProcessCount; i++) |
|
|
|
{ |
|
|
|
pProcesses[i] = |
|
|
|
(Win32.WTS.WTS_PROCESS_INFO)Marshal.PtrToStructure(pProcessInfo, |
|
|
|
typeof(Win32.WTS.WTS_PROCESS_INFO)); |
|
|
|
pProcessInfo = (IntPtr)((long)pProcessInfo + Marshal.SizeOf(pProcesses[i])); |
|
|
|
var processName = Marshal.PtrToStringAnsi(pProcesses[i].ProcessName); |
|
|
|
Win32.SID.ConvertSidToStringSid(pProcesses[i].UserSid, out string sid); |
|
|
|
string strSid; |
|
|
|
if (processName == null || pProcesses[i].UserSid == default || sid != "S-1-5-18") continue; |
|
|
|
if ((-1 == dwLsassPID) && (0 == pProcesses[i].SessionID) && (processName == "lsass.exe")) |
|
|
|
{ |
|
|
|
dwLsassPID = pProcesses[i].ProcessID; |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if ((-1 == dwWinLogonPID) && (sessionId == pProcesses[i].SessionID) && |
|
|
|
(processName == "winlogon.exe")) |
|
|
|
{ |
|
|
|
dwWinLogonPID = pProcesses[i].ProcessID; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Win32.WTS.WTSFreeMemory(pMemory); |
|
|
|
} |
|
|
|
|
|
|
|
IntPtr systemProcessHandle = IntPtr.Zero; |
|
|
|
try |
|
|
|
{ |
|
|
|
systemProcessHandle = Process.GetProcessById(dwLsassPID).Handle; |
|
|
|
} |
|
|
|
catch |
|
|
|
{ |
|
|
|
systemProcessHandle = Process.GetProcessById(dwWinLogonPID).Handle; |
|
|
|
} |
|
|
|
|
|
|
|
if (!Win32.Tokens.OpenProcessToken(systemProcessHandle, Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE, |
|
|
|
out Win32.TokensEx.SafeTokenHandle token)) |
|
|
|
{ |
|
|
|
Win32.CloseHandle(systemProcessHandle); |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token."); |
|
|
|
} |
|
|
|
|
|
|
|
if (!Win32.Tokens.DuplicateTokenEx(token, Win32.Tokens.TokenAccessFlags.MAXIMUM_ALLOWED, IntPtr.Zero, |
|
|
|
Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, |
|
|
|
Win32.Tokens.TOKEN_TYPE.TokenPrimary, out systemToken)) |
|
|
|
{ |
|
|
|
Win32.CloseHandle(systemProcessHandle); |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to duplicate process token."); |
|
|
|
} |
|
|
|
|
|
|
|
Win32.CloseHandle(systemProcessHandle); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static Win32.TokensEx.SafeTokenHandle GetCurrentProcessToken() |
|
|
|
{ |
|
|
|
if (!Win32.Tokens.OpenProcessToken(Win32.Process.GetCurrentProcess(), |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_READ, out Win32.TokensEx.SafeTokenHandle token)) |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Error opening token for current process."); |
|
|
|
return token; |
|
|
|
} |
|
|
|
|
|
|
|
private static Win32.TokensEx.SafeTokenHandle GetProcessTokenByName(string name, bool impersonation) |
|
|
|
{ |
|
|
|
var processHandle = Process.GetProcessesByName(name).First().Handle; |
|
|
|
if (!Win32.Tokens.OpenProcessToken(processHandle, |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE | Win32.Tokens.TokenAccessFlags.TOKEN_ASSIGN_PRIMARY | |
|
|
|
Win32.Tokens.TokenAccessFlags.TOKEN_QUERY | Win32.Tokens.TokenAccessFlags.TOKEN_IMPERSONATE, |
|
|
|
out var tokenHandle)) |
|
|
|
{ |
|
|
|
Win32.CloseHandle(processHandle); |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token for " + name + "."); |
|
|
|
} |
|
|
|
|
|
|
|
if (!Win32.Tokens.DuplicateTokenEx(tokenHandle, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, IntPtr.Zero, |
|
|
|
impersonation ? Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation : Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, |
|
|
|
impersonation ? Win32.Tokens.TOKEN_TYPE.TokenImpersonation : Win32.Tokens.TOKEN_TYPE.TokenPrimary, out Win32.TokensEx.SafeTokenHandle handle)) |
|
|
|
{ |
|
|
|
Win32.CloseHandle(processHandle); |
|
|
|
throw new Win32Exception(Marshal.GetLastWin32Error(), |
|
|
|
"Failed to duplicate process token for " + name + "."); |
|
|
|
} |
|
|
|
|
|
|
|
Win32.CloseHandle(processHandle); |
|
|
|
return handle; |
|
|
|
} } |
|
|
|
} |