Inside Brazil’s Financial Malware Ecosystem: Deep Dive into the Astaroth

This post is the second part of a three-part series of analyses concerning the ecosystem of Brazilian banking malware. We began with a sample from a recent Eternidade Stealer campaign, examining its infection chain all the way to the banking malware deployed on the victim’s device. Now, we will continue using the same analytical methodology, this time focusing on a sample from a recent Astaroth campaign, collected by Bradley Duncan and featured on his website, malware-analysis-traffic.net (thank you so much man…).

Through this analysis, you may have noticed a recurring pattern in the structure of the infection chain, as well as in the technologies employed, such as the use of AutoIT scripts and the choice of Delphi for developing the malware. Ultimately, however, you will see that, despite certain similarities, Astaroth is a far more complex piece of malware than Eternidade Stealer, particularly regarding its code obfuscation.

Threat Summary

Astaroth, also known as Guildma, is one of the most well-established families of banking trojans within the Latin American ecosystem. Developed primarily in Delphi and publicly documented since at least 2017, the malware has a history of campaigns targeting users, predominantly in Brazil, by employing social engineering, multi-stage infection chains, the abuse of legitimate Windows binaries, and evasion techniques to compromise systems and facilitate financial fraud.

Throughout 2025 and 2026, Astaroth operators has shown significant evolution in its distribution and control mechanisms. In addition to traditional email-based phishing campaigns, its operators have incorporated automated propagation components via WhatsApp Web (wich we’ll not cover in this post). These capabilities allow the malware to exploit existing trust-based relationships between contacts, thereby extending the reach of its campaigns.

Below is a summary profile of the Astaroth threat.

AttributeCharacterization
Malware familyAstaroth
Alternative nameGuildma
MITRE ATT&CK Software IDS0373
ClassificationBanking Trojan / Information Stealer / RAT
Publicly documentedSince at least 2017
Primary targetingBrazil
Target platformMicrosoft Windows
Main payload languageDelphi
Infection-chain technologiesLNK, ADS, AutoIt, Delphi, Python and JavaScript, depending on campaign
Primary objectivesBanking credential theft and financial fraud
Persistence mechanismsStartup-folder shortcuts and other campaign-dependent mechanisms
C&C architecture of this campaignRaw TCP via Pinggy relay and HTTP configuration/update channel
AttributionFinancially motivated cybercrime operators

Below you can see an simplified overview of the infection chain, that we will analyze in this post.

As we can observe, the infection chain for the Astaroth campaign actually contains more layers than those we saw in the previous post regarding Eternidade Stealer. Astaroth makes interesting use of the NTFS Alternate Data Stream, loading the scrobj.dll DLL via regsvr32.exe, with the aim of remotely downloading the entire set of components necessary for the continuation of the infection chain, in the C:\Users\Public\Libraries.cache\PLAX directory.

Below, we can observe the Tactics, Techniques, and Procedures (TTPs) correlated with each phase of the Cyber ​​Kill Chain that are persistently executed by Astaroth in its campaign analyzed in this post.

ATT&CK IDTechnique NameKill Chain Phase
T1566.002Phishing: Spearphishing LinkDelivery
T1204.001User Execution: Malicious LinkExploitation
T1204.002User Execution: Malicious FileExploitation
T1059.003Command and Scripting Interpreter: Windows Command ShellExploitation
T1027.010Obfuscated Files or Information: Command ObfuscationExploitation
T1218.010System Binary Proxy Execution: Regsvr32Exploitation
T1059.010Command and Scripting Interpreter: AutoHotKey & AutoITInstallation
T1564.004Hide Artifacts: NTFS File AttributesInstallation
T1027Obfuscated Files or InformationInstallation
T1027.007Obfuscated Files or Information: Dynamic API ResolutionInstallation
T1027.009Obfuscated Files or Information: Embedded PayloadsInstallation
T1027.013Obfuscated Files or Information: Encrypted/Encoded FileInstallation
T1036.008Masquerading: Masquerade File TypeInstallation
T1140Deobfuscate/Decode Files or InformationInstallation
T1055.012Process Injection: Process HollowingInstallation
T1547.001Boot or Logon Autostart Execution: Registry Run Keys / Startup FolderInstallation
T1059.001Command and Scripting Interpreter: PowerShellInstallation
T1057Process DiscoveryInstallation
T1518.001Software Discovery: Security Software DiscoveryInstallation
T1622Debugger EvasionInstallation
T1497.001Virtualization/Sandbox Evasion: System ChecksInstallation
T1497.002Virtualization/Sandbox Evasion: User Activity Based ChecksInstallation
T1564.003Hide Artifacts: Hidden WindowInstallation
T1083File and Directory DiscoveryInstallation
T1012Query RegistryInstallation
T1016System Network Configuration DiscoveryInstallation
T1106Native APIInstallation
T1071.001Application Layer Protocol: Web ProtocolsCommand and Control
T1095Non-Application Layer ProtocolCommand and Control
T1090.002Proxy: External ProxyCommand and Control
T1105Ingress Tool TransferCommand and Control
T1082System Information DiscoveryActions on Objectives
T1614.001System Location Discovery: System Language DiscoveryActions on Objectives
T1010Application Window DiscoveryActions on Objectives
T1056.001Input Capture: KeyloggingActions on Objectives
T1115Clipboard DataActions on Objectives
T1113Screen CaptureActions on Objectives
T1059.007Command and Scripting Interpreter: JavaScript/JScriptActions on Objectives
T1529System Shutdown/RebootActions on Objectives
T1070.004Indicator Removal: File DeletionActions on Objectives
T1041Exfiltration Over C2 ChannelActions on Objectives

