typeanalysisfamilysilverfoxconfidencehighcreated2026-09-07updated2026-09-07pemalware-familyloaderdefense-evasionc2evasionobfuscationsigning
SHA-256: 88f7d22ed2494fb53d1806011173dd739f77bda9ff8d20f130b4bc5fdde761d7

silverfox: 88f7d22e — Bkav masquerade C stub, builder-morphed sibling of b37efcbc

Executive Summary

A 54 KB PE32+ x64 C stub from the SilverFox cluster, compiled May 28 2026 with an anachronistic MSVC 6.0 linker. It is byte-for-byte identical in build fingerprint to sibling b37efcbc (same XOR key, same timestamp, same stream-cipher constants) but carries a Bkav Corporation VersionInfo masquerade instead of the WPS Office lure seen in the earlier sample. This confirms builder-level morphing of metadata while the payload core remains static. Static-only analysis; no CAPE Windows guest available.^[dynamic-analysis.md]

What It Is

Attribute Detail
SHA-256 88f7d22ed2494fb53d1806011173dd739f77bda9ff8d20f130b4bc5fdde761d7
Size 54 272 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 2026.05.28裁员名单及补偿方案WPS.exe (Chinese staff list + severance compensation lure, WPS Office masquerade)^[triage.json:5]
VersionInfo Bkav Corporation / Bkav Restore Service / BkavRestoreService.exe / BkavPro / 3.0.0.23^[exiftool.json:36-43]^[pefile.txt:261-268]

Build / RE

  • No packing or compression. No UPX, no LZSS, no RC4 engine, no custom stream-cipher payload block. The .rsrc section contains only standard dialog/string/icon resources (RT_DIALOG, RT_STRING, RT_ICON) with a benign BkavRestoreService string table.^[pefile.txt:390-500]
  • XOR-thunk API dispatch. Every API call is indirected through a single QWORD key 0x578d9d6102d087e9 stored at .data:0x408000. Twelve encrypted function pointers live in .data at VA 0x409a98, each decrypted at runtime via XOR against a rotating key from the .data key table.^[terminal:python .data analysis]^[r2:fcn.0040100d]
  • No FNV-1a resolver. Unlike the 50 KB sibling 82d425516199, this stub drops the FNV-1a hash→name→address chain entirely. The key is a single QWORD, simplifying reversal.^[r2:fcn.0040100d]
  • Standard IAT. Full visible import table from KERNEL32, ADVAPI32, SHELL32, PSAPI, and msvcrt — no PEB-walking, no zero-IAT obfuscation.^[pefile.txt:281-388]^[r2:list_imports]
  • Three of four SilverFox stream-cipher constants present: 0xcaaafe23, 0x3d57aa23, 0x44d9bb23. The fourth (0x9e37cb23) is absent, matching the pattern seen in b37efcbc and aa029dcb.^[terminal:python search]
  • Process hollowing imports. CreateProcessW, VirtualAllocEx, WriteProcessMemory, GetModuleInformation are all statically imported, strongly suggesting suspended-child injection.^[pefile.txt:323-353]

Deploy / ATT&CK

ATT&CK ID Technique Evidence
T1055 Process Injection Static imports VirtualAllocEx, WriteProcessMemory, CreateProcessW^[pefile.txt:323-353]
T1055.012 Process Hollowing GetModuleInformation + hollowing API cluster present^[pefile.txt:353]
T1497.001 Sandbox Evasion __argc <= 1 gate at entry0; clean exit if no arguments^[r2:entry0]
T1070.004 File Deletion MoveFileExW imported^[pefile.txt:351]
T1106 Native API OpenProcessToken, LookupPrivilegeValueA, AdjustTokenPrivileges for privilege escalation^[pefile.txt:367-368]
T1562.001 Impair Defenses ShellExecuteExW fallback for UAC bypass or elevated execution^[pefile.txt:378]
  • Privilege escalation path: OpenProcessToken → LookupPrivilegeValueA → AdjustTokenPrivileges suggests SeDebugPrivilege or similar token escalation before injection.^[pefile.txt:367-368]
  • Self-deletion: MoveFileExW (with MOVEFILE_DELAY_UNTIL_REBOOT) is the likely cleanup mechanism, consistent with all SilverFox C stubs.^[pefile.txt:351]
  • No C2 recoverable statically. No hardcoded IPs, domains, URLs, or mutex names. The payload is likely fetched at runtime (network pull) or delivered via a companion file — neither mechanism is visible in static strings.^[strings.txt]^[floss.txt]

Decompiled Behavior

The entry point (entry0 at 0x00405fb4) is a minimal MSVC CRT wrapper:^[r2:entry0]

  1. Calls GetStartupInfoA, GetCommandLineA, __getmainargs to initialise the CRT.
  2. Reads __argc. If argc <= 1, exits cleanly — this is the sandbox gate.^[r2:entry0]
  3. Calls fcn.00405e59, the main orchestrator.

fcn.00405e59 (347 bytes) does the heavy lifting:^[r2:fcn.00405e59]

  • Copies the command line via _strdup.
  • Walks a table of encrypted function pointers at .data:0x409a98 (12 entries).
  • Each pointer is decrypted at call time by XOR against a rotating key from the .data:0x408000 key table.
  • The decrypted pointers resolve to small thunks in the 0x406130–0x406158 range (msvcrt wrappers) and to fcn.004054b4 (a 2-byte forwarder).

fcn.0040100d (233 bytes) demonstrates the thunk pattern in Ghidra-decompiled form:^[r2:fcn.0040100d]

  • Loads encrypted pointer 0x578d9d610290e6d9 from .data:0x409a98.
  • XORs it against the key at .data:0x408000 (0x578d9d6102d087e9).
  • Result: 0x406130 — a memset wrapper thunk.
  • Calls the decrypted address via call r11.

No anti-debug checks, no VM detection, no PEB-walking. The entire anti-analysis budget is the __argc gate and the XOR-thunk indirection.

C2 Infrastructure

Not recoverable from static analysis. No network indicators in strings, floss, or decompiled code. The payload delivery mechanism is external to this binary.^[strings.txt]^[floss.txt]

Interesting Tidbits

  • Builder-level morphing confirmed. This sample shares the exact same XOR key, timestamp, linker fingerprint, and code layout as b37efcbc. The only material difference is the VersionInfo block (Bkav vs WPS Office). This is a builder that swaps metadata per campaign while reusing the same payload stub.^[exiftool.json:36-43] ^[entities/silverfox.md]
  • Bkav is a legitimate Vietnamese AV vendor. Masquerading as Bkav Restore Service is a geographic pivot — previous siblings used Chinese company names (Sangfor, WPS). The actor may be A/B testing lure credibility across regions.^[exiftool.json:36-43]
  • Identical .rsrc timestamp anomaly. The resource directory carries a secondary timestamp Thu May 28 18:36:23 2026 UTC, roughly 18 hours after the PE header timestamp. This suggests the resources were added or modified in a separate build step after compilation.^[pefile.txt:394]
  • MSVC 6.0 linker in 2026. Still observed in this cluster. Either a deliberate artifact from a legacy build VM or a fabricated linker version to evade heuristic detection.^[pefile.txt:45-46]

How To Mess With It (Homelab Replication)

  1. Build a minimal PE32+ x64 C program with MSVC 6.0 or an equivalent toolchain (e.g., mingw-w64 with /link /version:6.0).
  2. Implement a single-QWORD XOR-thunk dispatcher:
    • Store a key K in .data.
    • Build an encrypted pointer table where each entry E[i] = target_i ^ K[i % N].
    • At runtime, decrypt via target = E[i] ^ K[i % N] and call target.
  3. Add an __argc gate at main() — if (argc <= 1) return 0;.
  4. Import CreateProcessW, VirtualAllocEx, WriteProcessMemory, MoveFileExW, and OpenProcessToken.
  5. Compile stripped (/strip or sstrip).
  6. Verify with capa (once signatures are installed) — the import cluster alone should flag process hollowing and token manipulation.

What you'll learn: how a 55 KB stub with trivial static obfuscation still achieves meaningful defense evasion through API indirection and argument gating.

Deployable Signatures

YARA

rule SilverFox_XOR_Thunk_Bkav_Masquerade {
    meta:
        description = "SilverFox C-stub variant with XOR-thunk API dispatch and Bkav VersionInfo"
        author      = "PacketPursuit"
        date        = "2026-09-07"
        sha256      = "88f7d22ed2494fb53d1806011173dd739f77bda9ff8d20f130b4bc5fdde761d7"
        family      = "silverfox"
    strings:
        $bkav1 = "Bkav Corporation" wide ascii
        $bkav2 = "Bkav Restore Service" wide ascii
        $bkav3 = "BkavRestoreService.exe" wide ascii
        $bkav4 = "BkavPro" wide ascii
        $key1  = { e9 87 d0 02 61 9d 8d 57 }  // XOR key at .data start (little-endian)
        $const1 = { 23 fe aa ca }
        $const2 = { 23 aa 57 3d }
        $const3 = { 23 bb d9 44 }
    condition:
        uint16(0) == 0x5A4D and
        filesize < 60KB and
        (2 of ($bkav*) or 1 of ($key*)) and
        2 of ($const*)
}

