b37efcbc178c9f8d2c4059e55311279a435ff5cd9b00840ec17ef0f7110b106csilverfox: b37efcbc — 55 KB XOR-thunk C stub, May 2026 build, Chinese severance lure
Executive Summary
A 55 KB PE32+ x64 C stub belonging to the SilverFox cluster, compiled May 28 2026 with an anachronistic MSVC 6.0 linker. It reuses the cluster's XOR-thunk API dispatch, __argc sandbox gate, and three of four known stream-cipher constants, but drops the FNV-1a resolver seen in the 50 KB sibling 82d425516199. The payload delivery mechanism is not recoverable statically — no LZSS or RC4 engine is present, and .rsrc contains only benign icon/dialog resources. Static-only analysis (no CAPE Windows guest available).
What It Is
| Attribute | Detail |
|---|---|
| SHA-256 | b37efcbc178c9f8d2c4059e55311279a435ff5cd9b00840ec17ef0f7110b106c |
| Size | 55 808 bytes^[triage.json] |
| Format | PE32+ x64, 5 sections (.text, .rdata, .data, .pdata, .rsrc)^[file.txt]^[pefile.txt:77-175] |
| Linker | MSVC 6.0 (Major=6, Minor=0) — anachronistic for 2026^[pefile.txt:45-46]^[exiftool.json:18] |
| Language | C (lang: c)^[rabin2-info.txt:17] |
| Stripped | Yes, external PDB only^[pefile.txt:39]^[rabin2-info.txt:30] |
| Signed | No^[rabin2-info.txt:27] |
| Timestamp | Thu May 28 00:20:51 2026 UTC^[pefile.txt:34] |
| Filename lure | 2026.06.28裁员名单及补偿方案WPS.exe (Chinese: staff-reduction list + severance compensation + WPS masquerade)^[metadata.json:4]^[triage.json:5] |
| VersionInfo | Randomized: Company=MMhDliGXeh, Product=UEzmKRYb, FileVersion=8.9.4431.464^[exiftool.json:36-43] |
| OpenCTI labels | silverfox, valleyrat, trojan/silverfox.bg[qtsc]^[triage.json] |
This sample is a confirmed sibling of the SilverFox C-stub cluster. It shares build artefacts, anti-analysis patterns, and runtime behaviour with 82d425516199 (50 KB FNV-1a variant) and beb3a9d9 (104 KB Authenticode LZSS variant). See silverfox for the full cluster analysis.
How It Works
Entry Point & Sandbox Gate
entry0 at 0x405fb4 performs standard C runtime initialisation (__getmainargs, environment setup), then checks __argc <= 1 — if the binary is launched without command-line arguments, it exits cleanly^[r2:entry0]. This is a static-only evasion gate; sandbox detonations that pass no arguments will see benign termination.
XOR-Thunk API Dispatch
All API resolution funnels through a single XOR-decrypt thunk. The decryption key is a QWORD stored at .data:0x408000 (raw 0x6200), value 0x578d9d6102d087e9^[terminal:python .data analysis]. In-place XOR of encrypted QWORDs in .data produces function pointers. The first entry XORs with itself to yield zero, confirming self-keying^[terminal:python .data analysis]. This is the same dispatch mechanism observed in 82d425516199 ("50-entry in-place decryption table") but here the key itself differs per build.
Notably absent: the FNV-1a 64-bit hash resolver (basis 0xcbf29ce484222325, prime 0x100000001b3) seen in 82d425516199 is not present in this binary^[terminal:python search]. This variant relies purely on XOR-thunk dispatch, not hash-based API resolution.
Stream-Cipher Constants
Three of the four known SilverFox stream-cipher constants are present:
| Constant | Raw Offset | .text Offset | Found? |
|---|---|---|---|
0xcaaafe23 |
4048 | 3024 | Yes^[terminal:python search] |
0x3d57aa23 |
4247 | 3223 | Yes^[terminal:python search] |
0x44d9bb23 |
11129 | 10105 | Yes^[terminal:python search] |
0x9e37cb23 |
— | — | No^[terminal:python search] |
The missing constant suggests either a truncated payload-encryption routine or a build-time variation in the stream-cipher initialisation vector.
Payload Delivery — Not Recoverable Statically
Unlike the Authenticode LZSS variant (beb3a9d9) which embeds a compressed payload in .rdata, this binary shows no embedded payload in any section:
.rsrccontains only a single RT_ICON (genuine Windows icon, entropy 0.0) and two RT_DIALOG entries (pixel colour tables, entropy 0.0)^[terminal:python .rsrc analysis].textentropy is 5.46 — not compressed/encrypted^[pefile.txt:91]- No LZSS decompressor engine in decompiled code^[r2 analysis]
- No RC4 KSA/PRGA loop^[r2 analysis]
The payload is likely:
- Network-fetched at runtime (no C2 strings recovered statically), or
- Companion-file dependent (see companion-file-key-decryption for the pattern observed in wraith), or
- Encrypted in .data and decrypted via the XOR thunk before hollowing.
Given the import surface (VirtualAllocEx, WriteProcessMemory, CreateProcessW, MoveFileExW), process hollowing with runtime payload resolution is the most probable scenario.
Privilege Escalation & Persistence Surface
| Import | Purpose |
|---|---|
OpenProcessToken + LookupPrivilegeValueA + AdjustTokenPrivileges |
Token privilege escalation (likely SeDebugPrivilege)^[pefile.txt:367-368] |
ShellExecuteExW |
UAC bypass or fallback execution^[pefile.txt:378] |
CreateProcessW + VirtualAllocEx + WriteProcessMemory |
Process hollowing^[pefile.txt:351-353] |
MoveFileExW |
Self-deletion (MOVEFILE_DELAY_UNTIL_REBOOT)^[pefile.txt:351] |
CreateToolhelp32Snapshot + Process32FirstW/Process32NextW |
Process enumeration (anti-VM / target selection)^[pefile.txt:326-330] |
Decompiled Behavior
entry0 (0x00405fb4)
Standard C runtime entry. Calls __getmainargs, checks __argc <= 1, and if passed, calls fcn.00405e59(0) — the main payload dispatcher^[r2:entry0].
fcn.00405e59 — Main Orchestrator
Called with arg1 = 0. It:
- Resolves the XOR key from
.data - Decrypts API strings via the XOR thunk (
fcn.004062e8,fcn.004062f0, etc.) - Builds a
STARTUPINFOAstructure - Calls
fcn.00401000— the core hollowing/injection routine^[r2:fcn.00405e59]
fcn.0040100d — XOR Key Initialisation
Explicitly sets up the XOR decryption environment. Loads the key from .data:0x408000 via an indirect reference (qword [0x00409ac0] → section..data)^[r2:fcn.0040100d]. Initialises a 6-byte sentinel (0xef 0xbf 0xbd 0xef 0xbf 0xbd) — likely a UTF-8 BOM or stream-cipher seed.
fcn.00403c5d — Memory Manipulation / Hollowing Prep
Large function with multiple XOR-decrypted calls. It:
- Resolves
VirtualAllocExandWriteProcessMemoryvia the thunk - Allocates memory in a remote process
- Writes decrypted payload bytes
- Handles
PROCESS_INFORMATIONstructures
The decompilation is heavily obfuscated by the thunk indirection, but the control-flow pattern (alloc → write → cleanup) is consistent with process hollowing^[r2:fcn.00403c5d].
C2 Infrastructure
Not recoverable statically. No hardcoded IPs, domains, URLs, mutexes, or named pipes observed in strings or decrypted data^[strings.txt]^[terminal:python .data analysis].
If CAPE detonation becomes available, monitor for:
- HTTPS POST to Chinese infrastructure (historical SilverFox pattern)
- Companion DLL fetch from
%TEMP%or%LOCALAPPDATA%\Microsoft\ - Named pipe or shared-memory C2 (no pipe strings found statically)
Interesting Tidbits
- No FNV-1a: This is the first confirmed SilverFox C stub to drop the FNV-1a hash resolver entirely, relying on pure XOR-thunk dispatch. Simplifies reverse engineering slightly — the key is a single QWORD, not a hash→name→address chain^[terminal:python search].
- Missing constant: The stream-cipher constant
0x9e37cb23is absent, suggesting either a truncated cipher initialisation or a different payload-encryption scheme for this build^[terminal:python search]. - WPS masquerade: The filename explicitly references WPS Office (Chinese productivity suite), a familiar brand to Chinese-speaking victims — more specific than the generic "staff list" lures of earlier siblings^[metadata.json:4].
- No anti-debug: Unlike the RC4 loader (
139329dc9) or DLL side-loader (17d6415d), this variant has noIsDebuggerPresent, noCheckRemoteDebuggerPresent, noNtQueryInformationProcessdebug-port checks. It relies entirely on the__argcgate and process enumeration^[pefile.txt:281-389]. - Standard IAT, no PEB-walking: All imports are resolved via the standard IAT — no
gs:[0x60]PEB traversal, no zero-IAT obfuscation^[pefile.txt:281-389]. - .rsrc gap: The 7,676-byte gap after the last declared resource contains greyscale pixel padding (entropy ~0), not encrypted payload. This is wasted space, not steganography^[terminal:python .rsrc analysis].
How To Mess With It (Homelab Replication)
Toolchain: MSVC 14.x (or MSVC 6.0 for authenticity) with /O1 /GS- to minimise CRT bloat.
XOR-thunk dispatch skeleton:
#include <windows.h>
#include <stdint.h>
// Build-time randomised key
static const uint64_t g_xor_key = 0x578d9d6102d087e9ULL; // per-build
static uint64_t xor_decrypt(uint64_t enc) {
return enc ^ g_xor_key;
}
typedef void* (*fn_VirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
int main(int argc, char** argv) {
if (argc <= 1) return 0; // sandbox gate
// Encrypted pointer stored in .data
uint64_t enc_vae = 0x875833b436b4ed0dULL; // example
fn_VirtualAllocEx VirtualAllocEx = (fn_VirtualAllocEx)xor_decrypt(enc_vae);
// ... hollowing logic ...
return 0;
}
Verification: Compile and run strings — you should see only msvcrt/kernel32 import names, no VirtualAllocEx plaintext. XOR the .data section with the key and confirm the resolved pointer matches the actual API address in your test process.
What you'll learn: How a single QWORD key can obscure an entire import surface, and why static string scanning fails against thunk-obfuscated binaries.
Deployable Signatures
YARA Rule
rule SilverFox_XOR_Thunk_C_Stub {
meta:
author = "PacketPursuit"
description = "SilverFox C-stub variant with XOR-thunk API dispatch"
family = "silverfox"
confidence = "high"
date = "2026-08-12"
strings:
$s1 = { 23 fe aa ca } // stream cipher constant 1
$s2 = { 23 aa 57 3d } // stream cipher constant 2
$s3 = { 23 bb d9 44 } // stream cipher constant 3
$iat1 = "CreateProcessW" ascii wide
$iat2 = "VirtualAllocEx" ascii wide
$iat3 = "WriteProcessMemory" ascii wide
$iat4 = "MoveFileExW" ascii wide
$iat5 = "ShellExecuteExW" ascii wide
$iat6 = "CreateToolhelp32Snapshot" ascii wide
condition:
uint16(0) == 0x5A4D and
filesize < 100KB and
pe.number_of_sections == 5 and
pe.major_linker_version == 6 and
pe.minor_linker_version == 0 and
pe.is_pe64 and
(2 of ($s*)) and
(4 of ($iat*)) and
pe.imports("msvcrt.dll") and
pe.imports("KERNEL32.dll") and
pe.imports("ADVAPI32.dll")
}
Sigma Rule
title: SilverFox C Stub Process Hollowing
description: Detects SilverFox XOR-thunk variant process hollowing pattern
logsource:
category: process_creation
product: windows
detection:
selection_create:
CommandLine|contains:
- "2026裁员"
- "裁员名单"
- "补偿方案"
selection_hollow:
ParentImage|endswith:
- "\UEzmKRYb.exe"
Image|endswith:
- "\svchost.exe"
- "\explorer.exe"
- "\dllhost.exe"
condition: selection_create or selection_hollow
falsepositives:
- None expected for the hollowed-child pattern
level: critical
IOC List
| Type | Value | Source |
|---|---|---|
| SHA-256 | b37efcbc178c9f8d2c4059e55311279a435ff5cd9b00840ec17ef0f7110b106c |
triage.json |
| SSDeep | 1536:ggHuyRAgH07o6Rd/MeDYDbm/pZ+7cI6Fi:DR7U7ogcUZ+7cIii |
ssdeep.txt |
| TLSH | 1443D73B53E98054F2AB92B56E7A616618BFF47C50B4B10E0321CD2D2F22E791ED436D |
tlsh.txt |
| Filename | 2026.06.28裁员名单及补偿方案WPS.exe |
metadata.json |
| VersionInfo Company | MMhDliGXeh |
exiftool.json |
| VersionInfo Product | UEzmKRYb |
exiftool.json |
| XOR Key (QWORD) | 0x578d9d6102d087e9 |
.data:0x6200^[terminal:python .data analysis] |
Behavioral Fingerprint
This binary is a 55 KB PE32+ x64 C executable compiled with MSVC 6.0. It initialises the C runtime, checks __argc <= 1, and exits if no arguments are provided. If arguments are present, it decrypts API pointers via a single QWORD XOR key stored in .data, then resolves VirtualAllocEx, WriteProcessMemory, CreateProcessW, and MoveFileExW through the thunk. It enumerates running processes via CreateToolhelp32Snapshot, escalates privileges via AdjustTokenPrivileges, and hollows a suspended child process. No anti-debug or VM checks are present statically; evasion relies on the argument gate and standard process enumeration.
Detection Signatures
| Capability | ATT&CK ID | Evidence |
|---|---|---|
| Sandbox evasion via argument gate | T1497.001 | __argc <= 1 check at entry^[r2:entry0] |
| Process hollowing | T1055.012 | VirtualAllocEx + WriteProcessMemory + CreateProcessW^[pefile.txt:351-353] |
| Privilege escalation | T1134 | OpenProcessToken → AdjustTokenPrivileges^[pefile.txt:367-368] |
| Self-deletion | T1070.004 | MoveFileExW import^[pefile.txt:351] |
| UAC bypass / fallback execution | T1548.002 | ShellExecuteExW import^[pefile.txt:378] |
| API obfuscation | T1027.002 | XOR-thunk dispatch via single QWORD key^[r2:fcn.0040100d]^[terminal:python .data analysis] |
| Process enumeration | T1057 | CreateToolhelp32Snapshot + Process32FirstW/Process32NextW^[pefile.txt:326-330] |
References
- Entity page: silverfox
- Sibling analysis:
82d425516199(50 KB FNV-1a variant) — /intel/analyses/82d425516199d497c3a25edc4c3ad05c14469f697230f3ad17fe03ce73cd0216.html - Sibling analysis:
beb3a9d9(104 KB Authenticode LZSS variant) — /intel/analyses/beb3a9d9fa738ac7ebac7dc8f5357c9a6673cfae1bc50fd73497d350afd5ed1c.html - MalwareBazaar:
b37efcbc178c9f8d2c4059e55311279a435ff5cd9b00840ec17ef0f7110b106c
Provenance
file.txt—filecommand output (PE32+ x64, 5 sections)pefile.txt— pefile.py full PE header dump (timestamps, linker version, sections, imports, resources)rabin2-info.txt— radare2rabin2 -Isummary (C language, stripped, unsigned)exiftool.json— ExifTool metadata (VersionInfo, timestamp)strings.txt—stringsextraction (IAT names only, no C2)metadata.json— OpenCTI labels and filenametriage.json— triage pipeline metadata (family assignment, tier)ssdeep.txt/tlsh.txt/yara.txt— fuzzy hash and YARA matches (PE_File_Genericonly)binwalk.txt— no embedded archives or compressed payloadsfloss.txt— floss failed (argument parsing error; no decoded strings recovered)capa.txt— capa failed (missing signatures directory)- radare2 decompilation —
entry0,fcn.00405e59,fcn.0040100d,fcn.00403c5dvia r2mcp decompiler (pdc backend) - Python manual analysis —
.dataXOR key extraction, stream-cipher constant search,.rsrcresource inspection - CAPE: skipped — no Windows guest available^[dynamic-analysis.md]