EggStreme Fileless Framework: Dissecting the China-Nexus APT Targeting Philippine Military Organizations With a Zero-Footprint Implant

You cannot grep for something that never lands on disk in a form you can read. That single fact is what makes EggStreme different from the usual APT show-and-tell. This is not a RAT you pull off a workstation and drop into VirusTotal. It is a six-part, memory-resident espionage platform that a China-nexus operator pointed at a Philippine military organization, and it is engineered from the ground up so that the interesting code only ever exists as bytes inside winlogon.exe. If your detection strategy still revolves around file hashes and YARA on the filesystem, EggStreme was purpose-built to walk right past you.


The campaign and why the Philippines

Bitdefender’s Bogdan Zavadovschi published the EggStreme teardown on September 10, 2025, after tracking activity that reached back to early 2024. The confirmed victim was a military organization in the Philippines, which is exactly the kind of target you would expect given who is holding the tools. The South China Sea has been the most contested maritime space in the region for a decade, and the Philippines sits at the center of the dispute over the Spratlys and Scarborough Shoal. When an actor invests in a bespoke, fileless framework and spends it against a military network in Manila, the strategic read almost writes itself.

Bitdefender is careful, and so should you be. They attribute EggStreme to “a China-based APT” and stop short of stamping a named group on it. The tradecraft, the target selection, and the geopolitical context all point in one direction, and the TTP overlaps with clusters Cisco Talos calls UAT-7237 and UAT-5918 are worth examining. But overlap is not identity, and I will keep that line bright throughout this post.

What makes the framework worth a full dissection is the design philosophy. EggStreme is not a loose collection of malware families that got lumped together in a report. It is a unified toolkit where each component exists to feed the next, and the whole chain is oriented toward one outcome: getting EggStremeAgent, the real backdoor, running in memory inside a trusted process without ever writing its decrypted body to disk.

The six-component unified framework

Treat this like an assembly line. Each stage prepares the environment for the one after it, and only the encrypted containers ever sit on the filesystem.

ComponentDisk artifactRole
EggStremeFuelmscorsvc.dll (sideloaded by WinMail.exe)Stage-1 loader; fingerprint plus reverse shell
EggStremeLoaderiscsiexe.dll / service binaryWindows service; decrypts and hands off
EggStremeReflectiveLoaderEncrypted inside ielowutil.exe.mui / splwow64.exe.muiIn-memory PE loader; injects the agent
EggStremeAgentNever on disk in plaintextCore C2 backdoor, 58 commands, gRPC/mTLS
EggStremeKeyloggersplwow64.exe.mui (encrypted)Per-session surveillance in explorer.exe
EggStremeWizardxwizards.dll (sideloaded by xwizard.exe)Fallback backdoor and secondary C2

The dependency map is linear at the front and redundant at the back. EggStremeFuel profiles the host and drops EggStremeLoader, which registers persistence and decrypts both EggStremeReflectiveLoader and EggStremeAgent from a .mui resource file. The reflective loader injects the agent into memory. EggStremeWizard sits off to the side as an independent re-entry channel so that a partial infrastructure takedown does not evict the operator.

Flowchart showing the six EggStreme components in execution order from EggStremeFuel through EggStremeLoader and ReflectiveLoader into EggStremeAgent and EggStremeKeylogger, with EggStremeWizard as a parallel fallback path
Every stage feeds the next: the only goal is landing EggStremeAgent decrypted in memory inside a trusted process, never as a readable file on disk.

Stage 1: DLL sideloading and EggStremeFuel

The entry point is a textbook DLL search-order hijack against WinMail.exe, the old Windows Mail binary. When that executable launches, it resolves mscorsvc.dll from its own application directory before it ever consults System32. Drop a malicious mscorsvc.dll next to WinMail.exe and the loader hands you code execution inside a signed, benign-looking process.

You can watch this happen without touching malware. Fire up Process Monitor and filter for the failed lookups:

Procmon.exe -> filter: Process Name = WinMail.exe, Result = NAME NOT FOUND, Path ends with .dll

Every NAME NOT FOUND on a DLL in the application directory is a sideload candidate. The behavior is governed by LoadLibraryEx, the LOAD_WITH_ALTERED_SEARCH_PATH flag, and Safe DLL Search Mode (HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeDllSearchMode). This is why LOLBin sideloading remains one of the most durable initial-access techniques in the game: the OS is doing exactly what it was told to do.

Inside a lab VM (Windows 10 22H2, host-only network, no live egress, Defender off), a stub proves the concept without any payload:

// stub_mscorsvc.c - lab-only proof that WinMail.exe triggers our DllMain
#include <windows.h>
BOOL WINAPI DllMain(HMODULE hMod, DWORD reason, LPVOID reserved) {
    if (reason == DLL_PROCESS_ATTACH) {
        // In EggStremeFuel, this is where the reverse-shell pipe is opened.
        FILE *f = fopen("C:\\lab\\sideload_triggered.txt", "w");
        if (f) { fprintf(f, "DLL_PROCESS_ATTACH in WinMail.exe context\n"); fclose(f); }
    }
    return TRUE;
}
// x86_64-w64-mingw32-gcc -shared -o mscorsvc.dll stub_mscorsvc.c

In the real EggStremeFuel, DllMain does two things: it fingerprints the host, and it opens a reverse shell. The shell is built the old-fashioned way, by spawning cmd.exe and wiring stdin/stdout to anonymous read-write pipes that pass traffic to the C2. The config blob for this stage lives at %APPDATA%\Microsoft\Windows\Cookies\cookies.dat, which is a nice bit of misdirection since a file named cookies.dat in the Cookies folder is the last thing an analyst clicks on. Lateral delivery of EggStremeFuel across the network rode a logon script at \\<samba share>\netlogon\logon.bat, which is how you push a foothold to every machine that authenticates against the domain.

Stage 2: EggStremeLoader and persistence as a service

EggStremeLoader is the plumbing. It registers itself as a Windows service, which gives the operator a persistence primitive that survives reboots and runs under LocalSystem if configured that way. When it executes, it resolves nine service-manipulation functions out of advapi32.dll. The function names are not sitting in the import table where you would find them. They are stored encrypted and decrypted at runtime with a single-byte XOR key of 0xFE, then resolved dynamically through LoadLibrary and GetProcAddress.

That XOR pre-step is trivial to unwind once you spot it in Ghidra or IDA:

def xor_decrypt(data: bytes, key: int) -> bytes:
    return bytes(b ^ key for b in data)

# Placeholder encrypted function-name bytes lifted from the string table
encrypted_fn = bytes([0xBA, 0xBC, 0xBB, 0xAF, 0xAF, 0xBA, 0xA9])
print(xor_decrypt(encrypted_fn, 0xFE).decode('ascii', errors='replace'))

Once resolved, EggStremeLoader decrypts two payloads (the reflective loader and the agent) out of a resource container at %WINDIR%\en-us\ielowutil.exe.mui. The .mui extension is meant to read as a Multilingual User Interface resource, which is exactly the kind of file nobody audits.

The persistence itself abuses services that are set to manual or disabled by default, specifically MSiSCSI, AppMgmt, and SWPRV. Rather than create a suspicious new service, the loader either swaps the legitimate service binary or edits the ServiceDLL value in the registry so a dormant, trusted service now points at attacker code. And it configures the service to run with SeDebugPrivilege, which is the privilege you need to open and write the memory of other processes. That grant is not incidental. It is the enabler for everything that happens in Stage 3.

Stage 3: EggStremeReflectiveLoader and zero-footprint injection