Sigma (Process Creation)

title: SilverFox C Stub Process Hollowing
description: Detects SilverFox XOR-thunk variant process hollowing pattern
logsource:
    category: process_creation
    product: windows
detection:
    selection:
        Image|contains:
            - 'BkavRestoreService'
            - 'BkavPro'
        CommandLine|re:
            - '.*裁员.*'
            - '.*WPS\.exe'
    susp_api:
        - LoadedImageName|contains: 'CreateProcessW'
        - LoadedImageName|contains: 'VirtualAllocEx'
        - LoadedImageName|contains: 'WriteProcessMemory'
    condition: selection and susp_api
falsepositives:
    - None expected (BkavRestoreService.exe with Chinese severance filename is not legitimate)
level: high

IOCs

Type Value Notes
SHA-256 88f7d22ed2494fb53d1806011173dd739f77bda9ff8d20f130b4bc5fdde761d7
SHA-1 219cc80b6eab57e8002309f7c0fa335971f31a02 .text section^[pefile.txt:94]
MD5 598fa2c46575c6a4a467d691577a0816 .text section^[pefile.txt:92]
Filename 2026.05.28裁员名单及补偿方案WPS.exe Chinese severance lure^[triage.json:5]
InternalName BkavRestoreService.exe VersionInfo^[exiftool.json:39]
ProductName BkavPro VersionInfo^[exiftool.json:42]
CompanyName Bkav Corporation VersionInfo^[exiftool.json:36]
XOR Key 0x578d9d6102d087e9 .data:0x408000^[terminal:python .data analysis]
Stream constants 0xcaaafe23, 0x3d57aa23, 0x44d9bb23 .text embedded^[terminal:python search]

Behavioral Fingerprint

This binary is a 54–56 KB PE32+ x64 C stub compiled with an anachronistic MSVC 6.0 linker. It imports CreateProcessW, VirtualAllocEx, WriteProcessMemory, and MoveFileExW via a standard IAT, then indirects all API calls through a single QWORD XOR key stored in .data. At launch it checks __argc; if no arguments are present it exits cleanly. The VersionInfo masquerades as Bkav Restore Service by Bkav Corporation. Three SilverFox stream-cipher constants are embedded in .text. No payload is embedded statically — the stub expects an external delivery mechanism.

Detection Signatures

  • CAPE skipped — no dynamic signature hits available.^[dynamic-analysis.md]
  • Static import cluster (CreateProcessW + VirtualAllocEx + WriteProcessMemory + MoveFileExW + OpenProcessToken) is a reliable hunt pivot for this stub family.^[pefile.txt:318-388]

References

  • Artifact ID: 66be54cf-2563-4c56-80d3-d30e795dd87f
  • OpenCTI labels: silverfox, valleyrat, trojan/silverfox.bg[qtsc]^[triage.json]
  • Related wiki: silverfox
  • Confirmed sibling: b37efcbc178c9f8d2c4059e55311279a435ff5cd9b00840ec17ef0f7110b106c — same XOR key, same timestamp, WPS masquerade^[entities/silverfox.md]
  • Confirmed sibling: aa029dcb4bdff2ac1e34c4829c774146dcf494f890fb2aefa08f4998321d9e2c — same XOR key, same constants, EwpiLOH masquerade^[entities/silverfox.md]

Provenance

  • file.txt — file v5.45
  • pefile.txt — pefile Python library
  • rabin2-info.txt — radare2 v5.x
  • strings.txt — strings from GNU binutils
  • exiftool.json — ExifTool v12.76
  • capa.txt — capa v9 (failed: missing signatures)
  • floss.txt — flare-floss v3.1 (failed: CLI arg parsing)
  • dynamic-analysis.md — CAPEv2 (skipped: no Windows guest)
  • radare2 static analysis with aaa + pdc — 248 functions recovered, level 3 analysis
  • Python 3.12 byte-level inspection for XOR key recovery and constant search