Using LLMs to analyze Hyper-V Register State and Instruction Trace

Using LLMs (in this case, with ChatGPT) to debug and reverse engineer Windows hypervisor technology is like going from “hunting with a stone spear to using a guided missile”.*

*paraphrased from the article, The Future of Crash Analysis: AI meets WinDbg.

I’ve written numerous articles on capturing Intel Processor Trace during Windows VM Launches and VM Exits. And I was asked recently whether it’s possible to capture register state at each instruction execution, at every N instructions (like every 32 instructions), or even after an allotted period of time. This would be awesome for exploring the traversal of given code paths, and seeing how key register contents change. Well, yes, it is possible; let’s take a walk-through.

Good pre-requisite reading for this article is: Using ChatGPT on Windows Secure Kernel with Intel Processor Trace.

Let’s take a very simple example: starting in the Windows kernel (ntkrnlmp) in Guest mode (of course), undergoing a transition to Host mode, and then back into ntkrnlmp as a Guest.  This is one of a million interesting code paths to look at, but it’s particularly good because it invokes a VM Exit and then a VM Resume on the boostrap processor (BSP), as the Windows kernel traps into the hypervisor (Host mode) and then does a resume back into the Normal Kernel (Guest mode again). Let’s examine that code path and do register state capture with the use of the built-in SourcePoint Command language.

As we’ll be doing some automation here, I’ll be using using the SourcePoint powerful command language via either the Command window, or as a macro. This programming language is very ‘C’-like, and has a ton of built-in functions to perform just about anything that the GUI is capable of. For some background reading, go here: The Minnowboard Chronicles Episode 9: SourcePoint Command Language and Macros.

To dump register state, let’s zero in specifically on the General Purpose Registers and the VMCS registers. A simple macro, RegisterDump.mac, is used to dump all of these; it looks like this:

regs
sregs
cregs
dregs

printf("Guest State:\n")
printf(“GUEST_BNDCFGS                  %16X\n”, GUEST_BNDCFGS)
printf(“GUEST_CR0                      %16X\n”, GUEST_CR0)
printf(“GUEST_CR3                      %16X\n”, GUEST_CR3)
printf(“GUEST_CR4                      %16X\n”, GUEST_CR4)
printf(“GUEST_CS                       %16X\n”, GUEST_CS)
printf(“GUEST_CSAR                     %16X\n”, GUEST_CSAR)
printf(“GUEST_CSBAS                    %16X\n”, GUEST_CSBAS)
printf(“GUEST_CSLIM                    %16X\n”, GUEST_CSLIM)
printf(“GUEST_DEBUGCTL                 %16X\n”, GUEST_DEBUGCTL)
printf(“GUEST_DR7                      %16X\n”, GUEST_DR7)
printf(“GUEST_DS                       %16X\n”, GUEST_DS)
printf(“GUEST_DSAR                     %16X\n”, GUEST_DSAR)
printf(“GUEST_DSBAS                    %16X\n”, GUEST_DSBAS)
printf(“GUEST_DSLIM                    %16X\n”, GUEST_DSLIM)
printf(“GUEST_EFER                     %16X\n”, GUEST_EFER)
printf(“GUEST_ES                       %16X\n”, GUEST_ES)
printf(“GUEST_ESAR                     %16X\n”, GUEST_ESAR)
printf(“GUEST_ESBAS                    %16X\n”, GUEST_ESBAS)
printf(“GUEST_ESLIM                    %16X\n”, GUEST_ESLIM)
printf(“GUEST_FS                       %16X\n”, GUEST_FS)
printf(“GUEST_FSAR                     %16X\n”, GUEST_FSAR)
printf(“GUEST_FSBAS                    %16X\n”, GUEST_FSBAS)
printf(“GUEST_FSLIM                    %16X\n”, GUEST_FSLIM)
printf(“GUEST_GDTBAS                   %16X\n”, GUEST_GDTBAS)
printf(“GUEST_GDTLIM                   %16X\n”, GUEST_GDTLIM)
printf(“GUEST_GS                       %16X\n”, GUEST_GS)
printf(“GUEST_GSAR                     %16X\n”, GUEST_GSAR)
printf(“GUEST_GSBAS                    %16X\n”, GUEST_GSBAS)
printf(“GUEST_GSLIM                    %16X\n”, GUEST_GSLIM)
printf(“GUEST_IDTBAS                   %16X\n”, GUEST_IDTBAS)
printf(“GUEST_IDTLIM                   %16X\n”, GUEST_IDTLIM)
printf(“GUEST_INT_STATE                %16X\n”, GUEST_INT_STATE)
printf(“GUEST_INT_STS                  %16X\n”, GUEST_INT_STS)
printf(“GUEST_INTERRUPT_SSP_TABLE_ADDR %16X\n”, GUEST_INTERRUPT_SSP_TABLE_ADDR)
printf(“GUEST_LBR_CTL                  %16X\n”, GUEST_LBR_CTL)
printf(“GUEST_LDTAR                    %16X\n”, GUEST_LDTAR)
printf(“GUEST_LDTBAS                   %16X\n”, GUEST_LDTBAS)
printf(“GUEST_LDTLIM                   %16X\n”, GUEST_LDTLIM)
printf(“GUEST_LDTR                     %16X\n”, GUEST_LDTR)
printf(“GUEST_LINEAR_ADDR              %16X\n”, GUEST_LINEAR_ADDR)
printf(“GUEST_PAT                      %16X\n”, GUEST_PAT)
printf(“GUEST_PDE                      %16X\n”, GUEST_PDE)
printf(“GUEST_PDPTE0                   %16X\n”, GUEST_PDPTE0)
printf(“GUEST_PDPTE1                   %16X\n”, GUEST_PDPTE1)
printf(“GUEST_PDPTE2                   %16X\n”, GUEST_PDPTE2)
printf(“GUEST_PDPTE3                   %16X\n”, GUEST_PDPTE3)
printf(“GUEST_PERF_GLOBAL_CTRL         %16X\n”, GUEST_PERF_GLOBAL_CTRL)
printf(“GUEST_PHYSICAL_ADDR            %16X\n”, GUEST_PHYSICAL_ADDR)
printf(“GUEST_PKRS                     %16X\n”, GUEST_PKRS)
printf(“GUEST_PML_INDEX                %16X\n”, GUEST_PML_INDEX)
printf(“GUEST_RFLAGS                   %16X\n”, GUEST_RFLAGS)
printf(“GUEST_RIP                      %16X\n”, GUEST_RIP)
printf(“GUEST_RSP                      %16X\n”, GUEST_RSP)
printf(“GUEST_RTIT_CTL                 %16X\n”, GUEST_RTIT_CTL)
printf(“GUEST_S_CET                    %16X\n”, GUEST_S_CET)
printf(“GUEST_SMBASE                   %16X\n”, GUEST_SMBASE)
printf(“GUEST_SS                       %16X\n”, GUEST_SS)
printf(“GUEST_SSAR                     %16X\n”, GUEST_SSAR)
printf(“GUEST_SSBAS                    %16X\n”, GUEST_SSBAS)
printf(“GUEST_SSLIM                    %16X\n”, GUEST_SSLIM)
printf(“GUEST_SSP                      %16X\n”, GUEST_SSP)
printf(“GUEST_STATE                    %16X\n”, GUEST_STATE)
printf(“GUEST_SYSENTER_CS              %16X\n”, GUEST_SYSENTER_CS)
printf(“GUEST_SYSENTER_EIP             %16X\n”, GUEST_SYSENTER_EIP)
printf(“GUEST_SYSENTER_ESP             %16X\n”, GUEST_SYSENTER_ESP)
printf(“GUEST_TR                       %16X\n”, GUEST_TR)
printf(“GUEST_TRAR                     %16X\n”, GUEST_TRAR)
printf(“GUEST_TRBAS                    %16X\n”, GUEST_TRBAS)
printf(“GUEST_TRLIM                    %16X\n”, GUEST_TRLIM)
printf(“GUEST_UINV                     %16X\n”, GUEST_UINV)
printf(“GUEST_VMCSP                    %16X\n”, GUEST_VMCSP)

printf("Host State:\n")
printf(“HOST_CR0                      = %16X\n”, HOST_CR0)
printf(“HOST_CR3                      = %16X\n”, HOST_CR3)
printf(“HOST_CR4                      = %16X\n”, HOST_CR4)
printf(“HOST_CS                       = %16X\n”, HOST_CS)
printf(“HOST_DS                       = %16X\n”, HOST_DS)
printf(“HOST_EFER                     = %16X\n”, HOST_EFER)
printf(“HOST_ES                       = %16X\n”, HOST_ES)
printf(“HOST_FS                       = %16X\n”, HOST_FS)
printf(“HOST_FSBAS                    = %16X\n”, HOST_FSBAS)
printf(“HOST_GDTBAS                   = %16X\n”, HOST_GDTBAS)
printf(“HOST_GS                       = %16X\n”, HOST_GS)
printf(“HOST_GSBAS                    = %16X\n”, HOST_GSBAS)
printf(“HOST_IDTBAS                   = %16X\n”, HOST_IDTBAS)
printf(“HOST_INTERRUPT_SSP_TABLE_ADDR = %16X\n”, HOST_INTERRUPT_SSP_TABLE_ADDR)
printf(“HOST_PAT                      = %16X\n”, HOST_PAT)
printf(“HOST_PERF_GLOBAL_CTRL         = %16X\n”, HOST_PERF_GLOBAL_CTRL)
printf(“HOST_PKRS                     = %16X\n”, HOST_PKRS)
printf(“HOST_RIP                      = %16X\n”, HOST_RIP)
printf(“HOST_RSP                      = %16X\n”, HOST_RSP)
printf(“HOST_S_CET                    = %16X\n”, HOST_S_CET)
printf(“HOST_SS                       = %16X\n”, HOST_SS)
printf(“HOST_SSP                      = %16X\n”, HOST_SSP)
printf(“HOST_SYSENTER_CS              = %16X\n”, HOST_SYSENTER_CS)
printf(“HOST_SYSENTER_EIP             = %16X\n”, HOST_SYSENTER_EIP)
printf(“HOST_SYSENTER_ESP             = %16X\n”, HOST_SYSENTER_ESP)
printf(“HOST_TR                       = %16X\n”, HOST_TR)
printf(“HOST_TRBAS                    = %16X\n”, HOST_TRBAS)

