Malware identities / source figures
Samples and source figures
Hashes for the analyzed files, followed by the screenshots used throughout the article.
Sample hashes
| Sample or object | SHA-256 |
|---|---|
| Campaign ZIP 248,759 bytes | 7108FF29916D064216AA2ECE7FB395F1E3A73D12D19895BFFC0BD46806CBF85A |
| Staged IMG 641,024 bytes | 38EC1F5E23F65B10AE3027BEABFA0BF7F9FB686355A9E33C7E7E44E6A998E04C |
| Tax_Notice_23665.exe 120,984 bytes | 93DD8B7B393289F88493596FAA4AE70054D9EB4FE47F2DD334F0C6BB5262F2A8 |
| nvdaHelperRemote.dll 455,527 bytes | 7295090C2CB63EBC43F932451971C41F9D015D2741E97AE3D9855F5AE87CFF94 |
| Decoded carrier record 415,071 bytes | 0419AE7381CAA97172C40F5AEA601B8A22F1F58D27F3930509AF5808E043F65E |
| Protected package allocation 417,792 bytes | E49581067CC2AA5ABD09C8DF42D6FBD87CB064A9363FE8B52D8369FD1C51FFE5 |
| Reconstructed image A 397,312-byte PE32 mapper | 28B8EB812E0F0AB724475BD51E3DC1F618BCB08B05998C414D4193009BF8D598 |
| Reconstructed image B PE32 launcher | 46B34789196733FAB62193F0AAEDB198B09F1362F9B10CA1DD70CF81D68B01AD |
| PLK1 compressed derivative 669,717 bytes | 502A7D2D72BEFA9114417936A1B3C2DD8EC84FCD4AE9EF9A09FFF3604FC05CCE |
| Reconstructed PackClientCore.dll 985,088 bytes | 4DE6EF8647FB4B599966A233740CB0514D1E71B8019A1A1792ED7E1E514EDF1C |
| Reconstructed Core .text 753,664 bytes | F06FF7AB6D62B761344CAECBCC6857912F7543F43C0E5FF462D2174BADB0CA3F |
| Filtered positive-flow PCAPNG 762,668 bytes | AB437D0EAE5E3C93764B89A3ECC5F6940D3CBEE0C2BE8D80D34CD7CB4CA38875 |
| PID 5812 dump 42,481,455 bytes | B67AA7F4176AF9793C0D2C53C12B757C95C213BF827108697ED5B60D2C1ED663 |
| PID 3696 dump 38,687,630 bytes | E635CC1F72112E10FEA9B9B9574FD7D2F7A5D101EDBF3C33B61FDD12071FA49E |
Source figures

Figure 01 / static reconstruction
The signed host calls the carrier initializer.
At host RVA 0x1004, the signed Tax Notice executable calls the imported nvdaHelperRemote.dll!injection_initialize entry.
Source: Ghidra disassembly and decompilation of Tax_Notice_23665.exe.

Figure 02 / runtime observation
The installed pair uses a signed host and a separate companion DLL.
Explorer shows Tax_Notice_23665.exe beside nvdaHelperRemote.dll under C:\ProgramData\NVIDIA Corporation\NvSvc. A separate properties view lists an embedded NV Access Limited signature for the host. The signature belongs to the host; this view does not authenticate the companion DLL.
Source: Explorer directory listing and host Digital Signatures properties, captured separately.

Figure 04 / static reconstruction
Launcher B retains its PackClientLauncher build identity.
The image summary identifies the imported PE and its PackClientLauncher PDB name; the recorded SHA-256 identifies the reconstructed image.
Source: Ghidra program information for recovered image B.

Figure 05 / static reconstruction
The worker opens an existing endpoint.
1. CreateFileW receives the supplied endpoint, read/write access and disposition 3 (OPEN_EXISTING). 2. The READY header uses magic 0x50435231 and type 1. The endpoint namespace and external peer are not recovered.
Source: Ghidra decompilation of the worker endpoint-open and READY path.

Figure 08 / static reconstruction
The recapture branch constructs a type-2 response.
The literal type 2 and the send-helper call are visible in the recapture path. The surrounding dataflow establishes the field semantics and BGRX payload layout.
Source: Ghidra disassembly of the recapture response in image B.

Figure 10 / static reconstruction
Authentication gates decryption.
A failed tag comparison exits the receive path before ciphertext reaches the AES-CBC helper.
Source: Ghidra decompilation of the authenticated receive path in image B.

