This post serves as a technical update to the previous analysis of the Acreed threat actor. Following the investigation into “EtherHiding” techniques and cross-platform infection chains, the focus has shifted to improving automated analysis capabilities.
For the full background on the campaign, refer to the previous report: Acreed: On‑Chain C2 Evolution.
This update covers fixes implemented for open-source sandbox parsers and the release of a unified tool designed to streamline the analysis of this family.
Terminology: ACR Stealer vs. Amatera
The terms ACR Stealer and Amatera are used interchangeably in this documentation. While Amatera appears to be the modern evolution of the malware, most security tools and sandboxes (such as CAPE) classify them under the same family. Despite naming differences, the core behavior and configuration structures remain consistent.
CAPE Sandbox Updates
Recent Amatera samples have introduced rotation in how decryption keys (AES and XOR) are stored to evade standard static extraction. These changes caused failures in existing community parsers.
To address this, the obfuscation patterns were reverse-engineered and a fix was submitted to the CAPE Sandbox project:
- PR #71: Support more Amatera variants (View on GitHub)
This update allows CAPE to automatically extract configuration data from these newer variants.
Unified Static-Dynamic Extractor
A standalone script has been developed to combine static parsing logic with dynamic C2 interaction. This tool creates a unified pipeline that:
- Statically Extracts Keys: Parses the unpacked executable to locate AES and XOR keys, accounting for multiple obfuscation techniques.
- Dynamically Communicates: Uses the extracted keys to emulate a victim machine and perform the encrypted handshake with the C2.
- Downloads Payloads: Decrypts the JSON configuration and retrieves secondary payloads (such as Amadey or Discord stealers) defined in the loader (
ld) section.
The script is available here: acreed_c2_download.py.
Handling Key Storage Variants
The script includes logic to handle recent samples where key storage prevents standard extraction. Amatera primarily utilizes two methods for this:
- Global Data: Keys are stored in the
.datasection and referenced via the stack. - Stack Construction: Keys are constructed byte-by-byte via
movinstructions directly on the stack to evade string-based detection.
The tool utilizes pefile and yara to dynamically detect the method used. The specific logic for differentiating between these storage methods is demonstrated in Listing 1.
def extract_config(data):
# ... setup pefile ...
# Scan for the XOR key pattern
offset = yara_scan(data, RULE_SOURCE)
# Variant A: Global Data Reference
# Pattern: mov eax, dword ptr ds:szXorKey
if data[offset] == 0xA1:
key_str_va = struct.unpack("i", data[offset + 1 : offset + 5])[0]
# ... extract string from data section ...
# Variant B: Stack Construction
# Pattern: sub esp, 1Ch ... mov [ebp+var], reg
elif data[offset] == 0x83:
key_bytes = bytearray()
# ... parse the 'mov' instructions to reconstruct the key byte-by-byte ...