Home Extracting out DarkGate malware from MSI
Post
Cancel

Extracting out DarkGate malware from MSI

Summary

According to malpedia, DarkGate malware is:

“A commodity loader with features that include the ability to download and execute files to memory, a Hidden Virtual Network Computing (HVNC) module, keylogging, information-stealing capabilities, and privilege escalation. DarkGate makes use of legitimate AutoIt files and typically runs multiple AutoIt scripts. New versions of DarkGate have been advertised on a Russian language eCrime forum since May 2023.”

Reference: “https://malpedia.caad.fkie.fraunhofer.de/details/win.darkgate”

The samples I have recently seen have typically been delivered as MSI files that users are lured into downloading and executing. This post walks through the manual steps for each stage of the unpacking process to get down to the final unpacked version of DarkGate.

Sample being analyzed
MD5: 04f4df0bbf69f930b44ed5accb44c606

Analysis

This malware sample can be found on VirusTotal. This is the starting MSI file that will often be delivered to a victim so this is how we start with the MSI installer and manually pull it apart to get to the malware of interest.

High-Level view

The high-level view of how DarkGate unpacks itself when starting from the MSI file is shown below.

To get a big picture of the MSI’s execution I sent it to JoeSandbox and the primary finding is that it clearly extracts an AutoIt3 script and executes it. This execution appears to start with Windbg somehow executing AutoIt3.exe passing in the extracted AutoIt3 script.

Users are lured into downloading and installing Microsoft installer files (MSI’s) like this one. The installers can be for anything from games to productivity or corporate applications. You can use tools like Orca or AdvancedInstaller to view the details of the MSI, its custom actions, etc. However, in most cases, we just need to manually extract it and the payloads to analyze are obvious.

Manual extraction

The extraction can be performed via tools like AdvancedInstaller, or in this case, by just using 7zip.

The Binary.bz.WrappedSetupProgram is where all the files of interest reside and is an archive as well. Upon extraction we can see many images and several key files. Among these are the windbg.exe and dbgeng.dll (of which gets side-loaded when windbg.exe is executed). In this case, windbg.exe is present purely to bootstrap the execution of the DLL file.

I pulled the dbgeng.dll into IDA Pro to better understand what it is doing upon being loaded by windbg.exe. During the start of the execution of the DLL it executes a routine to first load in the bytes from the data.bin file.

The DLL will use a custom string to replace the standard base64 alphabet. It will also read in the content of the data.bin file which is the base64 text that is encoded using this custom base64 alphabet string.

The referenced custom alphabet string is seen below.

The data.bin bytes will be decoded with this and then subsequently be executed in memory.

However, I want to decode this manually and inspect the resulting decoded bytes and pull that back into IDA Pro. I wrote some simple python code that will perform the base64 decoding using the custom alphabet used by the DarkGate malware.

1
2
3
4
5
6
7
8
9
10
11
import base64

b64_standard = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
b64_custom = 'zLAxuU0kQKf3sWE7ePRO2imyg9GSpVoYC6rhlX48ZHnvjJDBNFtMd1I5acwbqT+='

with open(file='data.bin', mode='r', encoding='utf-8') as file:
    with open(file='data_decoded.bin', mode='+wb') as out_file:
        x = file.read()
        encoded = x.translate(str.maketrans(b64_custom, b64_standard))
        decoded = base64.b64decode(encoded)
        out_file.write(decoded)

We can now see that this is a compiled binary when taking a quick peek at it in Detect-It-Easy. Let’s pull it into IDA Pro to see what it does.

Just as in the first data file, we will be using the same custom base64 alphabet and now opening the data2.bin file instead.

The data2.bin file turns out to be two different files packed into one. There is a separator string with the value “splitres” that is searched for. The first part that is written to disk is the AutoIt3.exe binary and the second part is the AutoIt3 script file.

If we open the data2.bin file into a hex editor and search for this separator string we can locate it. Note that this is before the bytes have been base64 decoded.

Once the two files are written to the temporary directory, the AutoIt3.exe files will be executed with the script.au3 file passed in as an argument.

To unpack these final two binaries from data2.bin I created the following python.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import base64

