CLI tool for running Playbooks
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

505 lines
25 KiB

6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Runtime.ConstrainedExecution;
  9. using System.Runtime.InteropServices;
  10. using System.Security;
  11. using System.Text;
  12. using System.Threading;
  13. using System.Threading.Tasks;
  14. using Microsoft.Win32.SafeHandles;
  15. using TrustedUninstaller.Shared.Actions;
  16. namespace TrustedUninstaller.Shared
  17. {
  18. public class ProcessPrivilege
  19. {
  20. private static Win32.TokensEx.SafeTokenHandle userToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  21. private static Win32.TokensEx.SafeTokenHandle elevatedUserToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  22. private static Win32.TokensEx.SafeTokenHandle systemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  23. private static Win32.TokensEx.SafeTokenHandle impsersonatedSystemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  24. private static Win32.TokensEx.SafeTokenHandle lsassToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  25. internal static void ResetTokens()
  26. {
  27. elevatedUserToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  28. lsassToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  29. systemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  30. impsersonatedSystemToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  31. userToken = new Win32.TokensEx.SafeTokenHandle(IntPtr.Zero);
  32. }
  33. public static void StartPrivilegedTask(AugmentedProcess.Process process, Privilege privilege)
  34. {
  35. var tcs = StartThread(process, privilege);
  36. tcs.Task.Wait();
  37. for (int i = 0; tcs.Task.Result != null && i <= 3; i++)
  38. {
  39. ErrorLogger.WriteToErrorLog("Error launching privileged process: " + tcs.Task.Result.Message, tcs.Task.Result.StackTrace, "PrivilegedProcess Warning",
  40. Path.GetFileName(process.StartInfo.FileName));
  41. ResetTokens();
  42. Thread.Sleep(500 * i);
  43. tcs = StartThread(process, privilege);
  44. tcs.Task.Wait();
  45. }
  46. if (tcs.Task.Result != null)
  47. throw new SecurityException("Error launching privileged process.", tcs.Task.Result);
  48. }
  49. private static TaskCompletionSource<Exception> StartThread(AugmentedProcess.Process process, Privilege privilege)
  50. {
  51. var tcs = new TaskCompletionSource<Exception>();
  52. var thread = new Thread(() =>
  53. {
  54. try
  55. {
  56. switch (privilege)
  57. {
  58. case (Privilege.System):
  59. GetSystemToken();
  60. process.Start(AugmentedProcess.Process.CreateType.RawToken, ref systemToken);
  61. break;
  62. case (Privilege.CurrentUser):
  63. GetUserToken(true);
  64. process.Start(AugmentedProcess.Process.CreateType.UserToken, ref userToken);
  65. break;
  66. case (Privilege.CurrentUserElevated):
  67. GetElevatedUserToken();
  68. process.Start(AugmentedProcess.Process.CreateType.RawToken, ref elevatedUserToken);
  69. break;
  70. default:
  71. throw new ArgumentException("Unexpected.");
  72. }
  73. }
  74. catch (Exception e)
  75. {
  76. tcs.SetResult(e);
  77. return;
  78. }
  79. tcs.SetResult(null);
  80. });
  81. thread.Start();
  82. return tcs;
  83. }
  84. private static uint GetUserSession()
  85. {
  86. var sessionId = Win32.WTS.WTSGetActiveConsoleSessionId();
  87. if (sessionId != 0xFFFFFFFF) return sessionId;
  88. IntPtr pSessionInfo = IntPtr.Zero;
  89. Int32 count = 0;
  90. if (Win32.WTS.WTSEnumerateSessions((IntPtr)null, 0, 1, ref pSessionInfo, ref count) == 0)
  91. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error enumerating user sessions.");
  92. Int32 dataSize = Marshal.SizeOf(typeof(Win32.WTS.WTS_SESSION_INFO));
  93. Int64 current = (Int64)pSessionInfo;
  94. for (int i = 0; i < count; i++)
  95. {
  96. Win32.WTS.WTS_SESSION_INFO si =
  97. (Win32.WTS.WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current,
  98. typeof(Win32.WTS.WTS_SESSION_INFO));
  99. current += dataSize;
  100. if (si.State == Win32.WTS.WTS_CONNECTSTATE_CLASS.WTSActive)
  101. {
  102. sessionId = (uint)si.SessionID;
  103. break;
  104. }
  105. }
  106. Win32.WTS.WTSFreeMemory(pSessionInfo);
  107. return sessionId;
  108. }
  109. private static void GetUserToken(bool getPrivileges)
  110. {
  111. if (getPrivileges)
  112. {
  113. GetSystemToken();
  114. var result = Win32.Tokens.ImpersonateLoggedOnUser(systemToken);
  115. if (!result)
  116. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error impersonating system process token.");
  117. Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_ASSIGNPRIMARYTOKEN_NAME);
  118. Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_INCREASE_QUOTA_NAME);
  119. }
  120. if (userToken.DangerousGetHandle() != IntPtr.Zero)
  121. return;
  122. var sessionId = GetUserSession();
  123. if (Win32.WTS.WTSQueryUserToken(sessionId, out Win32.TokensEx.SafeTokenHandle wtsToken))
  124. {
  125. if (!Win32.Tokens.DuplicateTokenEx(wtsToken, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS,
  126. IntPtr.Zero,
  127. Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
  128. Win32.Tokens.TOKEN_TYPE.TokenPrimary, out userToken))
  129. {
  130. throw new Win32Exception(Marshal.GetLastWin32Error(),
  131. "Failed to duplicate process token for lsass.");
  132. }
  133. return;
  134. }
  135. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error fetching active user session token.");
  136. }
  137. private static void GetElevatedUserToken()
  138. {
  139. GetSystemToken();
  140. var result = Win32.Tokens.ImpersonateLoggedOnUser(systemToken);
  141. if (!result)
  142. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error impersonating system process token.");
  143. if (lsassToken.DangerousGetHandle() == IntPtr.Zero)
  144. {
  145. var processHandle = Win32.Process.OpenProcess(Win32.Process.ProcessAccessFlags.QueryLimitedInformation, false, Process.GetProcessesByName("lsass").First().Id);
  146. if (!Win32.Tokens.OpenProcessToken(processHandle,
  147. Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE |
  148. Win32.Tokens.TokenAccessFlags.TOKEN_ASSIGN_PRIMARY |
  149. Win32.Tokens.TokenAccessFlags.TOKEN_QUERY | Win32.Tokens.TokenAccessFlags.TOKEN_IMPERSONATE,
  150. out var tokenHandle))
  151. {
  152. Win32.CloseHandle(processHandle);
  153. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token for lsass.");
  154. }
  155. if (!Win32.Tokens.DuplicateTokenEx(tokenHandle, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS,
  156. IntPtr.Zero,
  157. Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
  158. Win32.Tokens.TOKEN_TYPE.TokenImpersonation, out lsassToken))
  159. {
  160. Win32.CloseHandle(processHandle);
  161. throw new Win32Exception(Marshal.GetLastWin32Error(),
  162. "Failed to duplicate process token for lsass.");
  163. }
  164. Win32.CloseHandle(processHandle);
  165. }
  166. result = Win32.Tokens.ImpersonateLoggedOnUser(lsassToken);
  167. if (!result)
  168. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error impersonating lsass process token.");
  169. Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_ASSIGNPRIMARYTOKEN_NAME);
  170. Win32.TokensEx.AdjustCurrentPrivilege(Win32.Tokens.SE_INCREASE_QUOTA_NAME);
  171. if (elevatedUserToken.DangerousGetHandle() != IntPtr.Zero)
  172. return;
  173. var privileges = new[]
  174. {
  175. Win32.Tokens.SE_INCREASE_QUOTA_NAME,
  176. Win32.Tokens.SE_MACHINE_ACCOUNT_NAME, Win32.Tokens.SE_SECURITY_NAME,
  177. Win32.Tokens.SE_TAKE_OWNERSHIP_NAME, Win32.Tokens.SE_LOAD_DRIVER_NAME,
  178. Win32.Tokens.SE_SYSTEM_PROFILE_NAME, Win32.Tokens.SE_SYSTEMTIME_NAME,
  179. Win32.Tokens.SE_PROFILE_SINGLE_PROCESS_NAME, Win32.Tokens.SE_INCREASE_BASE_PRIORITY_NAME,
  180. Win32.Tokens.SE_CREATE_PERMANENT_NAME,
  181. Win32.Tokens.SE_BACKUP_NAME, Win32.Tokens.SE_RESTORE_NAME, Win32.Tokens.SE_SHUTDOWN_NAME,
  182. Win32.Tokens.SE_DEBUG_NAME, Win32.Tokens.SE_AUDIT_NAME, Win32.Tokens.SE_SYSTEM_ENVIRONMENT_NAME,
  183. Win32.Tokens.SE_CHANGE_NOTIFY_NAME,
  184. Win32.Tokens.SE_UNDOCK_NAME, Win32.Tokens.SE_SYNC_AGENT_NAME,
  185. Win32.Tokens.SE_ENABLE_DELEGATION_NAME, Win32.Tokens.SE_MANAGE_VOLUME_NAME,
  186. Win32.Tokens.SE_IMPERSONATE_NAME, Win32.Tokens.SE_CREATE_GLOBAL_NAME,
  187. Win32.Tokens.SE_TRUSTED_CREDMAN_ACCESS_NAME, Win32.Tokens.SE_RELABEL_NAME,
  188. Win32.Tokens.SE_TIME_ZONE_NAME,
  189. Win32.Tokens.SE_CREATE_SYMBOLIC_LINK_NAME, Win32.Tokens.SE_DELEGATE_SESSION_USER_IMPERSONATE_NAME
  190. };
  191. var authId = Win32.Tokens.SYSTEM_LUID;
  192. GetUserToken(false);
  193. Win32.Tokens.DuplicateTokenEx(userToken,
  194. Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, IntPtr.Zero,
  195. Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, Win32.Tokens.TOKEN_TYPE.TokenPrimary,
  196. out Win32.TokensEx.SafeTokenHandle dupedUserToken);
  197. Win32.SID.AllocateAndInitializeSid(
  198. ref Win32.SID.SECURITY_MANDATORY_LABEL_AUTHORITY,
  199. 1,
  200. (int)Win32.SID.SECURITY_MANDATORY_LABEL.High,
  201. 0,
  202. 0,
  203. 0,
  204. 0,
  205. 0,
  206. 0,
  207. 0,
  208. out IntPtr integritySid);
  209. var tokenMandatoryLabel = new Win32.Tokens.TOKEN_MANDATORY_LABEL() {
  210. Label = default(Win32.SID.SID_AND_ATTRIBUTES)
  211. };
  212. tokenMandatoryLabel.Label.Attributes = (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_INTEGRITY;
  213. tokenMandatoryLabel.Label.Sid = integritySid;
  214. var integritySize = Marshal.SizeOf(tokenMandatoryLabel);
  215. var tokenInfo = Marshal.AllocHGlobal(integritySize);
  216. Marshal.StructureToPtr(tokenMandatoryLabel, tokenInfo, false);
  217. Win32.Tokens.SetTokenInformation(
  218. dupedUserToken,
  219. Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenIntegrityLevel,
  220. tokenInfo,
  221. integritySize + Win32.SID.GetLengthSid(integritySid));
  222. var pTokenUser = Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenUser);
  223. var pTokenOwner =
  224. Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenOwner);
  225. var pTokenPrivileges =
  226. Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenPrivileges);
  227. var pTokenGroups =
  228. Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenGroups);
  229. var pTokenPrimaryGroup =
  230. Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenPrimaryGroup);
  231. var pTokenDefaultDacl =
  232. Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenDefaultDacl);
  233. var pTokenSource =
  234. Win32.TokensEx.GetInfoFromToken(dupedUserToken, Win32.Tokens.TOKEN_INFORMATION_CLASS.TokenSource);
  235. var tokenUser =
  236. (Win32.Tokens.TOKEN_USER)Marshal.PtrToStructure(pTokenUser, typeof(Win32.Tokens.TOKEN_USER));
  237. if (!Win32.TokensEx.CreateTokenPrivileges(privileges, out var tokenPrivileges))
  238. tokenPrivileges =
  239. (Win32.Tokens.TOKEN_PRIVILEGES)Marshal.PtrToStructure(pTokenPrivileges,
  240. typeof(Win32.Tokens.TOKEN_PRIVILEGES));
  241. var tokenGroups = (Win32.Tokens.TOKEN_GROUPS)Marshal.PtrToStructure(
  242. pTokenGroups, typeof(Win32.Tokens.TOKEN_GROUPS));
  243. var tokenOwner =
  244. (Win32.Tokens.TOKEN_OWNER)Marshal.PtrToStructure(pTokenOwner, typeof(Win32.Tokens.TOKEN_OWNER));
  245. var tokenPrimaryGroup =
  246. (Win32.Tokens.TOKEN_PRIMARY_GROUP)Marshal.PtrToStructure(pTokenPrimaryGroup,
  247. typeof(Win32.Tokens.TOKEN_PRIMARY_GROUP));
  248. var tokenDefaultDacl = (Win32.Tokens.TOKEN_DEFAULT_DACL)Marshal.PtrToStructure(
  249. pTokenDefaultDacl, typeof(Win32.Tokens.TOKEN_DEFAULT_DACL));
  250. var tokenSource = (Win32.Tokens.TOKEN_SOURCE)Marshal.PtrToStructure(
  251. pTokenSource, typeof(Win32.Tokens.TOKEN_SOURCE));
  252. /*
  253. for (var idx = 0; idx < tokenPrivileges.PrivilegeCount - 1; idx++)
  254. {
  255. if ((tokenPrivileges.Privileges[idx].Attributes &
  256. (uint)Win32.Tokens.SE_PRIVILEGE_ATTRIBUTES.SE_PRIVILEGE_ENABLED) != 0)
  257. {
  258. }
  259. if ((tokenPrivileges.Privileges[idx].Attributes &
  260. (uint)Win32.Tokens.SE_PRIVILEGE_ATTRIBUTES.SE_PRIVILEGE_ENABLED_BY_DEFAULT) != 0)
  261. {
  262. }
  263. }
  264. */
  265. IntPtr adminsSid = IntPtr.Zero;
  266. IntPtr localAndAdminSid = IntPtr.Zero;
  267. bool adminsFound = false;
  268. bool localAndAdminFound = false;
  269. for (var idx = 0; idx < tokenGroups.GroupCount - 1; idx++)
  270. {
  271. Win32.SID.ConvertSidToStringSid(tokenGroups.Groups[idx].Sid, out string strSid);
  272. if (string.Compare(strSid, Win32.SID.DOMAIN_ALIAS_RID_ADMINS, StringComparison.OrdinalIgnoreCase) == 0)
  273. {
  274. adminsFound = true;
  275. tokenGroups.Groups[idx].Attributes = (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED |
  276. (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES
  277. .SE_GROUP_ENABLED_BY_DEFAULT | (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_MANDATORY | (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_OWNER;
  278. } else if (string.Compare(strSid, Win32.SID.DOMAIN_ALIAS_RID_LOCAL_AND_ADMIN_GROUP, StringComparison.OrdinalIgnoreCase) == 0)
  279. {
  280. localAndAdminFound = true;
  281. tokenGroups.Groups[idx].Attributes = (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED |
  282. (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES
  283. .SE_GROUP_ENABLED_BY_DEFAULT | (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_MANDATORY;
  284. }
  285. }
  286. if (!adminsFound)
  287. {
  288. Win32.SID.ConvertStringSidToSid(Win32.SID.DOMAIN_ALIAS_RID_ADMINS, out adminsSid);
  289. tokenGroups.Groups[tokenGroups.GroupCount].Sid = adminsSid;
  290. tokenGroups.Groups[tokenGroups.GroupCount].Attributes =
  291. (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED |
  292. (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED_BY_DEFAULT;
  293. tokenGroups.GroupCount++;
  294. }
  295. if (!localAndAdminFound)
  296. {
  297. Win32.SID.ConvertStringSidToSid(Win32.SID.DOMAIN_ALIAS_RID_LOCAL_AND_ADMIN_GROUP, out localAndAdminSid);
  298. tokenGroups.Groups[tokenGroups.GroupCount].Sid = localAndAdminSid;
  299. tokenGroups.Groups[tokenGroups.GroupCount].Attributes =
  300. (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED |
  301. (uint)Win32.Tokens.SE_GROUP_ATTRIBUTES.SE_GROUP_ENABLED_BY_DEFAULT;
  302. tokenGroups.GroupCount++;
  303. }
  304. var expirationTime = new Win32.LARGE_INTEGER() { QuadPart = -1L };
  305. var sqos = new Win32.Tokens.SECURITY_QUALITY_OF_SERVICE(
  306. Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, Win32.Tokens.SECURITY_STATIC_TRACKING,
  307. 0);
  308. var oa = new Win32.Tokens.OBJECT_ATTRIBUTES(string.Empty, 0) { };
  309. var pSqos = Marshal.AllocHGlobal(Marshal.SizeOf(sqos));
  310. Marshal.StructureToPtr(sqos, pSqos, true);
  311. oa.SecurityQualityOfService = pSqos;
  312. var status = Win32.Tokens.ZwCreateToken(out elevatedUserToken,
  313. Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, ref oa, Win32.Tokens.TOKEN_TYPE.TokenPrimary,
  314. ref authId, ref expirationTime, ref tokenUser, ref tokenGroups, ref tokenPrivileges, ref tokenOwner,
  315. ref tokenPrimaryGroup, ref tokenDefaultDacl, ref tokenSource);
  316. Win32.LocalFree(pTokenUser);
  317. Win32.LocalFree(pTokenOwner);
  318. Win32.LocalFree(pTokenGroups);
  319. Win32.LocalFree(pTokenDefaultDacl);
  320. Win32.LocalFree(pTokenPrivileges);
  321. Win32.LocalFree(pTokenPrimaryGroup);
  322. if (adminsSid != IntPtr.Zero)
  323. Win32.SID.FreeSid(adminsSid);
  324. if (localAndAdminSid != IntPtr.Zero)
  325. Win32.SID.FreeSid(localAndAdminSid);
  326. if (integritySid != IntPtr.Zero)
  327. Win32.SID.FreeSid(integritySid);
  328. if (status != 0)
  329. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error creating elevated user token: " + status);
  330. }
  331. public static void GetSystemToken()
  332. {
  333. if (systemToken.DangerousGetHandle() != IntPtr.Zero)
  334. return;
  335. try
  336. {
  337. var processHandle = Win32.Process.OpenProcess(Win32.Process.ProcessAccessFlags.QueryLimitedInformation, false, Process.GetProcessesByName("winlogon").First().Id);
  338. if (!Win32.Tokens.OpenProcessToken(processHandle,
  339. Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE | Win32.Tokens.TokenAccessFlags.TOKEN_ASSIGN_PRIMARY |
  340. Win32.Tokens.TokenAccessFlags.TOKEN_QUERY | Win32.Tokens.TokenAccessFlags.TOKEN_IMPERSONATE,
  341. out var tokenHandle))
  342. {
  343. Win32.CloseHandle(processHandle);
  344. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token for winlogon.");
  345. }
  346. if (!Win32.Tokens.DuplicateTokenEx(tokenHandle, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, IntPtr.Zero,
  347. Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
  348. Win32.Tokens.TOKEN_TYPE.TokenPrimary, out systemToken))
  349. {
  350. Win32.CloseHandle(processHandle);
  351. throw new Win32Exception(Marshal.GetLastWin32Error(),
  352. "Failed to duplicate process token for winlogon.");
  353. }
  354. Win32.CloseHandle(processHandle);
  355. }
  356. catch (Exception e)
  357. {
  358. var sessionId = GetUserSession();
  359. int dwLsassPID = -1;
  360. int dwWinLogonPID = -1;
  361. Win32.WTS.WTS_PROCESS_INFO[] pProcesses;
  362. IntPtr pProcessInfo = IntPtr.Zero;
  363. int dwProcessCount = 0;
  364. if (Win32.WTS.WTSEnumerateProcesses((IntPtr)null, 0, 1, ref pProcessInfo, ref dwProcessCount))
  365. {
  366. IntPtr pMemory = pProcessInfo;
  367. pProcesses = new Win32.WTS.WTS_PROCESS_INFO[dwProcessCount];
  368. for (int i = 0; i < dwProcessCount; i++)
  369. {
  370. pProcesses[i] =
  371. (Win32.WTS.WTS_PROCESS_INFO)Marshal.PtrToStructure(pProcessInfo,
  372. typeof(Win32.WTS.WTS_PROCESS_INFO));
  373. pProcessInfo = (IntPtr)((long)pProcessInfo + Marshal.SizeOf(pProcesses[i]));
  374. var processName = Marshal.PtrToStringAnsi(pProcesses[i].ProcessName);
  375. Win32.SID.ConvertSidToStringSid(pProcesses[i].UserSid, out string sid);
  376. string strSid;
  377. if (processName == null || pProcesses[i].UserSid == default || sid != "S-1-5-18") continue;
  378. if ((-1 == dwLsassPID) && (0 == pProcesses[i].SessionID) && (processName == "lsass.exe"))
  379. {
  380. dwLsassPID = pProcesses[i].ProcessID;
  381. continue;
  382. }
  383. if ((-1 == dwWinLogonPID) && (sessionId == pProcesses[i].SessionID) &&
  384. (processName == "winlogon.exe"))
  385. {
  386. dwWinLogonPID = pProcesses[i].ProcessID;
  387. continue;
  388. }
  389. }
  390. Win32.WTS.WTSFreeMemory(pMemory);
  391. }
  392. IntPtr systemProcessHandle = IntPtr.Zero;
  393. try
  394. {
  395. systemProcessHandle = Process.GetProcessById(dwLsassPID).Handle;
  396. }
  397. catch
  398. {
  399. systemProcessHandle = Process.GetProcessById(dwWinLogonPID).Handle;
  400. }
  401. if (!Win32.Tokens.OpenProcessToken(systemProcessHandle, Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE,
  402. out Win32.TokensEx.SafeTokenHandle token))
  403. {
  404. Win32.CloseHandle(systemProcessHandle);
  405. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token.");
  406. }
  407. if (!Win32.Tokens.DuplicateTokenEx(token, Win32.Tokens.TokenAccessFlags.MAXIMUM_ALLOWED, IntPtr.Zero,
  408. Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
  409. Win32.Tokens.TOKEN_TYPE.TokenPrimary, out systemToken))
  410. {
  411. Win32.CloseHandle(systemProcessHandle);
  412. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to duplicate process token.");
  413. }
  414. Win32.CloseHandle(systemProcessHandle);
  415. }
  416. }
  417. public static Win32.TokensEx.SafeTokenHandle GetCurrentProcessToken()
  418. {
  419. if (!Win32.Tokens.OpenProcessToken(Win32.Process.GetCurrentProcess(),
  420. Win32.Tokens.TokenAccessFlags.TOKEN_READ, out Win32.TokensEx.SafeTokenHandle token))
  421. throw new Win32Exception(Marshal.GetLastWin32Error(), "Error opening token for current process.");
  422. return token;
  423. }
  424. private static Win32.TokensEx.SafeTokenHandle GetProcessTokenByName(string name, bool impersonation)
  425. {
  426. var processHandle = Process.GetProcessesByName(name).First().Handle;
  427. if (!Win32.Tokens.OpenProcessToken(processHandle,
  428. Win32.Tokens.TokenAccessFlags.TOKEN_DUPLICATE | Win32.Tokens.TokenAccessFlags.TOKEN_ASSIGN_PRIMARY |
  429. Win32.Tokens.TokenAccessFlags.TOKEN_QUERY | Win32.Tokens.TokenAccessFlags.TOKEN_IMPERSONATE,
  430. out var tokenHandle))
  431. {
  432. Win32.CloseHandle(processHandle);
  433. throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to open process token for " + name + ".");
  434. }
  435. if (!Win32.Tokens.DuplicateTokenEx(tokenHandle, Win32.Tokens.TokenAccessFlags.TOKEN_ALL_ACCESS, IntPtr.Zero,
  436. impersonation ? Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation : Win32.Tokens.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
  437. impersonation ? Win32.Tokens.TOKEN_TYPE.TokenImpersonation : Win32.Tokens.TOKEN_TYPE.TokenPrimary, out Win32.TokensEx.SafeTokenHandle handle))
  438. {
  439. Win32.CloseHandle(processHandle);
  440. throw new Win32Exception(Marshal.GetLastWin32Error(),
  441. "Failed to duplicate process token for " + name + ".");
  442. }
  443. Win32.CloseHandle(processHandle);
  444. return handle;
  445. } }
  446. }