Let’s Learn: Dissecting Dridex Banking Malware Part 1: Loader and Avast "snxk.dll" Hooking Lib

Goal: Reverse engineer and analyze the latest “Dridex” banking malware loader and its usage of Avast “snxk.dll” hooking library.

Dridex Packed Loader 32-bit (x86) Executable (MD5: de0bb0bec9fd145a6f57e538a7dd8693)
Unpacked Dridex “ldr” Loder 32-bit (x86) Executable (MD5: 0fc7b913d0e0278d195b3606b608a223)
“snxk.dll” Injector 32-bit (x86) DLL (MD5: 105987197a3c8f76b92c4cae56fe1b16)

I. Background
II. Malware Campaign Spreading "Dridex" Banker
III. Original Dridex Packed Loader 32-bit (x86) Executable
IV. Unpacked Dridex Loader 32-bit (x86) Executable
A. Dridex Loader OutputDebugStringW(L"installing"/ L"installed")
B. Loader System Profile
C. CreateMutex: GetComputerNameA & GetEnvironmentVariableW(USERNAME)
D. Dridex Loader API and Function Resolver
E. CreateProcessW "svchost.exe" Process (flag=0xC)
F. Loader Enumerate Modules and Inject "snhxk.dll" Hooker Library
H. Loader AtomBombing Technique.
V. Unpacked "snxk.dll" Hooker 32-bit (x86) DLL
V. Yara Signature: Dridex Loader

I. Background
Dridex by far is one of the most complex and sophisticated financial banking malware on the e-crime landscape. The malware is also referred to as “Bugat” and “Cridex” by various researchers. The original Bugat malware dates back to 2010, which at some point rivaled the original “Zeus” banking malware. This malware group behind it was referenced in the Department of Justice arrest and indictment of a certain Moldovan national back in 2015. Notably, Dridex leverages AtomBombing process injection technique, initially discovered by EnSilo researchers. Before diving deeper, I highly recommend reading IBM X-Force blog titled “Dridex’s Cold War: Enter AtomBombing” detailing the Dridex method implementing this AtomBombing technique.

II. Malware Campaign Spreading "Dridex" Banker
This latest Dridex variant was distruted via an interesting chain from Microsoft Office document with macros communicating with the intermediatery server receving tasks and receiving encrypted payloads as follows: 
Finally, the Dridex loader was retrieved from the following URL as "dridex.exe":
III.  Original Dridex Packed Loader 32-bit (x86) Executable

The crypted binary leverages GdiFlush API in a loop until it reaches the decoding loop, which unpacks the loader leveraging the following API calls:


The original loader was obfuscated and packed by pretty interesting crypter with the following executable information with the program database (PDB) path.

----------Dridex Packed Loader---------

0x1F760 0x0 Characteristics: 0x0
0x1F764 0x4 TimeDateStamp: 0x5B90D07C [Thu Sep 6 07:00:12 2018 UTC]
0x1F768 0x8 MajorVersion: 0x0
0x1F76A 0xA MinorVersion: 0x0
0x1F76C 0xC Type: 0x2
0x1F770 0x10 SizeOfData: 0x33
0x1F774 0x14 AddressOfRawData: 0x28CE4
0x1F778 0x18 PointerToRawData: 0x28CE4

0x28CE4 0x0 CvSignature: 0x53445352
0x28CE8 0x4 Signature_Data1: 0x5F1B5FEA
0x28CEC 0x8 Signature_Data2: 0x48
0x28CEE 0xA Signature_Data3: 0x446A
0x28CF0 0xC Signature_Data4: 0xDA80
0x28CF2 0xE Signature_Data5: 0x6506
0x28CF4 0x10 Signature_Data6: 0x14D18F78
0x28CF8 0x14 Age: 0x1
0x28CFC 0x18 PdbFileName: EHW###%@$WHRENBRWHrjhss.pdb

IV. Unpacked Dridex Loader 32-bit (x86) Executable
The unpacked Dridex loader contains 398 functions and 4 sections (.text, .rdata, .data, and .reloc) with only one imported KERNEL32.dll and one API call OutputDebugStringW, statically. The total size of the unpacked loader is 86 KB. By far, the Dridex is more complex with obscure API calls obfuscated by its API hashing algorithm, process environment block (PEB) traversal, and Nt-level calls, meant to evade and frustrate automated analysis. Additionally, the loader also appears to leverage legitimate Avast library “snxk.dll” to evade detection.

----------Dridex Unpacked Loader-------

0x151B0 0x0 Characteristics: 0x0
0x151B4 0x4 TimeDateStamp: 0x5B8EAB53 [Tue Sep 4 15:57:07 2018 UTC]
0x151B8 0x8 MajorVersion: 0x0
0x151BA 0xA MinorVersion: 0x0
0x151BC 0xC Type: 0x2
0x151C0 0x10 SizeOfData: 0x3B
0x151C4 0x14 AddressOfRawData: 0x16804
0x151C8 0x18 PointerToRawData: 0x15204

