Zloader Reversing

Aka: ZeusLoader, Deloader, Terdot, Zbot is a malware family that downloads Zeus OpenSSL. Parts of the source code of Zeus were leaked back in 2010 [1] and since couple of versions been forked. Each of the version has its malicious capabilities, but all in common do info stealing specially banking information. Zeus in its core does wild stuff from stealing HTTPS session before being encrypted; to split  stolen data and send it in multiple channels over different C2 server based on the stolen info-type [2]. The sent data is being encrypted using RC4 algorithm. Given that major parts of the Zeus being well known and very detectable by almost every AV; Zloader is not just a loader/packer to Zeus core functionality. There are some complicated obfuscation techniques and visual encryption implemented on every single unpacked version of Zloader that bypass security and difficulty extracting configuration. Uncommon attack vector like using Google AdSense has been observed lately [3] also attacker signs Zloader with a certificate compromised from legitimate software in order to evade detection. In this post, we gonna take a look of common Zloader 123 botnet attack that uses maldoc vector. Quickly analyze maldoc, downloader, and the well known unpacking technique with observed behavior which simple and not quite interesting. However, the second part is going to be deep dive into analyzing and reversing techniques of Zloader unpacked version.

Maldoc

SHA256 500856ee3fc13326cad564894a0423e0583154ef10531de4ab6e6d5df90d4e31

File Type Office Open XML Spreadsheet

Name tn4598151.xlsm

Size 182.62 KB (187002 bytes)

Creation Time 2021-10-04 13:17:51

Links MalwareBazaarVirusTotal, Any.run

In clear text on sheet2, the maldoc give away downloader URL, directory where it’s been dropped, and shell command to run a Dll which is the Zloader.

Enable macro is required to run the above in VBA script.

Downloaded test.dll is just an HTML! that downloads logs.php which is a Zloader Dll file!

Dll Zloader

SHA256 c4ab81d7b7d44dd6dfc4f2b69dbe3f22fbf23c1ae49ab8edac2d26f85ae4514d

File Type Win32 DLL

Names suqyatda.dll, ewviv.dll, ehev.dll, cyvi.dll, logs.php

Size 1.13 MB (1189888 bytes)

Compiler Time-stamp Mon Sep 23 01:29:14 2019

First Submission 2021-10-04 18:23:00

Links MalwareBazaarVirusTotal, Tria.ge

Zloader Dll file is been downloaded and runned in temp location. After Zloader runs:

  1. Create new process msiexec.exe and inject its loader in it.
  2. Loader sets new registry values using random hive and key names in:
    • HKCU\Software\Mircosoft\bbxk\uuwk
    • HKCU\Software\Mircosoft\bbxk\ziox
  3. Deletes original downloader and copy itself to %AppData%\Roaming\*random name\*.dll

The registry value calls the new directory for persistent in case of host rebooted.  Both registry values are encrypted with RC4 but more to that in next section

When checking memory strings for any forensics it spells out great number of C2 values. Noticed that 20 URLs has random name with fixed length. Those are called Domain Generated Algorithm DGA, unlike hardcode C2 URLs those are queried during running. More to that later in next section.

Using pe-sieve64 tool is good way to dump the unpacked Zloader from the running process which is valid PE file to be analyzed. However, just a quick debugging would give same result. In SquirrelWaffle and QakBot recent analysis [4] [5] it’s been observed that Zloader among other malwares are using same crypters/decryptor for unpacking mechanism for their loaders before injecting them in process. Following the same debugging method in [4] would reveal the packed Zloader.

Unpacked Zloader

SHA256 3A4CA58B0A2E72A264466A240C6636F62B8742FFBC96CE14E2225F0E57012E96

File Type Win32 DLL

Name unpacked_zloader_21_10_4.dll, 

Size 146.00 KB (149504 bytes)

Compiler Time-stamp Wed Jul 14 08:04:16 2021

First Submission 2021-10-18 15:32:37

Links MalwareBazaarVirusTotal, Tria.ge

The unpacked Zloader is a master piece of obfuscated functions that waste lots of analysis time to dig into. API strings among other static indicators would not be a good clue for analyzing Zloader. Beside, this malware family is known for API hashing, Visual Encryption using XOR, and RC4 encryption to encrypt strings.

There are five main topics we are going to discuss in this section when reversing Zloader: API hashing, XORing string, extracting Configuration, DGA routine, and Zeus function.

API Hashing:

Statically analyzing Zloader is a bit of a challenge. However, with a new amazing IDA plugin called HashDB from OpenAnalysis Labs [6] it’s amazing how much obfuscated strings get out the way when reversing Zloader. Just to show a case of what HashDB can do before and after shots of hashed values in a random function. The hashes been checked among large database of hashes with good prediction of hashing algorithms been used.

XORing Strings:

With API hashing out of the way. It’s important to get reversing tricks to dig into the main functions and extract configurations. There’re very limited hardcode strings in Zloader that can be clues like those.

First, let’s look at Off_186010 which is an offset of an offset of a memory location rdata:00183D80 with literal string ( #uVTN7’GQ’rxUf5Ly ). When cross referencing this offset it’s been used 4 times in two different functions. And there’s some sort of XOR function in both subroutines which reveal this is the key literal string could be an XOR key value.

 Cross referencing both sub_1658F0 and sub_173C90 routines would shows that over 120 times those functions has been called. Randomly checking any of the cross referencing like below

….skipped lines……..
text:001610E0 push offset unk_183E8E
.text:001610E5 call sub_1658F0
….skipped lines……..
text:0016444E push offset unk_184310
text:00164453 call sub_173C90
….. skipped lines……
text:00165685 push offset unk_184040
text:0016568A call sub_1658F0

We noticed both subrouties been called after a push of unknow offsets

Let’s use XOR key (#uVTN7’GQ’rxUf5Ly) with offset unk_184040 value.

Shift+E over unknow offset location

Hex: 70 00 1A 00 30 00 20 00 39 00 56 00 55 00 22 00 0D 00 6A 00 1B 00 1B 00 27 00 09 00 46 00 23 00 1F 00 57 00 29 00 56 00
key: #uVTN7’GQ’rxUf5Ly
Result: SuLT~7.Gh’$x.f.Lt#.VON,’`Q.r>UE5Sytu.T.7

The XORed value/result doesn’t make sense. If anything noticeable that the Hex values has zeros in sequence. Which indicate sub_1658F0 is for wide character and this makes and sub_173C90 for normal character. let’s try again deleting all repeated zeros and XOR with the key

Hex: 701A3020395655220D6A1B1B270946231F572956
key: #uVTN7’GQ’rxUf5Ly
Result: Software\Microsoft\

It’s not just strings that been obfuscated, some API calls been XORed too. Almost 120 offset being pushed in stack which means 120 strings are being XORed and to make it readable; Appendix – A contains all the strings with addresses after been XORed.

Configuration:

The other string ‘qhpacozsstaznupphhedjtuoww’ is 26 length. It’s crossed referenced twice in two separate routines.

snipped assembly from sub_161E40 and sub_1673D0 routines

.text:00161EE3 push offset aQhpacozsstaznu ; “qhpacozsstaznupphhedjtuoww”
.text:00161EE8 push offset unk_184404
——-skipped lines—
text:001673D0 sub_1673D0 proc near ; CODE XREF: sub_171400+40↓p
.text:001673D0 push ebp
.text:001673D1 mov ebp, esp
.text:001673D3 push edi
.text:001673D4 push esi
.text:001673D5 mov esi, ecx
.text:001673D7 call sub_1809A0
.text:001673DC mov edi, [eax+30h]
.text:001673DF mov ecx, esi
.text:001673E1 call sub_1809A0
.text:001673E6 add eax, edi
.text:001673E8 push 36Fh
.text:001673ED push offset unk_184404
.text:001673F2 push eax
.text:001673F3 call sub_171D80
.text:001673F8 add esp, 0Ch
.text:001673FB mov ecx, esi
.text:001673FD call sub_1809A0
.text:00167402 mov edi, [eax+34h]
.text:00167405 mov ecx, esi
.text:00167407 call sub_1809A0
.text:0016740C add eax, edi
.text:0016740E push 64h ; ‘d’
.text:00167410 push offset aQhpacozsstaznu ; “qhpacozsstaznupphhedjtuoww”

In both routines notice a repeated push to an offset unk_184404. This offset contains configurations. Noticed that both offset passed into a function sub_1656B0 (name decrypting_rc4)

Decrypting_rc4 function calls multiple function and those are calling other functions. What we are looking here is RC4 algorithm.

To have mind map where RC4 algorithm location lets Xref-from Decrypting_rc4 function where Config strings and key retrieved

Now let’s go back to the configuration ‘config’ offset in data block and copy its hex value to CyberChef and use RC4 algorithm to decrypt it with the key (qhpacozsstaznupphhedjtuoww)

Notice three things: got C2 URLs, list in Table-1, and 123 which is ID for this variant of Zloader, and at the tail there’s this value (djfsf02hf832hf03) which is another RC4 key that decrypt the registry values in \HKEY_CURRENT_USER\Software\Microsoft\bbxk and also encrypt decrypt traffic with C2 [7].

Table-1

123
hxxp://gipc.in/post[.]php
hxxp://fbhindia.com/post[.]php
hxxp://ecolenefiber.com/post[.]php
hxxp://design.ecolenefiber.com/post[.]php
hxxp://beta.marlics.ir/post[.]php
hxxp://hari.pk/post[.]php
hxxp://iaiskjmalang.ac.id/post[.]php
hxxp://314xd.com/post[.]php
hxxp://ejournal.iaiskjmalang.ac[.]id/post.php
hxxp://duanvn.com/post[.]php
djfsf02hf832hf03

Decrytped registry key value contains host name and the Zloader in %AppData% directory.

DGA:

Zloader know for using DGA algorithm and we notice above some of the generated 32 character length URLs. To find the DGA function in this we can look for .com or post.php strings that been deobfuscatd in the previous section of XORing strings.

when cross referencing .com from rdata:001849B4 location we find that it’s been called by one function and let’s name that function the_dga

The_dga function has been called one by another function. Based on [8], the caller of DGA routine does it math calculating values called Seed based on time and RC4 key (djfsf02hf832hf03) (second key). So the values generated are much different each day passed in used GetLocalTime and SystemTimetoFileTime APIs. Notice that the_dga function has passed value of 32 which is the same length of the URL string with Seed value which in this case makes the entire caller function to calculate Seed value. followed by post.php and https while loop. The caller function got many obfuscated function that slows down analysis and it get complicated calculating generated domains manually.

Zeus Items:

Zeus uses item ID as list below which is the main one, there are more extended list based on Zloader version [1] [2] [7]. Each ID passed into a function and dissect information from victim machine. When that information stored in attacker SQL filed it show retrieved info about the host.

Item IDValue
10001SBCID BOT ID
10002 SBCID BOTNET
10003 SBCID BOT VERSION
10005 SBCID NET LATENCY
10006 SBCID TCPPORT S1
10007 SBCID PATH SOURCE
10008 SBCID PATH DEST
10009 SBCID TIME SYSTEM
10010 SBCID TIME TICK
10011 SBCID TIME LOCALBIAS
10012 SBCID OS INFO
10013 SBCID LANGUAGE ID
10014SBCID PROCESS NAME
10015 SBCID PROCESS USER
10016 SBCID IPV4 ADDRESSES
10017 SBCID IPV6 ADDRESSES
10018 SBCID BOTLOG TYPE
10019 SBCID BOTLOG

To get to Zeus item values and function we need to search strings in IDA to find one the common ID values since they are constant.  

Notice that most the calls are sub_1657B0, let’s call it z_items_main, it’s been crossed referenced 17 times. List of Zeus items being found in 123 variant.

Item IDValue
10001SBCID BOT ID
10003 SBCID BOT VERSION
10006 SBCID_PING
10007 SBCID PATH SOURCE
11014 SBCID_GET_FILE
11015 SBCID_GET_FILE_VER
11031 SBCID_LOG_ID_EXT
11032 SBCID_LOG_ERR_CODE
11033 SBCID_LOG_MSG
10022 SBCID_DEBUG
10025 SBCID_MARKER
20001 CFGID_LAST_VERSION
20000 SBCID_BOTLOG
20005 CFG_HTTP_FILTER
20006 CFGID_HTTP_POSTDATA_FILTER
20008 CFGID_DNS_LIST

Just to give an example of the level of obfuscation on every stage of Zloader. Not all the items ID values are retrieved in decimal passed to the function. Some values passed into another function and require to calculate separately like below in v29 value return from sub_167890 .

To give an example of how Zeus item works let take a look at this function sub_177110.

sub_16F780 has (20001: CFGID_LAST_VERSION) that updates Zloader version. Looking at it in the disassembler would show so much obfuscated function, but to have an idea of what possibly this update could do let’s see the leaked source code having this similar Item ID in similar fashion [9].

The successful update would lead to update registry values in HKCU\Software\Mircosoft\bbxk\ which points to %AppData% directory of possible the new Zloader that has new C2 connections

Finally, to have an idea how Zeus function being called here’s a mind map when Xref-to it.

Appendix A

AddressXORed string
rdata:00183DEDkernel32.dll
rdata:00183DFAhttp
rdata:00183E26post
rdata:00183E37.63
rdata:00183E3BWininet.dll
rdata:00183DE0Imagehlp.dll
rdata:00183DB0C:\Windows\SystemApps
rdata:00183D9CLocal
rdata:00183D92.exe
rdata:00183D50NtQueryVirtualMemory
rdata:00183D43Bcrypt.dll
rdata:00183D38Ftllib.dll
rdata:00183D2ASamlib.dll
rdata:00183D20Post.php
rdata:00183E47Ntdll.dll
rdata:00183E5CCmpMem64
rdata:00183E70INVALID_BOT_ID
rdata:00183E8E\start
rdata:00183EA0HideClass
rdata:00183EB4advapi32.dll
rdata:00183ED0ABCDEFGHIJKLMNOPQRSTUVWZabcdefghijklmnopqrstuvwz
rdata:00183F21ws2_32.dll
rdata:00183F3BShlwapi.dll
rdata:00183F47crypt32.dll
rdata:00183F60NtProtectVirtualMemory
rdata:00183F77GetMem64
rdata:00183F90Get
rdata:00183FA0Software\Microsoft\Windows\CurrentVersion\Run
rdata:00183FFCUrlmon.dll
rdata:0018400Awtsapi32.dll
rdata:00184040Software\Microsoft
rdata:00184068tmp
rdata:0018407CIphlpapi.dll
rdata:0018408CVersion.dll
rdata:0018409Erpcrt4.dll
rdata:001840AADll
rdata:00184111wldap32.dll
rdata:00184165ole32.dll
rdata:0018416Fpsapi_dll
rdata:00184180NtFreeVirtualMemory
rdata:001841A0NtSetContextThread
rdata:001841B3Winsta.dll
rdata:001841D0user32.dll
rdata:001841E0Software\Microsoft\WindowsNT\CurrentVersion
rdata:00184288gdi32.dll
rdata:00184292Gdiplus.dll
rdata:001842C0regsvr32.exe
rdata:001842F0RtlCreateUserProcess
rdata:00184310NtWriteVirtualMemory
rdata:00184330InstallDate
rdata:001843B0NtReadVirtualMemory
rdata:001843E0RtlCreateProcessParameters
rdata:00184780Connection_close
rdata:00184794Dnsapi.dll
rdata:001847BCsecur32.dll
rdata:001847D0kernel32.dll
rdata:001847F0NtGetContextThread
rdata:00184820Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36.
rdata:00184892NtResumeThread
rdata:001848B0SeSecurityPrivilege
rdata:00184914shell32.dll
rdata:00184920Ntdll.dll
rdata:00184940LdrGetProcedureAddress
rdata:00184957netapi32.dll
rdata:00184964Mpr.dll
rdata:0018496Chttps:\\
rdata:00184975X64Call
rdata:00184980NtAllocateVirtualMemory
rdata:001849B4.com
rdata:001849BAGlobal
rdata:001849CAWinscard.dll
rdata:001849D7Cabinet.dll
rdata:001849E3Userenv.dll
rdata:001849EFNcrypt.dll

References

[1] Zeus opensource, https://github.com/Visgean/Zeus

[2] Titans’ revenge: detecting Zeus via its own flaws, https://www.honeynet.it/wp-content/uploads/Papers/04-Titans%20revenge.pdf

[3] Hide and Seek | New Zloader Infection Chain Comes With Improved Stealth and Evasion Mechanisms, https://www.sentinelone.com/labs/hide-and-seek-new-zloader-infection-chain-comes-with-improved-stealth-and-evasion-mechanisms/

[4] The Squirrel Strikes Back: Analysis of the newly emerged cobalt-strike loader “SquirrelWaffle” , https://elis531989.medium.com/the-squirrel-strikes-back-analysis-of-the-newly-emerged-cobalt-strike-loader-squirrelwaffle-937b73dbd9f9

[5] QakBot Quick analysis, https://twitter.com/aaqeel87/status/1443255927000424449?s=20

[6] HashDB project, https://hashdb.openanalysis.net/#section/Using-The-API/Hash-Format

[7] The “Silent Night” Zloader/Zbot , https://www.malwarebytes.com/resources/files/2020/06/the-silent-night-zloader-zbot_final.pdf

[8] The DGA of Zloader, https://bin.re/blog/the-dga-of-zloader/

[9] Zeus source code, https://github.com/Visgean/Zeus/blob/c55a9fa8c8564ec196604a59111708fa8415f020/source/client/dynamicconfig.cpp