printf("VM-Entry Controls:\n")
printf(“VMENTRY_CONTROL      = %16X\n”, VMENTRY_CONTROL)
printf(“VMENTRY_EXC_ERR      = %16X\n”, VMENTRY_EXC_ERR)
printf(“VMENTRY_INST_LEN     = %16X\n”, VMENTRY_INST_LEN)
printf(“VMENTRY_INT_INFO     = %16X\n”, VMENTRY_INT_INFO)
printf(“VMENTRY_MSR_LD_ADDR  = %16X\n”, VMENTRY_MSR_LD_ADDR)
printf(“VMENTRY_MSR_LD_COUNT = %16X\n”, VMENTRY_MSR_LD_COUNT)

printf("VM-Exit Controls:\n")
printf(“VMEXIT_CONTROL2            = %16X\n”, VMEXIT_CONTROL2)
printf(“VMEXIT_INST_INFO       = %16X\n”, VMEXIT_INST_INFO)
printf(“VMEXIT_INST_LEN        = %16X\n”, VMEXIT_INST_LEN)
printf(“VMEXIT_INT_ERR         = %16X\n”, VMEXIT_INT_ERR)
printf(“VMEXIT_INT_INFO        = %16X\n”, VMEXIT_INT_INFO)
printf(“VMEXIT_MSR_LD_ADDR     = %16X\n”, VMEXIT_MSR_LD_ADDR)
printf(“VMEXIT_MSR_LD_COUNT    = %16X\n”, VMEXIT_MSR_LD_COUNT)
printf(“VMEXIT_MSR_ST_ADDR     = %16X\n”, VMEXIT_MSR_ST_ADDR)
printf(“VMEXIT_MSR_ST_COUNT    = %16X\n”, VMEXIT_MSR_ST_COUNT)
printf(“VMEXIT_PRIMARY         = %16X\n”, VMEXIT_PRIMARY)
printf(“VMEXIT_QUALIFICATION   = %16X\n”, VMEXIT_QUALIFICATION)
printf(“VMEXIT_REASON          = %16X\n”, VMEXIT_REASON)
printf(“VMEXIT_XSS_EXIT_BITMAP = %16X\n”, VMEXIT_XSS_EXIT_BITMAP)

printf("VM-Execution Controls:\n")
printf(“VMCS_APIC_ACC_ADDR       = %16X\n”, VMCS_APIC_ACC_ADDR) 
printf(“VMCS_CR0_MASK            = %16X\n”, VMCS_CR0_MASK)
printf(“VMCS_CR0_SHADOW          = %16X\n”, VMCS_CR0_SHADOW)
printf(“VMCS_CR3_COUNT           = %16X\n”, VMCS_CR3_COUNT)
printf(“VMCS_CR3_VALUE0          = %16X\n”, VMCS_CR3_VALUE0)
printf(“VMCS_CR3_VALUE1          = %16X\n”, VMCS_CR3_VALUE1)
printf(“VMCS_CR3_VALUE2          = %16X\n”, VMCS_CR3_VALUE2)
printf(“VMCS_CR3_VALUE3          = %16X\n”, VMCS_CR3_VALUE3)
printf(“VMCS_CR4_MASK            = %16X\n”, VMCS_CR4_MASK)
printf(“VMCS_CR4_SHADOW          = %16X\n”, VMCS_CR4_SHADOW)
printf(“VMCS_ENCLS_EXIT_BITMAP   = %16X\n”, VMCS_ENCLS_EXIT_BITMAP)
printf(“VMCS_ENCLV_EXIT_BITMAP   = %16X\n”, VMCS_ENCLV_EXIT_BITMAP)
printf(“VMCS_EOI_EXIT_BITMAP0    = %16X\n”, VMCS_EOI_EXIT_BITMAP0)
printf(“VMCS_EOI_EXIT_BITMAP1    = %16X\n”, VMCS_EOI_EXIT_BITMAP1)
printf(“VMCS_EOI_EXIT_BITMAP2    = %16X\n”, VMCS_EOI_EXIT_BITMAP2)
printf(“VMCS_EOI_EXIT_BITMAP3    = %16X\n”, VMCS_EOI_EXIT_BITMAP3)
printf(“VMCS_EPTP                = %16X\n”, VMCS_EPTP)
printf(“VMCS_EPTP_INDEX          = %16X\n”, VMCS_EPTP_INDEX)
printf(“VMCS_EPTP_LIST_ADDR      = %16X\n”, VMCS_EPTP_LIST_ADDR)
printf(“VMCS_EXC_BITMAP          = %16X\n”, VMCS_EXC_BITMAP)
printf(“VMCS_HIGH_PASID_ADDR     = %16X\n”, VMCS_HIGH_PASID_ADDR)
printf(“VMCS_HLAT_PRESIZE        = %16X\n”, VMCS_HLAT_PRESIZE)
printf(“VMCS_HLATP               = %16X\n”, VMCS_HLATP)
printf(“VMCS_IDT_ERR             = %16X\n”, VMCS_IDT_ERR)
printf(“VMCS_IDT_INFO            = %16X\n”, VMCS_IDT_INFO)
printf(“VMCS_INST_TOC            = %16X\n”, VMCS_INST_TOC)
printf(“VMCS_IO_BITMAPA          = %16X\n”, VMCS_IO_BITMAPA)
printf(“VMCS_IO_BITMAPB          = %16X\n”, VMCS_IO_BITMAPB)
printf(“VMCS_IO_RCX              = %16X\n”, VMCS_IO_RCX)
printf(“VMCS_IO_RDI              = %16X\n”, VMCS_IO_RDI)
printf(“VMCS_IO_RIP              = %16X\n”, VMCS_IO_RIP)
printf(“VMCS_IO_RSI              = %16X\n”, VMCS_IO_RSI)
printf(“VMCS_LOW_PASID_ADDR      = %16X\n”, VMCS_LOW_PASID_ADDR)
printf(“VMCS_MSR_BITMAP          = %16X\n”, VMCS_MSR_BITMAP)
printf(“VMCS_PCONFIG_EXIT_BITMAP = %16X\n”, VMCS_PCONFIG_EXIT_BITMAP)
printf(“VMCS_PF_MASK             = %16X\n”, VMCS_PF_MASK)
printf(“VMCS_PF_MATCH            = %16X\n”, VMCS_PF_MATCH)
printf(“VMCS_PID_ADDR            = %16X\n”, VMCS_PID_ADDR)
printf(“VMCS_PIDP_INDEX          = %16X\n”, VMCS_PIDP_INDEX)
printf(“VMCS_PIDP_TABLE_ADDR     = %16X\n”, VMCS_PIDP_TABLE_ADDR)
printf(“VMCS_PINV                = %16X\n”, VMCS_PINV)
printf(“VMCS_PLE_GAP             = %16X\n”, VMCS_PLE_GAP)
printf(“VMCS_PLE_WIN             = %16X\n”, VMCS_PLE_WIN)
printf(“VMCS_PML_ADDR            = %16X\n”, VMCS_PML_ADDR)
printf(“VMCS_SHARED_EPTP         = %16X\n”, VMCS_SHARED_EPTP)
printf(“VMCS_SPEC_CTRL_MASK      = %16X\n”, VMCS_SPEC_CTRL_MASK)
printf(“VMCS_SPEC_CTRL_SDW       = %16X\n”, VMCS_SPEC_CTRL_SDW)
printf(“VMCS_SPPTP               = %16X\n”, VMCS_SPPTP)
printf(“VMCS_TD_KEYID            = %16X\n”, VMCS_TD_KEYID)
printf(“VMCS_TPR_THRESHOLD       = %16X\n”, VMCS_TPR_THRESHOLD)
printf(“VMCS_TSC_MULT            = %16X\n”, VMCS_TSC_MULT)
printf(“VMCS_TSC_OFFSET          = %16X\n”, VMCS_TSC_OFFSET)
printf(“VMCS_VAPIC_ADDR          = %16X\n”, VMCS_VAPIC_ADDR)
printf(“VMCS_VEIA                = %16X\n”, VMCS_VEIA)
printf(“VMCS_VM_PIN              = %16X\n”, VMCS_VM_PIN)
printf(“VMCS_VM_PRIMARY          = %16X\n”, VMCS_VM_PRIMARY)
printf(“VMCS_VM_SECONDARY        = %16X\n”, VMCS_VM_SECONDARY)
printf(“VMCS_VM_TERTIARY         = %16X\n”, VMCS_VM_TERTIARY)
printf(“VMCS_VMCSP               = %16X\n”, VMCS_VMCSP)
printf(“VMCS_VMFC                = %16X\n”, VMCS_VMFC)
printf(“VMCS_VMINST_ERR          = %16X\n”, VMCS_VMINST_ERR)
printf(“VMCS_VMREAD_BITMAP       = %16X\n”, VMCS_VMREAD_BITMAP)
printf(“VMCS_VMWRITE_BITMAP      = %16X\n”, VMCS_VMWRITE_BITMAP)
printf(“VMCS_VPID                = %16X\n”, VMCS_VPID)

Note that the regs, sregs, cregs and dregs respectively display the GPRs, segment registers, control registers, and debug registers. And, although there is not currently a single command that dumps the VMCS (we’ll add that in a future release), for illustration purposes I’ve just used a bunch of printf’s: note that it’s a simple matter of just typing in a register’s name into the Command window, or calling it out within a macro, to display it.

This is all very interesting, but how do I display this state at a pre-determined sequence of instructions, breakpoints, time, or otherwise? This is easy: the use of event macros, the command language, and breakpoints will do the trick. SourcePoint has powerful automation capabilities built-in.

Let’s take an example: below are some simple steps that perform the tasks for this investigation:

  1. Dump registers (capturing some of the current processor state)
  2. Do a target Go
  3. Wait for 0.001 seconds
  4. Stop the target
  5. Capture Intel Processor Trace
  6. Dump the registers again

Firstly, set an event macro up to run the RegisterDump.mac when a breakpoint is hit:

This is super simple to encode in a macro with a handful of lines. Here’s the pseudocode:

run RegisterDump.mac     // Dump the registers
go
sleep(0.001)      // Sleep for 1/1000th of a second
stop
print cycles    // Dump the Intel PT data
run RegisterDump.mac

Below is the some of the register dump, as well as some Intel PT:

RAX    = 00000000FFFFFFB0: EAX=FFFFFFB0 AX=FFB0 AH=FF AL=B0
RBX    = 0000000000000030: EBX=00000030 BX=0030 BH=00 BL=30
RCX    = 00000000000002D0: ECX=000002D0 CX=02D0 CH=02 CL=D0
RDX    = FFFFF80452551000: EDX=52551000 DX=1000 DH=10 DL=00
RBP    = 00000000002142A0: EBP=002142A0 BP=42A0 BPL=A0
RSI    = FFFFF804525512D0: ESI=525512D0 SI=12D0 SIL=D0
RDI    = 00000000000002D0: EDI=000002D0 DI=02D0 DIL=D0
RSP    = FFFFCF0A7D006B00: ESP=7D006B00 SP=6B00 SPL=00
R8     = 0000000000214000: R8D=00214000 R8W=4000 R8B=00
R9     = 0000000000020000: R9D=00020000 R9W=0000 R9B=00
R10    = 0000000000001000: R10D=00001000 R10W=1000 R10B=00
R11    = FFFFE18218448120: R11D=18448120 R11W=8120 R11B=20
R12    = 0000000000214000: R12D=00214000 R12W=4000 R12B=00
R13    = 0000000000020000: R13D=00020000 R13W=0000 R13B=00
R14    = FFFFE18218476000: R14D=18476000 R14W=6000 R14B=00
R15    = FFFFF80452551000: R15D=52551000 R15W=1000 R15B=00
CS     = 0010
DS     = 002B
SS     = 0018
ES     = 002B
FS     = 0053
GS     = 002B
RIP    = FFFFF80457BE567A: EIP=57BE567A IP=567A
RFLAGS = 0000000000050282: EFLAGS=00050282 FLAGS=0282 ID=0 VIP=0 VIF=0 AC=1 VM=0 RF=1 NT=0 IOPL=0 OF=0 DF=0 INF=1 TF=0 SF=1 ZF=0 AF=0 PF=0 CF=0
CS     = 0010
CSBAS  = 0000000000000000: CSBAS_32=00000000
CSLIM  = 00000000
CSAR   = 209B: G=0 D=0 L=1 AVL=0 P=1 DPL=0 C=0 R=1 A=1
DS     = 002B
DSBAS  = 0000000000000000: DSBAS_32=00000000
DSLIM  = FFFFFFFF
DSAR   = C0F3: G=1 B=1 AVL=0 P=1 DPL=3 E=0 W=1 A=1
SS     = 0018
SSBAS  = 0000000000000000: SSBAS_32=00000000
SSLIM  = 00000000
SSAR   = 4093: G=0 B=1 AVL=0 P=1 DPL=0 E=0 W=1 A=1
ES     = 002B
ESBAS  = 0000000000000000: ESBAS_32=00000000
ESLIM  = FFFFFFFF
ESAR   = C0F3: G=1 B=1 AVL=0 P=1 DPL=3 E=0 W=1 A=1
FS     = 0053
FSBASE = 0000000000000000
FSLIM  = 00003C00
FSAR   = 40F3: G=0 B=1 AVL=0 P=1 DPL=3 E=0 W=1 A=1
GS     = 002B
GSBASE = FFFFF804522C2000
GSLIM  = FFFFFFFF
GSAR   = C0F3: G=1 B=1 AVL=0 P=1 DPL=3 E=0 W=1 A=1
GDTBAS = FFFFF8045386EFB0: GDTBAS_32=5386EFB0
GDTLIM = 0057
IDTBAS = FFFFF8045386C000: IDTBAS_32=5386C000
IDTLIM = 0FFF
LDTR   = 0000
LDTBAS = 0000000000000000: LDTBAS_32=00000000
LDTLIM = FFFF
LDTAR  = C000: G=1 AVL=0 P=0 DPL=0 B=0
TR     = 0040
TSSBAS = FFFFF8045386D000: TSSBAS_32=5386D000
TSSLIM = 00000067
TSSAR  = 008B: G=0 AVL=0 P=1 DPL=0 B=1
CR0 = 0000000080050033: CR0_32=80050033 PG=1 CD=0 NW=0 AM=1 WP=1 NE=1 ET=1 TS=0 EM=0 MP=1 PE=1
CR2 = FFFFE182184E5000: CR2_32=184E5000
CR3 = 0000000487282000: CR3_32=87282000 LAM_U48=0 LAM_U57=0 PDB=0000487282 PCD=0 PWT=0
CR4 = 0000000000B52EF8: CR4_32=00B52EF8 LAM_SUP=0 UINTR=0 PKS=0 CET=1 PKE=0 SMAP=1 SMEP=1 KL=0 OSXSAVE=1 PCIDE=0 FSGSBASE=1 SMXE=0 VMXE=1 LA57=0 UMIP=1 OSXMMEXCPT=1 OSFXSR=1 PCE=0 PGE=1 MCE=1 PSE=1 PAE=1 DE=1 TSD=0 PVI=0 VME=0
CR8 = 0000000000000000: TPR=0
SSP = 0000000000000000
DR0 = 0000000000000000
DR1 = 0000000000000000
DR2 = 0000000000000000
DR3 = 0000000000000000
DR6 = 00000000FFFF0FF0: RTM=1 BT=0 BS=0 BD=0 B3=0 B2=0 B1=0 B0=0
DR7 = 0000000000000400: LN3=0 RW3=0 LN2=0 RW2=0 LN1=0 RW1=0 LN0=0 RW0=0 GD=0 RTM=0 GE=0 LE=0 G3=0 L3=0 G2=0 L2=0 G1=0 L1=0 G0=0 L0=0

