Remote Access Trojan · Worm · Dropper
VioletWorm - game.exe
- Author
- Moise Medici
- Updated
- 07 Sept 2026 · Completed
- Difficulty
- Easy
- Platform
- Capabilities
- Tags
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.
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 Name | Renamed as |
|---|---|
Ho0yEUitpuOd8fLq9TkF | GetProcessWindowStation |
dhBgAJi7PxTsE7FkFimH | EnumDesktops |
bKeraW8Ba1kq7cUyxEeh | SetProcessDPIAwareness |
uLCOof8vGfxVlq6aAtWe | SetProcessDPIAware |
kOwDQSHhp21iFPBZIZCv | DpiAwareness |
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.
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:
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:1080This string is returned to the caller.
This function can be renamed GetDesktopBounds, and the whole module DesktopsOperations.