Bitdefender Hypervisor Memory Introspection
memtables.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "memtables.h"
6 #include "guests.h"
7 #include "icache.h"
8 #include "memcloak.h"
9 #include "ptfilter.h"
10 #include "slack.h"
11 
12 static LIST_HEAD gMemTables = LIST_HEAD_INIT(gMemTables);
13 
14 
29 
30 
31 static INTSTATUS
34  )
45 {
46  if (NULL != Reloc->InsCloak)
47  {
49 
50  Reloc->InsCloak = NULL;
51 
52  // Flush the cache.
54  }
55 
56  if (NULL != Reloc->SlackCloak)
57  {
59 
60  Reloc->SlackCloak = NULL;
61  }
62 
63  Reloc->Patched = FALSE;
64 
65  return INT_STATUS_SUCCESS;
66 }
67 
68 
69 static INTSTATUS
72  _In_ PINSTRUX Instrux,
73  _In_ PIG_ARCH_REGS Regs
74  )
156 //
157 {
158  INTSTATUS status;
159  QWORD slackAddr;
160  DWORD tableSize, slackSize, regDst, regIdx, table[MAX_MEM_TABLE_SIZE + 1], cb, rel;
161  BYTE code[MAX_MEM_TABLE_SLACK_SIZE], jins[ND_MAX_INSTRUCTION_LENGTH], origins[ND_MAX_INSTRUCTION_LENGTH];
162  BOOLEAN inAgent = FALSE;
163 
164  // Safe: note that table is DWORD[MAX_MEM_TABLE_SIZE + 1].
165  status = IntKernVirtMemRead(Reloc->TableGva, (MAX_MEM_TABLE_SIZE + 1) * 4, table, NULL);
166  if (!INT_SUCCESS(status))
167  {
168  ERROR("[ERROR] IntKernVirtMemRead failed: 0x%08x\n", status);
169  return status;
170  }
171 
172  // Extract the table size. Each entry must be a dword RVA inside the NT image. We support max 16 entries per table.
173  for (tableSize = 0; tableSize < MAX_MEM_TABLE_SIZE + 1; tableSize++)
174  {
175  if (table[tableSize] >= gGuest.KernelSize)
176  {
177  break;
178  }
179  }
180 
181  // Can't reliably get the size, bail out.
182  if (tableSize > MAX_MEM_TABLE_SIZE)
183  {
184  WARNING("[WARNING] Table size at %llx is %d, bailing out.\n", Reloc->TableGva, tableSize);
186  }
187 
188  regDst = Instrux->Operands[0].Info.Register.Reg;
189  regIdx = Instrux->Operands[1].Info.Memory.Index;
190 
191  slackSize = MEM_TABLE_HEADER_SIZE + MEM_TABLE_ENTRY_SIZE * tableSize;
192 
193  slackAddr = IntPtiAllocMemtableSpace(Regs->Rip + Instrux->Length, slackSize);
194  if (0 != slackAddr)
195  {
196  TRACE("[MEMTABLE] We could allocated space in PT filter agent!\n");
197  inAgent = TRUE;
198  }
199  else
200  {
201  status = IntSlackAlloc(gGuest.KernelVa, FALSE, slackSize, &slackAddr, 0);
202  if (!INT_SUCCESS(status))
203  {
204  ERROR("[ERROR] IntSlackAlloc failed: 0x%08x\n", status);
205  return status;
206  }
207  }
208 
209  Reloc->InAgent = inAgent;
210  Reloc->SlackAddress = slackAddr;
211  Reloc->SlackSize = slackSize;
212 
213  cb = 0;
214 
215  // Store the "PUSHFQ" instruction.
216  code[cb++] = 0x9C;
217 
218  // Store the "PUSH dst" instruction.
219  code[cb++] = 0x48 | (regDst >= 8 ? 0x1 : 0x0);
220  code[cb++] = 0x50 | (regDst & 7);
221 
222  // Store the "PUSH idx" instruction.
223  code[cb++] = 0x48 | (regIdx >= 8 ? 0x1 : 0x0);
224  code[cb++] = 0x50 | (regIdx & 7);
225 
226  // Overwrite the saved dst with the slack target address.
227 
228  // Store the "MOV [rsp + 8], addr low" instruction
229  code[cb++] = 0xC7;
230  code[cb++] = 0x44;
231  code[cb++] = 0x24;
232  code[cb++] = 0x08;
233  code[cb++] = ((slackAddr + MEM_TABLE_HEADER_SIZE) >> 0) & 0xFF;
234  code[cb++] = ((slackAddr + MEM_TABLE_HEADER_SIZE) >> 8) & 0xFF;
235  code[cb++] = ((slackAddr + MEM_TABLE_HEADER_SIZE) >> 16) & 0xFF;
236  code[cb++] = ((slackAddr + MEM_TABLE_HEADER_SIZE) >> 24) & 0xFF;
237 
238  // Store the "MOV [rsp + C], addr high" instruction
239  code[cb++] = 0xC7;
240  code[cb++] = 0x44;
241  code[cb++] = 0x24;
242  code[cb++] = 0x0C;
243  code[cb++] = ((slackAddr + MEM_TABLE_HEADER_SIZE) >> 32) & 0xFF;
244  code[cb++] = ((slackAddr + MEM_TABLE_HEADER_SIZE) >> 40) & 0xFF;
245  code[cb++] = ((slackAddr + MEM_TABLE_HEADER_SIZE) >> 48) & 0xFF;
246  code[cb++] = ((slackAddr + MEM_TABLE_HEADER_SIZE) >> 56) & 0xFF;
247 
248  // Store the "IMUL idx, idx, 11" instruction.
249  code[cb++] = 0x48 | (regIdx >= 8 ? 0x5 : 0x0);
250  code[cb++] = 0x6B;
251  code[cb++] = 0xC0 | (((regIdx & 7) << 3) | (regIdx & 7));
252  code[cb++] = MEM_TABLE_ENTRY_SIZE;
253 
254  // Store the "ADD [rsp + 8], idx" instruction.
255  code[cb++] = 0x48 | (regIdx >= 8 ? 0x4 : 0x0);
256  code[cb++] = 0x01;
257  code[cb++] = 0x44 | ((regIdx & 7) << 3);
258  code[cb++] = 0x24;
259  code[cb++] = 0x08;
260 
261  // Store the "POP idx" instruction.
262  code[cb++] = 0x48 | (regIdx >= 8 ? 0x1 : 0x0);
263  code[cb++] = 0x58 | (regIdx & 7);
264 
265  // Store the "POP dst" instruction.
266  code[cb++] = 0x48 | (regDst >= 8 ? 0x1 : 0x0);
267  code[cb++] = 0x58 | (regDst & 7);
268 
269  // Store the "MOV [rsp - 8], 0" instruction, which will remove the pointer which may still point inside of us.
270  code[cb++] = 0x48;
271  code[cb++] = 0xc7;
272  code[cb++] = 0x44;
273  code[cb++] = 0x24;
274  code[cb++] = 0xF8;
275  code[cb++] = 0x00;
276  code[cb++] = 0x00;
277  code[cb++] = 0x00;
278  code[cb++] = 0x00;
279 
280  // Store the "POPFQ" instruction.
281  code[cb++] = 0x9D;
282 
283  // Store the "JMP regDst" instruction.
284  code[cb++] = 0x40 | ((regDst >= 8) ? 0x1 : 0x0); // REX prefix.
285  code[cb++] = 0xFF; // Opcode.
286  code[cb++] = 0xE0 | (regDst & 0x7); // Mod R/M, mod 3, reg 4, rm regDst.
287 
288  // Store the "MOV regDst, imm/JMP back" stubs.
289  for (QWORD i = 0; i < tableSize; i++)
290  {
291  // Store the "MOV regDst, imm" instruction.
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;
298 
299  if (inAgent)
300  {
301  // Store the "IRETQ"
302  code[cb++] = 0x48;
303  code[cb++] = 0xCF;
304  // For padding, to make it as long as a "JMP near"
305  code[cb++] = 0x90;
306  code[cb++] = 0x90;
307  code[cb++] = 0x90;
308  }
309  else
310  {
311  // Store the "JMP original_code" instruction.
312  code[cb++] = 0xE9;
313  rel = (DWORD)((gVcpu->Regs.Rip + Instrux->Length) -
314  (slackAddr + MEM_TABLE_HEADER_SIZE + MEM_TABLE_ENTRY_SIZE * (i + 1)));
315  code[cb++] = (rel >> 0) & 0xFF;
316  code[cb++] = (rel >> 8) & 0xFF;
317  code[cb++] = (rel >> 16) & 0xFF;
318  code[cb++] = (rel >> 24) & 0xFF;
319  }
320  }
321 
322  if (inAgent)
323  {
324  // We are using the PT filter agent, we can just INT 20 into it.
325  memset(jins, 0x66, sizeof(jins));
326  jins[Instrux->Length - 2] = 0xCD;
327  jins[Instrux->Length - 1] = 0x14;
328  }
329  else
330  {
331  // Patch the instruction with a JMP.
332  memset(jins, 0x90, sizeof(jins));
333  jins[0] = 0xE9;
334  *((DWORD *)&jins[1]) = (DWORD)(slackAddr - (Regs->Rip + 5));
335  }
336 
337  // Save the old instruction.
338  memcpy(origins, Instrux->InstructionBytes, Instrux->Length);
339 
340  // Now do the actual patching.
341  IntPauseVcpus();
342 
343  status = IntMemClkCloakRegion(Regs->Rip, 0, Instrux->Length, MEMCLOAK_OPT_APPLY_PATCH,
344  origins, jins, NULL, &Reloc->InsCloak);
345  if (!INT_SUCCESS(status))
346  {
347  ERROR("[ERROR] IntMemClkCloakRegion failed: 0x%08x\n", status);
348  goto _resume_and_exit;
349  }
350 
351  if (!inAgent)
352  {
353  status = IntMemClkCloakRegion(slackAddr, 0, slackSize, MEMCLOAK_OPT_APPLY_PATCH,
354  NULL, code, NULL, &Reloc->SlackCloak);
355  if (!INT_SUCCESS(status))
356  {
357  ERROR("[ERROR] IntMemClkCloakRegion failed: 0x%08x\n", status);
358  goto _resume_and_exit;
359  }
360  }
361  else
362  {
363  // No need to use IntVirtMemSafeWrite, as this is a pointer "allocated" by Introcore. Plus, it's EPT protected.
364  status = IntKernVirtMemWrite(slackAddr, slackSize, code);
365  if (!INT_SUCCESS(status))
366  {
367  ERROR("[ERROR] IntKernVirtMemWrite failed: 0x%08x\n", status);
368  goto _resume_and_exit;
369  }
370  }
371 
372  // Flush the RIP address. This is needed because a read violation may be generated for the same RIP
373  // for more than one VCPU. The first exit that is handled will also patch the instruction and if the cache
374  // is not flushed, the other VCPUs will patch it again (because instead of decoding a jump, they will decode
375  // a mov from memory
377  if (!INT_SUCCESS(status))
378  {
379  ERROR("[ERROR] IntIcFlushAddress failed: 0x%08x\n", status);
380  goto _resume_and_exit;
381  }
382 
383  Reloc->Patched = TRUE;
384 
385  // Indicate that we've patched the instruction.
387 
388 _resume_and_exit:
389  if (!INT_SUCCESS(status))
390  {
391  IntMtblRemoveEntry(Reloc);
392  }
393 
394  IntResumeVcpus();
395 
396  return status;
397 }
398 
399 
400 INTSTATUS
402  void
403  )
430 {
431  INTSTATUS status;
432  QWORD gva;
433  QWORD tableStart;
434  BYTE base;
435  QWORD disp;
436  PIG_ARCH_REGS pRegs;
437  PINSTRUX instr;
438  LIST_ENTRY *list;
439  BOOLEAN foundTable;
440  PMEM_TABLE_RELOC pTable;
441 
443  {
445  }
446 
447  if (!gGuest.Guest64)
448  {
450  }
451 
453  {
455  }
456 
457  pRegs = &gVcpu->Regs;
458  gva = gVcpu->Gla;
459  instr = &gVcpu->Instruction;
460  base = 0;
461  disp = 0;
462  foundTable = FALSE;
463  status = INT_STATUS_SUCCESS;
464 
465  if (instr->Instruction != ND_INS_MOV)
466  {
468  }
469 
470  // Make sure we can reloc this instruction + table.
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) ||
475  (instr->Length < 5))
476  {
478  }
479 
480  // Ignore anything outside the NT image.
481  if ((gva < gGuest.KernelVa) || (gva >= gGuest.KernelVa + gGuest.KernelSize) ||
482  (pRegs->Rip < gGuest.KernelVa) || (pRegs->Rip >= gGuest.KernelVa + gGuest.KernelSize))
483  {
485  }
486 
488  {
489  if ((gva >= gWinGuest->Ssdt) &&
490  (gva < gWinGuest->Ssdt + ((QWORD)gWinGuest->NumberOfServices * gGuest.WordSize)))
491  {
493  }
494  }
495 
496  if (instr->Operands[1].Info.Memory.HasBase)
497  {
498  base = instr->Operands[1].Info.Memory.Base;
499  }
500 
501  if (instr->Operands[1].Info.Memory.HasDisp)
502  {
503  disp = instr->Operands[1].Info.Memory.Disp;
504  }
505 
506  tableStart = *((QWORD *)pRegs + base) + disp;
507  if (tableStart == 0)
508  {
510  }
511 
512  list = gMemTables.Flink;
513  while (list != &gMemTables)
514  {
515  pTable = CONTAINING_RECORD(list, MEM_TABLE_RELOC, Link);
516  list = list->Flink;
517 
518  if (pTable->TableGva != tableStart)
519  {
520  continue;
521  }
522 
523  foundTable = TRUE;
524 
525  ++pTable->Hits;
526 
527  if (pTable->Ignored || pTable->Patched)
528  {
529  continue;
530  }
531 
532  if (pTable->Hits % 10000 == 0)
533  {
534  TRACE("[MEMTABLE] Table at %llx accessed for %lld time, from RIP %llx\n",
535  pTable->TableGva, pTable->Hits, pRegs->Rip);
536  }
537 
538  if (pTable->Hits >= 100000 && !pTable->Dumped)
539  {
540  ERROR("[ERROR] Table at %llx accessed too many times (%lld), from RIP %llx, event %lld\n",
541  pTable->TableGva, pTable->Hits, pRegs->Rip, gEventId);
542 
543  IntDisasmGva(pRegs->Rip, ND_MAX_INSTRUCTION_LENGTH);
544  IntDumpGvaEx(pTable->TableGva, MAX_MEM_TABLE_SIZE, 0, 16, 4, TRUE, FALSE);
545 
546  pTable->Dumped = TRUE;
547  }
548 
549  if (pTable->Hits >= 50 && (!gGuest.BootstrapAgentAllocated || IntPtiGetAgentAddress()))
550  {
551  // Try to patch this instruction. Note that we won't relocate the instruction and table if the bootstrap
552  // agent is active, because we would generate slack holes when we would free the it.
553  status = IntMtblPatchInstruction(pTable, instr, pRegs);
554  if (!INT_SUCCESS(status))
555  {
556  WARNING("[WARNING] IntMemTablesPatchInstruction failed: 0x%08x\n", status);
557 
558  pTable->Ignored = TRUE;
559  }
560  else
561  {
562  CHAR text[ND_MIN_BUF_SIZE];
563 
564  NdToText(instr, pRegs->Rip, sizeof(text), text);
565 
566  LOG("[MEMTABLE] [%d] Successfully patched instruction %llx:%s, will return 0x%x\n",
567  gVcpu->Index, pRegs->Rip, text, status);
568  }
569  }
570 
571  break;
572  }
573 
574  if (foundTable)
575  {
576  return status;
577  }
578 
579  pTable = HpAllocWithTag(sizeof(*pTable), IC_TAG_MTBL);
580  if (NULL == pTable)
581  {
583  }
584 
585  pTable->Rip = pRegs->Rip;
586  pTable->Hits = 1;
587  pTable->TableGva = tableStart;
588 
589  InsertTailList(&gMemTables, &pTable->Link);
590 
591  return status;
592 }
593 
594 
595 BOOLEAN
597  _In_ QWORD Ptr,
598  _In_ THS_PTR_TYPE Type,
599  _Out_opt_ QWORD *Table
600  )
610 {
611  LIST_ENTRY *list;
612 
613  list = gMemTables.Flink;
614  while (list != &gMemTables)
615  {
616  PMEM_TABLE_RELOC pTable = CONTAINING_RECORD(list, MEM_TABLE_RELOC, Link);
617  list = list->Flink;
618 
619  if ((Ptr >= pTable->SlackAddress) && (Ptr < pTable->SlackAddress + pTable->SlackSize))
620  {
621  WARNING("[WARNING] Found %s ptr 0x%016llx in memtable relocs: slack addr 0x%016llx, "
622  "instruction addr 0x%016llx\n",
623  Type == ptrLiveRip ? "live RIP" : "stack value", Ptr, pTable->SlackAddress, pTable->Rip);
624 
625  if (NULL != Table)
626  {
627  *Table = pTable->TableGva;
628  }
629 
630  return TRUE;
631  }
632  }
633 
634  if (NULL != Table)
635  {
636  *Table = 0;
637  }
638 
639  return FALSE;
640 }
641 
642 
643 void
645  void
646  )
654 {
655  LIST_ENTRY *list;
656 
657  list = gMemTables.Flink;
658  while (list != &gMemTables)
659  {
660  PMEM_TABLE_RELOC pTable = CONTAINING_RECORD(list, MEM_TABLE_RELOC, Link);
661  list = list->Flink;
662 
663  if (pTable->InsCloak)
664  {
666 
667  pTable->InsCloak = NULL;
668 
669  // Flush the icache entry.
671  }
672  }
673 }
674 
675 
676 BOOLEAN
678  _In_ QWORD Rip
679  )
687 {
688  LIST_ENTRY *list;
689 
690  list = gMemTables.Flink;
691  while (list != &gMemTables)
692  {
693  PMEM_TABLE_RELOC pTable = CONTAINING_RECORD(list, MEM_TABLE_RELOC, Link);
694  list = list->Flink;
695 
696  if (pTable->Rip == Rip)
697  {
698  return TRUE;
699  }
700  }
701 
702  return FALSE;
703 }
704 
705 
706 INTSTATUS
708  void
709  )
720 {
721  LIST_ENTRY *list;
722 
723  list = gMemTables.Flink;
724  while (list != &gMemTables)
725  {
726  PMEM_TABLE_RELOC pTable = CONTAINING_RECORD(list, MEM_TABLE_RELOC, Link);
727  list = list->Flink;
728 
729  if (pTable->InAgent)
730  {
731  // No need to pause here, uninit functions are called with all the VCPUs paused.
732  IntMtblRemoveEntry(pTable);
733 
734  RemoveEntryList(&pTable->Link);
735 
737  }
738  }
739 
740  return INT_STATUS_SUCCESS;
741 }
742 
743 
744 INTSTATUS
746  void
747  )
756 {
757  PMEM_TABLE_RELOC pTable;
758  LIST_ENTRY *list;
759 
760  list = gMemTables.Flink;
761  while (list != &gMemTables)
762  {
763  pTable = CONTAINING_RECORD(list, MEM_TABLE_RELOC, Link);
764  list = list->Flink;
765 
766  LOG("[MEMTABLE] Table at %llx accessed for %lld time, from RIP %llx, ignored = %d\n",
767  pTable->TableGva, pTable->Hits, pTable->Rip, pTable->Ignored);
768 
769  // No need to pause here, uninit functions are called with all the VCPUs paused.
770  IntMtblRemoveEntry(pTable);
771 
772  RemoveEntryList(&pTable->Link);
773 
775  }
776 
777  return INT_STATUS_SUCCESS;
778 }
_Bool BOOLEAN
Definition: intro_types.h:58
#define CONTAINING_RECORD(List, Type, Member)
Definition: introlists.h:36
uint8_t BYTE
Definition: intro_types.h:47
WINDOWS_GUEST * gWinGuest
Global variable holding the state of a Windows guest.
Definition: winguest.c:37
INTSTATUS IntKernVirtMemWrite(QWORD KernelGva, DWORD Length, void *Buffer)
Writes data to a guest kernel virtual memory range.
Definition: introcore.c:699
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
DWORD Index
The VCPU number.
Definition: guests.h:172
#define _In_
Definition: intro_sal.h:21
#define INT_STATUS_INSTRUCTION_PATCHED
Indicates that an instruction was patched.
Definition: introstatus.h:386
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
DWORD KernelSize
The size of the kernel.
Definition: guests.h:284
#define MEM_TABLE_HEADER_SIZE
Definition: memtables.h:25
struct _LIST_ENTRY * Flink
Definition: introlists.h:20
#define IC_ANY_VAS
Definition: icache.h:86
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
static LIST_HEAD gMemTables
List of memtables.
Definition: memtables.c:12
INTSTATUS IntResumeVcpus(void)
Resumes the VCPUs previously paused with IntPauseVcpus.
Definition: introcore.c:2355
void IntMtblDisable(void)
Disables mem-table instructions instrumentation.
Definition: memtables.c:644
BOOLEAN InAgent
True if we relocated the instruction inside the PT filter agent.
Definition: memtables.h:48
INTSTATUS IntMtblCheckAccess(void)
Check if the current instruction is like a switch-case table access instruction.
Definition: memtables.c:401
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
BOOLEAN IntMtblInsRelocated(QWORD Rip)
Check if the instruction at the provided RIP is instrumented.
Definition: memtables.c:677
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
int INTSTATUS
The status data type.
Definition: introstatus.h:24
QWORD gEventId
The ID of the current event.
Definition: glue.c:55
DWORD NumberOfServices
The number of entries in the SSDT.
Definition: winguest.h:819
BOOLEAN BootstrapAgentAllocated
True if the slack space for the bootstrap agent has been allocated.
Definition: guests.h:332
INTSTATUS IntMtblRemoveAgentEntries(void)
Removes only the mem-table entries that were relocated inside the PT filter.
Definition: memtables.c:707
#define MAX_MEM_TABLE_SLACK_SIZE
Definition: memtables.h:27
INTSTATUS IntPauseVcpus(void)
Pauses all the guest VCPUs.
Definition: introcore.c:2320
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
INSTRUX Instruction
The current instruction, pointed by the guest RIP.
Definition: guests.h:88
Will write the contents of the patched data inside the guest.
Definition: memcloak.h:54
INTSTATUS IntSlackAlloc(QWORD ModuleBase, BOOLEAN Pageable, DWORD Size, QWORD *Buffer, QWORD SecHint)
Allocate slack inside the guest.
Definition: slack.c:437
#define LOG(fmt,...)
Definition: glue.h:61
BOOLEAN Patched
True if the instruction has been instrumented.
Definition: memtables.h:46
QWORD SlackAddress
Slack address where the handler was allocated.
Definition: memtables.h:41
void * InsCloak
Instrumented instruction cloak handle.
Definition: memtables.h:43
#define MAX_MEM_TABLE_SIZE
Definition: memtables.h:11
BOOLEAN Ignored
True if we didn&#39;t manage to hook it.
Definition: memtables.h:47
#define _Inout_
Definition: intro_sal.h:20
#define _Out_opt_
Definition: intro_sal.h:30
QWORD TableGva
Guest virtual address of the switch-case table accessed by the instruction.
Definition: memtables.h:38
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
CPU_STATE State
The state of this VCPU. Describes what action is the VCPU currently doing.
Definition: guests.h:173
BOOLEAN Guest64
True if this is a 64-bit guest, False if it is a 32-bit guest.
Definition: guests.h:290
unsigned long long QWORD
Definition: intro_types.h:53
QWORD Rip
RIP of the instrumented instruction.
Definition: memtables.h:37
BOOLEAN Dumped
TRUE if it&#39;s a problematic table and we dumped it&#39;s content in an error.
Definition: memtables.h:49
QWORD IntPtiGetAgentAddress(void)
Get the guest virtual address where the PT filter resides.
Definition: ptfilter.c:1974
#define TRUE
Definition: intro_types.h:30
QWORD Ssdt
Guest virtual address of the SSDT structure inside the kernel.
Definition: winguest.h:818
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
#define TRACE(fmt,...)
Definition: glue.h:58
static INTSTATUS IntMtblRemoveEntry(PMEM_TABLE_RELOC Reloc)
Removes a mem-table entry.
Definition: memtables.c:32
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.
Definition: memcloak.c:548
QWORD KernelVa
The guest virtual address at which the kernel image.
Definition: guests.h:283
INTSTATUS IntIcFlushAddress(PINS_CACHE Cache, QWORD Gva, QWORD Cr3)
Flush entries cached from a given address.
Definition: icache.c:597
BYTE WordSize
Guest word size. Will be 4 for 32-bit guests and 8 for 64-bit guests.
Definition: guests.h:367
The RIP of a thread.
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
Definition: introlists.h:135
#define WARNING(fmt,...)
Definition: glue.h:60
void * InstructionCache
The currently used instructions cache.
Definition: guests.h:404
uint32_t DWORD
Definition: intro_types.h:49
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...
Definition: dumper.c:204
#define IC_TAG_MTBL
Mem Table.
Definition: memtags.h:113
#define MEM_TABLE_ENTRY_SIZE
Definition: memtables.h:26
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
INTSTATUS IntMtblUninit(void)
Completely uninit the mem-tables, removing all the handlers from the NT slack space.
Definition: memtables.c:745
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.
Definition: introcore.c:674
#define LIST_HEAD_INIT(Name)
Definition: introlists.h:39
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
INTSTATUS IntMemClkUncloakRegion(void *CloakHandle, DWORD Options)
Removes a cloak region, making the original memory contents available again to the guest...
Definition: memcloak.c:970
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
Holds register state.
Definition: glueiface.h:30
void IntDisasmGva(QWORD Gva, DWORD Length)
This function disassembles a code buffer (given its GVA) and then dumps the instructions (textual dis...
Definition: dumper.c:432
BOOLEAN IntMtblIsPtrInReloc(QWORD Ptr, THS_PTR_TYPE Type, QWORD *Table)
Check if the given pointer is inside a mem-table relocation handler.
Definition: memtables.c:596
DWORD SlackSize
Size of the allocated slack buffer.
Definition: memtables.h:42
char CHAR
Definition: intro_types.h:56
QWORD Hits
Number of times this instruction generated a read EPT violation.
Definition: memtables.h:39
QWORD IntPtiAllocMemtableSpace(QWORD Rip, DWORD Size)
Allocate space for a mem-table.
Definition: ptfilter.c:1988
QWORD Gla
The accessed guest virtual address. Valid only for EPT exits.
Definition: guests.h:102
static INTSTATUS IntMtblPatchInstruction(PMEM_TABLE_RELOC Reloc, PINSTRUX Instrux, PIG_ARCH_REGS Regs)
Relocate and instrument a switch-case load instruction.
Definition: memtables.c:70
LIST_ENTRY Link
List element link.
Definition: memtables.h:35
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
Handling EPT violation.
Definition: guests.h:22