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);
141 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside mem table for %016llx\n",
142 stackPtr + i, stackValue, tableGva);
149 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside agent trampoline\n",
150 stackPtr + i, stackValue);
157 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside PT Filter\n",
158 stackPtr + i, stackValue);
165 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside the #VE Agent\n",
166 stackPtr + i, stackValue);
173 WARNING(
"[SAFENESS] Stack value @ %016llx (= %016llx) points inside a SWAPGS gadget at 0x%016llx\n",
174 stackPtr + i, stackValue, gadget);
182 StackFrameStart += toCheck;
205 QWORD tableGva, gadget;
209 WARNING(
"[SAFENESS] Live RIP %016llx points inside detour %d\n", Registers->Rip, detTag);
215 WARNING(
"[SAFENESS] Live RIP %016llx points inside mem table for %016llx\n", Registers->Rip, tableGva);
221 WARNING(
"[SAFENESS] Live RIP %016llx points inside agent trampoline\n", Registers->Rip);
227 WARNING(
"[SAFENESS] Live RIP %016llx points inside PT Filter\n", Registers->Rip);
229 IntDumpGva(Registers->Rip, 16, Registers->Cr3);
235 WARNING(
"[SAFENESS] Live RIP %016llx points inside the #VE Agent\n", Registers->Rip);
241 WARNING(
"[SAFENESS] Live RIP 0x%016llx points inside SWAPGS gadget at 0x%016llx\n", Registers->Rip, gadget);
264 QWORD stackPtr = StackFrameStart;
277 if (StackFrameEnd == 0)
282 if (StackFrameStart > StackFrameEnd)
284 WARNING(
"[WARNING] Found a start stack pointer value (0x%llx) greater than the end value (0x%llx).",
285 StackFrameStart, StackFrameEnd);
289 while (StackFrameStart < StackFrameEnd)
302 QWORD stackValue, newValue;
306 stackValue = *(
QWORD *)(pStack + i);
310 stackValue = *(
DWORD *)(pStack + i);
314 if (newValue == stackValue)
319 if (newValue != stackValue)
323 WARNING(
"[WARNING] Moving stack value (@ 0x%016llx) from 0x%016llx to 0x%016llx\n",
324 (stackPtr &
PAGE_MASK) + i, stackValue, newValue);
328 LOG(
"[SAFENESS] @ 0x%016llx we have: 0x%016llx\n", (stackPtr & PAGE_MASK) + i -
gGuest.
WordSize,
334 LOG(
"[SAFENESS] @ 0x%016llx we have: 0x%016llx\n", (stackPtr & PAGE_MASK) + i +
gGuest.
WordSize,
340 *(
QWORD *)(pStack + i) = newValue;
344 *(
DWORD *)(pStack + i) = newValue & 0xffffffff;
351 StackFrameStart += toCheck;
375 if (NULL == Registers)
381 if (newRip == Registers->Rip)
385 if (newRip != Registers->Rip)
387 WARNING(
"[WARNING] Moving live RIP from 0x%016llx 0x%016llx\n", Registers->Rip, newRip);
394 ERROR(
"[ERROR] Failed moving the RIP of the running CPU %d to the new address: 0x%08x\n",
427 UCHAR state, waitReason;
438 WARNING(
"[WARNING] Ethread 0x%016llx is too high in page!\n", Ethread);
445 ERROR(
"[ERROR] IntVirtMemMap failed for VA 0x%016llx: 0x%08x\n", Ethread, status);
450 waitReason = *(pThread +
WIN_KM_FIELD(Thread, WaitReason));
464 LOG(
"[SAFENESS] Thread 0x%016llx is running, will examine it later\n", Ethread);
469 LOG(
"[SAFENESS] Terminated thread 0x%016llx\n", Ethread);
478 LOG(
"[SAFENESS] We have a WAITING thread to examine at 0x%016llx! Reason: %d, State: %d\n",
479 Ethread, waitReason, state);
484 WARNING(
"[WARNING] Thread %016llx has stack at %016llx. Thread was TERMINATED!\n",
485 Ethread, currentStack);
502 ERROR(
"[ERROR] IntThrSafeMoveReturn failed for stack %016llx: %08x\n", currentStack, status);
534 ERROR(
"[ERROR] Failed getting the task's flags from %llx: 0x%08x.\n",
535 TaskStruct +
LIX_FIELD(TaskStruct, Flags), status);
541 LOG(
"[SAFENESS] Ignoring task %llx which is dying: %08x\n", TaskStruct, taskFlags);
551 ERROR(
"[ERROR] IntKernVirtMemFetchQword failed for %llx with status: 0x%08x\n", currentStack, status);
556 ERROR(
"[ERROR] Failed getting the task's stack from %llx: 0x%08x\n",
557 TaskStruct +
LIX_FIELD(TaskStruct, Stack), status);
564 WARNING(
"[WARNING] Task %llx has current stack %llx, with flags %08x\n",
565 TaskStruct, currentStack, taskFlags);
570 currentStack =
ALIGN_UP(currentStack, 8);
585 ERROR(
"[ERROR] IntThrSafeMoveReturn failed for stack 0x%016llx: 0x%08x\n", currentStack, status);
618 stackOffset =
LIX_FIELD(TaskStruct, Stack);
656 WARNING(
"[WARNING] IntWinThrGetCurrentThread failed: 0x%08x\n", status);
666 LOG(
"[ERROR] IntKernVirtMemRead failed for (Ethread: %016llx, KernelStack: 0x%x): 0x%08x\n",
667 currentThread,
WIN_KM_FIELD(Thread, KernelStack), status);
677 LOG(
"[ERROR] IntKernVirtMemRead failed for (Ethread: %016llx, StackBase: 0x%x): 0x%08x\n",
678 currentThread,
WIN_KM_FIELD(Thread, StackBase), status);
688 LOG(
"[ERROR] IntKernVirtMemRead failed for (Ethread: %016llx, StackLimit: 0x%x): 0x%08x\n",
689 currentThread,
WIN_KM_FIELD(Thread, StackLimit), status);
727 LOG(
"[SAFENESS] CPU %u has current stack = 0x%016llx and RSP = 0x%016llx\n", Cpu, currentStack, Regs->Rsp);
729 if (Regs->Rsp < currentStack)
731 toCheck[0] = Regs->Rsp;
732 toCheck[1] = currentStack;
736 toCheck[0] = currentStack;
737 toCheck[1] = Regs->Rsp;
741 if (toCheck[1] - toCheck[0] < maxSize)
749 const QWORD ptr = toCheck[p];
757 LOG(
"[SAFENESS] Will check stack %016llx with RIP %016llx on CPU %u\n", ptr, Regs->Rip, Cpu);
771 ERROR(
"[ERROR] IntThrSafeMoveReturn failed for stack %016llx for CPU %u: 0x%08x\n", ptr, Cpu, status);
801 QWORD stackBase, stackLimit, stackSavedInEthread, low, high;
806 stackSavedInEthread = stackLimit = stackBase = 0;
811 ERROR(
"[ERROR] IntThrSafeWinGetCurrentStack failed on CPU %u: 0x%08x\n", Cpu, status);
815 LOG(
"[SAFENESS] Active thread on CPU %u has stack @ 0x%016llx with base = 0x%016llx " 816 "limit = 0x%016llx RSP = 0x%016llx and RBP = 0x%016llx\n",
817 Cpu, stackSavedInEthread, stackBase, stackLimit, Regs->Rsp, Regs->Rbp);
819 toCheck[0] = Regs->Rsp;
820 toCheck[1] = stackSavedInEthread;
826 if (stackBase > stackLimit)
840 const QWORD ptr = toCheck[p];
846 if (!lowestPtrChecked &&
IN_RANGE(ptr, low, high))
851 lowestPtrChecked =
TRUE;
862 LOG(
"[SAFENESS] Stack pointer 0x%016llx is not on the known Ethread stack [0x%016llx, 0x%016llx)!\n",
879 ERROR(
"[ERROR] IntThrSafeMoveReturn failed for stack %016llx for CPU %u: 0x%08x\n", ptr, Cpu, status);
913 ERROR(
"[ERROR] IntGetGprs failed for CPU %u: 0x%08x\n", c, status);
919 LOG(
"[CPU %u] Is inactive, will not check anything!\n", c);
926 TRACE(
"[INFO] CPU %u, RIP 0x%016llx is in user-mode... We can safely ignore it\n", c, regs.
Rip);
930 TRACE(
"[INFO] Cpu %u, RIP 0x%016llx, will continue checking\n", c, regs.
Rip);
936 WARNING(
"[SAFENESS] IntThrSafeIsLiveRIPInIntro failed for CPU %u\n", c);
945 ERROR(
"[ERROR] Failed moving RIP %016llx on CPU %u: 0x%08x\n", regs.
Rip, c, status);
954 ERROR(
"[ERROR] IntThrSafeWinInspectRunningThreadOnCpu failed for CPU %u: 0x%08x\n", c, status);
965 ERROR(
"[ERROR] IntThrSafeLixInspectRunningThreadOnCpu failed for CPU %u: 0x%08x\n", c, status);
1023 ERROR(
"[ERROR] IntThrSafeInspectRunningThreads failed: 0x%08x\n", status);
1055 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.