This is the heart of the “fileless” claim. EggStremeReflectiveLoader takes the encrypted EggStremeAgent PE, decrypts it with RC4 (key google), maps it into memory manually, and injects it into a trusted host process. The candidate hosts are winlogon.exe, MsMpEng.exe, and explorer.exe. Picking MsMpEng.exe, the Defender engine process, is a particularly cynical touch: hiding inside the antivirus.

The payload container uses a simple framing scheme. Each of the three parts (a 4-byte big-endian length, the loader, and the agent) is individually RC4-encrypted. The RC4 keys observed across the framework are google, Google, Microsoft, and microsoft. Here is a clean RC4 implementation you will reuse for both payload and C2 decryption:

def rc4(key: bytes, data: bytes) -> bytes:
    S = list(range(256)); j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    i = j = 0; out = []
    for byte in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        out.append(byte ^ S[(S[i] + S[j]) % 256])
    return bytes(out)

The injection primitive is the classic cross-process trio, and the mechanics matter for detection later. In a lab, the skeleton looks like this against notepad.exe:

// reflective_inject_demo.c - lab skeleton, benign MessageBox payload only
#include <windows.h>
#include <tlhelp32.h>
int main() {
    DWORD pid = GetPID(L"notepad.exe");
    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    LPVOID rmt = VirtualAllocEx(hProc, NULL, payloadSize,
                                MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(hProc, rmt, payload, payloadSize, NULL);
    CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)rmt, NULL, 0, NULL);
}

OpenProcess with PROCESS_ALL_ACCESS (that is SeDebugPrivilege paying off), VirtualAllocEx to carve an RWX region, WriteProcessMemory to copy the mapped agent, then NtCreateThreadEx or CreateRemoteThread to run it. The reason this defeats file scanners is that the agent PE never exists as a file. It is decrypted in the loader’s address space, reflectively mapped, and executed. Attach WinDbg to the target and run lm before and after: a normally-loaded DLL shows up in the module list, but a reflectively-loaded PE does not, because it was never registered with the loader’s PEB->Ldr structures. Use !address to hunt the RWX region instead. That gap between “what the module list says” and “what is actually executing” is the whole detection story here.

Step-by-step flow diagram tracing how EggStremeReflectiveLoader reads the encrypted MUI file, decrypts the agent PE with RC4 in its own memory, then uses VirtualAllocEx and WriteProcessMemory to inject it into winlogon.exe before launching it with CreateRemoteThread
The agent PE exists decrypted only as transient bytes in loader memory and the target’s RWX region – it never touches disk in a form a file scanner can read.

EggStremeAgent: the C2 protocol and the 58-command model

EggStremeAgent is the payoff, and its transport is unusually modern for an espionage implant. It speaks gRPC over mutual TLS. gRPC rides HTTP/2 framing, and mTLS means both the implant and the C2 present certificates and validate each other. That gives the operator authenticated, multiplexed, TLS-wrapped channels that blend into normal encrypted traffic and resist casual interception.

Inside the encrypted tunnel, the tasking format is layered. A command is a JSON object, serialized to a string, RC4-encrypted, then prefixed with an RC4-encrypted command ID:

import json, struct

def build_task_message(cmd_id: int, payload: dict, key: bytes) -> bytes:
    encrypted_json = rc4(key, json.dumps(payload).encode())
    encrypted_cmd  = rc4(key, struct.pack('>I', cmd_id))
    return encrypted_cmd + encrypted_json

msg = build_task_message(1, {"hostname": "LAB-PC", "os": "Windows 10"}, b'google')
print(msg.hex())

If you drop a tshark -d tcp.port==443,http2 dissector on captured C2, you will see clean HTTP/2 frames carrying opaque ciphertext. Without the RC4 key you get nothing useful out of the payload, which is the point of double-wrapping application data inside TLS.

The agent supports 58 distinct commands. Rather than list all of them, the categories tell you the operator’s intent:

Capability categoryWhat it does
System fingerprintingDetailed host and domain enumeration
Resource enumerationLocal and remote network resource discovery
Privilege escalationToken and privilege manipulation
Command executionArbitrary command running
Data exfiltrationStaged collection and theft
File and directory manipulationCreate, delete, modify
Process injectionPush further code into other processes

There is also a session-awareness thread that matters for the keylogger. Before doing much, the agent registers to watch for the WTS_EVENT_LOGON event and waits for a user’s explorer.exe to spawn. Only then does it move to the surveillance stage.

Illustration of layered encryption surrounding C2 command traffic, representing gRPC over mTLS with an inner RC4-encrypted command payload
EggStremeAgent double-wraps its tasking: RC4-encrypted JSON inside a mutual-TLS gRPC tunnel, making passive interception produce nothing actionable without the key.

EggStremeKeylogger: per-session surveillance in explorer.exe

The keylogger is stored encrypted at C:\Windows\en-US\splwow64.exe.mui, decrypted with the RC4 key Microsoft, and injected into the logged-in user’s explorer.exe. Injecting per session is deliberate: it puts the collector inside the process that owns the interactive desktop, so it can grab keystrokes, clipboard contents, window titles, and network configuration for the actual human at the keyboard. Encrypted logs get written to a hidden file under %LOCALAPPDATA%.

The session hook that drives all of this is WTSRegisterSessionNotification, and you can model it cleanly:

// wts_session_hook_demo.c - lab demo of new-logon detection
#include <windows.h>
#include <wtsapi32.h>
#pragma comment(lib, "wtsapi32.lib")

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    if (msg == WM_WTSSESSION_CHANGE && wParam == WTS_SESSION_LOGON) {
        // EggStreme: trigger keylogger RC4 decrypt + inject into explorer.exe
        OutputDebugStringW(L"[LAB] WTS_SESSION_LOGON detected");
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
// WTSRegisterSessionNotification(hwnd, NOTIFY_FOR_ALL_SESSIONS);

The pairing of WTSEnumerateSessions and WTSQueryUserToken lets the malware target the right token for the right session, which is how it stays user-scoped instead of leaking across desktops.

EggStremeWizard and the redundant backdoor

EggStremeWizard is insurance. It rides a second DLL sideload, this time abusing the legitimate xwizard.exe to load a malicious xwizards.dll. It gives the operator a reverse shell and file upload/download, and it carries its own fallback list of C2 servers. The design intent is resilience: if the primary agent infrastructure gets burned in a takedown, Wizard keeps a door open.

The infrastructure itself hands defenders one of the few durable pivots in this whole campaign. Across every analyzed EggStremeAgent configuration, Bitdefender found the same certificate authority issuing the mTLS certificates. That CA issued certs to multiple C2 domains, including fsstore[.]org, with matching identifiers spread across different IPs. When file IOCs are worthless, a shared CA and its Subject Key Identifiers become gold, because the operator has to reuse infrastructure to keep the mTLS trust chain working.

Public network IOCs from the Bitdefender GitHub repository:

TypeIndicator
Domainwhosecity[.]org
Domainwebpirat[.]net
Domainfsstore[.]org
IP154.90.35.190
IP45.115.224.163
CA Subject Key ID64:30:42:DF:50:CE:F0:80:E4:48:51:E7:D5:D6:F6:54:F7:72:EB:C5
CA Subject Key ID51:65:5E:8E:97:FC:72:65:B1:AA:A4:26:5D:94:E2:F7:CA:E9:C9:13

Network pivoting with Stowaway

For lateral movement, the operator dropped Stowaway, an open-source Go proxy tool, as burn.conf. It exposed an internal proxy on port 8531, authenticated with a hardcoded secret, and used it to pivot past network segmentation. This is a common pattern in China-nexus intrusions: instead of dragging a heavy C2 to every internal host, you tunnel through one compromised pivot and reach the rest of the segment from inside.

Cluster cross-reference: EggStreme against UAT-7237 and UAT-5918

Cisco Talos published on UAT-7237 in August 2025 and describes it as a Chinese-speaking group active since at least 2022, likely a subgroup operating under the UAT-5918 umbrella. Both develop and operate tooling in Chinese, both target APAC critical infrastructure and government, and both lean heavily on DLL sideloading and living-off-the-land. UAT-7237 is also assessed to orbit the Volt Typhoon and Flax Typhoon clusters.

Where they diverge is instructive when you line them up against EggStreme:

TTP dimensionEggStreme operatorUAT-7237UAT-5918
Primary implantCustom EggStremeAgent (gRPC/mTLS)Cobalt StrikeMeterpreter reverse shells
Shellcode loadingReflective in-memory, RC4SoundBill custom loaderStandard MSF stagers
Web shellsNot centralHighly selectiveDeployed in volume
PersistenceService ServiceDLL hijackSoftEther VPN + RDPWeb shells
Priv-escAgent commandsJuicyPotatoVaried
CredentialsKeylogger + collectionMimikatzVaried
Initial access themeDLL sideloading (LOLBin)DLL sideloadingWeb-facing exploitation

The shared DNA is real: DLL sideloading, LOTL discipline (nslookup, systeminfo), APAC military and infrastructure targeting, and selective, deliberate tooling. But the payload architecture is genuinely different. EggStreme’s fully custom, memory-only gRPC agent is a step beyond off-the-shelf Cobalt Strike or Meterpreter. My read: EggStreme belongs in the same neighborhood, the broader China-nexus espionage cluster oriented on the South China Sea, and the tradecraft parallels are strong enough to treat as analytical siblings. But nobody has merged these operators by name, and you should not either. Treat the overlap as a hunting hypothesis, not a verdict.

Detection and defense: hunt in memory, not on disk

The central defensive truth is uncomfortable: while encrypted components sit on disk, the malicious code that matters only exists decrypted in memory. File hashes will not save you. You detect EggStreme by watching behavior, memory, and infrastructure.

Memory forensics with Volatility

Acquire memory (WinPmem, or a hypervisor snapshot) and pivot on injection artifacts, not files. The workflow:

  • windows.malfind to surface RWX private memory regions that hold executable code with no backing file. The reflectively-loaded EggStremeAgent inside winlogon.exe or MsMpEng.exe shows up here as a private, executable, unbacked region.
  • windows.ldrmodules to find the discrepancy between the three loader lists. A reflectively-mapped PE appears in memory but is missing from InLoad, InInit, or InMem lists, which is the signature of manual mapping.
  • windows.dlllist cross-referenced against ldrmodules to spot loaded code the PEB never acknowledged.
  • windows.svcscan to catch the hijacked MSiSCSI, AppMgmt, or SWPRV ServiceDLL pointing somewhere it should not.
  • windows.pstree to validate parent-child anomalies like cmd.exe under WinMail.exe.

If you can carve the RWX region out of malfind and it decrypts under RC4 with google, you have your agent.

ETW: the highest-fidelity signal

The Microsoft-Windows-Threat-Intelligence provider ({F4E1897C-BB5D-5668-F1D8-040F4D8DD344}) is the best telemetry for reflective injection because it reports remote memory operations from the kernel’s perspective, below the point where userland evasion helps. Watch KERNEL_THREATINT_TASK_ALLOCVM_REMOTE (remote VirtualAllocEx), KERNEL_THREATINT_TASK_WRITEVM_REMOTE (remote WriteProcessMemory), and KERNEL_THREATINT_TASK_QUEUEUSERAPC_REMOTE. One caveat that trips people up: this provider is PPL-protected and requires a signed kernel driver or a PPL-level consumer to subscribe. It is what commercial EDRs consume under the hood; rolling your own means an anti-malware-protected process or driver.

Sysmon and Security auditing

SignalFieldWhat it catches
Sysmon ID 7 (ImageLoad)ImageLoaded, SignatureStatusmscorsvc.dll loaded by WinMail.exe; xwizards.dll by xwizard.exe; unsigned DLL from a signed LOLBin
Sysmon ID 8 (CreateRemoteThread)SourceImage, TargetImage, StartAddressRemote thread into winlogon.exe, MsMpEng.exe, explorer.exe
Sysmon ID 10 (ProcessAccess)GrantedAccess0x1fffff (PROCESS_ALL_ACCESS) from a service binary against winlogon.exe
Sysmon ID 1 / Event 4688CommandLine, ParentImagecmd.exe spawned by WinMail.exe
Sysmon ID 11 (FileCreate)TargetFilenameWrites to ielowutil.exe.mui / splwow64.exe.mui
Sysmon ID 13 (Registry)TargetObjectServiceDLL changes under MSiSCSI, AppMgmt, SWPRV
Sysmon ID 17/18 (Pipe)PipeNameReverse-shell pipes from WinMail.exe / mscorsvc.dll
Event 4697Service name / pathEggStremeLoader service registration

MITRE ATT&CK coverage

Initial Access via logon-script delivery (T1078, T1021.002 SMB shares). Execution through WinMail.exe and cmd.exe (T1059.003). Persistence via service hijack (T1543.003) and ServiceDLL (T1574.011). Privilege escalation and defense evasion through DLL sideloading (T1574.002), reflective loading (T1620), and SeDebugPrivilege abuse (T1134). Process injection into trusted hosts (T1055.001/.012). Collection through the keylogger and clipboard (T1056.001, T1115). C2 over encrypted gRPC/mTLS (T1071.001, T1573.002). Lateral pivot via Stowaway proxy (T1090). Discovery through nslookup and systeminfo (T1016, T1082).

Hardening

Restrict where WinMail.exe, xwizard.exe, and other sideload-prone LOLBins can run, and enforce signed-DLL loading where you can. Alert on any modification to ServiceDLL for dormant services. Egress-filter and TLS-inspect outbound HTTP/2 to catch anomalous gRPC to newly-registered domains, and block or alert on the known CA Subject Key Identifiers above. Feed Microsoft-Windows-Threat-Intelligence into your EDR and make sure remote-injection events actually generate alerts rather than getting swallowed.

Symbolic illustration of a memory module as the primary source of forensic truth, with disk storage shown as dark and inactive, representing the shift from file-based to memory-based detection for fileless malware
Against a fully fileless framework, disk artifacts are decoys – memory acquisition and kernel-level ETW telemetry are the only reliable detection surfaces.

Key takeaways

  • EggStreme is a unified, six-component, memory-resident espionage platform, not a loose malware family. The whole chain exists to get a gRPC/mTLS backdoor running inside winlogon.exe or MsMpEng.exe without a readable file ever hitting disk.
  • File-based IOCs are effectively dead here. Detection lives in memory forensics (malfind, ldrmodules), kernel ETW (Microsoft-Windows-Threat-Intelligence remote-alloc and remote-write events), and infrastructure pivots (shared CA and Subject Key Identifiers).
  • The loader chain is old primitives wired together well: DLL sideloading, XOR/RC4 string and payload decryption, ServiceDLL hijack of dormant services, SeDebugPrivilege, and classic VirtualAllocEx / WriteProcessMemory / NtCreateThreadEx injection.
  • The TTP overlap with UAT-7237 and UAT-5918, and the South China Sea targeting, place EggStreme firmly in the China-nexus espionage orbit. That is an analytical parallel, not a confirmed attribution. Hunt on the hypothesis; do not write the verdict.
  • If you take one operational action from this: turn on and actually alert on remote memory-write telemetry, and start acquiring memory as a first-class part of incident response. Against fileless frameworks, the disk lies and RAM tells the truth.

Related Tutorials

References