Let’s deep dive into the Astaroth infection chain!!


Analyzing the Phishing E-mail and Zip/LNK File

As is quite characteristic of Astaroth campaigns, initial access is gained through phishing emails containing malicious links. The image below shows an email received by a victim of the campaign we are analyzing in this post, it is in Brazilian Portuguese and centers on the signing of contracts via DocuSign.

When the link in this email is clicked, the traffic is redirected until it reaches the server containing the malicious ZIP file, which is then downloaded onto the victim’s device, as we can see on the image below.

Inside this ZIP file, there is a Windows shortcut that bears the same name as the ZIP file itself.

This shortcut essentially executes cmd.exe, containing an obfuscated command line, as can be seen in the image below.

In short, when the shortcut is executed, a loop is implemented that will rebuild the regsvr32.exe command, which will execute the scrobj.dll DLL in an NTFS ADS located in the file C:\Users<user>\AppData\Local\Temp\n1LUQ7.log:h6JSb, which will download it via the URL https[:]//plosancol[.]aguamammillaria[.]cfd/?1/_x. Below, we can see that the NTFS ADS h6JSb present in the n1LUQ7.log artifact is indeed the scrobj.dll DLL.

This download will place all components into the directory C:\Users\Public\Libraries.cache\PLAX\ and create a PowerShell script for persistence in the directory C:\Users<user>\AppData\Roaming\ Microsoft\Windows\Start Menu\Programs\Startup. Upon system logon, this script will execute the binary Beatz.LEDPRO.09662.8729.422.exe, using Beatz.LEDPRO.09662.8729.422.log as an argument.

Within the C:\Users\Public\Libraries.cache\PLAX\ directory, there are also several components that will be used later in the infection chain, such as metrics.mca and dump.log, as well as components related to a WhatsApp spambot.


Analyzing the AutoIT Loader

The binary Beatz.LEDPRO.09662.8729.422.exe is an AutoIT interpreter, as can be seen below.

We can reasonably assume that the artifact presented as evidence is an AutoIT script. This hypothesis is confirmed, as can be seen below.

As we can see in the excerpt shown in the image below, the AutoIT script appears more complicated than it actually is. Essentially, it concatenates data, represented in hexadecimal format as strings, into a single blob, which is then converted into binary data. With a little experience, it’s possible to see that the first 4 hexadecimal bytes of the blob are 4D 5A, that is, the magic bytes of every PE executable file for Windows systems.

With a few simple modifications to the large blob present in the AutoIT script, combined with a hex-decode transform, we have the PE artifact in our hands.


Analyzing the Delphi Loader

This binary, which the AutoIT script loads into memory, is a DLL developed in Delphi, a combination typical of Brazilian malware, as is the use of AutoIT, tasked with decoding and injecting Astaroth into a sacrificial process.

The CAPA rule matches provide a strong clue regarding the loading implementation methods, while disregarding false positives, such as matches related to the RC4 algorithm.

The final Astaroth sample is encrypted in the metrics.mca artifact, which this loader is responsible for collecting, decoding, and injecting into memory.

The first relevant action the loader takes is to search for the metrics.mca artifact located in the same directory as the other components downloaded in the previous phase of the infection chain.

To locate this artifact, a search routine is implemented, which incorporates the use of WinAPIs such as FindFirstFileW.

Upon encountering this artifact and loading it, the loader initiates a decoding routine for it, using 0x2a as a single-byte key.

The algorithm is extremely simple, essentially consisting of a loop that subtracts the byte 0x2a from each byte of the artifact.

By performing this decoding using Malcat’s transform sub feature, we obtain the next decoded stage.

The loader also implements the injection of this decoded payload into the memory of a sacrificial process. Although it attempts to hide the name of the process to be used for the injection, employing a technique known as “Stack Strings“, Binary Ninja was able to easily recover the string within the HLIL. Below we can see that this sacrificial process is RegSvcs.exe, part of the .NET framework.

Since the binary is developed in Delphi, Binary Ninja (and any other reverse engineering software) struggles to reconstruct pseudocode that is both simple and illustrative. Therefore, to make it easier to understand, I used scripting to generate the output below, which clearly illustrates the code flow of the function I’ve named ‘loader_hollow_process‘.

This function implements the Process Hollowing technique on a sacrificial process, specifically, by injecting and executing Astaroth within the context of the RegSvcs.exe process.


Astaroth Reverse Engineering

The final payload of Astaroth is also an executable developed in Delphi, following the pattern typical of the Brazilian banking malware ecosystem (AutoIT loaders paired with Delphi-based malware). It features a very broad range of targets, encompassing Brazilian banks and fintechs.

Its capabilities include credential harvesting with browser detection, monitoring of the foreground window, targeted collection of keystrokes and clipboard data, the use of exclusion lists to evade analysis, the receipt of remote commands, a user interface that simulates software updates, modification of browser settings, management of temporary files (staging), and the remote execution of JScript. The execution flow of Astaroth’s actions is outlined at a high level below.