Guest State:
GUEST_BNDCFGS                   DEADBEE0BADBEEF
GUEST_CR0                              80050033
GUEST_CR3                                1AD000
GUEST_CR4                                B52EF8
GUEST_CS                                     10
GUEST_CSAR                                 209B
GUEST_CSBAS                                   0
GUEST_CSLIM                                   0
GUEST_DEBUGCTL                                0
GUEST_DR7                                   400
GUEST_DS                                     2B
GUEST_DSAR                                 C0F3
GUEST_DSBAS                                   0
GUEST_DSLIM                            FFFFFFFF
GUEST_EFER                                  D00
GUEST_ES                                     2B
GUEST_ESAR                                 C0F3
GUEST_ESBAS                                   0
GUEST_ESLIM                            FFFFFFFF
GUEST_FS                                     53
GUEST_FSAR                                 40F3
GUEST_FSBAS                                   0
GUEST_FSLIM                                3C00
GUEST_GDTBAS                   FFFFF8045386EFB0
GUEST_GDTLIM                                 57
GUEST_GS                                     2B
GUEST_GSAR                                 C0F3
GUEST_GSBAS                    FFFFF804522C2000
GUEST_GSLIM                            FFFFFFFF
GUEST_IDTBAS                   FFFFF8045386C000
GUEST_IDTLIM                                FFF
GUEST_INT_STATE                               0
GUEST_INT_STS                                 0
GUEST_INTERRUPT_SSP_TABLE_ADDR                0
GUEST_LBR_CTL                   DEADBEE0BADBEEF
GUEST_LDTAR                               1C000
GUEST_LDTBAS                                  0
GUEST_LDTLIM                           FFFFFFFF
GUEST_LDTR                                    0
GUEST_LINEAR_ADDR                             0
GUEST_PAT                         7010600070106
GUEST_PDE                                     0
GUEST_PDPTE0                                  0
GUEST_PDPTE1                                  0
GUEST_PDPTE2                                  0
GUEST_PDPTE3                                  0
GUEST_PERF_GLOBAL_CTRL                       FF
GUEST_PHYSICAL_ADDR                  4000166318
GUEST_PKRS                      DEADBEE0BADBEEF
GUEST_PML_INDEX                               0
GUEST_RFLAGS                              40206
GUEST_RIP                      FFFFF80458056573
GUEST_RSP                      FFFFCF0A7D006F00
GUEST_RTIT_CTL                             2C0F
GUEST_S_CET                                   0
GUEST_SMBASE                                  0
GUEST_SS                                     18
GUEST_SSAR                                 4093
GUEST_SSBAS                                   0
GUEST_SSLIM                                   0
GUEST_SSP                                     0
GUEST_STATE                                   0
GUEST_SYSENTER_CS                             0
GUEST_SYSENTER_EIP                            0
GUEST_SYSENTER_ESP                            0
GUEST_TR                                     40
GUEST_TRAR                                   8B
GUEST_TRBAS                    FFFFF8045386D000
GUEST_TRLIM                                  67
GUEST_UINV                                 BEEF
GUEST_VMCSP                    FFFFFFFFFFFFFFFF

Host State:
HOST_CR0                      =         80010031
HOST_CR3                      =        100103000
HOST_CR4                      =            422E0
HOST_CS                       =               10
HOST_DS                       =               20
HOST_EFER                     =              D01
HOST_ES                       =               20
HOST_FS                       =               20
HOST_FSBAS                    =                0
HOST_GDTBAS                   = FFFFF81165E01190
HOST_GS                       =               20
HOST_GSBAS                    = FFFFF81165FAD000
HOST_IDTBAS                   = FFFFF81165E00010
HOST_INTERRUPT_SSP_TABLE_ADDR =                0
HOST_PAT                      =  606050400070106
HOST_PERF_GLOBAL_CTRL         =                0
HOST_PKRS                     =  DEADBEE0BADBEEF
HOST_RIP                      = FFFFF81165A3E30B
HOST_RSP                      =      10000005FC0
HOST_S_CET                    =                0
HOST_SS                       =               20
HOST_SSP                      =                0
HOST_SYSENTER_CS              =                0
HOST_SYSENTER_EIP             =                0
HOST_SYSENTER_ESP             =                0
HOST_TR                       =               30
HOST_TRBAS                    = FFFFF81165F7D000

VM-Entry Controls:
VMENTRY_CONTROL      =           1233FF
VMENTRY_EXC_ERR      =                0
VMENTRY_INST_LEN     =                0
VMENTRY_INT_INFO     =                0
VMENTRY_MSR_LD_ADDR  =                0
VMENTRY_MSR_LD_COUNT =                0

