typeanalysisfamilysilverfoxconfidencehighcreated2026-08-12updated2026-08-12pemalware-familyloaderdefense-evasionc2evasionobfuscation
SHA-256: b37efcbc178c9f8d2c4059e55311279a435ff5cd9b00840ec17ef0f7110b106c

silverfox: 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:

  • .rsrc contains 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]
  • .text entropy 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:

  1. Network-fetched at runtime (no C2 strings recovered statically), or
  2. Companion-file dependent (see companion-file-key-decryption for the pattern observed in wraith), or
  3. 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:

  1. Resolves the XOR key from .data
  2. Decrypts API strings via the XOR thunk (fcn.004062e8, fcn.004062f0, etc.)
  3. Builds a STARTUPINFOA structure
  4. 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:

  1. Resolves VirtualAllocEx and WriteProcessMemory via the thunk
  2. Allocates memory in a remote process
  3. Writes decrypted payload bytes
  4. Handles PROCESS_INFORMATION structures

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 0x9e37cb23 is 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 no IsDebuggerPresent, no CheckRemoteDebuggerPresent, no NtQueryInformationProcess debug-port checks. It relies entirely on the __argc gate 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 — file command output (PE32+ x64, 5 sections)
  • pefile.txt — pefile.py full PE header dump (timestamps, linker version, sections, imports, resources)
  • rabin2-info.txt — radare2 rabin2 -I summary (C language, stripped, unsigned)
  • exiftool.json — ExifTool metadata (VersionInfo, timestamp)
  • strings.txt — strings extraction (IAT names only, no C2)
  • metadata.json — OpenCTI labels and filename
  • triage.json — triage pipeline metadata (family assignment, tier)
  • ssdeep.txt / tlsh.txt / yara.txt — fuzzy hash and YARA matches (PE_File_Generic only)
  • binwalk.txt — no embedded archives or compressed payloads
  • floss.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.00403c5d via r2mcp decompiler (pdc backend)
  • Python manual analysis — .data XOR key extraction, stream-cipher constant search, .rsrc resource inspection
  • CAPE: skipped — no Windows guest available^[dynamic-analysis.md]