typeanalysisfamilyghostpulseconfidencemediumcreated2026-08-06updated2026-08-06malware-familyloaderpeevasionc2
SHA-256: 94db5892d51fa7f24c6f406591d5cc143f48f3f9f576c66d36a8682e3950102b

ghostpulse: 94db5892 — x86 YHClient masquerade with Log.dll sidecar and cmd.exe pipe execution

Executive Summary

A 6.2 MB 7-Zip SFX archive that silently extracts an x86 MSVC C++ payload (FrameworSwitch32.exe) to %TEMP% and executes it. The inner PE masquerades as a "YHClient" product with PDB paths referencing D:\slave\workspace\YHClient\Release\startbc.pdb. It is bundled with a custom Log.dll helper, legitimate MSVC redistributables, a 6 MB high-entropy encrypted sidecar (monitor.sym), and a 34 KB config file (sampler.xml). Notably, this sample diverges from prior GhostPulse siblings by using an x86 (not x64/Qt5) inner payload and introducing a cmd.exe pipe-execution pattern not observed in the Qt5 cluster. No CAPE detonation available (no Windows guest); all behavior inferred from static extraction and decompilation.

What It Is

  • Outer container: 7-Zip SFX stub (7ZSfxMod_x86.exe, Oleg Scherbakov, 2010), MSVC linker v8.0, compiled 2010-06-27 ^[exiftool.json] ^[pefile.txt]
  • Archive: LZMA-compressed 7z solid archive at offset 0x2df4f; 6 files extracted to %TEMP% ^[binwalk.txt] ^[sfx-config.json]
  • Inner payload: FrameworSwitch32.exe — PE32 x86, MSVC 14.x (VS 2019+), timestamp 0x6790d7cb (2025-01-22), 6 sections, no Authenticode ^[file.txt] ^[rabin2-info.txt]
  • PDB path: D:\slave\workspace\YHClient\Release\startbc.pdb — masquerades as a "YHClient" product build ^[rabin2-info.txt] ^[r2:str.startbc.pdb]
  • Helper DLL: Log.dll — PE32 x86, same toolchain/timestamp as inner payload, exports GenericLogImpl, LogSetOption, LogSetOutputLevel ^[file.txt]
  • Sidecar files: monitor.sym (5.98 MB, entropy 7.95, near-random — encrypted payload) and sampler.xml (34 KB, entropy 5.35 — likely config/key) ^[terminal:entropy-check]
  • Legitimate libraries: msvcp_win.dll and ucrtbase.dll — standard MSVC 2019+ redistributables

How It Works

Stage 1 — SFX Extraction

The outer binary is a legitimate 7-Zip SFX mod configured to silently extract (Progress=no, GUIFlags=8) to %TEMP% and immediately run "%%T\\FrameworSwitch32.exe". ^[sfx-config.json] The 7z archive contains the inner payload, the Log.dll helper, MSVC runtime libraries, and two attacker-controlled sidecar files.

Stage 2 — Payload Execution (FrameworSwitch32.exe)

main() at 0x004058b0 performs the following control flow: ^[r2:main]

  1. Clean-Edashi gate: Tests bit 0x4000 at 0x43394c. If set, logs "Execute Clean Edashi finished!" via log.dll_GenericLogImpl and exits. This is a conditional abort path, possibly environment-gated.
  2. Single-instance mutex: Opens mutex {FA531CC1-0497-11d3-A180-00105A276C3E} with SYNCHRONIZE rights. If the mutex exists, the process finds a window via FindWindowW and sends WM_USER+0x4a (0x4a = 74) with lParam pointing to a 1307-byte (0x51b) payload — likely inter-process communication to an already-running instance. ^[r2:main]
  3. Path construction: Builds a wide-char path to BarClientView.exe in the same directory. ^[r2:main:0x00405986]
  4. File-existence check: Calls PathFileExistsW on the constructed path. ^[r2:main:0x004059dd]
  5. Launch: If the file exists, calls ShellExecuteW("open", ...) to launch it. If not, logs "path not exists.%s". ^[r2:main:0x00405a0f]

Stage 3 — Encrypted Sidecar Loading

monitor.sym (5.98 MB, entropy 7.95) is strongly consistent with encrypted payload data. sampler.xml (34 KB, entropy 5.35) is lower-entropy, consistent with a configuration or decryption-key file. Neither filename appears as a plaintext string in FrameworSwitch32.exe, suggesting the sidecar names may be hardcoded in .data or resolved dynamically. The Log.dll helper provides structured logging, indicating the authors care about operational telemetry.