VM-Exit Controls:
VMEXIT_CONTROL2        =  DEADBEE0BADBEEF
VMEXIT_INST_INFO       =         12614924
VMEXIT_INST_LEN        =                5
VMEXIT_INT_ERR         =                0
VMEXIT_INT_INFO        =                0
VMEXIT_MSR_LD_ADDR     =                0
VMEXIT_MSR_LD_COUNT    =                0
VMEXIT_MSR_ST_ADDR     =                0
VMEXIT_MSR_ST_COUNT    =                0
VMEXIT_PRIMARY         =            3FFFF
VMEXIT_QUALIFICATION   =               20
VMEXIT_REASON          =               2E
VMEXIT_XSS_EXIT_BITMAP =                0

VM-Execution Controls:
VMCS_APIC_ACC_ADDR       =        101400000
VMCS_CR0_MASK            = FFFFFFFFFFFFFFE1
VMCS_CR0_SHADOW          =         80050033
VMCS_CR3_COUNT           =                0
VMCS_CR3_VALUE0          =                0
VMCS_CR3_VALUE1          =                0
VMCS_CR3_VALUE2          =                0
VMCS_CR3_VALUE3          =                0
VMCS_CR4_MASK            = FFFFFFFFFFFFFE7F
VMCS_CR4_SHADOW          =           B50EF8
VMCS_ENCLS_EXIT_BITMAP   =  DEADBEE0BADBEEF
VMCS_ENCLV_EXIT_BITMAP   =  DEADBEE0BADBEEF
VMCS_EOI_EXIT_BITMAP0    =                0
VMCS_EOI_EXIT_BITMAP1    =                0
VMCS_EOI_EXIT_BITMAP2    =                0
VMCS_EOI_EXIT_BITMAP3    =                0
VMCS_EPTP                =        1109F501E
VMCS_EPTP_INDEX          =             BEEF
VMCS_EPTP_LIST_ADDR      =                0
VMCS_EXC_BITMAP          =            60000
VMCS_HIGH_PASID_ADDR     =  DEADBEE0BADBEEF
VMCS_HLAT_PRESIZE        =             BEEF
VMCS_HLATP               =  DEADBEE0BADBEEF
VMCS_IDT_ERR             =                0
VMCS_IDT_INFO            =                0
VMCS_INST_TOC            =          BADBEEF
VMCS_IO_BITMAPA          =        101401000
VMCS_IO_BITMAPB          =        101402000
VMCS_IO_RCX              =                1
VMCS_IO_RDI              =                1
VMCS_IO_RIP              =                1
VMCS_IO_RSI              =                1
VMCS_LOW_PASID_ADDR      =  DEADBEE0BADBEEF
VMCS_MSR_BITMAP          =        10E054000
VMCS_PCONFIG_EXIT_BITMAP =  DEADBEE0BADBEEF
VMCS_PF_MASK             =                0
VMCS_PF_MATCH            =                0
VMCS_PID_ADDR            =        10E05B340
VMCS_PIDP_INDEX          =             BEEF
VMCS_PIDP_TABLE_ADDR     =  DEADBEE0BADBEEF
VMCS_PINV                =               1D
VMCS_PLE_GAP             =                0
VMCS_PLE_WIN             =                0
VMCS_PML_ADDR            =                0
VMCS_SHARED_EPTP         =  DEADBEE0BADBEEF
VMCS_SPEC_CTRL_MASK      =  DEADBEE0BADBEEF
VMCS_SPEC_CTRL_SDW       =  DEADBEE0BADBEEF
VMCS_SPPTP               =  DEADBEE0BADBEEF
VMCS_TD_KEYID            =          BADBEEF
VMCS_TPR_THRESHOLD       =                0
VMCS_TSC_MULT            =    1000000000000
VMCS_TSC_OFFSET          =                0
VMCS_VAPIC_ADDR          =        10E053000
VMCS_VEIA                =                0
VMCS_VM_PIN              =               BF
VMCS_VM_PRIMARY          =         B6A065FA
VMCS_VM_SECONDARY        =           5013AF
VMCS_VM_TERTIARY         =                0
VMCS_VMCSP               =                0
VMCS_VMFC                =                0
VMCS_VMINST_ERR          =                C
VMCS_VMREAD_BITMAP       =  DEADBEE0BADBEEF
VMCS_VMWRITE_BITMAP      =  DEADBEE0BADBEEF
VMCS_VPID                =                1

-130226 P0     *** VMCS pointer change: 10E052 ***                                            
-130192 P0     FFFFF804579D52A7 test        al,40                                                -229.414 us
        P0     FFFFF804579D52A9 je          ::ntkrnlmp.woutput_l+90f
        P0     FFFFF804579D52AB cmp         [rdx+10],00000000
        P0     FFFFF804579D52B0 jne         ::ntkrnlmp.woutput_l+90f
        P0     FFFFF804579D52B7 call        ::ntkrnlmp.fputwc_nolock
        P0     FFFFF804579D638C sub         rsp,00000038
        P0     FFFFF80457D6390 test        rdx,rdx
        P0     FFFFF804579D6393 jne         ::ntkrnlmp.fputwc_nolock+22
        P0     FFFFF804579D63AE add         [rdx+08],fffffffe
        P0     FFFFF804579D63B2 js          ::ntkrnlmp.fputwc_nolock+37