0x15204 0x0 CvSignature: 0x53445352
0x15208 0x4 Signature_Data1: 0xF58A923F
0x1520C 0x8 Signature_Data2: 0xE81
0x1520E 0xA Signature_Data3: 0x4833
0x15210 0xC Signature_Data4: 0xCBB4
0x15212 0xE Signature_Data5: 0x23F9
0x15214 0x10 Signature_Data6: 0x7FBD8DA0
0x15218 0x14 Age: 0xE
0x1521C 0x18 PdbFileName: S:\Work\_bin\Release-Win32\ldr.pdb

A. Dridex Loader OutputDebugStringW(L”installing”/ L”installed”)
Once the packed loader is unpacked, we observe the Dridex loader loop leveraging OutputDebugStringW and wide strings “installing” and “installed.” It is also notable that the malware proceeds to call GetAdaptersInfo immediately after presumably to check for architecture and Windows version compatibility.

//////// Dridex Loader "installed" start exceprt ///////////
if ( (signed int)installing_ldr((char *)2) > 1 )
// OutputDebugStringW(L"installing")
v51 = a1;
svchost_exe_dridex_loader_process = a4;
v52 = 10240;
hash_func1((int)&v69, 10240);
v4 = func_calc((int)&v69, 0);
GetAdaptersInfo = (void (__cdecl *)(int, int *))func_hash1(0xDEE7C423, 0xDC613C9);
if ( GetAdaptersInfo )
GetAdaptersInfo(v4, &v52);
while ( v4 )
if ( *(_DWORD *)(v4 + 0x194) == 0x4B005452 && *(_WORD *)(v4 + 0x198) == 0x31A1 )
Dridex_loader_start(0, a2, a3, v4);
goto LABEL_12;
v4 = *(_DWORD *)v4;

B. Loader System Profile
Dridex loader profiles the system architecture leveraging various APIs and tries to obtain process token access. Additionally, the malware leverages RtlQueryElevationFlags to identify system privileges and configuration. The malware verifies it was launched with administrative privileges by calling the AllocateAndInitializeSid() function with the 0x20 (SECURITY_BUILTIN_DOMAIN_RID) and 0x220 (DOMAIN_ALIAS_RID_ADMINS) sub-authorities.
The Dridex loader leverages the following API call sequences to profile the system:

  • GetVersionExW
  • IsWow64Process
  • Process Token Access
    • OpenProcessToken
    • GetTokenInformation
    • AllocateAndInitializeSid
    • EqualSid
    • FreeSid
  • RtlQueryElevationFlags
  • GetSystemInfo

Additionally, the loader also uses SHRegDuplicateHKey API call to and enumerates registry keys at the following location leveraging RegOpenKeyExW, RegEnumKeyW:

  • HKLM\Software\Microsof\Windows\CurrentVersion\Policies\System
//////// Dridex Loader Registry Enum exceprt ///////////
if ( HKLM && HKLM != -1 )
HKLM = v9;
v9 = 0;
v12 = (_DWORD *)func_calc(a2, 4 * v11);
v13 = 0;
v36 = *v12 ^ 0x3F62AA29;
while ( 1 )
v33 = v13;
RegEnumKeyW = (int (__stdcall *)(int, int, char *, signed int))func_hash1(0x3D61B1D5, 0xF2B958D9);
v5 = RegEnumKeyW ? RegEnumKeyW(HKLM, v13, Microsoft, 260) : 0;
if ( v5 )
v15 = (void **)Alpha_Alloc((_WORD **)&Microsoft, (unsigned __int16 **)&v41);
v16 = WideCharToMultiByte_func_0(*v15);
v17 = v16 == v36;
if ( v17 )
v35 = 0;
RegOpenKeyExW = (int (__stdcall *)(int, char *, _DWORD, signed int, int *))func_hash1(0x3D61B1D5, 0xA8C65AB);
if ( RegOpenKeyExW )
v19 = 0x20109;
if ( v31 == v37 )
v19 = v34;
v5 = RegOpenKeyExW(HKLM, Microsoft, 0, v19, &v35);
// HKLM\Software\ Microsof\Windows\CurrentVersion\Policies\System
v5 = 0;

C. CreateMutex: GetComputerNameA & GetEnvironmentVariableW(USERNAME)
The malware creates mutex leveraging advapi32.dll’s Crypto API CryptHashData calculating an MD5 value out of the concatenated output of GetComputerNameA and GetEnvironmentVariableW(“USERNAME”).
D. Dridex Loader API and Function Resolver
The malware resolves ZwProtectVirtualMemory and GetSystemDirectory and LoadLibraryW (advapi32.dll, psapi.dll, shlwapi.dll, shell32.dll, wininet.dll)

E. CreateProcessW “svchost.exe” process (flag=0xC)
The Dridex loader leverages CreateProcessW with the creation flag 0xC (CREATE_SUSPENDED|DETACHED_PROCESS) for initial process start via “svchost.exe passing the location of the Dridex loader as a command-line argument to “C:\Windows\system32\svchost.exe” and setting the current directory as “C:\Windows\system32.”

