46 if (NULL != Reloc->InsCloak)
50 Reloc->InsCloak = NULL;
56 if (NULL != Reloc->SlackCloak)
60 Reloc->SlackCloak = NULL;
63 Reloc->Patched =
FALSE;
72 _In_ PINSTRUX Instrux,
168 ERROR(
"[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
182 if (tableSize > MAX_MEM_TABLE_SIZE)
184 WARNING(
"[WARNING] Table size at %llx is %d, bailing out.\n", Reloc->TableGva, tableSize);
188 regDst = Instrux->Operands[0].Info.Register.Reg;
189 regIdx = Instrux->Operands[1].Info.Memory.Index;
196 TRACE(
"[MEMTABLE] We could allocated space in PT filter agent!\n");
204 ERROR(
"[ERROR] IntSlackAlloc failed: 0x%08x\n", status);
209 Reloc->InAgent = inAgent;
210 Reloc->SlackAddress = slackAddr;
211 Reloc->SlackSize = slackSize;
219 code[cb++] = 0x48 | (regDst >= 8 ? 0x1 : 0x0);
220 code[cb++] = 0x50 | (regDst & 7);
223 code[cb++] = 0x48 | (regIdx >= 8 ? 0x1 : 0x0);
224 code[cb++] = 0x50 | (regIdx & 7);
249 code[cb++] = 0x48 | (regIdx >= 8 ? 0x5 : 0x0);
251 code[cb++] = 0xC0 | (((regIdx & 7) << 3) | (regIdx & 7));
255 code[cb++] = 0x48 | (regIdx >= 8 ? 0x4 : 0x0);
257 code[cb++] = 0x44 | ((regIdx & 7) << 3);
262 code[cb++] = 0x48 | (regIdx >= 8 ? 0x1 : 0x0);
263 code[cb++] = 0x58 | (regIdx & 7);
266 code[cb++] = 0x48 | (regDst >= 8 ? 0x1 : 0x0);
267 code[cb++] = 0x58 | (regDst & 7);
284 code[cb++] = 0x40 | ((regDst >= 8) ? 0x1 : 0x0);
286 code[cb++] = 0xE0 | (regDst & 0x7);
289 for (
QWORD i = 0; i < tableSize; i++)
292 code[cb++] = 0x40 | ((regDst >= 8) ? 0x1 : 0x0);
293 code[cb++] = 0xB8 + (regDst % 8);
294 code[cb++] = (table[i] >> 0) & 0xFF;
295 code[cb++] = (table[i] >> 8) & 0xFF;
296 code[cb++] = (table[i] >> 16) & 0xFF;
297 code[cb++] = (table[i] >> 24) & 0xFF;
315 code[cb++] = (rel >> 0) & 0xFF;
316 code[cb++] = (rel >> 8) & 0xFF;
317 code[cb++] = (rel >> 16) & 0xFF;
318 code[cb++] = (rel >> 24) & 0xFF;
325 memset(jins, 0x66,
sizeof(jins));
326 jins[Instrux->Length - 2] = 0xCD;
327 jins[Instrux->Length - 1] = 0x14;
332 memset(jins, 0x90,
sizeof(jins));
334 *((
DWORD *)&jins[1]) = (
DWORD)(slackAddr - (Regs->Rip + 5));
338 memcpy(origins, Instrux->InstructionBytes, Instrux->Length);
344 origins, jins, NULL, &Reloc->InsCloak);
347 ERROR(
"[ERROR] IntMemClkCloakRegion failed: 0x%08x\n", status);
348 goto _resume_and_exit;
354 NULL, code, NULL, &Reloc->SlackCloak);
357 ERROR(
"[ERROR] IntMemClkCloakRegion failed: 0x%08x\n", status);
358 goto _resume_and_exit;
367 ERROR(
"[ERROR] IntKernVirtMemWrite failed: 0x%08x\n", status);
368 goto _resume_and_exit;
379 ERROR(
"[ERROR] IntIcFlushAddress failed: 0x%08x\n", status);
380 goto _resume_and_exit;
383 Reloc->Patched =
TRUE;
465 if (instr->Instruction != ND_INS_MOV)
471 if ((instr->OperandsCount != 2) || (instr->Operands[0].Type != ND_OP_REG) ||
472 (instr->Operands[1].Type != ND_OP_MEM) || !instr->HasSib ||
473 !instr->Operands[1].Info.Memory.HasIndex || (instr->MemoryAccess != ND_ACCESS_READ) ||
474 (instr->Operands[0].Size != 4) || (instr->Operands[1].Size != 4) ||
496 if (instr->Operands[1].Info.Memory.HasBase)
498 base = instr->Operands[1].Info.Memory.Base;
501 if (instr->Operands[1].Info.Memory.HasDisp)
503 disp = instr->Operands[1].Info.Memory.Disp;
506 tableStart = *((
QWORD *)pRegs + base) + disp;
512 list = gMemTables.
Flink;
513 while (list != &gMemTables)
532 if (pTable->
Hits % 10000 == 0)
534 TRACE(
"[MEMTABLE] Table at %llx accessed for %lld time, from RIP %llx\n",
538 if (pTable->
Hits >= 100000 && !pTable->
Dumped)
540 ERROR(
"[ERROR] Table at %llx accessed too many times (%lld), from RIP %llx, event %lld\n",
556 WARNING(
"[WARNING] IntMemTablesPatchInstruction failed: 0x%08x\n", status);
562 CHAR text[ND_MIN_BUF_SIZE];
564 NdToText(instr, pRegs->
Rip,
sizeof(text), text);
566 LOG(
"[MEMTABLE] [%d] Successfully patched instruction %llx:%s, will return 0x%x\n",
613 list = gMemTables.
Flink;
614 while (list != &gMemTables)
621 WARNING(
"[WARNING] Found %s ptr 0x%016llx in memtable relocs: slack addr 0x%016llx, " 622 "instruction addr 0x%016llx\n",
657 list = gMemTables.
Flink;
658 while (list != &gMemTables)
690 list = gMemTables.
Flink;
691 while (list != &gMemTables)
696 if (pTable->
Rip == Rip)
723 list = gMemTables.
Flink;
724 while (list != &gMemTables)
760 list = gMemTables.
Flink;
761 while (list != &gMemTables)
766 LOG(
"[MEMTABLE] Table at %llx accessed for %lld time, from RIP %llx, ignored = %d\n",
#define CONTAINING_RECORD(List, Type, Member)
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
INTSTATUS IntKernVirtMemWrite(QWORD KernelGva, DWORD Length, void *Buffer)
Writes data to a guest kernel virtual memory range.
IG_ARCH_REGS Regs
The current state of the guest registers.
DWORD Index
The VCPU number.
#define INT_STATUS_INSTRUCTION_PATCHED
Indicates that an instruction was patched.
#define INT_STATUS_SUCCESS
DWORD KernelSize
The size of the kernel.
#define MEM_TABLE_HEADER_SIZE
struct _LIST_ENTRY * Flink
#define INT_SUCCESS(Status)
static LIST_HEAD gMemTables
List of memtables.
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
void IntMtblDisable(void)
Disables mem-table instructions instrumentation.
BOOLEAN InAgent
True if we relocated the instruction inside the PT filter agent.
INTSTATUS IntMtblCheckAccess(void)
Check if the current instruction is like a switch-case table access instruction.
#define INT_STATUS_NOT_NEEDED_HINT
BOOLEAN IntMtblInsRelocated(QWORD Rip)
Check if the instruction at the provided RIP is instrumented.
#define HpAllocWithTag(Len, Tag)
int INTSTATUS
The status data type.
QWORD gEventId
The ID of the current event.
DWORD NumberOfServices
The number of entries in the SSDT.
BOOLEAN BootstrapAgentAllocated
True if the slack space for the bootstrap agent has been allocated.
INTSTATUS IntMtblRemoveAgentEntries(void)
Removes only the mem-table entries that were relocated inside the PT filter.
#define MAX_MEM_TABLE_SLACK_SIZE
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
INTRO_GUEST_TYPE OSType
The type of the guest.
INSTRUX Instruction
The current instruction, pointed by the guest RIP.
Will write the contents of the patched data inside the guest.
INTSTATUS IntSlackAlloc(QWORD ModuleBase, BOOLEAN Pageable, DWORD Size, QWORD *Buffer, QWORD SecHint)
Allocate slack inside the guest.
BOOLEAN Patched
True if the instruction has been instrumented.
QWORD SlackAddress
Slack address where the handler was allocated.
void * InsCloak
Instrumented instruction cloak handle.
#define MAX_MEM_TABLE_SIZE
BOOLEAN Ignored
True if we didn't manage to hook it.
QWORD TableGva
Guest virtual address of the switch-case table accessed by the instruction.
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
CPU_STATE State
The state of this VCPU. Describes what action is the VCPU currently doing.
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
QWORD Rip
RIP of the instrumented instruction.
BOOLEAN Dumped
TRUE if it's a problematic table and we dumped it's content in an error.
QWORD IntPtiGetAgentAddress(void)
Get the guest virtual address where the PT filter resides.
QWORD Ssdt
Guest virtual address of the SSDT structure inside the kernel.
#define HpFreeAndNullWithTag(Add, Tag)
static INTSTATUS IntMtblRemoveEntry(PMEM_TABLE_RELOC Reloc)
Removes a mem-table entry.
INTSTATUS IntMemClkCloakRegion(QWORD VirtualAddress, QWORD Cr3, DWORD Size, DWORD Options, PBYTE OriginalData, PBYTE PatchedData, PFUNC_IntMemCloakWriteHandle WriteHandler, void **CloakHandle)
Hides a memory zone from the guest.
QWORD KernelVa
The guest virtual address at which the kernel image.
INTSTATUS IntIcFlushAddress(PINS_CACHE Cache, QWORD Gva, QWORD Cr3)
Flush entries cached from a given address.
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
void * InstructionCache
The currently used instructions cache.
TIMER_FRIENDLY void IntDumpGvaEx(QWORD Gva, DWORD Length, QWORD Cr3, DWORD RowLength, DWORD ElementLength, BOOLEAN LogHeader, BOOLEAN DumpAscii)
This function dumps a given GVA in a user friendly format. This function uses IntDumpBuffer to perfor...
#define MEM_TABLE_ENTRY_SIZE
GUEST_STATE gGuest
The current guest state.
INTSTATUS IntMtblUninit(void)
Completely uninit the mem-tables, removing all the handlers from the NT slack space.
THS_PTR_TYPE
The type of pointer to be checked.
INTSTATUS IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
#define LIST_HEAD_INIT(Name)
#define INT_STATUS_NOT_SUPPORTED
INTSTATUS IntMemClkUncloakRegion(void *CloakHandle, DWORD Options)
Removes a cloak region, making the original memory contents available again to the guest...
VCPU_STATE * gVcpu
The state of the current VCPU.
void IntDisasmGva(QWORD Gva, DWORD Length)
This function disassembles a code buffer (given its GVA) and then dumps the instructions (textual dis...
BOOLEAN IntMtblIsPtrInReloc(QWORD Ptr, THS_PTR_TYPE Type, QWORD *Table)
Check if the given pointer is inside a mem-table relocation handler.
DWORD SlackSize
Size of the allocated slack buffer.
QWORD Hits
Number of times this instruction generated a read EPT violation.
QWORD IntPtiAllocMemtableSpace(QWORD Rip, DWORD Size)
Allocate space for a mem-table.
QWORD Gla
The accessed guest virtual address. Valid only for EPT exits.
static INTSTATUS IntMtblPatchInstruction(PMEM_TABLE_RELOC Reloc, PINSTRUX Instrux, PIG_ARCH_REGS Regs)
Relocate and instrument a switch-case load instruction.
LIST_ENTRY Link
List element link.
#define INT_STATUS_INSUFFICIENT_RESOURCES