-130185 P0     FFFFF804579D63B4 mov         rax,[rdx]                                            -229.406 us

Note that whenever a VMCS register cannot be read, because it is deprecated, out of context, or simply not available (i.e. HLAT is not active on this target), it shows up with “DEAD” or “BEEF” or some combination thereof.

And below is the Intel PT captured once the target is stopped, as can be seen in a SourcePoint screenshot:

It’s time to collect the beginning register dump, Intel PT, and ending register dump, and feed it to ChatGPT for analysis. Here’s an few excerpts of the results:

🔒 1. CET (Control-Flow Enforcement Technology) Enablement

CET uses shadow stacks and indirect branch tracking. Its activation requires:

  • CR4.CET (Bit 23) — not explicitly visible, but we can infer CET enablement from:
  • VMCS entry control VMENTRY_CONTROL = 0x1213FF

This includes:

  • Bit 20 set: Load CET state → ✅
  • Therefore, CET is enabled in the guest at VM-entry.

PT Behavior Correlation:

Intel PT shows frequent instruction-pointer changes within tight loops:

mov [r9], al

add rdi, 2

inc r9

sub r10, 1

jne CmpGetNameControlBlock+1b0

🧠 Shadow Stack Insight:

  • These forward-only calls (call, retn) align with a CET-protected environment.
  • No suspicious jmp to invalid regions — consistent with valid indirect control flow.
  • No PT TNT (Taken/Not Taken) anomalies suggesting control-flow violations.

Conclusion: CET is enforced, and execution flow never violates shadow stack integrity during trace.

🧭 2. VMCS + PT Correlation for Secure Nested Execution

VMCS Guest State:

  • CR4.VMXE = 1 (VMX instructions allowed in guest)
  • CR4.SMEE = 1 (SMX enabled)
  • CR4.SMPE/SMAP = 1 (Supervisor protections)
  • BNDCFGS present (MPX state loaded — often with CET)

Intel PT Events:

  • Starts at HvpEnlistFreeCells, ends in CmpGetNameControlBlock
  • Consistent with hypervisor-managed secure memory enumeration and registry lookup
  • No EPT violations, no unexpected VMEXITs, no flow divergence

Conclusion: The guest is likely running in a nested, secure enclave (e.g. VTL1) with CET and memory protections enforced. PT confirms smooth control flow without interruption, validating VMCS configuration.

🔁 Summary Table

Capability VMCS Evidence PT Confirmation
CET Load CET = 1, BNDCFGS present Valid returns, no IB violations
SMEP/SMAP CR4.SMPE = 1, CR4.SMAP = 1 No code execution from user pages
VMX in Guest CR4.VMXE = 1 No violation of nested control
Secure Context SMXE = 1, BNDCFGS, FSGSBASE Secure stack behavior, string copy integrity

 

Displaying all VMCS fields with changed values:

Register Before Intel PT After Intel PT
RAX 00000000FFFFFFB0 0000000000000032
RBX 0000000000000030 000000008D6BBC52
RCX 00000000000002D0 FFFFE182185E4240
RDX FFFFF80452551000 0000000000000000
RBP 00000000002142A0 00000000000000D9
RSI FFFFF804525512D0 FFFFE182185E4150
RDI 00000000000002D0 00000000000000C0
RSP FFFFCF0A7D006B00 FFFFCF0A7D005B60
R8 0000000000214000 0000000000000003
R9 0000000000020000 FFFFE182185E41CA
R10 0000000000001000 0000000000000079
R11 FFFFE18218448120 0000000000001001
R12 0000000000214000 00000000000006C4
R13 0000000000020000 FFFFCF0A7D005F10
R14 FFFFE18218476000 00000000000000F3
R15 FFFFF80452551000 0000000000068501
RIP FFFFF80457BE567A FFFFF80457C0BE40
RFLAGS 0000000000050282 0000000000050202
CR2 FFFFE182184E5000 FFFFE182188C3392
VMENTRY_CONTROL 1233FF 1213FF
VMEXIT_INST_INFO 12614924 0
VMEXIT_INST_LEN 5 4
VMEXIT_INT_INFO 0 800000FF
VMEXIT_PRIMARY 3FFFF 3EFFF
VMEXIT_QUALIFICATION 20 0
VMEXIT_REASON 2E 1
VMCS_VM_PRIMARY B6A065FA B6A06DFA

Now, it’s possible to create much more complex sequences using the power of SourcePoint’s command language. Here’s another example where we capture execution trace using Intel Processor Trace and register state during five sequential VM Exits; just with one simple chained command in the Command window:

P8>define ord1 i=0; while(i<5) {i++; printf(“VM Exit # = %u\n”,i); go; wait}

Or you can use the SourcePoint bstep (branch step) command to break with every code branch. Very cool!

In the interest of space, I won’t go through the results here; suffice to say that they’re fascinating!

This blog is getting a little long to cover all I would like to write about. There are a million things to review about the use of SourcePoint + AI. This is probably best served with an upcoming webinar and/or video.

And in an upcoming blog, I’ll write about the use of SourcePoint with MCP.