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.
| Component | Disk artifact | Role |
|---|---|---|
| EggStremeFuel | mscorsvc.dll (sideloaded by WinMail.exe) | Stage-1 loader; fingerprint plus reverse shell |
| EggStremeLoader | iscsiexe.dll / service binary | Windows service; decrypts and hands off |
| EggStremeReflectiveLoader | Encrypted inside ielowutil.exe.mui / splwow64.exe.mui | In-memory PE loader; injects the agent |
| EggStremeAgent | Never on disk in plaintext | Core C2 backdoor, 58 commands, gRPC/mTLS |
| EggStremeKeylogger | splwow64.exe.mui (encrypted) | Per-session surveillance in explorer.exe |
| EggStremeWizard | xwizards.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.

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.

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 category | What it does |
|---|---|
| System fingerprinting | Detailed host and domain enumeration |
| Resource enumeration | Local and remote network resource discovery |
| Privilege escalation | Token and privilege manipulation |
| Command execution | Arbitrary command running |
| Data exfiltration | Staged collection and theft |
| File and directory manipulation | Create, delete, modify |
| Process injection | Push 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.

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:
| Type | Indicator |
|---|---|
| Domain | whosecity[.]org |
| Domain | webpirat[.]net |
| Domain | fsstore[.]org |
| IP | 154.90.35.190 |
| IP | 45.115.224.163 |
| CA Subject Key ID | 64:30:42:DF:50:CE:F0:80:E4:48:51:E7:D5:D6:F6:54:F7:72:EB:C5 |
| CA Subject Key ID | 51: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 dimension | EggStreme operator | UAT-7237 | UAT-5918 |
|---|---|---|---|
| Primary implant | Custom EggStremeAgent (gRPC/mTLS) | Cobalt Strike | Meterpreter reverse shells |
| Shellcode loading | Reflective in-memory, RC4 | SoundBill custom loader | Standard MSF stagers |
| Web shells | Not central | Highly selective | Deployed in volume |
| Persistence | Service ServiceDLL hijack | SoftEther VPN + RDP | Web shells |
| Priv-esc | Agent commands | JuicyPotato | Varied |
| Credentials | Keylogger + collection | Mimikatz | Varied |
| Initial access theme | DLL sideloading (LOLBin) | DLL sideloading | Web-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.malfindto surface RWX private memory regions that hold executable code with no backing file. The reflectively-loadedEggStremeAgentinsidewinlogon.exeorMsMpEng.exeshows up here as a private, executable, unbacked region.windows.ldrmodulesto find the discrepancy between the three loader lists. A reflectively-mapped PE appears in memory but is missing fromInLoad,InInit, orInMemlists, which is the signature of manual mapping.windows.dlllistcross-referenced againstldrmodulesto spot loaded code the PEB never acknowledged.windows.svcscanto catch the hijackedMSiSCSI,AppMgmt, orSWPRVServiceDLLpointing somewhere it should not.windows.pstreeto validate parent-child anomalies likecmd.exeunderWinMail.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
| Signal | Field | What it catches |
|---|---|---|
| Sysmon ID 7 (ImageLoad) | ImageLoaded, SignatureStatus | mscorsvc.dll loaded by WinMail.exe; xwizards.dll by xwizard.exe; unsigned DLL from a signed LOLBin |
| Sysmon ID 8 (CreateRemoteThread) | SourceImage, TargetImage, StartAddress | Remote thread into winlogon.exe, MsMpEng.exe, explorer.exe |
| Sysmon ID 10 (ProcessAccess) | GrantedAccess | 0x1fffff (PROCESS_ALL_ACCESS) from a service binary against winlogon.exe |
| Sysmon ID 1 / Event 4688 | CommandLine, ParentImage | cmd.exe spawned by WinMail.exe |
| Sysmon ID 11 (FileCreate) | TargetFilename | Writes to ielowutil.exe.mui / splwow64.exe.mui |
| Sysmon ID 13 (Registry) | TargetObject | ServiceDLL changes under MSiSCSI, AppMgmt, SWPRV |
| Sysmon ID 17/18 (Pipe) | PipeName | Reverse-shell pipes from WinMail.exe / mscorsvc.dll |
| Event 4697 | Service name / path | EggStremeLoader 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.

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.exeorMsMpEng.exewithout 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-Intelligenceremote-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,
ServiceDLLhijack of dormant services,SeDebugPrivilege, and classicVirtualAllocEx/WriteProcessMemory/NtCreateThreadExinjection. - 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
- EggStreme Malware: Unpacking a New APT Framework Targeting a Philippine Military Company – Bitdefender (Primary Research Blog)
- Chinese APT Deploys EggStreme Fileless Malware to Breach Philippine Military Systems – The Hacker News
- MITRE ATT&CK: Process Injection (T1055) – Enterprise Technique
- MITRE ATT&CK: Hijack Execution Flow – DLL Side-Loading, Sub-technique T1574.002
- MITRE ATT&CK: Process Injection – DLL Injection, Sub-technique T1055.001