Bitdefender Hypervisor Memory Introspection
winstack.c File Reference
#include "winstack.h"
#include "decoder.h"
#include "drivers.h"
#include "guests.h"
#include "introcpu.h"
#include "winpe.h"
#include "winummodule.h"
#include "winthread.h"
#include "swapmem.h"

Go to the source code of this file.

Macros

#define TRAPFRAME_MAX_ITERATIONS   0x100
 

Functions

static INTSTATUS IntStackAnalyzePointer (QWORD Gva, QWORD *CallAddress)
 Get the address of the kernel function that was called in order to push Gva on the stack as a return address. More...
 
static INTSTATUS IntWinStackTraceGet64 (QWORD Rsp, QWORD Rip, DWORD MaxTraces, QWORD Flags, STACK_TRACE *StackTrace)
 Get a kernel stack trace starting from the current stack pointer for 64 bit systems. More...
 
static INTSTATUS IntWinStackTraceGet32 (DWORD Stack, DWORD Eip, DWORD MaxNumberOfTraces, QWORD Flags, STACK_TRACE *StackTrace)
 Get a kernel stack trace starting from the current stack pointer for 32 bit systems. More...
 
INTSTATUS IntWinStackTraceGet (QWORD StackFrame, QWORD Rip, DWORD MaxNumberOfTraces, QWORD Flags, STACK_TRACE *StackTrace)
 Get a kernel stack trace starting from the current stack pointer for 64 bit systems. More...
 
static INTSTATUS IntWinStackTraceGetUser32 (PIG_ARCH_REGS Registers, PWIN_PROCESS_OBJECT Process, DWORD MaxNumberOfTraces, STACK_TRACE *StackTrace)
 Get the user stack trace of a 32 bit windows process. More...
 
static INTSTATUS IntWinStackTraceGetUser64 (PIG_ARCH_REGS Registers, PWIN_PROCESS_OBJECT Process, DWORD MaxNumberOfTraces, QWORD Remaining, STACK_TRACE *StackTrace)
 Get the user stack trace of a 64 bit windows process. More...
 
static INTSTATUS IntWinStackHandleUserStackPagedOut (WIN_PROCESS_OBJECT *Process, QWORD *Remaining)
 Handles the case when the stack is needed but is swapped out. More...
 
INTSTATUS IntWinStackTraceGetUser (PIG_ARCH_REGS Registers, PWIN_PROCESS_OBJECT Process, DWORD MaxNumberOfTraces, STACK_TRACE *StackTrace)
 Get the user stack trace of a windows process. More...
 
INTSTATUS IntWinStackUserCheckIsPivoted (QWORD UserRsp, DWORD SegCs, BOOLEAN IsWow64Stack, DPI_EXTRA_INFO *DpiExtraInfo, BOOLEAN *IsPivoted)
 Check whether the stack is pivoted by checking if it's in the bounds of the stack base and limit from the TIB. More...
 
static INTSTATUS IntWinStackUserTrapFrameGet64 (QWORD KernelStack, DPI_EXTRA_INFO *DpiExtraInfo, KTRAP_FRAME64 *TrapFrame)
 Get a 64 bit trap frame from a kernel stack. More...
 
static INTSTATUS IntWinStackUserTrapFrameGet32 (DWORD KernelStack, DPI_EXTRA_INFO *DpiExtraInfo, KTRAP_FRAME32 *TrapFrame)
 Get a 32 bit trap frame from a kernel stack. More...
 
INTSTATUS IntWinStackUserTrapFrameGetGeneric (QWORD *UserRsp, DWORD *SegCs, BOOLEAN Fallback, DPI_EXTRA_INFO *DpiExtraInfo)
 Get a bit trap frame from a kernel stack. More...
 
INTSTATUS IntWinStackWow64CheckIsPivoted (WIN_PROCESS_OBJECT *Process, WIN_PROCESS_OBJECT *RealParent, DPI_EXTRA_INFO *DpiExtraInfo)
 Check whether a wow64 process' stack is pivoted. More...
 
BOOLEAN IntWinIsUmTrapFrame (void *TrapFrame)
 Checks whether a TrapFrame is valid or not. More...
 

Macro Definition Documentation

◆ TRAPFRAME_MAX_ITERATIONS

#define TRAPFRAME_MAX_ITERATIONS   0x100

Definition at line 16 of file winstack.c.

Referenced by IntWinStackUserTrapFrameGetGeneric().

Function Documentation

◆ IntStackAnalyzePointer()

static INTSTATUS IntStackAnalyzePointer ( QWORD  Gva,
QWORD CallAddress 
)
static

Get the address of the kernel function that was called in order to push Gva on the stack as a return address.

Parameters
[in]GvaThe return address.
[out]CallAddressThe address of the called function.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

TRACE("[STACK] Op type not supported: %d\n", instruction.Operands[0].Type);

Definition at line 20 of file winstack.c.

Referenced by IntWinStackTraceGet32(), and IntWinStackTraceGet64().

◆ IntWinIsUmTrapFrame()

BOOLEAN IntWinIsUmTrapFrame ( void *  TrapFrame)

Checks whether a TrapFrame is valid or not.

Parameters
[in]TrapFramePointer to a trap frame to be checked.
Returns
TRUE if the trap frame is valid, FALSE otherwise.

Definition at line 2283 of file winstack.c.

Referenced by IntWinStackUserTrapFrameGet32(), IntWinStackUserTrapFrameGet64(), and IntWinStackUserTrapFrameGetGeneric().

◆ IntWinStackHandleUserStackPagedOut()

static INTSTATUS IntWinStackHandleUserStackPagedOut ( WIN_PROCESS_OBJECT Process,
QWORD Remaining 
)
static

Handles the case when the stack is needed but is swapped out.

When checking for the return modules in some certain cases, such as writes from memcpy-like functions, we will need the return module in order to match the exceptions, as the caller should be excepted instead of the memcpy function. But, in the case when the stack is swapped out, we would most probably raise some false positives, as the return module cannot be fetched and the exceptions will not match on these violations. For this purpose, when the exception mechanism returns INT_STATUS_STACK_SWAPPED_OUT, this function should be called. This function will check if the stack is inside the known limits (fetched from TIB), and will inject a page-fault in order to force the OS to swap in the stack. The caller must retry the instruction which caused the violation when this function succeeds, as, on retrying, the stack should be in memory. Note that, sometimes we would need the next page as well in order to get a correct stack trace. For this purpose, we will get the current VAD containing the stack and inject a page fault either up until the end of the VAD, or up until the next page after the one containing the RSP. If there doesn't exist such a VAD then we will not inject any page faults, so the presence of a VAD for the current stack is also a form of validation.

Parameters
[in]ProcessThe process in which the stack swapped out corner case took place.
[out]RemainingIf the function succeeds, will contain the number of bytes which are accessible starting from the current RSP.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_DATA_VALUEIf the stack is a kernel pointer.
INT_STATUS_NOT_NEEDED_HINTIf we are in the context of another process, in the case of shared memory, indicating that no action needs to be done for this process.
INT_STATUS_STACK_SWAPPED_OUTIf a #PF was injected, either for the TIB or the stack, signaling that the current instruction must be retried.

Definition at line 1462 of file winstack.c.

Referenced by IntWinStackTraceGetUser().

◆ IntWinStackTraceGet()

INTSTATUS IntWinStackTraceGet ( QWORD  StackFrame,
QWORD  Rip,
DWORD  MaxNumberOfTraces,
QWORD  Flags,
STACK_TRACE StackTrace 
)

Get a kernel stack trace starting from the current stack pointer for 64 bit systems.

Parameters
[in]StackFrameThe current stack frame (EBP on x86, RSP on x86_64).
[in]RipThe current instruction pointer ( ignored on x86).
[in]MaxNumberOfTracesMaximum number of stack traces to get.
[in]FlagsCan be either STACK_FLG_ONLY_DRIVER_ADDRS or STACK_FLG_FAST_GET.
[in,out]StackTraceA caller initialized STACK_TRACE structure that will hold the stack trace.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 1164 of file winstack.c.

Referenced by IntExceptWinKernelGetOriginator().

◆ IntWinStackTraceGet32()

static INTSTATUS IntWinStackTraceGet32 ( DWORD  Stack,
DWORD  Eip,
DWORD  MaxNumberOfTraces,
QWORD  Flags,
STACK_TRACE StackTrace 
)
static

Get a kernel stack trace starting from the current stack pointer for 32 bit systems.

Simplest algorithm. EBP[0] = next stack frame, EBP[1] = return address, EBP[2..] = parameters

If the function doesn't use the x86 stack convention, will just skip it... Either way, the old method failed too if the EBP wasn't used as a stack pointer. From what I saw, the windows kernel drivers are respecting the stack convention. If it fails for a 3rd party driver, we will have no way but to except it through exceptions.bin.

Parameters
[in]StackStack frame pointer from where to start searching.
[in]EipInstruction pointer from where to start searching.
[in]MaxNumberOfTracesMaximum number of stack traces to get.
[in]FlagsCan be either STACK_FLG_ONLY_DRIVER_ADDRS or STACK_FLG_FAST_GET.
[in,out]StackTraceA caller initialized STACK_TRACE structure that will hold the stack trace.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 985 of file winstack.c.

Referenced by IntWinStackTraceGet().

◆ IntWinStackTraceGet64()

static INTSTATUS IntWinStackTraceGet64 ( QWORD  Rsp,
QWORD  Rip,
DWORD  MaxTraces,
QWORD  Flags,
STACK_TRACE StackTrace 
)
static

Get a kernel stack trace starting from the current stack pointer for 64 bit systems.

This is the same method WinDbg uses. It parses the internal windows structures _RUNTIME_FUNCTION and _UNWIND_INFO to see how may stack space each function needs (just the prologue which contains push registers and sub rsp, value). A further check it's still needed because we don't know how many parameters each function has on the stack.

Parameters
[in]RspStack frame pointer from where to start searching.
[in]RipInstruction pointer from where to start searching.
[in]MaxTracesMaximum number of stack traces to get.
[in]FlagsCan be either STACK_FLG_ONLY_DRIVER_ADDRS or STACK_FLG_FAST_GET.
[in,out]StackTraceA caller initialized STACK_TRACE structure that will hold the stack trace.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 208 of file winstack.c.

Referenced by IntWinStackTraceGet().

◆ IntWinStackTraceGetUser()

INTSTATUS IntWinStackTraceGetUser ( PIG_ARCH_REGS  Registers,
PWIN_PROCESS_OBJECT  Process,
DWORD  MaxNumberOfTraces,
STACK_TRACE StackTrace 
)

Get the user stack trace of a windows process.

Parameters
[in]RegistersPointer to a structure containing registers of the current CPU.
[in]ProcessPointer to the process from which to get the stack trace.
[in]MaxNumberOfTracesMaximum number of stack traces to get.
[in,out]StackTraceA caller initialized STACK_TRACE structure that will hold the stack trace.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 1604 of file winstack.c.

Referenced by IntExceptUserGetExecOriginator(), and IntExceptUserHandleMemoryFunctions().

◆ IntWinStackTraceGetUser32()

static INTSTATUS IntWinStackTraceGetUser32 ( PIG_ARCH_REGS  Registers,
PWIN_PROCESS_OBJECT  Process,
DWORD  MaxNumberOfTraces,
STACK_TRACE StackTrace 
)
static

Get the user stack trace of a 32 bit windows process.

Parameters
[in]RegistersPointer to a structure containing registers of the current CPU.
[in]ProcessPointer to the process from which to get the stack trace.
[in]MaxNumberOfTracesMaximum number of stack traces to get.
[in,out]StackTraceA caller initialized STACK_TRACE structure that will hold the stack trace.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 1195 of file winstack.c.

Referenced by IntWinStackTraceGetUser().

◆ IntWinStackTraceGetUser64()

static INTSTATUS IntWinStackTraceGetUser64 ( PIG_ARCH_REGS  Registers,
PWIN_PROCESS_OBJECT  Process,
DWORD  MaxNumberOfTraces,
QWORD  Remaining,
STACK_TRACE StackTrace 
)
static

Get the user stack trace of a 64 bit windows process.

Parameters
[in]RegistersPointer to a structure containing registers of the current CPU.
[in]ProcessPointer to the process from which to get the stack trace.
[in]MaxNumberOfTracesMaximum number of stack traces to get.
[in]RemainingNumber of bytes that can be accessed starting from the current RSP.
[in,out]StackTraceA caller initialized STACK_TRACE structure that will hold the stack trace.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 1361 of file winstack.c.

Referenced by IntWinStackTraceGetUser().

◆ IntWinStackUserCheckIsPivoted()

INTSTATUS IntWinStackUserCheckIsPivoted ( QWORD  UserRsp,
DWORD  SegCs,
BOOLEAN  IsWow64Stack,
DPI_EXTRA_INFO DpiExtraInfo,
BOOLEAN IsPivoted 
)

Check whether the stack is pivoted by checking if it's in the bounds of the stack base and limit from the TIB.

Parameters
[in]UserRspThe current user stack pointer.
[in]SegCsThe CS selector, can be any of the CODE_SEG_UM_32_GUEST_64, CODE_SEG_UM_64_GUEST_64, or CODE_SEG_UM_32_GUEST_32.
[in]IsWow64StackTrue if this is a Wow64 stack.
[in,out]DpiExtraInfoPointer to a caller allocated DPI_EXTRA_INFO structure that will have the stack base and limit fields set upon success.
[out]IsPivotedWill be set to TRUE if the stack is pivoted, FALSE otherwise.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 1741 of file winstack.c.

Referenced by IntWinDpiValidatePivotedStack(), and IntWinStackWow64CheckIsPivoted().

◆ IntWinStackUserTrapFrameGet32()

static INTSTATUS IntWinStackUserTrapFrameGet32 ( DWORD  KernelStack,
DPI_EXTRA_INFO DpiExtraInfo,
KTRAP_FRAME32 TrapFrame 
)
static

Get a 32 bit trap frame from a kernel stack.

Will parse the current KM stack for the trap frame. We will check some fields in TrapFrame to validate it.

Parameters
[in]KernelStackThe kernel stack from which to start searching for the trap frame.
[in,out]DpiExtraInfoPointer to a caller allocated DPI_EXTRA_INFO structure. It will have the DpiPivotedStackExtraInfo.TrapFrameAddress set accordingly upon success.
[out]TrapFramePointer to a caller allocated KTRAP_FRAME32 structure that will hold the trap frame.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 1942 of file winstack.c.

Referenced by IntWinStackUserTrapFrameGetGeneric().

◆ IntWinStackUserTrapFrameGet64()

static INTSTATUS IntWinStackUserTrapFrameGet64 ( QWORD  KernelStack,
DPI_EXTRA_INFO DpiExtraInfo,
KTRAP_FRAME64 TrapFrame 
)
static

Get a 64 bit trap frame from a kernel stack.

Will parse the current KM stack for the trap frame. We will check some fields in TrapFrame to validate it.

Parameters
[in]KernelStackThe kernel stack from which to start searching for the trap frame.
[in,out]DpiExtraInfoPointer to a caller allocated DPI_EXTRA_INFO structure. It will have the DpiPivotedStackExtraInfo.TrapFrameAddress set accordingly upon success.
[out]TrapFramePointer to a caller allocated KTRAP_FRAME64 structure that will hold the trap frame.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 1865 of file winstack.c.

Referenced by IntWinStackUserTrapFrameGetGeneric().

◆ IntWinStackUserTrapFrameGetGeneric()

INTSTATUS IntWinStackUserTrapFrameGetGeneric ( QWORD UserRsp,
DWORD SegCs,
BOOLEAN  Fallback,
DPI_EXTRA_INFO DpiExtraInfo 
)

Get a bit trap frame from a kernel stack.

Will also set the DpiExtraInfo DpiPivotedStackExtraInfo.TrapFrameAddress and DpiPivotedStackExtraInfo.CurrentStack fields accordingly upon success.

Parameters
[out]UserRspWill hold the current user space stack pointer.
[out]SegCsWill be set to any of the CODE_SEG_UM_32_GUEST_64, CODE_SEG_UM_64_GUEST_64, or CODE_SEG_UM_32_GUEST_32 accordingly.
[in]FallbackIf TRUE and we fail getting a valid trap frame, will search on the user stack.
[in,out]DpiExtraInfoPointer to a caller allocated DPI_EXTRA_INFO structure.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 2020 of file winstack.c.

Referenced by IntWinDpiValidatePivotedStack().

◆ IntWinStackWow64CheckIsPivoted()

INTSTATUS IntWinStackWow64CheckIsPivoted ( WIN_PROCESS_OBJECT Process,
WIN_PROCESS_OBJECT RealParent,
DPI_EXTRA_INFO DpiExtraInfo 
)

Check whether a wow64 process' stack is pivoted.

Will set the CreationInfo field of the Process accordingly upon success.

Parameters
[in]ProcessThe process whose stack to be checked.
[in]RealParentThe process' parent.
[in,out]DpiExtraInfoPointer to a caller allocated DPI_EXTRA_INFO structure.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 2203 of file winstack.c.

Referenced by IntWinDpiValidatePivotedStack().