Skip to content

Breaking Aura: five obfuscation layers & hates sandboxes

Kirk
16 min read
malwarestealerreverse-engineeringobfuscationencryption
On this page

Aura is a native C++ info-stealer sold as a service since July 2025. It appeared as a post-Lumma replacement, advertised to the same buyer base after the Lumma takedown. 104 unique samples have passed through Triage (opens in new tab) since November 2025, all scoring 10/10 and classified as aura_stealer. Every submission ends in a crash. VirusTotal detection sits at 53/75. The anti-sandbox code runs in global constructors before WinMain, and most public sandboxes capture only the crash.

The binary ships with five layers of code obfuscation: a patched ImageBase that breaks static IAT analysis, a Heaven's Gate shellcode block that transitions to 64-bit mode for Chrome credential theft, a generic 32-to-64-bit trampoline, control flow flattening over an FNV-1a API hash table, and per-build AES-256-CBC config encryption. On top of that, a separate SSE XOR layer encrypts every string argument passed to the resolved APIs. The stealing targets themselves are not in the binary at all. They are pushed from the C2 server at runtime.

We broke all five code layers through static analysis, then emulated the binary past the sandbox wall and onto a live C2 server. The transport encryption turned out to be AES-256-CBC with the key and IV prepended in plaintext to every message. TLS is the only wire protection. We replayed the client handshake against the one surviving C2 domain (glider[.]cfd), got a 200 response, and decrypted 42 KB of server-pushed configuration: 212 stealing tasks across 170 targets, including 99 Chromium browsers, 13 Gecko browsers, 40+ crypto wallets, VPN clients, password managers, and messaging apps.


Sample overview

FieldValue
SHA25690a1fb5ef34cc6abee75e7b39166b3cbb97d5545496251ea69c4d4372aa4c3fe
TypePE32 (GUI) Intel 80386, MSVC 14.0
Size725,472 bytes
Compiled2025-10-25
Version1.5.2
Build IDa05e095d-3b2d-4912-9174-a1ce01e86dda
imphash1cb7010fa29c1205e95faaaf21e5a21c
VT53/75 (opens in new tab) (AVG/Avast: Win32:AURAStealer-D, BitDefender: Gen:Variant.Fragtor.907392)
Triage10/10 (opens in new tab) aura_stealer, crashes in sandbox (WerFault.exe)
First seen2025-11-20 (VirusTotal)
C2 domainsmagicupdate[.]cfd, searchagent[.]cfd, mscloud[.]cfd

The PE header has ASLR, DEP, and CFG disabled. The Rich header is stripped. No resources, no TLS callbacks, no overlay. The builder strips metadata from the output binary and patches the ImageBase post-compilation from the original 0x750000 to a random value. All code references use the compile-time base; the .reloc section fixes them up at load.

Five samples were analysed across two versions (v1.5.1 and v1.5.2), including one UPX-packed build.

Code obfuscation: five layers

Layer 1: static IAT

The import table has 105 functions across three DLLs (KERNEL32, ADVAPI32, gdiplus). All are called via FF 15 (call [mem32]) using 0x750000-based addresses. The builder's ImageBase patching means these calls only resolve after .reloc fixups apply. The original base can be recovered by scanning FF 15 call targets against candidate base addresses until the IAT entries align.

Layer 2: Heaven's Gate x64 shellcode

A 3.5 KB block of x64 code sits in the .data section. It executes through a push 0x33; retf transition that switches the CPU from 32-bit to 64-bit mode (CS selector 0x33). This is the Heaven's Gate technique.

The shellcode walks the PEB in 64-bit mode to find kernel32.dll (the third entry in InMemoryOrderModuleList, not ntdll). It resolves GetProcAddress and LoadLibraryA by walking the PE export table and computing DJB2 hashes (seed 0x1505) with a per-build XOR key.

A 32-byte XOR key, stored in register assignments to an [r15] buffer, decrypts 16 API name strings via SSE xorps. The key registers vary by version: rbp/rdi in v1.5.2, r14/rsi in v1.5.1. The decrypted APIs are file I/O (8), COM/WMI (6), and OLE automation (2). Their purpose: read Chrome's App-Bound encryption key (written to a file with an "APPB" magic header) and fingerprint the machine via WMI queries.

The WMI queries are dormant in all v1.5.x builds. The control value is the string "BROWSERTYPE", which causes the WMI code path to be skipped.

Layer 3: Heaven's Gate trampoline

A 137-byte trampoline in .rdata acts as a generic 32-to-64-bit function caller. It copies itself to VirtualAlloc'd executable memory during init. The calling sequence:

push 0x33            ; x64 code segment
call $+5
add  [esp], 5
retf                 ; far return -> switches to 64-bit mode

In 64-bit mode, it loads arguments from the 32-bit stack into the x64 calling convention (rcx/rdx/r8/r9 + stack), calls the target function, stores the result, and returns to 32-bit mode.

Layer 4: control flow flattening + FNV-1a hash table

Two CFF variants protect most API calls:

Pattern A (multi-level chain): 3-4 pointer dereferences through 17 pre-initialised .data base pointers, summed to produce a computed jump target.

Pattern B (constant + pointer): a compile-time constant added to a .data value produces the target directly.

Both patterns resolve to the same FNV-1a hash table wrapper at 0x7F4D68. The hash table uses seed 0x811C9DC5 and prime 0x01000193. It is populated during init via GetModuleHandleA("ntdll.dll") and LdrGetProcedureAddress, with API addresses stored XOR-encrypted ([entry+0xC] ^ [entry+0x10]).

Nine lookup keys are identified. Each is a builder-assigned compile-time constant, XOR-obfuscated per call site. A 99-call function pointer at 0x903B8 points to a ret 0 stub, a no-op placeholder disabled in v1.5.x.

Layer 5: config encryption (AES-256-CBC)

The build config is encrypted in the .data section after the Heaven's Gate shellcode. Layout:

[32-byte AES key][16-byte IV][0-8 byte gap][ciphertext]

Each build has a unique key and IV generated by the builder panel. The gap between key/IV and ciphertext varies per build (0, 7, or 8 bytes observed). Decrypted, the config is JSON:

{
  "conf": {
    "hosts": ["https://magicupdate.cfd", "https://searchagent.cfd", "https://mscloud.cfd"],
    "anti_vm": false,
    "anti_dbg": true,
    "self_del": true,
    "run_delay": 0,
    "useragents": [""],
    "human_check": false
  },
  "build": {
    "ver": "1.5.2",
    "build_id": "a05e095d-3b2d-4912-9174-a1ce01e86dda"
  }
}

The encrypted config can be located in any build by scanning for the PEB walk signature (the Heaven's Gate anchor) and reading the key, IV, and ciphertext relative to that anchor. No hardcoded offsets are needed.

Data obfuscation: XOR string encryption

A separate obfuscation layer protects the string arguments passed to the resolved APIs: credential paths, browser profile names, registry keys, process blacklists. The strings are encrypted inline via SSE xorps using per-block XOR keys derived from .data base pointers.

252 XOR sites across four function blocks produce 235+ unique decoded strings. The decoded content includes:

CategoryCountExamples
Chrome file targets8Local State, Login Data, Network\Cookies, History, Bookmarks
Firefox file targets16key4.db, logins.json, cookies.sqlite, places.sqlite, cert9.db
Chrome ABE strings7os_crypt, encrypted_key, app_bound_encrypted_key
Process blacklist37ollydbg.exe, ida64.exe, x64dbg.exe, Wireshark.exe, windbg.exe, Fiddler.exe
DLL/driver blacklist23apimonitor-x86.dll, apimonitor-psn-x86.sys, sbiedll.dll, cuckoomon.dll
Sandbox usernames2JohnDoe, HAL9TH
CIS locale exclusion3AM, BY, GE
C2 protocol strings~30/api/conf, /api/send, multipart/form-data, pow=
Self-delete commands7cmd.exe, taskkill, del /f /, fsutil f, timeout
DLL inventory14kernel32.dll, ntdll.dll, winhttp.dll, crypt32.dll, ws2_32.dll
System fingerprint155AURA self-ID, HWID, [System Info], [Hardware], IsWow64Process

The system fingerprint block reveals the full exfil report format. The binary builds a structured text document with the self-identification marker AURA, followed by labelled sections:

AURA
HWID: {MachineGuid}
Launched at: {%Y-%m-%d %H:%M:%S UTC}
Location: {binary path}
Run as Admin: {yes/no}
User in Admins group: {yes/no}
[System Info]
Architecture: {x64/x32}
Language: {locale}
Keyboard Layouts: {list}
Time Zone: {tz}
Computer Name: {NetBIOS}
User Name: {user}
Screen resolution: {WxH}
OS Name: {ProductName}
Edition: {EditionID}
Version: {CurrentBuild}
Build Number: {BuildLab}
[Hardware]
CPU: {ProcessorNameString}
RAM: {total} MB
GPUs: {display devices}
[Processes List]
{running processes}
[Installed Software]
{installed programs}

OS version data comes from the registry at SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion (ProductName, EditionID, CurrentBuild, BuildLab, CSDVersion, InstallDate) and HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0 (ProcessorNameString). The binary also calls RtlGetVersion from ntdll and IsWow64Process for architecture detection.

Hardcoded Chrome targets

These file names are in the binary, not server-pushed. They target specific Chrome data files within each profile directory:

FilePurpose
/MasterKey.binApp-Bound master encryption key (via Heaven's Gate APPBKEYREAD)
/Local StateContains encrypted_key for cookie/password decryption
Login DataSQLite DB with saved passwords
Web DataSQLite DB with autofill and saved credit cards
Network\\CookiesSQLite DB with cookies (Chromium 96+ path)
HistorySQLite DB with browsing history
BookmarksJSON with saved bookmarks
Last VersionChrome version tracking

The Chrome App-Bound Key theft uses the Heaven's Gate shellcode to read Chrome's App-Bound encryption key in 64-bit mode and write it to a file with an APPB magic header. The key fields os_crypt, encrypted_key, and app_bound_encrypted_key are parsed from Local State to locate the encrypted credential material.

Runtime-resolved API surface

The binary resolves 100+ APIs at runtime through the FNV-1a hash table and CFF dispatch. The full surface, from .rdata strings interleaved with nlohmann JSON error messages:

CategoryAPIs
Anti-analysisNtQueryInformationProcess, NtCreateDebugObject, NtQueryObject, NtGetContextThread, NtSetContextThread, GetTickCount
NetworkWinHttpOpen/Connect/OpenRequest/SendRequest/ReceiveResponse/ReadData/WriteData + 10 more WinHTTP, WSAStartup, getaddrinfo, connect, htons
Credential theftCryptUnprotectData, CryptBinaryToStringA, CredReadA, RegOpenKeyExW, RegEnumKeyExW, RegQueryValueExW
ScreenshotBitBlt, CreateCompatibleBitmap, GdipCreateBitmapFromHBITMAP, GdipSaveImageToStream, CreateStreamOnHGlobal
ClipboardOpenClipboard, GetClipboardData, CloseClipboard
System enumGetComputerNameW, GetUserNameW, GetSystemInfo, EnumDisplayDevicesW, Process32FirstW/NextW, CreateToolhelp32Snapshot
Process controlCreateProcessW, OpenProcess, TerminateProcess, NtResumeProcess, NtSuspendProcess, ShellExecuteExW
File systemNtCreateFile, NtOpenFile, NtReadFile, NtQueryDirectoryFile, ExpandEnvironmentStringsW

The stealing targets (credential paths, wallet extension IDs, browser profile directories) are not in the binary. They are pushed from the C2 server at runtime. We confirmed this by searching all six encrypted blocks against 916 known target strings, including all 274 Avast-captured extension IDs. None matched. The targets come from the server.

Dynamic analysis: breaking the sandbox wall

Every Aura sample crashes in the Triage sandbox. The anti-sandbox code runs in global constructors (_initterm_e), not in WinMain. The _initterm_e table at 0x7E0408 contains eight function pointers. One or more of them contain:

  • MapFileAndCheckSumW binary integrity verification
  • Software breakpoint detection on return addresses
  • Anti-debug checks (configurable via anti_dbg config flag)

These fire before WinMain executes. Patching the config is not enough. The constructors must be survived.

We emulated both samples using a custom PE emulator. Both ran to a clean ExitProcess(0), producing ~16.5 million instructions and ~2,800 API calls each. The emulator walked through all eight global constructors without issue.

The runtime behaviour sequence:

  1. MSVC CRT init (_initterm_e, eight global constructors)
  2. MapFileAndCheckSumW binary integrity check
  3. Sleep(968) post-checksum delay
  4. GetUserNameW (sandbox username check against JohnDoe/HAL9TH)
  5. AES-256-CBC config decryption
  6. NtCreateDebugObject + NtQueryObject anti-debug check
  7. Process blacklist scan via CreateToolhelp32Snapshot + Process32FirstW/Process32NextW
  8. RegOpenKeyExW("SOFTWARE\\Microsoft\\Cryptography") + RegQueryValueExW("MachineGuid") for HWID
  9. CreateMutexA("Global\\{build_token}") single-instance guard
  10. DNS connectivity check: ws2_32.socket + connect to port 53
  11. Heartbeat loop: six WinHTTP GET requests to /api/live (three domains, two attempts each)
  12. Build /api/conf request payload (multipart with encrypted build ID)
  13. CorExitProcess(0)

The mutex token is per-build but is not the build UUID. Examples: LI5joIjAwOpBWBvWHUk2YOU5fz20 (build a05e095d), 1yilNwHd5QDEvAUm0GCI6Oc (build a068cff0).

C2 protocol

Infrastructure status (as of 2026-03-28)

DomainStatus
glider[.]cfdLive. Backend active, Cloudflare-proxied.
mushub[.]cfdCloudflare phishing interstitial.
searchservice[.]cfdCloudflare phishing interstitial.
sakuratea[.]cfdCloudflare malware interstitial.
magicupdate[.]cfdDNS dead.
searchagent[.]cfdDNS dead.
mscloud[.]cfdDNS dead.
All .shop domainsDNS dead.

glider[.]cfd is the only domain with a functioning backend.

Heartbeat: /api/live

GET /api/live HTTP/2
Host: {c2_domain}
Connection: Close
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36

The server responds with the string true (4 bytes). The binary iterates the hosts array from the config, trying each domain in order. Timeout is 0x55730 ms (~350 seconds) for resolve, connect, send, and receive.

Config fetch: /api/conf

POST-only (Allow: POST on GET). The error page on invalid requests uses the Tabler CSS framework and renders a Russian-language "Домой" (Home) button.

The binary sends a multipart POST with a single field named data containing a base64-encoded envelope. We probed the live server and got a 200 response with the encrypted config. Garbage data returns 500. Missing or malformed requests return 302.

Transport encryption

The transport envelope is identical for client-to-server and server-to-client:

[32-byte AES-256 key][16-byte IV][8 random bytes][AES-256-CBC ciphertext, PKCS7 padded]

Both sides generate a fresh AES-256 key and IV per message, prepend them in plaintext, and encrypt the payload. TLS is the only wire protection. The 8 random bytes between the IV and ciphertext come from SystemFunction036 (RtlGenRandom) via MT19937.

We confirmed this structure by comparing the base64 blobs from two builds. Both encode to 120 bytes. The first 72 bytes are identical between builds (same key and IV material, same JSON prefix). The builds diverge at byte 72 where the UUID differs. Decrypting blob[56:120] with key blob[0:32] and IV blob[32:48] in AES-256-CBC yields:

{"build":{"build_id":"a05e095d-3b2d-4912-9174-a1ce01e86dda"}}

Valid PKCS7 padding (pad=3). The server response follows the same envelope. The server's AES key and IV are in the first 48 bytes of the response.

Decrypted server config

We decrypted the /api/conf response from glider[.]cfd using the server's key and IV. The result is 42,658 bytes of JSON (config version 1.1.0) defining 212 stealing tasks across 172 unique targets.

Task breakdown

TypeCountDescription
fg-std98File grabbers. Steal files matching glob patterns from target directories.
chromium99Chromium browser data extraction. Credentials, cookies, history, bookmarks.
gecko13Gecko/Firefox browser data extraction.
system-info1Machine fingerprint collection.
screenshot1Desktop screenshot capture.

File grabber targets (98 tasks)

The file grabber tasks target application data directories under %appdata%, %localappdata%, and %programfiles%. Each task specifies a name, path, file mask pattern, maximum depth, maximum file size, and archive entry path.

Crypto wallets (30+): Anoncoin, Armory, Atomic, BBQCoin, Binance, Bitcoin, Blockstream Green, Bytecoin, Coinomi, Daedalus, DashCore, Devcoin, Digitalcoin, Dogecoin, ElectronCash, Electrum, Electrum-G, Electrum-LTC, Ethereum, Exodus, Florincoin, Franko, Freicoin, GoldCoinGLD, Guarda, IOCoin, Infinitecoin, Ixcoin, Jaxx, Ledger, Litecoin, Megacoin, Mincoin, MultiDoge, Namecoin, Primecoin, Raven, Terracoin, Wasabi Wallet, YACoin, Zcash.

Applications: FileZilla (FTP credentials), AnyDesk (remote access configs), KeePass (password database files), Discord (LevelDB token storage), Telegram (tdata session files), Steam (config + ssfn files), Uplay, OpenVPN/NordVPN/ProtonVPN (VPN profiles), Authy Desktop (2FA tokens), Pidgin/Psi+/qTox (messaging).

Generic: Two tasks scan %appdata% and %localappdata% with broad masks for "important files."

Browser targets

Chromium (99 browsers): Google Chrome (8 variants including Beta, Canary, Dev, SxS, x86), Microsoft Edge, Brave, Opera (Stable, GX, Crypto Developer, Neon), Vivaldi, Yandex (6 variants), 360 (5 variants), CentBrowser, Comodo/Comodo Dragon, CryptoTab, Epic Privacy, Iridium, Maxthon, Naver Whale, SRWare Iron, Slimjet, Torch, UCBrowser, and 70 others.

Gecko (13 browsers): Firefox, Thunderbird, Waterfox (Classic + current), Pale Moon, SeaMonkey, Basilisk, Cyberfox, IceDragon, K-Meleon, SlimBrowser, BitTube, BlackHawk.

Anti-analysis

Process blacklist (37 entries)

ollydbg.exe      ollyice.exe       tcpview.exe      autoruns.exe
autorunsc.exe    filemon.exe       procmon.exe      regmon.exe
procexp.exe      idaq.exe          idaq64.exe       ida64.exe
radare2.exe      ImmunityDebugger  Wireshark.exe    dumpcap.exe
HookExplorer     ImportREC.exe     PETools.exe      LordPE.exe
SysInspector     proc_analyzer     sysAnalyzer.exe  sniff_hit.exe
windbg.exe       joeboxcontrol    joeboxserver      ResourceHacker
x32dbg.exe       x64dbg.exe       Fiddler.exe      httpdebugger
cheatengine-i386                   cheatengine-x86_64
cheatengine-x86_64-SSE4-AVX2      frida-helper-32  frida-helper-64

DLL/driver blacklist (23 entries)

npf.sys              winpcap.dll         npcap.dll           wpcap.dll
packet.dll           windivert.dll       detours.dll         apimonitor-x86.dll
apimonitor-drv-x86   apimonitor-psn-x86  vehdebug-x86_64     sbiedll.dll
dbghelp.dll          dbgeng.dll          api_log.dll         dir_watch.dll
pstorec.dll          cuckoomon.dll       wpespy.dll          printfhelp.dll
cheatengine-i386     frida-helper-32     frida-helper-64

Sandbox evasion

Username comparison against JohnDoe and HAL9TH. Locale check excludes CIS country codes AM, BY, GE. Binary integrity verification via MapFileAndCheckSumW. All checks run in global constructors before WinMain.

Human verification gate

When human_check is true in the config, the binary creates a window titled with the first 8 characters of the multipart boundary and displays "Enter {prefix} to continue" with an input field and Ok/Exit buttons. The prefix is derived from the randomly generated boundary string. The binary blocks on GetMessageW until the user enters the correct value. A second build (a068cff0) had human_check: true and anti_vm: true where the primary sample had both set to false.

Self-delete

When self_del is true in the config, the binary wipes and deletes itself after exfiltration. The reconstructed command from decoded string fragments:

cmd.exe /c taskkill /f /im <process> & fsutil file setZeroData offset=0 length=<size> <path> & del /f /q <path> & timeout /t 5

fsutil file setZeroData overwrites the file contents with zeros before deletion, defeating forensic file recovery.

IOC summary

Network

IOCTypeNotes
glider[.]cfdC2 domainLive as of 2026-03-28
mushub[.]cfdC2 domainCloudflare-flagged
searchservice[.]cfdC2 domainCloudflare-flagged
sakuratea[.]cfdC2 domainCloudflare-flagged
magicupdate[.]cfdC2 domainDNS dead
searchagent[.]cfdC2 domainDNS dead
mscloud[.]cfdC2 domainDNS dead
opencamping[.]shopC2 domainDNS dead
gamedb[.]shopC2 domainDNS dead
unknowntool[.]shopC2 domainDNS dead
browsertools[.]shopC2 domainDNS dead
armydevice[.]shopC2 domainDNS dead
glossmagazine[.]shopC2 domainDNS dead

Host

IOCType
Global\\{random_token}Mutex (per-build)
SOFTWARE\\Microsoft\\Cryptography\\MachineGuidRegistry read (HWID)

Behavioural

BehaviourDetail
User-AgentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36
HeartbeatGET /api/live
Config fetchPOST /api/conf (multipart, data field)
Data exfilPOST /api/send
Self-deletefsutil file setZeroData + del
Integrity checkMapFileAndCheckSumW in global constructor

Crypto constants

ConstantValuePurpose
FNV-1a seed0x811C9DC5API hash table
FNV-1a prime0x01000193API hash table
DJB2 seed0x1505Heaven's Gate export resolution
MT19937 init0x6C078965Transport key generation
AES S-box VA0x7D9744Custom AES-256 implementation

The transport encryption sends the AES key and IV in plaintext with every message. The only protection is TLS. Any entity with visibility into the TLS session (the Cloudflare proxy, for example) can decrypt both the build registration and the server-pushed config.

Share this article