familyphorpiexconfidencemedium-highcreated2026-06-15
SHA-256: 45d0464a55298987781c2e1d4327aa2ce1ab77ad7ca9f58d85322f1e77a64966

Phorpiex x64 CPlApplet PNG Payload Dropper

Summary

A 64-bit PE32+ (x64) Control Panel Applet (CPlApplet) acting as a two-stage dropper. It masquerades as a Windows screensaver (v6.scr) and searches its working directory for a companion file named payload.png. The "PNG" is a custom container: standard PNG signature and chunk types (IDAT, IEND) are parsed, but the data is decrypted via a custom XOR loop, then decompressed with a custom byte-pair algorithm, and written to disk as kernelbase.dll. The dropper then executes kernelbase.dll via CreateProcessA, after zeroing its own .text section. Heavy anti-debug/sandbox checks and API hashing for dynamic resolution are present ^[ghidra:FUN_140004cf0], ^[ghidra:FUN_140001740].

Build / RE

Toolchain & PE Structure

  • Compiler: MSVC 14 (Visual Studio 2015+), C++ x64 ^[pefile.txt:33,34], ^[rabin2-info.txt:5,11]
  • Binary Type: PE32+ (AMD64), 10 sections, standard MSVC layout ^[pefile.txt:78-275]
  • Compile Timestamp: Thu May 21 11:06:01 2026 UTC ^[pefile.txt:34], ^[rabin2-info.txt:11]
  • Linker Version: 2.45 ^[pefile.txt:45,46]
  • Subsystem: Windows GUI (0x2) ^[pefile.txt:65]
  • Characteristics: Large Address Aware, NX compatible, Dynamic Base, High Entropy VA ^[pefile.txt:39,67]
  • Stripped: Yes ^[rabin2-info.txt:30]

Packing & Obfuscation

  • Packing: None. Natural section entropy (6.17 for .text, ~5.2 for .rdata) ^[pefile.txt:91,131]. No UPX, no .NET, no resource compression.
  • Overlay: No extra overlay ^[binwalk.txt]. Entire logic is in .text and .rdata.

Anti-Analysis

  • Dynamic API Resolution: IAT contains only KERNEL32 and GDI32 base functions ^[pefile.txt:346-392]. Runtime resolution uses decrypted string names XORed byte-by-byte against constants in .rdata, then resolved via GetProcAddress ^[ghidra:FUN_140001a60].
  • API Hashing: Routine at 0x1400022d0 hashes decrypted API names before resolution ^[ghidra:FUN_1400022d0], avoiding plaintext strings in imports.
  • Debugger / Sandbox Checks:
    • IsDebuggerPresent via direct GS:[0x60] PEB read and BeingDebugged byte check ^[ghidra:FUN_140004cf0:0x140004d40].
    • Memory size anomalies (NtGlobalFlag, heap flags) checked via PEB/heap structures ^[ghidra:FUN_140004cf0].
    • Anti-emulation: GetTickCount called in pairs; if delta < 3000 ms, enters tight busy loop (do {} while (i < 10000)) that burns CPU before proceeding ^[ghidra:FUN_140001740].
    • Loaded DLL checks by enumerating PEB LDR list for sandbox module hashes (e.g., sandboxie.dll, snxhk.dll, api_log.dll) ^[ghidra:FUN_140004cf0].
  • Self-Erasure: Before launching the payload, the sample resolves the base address of its own image and overwrites the .text section with zeros via memset ^[ghidra:FUN_140003c3c].

Notable Functions

  • CPlApplet (export 0x140004cf0): Entry point for the Control Panel Applet. Sets up anti-debug checks, then calls the main orchestrator ^[ghidra:FUN_140004cf0], ^[pefile.txt:344].
  • FUN_140002fd0 (0x140002fd0): Main orchestrator. Opens payload.png, parses PNG header and chunks, decrypts IDAT data with XOR loop, decompresses via custom algorithm (calls helper at 0x140002620), allocates memory, then launches the decrypted second-stage PE via process creation ^[ghidra:FUN_140002fd0].
  • FUN_140001f60: Anti-emulation tick-count delay loop. Calls GetTickCount three times and burns CPU in a do {} while (i < 10000) loop until a dynamically-calculated delay expires ^[ghidra:FUN_140001f60].
  • FUN_140001ff0: API resolver / export hasher. Walks the PE export table of kernel32.dll, hashes each export name with hash = hash * 0x21 ^ byte ^ 0x5a5a5a5a, and returns the VirtualAddr of the matching export. Used for all dynamic API resolution ^[ghidra:FUN_140001ff0].
  • FUN_140002620: Custom byte-pair / Huffman-like decompression engine. Called by the main orchestrator on the decrypted PNG data to produce the second-stage PE ^[ghidra:FUN_140002620].

