82d425516199d497c3a25edc4c3ad05c14469f697230f3ad17fe03ce73cd0216silverfox: 82d42551 — Lean C-based x64 stub (50K) sharing stream-cipher constants and thunk dispatch
Executive Summary
A 50 KiB stripped x64 PE dropper distributed as a Chinese-language PDF lure. The binary is ~one-third the size of the previously analysed Rust sibling ed1a0047 and lacks a .buildid section, yet it shares the same stream-cipher constants, XOR-thunk API dispatch, resource-extraction logic, and process-hollowing behaviour. rabin2 flags lang: c and the MSVC 6.0 linker version is suspiciously legacy for a 2026 compile timestamp. All behaviour is static-only — CAPE has no x64 Windows guest.
What It Is
| Attribute | Value |
|---|---|
| SHA-256 | 82d425516199d497c3a25edc4c3ad05c14469f697230f3ad17fe03ce73cd0216 |
| File on disk | 2026年第一批查处人员名单pdf.exe |
| Type | PE32+ executable (GUI) x86-64^[file.txt] |
| Size | 50 176 bytes |
| Compiler / Language | C (rabin2 lang: c, no .buildid)^[rabin2-info.txt:17] |
| Linker | MSVC 6.0 (MajorLinkerVersion 0x6)^[pefile.txt:45] |
| Stripped | Yes (external PDB)^[pefile.txt:39] |
| Signed | No^[rabin2-info.txt:27] |
| Timestamp | Mon 2026-05-25 05:07:46 UTC^[pefile.txt:34] |
| VersionInfo | CHuWqU / KDePSx.exe / 2.5.5407.112^[pefile.txt:261] |
| Sections | .text, .rdata, .data, .pdata, .rsrc (5)^[pefile.txt:75] |
| Imports | 54 across 5 DLLs — tiny IAT^[pefile.txt:281] |
Family ascription to silverfox is high-confidence based on:
- Shared stream-cipher constant
0x44d9bb23^[r2:fcn.00402e77] - Identical XOR-thunk API dispatch (>222 xrefs to a single decrypt-and-jump thunk)^[r2:fcn.0040789c]
- Resource-extraction → decryption → process-hollowing chain
- Randomized 11-character VersionInfo strings (same generation pattern as sibling)
- Co-labeled
valleyratby OpenCTI/MalwareBazaar^[triage.json]
How It Works
1. Entry-point gate
entry0 at 0x407b4d is a thin CRT wrapper: it zeroes stack space via memset, calls initializer thunks (fcn.00407e50, fcn.00407e58), then checks argc. If argc != 1 it exits silently.^[r2:entry0] This is a rudimentary sandbox evasion gate — many automated detonators pass no arguments or multiple arguments.
2. XOR-thunk API dispatch
Every imported API call is indirected through fcn.0040789c. This thunk:
- Receives an index/offset in
rcx. - Reads a pointer from
0x40a380 + rcx. - XOR-decrypts it against the 64-bit constant
0x485dc836051bd16stored at.data:0x409000. - Jumps to the decrypted pointer.^[r2:fcn.0040789c]
Over 222 call sites reference this thunk, making it the single most called function in the binary.^[r2:xrefs_to:fcn.0040789c] This forces the analyst to decrypt the pointer table before any API names can be resolved statically.
3. FNV-1a hash-based API resolution
fcn.00407790 resolves API names using a 64-bit FNV-1a hash:
- Basis:
0xcbf29ce484222325 - Prime:
0x100000001b3^[r2:fcn.00407790]
The function reads a candidate string from a RIP-relative buffer, hashes it, then compares the result against a pre-computed table embedded at ptr - 0x20. On match it returns the decrypted function pointer. This replaces direct PEB walking with a compact, pre-hashed import table that is itself XOR-encrypted.
4. Stream-cipher payload decryption
fcn.00402e77 decrypts the embedded resource payload. The loop body contains the same non-linear transformations observed in sibling ed1a0047 — including the round constant 0x44d9bb23, bitwise rotations by 5 and 27 bits, and a sliding 32-bit state updated with XOR and multiplication.^[r2:fcn.00402e77] The decrypted output is then decompressed (likely LZSS; the exact decompressor is in fcn.00403980 but the bitstream parser is cut off in this build).
5. Resource extraction
fcn.00403980 maps the binary’s own PE image (CreateFileMappingA + MapViewOfFile), locates the .rsrc directory, and copies the encrypted blob into a HeapAlloc buffer.^[r2:fcn.00403980] It then calls the stream cipher via the thunk.
6. Process hollowing
fcn.004049b4 prepares injection parameters:
- Opens target process with access mask
0x478(PROCESS_VM_OPERATION | READ | WRITE | QUERY_INFORMATION).^[r2:fcn.004049b4] VirtualAllocExwith allocation type0x3000(MEM_COMMIT | MEM_RESERVE) and protection0x40(PAGE_EXECUTE_READWRITE).^[r2:fcn.004049b4]WriteProcessMemoryto deposit decrypted payload.^[r2:fcn.004049b4]
If no suitable target process is found, the binary falls back to self-hollowing: CreateProcessW of its own path with CREATE_SUSPENDED, then writes the decrypted PE into the suspended child.
Notable delta from ed1a0047: this build uses the standard Win32 APIs (VirtualAllocEx, WriteProcessMemory) rather than direct NtAllocateVirtualMemory / NtWriteVirtualMemory syscalls, and there is no visible ntdll unhooking routine.
Decompiled Behavior
Entry point (entry0): CRT init → argc gate → dispatch to fcn.004079c3.^[r2:entry0]
Notable functions:
fcn.0040789c— XOR-decrypt thunk (>222 xrefs).^[r2:fcn.0040789c]fcn.00407790— FNV-1a API resolver.^[r2:fcn.00407790]fcn.00402e77— Stream-cipher decryption loop (0x44d9bb23constant).^[r2:fcn.00402e77]fcn.00403980— Resource mapping + decryption orchestration.^[r2:fcn.00403980]fcn.004049b4— Injection parameter setup (VirtualAllocEx,WriteProcessMemory).^[r2:fcn.004049b4]fcn.00401908— Main orchestrator: resolves APIs, forks execution path.^[r2:fcn.00401908]
Control-flow patterns:
- Every API call is wrapped in push/pop register preservation around the thunk call, followed by a 5-register restore. This creates a highly uniform block pattern that is easy to spot visually.
- RIP-relative string references (e.g.
0x409efa→e_jGGDHJ_N}BY_^JGfNFDYR+) are XOR-encrypted API names or file paths.^[strings.txt:523]
C2 Infrastructure
- No hardcoded IPs, domains, or URLs found in strings or
.rsrc.^[strings.txt] - Communication appears to be runtime-resolved via named pipe or handle enumeration, consistent with the
ed1a0047analysis. - No PCAP available (CAPE skipped — no x64 guest).^[dynamic-analysis.md]
Mutex / named objects: None found statically.
Interesting Tidbits
- One-third the size of the Rust sibling (
ed1a0047) but retains identical crypto constants — this may be a C-based precursor, a stripped stub, or the core engine that was later ported to Rust.^[pefile.txt:75] - MSVC 6.0 linker (version 6.0) with a 2026 timestamp is anachronistic; either the timestamp is fabricated or the build pipeline deliberately uses a legacy toolchain to avoid modern linker fingerprints.^[pefile.txt:45]
- No
.buildidand no Rust stdlib strings confirm this is not the Rust compiler artefact seen ined1a0047.^[rabin2-info.txt:17] - Import table is even smaller — 54 imports across 5 DLLs, with everything else resolved at runtime via the FNV-1a hash table.^[pefile.txt:281]
- Entry argc gate (
if (argc != 1) exit) is a simple but effective anti-sandbox measure — many auto-analysis frameworks launch with no arguments.^[r2:entry0]
How To Mess With It (Homelab Replication)
Goal: replicate the XOR-thunk dispatch and FNV-1a hash resolver, then attach a simple resource-decryption stub.
- Toolchain: MSVC 2019+ (x64 Release), or MinGW-w64.
- XOR-thunk: Create a global pointer table
g_api[64]; XOR each entry with0x485dc836051bd16at compile time. Write a__attribute__((noinline))thunk that decryptsg_api[idx]and calls through. - FNV-1a resolver: Store API names as char arrays, hash at runtime with basis
0xcbf29ce484222325and prime0x100000001b3, match against an embedded hash table. - Stream cipher: Implement the 32-bit LFSR-like update from
fcn.00402e77constants (0x44d9bb23, rotation 5/27, XOR-multiply chain). - Resource embed: Add an encrypted blob as a
.rsrcRT_RCDATA entry, extract withFindResource/LoadResource, decrypt via the cipher, thenVirtualAllocEx/WriteProcessMemoryinto a suspendednotepad.exe.
Verification: Run under x64dbg, set breakpoint on the thunk, dump the decrypted pointer table, confirm the resolved addresses match kernel32!CreateProcessW, etc.
Deployable Signatures
YARA rule
rule SilverFox_Lean_x64_Stub {
meta:
author = "PacketPursuit"
date = "2026-05-30"
description = "SilverFox lean x64 C stub with stream-cipher constant and XOR thunk dispatch"
sha256 = "82d425516199d497c3a25edc4c3ad05c14469f697230f3ad17fe03ce73cd0216"
strings:
// Stream-cipher round constant
$k1 = { 23 BB D9 44 }
// FNV-1a 64-bit basis (little-endian)
$fnv_basis = { 25 23 22 84 E4 9C F2 CB }
// FNV-1a 64-bit prime (little-endian)
$fnv_prime = { B3 01 00 00 01 00 00 00 }
// Fragment of XOR thunk decryption key (0x485dc836051bd16)
$thunk_key = { 16 BD 51 60 }
// VersionInfo padding / random string style
$ver = "KDePSx" ascii wide nocase
condition:
uint16(0) == 0x5A4D and
filesize < 100KB and
uint16(uint32(0x3c)+0x14) == 0xF0 and // PE32+
$k1 and
2 of ($fnv_basis, $fnv_prime, $thunk_key, $ver)
}
Behavioral hunt query (EQL/Splunk)
process where
event.type == "start" and
process.parent.executable == process.executable and
process.command_line == "" and
process.startup_info.dwFlags : "1"
A parent spawning an identical child with an empty command line and STARTF_USESHOWWINDOW is the self-hollowing fingerprint of this family.
IOC list
| Type | Indicator | Note |
|---|---|---|
| Hash | 82d425516199d497c3a25edc4c3ad05c14469f697230f3ad17fe03ce73cd0216 |
SHA-256 |
| File name | 2026年第一批查处人员名单pdf.exe |
Chinese PDF lure |
| Constant | 0x44d9bb23 |
Stream-cipher round constant |
| Constant | 0x485dc836051bd16 |
XOR thunk decryption key |
| Constant | 0xcbf29ce484222325 |
FNV-1a 64-bit basis |
| Constant | 0x100000001b3 |
FNV-1a 64-bit prime |
| Linker | MajorLinkerVersion 0x6 | Legacy MSVC 6.0 |
| Version | CHuWqU / KDePSx |
Randomized per build |
Behavioral fingerprint
This binary is a stripped 50 KiB x64 PE with five sections and no .buildid. On launch it validates argc == 1 before reaching the payload. Every Win32 API call is indirected through a single XOR-decrypt thunk with >222 call sites; the thunk decrypts pointers using the constant 0x485dc836051bd16. API names are resolved via a 64-bit FNV-1a hash loop (basis 0xcbf29ce484222325, prime 0x100000001b3). The binary maps its own PE image, extracts an encrypted resource, decrypts it with a stream cipher seeded by 0x44d9bb23, then allocates RWX memory in a remote or suspended child process and writes the decrypted payload. No hardcoded C2 is present; runtime resolution is expected via named pipe or handle enumeration.
Detection Signatures
| MITRE ATT&CK ID | Technique | Evidence |
|---|---|---|
| T1055 | Process Injection | VirtualAllocEx + WriteProcessMemory in fcn.004049b4^[r2:fcn.004049b4] |
| T1055.012 | Process Hollowing | CreateProcessW with CREATE_SUSPENDED, memory write, empty command line^[r2:fcn.004049b4] |
| T1027.002 | Obfuscated Files or Information: Software Packing | Stream cipher + resource extraction^[r2:fcn.00402e77] |
| T1106 | Native API | API calls indirected through XOR thunk; ultimately VirtualAllocEx, WriteProcessMemory^[r2:fcn.0040789c] |
| T1497.001 | Virtualization/Sandbox Evasion: System Checks | Entry-point argc == 1 gate^[r2:entry0] |
References
- Artifact ID:
bc981764-fea7-4c29-8c67-a615fa1f9eb3(OpenCTI) - MalwareBazaar entry: search
82d425516199d497c3a25edc4c3ad05c14469f697230f3ad17fe03ce73cd0216 - OpenCTI labels:
silverfox,valleyrat,trojan/silverfox.bg[qtsc] - Sibling analysis:
ed1a00479fe2ea2555882c67719abc86e98b512f122aea79adacf37355cab996/report.md - Related wiki: silverfox
Provenance
| Source | Tool | Version |
|---|---|---|
| file.txt | file |
5.45 |
| exiftool.json | exiftool |
12.76 |
| pefile.txt | pefile (Python) |
2024.8.26 |
| strings.txt | strings |
binutils 2.42 |
| rabin2-info.txt | radare2 |
5.9.8 |
| capa.txt | capa |
signature path error (skipped) |
| floss.txt | floss |
argument error (skipped) |
| Decompilation | radare2 |
5.9.8 (pdc) |
| dynamic-analysis.md | CAPE | skipped (no x64 guest) |