As can be seen in the image above, there are two distinct layers of obfuscation:

  • String encryption;
  • Encryption of the C&C/logging configuration file.

Resolving these layers of obfuscation is crucial for the execution of Astaroth’s subsequent capabilities. Therefore, we will first examine how the strings are decrypted, and how the file containing C&C information is decrypted.

Reconstructing Astaroth’s String Decryption Routine

During the reverse engineering of Astaroth’s final payload, I identified a custom string protection mechanism designed to conceal information used throughout the malware’s execution, including browser identifiers, banking targets, and anti-analysis artifacts.

Rather than relying on a conventional cryptographic algorithm, the analyzed sample implements multiple reversible transformations involving XOR operations, byte arithmetic, character substitution, and custom encoding.

An important characteristic of this implementation is that not every protected string follows the same decoding path. While some strings require only the primary decoding routine, others contain an additional encoded representation that must be processed before the original plaintext can be recovered.

Below, you can see a snippet where the function responsible for decrypting strings receives an encrypted blob as an argument, along with comments generated by running the decryption script for Binary Ninja (link provided at the end of the post).

Before processing its protected strings, Astaroth initializes a decoding key derived from a hardcoded encoded seed.

Interestingly, the initialization routine introduces random alphanumeric characters around this seed. Three padding distributions were observed in the analyzed code: 9+3, 6+6, and 3+9 characters, corresponding to a total of 12 padding characters.

Although this may suggest that a different key is generated during each execution, the selected prefix and suffix lengths are passed to ExtractAndDecodeEmbeddedKeySeed function (named by me.. of course).

This routine removes exactly those characters and recovers the fixed 43-character seed EMBMAMDMSLXLWMQLVMONEMRMDMMMHNHNJNKLVNCMBNI. The random padding therefore has no influence on the effective decoder key. After derivation, the resulting Delphi UnicodeString is cached in global variable called (by me) real_key.

The recovered seed is not Base64. It consists of one salt character followed by 21 encoded character pairs. The initial E produces a salt value of 4. For each pair, DecodeSaltedBase25Pairs function computes:

salt = seed[0] - 'A'
intermediate =
25 × (first - 'A') + (second - 'A') - salt - 100

Below, we can observe the implementation within the Astaroth code.

This operation produces 21 intermediate characters. Their CP1252 byte representation is:

c5 c4 c7 d6 c2 c1 d4 c0 d2 e1 d5
c7 d0 cb e4 e6 e7 c0 df c5 e5

TransformKeyBytesByLength function then transforms each intermediate byte using:

key_byte = (input_length + 2 - intermediate_byte) mod 256

Because the intermediate sequence contains 21 bytes, the effective operation for this sample is:

key_byte = (23 - intermediate_byte) mod 256

The resulting 21-byte decoder key is:

RSPAUVCWE6BPGL310W8R2

The following Python snippet, executed in the Binary Ninja Python Console, reproduces both seed-decoding stages and recovers the effective key.

After reconstructing the key, the malware processes its protected strings through a sequence of reversible transformations. First, the hexadecimal representation of the encrypted data is converted into bytes. The decoder then applies the reconstructed key cyclically, combining XOR operations with a subtraction involving adjacent ciphertext bytes.

The resulting byte sequence is reversed and subjected to further arithmetic transformations, followed by a salted, base-25-like character-pair decoding stage. Finally, the decoded sequence is reversed again and transformed using an arithmetic constant derived from the key length.

At this point, the routine produces the first-layer output. However, this output does not necessarily correspond to the final plaintext.

Some protected strings undergo an additional encoding stage. In these cases, the output of the primary decoder contains an encoded payload surrounded by wrapper characters. The nested decoder reverses this intermediate string, removes the wrapper, and interprets the remaining characters as pairs representing positions in a custom alphabet.

Below we can see the macro function that orquestrate this decode routine. The routine hex-decodes the encoded UnicodeString, applies the chained XOR/delta transformation, performs two reversals and two byte-arithmetic stages, and decodes the salted radix-25 representation as I explain earlier.

Parses a protected UTF-16 hexadecimal string into ciphertext bytes. The first byte initializes the chaining state. Each subsequent byte is XORed with the cyclic decoder key, subtracted from the previous ciphertext byte using a one-based modulo-255 operation, and appended to the output as a Unicode character.

The decoder uses a chained one-based modulo-255 subtraction. When the XORed byte is not greater than the previous ciphertext byte, it adds 255 before subtracting. This differs from conventional byte subtraction modulo 256.

By understanding the string decryption algorithm, we can test implementations within the Binary Ninja Python Console. I captured an example string and passed it to a Python implementation of this decryption routine, as we can see below.

As we can see on imagem above, the decryption occur successfully, showing the name of a debugging tool.

By understanding the string decryption algorithm, it was possible to implement a script integrated into Binary Ninja designed to identify encrypted strings, pass them through the decryption algorithm, and generate output in the console, as well as add comments to both the Disassembly and the HLIL views.

This automation substantially reduces the manual effort required to analyze functions that reference protected strings. More importantly, recovering these strings provides additional context for understanding the malware’s internal logic, including browser identification, target selection, and anti-analysis functionality.

