Goal: Reverse the latest Magniber ransomware with the focus on its PEB traversal function resolving APIs to hardcoded hashes.
Original infector: a4100b682b2b63374e4ed2fc937d9b96
Decoded payload: f51a5b8ee6a5f25aa293911702a37a34
Background:
- The ransomware served by Magnitude Exploit Kit (EK), named “Magniber,” specifically targets individuals in the Republic of Korea. Magniber checks that the potential victim’s system default language is Korean (code: 0x0412) via GetSystemDefaultUILanguage; if it is, the ransomware will terminate. Magniber generates a unique command-and-control (C2) server and ransom note website for each victim, only giving a valid response if the victim’s public IP address is located in South Korea.
#Magniber #Ransomware new variant via #MagnitudeEK with extension “.wmfxdqz”, evolved and is obfuscated now – still targets to South Korea.
Thx! @hasherezade @jeromesegura
MD5: a4100b682b2b63374e4ed2fc937d9b96 pic.twitter.com/b1BultusoG— Marcelo Rivero (@MarceloRivero) December 13, 2017
https://platform.twitter.com/widgets.js
Malwarebytes’ @hasherezade and FireEye researchers previously extensively covered some of the Magniber ransomware cryptography and basic functionality. The scope of the blog is to unpack the ransomware with the focus on its PEB traversal function resolving APIs to hardcoded hashes.
Outline:
I. Unpacking malware
Extract the first-layer Magniber ransomware payload after it decodes and injects itself via WriteProcessMemory. This process is rather trivial, and it includes simply dumping the buffer in OllyDbg.
II. Victim ID generation function
III. The PEB traversal code resolving hashes to APIs
Here, we observe interesting Magniber ransomware technique for traversing the Process Environment Block (PEB) data.
PEB is a user-mode data structure that can be used by applications to get information such as the list of loaded modules, process startup arguments, heap address amongst other useful capabilities. From MSDN more on the PEB structure, read here.
The malware traverses PEB structure to search for module hash match obtaining access to PEB via __readfsdword( 0x30 ) [fs:30h] iterating through loaded modules looking for pFunctionName and matching it with hash via ROTR macro implementing the logic of a rotate right operation.
By and large, this PEB traversal function is used to load hashes and to avoid usual sequence of LoadLibrary and GetProcAddress API from anti-virus basic detection. In this case, the ransomware resolves all Advapi32 cryptography, registry and Internet API calls.
Notably, this PEB traversal is almost an exact copy of the GitHub code belonging to the project “Position Independent Code Bindshell.”
The function C++ code works as follows:
{
int pFunctionName;
int v3;
int v4;
int v5;
_DWORD *pdwFunctionNameBase;
int v7;
int v8;
unsigned int dwFunctionHash;
int dwModuleHash;
int v11;
_BYTE *pTempChar;
_BYTE *pTempChar_;
unsigned int i;
unsigned int j;
v7 = *(_DWORD *)(*(_DWORD *)(__readfsdword(0x30) + 0xC) + 0xC);// 0x30 = PEB; 0x0C = InLoadOrderModuleList
while ( *(_DWORD *)(v7 + 0x18) )
// while (pDataTableEntry->DllBase != NULL))
{
dwModuleHash = 0;
v8 = *(_DWORD *)(v7 + 0x18);
// pDataTableEntry->DllBase
v3 = *(_DWORD *)(v7 + 0x2C);
// pDataTableEntry->BaseDllName
v4 = *(_DWORD *)(v7 + 0x30);
// pNTHeader
v5 = *(_DWORD *)(*(_DWORD *)(v8 + 0x3C) + v8 + 0x78);
/*pNTHeader >OptionalHeader.DataDirectory[0].VirtualAddress;dwExportDirRVA
*/
v7 = *(_DWORD *)v7;
if ( v5 )
// dwExportDirRVA != 0
{
for ( i = 0; i < HIWORD(v3); ++i )
// calculate module hash
{
pTempChar = (_BYTE *)(i + v4); // pTempChar
v11 = (dwModuleHash <> 13);
// dwModuleHash = ROTR32( dwModuleHash, 13 )
if ( (signed int)*(_BYTE *)(i + v4) < ‘a’ )
// if ( *pTempChar >= 0x61 )
dwModuleHash = v11 + *pTempChar;
// dwModuleHash += *pTempChar
else
dwModuleHash = v11 + *pTempChar – ‘ ‘;
// dwModuleHash += *pTempChar – 0x20
}
pdwFunctionNameBase = (_DWORD *)(*(_DWORD *)(v5 + v8 + 0x20) + v8);
// pdwFunctionNameBase = (PDWORD) ((PCHAR) pModuleBase + pExportDir->AddressOfNames)
for ( j = 0; j < *(_DWORD *)(v5 + v8 + 0x18); ++j )// for (i = 0; i < dwNumFunctions; i++)
{
dwFunctionHash = 0;
pFunctionName = v8 + *pdwFunctionNameBase;
// (PCSTR) (*pdwFunctionNameBase + (ULONG_PTR) pModuleBase)
++pdwFunctionNameBase;
pTempChar_ = (_BYTE *)pFunctionName;
do
dwFunctionHash = ((dwFunctionHash <> 13)) + *pTempChar_++;
// dwFunctionHash = ROTR32( dwFunctionHash, 13 )
while ( *(pTempChar_ – 1) );
if ( dwModuleHash + dwFunctionHash == a1 )
return *(_DWORD *)(*(_DWORD *)(v5 + v8 + 28) + v8 + 4 * *(_WORD *)(*(_DWORD *)(v5 + v8 + 36) + v8 + 2 * j))
+ v8;
}
}
}
return 0;
}
The PEB traversal function leveraged 18 times to import and resolve the following hashes to their respective functions as follows: