typeanalysisfamilysilverfoxconfidencehighpemalware-familyloaderdefense-evasionc2evasionobfuscationcompilersigning
SHA-256: beb3a9d9fa738ac7ebac7dc8f5357c9a6673cfae1bc50fd73497d350afd5ed1c

silverfox: beb3a9d9 — Authenticode-signed C x64 sibling with LZSS .rdata payload and process enumeration

Executive Summary

A 104 KB MSVC C x64 dropper attributed to the SilverFox/ValleyRAT cluster. Unlike the Rust primary (ed1a0047) and the FNV-1a C stub (82d42551), this sibling uses a standard IAT (no zero-IAT/PEB-walking), embeds its LZSS-compressed payload in .rdata (no .rsrc section), and carries a Microsoft Authenticode signature chain. It enumerates running processes before injection, sleeps in retry loops, and decrypts strings at runtime via small helper functions. The payload is decompressed by a documented LZSS routine (~0x140004000) and then injected into a suspended child process. Static-only analysis (CAPE skipped — no Windows guest).

What It Is

Attribute Detail
SHA-256 beb3a9d9fa738ac7ebac7dc8f5357c9a6673cfae1bc50fd73497d350afd5ed1c
Size 104 208 bytes (101.8 KB)^^[triage.json]
Format PE32+ x64, stripped to external PDB^[file.txt]
Timestamp Fri May 22 01:10:24 2026 UTC (plausible; debug directory carries fabricated 2092 date)^^[pefile.txt:34,pefile.txt:377]
Compiler MSVC C (rabin2 lang: c; linker 14.0)^^[rabin2-info.txt:18,exiftool.json:18]
Signed Authenticode PKCS#7 blob present; Microsoft root chain^[binwalk.txt:4-9,rabin2-info.txt:27]
Sections .text, .rdata, .buildid, .data, .pdata, .tls, .reloc (no .rsrc)^^[pefile.txt:78-209]
IAT profile Standard imports (KERNEL32, ntdll, ADVAPI32, SHELL32, PSAPI) — not zero-IAT/PEB-walking^[pefile.txt:268-361]
Lure Chinese-language filename masquerading as a WPS staff-reduction list (2026.05.22裁员名单及补偿方案WPS.exe)^^[metadata.json:4,triage.json:5]
Family confidence High — co-labeled silverfox + valleyrat by OpenCTI/MalwareBazaar^[metadata.json:6-12]

How It Works

  1. Entry (entry0) → calls fcn.140001020 (TLS init / zeroing) then fcn.140001030 (main orchestrator)^^[r2:entry0].
  2. String decryptionfcn.140001030 decrypts embedded API / DLL / process-name strings at runtime using helpers fcn.140004a90, fcn.140004750, and fcn.140004570 before resolving them via GetProcAddress / LoadLibraryW^[r2:fcn.140001030:0x140001097-0x1400013fa].
  3. Process enumeration gate — calls CreateToolhelp32SnapshotProcess32FirstW / Process32NextW, iterating processes and comparing image names with lstrcmpiW^[r2:fcn.140001030:0x1400010df-0x14000127c]. This is likely a sandbox / AV process check or target-process selection.
  4. Privilege escalation — resolves OpenProcessToken, LookupPrivilegeValueW, and AdjustTokenPrivileges to enable SeDebugPrivilege^[pefile.txt:339-341].
  5. Payload extraction — reads compressed bytes from .rdata (no .rsrc section in this build)^^[pefile.txt:98-115], allocates executable memory via NtAllocateVirtualMemory^[pefile.txt:322], and passes the buffer to fcn.140004000.
  6. LZSS decompressionfcn.140004000 decompresses the payload using a 12-bit offset window (0xfff mask) and variable-length match copies^[r2:fcn.140004000:0x140004078-0x140004240]. This is the same algorithm family observed in the Rust sibling ed1a0047 (see silverfox overview and lzss-payload-decompression).
  7. Injection / hollowing — creates a suspended child process (CreateProcessW)^[pefile.txt:281], writes the decompressed payload into it with NtWriteVirtualMemory^[pefile.txt:327], and resumes execution. VirtualAllocEx and WriteProcessMemory are also available in the IAT^[pefile.txt:308,310].
  8. Self-deletion — imports MoveFileExW^[pefile.txt:302]; in siblings this is used with MOVEFILE_DELAY_UNTIL_REBOOT for self-erasure.

Decompiled Behavior

entry0 (0x140001000)

Standard MSVC x64 entry prologue: aligns RSP, zeroes stack slots, then passes control to fcn.140001030. TLS directory exists but AddressOfCallBacks points to a null array — no anti-debug TLS callbacks^[r2:entry0,pefile.txt:369-371].

Main orchestrator — fcn.140001030

  • Loads ntdll.dll and kernel32.dll by decrypted name, then resolves NtAllocateVirtualMemory, NtWriteVirtualMemory, and several KERNEL32 exports via GetProcAddress^[r2:fcn.140001030:0x140001394-0x1400013fa].
  • Enumerates all processes in a loop with CreateToolhelp32Snapshot (handle = 2 → TH32CS_SNAPPROCESS) and compares executable names^[r2:fcn.140001030:0x14000110df].
  • On failure, enters a Sleep(1000) retry loop — repeated up to ~10 iterations^[r2:fcn.140001030:0x14000127c-0x140001364]. This is a time-bomb / anti-sandbox gate.
  • Allocates remote memory and writes the LZSS-decompressed payload.

LZSS decompressor — fcn.140004000

  • Accepts a source buffer, output buffer, and two size/flag arguments.
  • Reads 16-bit control tokens; extracts 12-bit offsets via 0xfff mask and multi-bit length fields^[r2:fcn.140004000:0x140004078].
  • Copies back-references from a sliding window; falls through to literal-byte copy when reference bit is clear.
  • SSE-optimized block moves for larger copies (calls fcn.140006300, an SSE memmove with 16/32/64-byte alignment branches)^^[r2:fcn.140006300].

Memory helpers

  • fcn.140006280 — simple memset-style fill (rep-style loop with bulk 8-byte stores)^^[r2:fcn.140006280].
  • fcn.140006300memmove with branches for 1-, 2-, 4-, 8-, 16-, 32-, and 64-byte alignment, using xmmword transfers for payloads ≥ 0x10 bytes^[r2:fcn.140006300].

C2 Infrastructure

None recoverable statically. The C2 configuration is embedded inside the LZSS-compressed .rdata payload and only exists in decrypted memory at runtime. CAPA was unavailable (missing signatures), and CAPE detonation was skipped due to no Windows guest. If detonated, the decoded payload would likely reveal hardcoded IPs or domains; without it, C2 is opaque.

Interesting Tidbits

  • Signed but not saintly — carries a Microsoft Authenticode chain (root + Code Signing PCA + timestamping service). Windows may render a valid signature dialog, lowering user suspicion. Whether the signature cryptographically verifies is unconfirmed (rabin2 says signed true, but does not validate hashes)^^[rabin2-info.txt:27,binwalk.txt:4].
  • No .rsrc — every prior SilverFox sibling had a .rsrc section (Rust: icons + payload; C stub e772: dual-language icons). This build strips .rsrc entirely and hides the payload in .rdata^[pefile.txt:78-115].
  • Future-dated debug directory.buildid contains an IMAGE_DEBUG_TYPE_REPRO entry stamped 2092 with zero data pointers^[pefile.txt:375-384]. Fabricated anti-forensic noise.
  • Masquerade via filename — the Chinese lure (裁员名单及补偿方案WPS.exe) targets Mandarin-speaking users, consistent with the cluster's social-engineering pattern.
  • Standard IAT — unlike the RC4 loader (139329dc9) and C stub (82d42551) which use PEB-walking or FNV-1a resolution, this sibling imports APIs normally. It relies on the signature + lure for stealth rather than heavy API obfuscation.

How To Mess With It (Homelab Replication)

  • Toolchain: MSVC 2015 (cl.exe 19.00 / link.exe 14.00) targeting x64.
  • Build flags: /O2 /GS- /Zi (optimized, no canary, program database). Strip to external PDB (/PDBSTRIPPED) to match.
  • LZSS compressor: Compress your second-stage PE/DLL with any LZSS encoder using a 4096-byte window (12-bit offset) and emit a raw byte stream. Embed the compressed blob as a byte array in .rdata.
  • Decompressor stub: Implement a decoder loop with:
    • 16-bit token read
    • offset = token & 0xfff
    • length = (token >> 12) with a small bias (e.g., length + 3)
    • Copy from out_ptr - offset into out_ptr, then fall through for literal bytes.
  • Inject payload via CreateProcessW + CREATE_SUSPENDEDNtAllocateVirtualMemoryNtWriteVirtualMemoryNtResumeThread (or ResumeThread if imported).
  • Verification: Run capa on the resulting binary — should hit allocate memory, write process memory, and create process capabilities.

Deployable Signatures

YARA

rule SilverFox_beb3a9d9_LZSS_rdata_variant {
    meta:
        description = "SilverFox C x64 variant with LZSS decompressor, no .rsrc, standard IAT"
        author = "wiki-agent"
        sha256 = "beb3a9d9fa738ac7ebac7dc8f5357c9a6673cfae1bc50fd73497d350afd5ed1c"
    strings:
        $lzss_and = { 41 81 E0 FF 0F 00 00 }           // and r8d, 0xfff — LZSS offset mask
        $lzss_shr = { C1 E8 0C }                        // shr eax, 0xc  — length extraction
        $winapi = "CreateToolhelp32Snapshot" ascii wide
        $nt_api1 = "NtAllocateVirtualMemory" ascii wide
        $nt_api2 = "NtWriteVirtualMemory" ascii wide
    condition:
        uint16(0) == 0x5A4D
        and pe.is_peplus
        and pe.number_of_sections == 7
        and not pe.section_index(".rsrc")
        and pe.timestamp >= 0x6A0FAD00
        and all of ($lzss_*)
        and 2 of ($nt_api*)
        and $winapi
}

Sigma

title: SilverFox Process Enumeration and LZSS Injection
description: Detects SilverFox process-snapshot enumeration followed by remote memory writes.
status: experimental
author: wiki-agent
logsource:
    category: process_creation
    product: windows
detection:
    selection_snapshot:
        CommandLine|contains:
            - 'CreateToolhelp32Snapshot'
    selection_inject:
        CommandLine|contains:
            - 'NtWriteVirtualMemory'
            - 'VirtualAllocEx'
    selection_lzss:
        - ImageLoaded|contains: '.rdata'
    condition: selection_snapshot and selection_inject
falsepositives:
    - Legitimate process enumeration utilities that also allocate remote memory (rare)
level: high

IOCs

Type Value Notes
SHA-256 beb3a9d9fa738ac7ebac7dc8f5357c9a6673cfae1bc50fd73497d350afd5ed1c This sample
Filename 2026.05.22裁员名单及补偿方案WPS.exe Chinese lure
Mutex / Named pipe None recovered statically Obfuscated inside LZSS payload
Registry None recovered statically Obfuscated inside LZSS payload
C2 None recovered statically Obfuscated inside LZSS payload
API sequence CreateToolhelp32SnapshotProcess32FirstWlstrcmpiWSleep(1000) loops → NtAllocateVirtualMemory + NtWriteVirtualMemory Behavioral fingerprint

Behavioral Fingerprint Statement

This binary is a 104 KB PE32+ x64 MSVC C executable with standard imports and no .rsrc section. On launch it decrypts API strings, resolves NtAllocateVirtualMemory and NtWriteVirtualMemory via GetProcAddress, enumerates all processes via CreateToolhelp32Snapshot (likely checking for AV/sandbox processes), then enters a loop of 1-second sleeps. It decompresses an embedded LZSS payload from .rdata using a 12-bit sliding-window routine, allocates executable memory, and injects the decompressed buffer into a suspended child process. It ends by scheduling self-deletion via MoveFileExW with delay-until-reboot.

Detection Signatures

ATT&CK ID Technique Evidence
T1027.002 Obfuscated Files LZSS-compressed payload in .rdata^[r2:fcn.140004000]
T1055 Process Injection NtAllocateVirtualMemory + NtWriteVirtualMemory imports^[pefile.txt:322,327]
T1055.012 Process Hollowing CreateProcessW + suspended child + remote memory write^[r2:fcn.140001030]
T1057 Process Discovery CreateToolhelp32SnapshotProcess32FirstW / Process32NextW^[r2:fcn.140001030]
T1070.004 File Deletion MoveFileExW imported^[pefile.txt:302]
T1106 Native API NtAllocateVirtualMemory, NtWriteVirtualMemory, NtFreeVirtualMemory^[pefile.txt:322,327,323]
T1134.001 Token Impersonation OpenProcessTokenLookupPrivilegeValueWAdjustTokenPrivileges^[pefile.txt:339-341]
T1497 Sandbox Evasion Sleep-loop retry logic and process enumeration before payload execution^[r2:fcn.140001030]
T1548.002 Bypass UAC ShellExecuteExW imported^[pefile.txt:351]

References

  • ed1a00479fe2ea2555882c67719abc86e98b512f122aea79adacf37355cab996 — Rust x64 sibling with .rsrc + stream cipher (see silverfox overview).
  • 82d425516199d497c3a25edc4c3ad05c14469f697230f3ad17fe03ce73cd0216 — C x64 lean stub with FNV-1a API resolution.
  • 139329dc9992e132f9c8d887ad685660161cefcfb0a18867d616a7d217a0605e — MSVC RC4 loader with zero-IAT/PEB-walking.
  • e772de930167a24868814510021d73d8c061b4d7af0946ac302e53bb1c9cba56 — Authenticode-signed C stub with Sangfor masquerade.

Provenance

Static analysis performed with:

  • file / exiftool / pefile / strings / floss / capa / binwalk (triage layer)
  • Radare2 aaa analysis + sdb type propagation
  • Ghidra queued but not yet analysed (project pending)
  • CAPE sandbox skipped — no Windows guest available
  • All claims carry provenance markers to the respective tool output files in raw/analyses/beb3a9d9fa738ac7ebac7dc8f5357c9a6673cfae1bc50fd73497d350afd5ed1c/.

Report generated 2026-06-04. Static-only (no runtime detonation). C2 IOCs not recoverable without dynamic execution or LZSS payload extraction.