Vectored Overloading PE Injection

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Aperçu de la technique

Vectored Overloading est une primitive d’injection PE Windows qui fusionne le classique Module Overloading avec Vectored Exception Handlers (VEHs) et des hardware breakpoints. Au lieu de patcher LoadLibrary ou d’écrire son propre loader, l’adversaire :

  1. Crée une section SEC_IMAGE basée sur un DLL légitime (par ex., wmp.dll).
  2. Écrase la vue mappée avec un PE malveillant entièrement relocalisé mais conserve l’objet de section pointant vers l’image bénigne sur disque.
  3. Enregistre un VEH et programme les registres de debug pour que chaque appel à NtOpenSection, NtMapViewOfSection, et optionnellement NtClose déclenche un breakpoint en espace utilisateur.
  4. Appelle LoadLibrary("amsi.dll") (ou toute autre cible bénigne). Lorsque le loader Windows invoque ces syscalls, le VEH saute la transition vers le noyau et retourne les handles et adresses de base de l’image malveillante préparée.

Parce que le loader croit toujours avoir mappé le DLL demandé, les outils qui ne regardent que les fichiers backing des sections voient wmp.dll même si la mémoire contient maintenant le payload de l’attaquant. Pendant ce temps, les imports/callbacks TLS sont toujours résolus par le loader authentique, réduisant significativement la quantité de logique de parsing PE personnalisée que l’adversaire doit maintenir.

Stage 1 – Build the disguised section

  1. Create and map a section for the decoy DLL
NtCreateSection(&DecoySection, SECTION_ALL_ACCESS, NULL,
0, PAGE_READWRITE, SEC_IMAGE, L"\??\C:\\Windows\\System32\\wmp.dll");
NtMapViewOfSection(DecoySection, GetCurrentProcess(), &DecoyView, 0, 0,
NULL, &DecoySize, ViewShare, 0, PAGE_READWRITE);
  1. Copy the malicious PE into that view section by section, honouring SizeOfRawData/VirtualSize and updating protections afterwards (PAGE_EXECUTE_READ, PAGE_READWRITE, etc.).
  2. Apply relocations and resolve imports exactly as a reflective loader would. Because the view is already mapped as SEC_IMAGE, section alignments and guard pages match what the Windows loader expects later.
  3. Normalize the PE header:
  • If the payload is an EXE, set IMAGE_FILE_HEADER.Characteristics |= IMAGE_FILE_DLL and zero the entry point to keep LdrpCallTlsInitializers from jumping into EXE-specific stubs.
  • DLL payloads can keep their headers unchanged.

At this point the process owns a RWX-capable view whose objet sous-jacent is still wmp.dll, yet the bytes in memory are attacker-controlled.

Stage 2 – Hijack the loader with VEHs

  1. Register a VEH and arm hardware breakpoints: program Dr0 (or another debug register) with the address of ntdll!NtOpenSection and set DR7 so every execution raises STATUS_SINGLE_STEP. Repeat later for NtMapViewOfSection and optionally NtClose.
  2. Trigger DLL loading with LoadLibrary("amsi.dll"). LdrLoadDll will eventually call NtOpenSection to obtain the real section handle.
  3. VEH hook for NtOpenSection:
  • Locate the stack slot for the [out] PHANDLE SectionHandle argument.
  • Write the previously created DecoySection handle into that slot.
  • Advance RIP/EIP to the ret instruction so the kernel is never called.
  • Re-arm the hardware breakpoint to watch NtMapViewOfSection next.
  1. VEH hook for NtMapViewOfSection:
  • Overwrite the [out] PVOID *BaseAddress (and size/protection outputs) with the address of the already mapped malicious view.
  • Skip the syscall body just like before.
  1. (Optional) VEH hook for NtClose verifies that the fake section handle is cleaned up, preventing resource leaks and providing a final sanity check.

Because the syscalls are never executed, kernel callbacks (ETWti, minifilter, etc.) do not observe the suspicious NtOpenSection/NtMapViewOfSection events, drastically lowering telemetry. From the loader’s point of view everything succeeded and amsi.dll is in memory, so it proceeds with import/TLS resolution against the attacker’s bytes.

Stage 3 – Execute the payload

  • EXE payload: The injector simply jumps to the original entry point once relocations are done. When the loader thinks it would call DllMain, the custom code instead executes the EXE-style entry.
  • DLL payload / Node.js addon: Resolve and call the intended export (Kidkadi exposes a named function to JavaScript). Because the module is already registered with LdrpModuleBaseAddressIndex, subsequent lookups see it as the benign DLL.

When combined with a Node.js native addon (.node file), all of the Windows-internals heavy lifting stays outside the JavaScript layer, helping the acteur malveillant ship the same loader with many different obfuscated Node wrappers.

References

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks