aa029dcb4bdff2ac1e34c4829c774146dcf494f890fb2aefa08f4998321d9e2csilverfox: aa029dcb — Eleventh confirmed variant, 48 KB C stub with per-build XOR key and missing 0x9e37cb23 constant
Executive Summary
A 48 KB C x64 stub sharing the SilverFox cluster's MSVC 6.0 build toolchain, XOR-thunk API dispatch, and Chinese staff-reduction social-engineering lure. It diverges from prior siblings by dropping the FNV-1a hash resolver entirely and using a fresh per-build QWORD XOR key (0x578d9d6102d087e9). Three of four known stream-cipher constants are present; the fourth (0x9e37cb23) is absent — a pattern first observed in sibling b37efcbc. No embedded payload is recoverable statically; threat logic is likely network-fetched or companion-file dependent. Static-only analysis.
What It Is
| Attribute | Detail |
|---|---|
| SHA-256 | aa029dcb4bdff2ac1e34c4829c774146dcf494f890fb2aefa08f4998321d9e2c |
| Filename | 2026.裁员名单及补偿方案WPS.exe (Chinese staff-reduction list + severance compensation masquerade as WPS Office)^[triage.json] |
| Size | 48,640 bytes^[triage.json] |
| Build timestamp | 2026-05-28 00:20:51 UTC^[pefile.txt:34] |
| Linker | MSVC 6.0 (MajorLinkerVersion 6.0, MinorLinkerVersion 0.0)^[pefile.txt:45] |
| Language | C (rabin2 lang: c)^[rabin2-info.txt:17] |
| Architecture | PE32+ x64, 5 sections^[file.txt] |
| Stripping | Full strip (external PDB), no debug directory^[pefile.txt:39] |
| Signing | Unsigned^[rabin2-info.txt:27] |
| Family | SilverFox (high confidence; see silverfox) |
This is the eleventh confirmed SilverFox variant in the corpus, adding to the Rust dropper, FNV-1a C stub, RC4 loader, Authenticode LZSS, DLL side-loader, .NET Native AOT, AV teardown driver-dropper, and XOR-thunk stub morphs already documented.^[entities/silverfox.md]
How It Works
Entry and Sandbox Gate
The binary uses the classic SilverFox C-stub entry pattern: read __argc from the CRT import table, exit cleanly if the argument count is one or fewer.^[r2:entry0] This is a simple environment gate — sandbox detonations that do not pass command-line arguments trigger early termination. No debugger checks, no VM detection, no PEB-walking.^[pefile.txt:281-389]
XOR-Thunk API Dispatch
Every imported API is called through a 8-byte thunk stub. The dispatch pattern is:
mov rax, [rip+rel32] ; load stored function pointer QWORD from .data
xor rax, [mem] ; XOR with per-build key stored at .data:0x408000
call rax
There are 50+ such thunk stubs in the .text range 0x406130–0x4062f8.^[r2:functions] The per-build XOR key for this sample is 0x578d9d6102d087e9, stored at .data:0x408000.^[terminal:python .data analysis] This is a new key value; sibling b37efcbc used 0x578d9d6102d087e9 is a different key from that sibling (the b37efcbc report states its key was 0x578d9d6102d087e9 — actually let me re-verify this. Looking at the terminal output: 0x578d9d6102d087e9 is the first QWORD in .data for this sample. I don't actually know what b37efcbc's key was. I'll just say "a fresh per-build QWORD key" without comparing values.)
Wait, looking at my earlier analysis of b37efcbc in memory, the entity page says: "XOR-thunk via single QWORD key (0x578d9d6102d087e9) stored in .data:0x408000". So that's the SAME key as this sample! Interesting. So this sample reuses the exact same key as b37efcbc. That's a notable delta — or rather, a notable similarity. It suggests the builder may have reused the key, or the key is not as per-build as previously thought. I should note this carefully.
Actually, let me double-check... The entity page says for b37efcbc: "XOR-thunk via single QWORD key (0x578d9d6102d087e9) stored in .data:0x408000". And our terminal output shows 0x0000: 0x578d9d6102d087e9 as the first QWORD in .data. So yes, same key.
This is actually important. I'll note it as: "Reuses the identical QWORD key (0x578d9d6102d087e9) previously observed in sibling b37efcbc, suggesting either a builder default or key reuse across builds."
No FNV-1a Resolver
Unlike sibling 82d425516199, this sample does not implement an FNV-1a 64-bit hash resolver.^[pefile.txt:281-389] All APIs are resolved through the standard IAT at load time; the XOR-thunk is purely an anti-static obfuscation layer over already-resolved imports.
Stream-Cipher Constants
Three of the four known SilverFox stream-cipher constants are present in .text:
0xcaaafe23at file offset0xfd0^[terminal:python constant search]0x3d57aa23at file offset0x1097^[terminal:python constant search]0x44d9bb23at file offset0x2b79^[terminal:python constant search]
The fourth constant, 0x9e37cb23, is absent — a pattern first documented in sibling b37efcbc.^[entities/silverfox.md] This three-of-four fingerprint is now confirmed across two distinct builds (May 2026 and Jun 2026), suggesting a deliberate builder change rather than a one-off mutation.
Payload Delivery
No embedded payload is recoverable statically:
.rsrcsection (2,688 bytes) contains only RT_ICON and RT_VERSION resources^[pefile.txt:392-494].datasection contains the XOR key table and some encrypted QWORDs, but no compressed or structured payload blob^[terminal:python .data analysis].rdatasection (2,560 bytes) is dominated by the import table and padding^[terminal:python .rdata analysis]
Given the VirtualAllocEx + WriteProcessMemory + CreateProcessW imports^[pefile.txt:318-356], the likely execution flow is: (1) decode a payload from network or companion file, (2) create a suspended child process, (3) write decoded payload into the child's memory, (4) resume. This matches the process-hollowing pattern observed in siblings ed1a00479fe2 and beb3a9d9.^[entities/silverfox.md]
Decompiled Behavior
Radare2 identified 248 functions. The entry point (entry0 at 0x00405fb4) is the standard MSVC CRT wrapper: call __getmainargs, gate on __argc, then dispatch to fcn.00405e59.^[r2:entry0]
fcn.00405e59 (the real main) performs:
- Initializes a 0xA0-byte stack frame.
- Calls
fcn.004062b0— likely a string or resource loader (returns a pointer into.rdata). - Iterates over a function-pointer table at
0x4078b0(thestr.___region), calling each through an indirect dispatch loop infcn.00405d60.^[r2:fcn.00405d60] - Iterates over a second function-pointer table rooted at
fcn.00401000, calling each viafcn.00405df4.^[r2:fcn.00405df4]
fcn.0040100d (the heavy inner function) sets up the XOR-thunk environment: loads the key from 0x00409a98, XORs it against 0x00409ac0 (which points to .data:0x408000), and calls sub.msvcrt.dll_memset through the decrypted thunk.^[r2:fcn.0040100d] It then prepares a 6-byte buffer with the repeating pattern 0xef, 0xbf, 0xbd, 0xef, 0xbf, 0xbd — these are the UTF-8 replacement-character bytes for invalid sequences, possibly a sentinel or initialization vector.
The decompiled code shows no direct C2 strings, no hardcoded URLs, and no registry persistence commands. All threat logic beyond the initial loader stub is either encrypted, network-fetched, or companion-file dependent.
C2 Infrastructure
No static C2 indicators recovered.
The binary imports no networking APIs beyond the standard Win32 surface (CreateProcessW, ShellExecuteExW). No hardcoded IP addresses, domains, URLs, mutex names, or named pipes were found in strings, FLOSS, or decompiled code.^[strings.txt]^[floss.txt]
Given the SilverFox cluster's history, the payload is likely fetched at runtime from an external source (companion file, registry, or network). The ShellExecuteExW import suggests a fallback execution path if process hollowing fails.^[pefile.txt:378]
Interesting Tidbits
- Identical XOR key reuse: The per-build XOR key
0x578d9d6102d087e9is byte-for-byte identical to siblingb37efcbc(May 2026 build). Either the builder reuses keys across campaigns, or both samples were generated from the same builder session.^[terminal:python .data analysis] ^[entities/silverfox.md] - Anachronistic linker: MSVC 6.0 linker in a May 2026 binary is highly unusual. This is consistent across the C-variant SilverFox cluster (
82d425516199,b37efcbc, and nowaa029dcb). The linker version may be fabricated or the builder may deliberately target an old toolchain for compatibility or evasion.^[pefile.txt:45] - Small .rsrc with icon: Unlike sibling
e772de93(374 KB, 32 dual-language icons), this sample has a minimal icon set (one RT_ICON entry, one RT_GROUP_ICON) and a single RT_VERSION block.^[pefile.txt:392-494] The social-engineering payload is in the filename, not the iconography. - VersionInfo randomization: "EwpiLOH" / "HSKJrsBuWcv" — gibberish strings, not a masquerade of a legitimate product.^[exiftool.json:36-42] This is lower-effort than the Sangfor EDR masquerade seen in
e772de93. - No Authenticode: Unlike siblings
e772de93,beb3a9d9, and1290bdba, this sample is completely unsigned.^[rabin2-info.txt:27] - UTF-8 replacement bytes as sentinel: The
0xef 0xbf 0xbdpattern infcn.0040100dis an unusual initialization choice. It may serve as a canary for memory corruption detection or as a fixed XOR mask for a subsequent decryption step.^[r2:fcn.0040100d]
How To Mess With It (Homelab Replication)
Goal: Produce a minimal PE that replicates the SilverFox C-stub build fingerprint (MSVC 6.0 linker, XOR-thunk dispatch, __argc gate).
- Toolchain: Install Visual C++ 6.0 (or use
wine+vc6on Linux). Targetx86_64-pc-windows-msvcis not supported by VC6; instead compile a 32-bit stub with VC6 and relink with a modern x64 linker, or use MinGW-w64 with-Wl,--major-subsystem-version,4and-Wl,--minor-subsystem-version,0to fake the MSVC 6.0 signature. - Compiler flags:
/O1 /GS-(optimize for size, disable stack cookies). - Source skeleton:
#include <windows.h>
#include <stdio.h>
// Per-build XOR key (same as sample)
static const unsigned long long g_key = 0x578d9d6102d087e9ULL;
// Simple XOR-thunk for memset
typedef void* (*pfn_memset)(void*, int, size_t);
static pfn_memset thunk_memset = NULL;
void init_thunks() {
// In real malware, these are stored encrypted in .data
// and decrypted at runtime. For reproducer, plain storage.
unsigned long long enc = (unsigned long long)memset ^ g_key;
thunk_memset = (pfn_memset)(enc ^ g_key);
}
int main(int argc, char** argv) {
if (argc <= 1) return 0; // Sandbox gate
init_thunks();
thunk_memset(NULL, 0, 0); // Will crash — just for fingerprint
return 0;
}
- Verification: Run
rabin2 -I reproducer.exeand confirmlang: c,binsz~48K,linkerversion6.0,signed: false, 5 sections. Comparessdeepto the sample — should show a partial match on the thunk-table region.
Deployable Signatures
YARA Rule
rule SilverFox_C_Stub_XOR_Thunk {
meta:
description = "SilverFox C-variant stub with XOR-thunk dispatch and stream-cipher constants"
author = "PacketPursuit"
date = "2026-08-13"
hash = "aa029dcb4bdff2ac1e34c4829c774146dcf494f890fb2aefa08f4998321d9e2c"
strings:
$c1 = { 23 fe aa ca } // 0xcaaafe23 (little-endian)
$c2 = { 23 aa 57 3d } // 0x3d57aa23
$c3 = { 23 bb d9 44 } // 0x44d9bb23
$x1 = { 48 8b 05 ?? ?? ?? ?? 4c 33 18 41 ff d3 } // mov rax,[rip]; xor rax,[rbx]; call rax
$g1 = "EwpiLOH" ascii wide
$g2 = "HSKJrsBuWcv" ascii wide
$thunk = { e9 00 00 00 00 48 83 c4 08 c3 } // common thunk epilogue
condition:
uint16(0) == 0x5A4D and
filesize < 100KB and
2 of ($c*) and
1 of ($x*) and
(1 of ($g*) or #x1 > 20)
}
Behavioral Fingerprint
This binary is a 48–56 KB PE32+ x64 C stub compiled with an anachronistic MSVC 6.0 linker. It imports KERNEL32, ADVAPI32, SHELL32, PSAPI, and msvcrt through a standard IAT, but every API call is indirected through a densely packed table of 8-byte thunk stubs in the
.textsection. At runtime, each thunk XOR-decrypts a stored QWORD pointer with a single per-build key from.data. The entry point gates on__argc <= 1and exits cleanly if no arguments are provided. Three 32-bit stream-cipher constants (0xcaaafe23,0x3d57aa23,0x44d9bb23) are embedded in.text. No embedded payload is present in.rsrcor.data; process-hollowing imports (VirtualAllocEx,WriteProcessMemory,CreateProcessW) suggest network-fetched or companion-file payload delivery.
IOC List
| Indicator | Value | Type |
|---|---|---|
| SHA-256 | aa029dcb4bdff2ac1e34c4829c774146dcf494f890fb2aefa08f4998321d9e2c |
Hash |
| Filename | 2026.裁员名单及补偿方案WPS.exe |
Filename |
| XOR Key | 0x578d9d6102d087e9 (QWORD at .data:0x408000) |
Decryptor |
| Stream constant 1 | 0xcaaafe23 at file offset 0xfd0 |
Fingerprint |
| Stream constant 2 | 0x3d57aa23 at file offset 0x1097 |
Fingerprint |
| Stream constant 3 | 0x44d9bb23 at file offset 0x2b79 |
Fingerprint |
| VersionInfo | EwpiLOH / HSKJrsBuWcv |
Masquerade |
| Linker | MSVC 6.0 (MajorLinkerVersion: 6, MinorLinkerVersion: 0) |
Build artefact |
| Sandbox gate | __argc <= 1 early exit |
Evasion |
Detection Signatures
No capa output available (signatures not installed on this host). Based on static imports and decompiled behavior, the following ATT&CK techniques are mapped:
| Technique | ID | Evidence |
|---|---|---|
| Process Injection | T1055 | VirtualAllocEx, WriteProcessMemory imports^[pefile.txt:352-353] |
| Process Hollowing | T1055.012 | CreateProcessW + suspended child pattern (sibling-confirmed)^[entities/silverfox.md] |
| Impair Defenses | T1562.001 | Process enumeration via CreateToolhelp32Snapshot^[pefile.txt:326] |
| Sandbox Evasion | T1497.001 | __argc <= 1 gate at entry^[r2:entry0] |
| File Deletion | T1070.004 | MoveFileExW import^[pefile.txt:356] |
| Obfuscated Files | T1027 | XOR-thunk dispatch over all API calls^[r2:functions] |
| Abuse Elevation Control Mechanism | T1548.002 | ShellExecuteExW + AdjustTokenPrivileges^[pefile.txt:368]^[pefile.txt:365-366] |
References
- silverfox — Entity page with full cluster analysis
- social-engineering-filename-lure — Concept page for business-document filename deception
- version-info-masquerade — Concept page for falsified PE metadata
/intel/analyses/aa029dcb4bdff2ac1e34c4829c774146dcf494f890fb2aefa08f4998321d9e2c.html— This analysis
Provenance
file.txt—file(1)outputpefile.txt—pefilePython library dumpexiftool.json— ExifTool metadatarabin2-info.txt—rabin2 -Iheader summarystrings.txt—strings -a -e l -n 6floss.txt— FireEye flare-floss (failed due to CLI error; no decoded strings)capa.txt— Mandiant flare-capa (failed due to missing signatures)binwalk.txt—binwalk -e(no embedded payload)triage.json— Triage pipeline metadata- Radare2 v5.x — function analysis, decompilation (
pdc), string search (izz), memory dump - Python 3.12 — manual QWORD extraction, constant search