Vectored Overloading PE Injection

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: 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 को patch करने या अपना loader लिखने के बजाय, हमलावर:

  1. एक SEC_IMAGE section बनाता है जिसका backing एक वैध DLL (उदा., wmp.dll) होता है।
  2. mapped view को एक पूरा relocated malicious PE से overwrite करता है लेकिन section object को disk पर मौजूद benign image की ओर point करता रहता है।
  3. एक VEH register करता है और debug registers program करता है ताकि हर कॉल NtOpenSection, NtMapViewOfSection, और आवश्यकता पड़ने पर NtClose पर user-mode breakpoint उठे।
  4. LoadLibrary("amsi.dll") (या कोई अन्य benign target) कॉल करता है। जब Windows loader उन syscalls को invoke करता है, VEH kernel transition को skip कर देता है और तैयार malicious image के handles और base addresses return कर देता है।

क्योंकि loader अभी भी मानता है कि उसने अनुरोधित DLL map किया है, ऐसे tooling जो केवल section backing files देखते हैं उन्हें wmp.dll दिखाई देगा भले ही memory में अब हमलावर का payload हो। साथ ही, imports/TLS callbacks वास्तविक loader द्वारा अभी भी resolve होते हैं, जिससे हमलावर द्वारा बनाए रखने वाला custom PE-parsing logic काफी कम हो जाता है।

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, SizeOfRawData/VirtualSize का पालन करते हुए और बाद में protections update करें (PAGE_EXECUTE_READ, PAGE_READWRITE, आदि)।
  2. Apply relocations and resolve imports बिल्कुल वैसे ही जैसे एक reflective loader करता है। क्योंकि view पहले से SEC_IMAGE के रूप में mapped है, section alignments और guard pages वही होते हैं जो Windows loader बाद में उम्मीद करता है।
  3. Normalize the PE header:
  • अगर payload EXE है, तो IMAGE_FILE_HEADER.Characteristics |= IMAGE_FILE_DLL सेट करें और entry point को zero करें ताकि LdrpCallTlsInitializers EXE-specific stubs में jump न करे।
  • DLL payloads अपने headers अनचेंज्ड रख सकते हैं।

इस बिंदु पर process के पास एक RWX-capable view है जिसका backing object अभी भी wmp.dll है, पर memory में bytes हमलावर के नियंत्रण में हैं।

Stage 2 – Hijack the loader with VEHs

  1. Register a VEH and arm hardware breakpoints: Dr0 (या कोई अन्य debug register) को ntdll!NtOpenSection के address से program करें और DR7 सेट करें ताकि हर execution पर STATUS_SINGLE_STEP आये। बाद में इसी तरह NtMapViewOfSection और आवश्यकता अनुसार NtClose के लिए दोहराएं।
  2. Trigger DLL loading LoadLibrary("amsi.dll") से। LdrLoadDll अंततः वास्तविक section handle प्राप्त करने के लिए NtOpenSection कॉल करेगा।
  3. VEH hook for NtOpenSection:
  • [out] PHANDLE SectionHandle argument के लिए stack slot ढूँढें।
  • उस slot में पहले से बनाई गई DecoySection handle लिख दें।
  • RIP/EIP को ret instruction पर advance करें ताकि kernel कभी कॉल न हो।
  • हार्डवेयर breakpoint को फिर से NtMapViewOfSection देखने के लिए re-arm करें।
  1. VEH hook for NtMapViewOfSection:
  • [out] PVOID *BaseAddress (और size/protection outputs) को पहले से mapped malicious view के address से overwrite करें।
  • syscall body को पहले की तरह skip करें।
  1. (Optional) VEH hook for NtClose यह verify करता है कि fake section handle clean up हो गया है, resource leaks रोकता है और एक अंतिम sanity check प्रदान करता है।

क्योंकि syscalls कभी execute नहीं होते, kernel callbacks (ETWti, minifilter, आदि) suspicious NtOpenSection/NtMapViewOfSection घटनाओं को observe नहीं करते, जिससे telemetry काफी घट जाती है। loader के दृष्टिकोण से सब कुछ सफल रहा और amsi.dll memory में है, इसलिए यह attacker के bytes के खिलाफ imports/TLS resolution के साथ आगे बढ़ता है।

PoC implementation notes (2025)

पब्लिक PoC कुछ व्यावहारिक विवरण दिखाता है जिनको technique को फिर से implement करते समय आसानी से मिस किया जा सकता है:

  • HWBPs are per-thread. PoC CONTEXT_DEBUG_REGISTERS को current thread पर LoadLibrary को कॉल करने से पहले सेट करता है, इसलिए VEH उसी thread पर चलना चाहिए जो loader को trigger करता है।
  • Syscall emulation: VEH RAX = 0 सेट करता है और RIP को ntdll stub के अंदर ret पर advance करता है (यह 0xC3 स्कैन करता है) ताकि kernel transition कभी न हो, फिर NtContinue के साथ resume करता है।
  • Output parameters: NtMapViewOfSection के लिए, VEH returned BaseAddress, ViewSize, और Win32Protect outputs को overwrite करता है ताकि loader मान ले कि mapping सफल हुई और attacker के view का उपयोग करके imports/TLS के साथ आगे बढ़े।

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);

Stealth variation

हालिया VEH रिसर्च यह उजागर करती है कि हैंडलरों को AddVectoredExceptionHandler कॉल करने के बजाय VEH list को मैन्युअली मैनिपुलेट करके रजिस्टर किया जा सकता है, जिससे उन user-mode APIs पर निर्भरता कम हो जाती है जिन्हें मॉनिटर या हुक किया जा सकता है। यह Vectored Overloading के लिए आवश्यक नहीं है, लेकिन observable API activity को कम करने के लिए इसे उसके साथ जोड़ा जा सकता है।

Stage 3 – Execute the payload

  • EXE payload: एक बार relocations हो जाने के बाद injector सरलता से original entry point पर जंप कर देता है। जब loader सोचता है कि वह DllMain कॉल करेगा, तो उसके बजाय custom कोड EXE-style entry को निष्पादित करता है।
  • DLL payload / Node.js addon: इच्छित export को resolve करके कॉल करें (Kidkadi JavaScript को एक named function एक्सपोज़ करता है)। क्योंकि मॉड्यूल पहले ही LdrpModuleBaseAddressIndex के साथ रजिस्टर्ड है, बाद के lookups इसे benign DLL के रूप में देखते हैं।

जब इसे Node.js native addon (.node file) के साथ जोड़ा जाता है, तो सभी Windows-internals से जुड़ा भारी काम JavaScript लेयर के बाहर रहता है, जिससे threat actor को एक ही loader को कई अलग-अलग obfuscated Node wrappers के साथ शिप करना आसान हो जाता है।

संदर्भ

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें