Tuesday, May 12, 2015

Walking the Stack in PowerShell - Part 1

One of the more sophisticated methods of Dynamic Link Library (DLL) injection employs reflective loading to avoid detection. Basically, a chunk of memory is allocated via VirtualAlloc(Ex), a DLL is written to the allocated memory chunk via WriteProcessMemory, and execution begins via Create(Remote)Thread. Since no files are written to disk and the standard LoadLibrary routine isn't used, it's harder to detect this injection technique.

Stephen Fewer's 2008 paper Reflective DLL Injection states:

At a process level the only indicators that the library exists is that their will be a chunk of allocated memory present, via VirtualAlloc, where the loaded library resides. This memory will be marked as readable, writable and executable. Their will also be a thread of execution which will be, periodically at least, executing code from this memory chunk.

Based on that information, there are at least two places to look for reflectively loaded DLLs: process memory and process threads. There are already tools to search the allocated memory of a process for committed pages that aren't referenced by a currently loaded library/module. You could use Sysinternal's Process Explorer to examine currently executing threads, but I'll explain how that might not give conclusive results and doesn't work well when trying to investigate machines over the network.

Walking the Stack isn't a new concept, so I'll only give it a brief overview here. The majority of my work was inspired by jkalmbach's StackWalker project. However, since I'm a PowerShell nut and interested in remote investigations, I wrote a .NET implementation, PowerWalker. Some of the Structs and Enums in my code were copied from Microsoft's MDbg Sample 4.0.

The basic steps to walking a thread's stack are as follows:

Set the _NT_SYMBOL_PATH environment variable to a functioning symbol server.

Initialize the symbol loader via SymInitialize.

Determine the machine's processor type via GetSystemInfo.

Determine the image type of the process via IsWow64Process.

Enumerate the currently loaded modules via EnumProcessModulesEx.

Get the necessary information for each module to load their symbols via SymLoadModuleEx.

Suspend the thread you're going to walk via (Wow64)SuspendThread.

Get the current CONTEXT structure of the thread via (Wow64)GetThreadContext.

Initialize a STACKFRAME64 structure with the offsets from the thread's context.

Pass the Context and Stackframe structures to StackWalk64.

Loop through StackWalk64 until the Return Address equals zero.

Cleanup allocated resources and call SymCleanup.

Resume the thread.

At each iteration through the StackWalk64 function the instruction pointer and return addresses are updated and we can use those as inputs to GetMappedFile. Any address where GetMappedFile returns null, we know that code was not loaded from a file on disk and can assume that it was loaded reflectively. While there are legitimate reasons for code to be loaded reflectively, this gives us a quick vector to investigate further.

To demonstrate this concept lets look at the stack of a reflectively loaded Meterpreter payload using Process Hacker, Process Explorer, and then finally the simple Cmdlet that I wrote.