Vectored Overloading PE Injection

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks

Tip

Шукаєте Windows 11 LFH heap shaping та VMware Workstation PVSCSI (vmware-vmx) escape techniques?

{{#ref}} vmware-workstation-pvscsi-lfh-escape.md {{#endref}}

Technique overview

Vectored Overloading — це Windows PE injection primitive, який поєднує класичний Module Overloading з Vectored Exception Handlers (VEHs) та hardware breakpoints. Замість патчу LoadLibrary або написання власного лоадера, противник:

  1. Створює секцію SEC_IMAGE, підкріплену легітимною DLL (наприклад, wmp.dll).
  2. Перезаписує mapped view повністю релокованим шкідливим PE, але залишає об’єкт секції, що вказує на безпечний образ на диску.
  3. Регіструє VEH і програмує debug registers так, щоб кожен виклик NtOpenSection, NtMapViewOfSection і, опціонально, NtClose викликав user-mode breakpoint.
  4. Викликає LoadLibrary("amsi.dll") (або будь-яку іншу benign ціль). Коли Windows loader викликає ці syscall-си, VEH пропускає перехід у kernel і повертає дескриптори та базові адреси підготовленого шкідливого образу.

Тому лоадер все ще вважає, що він замапив запитану DLL; інструменти, які дивляться лише на section backing files, бачать wmp.dll, хоча в пам’яті тепер міститься payload атакуючого. Тим часом імпорти/TLS callbacks все ще вирішуються справжнім лоадером, що значно знижує обсяг власної логіки парсингу PE, яку повинен підтримувати противник.

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.

На цьому етапі процес має RWX-здатний view, чиє backing object все ще wmp.dll, але байти в пам’яті контролює атакуючий.

Stage 2 – Hijack the loader with VEHs

  1. Register a VEH and arm hardware breakpoints: запрограмуйте Dr0 (або інший debug register) з адресою ntdll!NtOpenSection і встановіть DR7 так, щоб кожне виконання викликало STATUS_SINGLE_STEP. Пізніше повторіть для NtMapViewOfSection і, опціонально, NtClose.
  2. Trigger DLL loading викликом LoadLibrary("amsi.dll"). LdrLoadDll врешті викличе NtOpenSection, щоб отримати реальний section handle.
  3. VEH hook for NtOpenSection:
  • Знайдіть слот у стеку для аргументу [out] PHANDLE SectionHandle.
  • Запишіть раніше створений дескриптор DecoySection у цей слот.
  • Просуньте RIP/EIP до інструкції ret, щоб виклик в ядро ніколи не відбувся.
  • Перепрограмуйте hardware breakpoint, щоб стежити за NtMapViewOfSection наступним.
  1. VEH hook for NtMapViewOfSection:
  • Перезапишіть [out] PVOID *BaseAddress (і виходи розміру/захисту) адресою вже замапленого шкідливого view.
  • Пропустіть тіло syscall так само, як раніше.
  1. (Optional) VEH hook for NtClose перевіряє, що фейковий section handle очищено, запобігаючи витіканню ресурсів та надаючи фінальну перевірку коректності.

Оскільки syscalls ніколи не виконуються, kernel callbacks (ETWti, minifilter тощо) не бачать підозрілих подій NtOpenSection/NtMapViewOfSection, що різко знижує телеметрію. З точки зору лоадера все пройшло успішно і amsi.dll знаходиться в пам’яті, тому він продовжує вирішувати імпорти/TLS проти view атакуючого.

PoC implementation notes (2025)

Публічний PoC показує кілька практичних деталей, які легко пропустити при повторній реалізації техніки:

  • HWBPs are per-thread. PoC встановлює CONTEXT_DEBUG_REGISTERS на поточному потоці перед викликом LoadLibrary, тож VEH має виконуватися на тому ж потоці, що й ініціює лоадер.
  • Syscall emulation: VEH встановлює RAX = 0 і просуває RIP до ret всередині ntdll-ового stub (сканує на 0xC3), тож перехід у kernel ніколи не відбувається, після чого відновлює виконання через NtContinue.
  • Output parameters: для NtMapViewOfSection VEH перезаписує повернені виходи BaseAddress, ViewSize, та Win32Protect, щоб лоадер вірив, що мапінг пройшов успішно і продовжив роботу з імпортами/TLS використовуючи view атакуючого.

Minimal HWBP setup used by the PoC (x64):

CONTEXT ctx = {0};
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext(GetCurrentThread(), &ctx);
ctx.Dr0 = (DWORD64)NtOpenSection;
ctx.Dr7 = 1;
SetThreadContext(GetCurrentThread(), &ctx);
AddVectoredExceptionHandler(1, VehHandler);

Стелс-варіація

Нещодавні дослідження VEH показують, що обробники можна зареєструвати шляхом ручної маніпуляції списком VEH замість виклику AddVectoredExceptionHandler, що зменшує залежність від user-mode APIs, які можуть бути monitored or hooked. Це не є обов’язковим для Vectored Overloading, але може бути поєднано з ним, щоб зменшити помітну активність API.

Етап 3 – Виконання payload

  • EXE payload: The injector просто переходить до початкової точки входу після завершення relocations. Коли loader вважає, що викличе DllMain, кастомний код натомість виконує EXE-style entry.
  • DLL payload / Node.js addon: Resolve and call the intended export (Kidkadi exposes a named function to JavaScript). Оскільки модуль вже зареєстровано в LdrpModuleBaseAddressIndex, наступні пошуки бачать його як benign DLL.

Коли поєднується з Node.js native addon (.node file), уся складна робота на рівні внутрішніх механізмів Windows залишається поза шаром JavaScript, що дозволяє threat actor постачати той самий loader з багатьма різними обфусцованими Node wrappers.

Посилання

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримайте HackTricks