18 #define KSTACK_PAGE_COUNT_X86 8 19 #define KSTACK_PAGE_COUNT_X64 16 61 QWORD stackPtr = StackFrameStart;
75 if (StackFrameEnd == 0)
80 if (StackFrameStart > StackFrameEnd)
82 WARNING(
"[WARNING] Found a start stack pointer value (0x%llx) greater than the end value (0x%llx).",
83 StackFrameStart, StackFrameEnd);
99 while (StackFrameStart < StackFrameEnd)
109 WARNING(
"[WARNING] Failed to map the stack page %llx : %08x\n",
120 QWORD tableGva, gadget;
124 stackValue = *(
QWORD *)(pStack + i);
128 stackValue = *(
DWORD *)(pStack + i);
133 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside detour %d\n",
134 stackPtr + i, stackValue, detTag);
140 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside mem table for %016llx\n",
141 stackPtr + i, stackValue, tableGva);
147 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside agent trampoline\n",
148 stackPtr + i, stackValue);
154 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside PT Filter\n",
155 stackPtr + i, stackValue);
161 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside the #VE Agent\n",
162 stackPtr + i, stackValue);
168 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside a SWAPGS gadget at 0x%016llx\n",
169 stackPtr + i, stackValue, gadget);
176 StackFrameStart += toCheck;
199 QWORD tableGva, gadget;
203 WARNING(
"[SAFENESS] Live RIP %016llx points inside detour %d\n", Registers->Rip, detTag);
209 WARNING(
"[SAFENESS] Live RIP %016llx points inside mem table for %016llx\n", Registers->Rip, tableGva);
215 WARNING(
"[SAFENESS] Live RIP %016llx points inside agent trampoline\n", Registers->Rip);
221 WARNING(
"[SAFENESS] Live RIP %016llx points inside PT Filter\n", Registers->Rip);
223 IntDumpGva(Registers->Rip, 16, Registers->Cr3);
229 WARNING(
"[SAFENESS] Live RIP %016llx points inside the #VE Agent\n", Registers->Rip);
235 WARNING(
"[SAFENESS] Live RIP 0x%016llx points inside SWAPGS gadget at 0x%016llx\n", Registers->Rip, gadget);
258 QWORD stackPtr = StackFrameStart;
271 if (StackFrameEnd == 0)
276 if (StackFrameStart > StackFrameEnd)
278 WARNING(
"[WARNING] Found a start stack pointer value (0x%llx) greater than the end value (0x%llx).",
279 StackFrameStart, StackFrameEnd);
283 while (StackFrameStart < StackFrameEnd)
296 QWORD stackValue, newValue;
300 stackValue = *(
QWORD *)(pStack + i);
304 stackValue = *(
DWORD *)(pStack + i);
308 if (newValue == stackValue)
313 if (newValue != stackValue)
317 WARNING(
"[WARNING] Moving stack value (@ 0x%016llx) from 0x%016llx to 0x%016llx\n",
318 (stackPtr &
PAGE_MASK) + i, stackValue, newValue);
322 LOG(
"[SAFENESS] @ 0x%016llx we have: 0x%016llx\n", (stackPtr & PAGE_MASK) + i -
gGuest.
WordSize,
328 LOG(
"[SAFENESS] @ 0x%016llx we have: 0x%016llx\n", (stackPtr & PAGE_MASK) + i +
gGuest.
WordSize,
334 *(
QWORD *)(pStack + i) = newValue;
338 *(
DWORD *)(pStack + i) = newValue & 0xffffffff;
345 StackFrameStart += toCheck;
369 if (NULL == Registers)
375 if (newRip == Registers->Rip)
379 if (newRip != Registers->Rip)
381 WARNING(
"[WARNING] Moving live RIP from 0x%016llx 0x%016llx\n", Registers->Rip, newRip);
388 ERROR(
"[ERROR] Failed moving the RIP of the running CPU %d to the new address: 0x%08x\n",
421 UCHAR state, waitReason;
432 WARNING(
"[WARNING] Ethread 0x%016llx is too high in page!\n", Ethread);
439 ERROR(
"[ERROR] IntVirtMemMap failed for VA 0x%016llx: 0x%08x\n", Ethread, status);
444 waitReason = *(pThread +
WIN_KM_FIELD(Thread, WaitReason));
458 LOG(
"[SAFENESS] Thread 0x%016llx is running, will examine it later\n", Ethread);
463 LOG(
"[SAFENESS] Terminated thread 0x%016llx\n", Ethread);
472 LOG(
"[SAFENESS] We have a WAITING thread to examine at 0x%016llx! Reason: %d, State: %d\n",
473 Ethread, waitReason, state);
478 WARNING(
"[WARNING] Thread %016llx has stack at %016llx. Thread was TERMINATED!\n",
479 Ethread, currentStack);
496 ERROR(
"[ERROR] IntThrSafeMoveReturn failed for stack %016llx: %08x\n", currentStack, status);
528 ERROR(
"[ERROR] Failed getting the task's flags from %llx: 0x%08x.\n",
529 TaskStruct +
LIX_FIELD(TaskStruct, Flags), status);
535 LOG(
"[SAFENESS] Ignoring task %llx which is dying: %08x\n", TaskStruct, taskFlags);
545 ERROR(
"[ERROR] IntKernVirtMemFetchQword failed for %llx with status: 0x%08x\n", currentStack, status);
550 ERROR(
"[ERROR] Failed getting the task's stack from %llx: 0x%08x\n",
551 TaskStruct +
LIX_FIELD(TaskStruct, Stack), status);
558 WARNING(
"[WARNING] Task %llx has current stack %llx, with flags %08x\n",
559 TaskStruct, currentStack, taskFlags);
564 currentStack =
ALIGN_UP(currentStack, 8);
579 ERROR(
"[ERROR] IntThrSafeMoveReturn failed for stack 0x%016llx: 0x%08x\n", currentStack, status);
612 stackOffset =
LIX_FIELD(TaskStruct, Stack);
650 WARNING(
"[WARNING] IntWinThrGetCurrentThread failed: 0x%08x\n", status);
660 LOG(
"[ERROR] IntKernVirtMemRead failed for (Ethread: %016llx, KernelStack: 0x%x): 0x%08x\n",
661 currentThread,
WIN_KM_FIELD(Thread, KernelStack), status);
671 LOG(
"[ERROR] IntKernVirtMemRead failed for (Ethread: %016llx, StackBase: 0x%x): 0x%08x\n",
672 currentThread,
WIN_KM_FIELD(Thread, StackBase), status);
682 LOG(
"[ERROR] IntKernVirtMemRead failed for (Ethread: %016llx, StackLimit: 0x%x): 0x%08x\n",
683 currentThread,
WIN_KM_FIELD(Thread, StackLimit), status);
721 LOG(
"[SAFENESS] CPU %u has current stack = 0x%016llx and RSP = 0x%016llx\n", Cpu, currentStack, Regs->Rsp);
723 if (Regs->Rsp < currentStack)
725 toCheck[0] = Regs->Rsp;
726 toCheck[1] = currentStack;
730 toCheck[0] = currentStack;
731 toCheck[1] = Regs->Rsp;
735 if (toCheck[1] - toCheck[0] < maxSize)
743 const QWORD ptr = toCheck[p];
751 LOG(
"[SAFENESS] Will check stack %016llx with RIP %016llx on CPU %u\n", ptr, Regs->Rip, Cpu);
765 ERROR(
"[ERROR] IntThrSafeMoveReturn failed for stack %016llx for CPU %u: 0x%08x\n", ptr, Cpu, status);
795 QWORD stackBase, stackLimit, stackSavedInEthread, low, high;
800 stackSavedInEthread = stackLimit = stackBase = 0;
805 ERROR(
"[ERROR] IntThrSafeWinGetCurrentStack failed on CPU %u: 0x%08x\n", Cpu, status);
809 LOG(
"[SAFENESS] Active thread on CPU %u has stack @ 0x%016llx with base = 0x%016llx " 810 "limit = 0x%016llx RSP = 0x%016llx and RBP = 0x%016llx\n",
811 Cpu, stackSavedInEthread, stackBase, stackLimit, Regs->Rsp, Regs->Rbp);
813 toCheck[0] = Regs->Rsp;
814 toCheck[1] = stackSavedInEthread;
820 if (stackBase > stackLimit)
834 const QWORD ptr = toCheck[p];
840 if (!lowestPtrChecked &&
IN_RANGE(ptr, low, high))
845 lowestPtrChecked =
TRUE;
856 LOG(
"[SAFENESS] Stack pointer 0x%016llx is not on the known Ethread stack [0x%016llx, 0x%016llx)!\n",
873 ERROR(
"[ERROR] IntThrSafeMoveReturn failed for stack %016llx for CPU %u: 0x%08x\n", ptr, Cpu, status);
907 ERROR(
"[ERROR] IntGetGprs failed for CPU %u: 0x%08x\n", c, status);
913 LOG(
"[CPU %u] Is inactive, will not check anything!\n", c);
920 TRACE(
"[INFO] CPU %u, RIP 0x%016llx is in user-mode... We can safely ignore it\n", c, regs.
Rip);
924 TRACE(
"[INFO] Cpu %u, RIP 0x%016llx, will continue checking\n", c, regs.
Rip);
930 WARNING(
"[SAFENESS] IntThrSafeIsLiveRIPInIntro failed for CPU %u\n", c);
939 ERROR(
"[ERROR] Failed moving RIP %016llx on CPU %u: 0x%08x\n", regs.
Rip, c, status);
948 ERROR(
"[ERROR] IntThrSafeWinInspectRunningThreadOnCpu failed for CPU %u: 0x%08x\n", c, status);
959 ERROR(
"[ERROR] IntThrSafeLixInspectRunningThreadOnCpu failed for CPU %u: 0x%08x\n", c, status);
1017 ERROR(
"[ERROR] IntThrSafeInspectRunningThreads failed: 0x%08x\n", status);
1049 ERROR(
"[ERROR] Failed iterating processes and threads: 0x%08x\n", status);
BOOLEAN IntPtiIsPtrInAgent(QWORD Ptr, THS_PTR_TYPE Type)
Check if an address points inside the PT filter. Ignore non-executable sections when doing so...
#define THS_CHECK_SWAPGS
Will check if any RIP is inside a mitigated SWAPGS gadget.
static INTSTATUS IntThrSafeMoveRip(IG_ARCH_REGS *Registers, DWORD CpuNumber)
Will check if it is safe for Introcore to modify the RIP value.
LIX_OPAQUE_FIELDS OsSpecificFields
OS-dependent and specific information.
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
#define THS_CHECK_PTFILTER
Will check if any RIP is inside the PT filter agent.
static INTSTATUS IntThrSafeWinInspectWaitingFromGuestList(QWORD Eprocess, QWORD Options)
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
QWORD SystemCr3
The Cr3 used to map the kernel.
#define INT_STATUS_SUCCESS
INTSTATUS IntThrSafeCheckThreads(QWORD Options)
Checks if any of the guest threads have their RIP or have any stack pointers pointing to regions of c...
#define PAGE_REMAINING(addr)
BOOLEAN IntMtblIsPtrInReloc(QWORD Ptr, THS_PTR_TYPE Type, QWORD *Table)
Check if the given pointer is inside a mem-table relocation handler.
INTSTATUS IntGetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Get the current guest GPR state.
static BOOLEAN gSafeToUnload
QWORD Gva
The guest virtual address of the task_struct.
#define INT_SUCCESS(Status)
INTSTATUS IntWinThrGetCurrentThread(DWORD CpuNumber, QWORD *EthreadAddress)
Get the ETHREAD structure address of the thread currently running on the given CPU.
void UtilSortQwords(PQWORD Array, const DWORD NumberOfElements)
#define INT_STATUS_NOT_NEEDED_HINT
int INTSTATUS
The status data type.
#define INT_STATUS_NOT_FOUND
DWORD ThreadStructOffset
The offset of the thread_struct from task_struct.
#define KSTACK_PAGE_COUNT_X86
Stack page count to check on 32-bit systems.
INTRO_GUEST_TYPE OSType
The type of the guest.
#define INT_STATUS_BREAK_ITERATION
Can be used by iteration callbacks to break the iteration early.
BOOLEAN IntSwapgsIsPtrInHandler(QWORD Ptr, THS_PTR_TYPE Type, QWORD *Gadget)
Check if a pointer points inside a SWAPGS handler.
Exposes the functions used to provide Windows Threads related support.
static INTSTATUS IntThrSafeMoveReturn(QWORD StackFrameStart, QWORD StackFrameEnd)
Will check if it is safe for Introcore to move the return value on the stack.
INTSTATUS IntLixTaskIterateGuestTasks(PFUNC_IterateListCallback Callback, QWORD Aux)
Iterates the guest process list and calls the provided callback for each process and thread found...
#define INT_STATUS_CANNOT_UNLOAD
Indicates that Introcore can not unload in a safely manner.
static INTSTATUS IntThrSafeWinInspectWaitingThread(QWORD Ethread, QWORD Options)
Inspects a waiting thread from a Windows guest.
INTSTATUS IntKernVirtMemFetchDword(QWORD GuestVirtualAddress, DWORD *Data)
Reads 4 bytes from the guest kernel memory.
#define IS_KERNEL_POINTER_LIX(p)
#define INT_STATUS_NOT_INITIALIZED
INTSTATUS IntKernVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD *Data)
Reads 8 bytes from the guest kernel memory.
static INTSTATUS IntThrSafeLixInspectRunningThreadOnCpu(DWORD Cpu, const IG_ARCH_REGS *Regs, QWORD Options)
Inspects the running threads of a VCPU.
#define IN_RANGE(x, start, end)
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
QWORD IntSwapgsRelocatePtrIfNeeded(QWORD Ptr)
Relocate a pointer if it points inside a SWAPGS gadget, and make it point inside the installed handle...
BOOLEAN IntAgentIsPtrInTrampoline(QWORD Ptr, THS_PTR_TYPE Type)
Check if the provided pointer points inside the Windows trampoline code.
#define IS_KERNEL_POINTER_WIN(is64, p)
Checks if a guest virtual address resides inside the Windows kernel address space.
BOOLEAN GuestInitialized
True if the OS-specific portion has been initialized.
#define LIX_FIELD(Structure, Field)
Macro used to access fields inside the LIX_OPAQUE_FIELDS structure.
BOOLEAN IntDetIsPtrInHandler(QWORD Ptr, THS_PTR_TYPE Type, DETOUR_TAG *Tag)
Checks if a guest pointer is inside a detour handler.
INTSTATUS IntWinProcIterateGuestProcesses(PFUNC_IterateListCallback Callback, QWORD Aux)
Iterates the in-guest process list and calls Callback for each entry.
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
static BOOLEAN IntThrSafeIsLiveRIPInIntro(const IG_ARCH_REGS *Registers, QWORD Options)
Checks if the RIP on one of the guests VCPU points inside an Introcore owned code section...
DWORD CpuCount
The number of logical CPUs.
#define WIN_KM_FIELD(Structure, Field)
Macro used to access kernel mode fields inside the WIN_OPAQUE_FIELDS structure.
static DWORD IntThrGetStackSize(QWORD Rsp)
#define THS_CHECK_DETOURS
Will check if any RIP is inside detours.
static INTSTATUS IntThrSafeLixInspectWaitingThread(QWORD TaskStruct, QWORD Options)
Inspects a waiting thread from a Linux guest.
static INTSTATUS IntThrSafeWinInspectRunningThreadOnCpu(DWORD Cpu, const IG_ARCH_REGS *Regs, QWORD Options)
Inspects the running threads of a VCPU.
#define THS_CHECK_VEFILTER
Will check if any RIP is inside the VE filter agent.
#define KSTACK_PAGE_COUNT_X64
Stack page count to check on 64-bit systems.
BOOLEAN IntVeIsPtrInAgent(QWORD Ptr, THS_PTR_TYPE Type)
Check if an address points inside the VE agent.
INTSTATUS IntSetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Sets the values of the guest GPRs.
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
INTSTATUS IntLixTaskGetCurrentTaskStruct(DWORD CpuNumber, QWORD *TaskStruct)
Reads the guest virtual address of the task currently running on a CPU.
GUEST_STATE gGuest
The current guest state.
#define FIX_GUEST_POINTER(is64, x)
Masks the unused part of a Windows guest virtual address.
TIMER_FRIENDLY void IntDumpGva(QWORD Gva, DWORD Length, QWORD Cr3)
This function is a wrapper over IntDumpGvaEx (it uses RowLength = 16, ElementLength = 1...
#define THS_CHECK_ONLY
Will check for safeness, without moving any RIP or stack value.
DWORD RemainingSections
The number of kernel sections not yet read into KernelBuffer.
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
static BOOLEAN IntThrSafeIsStackPtrInIntro(QWORD StackFrameStart, QWORD StackFrameEnd, QWORD Options, QWORD ProcessGva)
Checks if a pointer from the stack points to a section of code injected or modified by Introcore insi...
#define THS_CHECK_TRAMPOLINE
Will check if any RIP is inside the agent loader.
static INTSTATUS IntThrSafeWinGetCurrentStack(DWORD CpuNumber, QWORD *CurrentStack, QWORD *StackBase, QWORD *StackLimit)
Get the current stack values for a VCPU for a Windows guest.
#define INT_STATUS_INVALID_PARAMETER_1
#define INT_STATUS_NOT_SUPPORTED
VCPU_STATE * gVcpu
The state of the current VCPU.
LIX_TASK_OBJECT * IntLixTaskGetCurrent(DWORD CpuNumber)
Finds the task that is currently running on the given CPU.
QWORD IntDetRelocatePtrIfNeeded(QWORD Ptr)
Returns the new value Ptr should have if it is currently pointing inside a relocated prologue...
static INTSTATUS IntThrSafeInspectRunningThreads(QWORD Options)
Inspects the currently running threads.
QWORD LixProcessGva
The guest virtual address of the running task on the current vCPU (valid only for Linux / thread safe...
DETOUR_TAG
Unique tag used to identify a detour.
INTSTATUS IntWinThrIterateThreads(QWORD Eprocess, PFUNC_IterateListCallback Callback, QWORD Aux)
Iterate all the threads of the given process and invoke the callback for each one of them...
#define THS_CHECK_MEMTABLES
Will check if any RIP is inside memtables.
#define INT_STATUS_INVALID_PARAMETER_2
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
static INTSTATUS IntThrSafeLixGetCurrentStack(DWORD CpuNumber, QWORD *Stack)
Get the current stack value for a VCPU for a Linux guest.