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.

539 lines
20 KiB

1 year ago
6 months ago
1 year ago
10 months ago
6 months ago
1 year ago
10 months ago
10 months ago
10 months ago
1 year ago
6 months ago
1 year ago
1 year ago
10 months ago
1 year ago
6 months ago
6 months ago
1 year ago
1 year ago
6 months ago
1 year ago
10 months ago
1 year ago
1 year ago
1 year ago
10 months ago
10 months ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
6 months ago
1 year ago
6 months ago
1 year ago
6 months ago
1 year ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Management;
  8. using System.Net;
  9. using System.Reflection;
  10. using System.Runtime.InteropServices;
  11. using System.Text;
  12. using System.Threading;
  13. using System.Threading.Tasks;
  14. using System.Windows;
  15. using System.Xml.Serialization;
  16. using Microsoft.Win32;
  17. using TrustedUninstaller.Shared;
  18. using TrustedUninstaller.Shared.Actions;
  19. using TrustedUninstaller.Shared.Tasks;
  20. using WUApiLib;
  21. namespace TrustedUninstaller.Shared
  22. {
  23. public static class Requirements
  24. {
  25. [Serializable]
  26. public enum Requirement
  27. {
  28. [XmlEnum("Internet")]
  29. Internet = 0,
  30. [XmlEnum("NoInternet")]
  31. NoInternet = 1,
  32. [XmlEnum("DefenderDisabled")]
  33. DefenderDisabled = 2,
  34. [XmlEnum("DefenderToggled")]
  35. DefenderToggled = 3,
  36. [XmlEnum("NoPendingUpdates")]
  37. NoPendingUpdates = 4,
  38. [XmlEnum("Activation")]
  39. Activation = 5,
  40. [XmlEnum("NoAntivirus")]
  41. NoAntivirus = 6,
  42. [XmlEnum("LocalAccounts")]
  43. LocalAccounts = 11,
  44. [XmlEnum("PasswordSet")]
  45. PasswordSet = 11,
  46. [XmlEnum("AdministratorPasswordSet")]
  47. AdministratorPasswordSet = 8,
  48. [XmlEnum("PluggedIn")]
  49. PluggedIn = 9,
  50. [XmlEnum("NoTweakware")]
  51. NoTweakware = 10,
  52. }
  53. public static async Task<Requirement[]> MetRequirements(this Requirement[] requirements, bool checkNoPendingUpdate = false)
  54. {
  55. var requirementEnum = (Requirement[])Enum.GetValues(typeof(Requirement));
  56. if (requirements == null)
  57. {
  58. return requirementEnum;
  59. }
  60. // Add all requirements that are not included
  61. var metRequirements = requirementEnum.Except(requirements).ToList();
  62. if (requirements.Contains(Requirement.Internet))
  63. if (await new Internet().IsMet()) metRequirements.Add(Requirement.Internet);
  64. else metRequirements.Add(Requirement.NoInternet);
  65. if (requirements.Contains(Requirement.NoAntivirus))
  66. if (true) metRequirements.Add(Requirement.NoAntivirus);
  67. // Handled upstream
  68. if (requirements.Contains(Requirement.Activation))
  69. if (true) metRequirements.Add(Requirement.Activation);
  70. if (requirements.Contains(Requirement.DefenderDisabled))
  71. if (await new DefenderDisabled().IsMet()) metRequirements.Add(Requirement.DefenderDisabled);
  72. if (requirements.Contains(Requirement.PluggedIn))
  73. if (await new Battery().IsMet()) metRequirements.Add(Requirement.PluggedIn);
  74. if (requirements.Contains(Requirement.NoPendingUpdates))
  75. if (!checkNoPendingUpdate || (new [] {
  76. Requirement.Internet,
  77. Requirement.NoInternet,
  78. Requirement.PluggedIn,
  79. Requirement.DefenderDisabled
  80. }.All(metRequirements.Contains) &&
  81. await new NoPendingUpdates().IsMet())) metRequirements.Add(Requirement.NoPendingUpdates);
  82. if (requirements.Contains(Requirement.DefenderToggled))
  83. if (await new DefenderDisabled().IsMet()) metRequirements.Add(Requirement.DefenderToggled);
  84. if (requirements.Contains(Requirement.LocalAccounts))
  85. metRequirements.Add(Requirement.LocalAccounts);
  86. if (requirements.Contains(Requirement.AdministratorPasswordSet))
  87. metRequirements.Add(Requirement.AdministratorPasswordSet);
  88. return metRequirements.ToArray();
  89. }
  90. public interface IRequirements
  91. {
  92. Task<bool> IsMet();
  93. Task<bool> Meet();
  94. }
  95. public class RequirementBase
  96. {
  97. public class ProgressEventArgs : EventArgs
  98. {
  99. public int PercentAdded;
  100. public ProgressEventArgs(int percent)
  101. {
  102. PercentAdded = percent;
  103. }
  104. }
  105. public event EventHandler<ProgressEventArgs> ProgressChanged;
  106. protected void OnProgressAdded(int percent)
  107. {
  108. ProgressChanged?.Invoke(this, new ProgressEventArgs(percent));
  109. }
  110. }
  111. public class Battery : RequirementBase, IRequirements
  112. {
  113. [StructLayout(LayoutKind.Sequential)]
  114. public class PowerState
  115. {
  116. public ACLineStatus ACLineStatus;
  117. public BatteryFlag BatteryFlag;
  118. public Byte BatteryLifePercent;
  119. public Byte Reserved1;
  120. public Int32 BatteryLifeTime;
  121. public Int32 BatteryFullLifeTime;
  122. // direct instantation not intended, use GetPowerState.
  123. private PowerState() {}
  124. public static PowerState GetPowerState()
  125. {
  126. PowerState state = new PowerState();
  127. if (GetSystemPowerStatusRef(state))
  128. return state;
  129. throw new ApplicationException("Unable to get power state");
  130. }
  131. [DllImport("Kernel32", EntryPoint = "GetSystemPowerStatus")]
  132. private static extern bool GetSystemPowerStatusRef(PowerState sps);
  133. }
  134. // Note: Underlying type of byte to match Win32 header
  135. public enum ACLineStatus : byte
  136. {
  137. Offline = 0, Online = 1, Unknown = 255
  138. }
  139. public enum BatteryFlag : byte
  140. {
  141. High = 1, Low = 2, Critical = 4, Charging = 8,
  142. NoSystemBattery = 128, Unknown = 255
  143. }
  144. public async Task<bool> IsMet()
  145. {
  146. try
  147. {
  148. PowerState state = PowerState.GetPowerState();
  149. if ((state.BatteryFlag == BatteryFlag.NoSystemBattery || state.BatteryFlag == BatteryFlag.Charging)
  150. || state.ACLineStatus == ACLineStatus.Online || (state.ACLineStatus == ACLineStatus.Unknown && state.BatteryFlag == BatteryFlag.Unknown))
  151. return true;
  152. else
  153. return false;
  154. }
  155. catch { }
  156. return true;
  157. }
  158. public Task<bool> Meet() => throw new NotImplementedException();
  159. }
  160. public class Internet : RequirementBase, IRequirements
  161. {
  162. [DllImport("wininet.dll", SetLastError = true)]
  163. private static extern bool InternetCheckConnection(string lpszUrl, int dwFlags, int dwReserved);
  164. [DllImport("wininet.dll", SetLastError=true)]
  165. extern static bool InternetGetConnectedState(out int lpdwFlags, int dwReserved);
  166. public async Task<bool> IsMet()
  167. {
  168. try
  169. {
  170. try
  171. {
  172. if (!InternetCheckConnection("http://archlinux.org", 1, 0))
  173. {
  174. if (!InternetCheckConnection("http://google.com", 1, 0))
  175. return false;
  176. }
  177. return true;
  178. }
  179. catch
  180. {
  181. var request = (HttpWebRequest)WebRequest.Create("http://google.com");
  182. request.KeepAlive = false;
  183. request.Timeout = 5000;
  184. using (var response = (HttpWebResponse)request.GetResponse())
  185. return true;
  186. }
  187. }
  188. catch
  189. {
  190. return false;
  191. }
  192. }
  193. public Task<bool> Meet() => throw new NotImplementedException();
  194. }
  195. public class DefenderDisabled : RequirementBase, IRequirements
  196. {
  197. public async Task<bool> IsMet()
  198. {
  199. try
  200. {
  201. if (Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Services\WinDefend") != null && new RegistryValueAction() { KeyName = @"HKLM\SYSTEM\CurrentControlSet\Services\WinDefend", Value = "Start", Data = 4, Type = RegistryValueType.REG_DWORD }.GetStatus() != UninstallTaskStatus.Completed)
  202. return false;
  203. if (Registry.ClassesRoot.OpenSubKey(@"CLSID\{2781761E-28E0-4109-99FE-B9D127C57AFE}\InprocServer32") != null) return false;
  204. if (Registry.ClassesRoot.OpenSubKey(@"CLSID\{a463fcb9-6b1c-4e0d-a80b-a2ca7999e25d}\InprocServer32") != null) return false;
  205. var key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity");
  206. if (key != null && (int)key.GetValue("Enabled") != 0)
  207. {
  208. return false;
  209. }
  210. }
  211. catch (Exception e)
  212. {
  213. }
  214. return RemnantsOnly();
  215. }
  216. public static bool RemnantsOnly()
  217. {
  218. if (Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Services\WinDefend") != null)
  219. return false;
  220. return Process.GetProcessesByName("MsMpEng").Length == 0;
  221. }
  222. public async Task<bool> Meet()
  223. {
  224. throw new NotImplementedException();
  225. OnProgressAdded(30);
  226. try
  227. {
  228. //Scheduled task to run the program on logon, and remove defender notifications
  229. var runOnLogOn = new CmdAction()
  230. {
  231. Command = $"schtasks /create /tn \"AME Wizard\" /tr \"{Assembly.GetExecutingAssembly().Location}\" /sc onlogon /RL HIGHEST /f",
  232. Wait = false
  233. };
  234. await runOnLogOn.RunTask();
  235. OnProgressAdded(10);
  236. var disableNotifs = new CmdAction()
  237. {
  238. Command = $"reg add \"HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender Security Center\\Notifications\" /v DisableNotifications /t REG_DWORD /d 1 /f"
  239. };
  240. await disableNotifs.RunTask();
  241. OnProgressAdded(10);
  242. var defenderService = new RunAction()
  243. {
  244. Exe = $"NSudoLC.exe",
  245. Arguments = "-U:T -P:E -M:S -Priority:RealTime -UseCurrentConsole -Wait reg delete \"HKLM\\SYSTEM\\CurrentControlSet\\Services\\WinDefend\" /f",
  246. BaseDir = true,
  247. CreateWindow = false
  248. };
  249. await defenderService.RunTask();
  250. OnProgressAdded(20);
  251. // MpOAV.dll normally is in use by a lot of processes. This prevents that.
  252. var MpOAVCLSID = new RunAction()
  253. {
  254. Exe = $"NSudoLC.exe",
  255. Arguments = @"-U:T -P:E -M:S -Priority:RealTime -Wait reg delete ""HKCR\CLSID\{2781761E-28E0-4109-99FE-B9D127C57AFE}\InprocServer32"" /f",
  256. BaseDir = true,
  257. CreateWindow = false
  258. };
  259. await MpOAVCLSID.RunTask();
  260. OnProgressAdded(20);
  261. if (Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\WinDefend") != null)
  262. {
  263. throw new Exception("Could not remove WinDefend service.");
  264. }
  265. OnProgressAdded(10);
  266. return true;
  267. }
  268. catch (Exception exception)
  269. {
  270. ErrorLogger.WriteToErrorLog(exception.Message, exception.StackTrace,
  271. $"Could not remove Windows Defender.");
  272. return false;
  273. // TODO: Move this to requirements page view if any Meet calls return false
  274. try
  275. {
  276. var saveLogDir = System.Windows.Forms.Application.StartupPath + "\\AME Logs";
  277. if (Directory.Exists(saveLogDir)) Directory.Delete(saveLogDir, true);
  278. Directory.Move(Directory.GetCurrentDirectory() + "\\Logs", saveLogDir);
  279. }
  280. catch (Exception) { }
  281. //MessageBox.Show("Could not remove Windows Defender. Check the error logs and contact the team " +
  282. // "for more information and assistance.", "Could not remove Windows Defender.", MessageBoxButton.OK, MessageBoxImage.Error);
  283. }
  284. }
  285. }
  286. public class DefenderToggled : RequirementBase, IRequirements
  287. {
  288. public async Task<bool> IsMet()
  289. {
  290. var defenderKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows Defender");
  291. RegistryKey realtimeKey = null;
  292. try
  293. {
  294. realtimeKey = defenderKey.OpenSubKey("Real-Time Protection");
  295. }
  296. catch
  297. {
  298. }
  299. if (realtimeKey != null)
  300. {
  301. try
  302. {
  303. if (!((int)realtimeKey.GetValue("DisableRealtimeMonitoring") != 1))
  304. return false;
  305. }
  306. catch (Exception exception)
  307. {
  308. return false;
  309. }
  310. }
  311. try
  312. {
  313. if (!((int)defenderKey.OpenSubKey("SpyNet").GetValue("SpyNetReporting") != 0))
  314. return false;
  315. }
  316. catch
  317. {
  318. }
  319. try
  320. {
  321. if (!((int)defenderKey.OpenSubKey("SpyNet").GetValue("SubmitSamplesConsent") != 0))
  322. return false;
  323. }
  324. catch
  325. {
  326. }
  327. try
  328. {
  329. if (!((int)defenderKey.OpenSubKey("Features").GetValue("TamperProtection") != 4))
  330. return false;
  331. }
  332. catch
  333. {
  334. }
  335. return true;
  336. }
  337. public async Task<bool> Meet()
  338. {
  339. throw new NotImplementedException();
  340. }
  341. }
  342. class SearchCompletedCallback : ISearchCompletedCallback
  343. {
  344. public void Invoke(ISearchJob searchJob, ISearchCompletedCallbackArgs callbackArgs)
  345. {
  346. this.CompleteTask();
  347. }
  348. private TaskCompletionSource<bool> taskSource = new TaskCompletionSource<bool>();
  349. protected void CompleteTask()
  350. {
  351. taskSource.SetResult(true);
  352. }
  353. public Task Task
  354. {
  355. get
  356. {
  357. return taskSource.Task;
  358. }
  359. }
  360. }
  361. private static Process _pendingUpdateCheckProcess = null;
  362. public class NoPendingUpdates : RequirementBase, IRequirements
  363. {
  364. public async Task<bool> IsMet()
  365. {
  366. try
  367. {
  368. if (_pendingUpdateCheckProcess != null && !_pendingUpdateCheckProcess.HasExited)
  369. {
  370. _pendingUpdateCheckProcess.Kill();
  371. }
  372. }
  373. catch (Exception e) { }
  374. bool updatesFound = false;
  375. try
  376. {
  377. // Using WUApiLib can crash the entire application if
  378. // Windows Update is faulty. For that reason we use a
  379. // separate process. To replicate, use an ameliorated
  380. // system and copy wuapi.dll & wuaeng.dll to System32.
  381. _pendingUpdateCheckProcess = new Process();
  382. _pendingUpdateCheckProcess.StartInfo = new ProcessStartInfo
  383. {
  384. FileName = Assembly.GetEntryAssembly().Location,
  385. Arguments = "-CheckPendingUpdates",
  386. UseShellExecute = false,
  387. RedirectStandardOutput = true,
  388. CreateNoWindow = true
  389. };
  390. _pendingUpdateCheckProcess.OutputDataReceived += delegate(object sender, DataReceivedEventArgs args)
  391. {
  392. if (!string.IsNullOrWhiteSpace(args.Data))
  393. bool.TryParse(args.Data, out updatesFound);
  394. };
  395. _pendingUpdateCheckProcess.Start();
  396. _pendingUpdateCheckProcess.BeginOutputReadLine();
  397. if (!_pendingUpdateCheckProcess.WaitForExit(55000))
  398. {
  399. _pendingUpdateCheckProcess.Kill();
  400. throw new TimeoutException();
  401. }
  402. _pendingUpdateCheckProcess.CancelOutputRead();
  403. _pendingUpdateCheckProcess.Dispose();
  404. }
  405. catch (Exception e) { }
  406. return !updatesFound;
  407. }
  408. public Task<bool> Meet() => throw new NotImplementedException();
  409. public static bool Check()
  410. {
  411. bool result = false;
  412. try
  413. {
  414. var updateSession = new UpdateSession();
  415. var updateSearcher = updateSession.CreateUpdateSearcher();
  416. updateSearcher.Online = false; //set to true if you want to search online
  417. SearchCompletedCallback searchCompletedCallback = new SearchCompletedCallback();
  418. ISearchJob searchJob = updateSearcher.BeginSearch(
  419. "IsInstalled=0 And IsHidden=0 And Type='Software' And DeploymentAction=*",
  420. searchCompletedCallback, null);
  421. try
  422. {
  423. searchCompletedCallback.Task.Wait(50000);
  424. }
  425. catch (OperationCanceledException)
  426. {
  427. searchJob.RequestAbort();
  428. }
  429. ISearchResult searchResult = updateSearcher.EndSearch(searchJob);
  430. if (searchResult.Updates.Cast<IUpdate>().Any(x => x.IsDownloaded))
  431. {
  432. result = true;
  433. }
  434. }
  435. catch (Exception e)
  436. {
  437. result = false;
  438. }
  439. return result;
  440. }
  441. }
  442. public class NoAntivirus : RequirementBase, IRequirements
  443. {
  444. public async Task<bool> IsMet()
  445. {
  446. return !WinUtil.GetEnabledAvList(false).Any();
  447. }
  448. public Task<bool> Meet() => throw new NotImplementedException();
  449. }
  450. public class Activation : RequirementBase, IRequirements
  451. {
  452. public async Task<bool> IsMet()
  453. {
  454. return WinUtil.IsGenuineWindows();
  455. }
  456. public Task<bool> Meet() => throw new NotImplementedException();
  457. }
  458. public class WindowsBuild
  459. {
  460. public bool IsMet(string[] builds)
  461. {
  462. return builds.Any(x => x.Equals(Globals.WinVer.ToString()));
  463. }
  464. public Task<bool> Meet() => throw new NotImplementedException();
  465. }
  466. }
  467. }