The reconstructed algorithm and its automated implementation demonstrate how reversing a custom obfuscation mechanism can transform otherwise difficult-to-interpret code into meaningful information for further reverse engineering of this sample (the link to the code is at the end of the post.).

The extractor recovered 732 first-layer strings. Of these, 453 matched the nested format, producing 426 unique nested plaintext values.

Financial Target Selection

Astaroth does not compare the active browser context against one flat list. The main routine decrypts every token in a rule group and requires all of them to occur in the candidate string. The caller of encrypted strings to iterates the groups and returns a match when any complete group succeeds. In simplified form, the logic is:

match(candidate, rule_groups) = any(
all(token in candidate for token in group)
for group in rule_groups
)

This design permits both simple rules, such as a single domain, and context-sensitive rules composed of a domain plus a path or page fragment. The Banco do Brasil matcher at the function code snippet below, for example, builds groups containing values such as internacional.bb.com.br, bblam.bb.com.br, brasil.com, and bb.com before applying the generic matching engine to the monitored browser/window string.

The decrypted corpus contains 426 unique nested plaintext values, including at least 146 strict domain-shaped strings. After removing internal classifier tags and normalizing obvious domain fragments, the following targets were recovered.

Banks, Investment Platforms, and Financial Institutions

It was identified the following targeted platforms:

  • Banco do Brasil, Caixa Econômica Federal, Banco Inter, Banestes, Banco Original, Superdigital, Grafeno, Banese, Itaú, Santander, Bradesco, Sicredi, Banrisul, and Sicoob.
  • ViaInvest, Banco Master, Agibank, Cora, Cetelem, Banco Alfa, Banco Afro, Social Bank, PJBank, Banco Guanabara, Flow Banco, Will Bank, Banco do Nordeste, BRB, Banpará, NBC Bank, Banco ABC Brasil, TotalBank, NetBank, Paraná, and Banco Arbi.
  • BTG Pactual, Banco BMG, Mercantil do Brasil, Banco da Amazônia, Modal, Ágora Investimentos, XP, C6 Bank, Nubank, Neon, Toro Investimentos, Clear, BS2, Banco Fibra, Pine, Safra, Genial Investimentos, Sofisa, Méliuz, and Rico.
  • YetBank, WQ3, NewBank, BV, GFT Bank, BIP, CCB Brasil, MokaBank, Maybank, O Agro Bank, Banco Pan, Banco Paulista, and BK Bank.
  • Unicred and Uniprime, in addition to the cooperative targets listed separately below.

Representative literal rules include caixa.gov.br, gerenciador.caixa.gov.br, loginx.caixa.gov.br, itau.com.br, santander.com.br, ib12.bradesco.com.br, ibpf.sicredi.com.br, ibpj.sicredi.com.br, banrisul.com.br, sicoob.com.br/sicoobnet, safraempresas.com.br, bancointer.com.br, and nubank.

A local path, C:\Sicoobnet, also appears in the decrypted corpus, suggesting awareness of the locally installed Sicoob environment in addition to browser-based targeting.

Credit cooperatives

  • Ailos, ViaCredi, Transpocred, Acentra, Civia, Evolua, Credifoz, ViaCredi Alto Vale, Unilos, Credicomin, Crevisc, CredCrea, and Acredi.

The generic .coop.br token broadens the matching surface beyond the explicitly named cooperatives.

Payment, fintech, merchant, and business platforms

  • XPAG/Idez, PayPal, Stone, Asaas, Omie, Aegro, Mercado Pago, MoneyP, Mercado Livre, Bling, Concil, Dattos, WK, Coinscrap Finance, OpenGalaxy, Procfy, and MagaluPay.
  • eWally, PicPay, BanQi, Coiban, RMSS, Malga, Celcoin, IOPay, Appmax, Efí, Bazk, InovaPay, Stripe, Click2Pay, Ebanx, PagBrasil, Iugu, PayBrokers, and BraPay.
  • Shopify, ShopeePay, Shopee, Fstatui, and WBA/IWBA Recebíveis.

Additional broad fragments such as banking, banco., .bank, .banco, and pay. allow to recognize services not represented by a dedicated brand rule. Internal values such as xBB, xCEF, xST, and xMPAGO are classifier tags assigned after a match, they are not domains or network indicators.

Cryptocurrency services

  • OKX, Polygon, NovaDAX, CEX.IO, Paxful, Bitstamp, Bitpanda, Bitfinex, Bitfy, eToro, Bybit, Bitso, Huobi, Blockchain.com, NiceHash, OKCoin, Paybis, Luno, Trust Wallet, and Gemini.
  • PooCoin, CoinMarketCap, Uniswap, BscScan, Etherscan, Binance, BitcoinTrade, PancakeSwap, MetaMask, Foxbit, LocalBitcoins, Mercado Bitcoin, and Coinbase.

The MetaMask rules are particularly revealing. One group combines metamask.io, home.html, import, and phrase, another combines metamask.io, home.html, and -phrase. Because all tokens in a group must match, these rules specifically identify seed-phrase import contexts rather than the MetaMask domain in general.

Gambling and gaming services

  • KTO, Eskybet, PG Soft, Blaze, Onebra, Bet4, Jonbet, Superbet, and CassinoPix.

