← Reports

Remote Access Trojan · Worm · Dropper

VioletWorm - game.exe

Author
Moise Medici
Updated
07 Sept 2026 · Completed
Difficulty
Easy
Platform
Windows
Capabilities
Dropping Secondary PayloadsPersistence MechanismsCommand and Control C2 CommunicationCommand Execution via Powershell Cmd BashData-ExfiltrationFile EncryptionKeyloggingScreen CaptureWebcam AccessClipboard ManipulationCredential TheftAMSI and ETW BypassSandbox and VM EvasionReflective Code LoadingUSB SpreadingDenial of Service
Tags
pythonC#

Class KPWIONSICglLbx

Why start with this class? When I opened the first class listed by dnSpy (FCLHYIYQnSe), line 22 immediately showed it using something from this class. A brief look shows that it does not seem to depend on many other classes, so it is a reasonable starting point.

Core.KPWIONSICglLbx
public class KPWIONSICglLbx
{
[DllImport("user32.dll", EntryPoint = "GetProcessWindowStation", SetLastError = true)]
private static extern IntPtr Ho0yEUitpuOd8fLq9TkF();
[DllImport("user32.dll", EntryPoint = "EnumDesktops", SetLastError = true)]
private static extern bool dhBgAJi7PxTsE7FkFimH(IntPtr hWinSta, KPWIONSICglLbx.EnumDesktopProc lpEnumFunc, IntPtr lParam);
public static string[] lekxBTP75AJeTJ0Zmjxv()
{
List<string> desktopList = new List<string>();
IntPtr intPtr = KPWIONSICglLbx.Ho0yEUitpuOd8fLq9TkF();
KPWIONSICglLbx.EnumDesktopProc enumDesktopProc = delegate(string name, IntPtr lParam)
{
desktopList.Add(name);
return true;
};
string[] array;
if (KPWIONSICglLbx.dhBgAJi7PxTsE7FkFimH(intPtr, enumDesktopProc, IntPtr.Zero))
{
array = desktopList.ToArray();
}
else
{
array = new string[0];
}
return array;
}
[DllImport("shcore.dll", EntryPoint = "SetProcessDpiAwareness")]
private static extern int bKeraW8Ba1kq7cUyxEeh(int value);
[DllImport("user32.dll", EntryPoint = "SetProcessDPIAware")]
private static extern bool uLCOof8vGfxVlq6aAtWe();
public static void kOwDQSHhp21iFPBZIZCv()
{
try
{
KPWIONSICglLbx.bKeraW8Ba1kq7cUyxEeh(2);
}
catch (Exception ex)
{
KPWIONSICglLbx.uLCOof8vGfxVlq6aAtWe();
}
}
public static string oduu3ZFgGjyEhzwgPyy6(string sep = "#")
{
StringBuilder stringBuilder = new StringBuilder();
Screen[] allScreens = Screen.AllScreens;
int num = 0;
checked
{
int num2 = allScreens.Length - 1;
for (int i = num; i <= num2; i++)
{
object obj = allScreens[i];
stringBuilder.Append(string.Format(Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("ZXpCOU9uc3hmVHA3TW4wNmV6TjlPbnMwZlE9PQ==")))), new object[]
{
i,
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("UW05MWJtUno=")))), new object[0], null, null, null), null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("V0E9PQ==")))), new object[0], null, null, null)),
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("UW05MWJtUno=")))), new object[0], null, null, null), null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("V1E9PQ==")))), new object[0], null, null, null)),
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("UW05MWJtUno=")))), new object[0], null, null, null), null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("VjJsa2RHZz0=")))), new object[0], null, null, null)),
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("UW05MWJtUno=")))), new object[0], null, null, null), null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("U0dWcFoyaDA=")))), new object[0], null, null, null))
}));
if (i < allScreens.Length - 1)
{
stringBuilder.Append(sep);
}
}
return stringBuilder.ToString();
}
}
private delegate bool EnumDesktopProc(string lpszDesktop, IntPtr lParam);
}
}

The following methods can be renamed:

Obfuscated NameRenamed as
Ho0yEUitpuOd8fLq9TkFGetProcessWindowStation
dhBgAJi7PxTsE7FkFimHEnumDesktops
bKeraW8Ba1kq7cUyxEehSetProcessDPIAwareness
uLCOof8vGfxVlq6aAtWeSetProcessDPIAware
kOwDQSHhp21iFPBZIZCvDpiAwareness

At this point, it is easy to see that the method lekxBTP75AJeTJ0Zmjxv enumerates the current desktops. It uses the GetProcessWindowStation 18 procedure, which returns a handle to the current window station object 19. It then defines a callback function, EnumDesktopProc, which is called by EnumDesktops 20 and adds each desktop to a list. EnumDesktops is a Windows function that passes the name of each desktop to the custom callback. The method lekxBTP75AJeTJ0Zmjxv can therefore be renamed EnumerateAllDesktops.

The last method left is oduu3ZFgGjyEhzwgPyy6.

Core.KPWIONSICglLbx
public static string oduu3ZFgGjyEhzwgPyy6(string sep = "#")
{
StringBuilder stringBuilder = new StringBuilder();
Screen[] allScreens = Screen.AllScreens;
int num = 0;
checked
{
int num2 = allScreens.Length - 1;
for (int i = num; i <= num2; i++)
{
object obj = allScreens[i];
stringBuilder.Append(string.Format(Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("ZXpCOU9uc3hmVHA3TW4wNmV6TjlPbnMwZlE9PQ==")))), new object[]
{
i,
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("UW05MWJtUno=")))), new object[0], null, null, null), null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("V0E9PQ==")))), new object[0], null, null, null)),
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("UW05MWJtUno=")))), new object[0], null, null, null), null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("V1E9PQ==")))), new object[0], null, null, null)),
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("UW05MWJtUno=")))), new object[0], null, null, null), null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("VjJsa2RHZz0=")))), new object[0], null, null, null)),
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("UW05MWJtUno=")))), new object[0], null, null, null), null, Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("U0dWcFoyaDA=")))), new object[0], null, null, null))
}));
if (i < allScreens.Length - 1)
{
stringBuilder.Append(sep);
}
}
return stringBuilder.ToString();

This method is simple: it decodes a few strings from Base64 twice. In dnSpy, I right-clicked the code, selected Edit Method (C#), and decoded the strings in CyberChef.

Basically every piece of code like:

Encoding.UTF8.GetString(Convert.FromBase64String(Encoding.UTF8.GetString(Convert.FromBase64String("U0dWcFoyaDA=")))),

This can be rewritten as the string it decodes to. In this case: Height.

So the code can be rewritten as:

Core.KPWIONSICglLbx
public static string oduu3ZFgGjyEhzwgPyy6(string sep = "#")
{
StringBuilder stringBuilder = new StringBuilder();
Screen[] allScreens = Screen.AllScreens;
int num3 = 0;
checked
{
int num2 = allScreens.Length - 1;
for (int i = num3; i <= num2; i++)
{
object obj = allScreens[i];
stringBuilder.Append(string.Format("{0}:{1}:{2}:{3}:{4}", new object[]
{
i,
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, "Bounds", new object[0], null, null, null), null, "X", new object[0], null, null, null)),
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, "Bounds", new object[0], null, null, null), null, "Y", new object[0], null, null, null)),
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, "Bounds", new object[0], null, null, null), null, "Width", new object[0], null, null, null)),
RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(NewLateBinding.LateGet(obj, null, "Bounds", new object[0], null, null, null), null, "Height", new object[0], null, null, null))
}));
if (i < allScreens.Length - 1)
{
stringBuilder.Append(sep);
}
}
return stringBuilder.ToString();
}
}

This makes it easier to see that for each available screen it builds a string with each monitor’s bounds, separated by sep, which has the value #. For example:

0:0:0:1920:1080#1:1920:0:1920:1080

This string is returned to the caller.

This function can be renamed GetDesktopBounds, and the whole module DesktopsOperations.