////// Dridex Loader "CreateProcessW" Call ///////////
(L"C:\Windows\system32\svchost.exe", // ModuleFileName
L"C:\Windows\system32\svchost.exe \
"PATH_TO_DRIDEX_LOADER"", // CommandLine
// CurrentDir

Then, the loader proceeds to immediately obtain process information via the following sequence of API calls:

GetProcessId -> NtOpenProcess -> GetProcessImageFileNameW -> NtQueryInformationProcess -> \
GetProcessTimes -> ProcessToken Access

F. Loader Enumerate Modules and Inject “snhxk.dll” Hooker Library
Dridex enumerates modules via the following chain and injects “snxhk.dll” into “svchost.exe”:

CreateToolhelp32Snapshot -> Thread32First -> Thread32Next -> OpenThread -> \
NtQueryVirtualMemory -> NtReadVirtualMemory -> \ NtWriteVirtualMemory -> NtResumeThread

Additionally, the malware injects the DLL into the memory leveraging NtWriteVirtualMemory into the space of the suspended “svchost.exe.” 

H. Loader AtomBombing Technique
The Dridex loader leverages GlobalAddAtomW and GlobalGetAtomName with NtQueueApcThread with NtProtectVirtualMemory API call in end to make the memory region RWX as it is well-documented here.

//////////// Dridex Atom NtNtQueueApcThread //////////////

bool __fastcall Dridex_Atom_NtQueueApc(void *this, int edx0, int a2, int a3, int a4)

v5 = this;
v6 = edx0;
v7 = GlobalAddAtomW_GlobalGetAtomNameW_func((void *)a4);
LOWORD(v13) = v7;
if ( v7 && -1 != v7 && (v8 = func2((void *)a4), NtQueueApcThread_func
(a2, (int)v5, (unsigned __int16)v7, a3, v8 / 2)) )
ZwDelayExecution_func((void *)0x64);
v9 = func2((void *)a4);
v10 = func_calc(a4, 0);
v11 = NtReadVirtualMemory_func(v6, a3, v10, v9);
v11 = 0;
if ( v7 && -1 != v7 )
return v11;

V. Unpacked “snhxk.dll” Hooker 32-bit (x86) DLL

The injected “snhxk.dll” DLL contains 15 functions and 4 sections (.text, .rdata, .data, and .reloc) and one imported library KERNEL32.dll with two imported APIs FreeConsole and VirtualQuery, statically. The size of the DLL is 9 KB. Once run, this DLL also resolves dynamically GetProcAddress, LoadLibraryA, VirtualAlloc, VirtualProtect and retrieves LdrLoadDll.
Dridex appears to leverage snxhk.dll specifically to monitor LdrLoadDll API calls. The “snhxk.dll” appears to be related to Avast anti-virus hooker library to monitor loader.
The malware sets up a hook on NTDLL.dll!LdrLoadDll overwriting it with relative opcode “0xe9” jump.
////// Dridex "snxhk.dll "LdrLoad" Hook Exceprt /////
PVOID LdrLoadDll_dridex()

v12 = (_BYTE *)load_ntdll((int)"LdrLoadDll");
v11 = v12;
if ( *v12 == 0xE9u // jmp relative offset = "0xE9" opcode
v0 = *(_DWORD *)(v11 + 1);
v1 = v11[v0 + 5] == 0xE9u;
v11 += v0 + 5;
while ( v1 );
v10 = 0;
if ( v12 != v11 )
VirtualQuery(v11, &Buffer, 0x1Cu);
v10 = 0;
if ( Buffer.AllocationBase )
v9 = (char *)Buffer.AllocationBase + *((_DWORD *)Buffer.AllocationBase + 15);
v10 = Buffer.AllocationBase;
if ( *(_WORD *)Buffer.AllocationBase == 0x5A4D )
v10 = Buffer.AllocationBase;
if ( *(_DWORD *)v9 == 0x4550 )
VI. Yara Signature: Dridex Loader
import "pe"

rule crime_win32_dridex_banker_loader {
description = "Detects Dridex Loader September 4, 2018"
author = "@VK_Intel"
date = "2018-09-10"
hash1 = "ce509469b80b97e857bcd80efffc448a8d6c63f33374a43e4f04f526278a2c41"
$s1 = "S:\\Work\\_bin\\Release-Win32\\ldr.pdb" fullword ascii
$s2 = "OutputDebugStringW" fullword ascii
$s3 = "KERNEL32.dll" fullword ascii

$hash_resolver = { 56 57 8b fa 8b f1 8b cf e8 ?? ?? ?? ?? 85 c0 75 ?? 81 fe 29 aa 62 3f 75 ?? 33 c0 5f 5e c3}

( uint16(0) == 0x5a4d and
filesize < 300KB ) and
pe.imphash() == "cdd344983e4f44182600c69cb4fab21d" and (1 of them) or
( 1 of ($s*) and $hash_resolver )
VII. Appendix: Dridex Loader Configuration
Dridex ID: “10205”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s