Page Streaming Loader

Page Streaming is a loader that uses VEH and Guard Pages to de-obfuscate and stream DLL pages into memory as they're needed. As new pages are streamed in, old pages are streamed out. With this technique, only a limited amount of the executing DLL content and resources are visible at any given time.

Project Files

Notes

loader.c is a little different from our other loaders. It finds the GetProcAddress/LoadLibraryA pointers and promptly kicks off a PICO COFF, implemented in guardexec.c.

The COFF guardexec.c handles our DLL loading for us. It's easier to do it here, as it allows the COFF to keep track of our DLL's various sections, and setup the data structures necessary for the page streaming. Find the entry point function go at the bottom and follow along. The code is pretty straight forward otherwise.

This implementation uses PAGE_GUARD permissions to trigger our VEH when our DLL memory is accessed. PAGE_NOACCESS is a viable option too. Also, this implementation attempts to keep section permissions accurate (when restoring the page contents). The benefit is the number of eXecutable pages is limited. I imagine there are circumstances where RWX permissions, preserved in the whole region, and PAGE_GUARD are advantageous (no need to use VirtualProtect).

The #define MAXVISIBLE setting is consequential. This is the maximum number of visible regions at one time. This value can't be one, because data accessing instructions (e.g., any loop), will trigger an exception and page streaming logic for each executed instruction. Two is even too low, as code logic going between two pages, can generate a lot of exceptions. Three seems good in my testing. Limits to visibility come with the cost of execution overhead in this technique.

Like all Tradecraft Garden projects, this implementation assumes the loaded DLL is single-threaded. This implementation does not do any synchronization, but if a memory scanning thread is triggering page streaming events and causes instability, I believe synchronizing on a mutex in the exception handler would make the solution more robust.

Conversation

  • Shellcode Fluctuation (2021) by Mariusz Banach uses these same tools, but in a different way. His POC hooks Sleep() to: obfuscate a Cobalt Strike Beacon payload in memory, flip its pages to PAGE_NOACCESS permissions, and when the Sleep completes--the return to a NO_ACCESS page will fire a VEH where the Beacon is restored.
  • Detecting anomalous Vectored Exception Handlers on Windows (2022) by Ollie Whitehouse walks through how to enumerate and find suspicious looking Vectored Exception Handlers (VEHs). Without extra care, this type of scrutiny would certainly make this implementation stand out.
  • You Can Run, but You Can't Hide - Finding the Footprints of Hidden Shellcode (2023) by John Uhlman discusses using ETW-Ti to detect tradecraft that rely on flipping page permissions.
  • Detecting Injected Code with Page Guards (2023) by Buzzer. Implications of obscure Windows APIs and techniques created with them often have many uses. By this, what one can do with a set of ideas and tools has offense and defense uses. This blog post discusses using guard pages on malicious code memory to aid in unpacking memory-injected malware.

License

This project is licensed under the GNU General Public License version 2 (GPLv2) or later..