022fe01a4fb8855747a4068de2131ceb7486cf846df6c18adbefe7564482adb59d2ca3: 022fe01a — MinGW-w64 HTTP downloader with in-memory reflective PE loader
A lightweight MinGW-w64 x64 downloader/loader dropped by the Amadey botnet. Instead of carrying an encrypted payload in .data, it hardcodes an XOR-obfuscated C2 URL, downloads the secondary stage over unencrypted HTTP, and maps it reflectively into fresh RWX memory without touching disk.
What It Is
- SHA-256:
022fe01a4fb8855747a4068de2131ceb7486cf846df6c18adbefe7564482adb5 - File: PE32+ executable (GUI) x86-64, 131 kB, 19 sections ^[file.txt]
- Timestamp: Thu May 28 12:10:32 2026 UTC ^[exiftool.json]
- Toolchain: MinGW-w64 GCC 15.2.0 (MSYS2 Rev8), GNU C99,
-m64 -O2 -std=gnu99 -fno-builtin^[strings.txt:33], ^[strings.txt:553] - Linker: LinkVersion 2.45, ASLR + DEP + High Entropy VA, no Control Flow Guard ^[pefile.txt:73]
- Signing: Unsigned ^[rabin2-info.txt:27]
- Family:
9d2ca3(OpenCTI label, co-taggeddropped-by-amadey) ^[metadata.json] - Dynamic: CAPE skipped — no Windows guest available. All behavior derived from static RE.
This sample is the sixth confirmed morph under the 9d2ca3 umbrella. Unlike prior MinGW siblings that embedded encrypted payloads locally, this binary is a pure network-downloader stub.
How It Works
- WOW64 check. Resolves
IsWow64Processdynamically viaGetModuleHandleA+GetProcAddressonkernel32.dll, compares the result against the target PE's machine type (AMD64), and aborts if the environments mismatch ^[r2:fcn.14000145c]. - URL decode. If no command-line argument is supplied,
main()XOR-decodes a 36-byte hardcoded C2 URL from fivemovabsqword constants on the stack using key0xAA^[r2:sym.main]. The decoded URL ishttp://89.125.188.171/nah11/file.exe. - Download.
DownloadPE()initializes WinHTTP with User-Agent"Lak2oes", cracks the URL, opens a GET request, and streams the response into a heap-allocated buffer ^[r2:sym.DownloadPE_char_const__unsigned_long_]. - Reflective load.
LoadPERaw()validates MZ/PE/AMD64 magic, allocates RWX memory, copies headers and sections, resolves imports viaLoadLibraryA+GetProcAddress, processes relocations, and jumps to the mapped entry point ^[r2:fcn.1400014c5]. A"Starting PE...\n"string is logged just before transfer. - Cleanup. The downloaded buffer is freed after the handoff.
Decompiled Behavior
Entry (main) — 0x140001f6f
Zeroes a 224-byte stack buffer, branches on argc. If argc > 1, copies argv[1] into the URL slot with strncpy(127). Otherwise, copies five movabs qword constants to [rbp-0xc0] and XOR-loops (i=0; i<=35; i++) with 0xAA, writing the plaintext URL to [rbp-0x90]. Passes the decrypted URL to DownloadPE(&url, &size), checks the returned pointer, then calls LoadPERaw(ptr, size) and free(ptr) ^[r2:sym.main].
Downloader (DownloadPE) — 0x1400019b5
Allocates a large stack frame, calls WinHttpOpen("Lak2oes", 0, 0, 0, 0), converts the URL to widechar with MultiByteToWideChar(CP_UTF8), cracks it with WinHttpCrackUrl, connects via WinHttpConnect, opens a GET request with WinHttpOpenRequest(NULL, "G", NULL, ...), sends it with WinHttpSendRequest, receives with WinHttpReceiveResponse, queries content length via WinHttpQueryHeaders, reads the payload into a malloc'd buffer via WinHttpReadData, and returns the buffer + size to the caller ^[r2:sym.DownloadPE_char_const__unsigned_long_]. Every failure path closes all WinHTTP handles and returns NULL.
Loader (LoadPERaw) — 0x1400014c5
A hand-written PE mapper. Validates e_magic==MZ, Signature==PE, Machine==AMD64, then checks IsWow64() against the target architecture — mismatch causes an early abort. Allocates a destination buffer with VirtualAlloc(..., 0x3000, PAGE_EXECUTE_READWRITE), copies the full raw image, walks section headers copying each section to its VirtualAddress, walks the import directory resolving each DLL with LoadLibraryA and each import by ordinal or name with GetProcAddress, walks the base-relocation directory patching offsets with the image-base delta, and finally calls the mapped entry point via a cast function pointer ^[r2:fcn.1400014c5].
WOW64 resolver — 0x14000145c
Standard runtime resolution: GetModuleHandleA("kernel32.dll") → GetProcAddress("IsWow64Process"). Result cached in a stack local ^[r2:fcn.14000145c].
C2 Infrastructure
| Indicator | Value | Provenance |
|---|---|---|
| URL | http://89.125.188.171/nah11/file.exe |
^[r2:sym.main] (XOR-decoded from stack constants) |
| Method | HTTP GET | ^[r2:sym.DownloadPE_char_const__unsigned_long_] |
| User-Agent | Lak2oes |
^[r2:sym.DownloadPE_char_const__unsigned_long_] |
| IP | 89.125.188.171 (Moldova / AS43289) |
derived from decoded URL |
| Path | /nah11/file.exe |
derived from decoded URL |
No other network IOCs, domains, or hardcoded IPs were recovered.
Interesting Tidbits
- Compiler freshness. GCC 15.2.0 is very recent (May 2026 build). The MSYS2 Rev8 toolchain string appears 40 times in
.rdata, a hallmark of MinGW-w64 debug-info retention ^[strings.txt:33]. - XOR key in plain sight. The decompiled
mainusesxor eax, 0xffffffaa— the high bytes are a disassembly artifact; the effective byte key is0xAA^[r2:sym.main]. - Reflective loader quality. The PE mapper is competent: it handles both import-by-name and import-by-ordinal, processes the full relocation bitmap, and enforces architecture parity before mapping. This is not a lazy dropper; it's a deliberate loader ^[r2:fcn.1400014c5].
- No opsec on UA. The hardcoded User-Agent
"Lak2oes"is unique and trackable across samples. No attempt to masquerade as a browser. - Empty
Logstub.Log(char const*)is compiled to a no-op (push rbp / mov rbp,rsp / pop rbp / ret) — a placeholder for debugging that survived release ^[r2:sym.Log_char_const_]. - No persistence, no registry. Unlike the .NET 4.6.2 stager morph (
8f288492), this sample has no persistence mechanism. It is a fire-and-forget downloader.
How To Mess With It (Homelab Replication)
Toolchain: MinGW-w64 GCC 15.2.0 via MSYS2 UCRT64 environment.
Goal: Produce a 64-bit PE that downloads a payload over WinHTTP and maps it reflectively.
- Write a minimal C program using
winhttp.handwindows.h. - Hardcode a URL string XOR-encrypted with key
0xAAasmovabsqword constants, or simply store it in.rdataand XOR at runtime. - Call
WinHttpOpen,WinHttpCrackUrl,WinHttpConnect,WinHttpOpenRequestwith"GET",WinHttpSendRequest,WinHttpReceiveResponse,WinHttpReadData. - Allocate a new buffer with
VirtualAlloc(..., MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE). - Implement a minimal PE mapper: validate MZ/PE/AMD64, copy headers and sections, resolve imports via
LoadLibraryA+GetProcAddress, apply relocations, and call((void(*)())entry)(). - Compile:
gcc -m64 -O2 -std=gnu99 -fno-builtin -o downloader.exe main.c -lwinhttp. - Verification: Run the reproducer against a local HTTP server hosting a tiny x64 PE. The target PE should execute without ever touching disk. Compare against this sample's capa fingerprint once capa signatures are available.
Deployable Signatures
YARA
rule nine_d2_ca3_mingw_reflective_downloader
{
meta:
description = "MinGW-w64 reflective PE loader / HTTP downloader used by 9d2ca3 cluster"
author = "PacketPursuit"
date = "2026-08-13"
reference = "022fe01a4fb8855747a4068de2131ceb7486cf846df6c18adbefe7564482adb5"
strings:
$pe_msg = "Starting PE...\n" ascii
$ua = "Lak2oes" ascii wide
$mingw_fail = "Mingw-w64 runtime failure:" ascii
$gcc = "GCC: (Rev8, Built by MSYS2 project) 15.2.0" ascii
$xor_decode = { c7 45 fc 00 00 00 00 eb ?? 8b 45 fc 48 98 0f b6 84 05 ?? ?? ff ff 83 f0 aa }
$winhttp_get = { 48 8d 15 ?? ?? ?? ?? 41 b8 0d 00 00 00 4c 89 c1 e8 ?? ?? ?? ?? }
condition:
uint16(0) == 0x5A4D and
pe.is_pe and
pe.machine == pe.MACHINE_AMD64 and
2 of ($pe_msg, $ua, $mingw_fail) and
1 of ($xor_decode, $winhttp_get)
}
Behavioral Hunt Query (KQL)
let suspicious_ua = dynamic(["Lak2oes"]);
NetworkConnection
| where InitiatingProcessLoadedDll contains "winhttp.dll"
| where Url matches regex @"^http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/.*\.exe$"
| where not(InitiatingProcessImageName in~ ("iexplore.exe", "chrome.exe", "firefox.exe", "edge.exe", "msedge.exe"))
| summarize count() by InitiatingProcessId, InitiatingProcessImageName, Url, UserAgent
| where count_ > 1 or UserAgent in (suspicious_ua)
IOC List
| Type | Value |
|---|---|
| SHA-256 | 022fe01a4fb8855747a4068de2131ceb7486cf846df6c18adbefe7564482adb5 |
| URL | http://89.125.188.171/nah11/file.exe |
| User-Agent | Lak2oes |
| IP | 89.125.188.171 |
| Compile time | 2026-05-28 12:10:32 UTC |
Behavioral Fingerprint
This 64-bit MinGW-w64 binary initializes the WinHTTP stack with a hardcoded User-Agent "Lak2oes", performs an unencrypted HTTP GET to an IP-based URL ending in .exe, downloads the response body into a heap buffer, then manually maps the buffer as a PE image into freshly allocated RWX memory — resolving imports, applying relocations, and transferring execution without ever writing the payload to disk.
Detection Signatures
| ATT&CK Technique | ID | Evidence |
|---|---|---|
| Command-Line Argument Handling | T1059 | strncpy from argv[1] into URL buffer when argc > 1 ^[r2:sym.main] |
| Application Layer Protocol: Web Protocols | T1071.001 | WinHTTP GET to 89.125.188.171 ^[r2:sym.DownloadPE_char_const__unsigned_long_] |
| Process Injection | T1055 | Reflective in-memory PE mapping with RWX allocation ^[r2:fcn.1400014c5] |
| Reflective Code Loading | T1620 | LoadPERaw maps downloaded payload without disk write ^[r2:fcn.1400014c5] |
| Sandbox Evasion: System Checks | T1497.001 | IsWow64Process runtime resolution for architecture parity ^[r2:fcn.14000145c] |
| Obfuscated Files or Information: Software Packing | T1027.002 | C2 URL XOR-encrypted with key 0xAA in code ^[r2:sym.main] |
References
- Artifact ID:
198125ab-cbd8-41ef-99f7-ccde68a4e948^[metadata.json] - OpenCTI labels:
9d2ca3,dropped-by-amadey^[triage.json] - Family entity: 9d2ca3
- Related concept: reflective-pe-loader
- Related concept: mingw-w64-build-artifacts
Provenance
Static inputs: file.txt, exiftool.json, pefile.txt, strings.txt, rabin2-info.txt, metadata.json, triage.json. Reverse engineering: radare2 analysis level 3, sym.main, sym.DownloadPE_char_const__unsigned_long_, fcn.1400014c5, fcn.14000145c decompiled via radare2 MCP. No dynamic detonation available (CAPE skipped — no Windows guest). capa and floss tooling not operational at time of analysis.