54 .FunctionName =
"native_swapgs",
73 .RelocatedCodeOffset = 0x00,
89 static BYTE lfence[3] = {0x0f, 0xae, 0xe8};
104 ERROR(
"[ERROR] IntKsymFindByName could not find native_swapgs\n");
108 WARNING(
"[WARNING] 'native_swapgs' size is 0x%llx, which we don't support!\n", symEnd -
gNativeSwapgs);
118 goto _instrument_kernel;
133 LOG(
"[SWAPGS] Overwriting native_swapgs...\n");
138 ERROR(
"[ERROR] IntKernVirtMemWrite failed for rip %llx: %08x\n",
gNativeSwapgs, status);
139 goto _instrument_kernel;
154 LOG(
"[SWAPGS] Detouring native_swapgs...\n");
159 ERROR(
"[ERROR] IntDetSetHook failed for 'native_swapgs': %08x\n", status);
160 goto _instrument_kernel;
166 ERROR(
"[ERROR] IntDetGetByTag failed after just setting it: %08x\n", status);
167 goto _instrument_kernel;
177 ERROR(
"[ERROR] Failed writing 'lfence' to the detour handler: %08x\n", status);
178 goto _instrument_kernel;
185 LOG(
"[SWAPGS] 'native_swapgs' already detoured!");
190 WARNING(
"[WARNING] Unknown native_swapgs...\n");
198 page < gLixGuest->Layout.CodeEnd;
206 ERROR(
"[ERROR]IntVirtMemMap failed for 0x%llx : %08x\n", page, status);
215 if (0x0F != buf[rip])
221 if (
PAGE_REMAINING(rip) > 2 && (0x01 != buf[rip + 1] || 0xF8 != buf[rip + 2]))
228 BYTE rest[2] = { 0 };
231 if (!
INT_SUCCESS(status) || 0x01 != rest[0] || 0xF8 != rest[1])
245 for (
QWORD fRip = symStart; fRip < symEnd;)
253 TRACE(
"[SWAPGS] Function starts at %llx but it's instr at %llx is invalid (the code-segment type is not 64): %08x\n",
254 symStart, fRip, status);
260 if (instrux.Instruction != ND_INS_SWAPGS)
265 fRip += instrux.Length;
273 if (instrux.Length == 3 && instrux.Instruction == ND_INS_NOP)
275 LOG(
"[SWAPGS] RIP %llx in function %s\n", fRip - instrux.Length, symName);
283 ERROR(
"[ERROR] IntKernVirtMemRead failed for rip %llx: %08x\n", fRip, status);
290 ERROR(
"[ERROR] IntKernVirtMemWrite failed for rip %llx: %08x\n", fRip, status);
298 char nd[ND_MIN_BUF_SIZE];
300 NdToText(&instrux, fRip,
sizeof(nd), nd);
301 LOG(
"[SWAPGS] Ignoring at RIP %llx (%s) in function %s\n",
302 fRip - instrux.Length, nd, symName);
312 fRip += instrux.Length;
343 ERROR(
"[ERROR] IntGetGprs failed on cpu %d: %08x\n", cpu, status);
354 LOG(
"[SWAPGS] RIP is at the start of patched native_swapgs, do nothing...\n");
359 LOG(
"[SWAPGS] RIP is %llx ('%s'), move it to %llx ('retn')...\n",
367 ERROR(
"[ERROR] IntSetGprs failed: %08x\n", status);
373 LOG(
"[SWAPGS] Invalid RIP (%llx) position: %ld\n", regs.
Rip, offset);
374 goto _restore_patched;
379 LOG(
"[SWAPGS] Restore original 'native_swapgs' at RIP %llx\n",
gNativeSwapgs);
384 ERROR(
"[ERROR] IntKernVirtMemWrite failed for 'native_swapgs': %08x\n", status);
406 ERROR(
"[ERROR] IntKernVirtMemWrite failed for rip %llx: %08x\n",
413 gTotalPatchedSwapgs = 0;
482 ERROR(
"[ERROR] IntKsymFindByAddress failed for %llx: 0x%08x\n", gva, status);
489 if (gva + size - ksymStart <= 5)
502 ERROR(
"[ERROR] IntExceptKernelGetOriginator failed with status: 0x%08x\n", status);
507 exitAfterInformation =
TRUE;
518 ERROR(
"[ERROR] IntExceptGetVictimEpt failed with status: 0x%08x\n", status);
523 exitAfterInformation =
TRUE;
526 if (exitAfterInformation)
542 memzero(pEptViol,
sizeof(*pEptViol));
582 WARNING(
"[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
622 ERROR(
"[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
647 ERROR(
"[ERROR] IntHookObjectHookRegion failed for region 0x%016llx - 0x%016llx: 0x%08x\n",
648 crtGva, crtGva + PAGE_SIZE, status);
689 ERROR(
"[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
705 ERROR(
"[ERROR] IntHookObjectHookRegion failed for region 0x%016llx - 0x%016llx: 0x%08x\n",
720 ERROR(
"[ERROR] IntHookObjectHookRegion failed for region 0x%016llx - 0x%016llx: 0x%08x\n",
737 ERROR(
"[ERROR] IntHookObjectHookRegion failed for region 0x%016llx - 0x%016llx : 0x%08x\n",
743 WARNING(
"[WARNING] ExTable is not available. Will skip protection.\n");
770 ERROR(
"[ERROR] IntLixHookKernel failed: 0x%08x\n", status);
797 ERROR(
"[ERROR] IntLixHookKernel failed: 0x%08x\n", status);
Measures kernel mode exceptions checks.
void * Module
The internal structure of a module.
static void IntLixPatchSwapgs(void)
Finds vulnerable SWAPGS instruction inside the kernel and applies mitigations.
#define DETOUR_ENABLE_ALWAYS
Can be used as the API_HOOK_DESCRIPTOR.EnableFlags to always enable the detour.
struct _EVENT_EPT_VIOLATION::@284 Victim
enum _INTRO_ACTION_REASON INTRO_ACTION_REASON
The reason for which an INTRO_ACTION was taken.
INTRO_CODEBLOCKS CodeBlocks
Code blocks extracted for the alert.
INTSTATUS IntLixKernelReadProtect(void)
Activates kernel protection.
Describes the information about a Linux active-patch.
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
QWORD IntAlertCoreGetFlags(QWORD ProtectionFlag, INTRO_ACTION_REASON Reason)
Returns the flags for an alert.
An internal error occurred (no memory, pages not present, etc.).
BOOLEAN IntPolicyCoreForceBetaIfNeeded(QWORD Flag, INTRO_ACTION *Action)
Checks if a forced action should be taken even if the log-only mode is active.
Kernel module (ntoskrnl.exe, hal.dll, etc.).
INTSTATUS IntKernVirtMemWrite(QWORD KernelGva, DWORD Length, void *Buffer)
Writes data to a guest kernel virtual memory range.
INTSTATUS IntHookObjectDestroy(HOOK_OBJECT_DESCRIPTOR **Object, DWORD Flags)
Destroy an entire hook object. All regions belonging to this object will be removed.
static BYTE gOriginalNativeSwapgs[0x10]
The original first 10 bytes of the "native_swapgs" function.
IG_ARCH_REGS Regs
The current state of the guest registers.
LIX_ACTIVE_PATCH ActivePatch[lixActivePatchCount]
An array that contains information about the active-patches.
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
QWORD SystemCr3
The Cr3 used to map the kernel.
#define INT_STATUS_SUCCESS
BOOLEAN IntPolicyCoreTakeAction(QWORD Flag, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
Returns the action that should be taken for a core introspection option.
#define PAGE_REMAINING(addr)
static void IntLixUnhookKernelRead(void)
Removes write hooks from the kernel code section.
INTSTATUS IntGetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Get the current guest GPR state.
static DWORD gTotalPatchedSwapgs
The total number of patched swapgs gadgets.
#define INTRO_OPT_PROT_KM_LX
Enable kernel image protection (Linux only).
QWORD RoDataStart
The guest virtual address where the read-only data starts.
INTSTATUS IntKsymFindByAddress(QWORD Gva, DWORD Length, char *SymName, QWORD *SymStart, QWORD *SymEnd)
Finds the symbol which is located at the given address.
#define INT_SUCCESS(Status)
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
#define INTRO_OPT_PROT_KM_LX_TEXT_READS
Enable kernel '_text' section read protection (Linux only).
WORD Length
The patch length.
#define INT_STATUS_NOT_NEEDED_HINT
KERNEL_DRIVER * Driver
The driver that's modifying the memory.
struct _EVENT_EPT_VIOLATION::@283 Originator
#define DETOUR_MAX_VERSION_ANY
Specifies that the first OS version for which a detour handler is available is the latest OS version ...
int INTSTATUS
The status data type.
QWORD GvaPage
Guest virtual page base address, aligned to 4K.
QWORD CodeEnd
The guest virtual address where the code ends.
BOOLEAN Protected
True if the driver is protected, False if it is not.
QWORD CodeStart
The guest virtual address where the code starts.
Describes a kernel-mode originator.
static void IntLixUnhookKernelWrite(void)
Removes write hooks from the kernel code section.
static INTSTATUS IntLixHookKernelWrite(void)
Establishes read and write hooks for Kernel code.
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
INSTRUX Instruction
The current instruction, pointed by the guest RIP.
INTSTATUS IntLixKernelWriteProtect(void)
Activates kernel protection.
struct _EXCEPTION_KM_ORIGINATOR::@63 Return
No hypercall. This detour does not generate events.
Describes a kernel driver.
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
DWORD AccessSize
The size of the memory access. Valid only for EPT exits.
INTRO_VIOLATION_HEADER Header
The alert header.
void * HookObjectRead
The hook object used to protect this driver against read. NULL if the driver is not protected...
#define PAGE_FRAME_NUMBER(addr)
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
static INTSTATUS IntLixKernelHandleRead(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Handles reads performed from a Kernel module's text section.
EXCEPTION_VICTIM_OBJECT Object
The modified object.
QWORD ExTableStart
The guest virtual address where the ex-table starts.
INTSTATUS IntAlertFillCodeBlocks(QWORD Rip, QWORD Cr3, BOOLEAN Execute, INTRO_CODEBLOCKS *CodeBlocks)
Fills the code blocks pattern for an alert.
EXCEPTION_VICTIM_MODULE Module
Used when a module is modified.
GENERIC_ALERT gAlert
Global alert buffer.
void IntAlertFillLixKmModule(const KERNEL_DRIVER *Driver, INTRO_MODULE *EventModule)
Saves information about a kernel module inside an alert.
#define DETOUR_MIN_VERSION_ANY
Specifies that the first OS version for which a detour handler is available is the first OS version s...
INTSTATUS IntLixDrvHandleWrite(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Called if an write occurs on the protected memory zone.
void IntAlertEptFillFromVictimZone(const EXCEPTION_VICTIM_ZONE *Victim, EVENT_EPT_VIOLATION *EptViolation)
Fills the victim information inside an EPT alert.
#define IS_KERNEL_POINTER_LIX(p)
#define INT_STATUS_NOT_INITIALIZED
struct _LINUX_GUEST::@126 Layout
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
#define IN_RANGE(x, start, end)
INTSTATUS IntExceptGetVictimEpt(void *Context, QWORD Gpa, QWORD Gva, INTRO_OBJECT_TYPE Type, DWORD ZoneFlags, EXCEPTION_VICTIM_ZONE *Victim)
Fills an EXCEPTION_VICTIM_ZONE with relevant information from an EPT violation.
QWORD Current
The currently used options.
#define IN_RANGE_LEN(x, start, len)
INTSTATUS IntDetSetHook(QWORD FunctionAddress, QWORD ModuleBase, API_HOOK_DESCRIPTOR *Descriptor, API_HOOK_HANDLER *Handler)
Will inject code inside the guest.
static BOOLEAN gNativeSwapgsHooked
Variable marking whether the "native_swapgs" function was detoured or not.
API_HOOK_DESCRIPTOR gSwapgsDetour
Hook descriptor for "native_swapgs" detour.
void IntExceptKernelLogInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a kernel-mode violation and dumps the code-blocks.
CHAR FunctionName[ALERT_MAX_FUNCTION_NAME_LEN]
The name of the modified function, if any. This is the same as Export.Name[0].
INTRO_EXEC_CONTEXT ExecContext
Information about the instruction that triggered the alert.
void IntLixDrvGetSecName(KERNEL_DRIVER *Driver, QWORD Gva, CHAR *SectionName)
Get the section of the driver that contains the provided guest virtual address.
LIX_KERNEL_MODULE Lix
Valid only for Linux guests.
void * HookObject
The hook object used to protect this driver. NULL if the driver is not protected. ...
Sent when an EPT violation triggers an alert. See EVENT_EPT_VIOLATION.
#define LIX_SYMBOL_NAME_LEN
The max length of the ksym as defined by Linux kernel.
DWORD CpuCount
The number of logical CPUs.
Describes the modified zone.
QWORD ProtectionFlag
The introcore option that decided that this driver must be protected.
enum _INTRO_ACTION INTRO_ACTION
Event actions.
QWORD Rip
The RIP from where the call to the exported function came.
INTSTATUS IntSetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Sets the values of the guest GPRs.
QWORD RoDataEnd
The guest virtual address where the read-only data ends.
__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.
GUEST_STATE gGuest
The current guest state.
static QWORD gNativeSwapgs
The guest virtual address of the "native_swapgs" function.
BYTE OriginalBytes[3]
The bytes that were modified with the lfence instruction.
#define DETOUR_INVALID_HYPERCALL
Used to specify that no hypercall is present in the detour handler so the HypercallOffset field insid...
API_HOOK_HANDLER Handlers[DETOUR_MAX_HANDLERS]
Handlers that can be set for this function.
struct _EXCEPTION_KM_ORIGINATOR::@64 Original
INTRO_ACTION Action
The action that was taken as the result of this alert.
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
#define ZONE_READ
Used for read violation.
CHAR ModifiedSectionName[ALERT_MAX_SECTION_NAME_LEN]
The name of the modified section, if any.
INTSTATUS IntHookObjectHookRegion(void *Object, QWORD Cr3, QWORD Gla, SIZE_T Length, BYTE Type, void *Callback, void *Context, DWORD Flags, HOOK_REGION_DESCRIPTOR **Region)
Hook a contiguous region of virtual memory inside the provided virtual address space.
static struct @268 gPatchedSwapgs[128]
native_swapgs gadgets patched by Introspection.
KERNEL_DRIVER * KernelDriver
Points to the driver object that describes the kernel image.
#define INTRO_OPT_PROT_KM_SWAPGS
Enable SWAPGS (CVE-2019-1125) mitigation.
void IntLixKernelReadUnprotect(void)
Deactivates the kernel protection against read.
INTRO_PROCESS CurrentProcess
The current process.
VCPU_STATE * gVcpu
The state of the current VCPU.
INTRO_MODULE Module
The module that did the malicious access.
CHAR RipSectionName[ALERT_MAX_SECTION_NAME_LEN]
The name of the section in which the RIP resides. May be empty.
Event structure for EPT violations.
void IntDisasmGva(QWORD Gva, DWORD Length)
This function disassembles a code buffer (given its GVA) and then dumps the instructions (textual dis...
void IntAlertFillLixCurrentProcess(INTRO_PROCESS *EventProcess)
Saves the current Linux process inside an event.
QWORD Gva
The start of the region which follows to be patched.
void IntLixKernelWriteUnprotect(void)
Deactivates the kernel protection against write.
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
static INTSTATUS IntLixHookKernelRead(void)
Establishes read hooks for Kernel code.
Exploitation of Remote Services.
#define INT_STATUS_REMOVE_HOOK_ON_RET
Can be used by hook callbacks in order to signal that the hook should be removed. ...
static void IntLixUnpatchSwapgs(void)
Deactivates swapgs mitigations set by IntLixPatchSwapgs.
INTSTATUS IntDetGetByTag(DETOUR_TAG Tag, QWORD *Address, DWORD *Size)
Get a detour handler address and size by its tag.
QWORD LfenceRip
The RIP where the lfence instruction was injected.
INTSTATUS IntExceptKernelGetOriginator(EXCEPTION_KM_ORIGINATOR *Originator, DWORD Options)
This function is used to get the information about the kernel-mode originator.
INTSTATUS IntAlertFillExecContext(QWORD Cr3, INTRO_EXEC_CONTEXT *ExecContext)
Fills the current execution context.
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
INTSTATUS IntDecDecodeInstruction(IG_CS_TYPE CsType, QWORD Gva, void *Instrux)
Decode an instruction from the provided guest linear address.
QWORD ExTableEnd
The guest virtual address where the ex-table ends.
INTSTATUS IntHookObjectCreate(DWORD ObjectType, QWORD Cr3, void **Object)
Create a new hook object.
Describes a function to be hooked.
void IntExcept(EXCEPTION_VICTIM_ZONE *Victim, void *Originator, EXCEPTION_TYPE Type, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason, INTRO_EVENT_TYPE EventClass)
This function is the entry point for the exception mechanism.
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
INTRO_MODULE ReturnModule
The module to which the current code returns to.