Figure 11 / runtime observation
A historical Triage Launcher flow reaches PLK1.
Wireshark displays PLH1, PLC1, PLA1 and PLK1 on the filtered historical flow. The selected PLK1 header declares wire version 2, LZ4, 669,717 transferred bytes, 985,088 original bytes and the expected Core plaintext SHA-256.
Source: Filtered PCAPNG derived from Triage 260715-wd77daas7l/behavioral1 and opened with the PackClient Wireshark dissector.

Figure 13 / static reconstruction
The plaintext must pass digest verification, cache save and cache reload.
The transfer body checks the plaintext digest, requires Save to succeed, and immediately requires TryLoad to return a nonempty vector. The visible failure branches are SHA256 mismatch, disk_cache_save_failed and disk_cache_reload_failed.
Source: Ghidra decompilation of image B’s PLK1 acceptance and cache-return path.

Figure 14 / recovery verification
Traffic recovery and memory identity agree.
PLK1 supplies the complete PE hash; the mapped .text hash independently links that build to all 352 memory images.
Source: PowerShell verification output for the historical PLK1 transfers and retained Core memory mappings.

Figure 15 / static reconstruction
The recovered Core is a 32-bit x86 PE DLL.
Ghidra identifies the reconstructed payload as little-endian 32-bit x86 and a Portable Executable, with the same SHA-256 recovered from PLK1 traffic.
Source: Ghidra import summary for the reconstructed PackClientCore.dll.

Figure 16 / static reconstruction
Core resolves and validates the modern plugin ABI.
The recovered Core resolves PackPlugin_GetAbiVersion and PackPlugin_GetFeatureId before accepting feature-specific host bindings. A separate legacy path resolves Main.
Source: Ghidra decompilation of reconstructed PackClientCore.dll function 0x10016231.

Figure 17 / static reconstruction
Core serializes its built-in preview as PV10.
The Core serializer emits the PV10 marker in the built-in screenshot-preview path. Packet reconstruction finds 15 matching type-18 JPEG frames; no bridge from the separate Launcher 1RCP endpoint is established.
Source: Ghidra disassembly and decompilation of reconstructed PackClientCore.dll RVA 0x236D0.

Figure 18 / static reconstruction
The active-session path retries a token-based launch.
The call uses CreateProcessAsUserW with flags 0x09000400. The loop sleeps for 1,000 ms after each failure and stops after at most 0x1E attempts. This helper handles session handoff; the original elevation path remains unresolved.
Source: Ghidra decompilation of the active-session spawn loop in image B.

Figure 19 / runtime observation
Private executable allocation in svchost.exe, PID 5812.
VMMap shows a 408 KiB Execute/Read allocation at 0x002E0000. Corresponding dump analysis identifies its contents as the transformed A/B package.
Source: VMMap allocation views from the PID 5812 capture.

Figure 21 / runtime observation
One parent creates two siblings.
Process Monitor records parent PID 2116 creating svchost PID 3696 and schtasks PID 4600; schtasks then creates conhost PID 8248. SUCCESS is the Process Create result, not the child's exit code.
Source: Process Monitor process-creation rows from the PID 3696 capture.

Figure 22 / runtime observation
NvSvc combines an at-logon trigger with a ProgramData action.
Task Scheduler shows NvSvc's enabled at-logon trigger, ProgramData action and configured principal. Highest available privileges for this user do not establish SYSTEM execution.
Source: Task Scheduler action, trigger and principal settings for NvSvc.

Figure 23 / runtime observation
Full-EXE execution persists the Tax Notice host.
The process view records NvSvc task creation with the ProgramData Tax_Notice_23665.exe action, matching the intended signed-host/carrier chain.
Source: Triage 260908-zwr5naybjb behavioral1 process report.

Figure 24 / runtime observation
Direct-DLL execution persists a copied rundll32 host.
The direct rundll32 invocation causes NvSvc to target a copied rundll32.exe without the DLL argument. That action cannot replay the original entry point and is treated as a sandbox-context artifact, not a second variant.
Source: Triage 260908-zwr5naybjb behavioral2 process report.

Figure 25 / runtime observation
The surviving surrogate has a bare command line.
1. Bare SysWOW64 svchost command line. 2. Parent 2116 has exited. 3. The process is x86. The Downloads\PackClient current directory supplies additional context. These properties support an anomalous surrogate, without identifying an injection subtype.
Source: Process Explorer properties for PID 3696.

Figure 26 / runtime observation
Connection attempts from svchost.exe, PID 3696.
Process Explorer shows two SYN_SENT attempts to 154.36.188.201:443, from local ports 54581 and 50275.
Source: Process Explorer TCP/IP views associated with PID 3696.