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
Project Overview
loader.c is a basic DLL loader. It allocates memory, sets up the DLL, runs our guardexec PICO, and then passes execution to our DLL via the free.c PICO (which frees our loader memory).
The free.c PICO is merged into our guardexec PICO and called via an exported function. See freeandrun.spec for more on this.
This project gets its PIC dfr and fixptrs implementation from the Simple PIC service module.
guardexec.c is where the magic happens. This PICO allocates space for our backup/masked DLL content and sets up the data structures necessary for page streaming. The code is pretty straight forward.
Page Streaming
This implementation uses PAGE_GUARD permissions to trigger our Vectored Exception Handler (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.
- Kong Loader (2024) by Tijme Gommers single steps through an encrypted program, like a debugger. A VEH is used to decrypt the next instruction of the program right before it executes.
- 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 BSD License.