Stage 4 — cmd.exe Pipe Execution (fcn.004026c0)

A distinct function at 0x004026c0 (2,492 bytes) creates anonymous pipes via CreatePipe, builds a STARTUPINFO with redirected std handles, and spawns cmd.exe. ^[r2:fcn.004026c0] This pattern is consistent with a reverse-shell or command-execution backdoor capability. It is not invoked from the main() flow visible in the disassembly, suggesting it may be triggered by:

  • A command received from the decrypted monitor.sym payload
  • An IPC message sent by a companion process (e.g., BarClientView.exe)
  • A callback from Log.dll under specific conditions

Decompiled Behavior

Notable Functions

Address Size Description
main (0x004058b0) 528 Entry logic: Clean-Edashi gate → mutex check → BarClientView.exe launch
fcn.004026c0 2,492 Pipe creation + cmd.exe spawn with redirected I/O
fcn.004063a0 3,619 Window message handler; sends WM_USER+0x4a with 1307-byte payload to existing window
fcn.00405340 1,386 Path/string construction helper
fcn.00405ac0 897 Early initialization called before gate check

Key Imports and Their Roles

  • KERNEL32.dll: CreatePipe, PeekNamedPipe, CreateProcessW — pipe-based command execution ^[r2:fcn.004026c0]
  • USER32.dll: FindWindowW, SendMessageW, PostMessageW — IPC to existing instance ^[r2:main]
  • SHELL32.dll: ShellExecuteW — launch BarClientView.exe ^[r2:main]
  • SHLWAPI.dll: PathFileExistsW — file-existence gate ^[r2:main]
  • log.dll: GenericLogImpl — structured logging telemetry ^[r2:main:0x004058fb]

Resource Section

The .rsrc section (586 KB, entropy 3.79) contains 17 RT_ICON groups, RT_GROUP_ICON, RT_VERSIONINFO, and RT_MANIFEST resources. ^[pefile.txt] The VS_VERSIONINFO reports:

  • ProductName: startbc
  • FileVersion: 1.0
  • InternalName: startbc
  • OriginalFilename: startbc.exe This masquerades as a benign "startbc" application.

C2 Infrastructure

No static C2 indicators recovered. No hardcoded URLs, IPs, domains, or mutex names (beyond the single-instance GUID) appear in plaintext. Network connectivity, if any, is expected to be:

  1. Encrypted inside monitor.sym and decrypted at runtime
  2. Communicated via a companion process (BarClientView.exe)
  3. Or relayed through the Log.dll telemetry channel

The BarClientLocatePassport export name in the strings hints at a "locate passport" function — possibly a geo-location or system-fingerprinting module that would beacon to a C2 server.

Interesting Tidbits

  1. Divergent build morph: Unlike all prior GhostPulse siblings (x64 Qt5 payloads with EaseUS masquerade), this sample is x86 MSVC C++ with a completely different masquerade identity ("YHClient" / "startbc"). The outer SFX packaging pattern is the only family fingerprint shared. ^[entities/ghostpulse.md]

  2. "YHClient" attribution clue: PDB paths reference D:\slave\workspace\YHClient\.... "YH" is a common Chinese abbreviation (银河 Yínhé, 银汉 Yínhàn). The "slave" directory name suggests a CI/CD build server or Jenkins-like environment.

  3. "Clean Edashi" gate: The conditional abort string "Execute Clean Edashi finished!" uses a Japanese given name (江戸橋 Edashi / 枝 Edashi). This may be a developer artefact, a code-name for an uninstall/cleanup routine, or an anti-analysis breadcrumb.

  4. Virtual disk bus driver reference: Source path ControlvDiskBus.cpp in the strings suggests the payload or a companion module includes virtual-disk or storage-filter-driver functionality — potentially used for hiding files or maintaining persistence.

  5. Multilingual UI support: 31 locale strings (zh-CHS, ar-SA, de-DE, en-US, fr-FR, ja-JP, ko-KR, ru-RU, etc.) in the .rsrc section indicate international deployment or a product built for global distribution. ^[r2:rabin2-z]

  6. Log.dll operational telemetry: The helper DLL exports LogSetOutputLevel and LogSetOption, suggesting configurable log verbosity and output redirection — unusual for commodity malware and more consistent with a managed tool or RAT.