Embedded Strings of Interest

  • "ScrPrev" — Window class name for screensaver preview window ^[strings.txt:41]
  • "payload.png" — Hardcoded companion payload filename ^[strings.txt:42]
  • "v6.scr" — Likely intended filename / version for screensaver masquerade ^[strings.txt:85]
  • "kernel32.dll" — Referenced during dynamic resolution ^[strings.txt:40]
  • "VirtualProtect failed with code 0x%x" — Debug/error string ^[strings.txt:79]
  • Lengthy decoy "WindowsScreenSaverConfigurationSettingsVersion1..." — High-entropy configuration-like string, likely decoy / social-engineering text ^[strings.txt:65]

Deploy / ATT&CK

TTP Mapping

  • T1204.002 — User Execution: Malicious File — Delivered as a .scr file, launched via user double-click or Control Panel Applet interface ^[dynamic-analysis.md: skipped — static inference].
  • T1027.002 — Obfuscated Files or Information: Software Packing — Custom PNG chunk container with XOR encryption and custom byte-pair decompression to hide the second-stage payload ^[ghidra:FUN_140001740].
  • T1055 — Process Injection — Writes kernelbase.dll to disk and executes it via CreateProcessA ^[ghidra:FUN_140003c3c].
  • T1070.004 — Indicator Removal: File Deletion — Likely deletes payload.png after reading (inferred from one-shot read logic) ^[ghidra:FUN_140001740].
  • T1497.001 — Virtualization/Sandbox Evasion: System Checks — Multi-layered debugger, tickcount, and loaded-DLL checks ^[ghidra:FUN_140004cf0].
  • T1622 — Debugger EvasionIsDebuggerPresent, PEB checks, tickcount loops ^[ghidra:FUN_140004cf0].
  • T1564.001 — Hide Artifacts: Hidden Files and Directories — Writes the payload to kernelbase.dll, a name resembling a core system library, to blend in ^[ghidra:FUN_140003c3c].

Persistence

  • None observed in this stage. Persistence is likely handled by the dropped kernelbase.dll payload.

C2 & Network Indicators

  • None in this stage. No network APIs (WinInet, WS2_32, URLDownloadToFile) are imported or resolved. The next stage (kernelbase.dll) would need to be analysed separately.

Attribution & Family

  • Phorpiex-aligned. The screensaver masquerade, CPlApplet export, minimal IAT with dynamic API hashing, and XOR-decrypted string patterns are consistent with the Phorpiex family cluster documented in the corpus ^[entities/phorpiex.md].
  • Distinct Build. This is a 64-bit MSVC 14 build from May 2026, whereas previous Phorpiex reports documented 32-bit MSVCR90 builds from 2018 and 2025 ^[raw/analyses/755bed07.../report.md, raw/analyses/17960bcb.../report.md]. The code has been rewritten for x64: no MSVCR90 dependency, uses api-ms-win-crt-* UCRT shim DLLs ^[pefile.txt:403-481].
  • Unique String lako — Not found in any other corpus sample; likely a new campaign/build marker ^[terminal: grep corpus].

Static vs Dynamic

  • Dynamic analysis was skipped (no CAPE Windows machine available at the time of detonation) ^[dynamic-analysis.md]. The companion file payload.png was also not present in the sample directory, so even with dynamic execution, the second stage would likely not fire without its companion file.

Recommendations

  • Hunt for payload.png in the same directory as any .scr or CPlApplet bearing this hash.
  • Hunt for kernelbase.dll written to user-writable directories (AppData, Temp, Desktop) — especially when the parent process is a screensaver or Control Panel Applet.
  • Monitor for CreateProcessA launching kernelbase.dll from unusual paths.
  • YARA/Detection: The anti-debug loop GetTickCount -> delta < 3000 -> 10000 iterations is a unique timing signature. The XOR decryption routine at 0x140001a60 uses a fixed 0x80-byte key from .rdata that can be targeted.