These strings are evidence of the pages and applications the malware recognizes. They do not demonstrate outbound connections to the named organizations.

Context-aware keylogging and clipboard theft

The credential-capture path is custom code rather than a capability inferred from imports. Astaroth installs a global low-level keyboard hook:

Before collecting a key, the callback verifies that GetForegroundWindow still corresponds to the window selected by the controller. It then obtains the current keyboard state with GetKeyboardState, uses the target thread’s keyboard layout, translates the virtual key through ToAscii, and appends the result to the capture buffer.

The decrypted strings show how non-printing keys are represented in the log:

[Backspace]
[END]
[HOME]
[Delete]
[UP]
[RIGHT]
[DOWN]
[Enter]
[Numlock]
[LEFT]
[Control+

The marker === is written when the foreground-window title changes, while xXxXx is used when the capture session is initialized. As a result, the captured input is associated with the page or application in which it was entered rather than being stored as an undifferentiated keystroke stream.

Clipboard theft is part of the same callback. When Control is held and the virtual key is V, the code calls ReadUnicodeClipboardText function, named by me.

That function opens the clipboard, requests CF_UNICODETEXT, locks the returned global-memory object, and copies the text. Values shorter than 999 characters are inserted into the same capture stream with delimiters. This lets Astaroth collect pasted credentials, account identifiers, cryptocurrency addresses, and other values that may never be typed one character at a time.

The input-blocking hooks must be described separately from the keylogger. Remote commands 0x52 and 0x53 install and remove a second pair of hooks: the keyboard callback function suppresses Windows keys and selected Alt/Control shortcuts, while the mouse callback function blocks WM_MOUSEWHEEL. These hooks constrain the victim’s interaction; they are not the primary credential-capture routine.

Banking-software and browser interference

Remote command 0x3D reaches the process-control routine. The decrypted process list is exact:

AplicativoBradesco.exe
NavegadorExclusivoBradesco.exe
java.exe
iexplore.exe
opera.exe
MicrosoftEdge.exe
msedge.exe
firefox.exe
chrome.exe

Below we can see on the code.

The malware supports two termination paths for every entry. One constructs taskkill /f /im and passes it to the common WinExec wrapper.

The other resolves the process ID by image name and calls OpenProcess followed by TerminateProcess. A check for the decrypted value AVAST Software influences which path is selected. This is stronger evidence than the presence of process-name strings alone: the names are passed directly into confirmed termination functions.

The core also checks for the names Topaz OFD and AppBrad.

These checks indicate awareness of banking/security software associated with the Bradesco environment, although the static code should be described as an environment check rather than proof that either product is disabled.

Command 0x3B reaches and modifies browser configuration. For Chrome and Edge, the malware opens each browser’s Local State file and replaces the enabled hardware-acceleration setting with:

"hardware_acceleration_mode":{"enabled":false},"hardware_acceleration_mode_previous":false

For Firefox, it creates or updates user.js in profile directories with:

user_pref("layers.acceleration.disabled", true);

Afterwards, a loop that modifies the configuration file is executed via the same WinExec wrapper.

The confirmed behavior is the disabling of hardware acceleration in Chrome, Edge, and Firefox. Making overlays or browser manipulation more reliable is a plausible purpose, but remains an inference.

Fake-update distraction

The decrypted UI strings expose a Portuguese Windows Update screen:

Trabalhando em Atualizações
Instalando Atualizações
Configurando Atualizações
Concluídas.
Não desligue o computador.

Timer-driven code rotates the displayed phase and updates a progress value. This provides a full-screen distraction while other operator-controlled actions take place. The fake-update implementation is confirmed; the exact action concealed during any individual activation depends on the command sequence received from the controller.

Remote command execution and host control

The interactive dispatcher function parses the first command value as an integer, masks it with 0x7F, and selects a handler from a large switch table. The batch parser splits tilde-delimited records, and forwards parsed arrays to the dispatcher. More than 70 numeric identifiers are accepted, only handlers whose behavior is supported by code review are named below.

CommandConfirmed or strongly supported behavior
0x11Responsive delay while continuing to pump messages
0x17Build and send the victim/controller profile
0x1DForce a system restart
0x1EForce a system shutdown
0x1FExecute DisplaySwitch.exe 1
0x20Parse and apply a multi-field runtime configuration
0x22 / 0x23Perform a file/stream operation on a generated or directly supplied path
0x24Run a shell-link and power-control sequence
0x38Launch the Chrome/Google workflow
0x3BDisable hardware acceleration in Chrome, Edge, and Firefox
0x3DTerminate the banking applications and browser processes listed above
0x40 / 0x41Base64-decode supplied content and write it to a generated or directly supplied path
0x49Close a stored handle
0x52 / 0x53Install or remove the input-blocking keyboard and mouse hooks
0x61 / 0x62Create a date-triggered shutdown link using a supplied date or the current date
0x65-0x70Create, delete, or toggle selected staged module files
0x71Delete the principal staging artifacts
0x72Terminate the malware process with ExitProcess(0)
0x75Clear a controller-state flag

The Chrome workflow constructs a path ending in Google\Chrome\Application\chrome.exe, appends http[:]//www.google[.]com, and can execute the result. This is a browser-launch or connectivity path, not a C2 URL.

The common execution sink converts a Delphi Unicode string to an ANSI command line and calls WinExec. The decrypted command strings show support for hidden PowerShell and minimized cmd.exe execution:

WindowsPowerShell\v1.0\powershell.exe
-windowstyle hidden -Command
cmd.exe
/c "start /MIN

The Astaroth prepares WinInittemp.log or WinInittemp.out, initializes COM, and creates a .lnk under the current user’s Startup folder. The function also removes older numbered link candidates. The most accurate description is therefore command execution through a Startup-folder shell link with cleanup, static analysis alone does not establish how long each linkpersists.

Immediate host-control commands are implemented with both PowerShell and command-shell variants:

WindowsPowerShell\v1.0\powershell.exe Restart-Computer -Force
cmd /V /C shutdown -r -t 2 -f

WindowsPowerShell\v1.0\powershell.exe stop-computer -force
cmd /V /C shutdown -s -t 2 -f

Commands 0x61 and 0x62 create a separate Startup link whose command compares the current date with a selected date and executes shutdown /s /t 0 on a match. The associated decrypted artifact name is WinInittempUpdates.log.

The HTTP configuration channel provides an additional execution path that is separate from the numeric socket dispatcher. A response field named upjs is isolated and passed to ScriptControl, the malware selects the JScript language, adds the received code, and invokes the selected function through COM dispatch. A party controlling a selected update endpoint or its response can therefore execute JScript inside on it’s own process.

Decrypted staging and cleanup artifacts

The following operational names are assembled under the malware’s staging directory and are relevant for host-based detection:

r.log
iotec.log
intec.log
datatemp.log
at.log
metrics.mca
<generated>.exe
<generated>.log
prev.log
digs.log
ax.mod
ay.mod
aw.mod
dump.log
temfic.mca
dbl.log
re.log
retrics.mca
inc.inf
db\
WinInittemp.log
WinInittemp.out
WinInittempUpdates.log

Command 0x71 calls the cleanup routine, which initializes the principal paths and passes them to the deletion helper. In this sample, dump.log is not an activity log: it is the encrypted runtime network configuration and can also be replaced by a server-supplied response.

Anti-analysis and environment detection

The process blacklist recovered from the first string layer contains:

Sysmon.exe
splunkd.exe
splunk-winevtlog
x32dbg.exe
x64dbg.exe
WinDbg.exe
Wireshark.exe
OLLYDB.exe
DbgX.Shell
SbieSvc.exe
QEMU-GA.exe
VBoxService.exe
ProcessHacker.exe
SystemInformer.exe
Fiddler.exe
Charles.exe
CrowdStrike.exe
SentinelAgent.exe
Procmon.exe
dnSpy.exe

A second blacklist initialized, contains tool names, window titles, and window-class fragments:

OllyDBG
ImmunityDebugger
WinDbg
IDA Pro
Process Explorer
Process Monitor
Regmon
Filemon
TCPView - Sysinternal
Autoruns - Sysinternals
Wireshark
Dumpcap
Process Hacker
SysAnalyzer
HookExplorer
SysInspector
ImportREC
PETools
LordPE
JoeBox
Sandbox
x32dbg
dbgviewClass
DbgX.Shell.exe
WinObj - Sysinternals
Sysinternal
Qt5152QWindowIcon
System Informer

These lists cover debuggers, packet analyzers, Sysinternals utilities, sandboxes and virtual machines, EDR/monitoring products, and reverse-engineering tools. They should be presented as anti-analysis and environment-detection configuration, not as processes that command 0x3D terminates.The latter is limited to the nine Bradesco, Java, and browser images shown earlier.


External Configuration and Command-and-Control

The apparent absence of a C&C address from Astaroth’s protected-string corpus is intentional. The live network configuration is externalized in dump.log, a 21,256-byte file staged beside the malware core. Despite its name, the file is not an execution log. It is an obfuscated bootstrap configuration used to initialize two related communication planes:

  • A raw TCP channel for victim registration and interactive numeric commands;
  • An HTTP channel for configuration rotation, update delivery, and optional JScript execution.

Below we can see the macro routine of the dump.log decoding.

After the outer Base64 layer, the first character encodes a salt. The decoder removes it and consumes the remaining text two characters at a time.

The disassembly above implements a similar process to the one we saw earlier in string decryption; however, in the context of decoding the dump.log file, they only share a similar transformation of radix-25 pairs, but use distinct algorithms, constants, and routines.

salt = ord(input[0]) - ord('A')
input = input[1:]

for each pair (c1, c2):
value = ((ord(c1) - ord('A')) * 25
+ (ord(c2) - ord('A'))
- salt
- 0x3F2)
output += wchar(value)

The multiplication by 25 is visible as two consecutive lea instructions:

lea edx, [edx+edx*4]   ; digit * 5
lea edx, [edx+edx*4] ; digit * 25

The output is a newline-separated stream of records. Each record has a plaintext key and a Base64-encoded value:

ips5=<Base64 value>
dt=<Base64 value>
ips1=<Base64 value>
ips=<Base64 value>
out=<Base64 value>
ips4=<Base64 value>
ips0=<Base64 value>
tp=<Base64 value>
ips3=<Base64 value>
ips2=<Base64 value>

This gives dump.log three distinct layers:

  1. Base64 over the complete file;
  2. the salt-prefixed radix-25 pair transform;
  3. Base64 over each individual configuration value.

Below we can see the execution of a script to decode the file

The code of this script, is on final of this post.

Recovered campaign configuration

KeyEntriesDecoded valueUse and confidence
ips50omzagdmspc.a.pinggy[.]link:21601 repeated 50 timesPrimary raw TCP list; selection and connection path confirmed in code and the endpoint observed in the matching PCAP
ips0–ips530 per key1.tcp.sa.ngrok[.]io:21131 repeated 30 times in each listAdditional or fallback-like lists; present in configuration, but their complete selection policy and use were not established
out2hxxps://bit[.]ly/4zzRb4P, hxxps://cutt[.]ly/cygeRswHHTTP configuration/update candidates; configured but not observed in the available PCAP
dt140000005Configuration scalar; exact timing, date, version, or sequence semantics remain unresolved
tp10Mode/transport scalar; exact semantics remain unresolved

The repetitions appear to provide redundant selection slots rather than dozens of independent servers. Only the primary ips path is fully connected to an observed network session. The ngrok value and both shortened URLs must be labeled configured, not contacted.


Communication Flow with C&C Servers

The communication flow begins when the installer writes dump.log, which the malware decodes through three layers, outer Base64, a salted radix-25 transformation, and Base64 encoding around each value, to recover dt, tp, and the ips and out lists. These values initialize two parallel controllers. In the HTTP plane, the malware selects a URL from out, performs a GET request through WinHTTP, and parses the response. If it contains a valid configuration, the malware replaces dump.log, immediately reloads the new endpoints, and restarts the cycle. If the upjs field is present, its contents may also be executed as JScript through COM automation.

In the raw TCP plane, the malware selects an endpoint from the primary ips list, omzagdmspc.a.pinggy [.]link:21601 in this campaign, resolves the hostname, opens a socket, and sends the victim registration profile. The public Pinggy relay forwards the connection to an operator-controlled backend, which returns command batches over the same channel. These batches are split into records, validated, converted into numeric command identifiers, and dispatched to actions such as browser capture, file or DLL execution, power control, and cleanup.

The dump.log file also contains 1.tcp.sa.ngrok[.]io:21131 in the secondary ips0 through ips5 lists, possibly as alternative or fallback infrastructure. However, this endpoint was only configured: its selection policy was not established, and no communication with it was observed in the analyzed PCAP provided by our dearst friend Bradley Duncan.

Thus, as shown in the diagram, HTTP maintains and refreshes the configuration and may deliver scripts, while TCP supports victim registration and interactive control, there is no evidence that the dump.log decoder is applied to C&C traffic.

Below, we can see a macro view of the flow.


Indicators of Compromise

The indicators below were recovered from the analyzed the current Astaroth campaign artifacts in this post and the matching packet capture (identified through malware-traffic-analysis.net). Network indicators are defanged, of course.

File Indicators

Malicious and Campaign-Specific Artifacts

ArtifactRoleSHA-256
868283789726483.zipInitial ZIP archivecc44782356cb0effc528a7ab22c19ab360a55ebbbe01feb0967031aa191c5869
868283789726483.lNkMalicious Windows shortcut extracted from the ZIP454339578b870730d146ad8fec776a9d59360417ab1c2e0e5f88414baf92a13d
log204017cd0477.lnkPersistence shortcut placed in the Startup folder32e5b7089317f4167b429606f5418b9e53a8278f2f89fa767edffe8056c9d70b
Beatz.LEDPRO.09662.8729.422.logCompiled malicious AutoIt scriptf62a958faf0491b2b2803be2ee69b664b58e4a1261f64e8530cdc1a3ff666aa4
Beatz.LEDPRO.09662.8729.422inc.infEncoded campaign companion databdf75e22ee42ed6606f6db771ca5c50d8fc68929e6bee634d50df96409eaa33d
Beatz.LEDPRO.09662.8729.422re.logAdd-0x2A encoded Delphi payloade60fe033235c71dd4cb8e7b718851c2f95b4e7ba3a93d7064c97e81bebb0b411
embeeded_log_loader_astaroth.exeExtracted x86 Delphi loader and process-hollowing componentd7bfb7daa2feed448d3c1ad9bb3799c75e39ead2bb42e297a44ec804ab77c9b4
metrics.mcaAdd-0x2A encoded Astaroth banking coree8f7ff8b9e8133a2b36854a33484235d53780be8358c0b07569c41b94ebb3b49
decrypted_metrics_stage.exeAnalyst-recovered Astaroth/Guildma core; internal name pxsaltisthimgruklia.exe74ab591bf4a271f136a65316f729dfb98b3f2270435ba688d1a030501e3d6938
dump.logObfuscated runtime C2 configuration9d749b90a29f1802329c7b677db725377c894db2e2dfb5352f654dfa57d6bc0c

decrypted_metrics_stage.exe and embeeded_log_loader_astaroth.exe are the recovered artifacts, named by me. Their hashes are useful for malware identification and retrospective hunting.

Legitimate or Dual-Use Components Abused by the Campaign

The following files are part of the infection chain, but their hashes must not be treated as malware-only indicators.

ArtifactRole in the ChainSHA-256
n1LUQ7.log:h6JSb / recovered as n1LUQ7.log-ADS-h6JSb.binApparently legitimate Microsoft scrobj.dll copy stored in an NTFS alternate data stream and abused through regsvr32.exea6044786991afdb9d42ceb350943987765a7d0e8537369b2092e3f019c0f63ca
Beatz.LEDPRO.09662.8729.422.exeRenamed legitimate AutoIt interpreter used to execute the malicious .log scriptbdd2b7236a110b04c288380ad56e8d7909411da93eed2921301206de0cb0dda1

Network Indicators

Observed Delivery and Command-and-Control Infrastructure

IndicatorTypeRole
relatorio01a.colombstracciatella[.]cfdDomainMalspam sender infrastructure
185.254.222[.]105IPv4Historical sending host for the malspam domain
sistema-ekg3h4htc0h0ggdh.canadacentral-01.azurewebsites[.]netDomainInitial delivery link and redirector
hxxps://static.50.121.238.62.clients.your-server[.]de/868283789726483.zipURLZIP download location
plosancol.aguamammillaria[.]cfdDomainComponent retrieval through the LNK/regsvr32.exe chain
hxxps://plosancol.aguamammillaria[.]cfd/?1/_xURLComponent-retrieval URL reconstructed from the obfuscated LNK command
crironxil.aguasedum[.]cfdDomainPost-delivery component infrastructure
omzagdmspc.a.pinggy[.]link:21601Domain and portPrimary raw TCP C2 relay

Configured but Not Observed in the Available PCAP [malware-traffic-analysis.net]

IndicatorTypeRole
1.tcp.sa.ngrok[.]io:21131Domain and portSecondary/fallback-like TCP endpoint
hxxps://bit[.]ly/4zzRb4PURLHTTP configuration/update candidate
hxxps://cutt[.]ly/cygeRswHURLHTTP configuration/update candidate

Historical DNS Resolutions Observed in the PCAP [malware-traffic-analysis.net]

DomainResolved IPv4 AddressOperational Note
sistema-ekg3h4htc0h0ggdh.canadacentral-01.azurewebsites[.]net52.228.84[.]36Shared Microsoft Azure infrastructure
static.50.121.238.62.clients.your-server[.]de62.238.121[.]50ZIP delivery host
plosancol.aguamammillaria[.]cfd104.21.68[.]199, 172.67.198[.]43Shared Cloudflare infrastructure
crironxil.aguasedum[.]cfd104.21.58[.]188, 172.67.206[.]66Shared Cloudflare infrastructure
omzagdmspc.a.pinggy[.]link172.235.51[.]109Shared Pinggy relay infrastructure

These resolutions are historical and provider-shared. Prefer the complete domain, port, process ancestry, and surrounding behavior over standalone IP blocking.

Host and Persistence Indicators

IndicatorDescription
C:\Users\%USERNAME%\AppData\Local\Temp\n1LUQ7.log:h6JSbNTFS alternate data stream containing the abused scrobj.dll copy
C:\Users\Public\Libraries\.cache\Campaign staging directory
C:\Users\Public\Libraries\.cache\PLAX\Main malware and configuration directory
C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\wininittemp.log204017cd0477.lnkStartup persistence shortcut
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegSvcs.exeLegitimate process created suspended and hollowed with the recovered Astaroth core
metrics.mcaEncoded Astaroth core
dump.logExternal C2 configuration

Conclusion

This post examined a recent Astaroth campaign, tracing its infection chain from the initial phishing email and malicious Windows shortcut to the AutoIt and Delphi loaders responsible for executing the final banking malware.

The reverse engineering of Astaroth’s core revealed a custom string protection mechanism combining deterministic key reconstruction, chained byte transformations, and an optional nested decoding layer. By reconstructing these algorithms and integrating them into Binary Ninja, I was able to automate the recovery of hundreds of protected strings, providing additional visibility into the malware’s internal functionality.

Further analysis revealed a context-aware financial targeting mechanism, targeted keyboard and clipboard capture, browser configuration manipulation, process termination capabilities, anti-analysis checks, and an extensive numeric command dispatcher.

Another important finding was the role of the external dump.log configuration file. Its multilayer encoding conceals the endpoints used by two distinct communication mechanisms: a raw TCP channel supporting interactive control and an HTTP-based configuration and update mechanism with potential JScript execution capabilities.

The available network evidence supports communication with the configured Pinggy endpoint, while the secondary ngrok endpoint and HTTP update URLs were identified in the configuration but were not observed being contacted in the analyzed capture. This distinction is essential when interpreting infrastructure indicators recovered through static analysis.

From a defensive perspective, these findings highlight opportunities to investigate multistage execution chains, suspicious browser configuration changes, context-dependent credential capture, unusual process termination activity, and network connections associated with malware staging and remote control.

Ultimately, this analysis illustrates how reversing custom obfuscation mechanisms can expose not only hidden strings and configuration data, but also the operational logic of a sophisticated banking malware family targeting the Brazilian financial ecosystem.

I hope this post has provided useful information to the malware research community, particularly regarding the Brazilian landscape, as well as to students of malware analysis. Below, you will find links to the YARA rules and Python scripts I used to automate certain tasks during the analysis.

Additional Information

Leave a Reply

Your email address will not be published. Required fields are marked *