
PolyEngine is an evasive PE packer designed for CTF challenges and low-level Windows security education. It focuses on bypassing EDR and AV heuristics through a layered stack of in-memory execution and obfuscation techniques.
PolyEngine is a research-grade, evasive PE packer designed for CTF challenges and low-level Windows security education. It focuses on bypassing EDR and AV heuristics through a layered stack of in-memory execution and obfuscation techniques.
This is a side project I've been working on for some time. I have used Claude Code to implement and correct some of techniques I wanted to implement in my own PE packer. There's a lot of comments on functions and what they do, since it was a big learning experience for me and Claude does this flawlessly (I'm bad at it). I hope it helps some people to learn some Windows internals or with bypassing some AVs and static detections from more advanced solutions when you tackle those ProLabs 🏯.
🔥 Big thank you to MalDevAcademy for all the materials to create it and inspiration.
🌩 Thanks to vx-underground for inspiration via some goofy tweet with silly cat.
Disclaimer: This tool is intended exclusively for authorized security testing, CTF competitions and educational use. Usage against systems without explicit permission is prohibited. The author assumes no liability for misuse.
Build order: Stub first, then Builder. Stub Release|x64 emits stub_v0.bin..stub_v3.bin; Builder embeds one into .rsrc.
Ensure stub_v0.bin..stub_v3.bin are in the working directory (or pass --stub).
Builder.exe <input> <output> [OPTIONS]
<input> Target PE (.exe/.dll) or raw shellcode (.bin)
Payload type is auto-detected from the MZ header - no flag needed.
<output> Output executable
Loader:
--stub <path> Loader stub PE [default: random ./stub_v0.bin..stub_v3.bin]
--preset PRINT|MEDIA|NETWORK|RANDOM
Module stomping DLL preset [default: PRINT]
--overload Module overloading instead of stomping
(NtCreateSection/NtMapViewOfSection, not in PEB LDR)
--keep-alive ExitThread(0) instead of ExitProcess
(required for C2 implants that spawn their own threads)
--unhook Restore original .text bytes in ntdll/kernel32/
kernelbase from \KnownDlls\ clean copies
(overwrites EDR inline hooks before any payload syscall)
Payload (PE/DLL only, silently ignored for shellcode):
--export <name> DLL export to invoke after DllMain
--arg <string> Argument passed to the export [max 127 chars]
Evasion (all ON by default):
--spoof-name <exe> Process name for PEB spoof [default: random from pool]
Pool: RuntimeBroker.exe SgrmBroker.exe WmiPrvSE.exe
SearchIndexer.exe taskhostw.exe spoolsv.exe
wlrmdr.exe WMPDMC.exe hvix64.exe
--exec-ctrl-name <name> Semaphore name for exec-ctrl check [default: wuauctl]
(max 31 chars)
--sleep-fwd-ms <ms> Sleep duration for sleep-fwd check [default: 500]
Detection threshold: 90% of <ms> elapsed
--uptime-min <minutes> Uptime threshold for uptime check [default: 2]
--hammer-s <seconds> API-hammer delay duration [default: 3]
--disable <token,token...> Disable one or more features (comma-separated, repeatable)
OPSEC tokens:
etw EtwEventWrite patch (ETW telemetry suppression)
spoofing Call-stack spoofing (SilentMoonwalk RSP pivot)
peb PEB path/cmdline spoof
tls TLS anti-debug callback (patches loader stub before embedding)
Sandbox/debug check tokens:
hammer API-hammer timing delay (VirtualAlloc/Free loop)
debugger Debugger detection (PEB flags / NtQueryInformationProcess)
api-emu API emulation probe (RtlComputeCrc32 identity check)
exec-ctrl Execution-control semaphore (re-execution detection)
sleep-fwd Sleep-forwarding detection (timing)
uptime System uptime check
cpu CPU count check (< 2 logical cores)
screen Screen resolution check (<= 1024 px width)
files Recent-files count check (< 5 RecentDocs subkeys)
all Disable every token listed above
Identity spoofing:
--pfx <path> PFX certificate container to sign the output with
--pfx-pass <password> PFX passphrase [omit if PFX has no password]
--ts-url <url> RFC 3161 timestamp URL [default: no timestamping]
OPSEC: timestamping reveals build IP/time to the TSA.
Enable only when signing from an isolated VM, or when
the signature must survive cert revocation.
--clone-meta <donor.exe> Clone VERSIONINFO, icon, and Authenticode cert directory
from a donor PE (e.g. notepad.exe, OneDrive.exe).
Explorer "Details" tab shows donor company/product/version;
file icon matches donor; "Digital Signatures" tab shows
donor's signer (HashMismatch — defeats visual inspection only).
Name output to match donor OriginalFilename field.
When combined with --pfx: real signature overwrites cloned cert.
--uac Embed a UAC elevation manifest (requireAdministrator).
Output PE prompts for admin privileges on launch.
Applied as Phase 10.5 (after packing, before signing).
Examples:
Builder.exe implant.exe packed.exe
Builder.exe implant.exe packed.exe --stub stub_v2.bin
Builder.exe shellcode.bin packed.exe --keep-alive
Builder.exe beacon.dll packed.exe --export Start --keep-alive
Builder.exe payload.dll packed.exe --export Execute --arg "calc.exe"
Builder.exe implant.exe packed.exe --preset NETWORK --disable etw,tls
Builder.exe implant.exe packed.exe --overload --hammer-s 5 --uptime-min 5
Builder.exe implant.exe packed.exe --exec-ctrl-name MyMutex --sleep-fwd-ms 1000
Builder.exe implant.exe packed.exe --pfx cert.pfx --pfx-pass hunter2
Builder.exe implant.exe packed.exe --pfx cert.pfx --ts-url http://timestamp.digicert.com
Builder.exe implant.exe notepad.exe --clone-meta C:\Windows\System32\notepad.exe
Builder.exe implant.exe notepad.exe --clone-meta notepad.exe --pfx self.pfx
Builder.exe implant.exe packed.exe --uac
Builder.exe implant.exe notepad.exe --uac --clone-meta notepad.exe --pfx self.pfx
Worked examples grouped by scenario. Every flag is opt-out (evasion is fully ON by default), so the simplest invocation already gets the full stack.
Pack an unmanaged EXE. Builder auto-detects the MZ header and routes through the RunPE path:
Builder.exe implant.exe packed.exe
Pack raw position-independent shellcode (Cobalt Strike .bin, msfvenom -f raw, etc.). No MZ → direct call into the decompressed buffer:
Builder.exe beacon.bin packed.exe
Pack a DLL and call its default DllMain only (no export):
Builder.exe payload.dll packed.exe
Use a stub from a non-default location:
Builder.exe implant.exe packed.exe --stub C:\build\release\stub_v1.bin
Call a named export after DllMain returns. Most C2 implants ship as a DLL with a single entry export (e.g. Havoc Demon: Start, Sliver: RunSliver):
Builder.exe demon.dll packed.exe --export Start --keep-alive