def b64_decode(file_bytes):
    b64_standard = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    b64_custom = 'zLAxuU0kQKf3sWE7ePRO2imyg9GSpVoYC6rhlX48ZHnvjJDBNFtMd1I5acwbqT+='
    encoded = file_bytes.translate(str.maketrans(b64_custom, b64_standard))
    return base64.b64decode(encoded)

with open(file='data2.bin', mode='r', encoding='utf-8') as file:
    file_bytes = file.read()

file_separator = file_bytes.find('splitres')

with open(file='autoit3.exe', mode='+wb') as file:
    file1_bytes = b64_decode(file_bytes[0:file_separator]+'==')
    file.write(file1_bytes)

with open(file='script.au3', mode='+wb') as file:
    file2_bytes = b64_decode(file_bytes[file_separator+8:file_separator+8+len(file_bytes)]+'=')
    file.write(file2_bytes)

After running this, we have the two files dropped to disk.

NOTE: It is worth mentioning that there is a shortcut to getting these files by acquiring them dynamically. In JoeSandbox these can both be picked up by downloading the “dropped binaries” where you will locate both of them.

Additionally, you could detonate the malware in your FlareVM and attempt to save them out of the VM, reset your VM image, and bring them back for further analysis.

De-obfuscating the AutoIt3 script

Using a tool called AutoIt Extractor, we can perform the first phase of deobfuscation. This allows us to work with a second stage of obfuscation but in the form of actual code we can interpret.

The extracted script was obfuscated via some simple appending of hex values where AutoIt3’s “BinaryToString” function converted it at the end.

Toward the end we can see where the appended hex is used.

Explaining the AutoIt3 calls
This creates a new struct that holds 0xbefa or 48,890 bytes of data.

$ixstniry = DllStructCreate("byte[" & 0xbefa & "]")

Then it calls VirtualProtect on the memory of that struct to change the page permissions to PAGE_EXECUTE_READWRITE (0x40). DllCall("kernel32.dll", "BOOL", "VirtualProtect", "ptr", DllStructGetPtr($ixstniry), "int", 48890, "dword", 0x40, "dword*", null)

BOOL VirtualProtect(
  [in]  LPVOID lpAddress,
  [in]  SIZE_T dwSize,
  [in]  DWORD  flNewProtect,
  [out] PDWORD lpflOldProtect
);

It then saves the hex bytes that were appended together from before into this memory space. DllStructSetData($ixstniry, 1, BinaryToString("0x"&$bdAFOyTD))

Finally, it calls User32.dll::EnumWindows with a pointer to this memory as a CallBack function. DllCall("user32.dll", "int", "EnumWindows", "ptr", DllStructGetPtr($ixstniry), "lparam", 0)

Resources

Moving the hex bytes into a binary file

The AutoIt3 “BinaryToString” function is used to convert the hex bytes to an ASCII string to then execute. To append all the hex together I simply used regex expressions in vscode to effectively convert the AutoIt3 code to python to dump it out into a single string.

Using a hex editor, I saved the hex bytes to a new binary file. Detect-It-Easy identifies that there is shellcode present and when opening in a hex editor we can see an MZ shortly after.

I did not fully understand how the shellcode worked but ultimately it invokes the entry point of the MZ.

We can delete the shellcode in front of it in the hex editor Detect-It-Easy recognizes it as a valid Win32 PE file.

The loader will locate two separate instances of the “AU3!EA06” string. The first it just verifies that it finds it, the second one it finds is to locate a decryption key. Below we can view the 8-byte key that it will use to decrypt the final MZ bytes of the DarkGate payload.

The decrypted bytes are saved into a buffer that will be used to copy into new memory before execution.

Finally, it copies the bytes to the new memory it allocates with VirtualAlloc and executes it.

After the VirtualAlloc, I set a hardware breakpoint on execute on the first byte of this new memory.

I let the bytes get copied over and let it break right when it’s about to execute it. At this point, I dump the section to disk from the memory map.

When opening this dump in IDA Pro we can see that we now have the final DarkGate payload to analyze.

This post is licensed under CC BY 4.0 by the author.