typeanalysisfamilysilverfoxconfidencehighcreated2026-05-30updated2026-05-30pemalware-familyloaderdefense-evasionobfuscationc2evasionmitre-attck
SHA-256: 82d425516199d497c3a25edc4c3ad05c14469f697230f3ad17fe03ce73cd0216

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

  1. Receives an index/offset in rcx.
  2. Reads a pointer from 0x40a380 + rcx.
  3. XOR-decrypts it against the 64-bit constant 0x485dc836051bd16 stored at .data:0x409000.
  4. 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]
  • VirtualAllocEx with allocation type 0x3000 (MEM_COMMIT | MEM_RESERVE) and protection 0x40 (PAGE_EXECUTE_READWRITE).^[r2:fcn.004049b4]
  • WriteProcessMemory to 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 (0x44d9bb23 constant).^[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. 0x409efae_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 ed1a0047 analysis.
  • 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 .buildid and no Rust stdlib strings confirm this is not the Rust compiler artefact seen in ed1a0047.^[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.

  1. Toolchain: MSVC 2019+ (x64 Release), or MinGW-w64.
  2. XOR-thunk: Create a global pointer table g_api[64]; XOR each entry with 0x485dc836051bd16 at compile time. Write a __attribute__((noinline)) thunk that decrypts g_api[idx] and calls through.
  3. FNV-1a resolver: Store API names as char arrays, hash at runtime with basis 0xcbf29ce484222325 and prime 0x100000001b3, match against an embedded hash table.
  4. Stream cipher: Implement the 32-bit LFSR-like update from fcn.00402e77 constants (0x44d9bb23, rotation 5/27, XOR-multiply chain).
  5. Resource embed: Add an encrypted blob as a .rsrc RT_RCDATA entry, extract with FindResource/LoadResource, decrypt via the cipher, then VirtualAllocEx/WriteProcessMemory into a suspended notepad.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)