How To Mess With It (Homelab Replication)

Reproducing the dropper pattern:

  1. Build a small MSVC C++ Win32 GUI app (VS 2019+, x86) that checks a mutex, then launches a hardcoded companion EXE via ShellExecuteW
  2. Add an IPC path: FindWindowW + SendMessageW(WM_USER+0x4a, ...) for single-instance coordination
  3. Include a conditional abort gate that logs and exits (mimic "Clean Edashi")
  4. Build a helper DLL with GenericLogImpl export and structured logging
  5. Package with 7-Zip SFX (7zSfxMod) with RunProgram="%%T\\YourApp.exe" and Progress=no
  6. Bundle a large encrypted sidecar file with >7.5 entropy alongside a smaller config file

Detection target for your own VMs: The resulting binary will have:

  • A 7-Zip SFX outer stub with RunProgram config
  • An inner x86 PE importing a custom log.dll
  • A .rsrc section with 17+ icons and multilingual locale tables
  • Companion files with >7.5 entropy and non-standard extensions (.sym, .xml)

Deployable Signatures

YARA Rule — GhostPulse SFX Loader (x86 YHClient Morph)

rule GhostPulse_SFX_YHClient_x86 {
    meta:
        description = "Detects GhostPulse family 7-Zip SFX dropper with x86 YHClient inner payload"
        author = "PacketPursuit"
        date = "2026-08-06"
        sha256 = "94db5892d51fa7f24c6f406591d5cc143f48f3f9f576c66d36a8682e3950102b"
    strings:
        $sfx1 = "7ZSfxMod" ascii
        $sfx2 = "7-Zip SFX" wide
        $runprog = /RunProgram="\\%%T\\\\[A-Za-z]{5,30}\.exe"/ wide
        $yhclient = "YHClient" ascii
        $startbc = "startbc.pdb" ascii
        $logdll = "log.dll" ascii
        $monitor = ".monitor.sym" ascii
        $barclient = "BarClientView.exe" ascii
        $passport = "BarClientLocatePassport" ascii
        $mutex = "{FA531CC1-0497-11d3-A180-00105A276C3E}" ascii
    condition:
        uint16(0) == 0x5A4D and
        filesize > 3MB and filesize < 15MB and
        ($sfx1 or $sfx2) and
        $runprog and
        (any of ($yhclient, $startbc, $logdll, $monitor, $barclient, $passport, $mutex))
}

YARA Rule — FrameworSwitch32 Inner Payload

rule GhostPulse_YHClient_Inner {
    meta:
        description = "Detects GhostPulse x86 inner payload with YHClient masquerade"
        author = "PacketPursuit"
        date = "2026-08-06"
        sha256 = "94db5892d51fa7f24c6f406591d5cc143f48f3f9f576c66d36a8682e3950102b"
    strings:
        $pdb = "D:\\slave\\workspace\\YHClient\\Release\\startbc.pdb" ascii
        $src1 = "D:\\slave\\workspace\\YHClient\\startbc\\startbc.cpp" ascii
        $src2 = "D:\\slave\\workspace\\YHClient\\startbc\\SecPolicy.cpp" ascii
        $src3 = "D:\\slave\\workspace\\YHClient\\CommFile\\driver\\ControlvDiskBus.cpp" ascii
        $passport = "BarClientLocatePassport" ascii
        $device = "\\\\.\\ControlDevice" ascii
        $clean = "Execute Clean Edashi finished!" ascii
        $log = "GenericLogImpl" ascii
    condition:
        uint16(0) == 0x5A4D and
        pe.machine == pe.MACHINE_I386 and
        3 of them
}

Behavioral Hunt Query (Sigma)

title: GhostPulse YHClient x86 Payload Execution
description: Detects the execution of GhostPulse inner payload FrameworSwitch32.exe or its BarClientView.exe companion
logsource:
  category: process_creation
  product: windows
detection:
  selection:
    CommandLine|contains:
      - 'FrameworSwitch32.exe'
      - 'BarClientView.exe'
  selection_mutex:
    - MutexName|contains: '{FA531CC1-0497-11d3-A180-00105A276C3E}'
  selection_pipe:
    ParentImage|endswith:
      - 'FrameworSwitch32.exe'
    Image|endswith:
      - 'cmd.exe'
    CommandLine|contains: 'cmd.exe'
  condition: selection or selection_mutex or selection_pipe
