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.

341 lines
14 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows;
  10. using Microsoft.Win32;
  11. using TrustedUninstaller.Shared;
  12. using TrustedUninstaller.Shared.Actions;
  13. namespace TrustedUninstaller.CLI
  14. {
  15. public class CLI
  16. {
  17. private static async System.Threading.Tasks.Task<int> Main(string[] args)
  18. {
  19. //Needed after defender removal's reboot, the "current directory" will be set to System32
  20. //After the auto start up.
  21. Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
  22. DualOut.Init();
  23. if (!WinUtil.IsAdministrator())
  24. {
  25. System.Console.Error.WriteLine("This program must be launched as an Administrator!");
  26. return -1;
  27. }
  28. #if !DEBUG
  29. /*
  30. if (!WinUtil.IsGenuineWindows())
  31. {
  32. System.Console.Error.WriteLine("This program only works on genuine Windows copies!");
  33. return -1;
  34. }
  35. */
  36. #endif
  37. if (args.Length < 1 || !Directory.Exists(args[0]))
  38. {
  39. Console.WriteLine("No Playbook selected: Use the GUI to select a playbook to run.");
  40. return -1;
  41. }
  42. AmeliorationUtil.Playbook = await AmeliorationUtil.DeserializePlaybook(args[0]);
  43. AmeliorationUtil.Playbook.Path = args[0];
  44. if (!Directory.Exists($"{AmeliorationUtil.Playbook.Path}\\Configuration") || Directory.GetFiles($"{AmeliorationUtil.Playbook.Path}\\Configuration").Length == 0)
  45. {
  46. Console.WriteLine("Configuration folder is empty, put YAML files in it and restart the application.");
  47. Console.WriteLine($"Current directory: {Directory.GetCurrentDirectory()}");
  48. return -1;
  49. }
  50. ExtractResourceFolder("resources", Directory.GetCurrentDirectory());
  51. if (!WinUtil.IsTrustedInstaller())
  52. {
  53. Console.WriteLine("Checking requirements...\r\n");
  54. if (AmeliorationUtil.Playbook.Requirements.Contains(Requirements.Requirement.Internet) && !await (new Requirements.Internet()).IsMet())
  55. {
  56. Console.WriteLine("Internet must be connected to run this Playbook.");
  57. }
  58. if (AmeliorationUtil.Playbook.Requirements.Contains(Requirements.Requirement.DefenderDisabled) && Process.GetProcessesByName("MsMpEng").Any())
  59. {
  60. bool first = true;
  61. while ((await GetDefenderToggles()).Any(x => x))
  62. {
  63. Console.WriteLine("All 4 windows security toggles must be set to off.\r\nNavigate to Windows Security > Virus & threat detection > manage settings.\r\nPress any key to continue...");
  64. Console.ReadKey();
  65. }
  66. Console.WriteLine("The system must be prepared before continuing Your system will restart after preparation\r\nPress any key to continue...");
  67. Console.ReadKey();
  68. try
  69. {
  70. WinUtil.PrepareSystemCLI();
  71. CmdAction reboot = new CmdAction()
  72. {
  73. Command = "timeout /t 1 & shutdown /r /t 0",
  74. Wait = false
  75. };
  76. AmeliorationUtil.SafeRunAction(reboot).Wait();
  77. Environment.Exit(0);
  78. } catch (Exception e)
  79. {
  80. Console.WriteLine("Error preparing system: " + e.Message);
  81. Environment.Exit(-1);
  82. }
  83. }
  84. if (AmeliorationUtil.Playbook.Requirements.Contains(Requirements.Requirement.Internet) && !await (new Requirements.Internet()).IsMet())
  85. {
  86. Console.WriteLine("Internet must be connected to run this Playbook.");
  87. }
  88. }
  89. try
  90. {
  91. if (!Directory.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ame-assassin")))
  92. {
  93. Console.WriteLine(":AME-STATUS: Extracting resources");
  94. ExtractResourceFolder("resources", Directory.GetCurrentDirectory());
  95. ExtractArchive(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CLI-Resources.7z"), AppDomain.CurrentDomain.BaseDirectory);
  96. try
  97. {
  98. File.Delete(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CLI-Resources.7z"));
  99. }
  100. catch (Exception e) { }
  101. }
  102. }
  103. catch (Exception e)
  104. {
  105. ErrorLogger.WriteToErrorLog(e.Message,
  106. e.StackTrace, "Error extracting resources.");
  107. Console.WriteLine($":AME-Fatal Error: Error extracting resources.");
  108. return -1;
  109. }
  110. await AmeliorationUtil.StartAmelioration();
  111. return 0;
  112. }
  113. public static void ExtractArchive(string file, string targetDir)
  114. {
  115. RunCommand($"x \"{file}\" -o\"{targetDir}\" -p\"wizard\" -y -aos");
  116. }
  117. private static void RunCommand(string command)
  118. {
  119. var proc = new Process();
  120. var startInfo = new ProcessStartInfo
  121. {
  122. CreateNoWindow = true,
  123. UseShellExecute = false,
  124. WindowStyle = ProcessWindowStyle.Normal,
  125. Arguments = command,
  126. FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "7za.exe"),
  127. RedirectStandardError = true,
  128. };
  129. proc.StartInfo = startInfo;
  130. proc.Start();
  131. StringBuilder errorOutput = new StringBuilder("");
  132. proc.ErrorDataReceived += (sender, args) => { errorOutput.Append("\r\n" + args.Data); };
  133. proc.BeginErrorReadLine();
  134. proc.WaitForExit();
  135. proc.CancelErrorRead();
  136. if (proc.ExitCode == 1)
  137. ErrorLogger.WriteToErrorLog(errorOutput.ToString(), Environment.StackTrace, "Warning while running 7zip.", command);
  138. if (proc.ExitCode > 1)
  139. throw new ArgumentOutOfRangeException("Error running 7zip: " + errorOutput.ToString());
  140. }
  141. public static void ExtractResourceFolder(string resource, string dir, bool overwrite = false)
  142. {
  143. if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
  144. Assembly assembly = Assembly.GetExecutingAssembly();
  145. var resources = assembly.GetManifestResourceNames().Where(res => res.StartsWith($"TrustedUninstaller.CLI.Properties"));
  146. foreach (var obj in resources)
  147. {
  148. using (UnmanagedMemoryStream stream = (UnmanagedMemoryStream)assembly.GetManifestResourceStream(obj))
  149. {
  150. int MB = 1024 * 1024;
  151. int offset = -MB;
  152. var file = dir + $"\\{obj.Substring($"TrustedUninstaller.CLI.Properties.{resource}.".Length).Replace("---", "\\")}";
  153. if (file.EndsWith(".gitkeep")) continue;
  154. var fileDir = Path.GetDirectoryName(file);
  155. if (fileDir != null && !Directory.Exists(fileDir)) Directory.CreateDirectory(fileDir);
  156. if (File.Exists(file) && !overwrite) continue;
  157. if (File.Exists(file) && overwrite)
  158. {
  159. try
  160. {
  161. File.Delete(file);
  162. }
  163. catch (Exception e)
  164. {
  165. if (!Directory.Exists(Directory.GetCurrentDirectory() + "\\Logs"))
  166. Directory.CreateDirectory(Directory.GetCurrentDirectory() + "\\Logs");
  167. using (var writer = new StreamWriter(Path.Combine(Directory.GetCurrentDirectory(), "Logs\\ErrorLog.txt"), true))
  168. {
  169. writer.WriteLine($"Title: Could not delete existing resource file {file}.\r\nMessage: {e.Message}\r\n\r\nStackTrace: {e.StackTrace}");
  170. writer.WriteLine("\r\nDate/Time: " + DateTime.Now);
  171. writer.WriteLine("============================================");
  172. }
  173. continue;
  174. }
  175. }
  176. using (FileStream fsDlst = new FileStream(file, FileMode.CreateNew, FileAccess.Write))
  177. {
  178. while (offset + MB < stream.Length)
  179. {
  180. var buffer = new byte[MB];
  181. offset += MB;
  182. if (offset + MB > stream.Length)
  183. {
  184. var bytesLeft = stream.Length - offset;
  185. buffer = new byte[bytesLeft];
  186. }
  187. stream.Seek(offset, SeekOrigin.Begin);
  188. stream.Read(buffer, 0, buffer.Length);
  189. fsDlst.Seek(offset, SeekOrigin.Begin);
  190. fsDlst.Write(buffer, 0, buffer.Length);
  191. }
  192. }
  193. }
  194. }
  195. }
  196. public static async Task<List<bool>> GetDefenderToggles()
  197. {
  198. var result = new List<bool>();
  199. await Task.Run(() =>
  200. {
  201. var defenderKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows Defender");
  202. var policiesKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Policies\Microsoft\Windows Defender");
  203. RegistryKey realtimePolicy = null;
  204. RegistryKey realtimeKey = null;
  205. try
  206. {
  207. try
  208. {
  209. realtimePolicy = policiesKey.OpenSubKey("Real-Time Protection");
  210. }
  211. catch (Exception e) { }
  212. if (realtimePolicy != null)
  213. realtimeKey = realtimePolicy;
  214. else
  215. realtimeKey = defenderKey.OpenSubKey("Real-Time Protection");
  216. }
  217. catch
  218. {
  219. result.Add(false);
  220. }
  221. if (realtimeKey != null)
  222. {
  223. try
  224. {
  225. result.Add((int)realtimeKey.GetValue("DisableRealtimeMonitoring") != 1);
  226. }
  227. catch (Exception exception)
  228. {
  229. try
  230. {
  231. realtimeKey = defenderKey.OpenSubKey("Real-Time Protection");
  232. result.Add((int)realtimeKey.GetValue("DisableRealtimeMonitoring") != 1);
  233. }
  234. catch (Exception e)
  235. {
  236. result.Add(true);
  237. }
  238. }
  239. }
  240. try
  241. {
  242. RegistryKey spynetPolicy = null;
  243. RegistryKey spynetKey = null;
  244. try
  245. {
  246. spynetPolicy = policiesKey.OpenSubKey("SpyNet");
  247. }
  248. catch (Exception e) { }
  249. if (spynetPolicy != null)
  250. spynetKey = spynetPolicy;
  251. else
  252. spynetKey = defenderKey.OpenSubKey("SpyNet");
  253. int reporting = 0;
  254. int consent = 0;
  255. try
  256. {
  257. reporting = (int)spynetKey.GetValue("SpyNetReporting");
  258. }
  259. catch (Exception e)
  260. {
  261. if (spynetPolicy != null)
  262. {
  263. reporting = (int)defenderKey.OpenSubKey("SpyNet").GetValue("SpyNetReporting");
  264. }
  265. }
  266. try
  267. {
  268. consent = (int)spynetKey.GetValue("SubmitSamplesConsent");
  269. }
  270. catch (Exception e)
  271. {
  272. if (spynetPolicy != null)
  273. {
  274. consent = (int)defenderKey.OpenSubKey("SpyNet").GetValue("SubmitSamplesConsent");
  275. }
  276. }
  277. result.Add(reporting != 0);
  278. result.Add(consent != 0 && consent != 2 && consent != 4);
  279. }
  280. catch
  281. {
  282. result.Add(false);
  283. result.Add(false);
  284. }
  285. try
  286. {
  287. int tamper = (int)defenderKey.OpenSubKey("Features").GetValue("TamperProtection");
  288. result.Add(tamper != 4 && tamper != 0);
  289. }
  290. catch
  291. {
  292. result.Add(false);
  293. }
  294. });
  295. return result;
  296. }
  297. }
  298. }