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.

222 lines
9.2 KiB

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.Diagnostics;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Text;
  7. using System.Windows;
  8. using TrustedUninstaller.Shared;
  9. using TrustedUninstaller.Shared.Actions;
  10. namespace TrustedUninstaller.CLI
  11. {
  12. public class CLI
  13. {
  14. private static async System.Threading.Tasks.Task<int> Main(string[] args)
  15. {
  16. //Needed after defender removal's reboot, the "current directory" will be set to System32
  17. //After the auto start up.
  18. Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
  19. DualOut.Init();
  20. if (!WinUtil.IsAdministrator())
  21. {
  22. System.Console.Error.WriteLine("This program must be launched as an Administrator!");
  23. return -1;
  24. }
  25. #if !DEBUG
  26. /*
  27. if (!WinUtil.IsGenuineWindows())
  28. {
  29. System.Console.Error.WriteLine("This program only works on genuine Windows copies!");
  30. return -1;
  31. }
  32. */
  33. #endif
  34. if (args.Length < 1 || !Directory.Exists(args[0]))
  35. {
  36. Console.WriteLine("No Playbook selected: Use the GUI to select a playbook to run.");
  37. return -1;
  38. }
  39. AmeliorationUtil.Playbook = await AmeliorationUtil.DeserializePlaybook(args[0]);
  40. if (!Directory.Exists($"{AmeliorationUtil.Playbook.Path}\\Configuration") || Directory.GetFiles($"{AmeliorationUtil.Playbook.Path}\\Configuration").Length == 0)
  41. {
  42. Console.WriteLine("Configuration folder is empty, put YAML files in it and restart the application.");
  43. Console.WriteLine($"Current directory: {Directory.GetCurrentDirectory()}");
  44. return -1;
  45. }
  46. if (!WinUtil.IsTrustedInstaller())
  47. {
  48. Console.WriteLine("Checking requirements...\r\n");
  49. if (AmeliorationUtil.Playbook.Requirements.Contains(Requirements.Requirement.Internet) && !await (new Requirements.Internet()).IsMet())
  50. {
  51. Console.WriteLine("Internet must be connected to run this Playbook.");
  52. }
  53. if (AmeliorationUtil.Playbook.Requirements.Contains(Requirements.Requirement.DefenderDisabled) && Process.GetProcessesByName("MsMpEng").Any())
  54. {
  55. Console.WriteLine("The system must be prepared before continuing. Make sure all 4 windows security toggles are set to off.\r\nYour system will restart after preparation\r\nPress any key to continue...");
  56. Console.ReadKey();
  57. try
  58. {
  59. WinUtil.PrepareSystemCLI();
  60. CmdAction reboot = new CmdAction()
  61. {
  62. Command = "timeout /t 1 & shutdown /r /t 0",
  63. Wait = false
  64. };
  65. AmeliorationUtil.SafeRunAction(reboot).Wait();
  66. Environment.Exit(0);
  67. } catch (Exception e)
  68. {
  69. Console.WriteLine("Error preparing system: " + e.Message);
  70. Environment.Exit(-1);
  71. }
  72. }
  73. if (AmeliorationUtil.Playbook.Requirements.Contains(Requirements.Requirement.Internet) && !await (new Requirements.Internet()).IsMet())
  74. {
  75. Console.WriteLine("Internet must be connected to run this Playbook.");
  76. }
  77. }
  78. try
  79. {
  80. if (!Directory.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ame-assassin")))
  81. {
  82. Console.WriteLine(":AME-STATUS: Extracting resources");
  83. ExtractResourceFolder("resources", Directory.GetCurrentDirectory());
  84. ExtractArchive(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CLI-Resources.7z"), AppDomain.CurrentDomain.BaseDirectory);
  85. try
  86. {
  87. File.Delete(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CLI-Resources.7z"));
  88. }
  89. catch (Exception e) { }
  90. }
  91. }
  92. catch (Exception e)
  93. {
  94. ErrorLogger.WriteToErrorLog(e.Message,
  95. e.StackTrace, "Error extracting resources.");
  96. Console.WriteLine($":AME-Fatal Error: Error extracting resources.");
  97. return -1;
  98. }
  99. await AmeliorationUtil.StartAmelioration();
  100. return 0;
  101. }
  102. public static void ExtractArchive(string file, string targetDir)
  103. {
  104. RunCommand($"x \"{file}\" -o\"{targetDir}\" -p\"wizard\" -y -aos");
  105. }
  106. private static void RunCommand(string command)
  107. {
  108. var proc = new Process();
  109. var startInfo = new ProcessStartInfo
  110. {
  111. CreateNoWindow = true,
  112. UseShellExecute = false,
  113. WindowStyle = ProcessWindowStyle.Normal,
  114. Arguments = command,
  115. FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "7za.exe"),
  116. RedirectStandardError = true,
  117. };
  118. proc.StartInfo = startInfo;
  119. proc.Start();
  120. StringBuilder errorOutput = new StringBuilder("");
  121. proc.ErrorDataReceived += (sender, args) => { errorOutput.Append("\r\n" + args.Data); };
  122. proc.BeginErrorReadLine();
  123. proc.WaitForExit();
  124. proc.CancelErrorRead();
  125. if (proc.ExitCode == 1)
  126. ErrorLogger.WriteToErrorLog(errorOutput.ToString(), Environment.StackTrace, "Warning while running 7zip.", command);
  127. if (proc.ExitCode > 1)
  128. throw new ArgumentOutOfRangeException("Error running 7zip: " + errorOutput.ToString());
  129. }
  130. public static void ExtractResourceFolder(string resource, string dir, bool overwrite = false)
  131. {
  132. if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
  133. Assembly assembly = Assembly.GetExecutingAssembly();
  134. var resources = assembly.GetManifestResourceNames().Where(res => res.StartsWith($"TrustedUninstaller.CLI.Properties"));
  135. foreach (var obj in resources)
  136. {
  137. using (UnmanagedMemoryStream stream = (UnmanagedMemoryStream)assembly.GetManifestResourceStream(obj))
  138. {
  139. int MB = 1024 * 1024;
  140. int offset = -MB;
  141. var file = dir + $"\\{obj.Substring($"TrustedUninstaller.CLI.Properties.{resource}.".Length).Replace("---", "\\")}";
  142. if (file.EndsWith(".gitkeep")) continue;
  143. var fileDir = Path.GetDirectoryName(file);
  144. if (fileDir != null && !Directory.Exists(fileDir)) Directory.CreateDirectory(fileDir);
  145. if (File.Exists(file) && !overwrite) continue;
  146. if (File.Exists(file) && overwrite)
  147. {
  148. try
  149. {
  150. File.Delete(file);
  151. }
  152. catch (Exception e)
  153. {
  154. if (!Directory.Exists(Directory.GetCurrentDirectory() + "\\Logs"))
  155. Directory.CreateDirectory(Directory.GetCurrentDirectory() + "\\Logs");
  156. using (var writer = new StreamWriter(Path.Combine(Directory.GetCurrentDirectory(), "Logs\\ErrorLog.txt"), true))
  157. {
  158. writer.WriteLine($"Title: Could not delete existing resource file {file}.\r\nMessage: {e.Message}\r\n\r\nStackTrace: {e.StackTrace}");
  159. writer.WriteLine("\r\nDate/Time: " + DateTime.Now);
  160. writer.WriteLine("============================================");
  161. }
  162. continue;
  163. }
  164. }
  165. using (FileStream fsDlst = new FileStream(file, FileMode.CreateNew, FileAccess.Write))
  166. {
  167. while (offset + MB < stream.Length)
  168. {
  169. var buffer = new byte[MB];
  170. offset += MB;
  171. if (offset + MB > stream.Length)
  172. {
  173. var bytesLeft = stream.Length - offset;
  174. buffer = new byte[bytesLeft];
  175. }
  176. stream.Seek(offset, SeekOrigin.Begin);
  177. stream.Read(buffer, 0, buffer.Length);
  178. fsDlst.Seek(offset, SeekOrigin.Begin);
  179. fsDlst.Write(buffer, 0, buffer.Length);
  180. }
  181. }
  182. }
  183. }
  184. }
  185. }
  186. }