falsepositives:
  - Unknown
level: high

IOC List

Indicator Type Value
SHA-256 Hash 94db5892d51fa7f24c6f406591d5cc143f48f3f9f576c66d36a8682e3950102b
Inner payload SHA-256 Hash (requires extraction from SFX)
Mutex Mutex {FA531CC1-0497-11d3-A180-00105A276C3E}
Sidecar payload File %TEMP%\monitor.sym (5.98 MB, entropy ~7.95)
Sidecar config File %TEMP%\sampler.xml (34 KB, entropy ~5.35)
Inner executable File %TEMP%\FrameworSwitch32.exe
Companion executable File %TEMP%\BarClientView.exe (launched by inner payload)
Helper DLL File %TEMP%\Log.dll
Device path String \\.\ControlDevice
Build path String D:\slave\workspace\YHClient\Release\startbc.pdb

Behavioral Fingerprint Statement

This binary is a 7-Zip SFX archive that silently extracts to %TEMP% and launches FrameworSwitch32.exe. The inner x86 PE checks a single-instance mutex ({FA531CC1-0497-11d3-A180-00105A276C3E}); if already running, it finds the existing window and sends WM_USER+0x4a with a 1307-byte payload. Otherwise it constructs a path to BarClientView.exe, verifies existence via PathFileExistsW, and launches it via ShellExecuteW. A secondary function creates anonymous pipes and spawns cmd.exe with redirected I/O, suggesting reverse-shell capability. The payload carries a custom Log.dll helper for structured telemetry and is accompanied by a 6 MB encrypted sidecar (monitor.sym) and a 34 KB config file (sampler.xml). Build artefacts reference a Chinese-origin "YHClient" product with virtual-disk driver components.

Detection Signatures

Technique ATT&CK ID Evidence
Single-instance mutex gating T1497.001 OpenMutexW("{FA531CC1-0497-11d3-A180-00105A276C3E}") ^[r2:main]
Windows Command Shell T1059.003 CreatePipe → CreateProcessW("cmd.exe") ^[r2:fcn.004026c0]
Shared Modules T1129 log.dll imported at runtime ^[pefile.txt]
Signed Binary Proxy Execution T1218.011 ShellExecuteW("open", "BarClientView.exe") ^[r2:main]
Ingress Tool Transfer T1105 Sidecar files (monitor.sym, sampler.xml) extracted via SFX ^[sfx-config.json]
File and Directory Discovery T1083 PathFileExistsW on companion EXE ^[r2:main]
Virtualization/Sandbox Evasion T1497 Conditional abort gate (bit 0x4000) ^[r2:main]
Process Injection (inferred) T1055 Pipe-based cmd.exe spawn capability ^[r2:fcn.004026c0]

References

  • ghostpulse — Family entity page with full cluster description
  • 833bffd0 — Prior GhostPulse analysis (x64 Qt5 EaseUS masquerade variant) ^[/intel/analyses/833bffd0ff2291001e0cb62f529cf947ba2753fa5888820848a2014eda2dc334.html]
  • 943cf1eb — Confirmed twin of 833bffd0 ^[/intel/analyses/943cf1ebeb089abcd2e6ff0c2bfefa4631855948ab3ef3811cba1c635aa389d1.html]

Provenance

  • File type: file v5.44 — PE32 executable (GUI) Intel 80386, for MS Windows, 4 sections ^[file.txt]
  • PE headers: pefile 2023.2.0 — full DOS/NT/optional headers, section entropy, import table ^[pefile.txt]
  • Strings: strings v2.42 — 11,290 strings recovered ^[strings.txt]
  • FLOSS: Failed (CLI argument error) ^[floss.txt]
  • capa: Failed (missing signatures directory) ^[capa.txt]
  • binwalk: 7-zip archive data at offset 0x2DF4F ^[binwalk.txt]
  • radare2: r2 v5.9.4 — rabin2 -I, rabin2 -z, r2 -A disassembly of main, fcn.004026c0, fcn.004063a0 ^[rabin2-info.txt] ^[r2:*]
  • 7-Zip extraction: 7-Zip 23.01 — 6 files extracted from offset 188,239 ^[terminal:7z-extract]
  • Entropy analysis: Custom Python using math.log2 and collections.Counter ^[terminal:entropy-check]