Merge pull request #541 from HyperDbg/save-restore-xmm-regs

Save and restore XMM registers on VM-exits
This commit is contained in:
Sina Karvandi 2025-08-10 01:10:12 +02:00 committed by GitHub
commit 57b4b6f4e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 242 additions and 154 deletions

View file

@ -12,8 +12,13 @@ New release of the HyperDbg Debugger.
- Export the SDK functions for SMI operations ([link](https://docs.hyperdbg.org/commands/extension-commands/smi#sdk))
### Changed
- The 'hyperhv' project now has build optimizations enabled
- Reformat VMXOFF restoring routines to restore general-purpose and XMM registers correctly before moving to the previous stack
- Fix unloading (VMXOFF) crash when restoring XMM registers
- Fix the problem with restoring XMM registers (#468) ([link](https://github.com/HyperDbg/HyperDbg/issues/468))
- Enhanced the '.pe' command to support PE Rich Headers thanks to [@Alish14](https://github.com/Alish14) ([link](https://github.com/HyperDbg/HyperDbg/pull/539))
## [0.14.1.0] - 2025-07-27
New release of the HyperDbg Debugger.

View file

@ -1,4 +1,5 @@
PUBLIC AsmVmexitHandler
PUBLIC AsmVmxoffRestoreXmmRegs
EXTERN VmxVmexitHandler:PROC
EXTERN VmxVmresume:PROC
@ -15,32 +16,36 @@ AsmVmexitHandler PROC
; irql less or equal as it doesn't exist, so we just put some extra space avoid
; these kind of errors
pushfq
; --------------- Save RFLAGS ----------------
pushfq ; Save the flags register (RFLAGS)
; ------------ Save XMM Registers ------------
;
; ;;;;;;;;;;;; 16 Byte * 16 Byte = 256 + 4 = 260 (0x106 == 0x110 but let's align it to have better performance) ;;;;;;;;;;;;
; sub rsp, 0110h
;
; movaps xmmword ptr [rsp+000h], xmm0 ; each xmm register 128 bit (16 Byte)
; movaps xmmword ptr [rsp+010h], xmm1
; movaps xmmword ptr [rsp+020h], xmm2
; movaps xmmword ptr [rsp+030h], xmm3
; movaps xmmword ptr [rsp+040h], xmm4
; movaps xmmword ptr [rsp+050h], xmm5
; movaps xmmword ptr [rsp+060h], xmm6
; movaps xmmword ptr [rsp+070h], xmm7
; movaps xmmword ptr [rsp+080h], xmm8
; movaps xmmword ptr [rsp+090h], xmm9
; movaps xmmword ptr [rsp+0a0h], xmm10
; movaps xmmword ptr [rsp+0b0h], xmm11
; movaps xmmword ptr [rsp+0c0h], xmm12
; movaps xmmword ptr [rsp+0d0h], xmm13
; movaps xmmword ptr [rsp+0e0h], xmm14
; movaps xmmword ptr [rsp+0f0h], xmm15
; stmxcsr dword ptr [rsp+0100h] ; MxCsr is 4 Byte
;
;---------------------------------------------
; 16 Byte * 16 Byte = 256 + 4 = 260 (0x104 == 0x110 but let's align it to have better performance)
sub rsp, 0110h
movaps xmmword ptr [rsp+000h], xmm0 ; each xmm register 128 bit (16 Byte)
movaps xmmword ptr [rsp+010h], xmm1
movaps xmmword ptr [rsp+020h], xmm2
movaps xmmword ptr [rsp+030h], xmm3
movaps xmmword ptr [rsp+040h], xmm4
movaps xmmword ptr [rsp+050h], xmm5
movaps xmmword ptr [rsp+060h], xmm6
movaps xmmword ptr [rsp+070h], xmm7
movaps xmmword ptr [rsp+080h], xmm8
movaps xmmword ptr [rsp+090h], xmm9
movaps xmmword ptr [rsp+0a0h], xmm10
movaps xmmword ptr [rsp+0b0h], xmm11
movaps xmmword ptr [rsp+0c0h], xmm12
movaps xmmword ptr [rsp+0d0h], xmm13
movaps xmmword ptr [rsp+0e0h], xmm14
movaps xmmword ptr [rsp+0f0h], xmm15
stmxcsr dword ptr [rsp+0100h] ; MxCsr is 4 Byte
; ------ Save General-purpose Registers ------
push r15
push r14
@ -58,21 +63,28 @@ AsmVmexitHandler PROC
push rdx
push rcx
push rax
; ----------- Call VM-exit Handler -----------
mov rcx, rsp ; Fast call argument to PGUEST_REGS
sub rsp, 020h ; Free some space for Shadow Section
call VmxVmexitHandler
add rsp, 020h ; Restore the state
cmp al, 1 ; Check whether we have to turn off VMX or Not (the result is in RAX)
cmp al, 1 ; Check whether we have to turn off VMX or Not (the result is in RAX)
je AsmVmxoffHandler
; ----------- Restore XMM Registers ----------
RestoreState:
pop rax
pop rcx
pop rdx
pop rbx
pop rbp ; rsp
pop rbp ; rsp
pop rbp
pop rsi
pop rdi
@ -86,71 +98,80 @@ RestoreState:
pop r15
; ------------ Restore XMM Registers ------------
;
; movaps xmm0, xmmword ptr [rsp+000h]
; movaps xmm1, xmmword ptr [rsp+010h]
; movaps xmm2, xmmword ptr [rsp+020h]
; movaps xmm3, xmmword ptr [rsp+030h]
; movaps xmm4, xmmword ptr [rsp+040h]
; movaps xmm5, xmmword ptr [rsp+050h]
; movaps xmm6, xmmword ptr [rsp+060h]
; movaps xmm7, xmmword ptr [rsp+070h]
; movaps xmm8, xmmword ptr [rsp+080h]
; movaps xmm9, xmmword ptr [rsp+090h]
; movaps xmm10, xmmword ptr [rsp+0a0h]
; movaps xmm11, xmmword ptr [rsp+0b0h]
; movaps xmm12, xmmword ptr [rsp+0c0h]
; movaps xmm13, xmmword ptr [rsp+0d0h]
; movaps xmm14, xmmword ptr [rsp+0e0h]
; movaps xmm15, xmmword ptr [rsp+0f0h]
;
; ldmxcsr dword ptr [rsp+0100h]
;
; add rsp, 0110h
movaps xmm0, xmmword ptr [rsp+000h]
movaps xmm1, xmmword ptr [rsp+010h]
movaps xmm2, xmmword ptr [rsp+020h]
movaps xmm3, xmmword ptr [rsp+030h]
movaps xmm4, xmmword ptr [rsp+040h]
movaps xmm5, xmmword ptr [rsp+050h]
movaps xmm6, xmmword ptr [rsp+060h]
movaps xmm7, xmmword ptr [rsp+070h]
movaps xmm8, xmmword ptr [rsp+080h]
movaps xmm9, xmmword ptr [rsp+090h]
movaps xmm10, xmmword ptr [rsp+0a0h]
movaps xmm11, xmmword ptr [rsp+0b0h]
movaps xmm12, xmmword ptr [rsp+0c0h]
movaps xmm13, xmmword ptr [rsp+0d0h]
movaps xmm14, xmmword ptr [rsp+0e0h]
movaps xmm15, xmmword ptr [rsp+0f0h]
ldmxcsr dword ptr [rsp+0100h]
add rsp, 0110h
; --------------- Restore RFLAGS ---------------
popfq ; Restore the flags register (RFLAGS)
; ----------------------------------------------
popfq
sub rsp, 0100h ; to avoid error in future functions
jmp VmxVmresume
AsmVmexitHandler ENDP
;------------------------------------------------------------------------
AsmVmxoffRestoreXmmRegs PROC
; ------------ Restore XMM Registers ------------
movaps xmm0, xmmword ptr [rcx+000h]
movaps xmm1, xmmword ptr [rcx+010h]
movaps xmm2, xmmword ptr [rcx+020h]
movaps xmm3, xmmword ptr [rcx+030h]
movaps xmm4, xmmword ptr [rcx+040h]
movaps xmm5, xmmword ptr [rcx+050h]
movaps xmm6, xmmword ptr [rcx+060h]
movaps xmm7, xmmword ptr [rcx+070h]
movaps xmm8, xmmword ptr [rcx+080h]
movaps xmm9, xmmword ptr [rcx+090h]
movaps xmm10, xmmword ptr [rcx+0a0h]
movaps xmm11, xmmword ptr [rcx+0b0h]
movaps xmm12, xmmword ptr [rcx+0c0h]
movaps xmm13, xmmword ptr [rcx+0d0h]
movaps xmm14, xmmword ptr [rcx+0e0h]
movaps xmm15, xmmword ptr [rcx+0f0h]
ldmxcsr dword ptr [rcx+0100h]
ret
AsmVmxoffRestoreXmmRegs ENDP
;------------------------------------------------------------------------
AsmVmxoffHandler PROC
sub rsp, 020h ; shadow space
call VmxReturnStackPointerForVmxoff
add rsp, 020h ; remove for shadow space
mov [rsp+88h], rax ; now, rax contains rsp
sub rsp, 020h ; shadow space
call VmxReturnInstructionPointerForVmxoff
add rsp, 020h ; remove for shadow space
mov rdx, rsp ; save current rsp
mov rbx, [rsp+88h] ; read rsp again
mov rsp, rbx
push rax ; push the return address as we changed the stack, we push
; it to the new stack
mov rsp, rdx ; restore previous rsp
sub rbx,08h ; we push sth, so we have to add (sub) +8 from previous stack
; also rbx already contains the rsp
mov [rsp+88h], rbx ; move the new pointer to the current stack
; ------ Restore General-purpose Registers ------
RestoreState:
pop rax
pop rcx
pop rdx
pop rbx
pop rbp ; rsp
pop rbp ; rsp
pop rbp
pop rsi
pop rdi
@ -163,34 +184,40 @@ RestoreState:
pop r14
pop r15
; ------------ Restore XMM Registers ------------
;
; movaps xmm0, xmmword ptr [rsp+000h]
; movaps xmm1, xmmword ptr [rsp+010h]
; movaps xmm2, xmmword ptr [rsp+020h]
; movaps xmm3, xmmword ptr [rsp+030h]
; movaps xmm4, xmmword ptr [rsp+040h]
; movaps xmm5, xmmword ptr [rsp+050h]
; movaps xmm6, xmmword ptr [rsp+060h]
; movaps xmm7, xmmword ptr [rsp+070h]
; movaps xmm8, xmmword ptr [rsp+080h]
; movaps xmm9, xmmword ptr [rsp+090h]
; movaps xmm10, xmmword ptr [rsp+0a0h]
; movaps xmm11, xmmword ptr [rsp+0b0h]
; movaps xmm12, xmmword ptr [rsp+0c0h]
; movaps xmm13, xmmword ptr [rsp+0d0h]
; movaps xmm14, xmmword ptr [rsp+0e0h]
; movaps xmm15, xmmword ptr [rsp+0f0h]
;
; ldmxcsr dword ptr [rsp+0100h]
;
; add rsp, 0110h
; ------------- Pass over XMM Regs -------------
; XMM registers are restored by AsmVmxoffRestoreXmmRegs
; Size of XMM registers are 110 bytes but we also remove the RFLAGS register (+8)
; so we have 118 bytes to remove from the stack
add rsp, 0118h
; ------------ Get Stack Pointer ---------------
sub rsp, 020h ; shadow space
call VmxReturnStackPointerForVmxoff
add rsp, 020h ; remove for shadow space
push rax ; save the current rsp, we will restore it later
; ------------ Get Instruction Pointer ---------
sub rsp, 020h ; shadow space
call VmxReturnInstructionPointerForVmxoff
add rsp, 020h ; remove for shadow space
pop rsp ; restore rsp
push rax ; push the instruction pointer
; ----------------------------------------------
popfq
pop rsp ; restore rsp
; There might be some registers that are modified by above CALLs,
; but here we do not care about them since we are also in a function,
; so the caller do not expect us to preserve these volatile registers
ret ; jump back to where we called Vmcall
xor rax, rax ; clear RAX to indicate VMXOFF was successful (VMCALL Status)
ret ; jump back to where we called Vmcall
AsmVmxoffHandler ENDP

View file

@ -31,9 +31,10 @@ VmxVmexitHandler(_Inout_ PGUEST_REGS GuestRegs)
VCpu = &g_GuestState[KeGetCurrentProcessorNumberEx(NULL)];
//
// Set the registers
// Set the registers (general-purpose and XMM)
//
VCpu->Regs = GuestRegs;
VCpu->Regs = GuestRegs;
VCpu->XmmRegs = (GUEST_XMM_REGS *)(((CHAR *)GuestRegs) + sizeof(GUEST_REGS));
//
// Indicates we are in Vmx root mode in this logical core
@ -77,6 +78,7 @@ VmxVmexitHandler(_Inout_ PGUEST_REGS GuestRegs)
// LogInfo("VM_EXIT_REASON : 0x%x", ExitReason);
// LogInfo("VMCS_EXIT_QUALIFICATION : 0x%llx", VCpu->ExitQualification);
//
switch (ExitReason)
{
case VMX_EXIT_REASON_TRIPLE_FAULT:

View file

@ -1156,6 +1156,15 @@ VmxVmxoff(VIRTUAL_MACHINE_STATE * VCpu)
//
HvRestoreRegisters();
//
// Restore XMM registers
// We restore XMM registers here because we are going to execute vmxoff instruction
// which enables interrupts and we don't want to lose the XMM registers
// since immediately after vmxoff, an interrupt might occur and context switch
// might change the XMM registers
//
AsmVmxoffRestoreXmmRegs((unsigned long long)VCpu->XmmRegs);
//
// Before using vmxoff, you first need to use vmclear on any VMCSes that you want to be able to use again.
// See sections 24.1 and 24.11 of the SDM.
@ -1167,6 +1176,11 @@ VmxVmxoff(VIRTUAL_MACHINE_STATE * VCpu)
//
__vmx_off();
//
// *** Note: After executing VMXOFF, XMM registers should not be used anymore
// Since we already restored them ***
//
//
// Indicate the current core is not currently virtualized
//

View file

@ -97,6 +97,12 @@ AsmVmexitHandler();
*/
extern void inline AsmSaveVmxOffState();
/**
* @brief Restore XMM registers
*
*/
extern void inline AsmVmxoffRestoreXmmRegs(unsigned long long XmmRegs);
//
// ==================== Extended Page Tables ====================
// File : AsmEpt.asm
@ -143,7 +149,7 @@ AsmGetCs();
extern unsigned short
AsmGetDs();
extern void
extern void
AsmSetDs(unsigned short DsSelector);
/**

View file

@ -302,52 +302,53 @@ typedef struct _NMI_BROADCASTING_STATE
*/
typedef struct _VIRTUAL_MACHINE_STATE
{
BOOLEAN IsOnVmxRootMode; // Detects whether the current logical core is on Executing on VMX Root Mode
BOOLEAN IncrementRip; // Checks whether it has to redo the previous instruction or not (it used mainly in Ept routines)
BOOLEAN HasLaunched; // Indicate whether the core is virtualized or not
BOOLEAN IgnoreMtfUnset; // Indicate whether the core should ignore unsetting the MTF or not
BOOLEAN WaitForImmediateVmexit; // Whether the current core is waiting for an immediate vm-exit or not
BOOLEAN EnableExternalInterruptsOnContinue; // Whether to enable external interrupts on the continue or not
BOOLEAN EnableExternalInterruptsOnContinueMtf; // Whether to enable external interrupts on the continue state of MTF or not
BOOLEAN RegisterBreakOnMtf; // Registered Break in the case of MTFs (used in instrumentation step-in)
BOOLEAN IgnoreOneMtf; // Ignore (mark as handled) for one MTF
BOOLEAN NotNormalEptp; // Indicate that the target processor is on the normal EPTP or not
BOOLEAN MbecEnabled; // Indicate that the target processor is on MBEC-enabled mode or not
PUINT64 PmlBufferAddress; // Address of buffer used for dirty logging
BOOLEAN Test; // Used for test purposes
UINT64 TestNumber; // Used for test purposes (Number)
GUEST_REGS * Regs; // The virtual processor's general-purpose registers
UINT32 CoreId; // The core's unique identifier
UINT32 ExitReason; // The core's exit reason
UINT32 ExitQualification; // The core's exit qualification
UINT64 LastVmexitRip; // RIP in the current VM-exit
UINT64 VmxonRegionPhysicalAddress; // Vmxon region physical address
UINT64 VmxonRegionVirtualAddress; // VMXON region virtual address
UINT64 VmcsRegionPhysicalAddress; // VMCS region physical address
UINT64 VmcsRegionVirtualAddress; // VMCS region virtual address
UINT64 VmmStack; // Stack for VMM in VM-Exit State
UINT64 MsrBitmapVirtualAddress; // Msr Bitmap Virtual Address
UINT64 MsrBitmapPhysicalAddress; // Msr Bitmap Physical Address
UINT64 IoBitmapVirtualAddressA; // I/O Bitmap Virtual Address (A)
UINT64 IoBitmapPhysicalAddressA; // I/O Bitmap Physical Address (A)
UINT64 IoBitmapVirtualAddressB; // I/O Bitmap Virtual Address (B)
UINT64 IoBitmapPhysicalAddressB; // I/O Bitmap Physical Address (B)
UINT32 QueuedNmi; // Queued NMIs
UINT32 PendingExternalInterrupts[PENDING_INTERRUPTS_BUFFER_CAPACITY]; // This list holds a buffer for external-interrupts that are in pending state due to the external-interrupt
// blocking and waits for interrupt-window exiting
// From hvpp :
// Pending interrupt queue (FIFO).
// Make storage for up-to 64 pending interrupts.
// In practice I haven't seen more than 2 pending interrupts.
VMX_VMXOFF_STATE VmxoffState; // Shows the vmxoff state of the guest
NMI_BROADCASTING_STATE NmiBroadcastingState; // Shows the state of NMI broadcasting
VM_EXIT_TRANSPARENCY TransparencyState; // The state of the debugger in transparent-mode
PEPT_HOOKED_PAGE_DETAIL MtfEptHookRestorePoint; // It shows the detail of the hooked paged that should be restore in MTF vm-exit
UINT8 LastExceptionOccuredInHost; // The vector of last exception occured in host
UINT64 HostIdt; // host Interrupt Descriptor Table (actual type is SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64*)
UINT64 HostGdt; // host Global Descriptor Table (actual type is SEGMENT_DESCRIPTOR_32* or SEGMENT_DESCRIPTOR_64*)
UINT64 HostTss; // host Task State Segment (actual type is TASK_STATE_SEGMENT_64*)
UINT64 HostInterruptStack; // host interrupt RSP
BOOLEAN IsOnVmxRootMode; // Detects whether the current logical core is on Executing on VMX Root Mode
BOOLEAN IncrementRip; // Checks whether it has to redo the previous instruction or not (it used mainly in Ept routines)
BOOLEAN HasLaunched; // Indicate whether the core is virtualized or not
BOOLEAN IgnoreMtfUnset; // Indicate whether the core should ignore unsetting the MTF or not
BOOLEAN WaitForImmediateVmexit; // Whether the current core is waiting for an immediate vm-exit or not
BOOLEAN EnableExternalInterruptsOnContinue; // Whether to enable external interrupts on the continue or not
BOOLEAN EnableExternalInterruptsOnContinueMtf; // Whether to enable external interrupts on the continue state of MTF or not
BOOLEAN RegisterBreakOnMtf; // Registered Break in the case of MTFs (used in instrumentation step-in)
BOOLEAN IgnoreOneMtf; // Ignore (mark as handled) for one MTF
BOOLEAN NotNormalEptp; // Indicate that the target processor is on the normal EPTP or not
BOOLEAN MbecEnabled; // Indicate that the target processor is on MBEC-enabled mode or not
PUINT64 PmlBufferAddress; // Address of buffer used for dirty logging
BOOLEAN Test; // Used for test purposes
UINT64 TestNumber; // Used for test purposes (Number)
GUEST_REGS * Regs; // The virtual processor's general-purpose registers
GUEST_XMM_REGS * XmmRegs; // The virtual processor's XMM registers
UINT32 CoreId; // The core's unique identifier
UINT32 ExitReason; // The core's exit reason
UINT32 ExitQualification; // The core's exit qualification
UINT64 LastVmexitRip; // RIP in the current VM-exit
UINT64 VmxonRegionPhysicalAddress; // Vmxon region physical address
UINT64 VmxonRegionVirtualAddress; // VMXON region virtual address
UINT64 VmcsRegionPhysicalAddress; // VMCS region physical address
UINT64 VmcsRegionVirtualAddress; // VMCS region virtual address
UINT64 VmmStack; // Stack for VMM in VM-Exit State
UINT64 MsrBitmapVirtualAddress; // Msr Bitmap Virtual Address
UINT64 MsrBitmapPhysicalAddress; // Msr Bitmap Physical Address
UINT64 IoBitmapVirtualAddressA; // I/O Bitmap Virtual Address (A)
UINT64 IoBitmapPhysicalAddressA; // I/O Bitmap Physical Address (A)
UINT64 IoBitmapVirtualAddressB; // I/O Bitmap Virtual Address (B)
UINT64 IoBitmapPhysicalAddressB; // I/O Bitmap Physical Address (B)
UINT32 QueuedNmi; // Queued NMIs
UINT32 PendingExternalInterrupts[PENDING_INTERRUPTS_BUFFER_CAPACITY]; // This list holds a buffer for external-interrupts that are in pending state due to the external-interrupt
// blocking and waits for interrupt-window exiting
// From hvpp :
// Pending interrupt queue (FIFO).
// Make storage for up-to 64 pending interrupts.
// In practice I haven't seen more than 2 pending interrupts.
VMX_VMXOFF_STATE VmxoffState; // Shows the vmxoff state of the guest
NMI_BROADCASTING_STATE NmiBroadcastingState; // Shows the state of NMI broadcasting
VM_EXIT_TRANSPARENCY TransparencyState; // The state of the debugger in transparent-mode
PEPT_HOOKED_PAGE_DETAIL MtfEptHookRestorePoint; // It shows the detail of the hooked paged that should be restore in MTF vm-exit
UINT8 LastExceptionOccuredInHost; // The vector of last exception occured in host
UINT64 HostIdt; // host Interrupt Descriptor Table (actual type is SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64*)
UINT64 HostGdt; // host Global Descriptor Table (actual type is SEGMENT_DESCRIPTOR_32* or SEGMENT_DESCRIPTOR_64*)
UINT64 HostTss; // host Task State Segment (actual type is TASK_STATE_SEGMENT_64*)
UINT64 HostInterruptStack; // host interrupt RSP
//
// EPT Descriptors

View file

@ -111,7 +111,7 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<Optimization>Disabled</Optimization>
<Optimization>Full</Optimization>
<PreprocessorDefinitions>ZYDIS_STATIC_BUILD;ZYCORE_STATIC_BUILD;ZYAN_NO_LIBC;ZYDIS_NO_LIBC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>

View file

@ -66,6 +66,7 @@ typedef unsigned __int64 UINT64, *PUINT64;
//
// DO NOT FUCKING TOUCH THIS STRUCTURE WITHOUT COORDINATION WITH SINA
//
#pragma pack(push, 1) // Ensure no padding
typedef struct GUEST_REGS
{
//
@ -94,6 +95,38 @@ typedef struct GUEST_REGS
//
} GUEST_REGS, *PGUEST_REGS;
#pragma pack(pop)
typedef struct XMM_REG
{
UINT64 XmmLow; // Low 64 bits
UINT64 XmmHigh; // High 64 bits
} XMM_REG;
#pragma pack(push, 1) // Ensure no padding
typedef struct GUEST_XMM_REGS
{
XMM_REG xmm0; // 0x00
XMM_REG xmm1; // 0x10
XMM_REG xmm2; // 0x20
XMM_REG xmm3; // 0x30
XMM_REG xmm4; // 0x40
XMM_REG xmm5; // 0x50
XMM_REG xmm6; // 0x60
XMM_REG xmm7; // 0x70
XMM_REG xmm8; // 0x80
XMM_REG xmm9; // 0x90
XMM_REG xmm10; // 0xA0
XMM_REG xmm11; // 0xB0
XMM_REG xmm12; // 0xC0
XMM_REG xmm13; // 0xD0
XMM_REG xmm14; // 0xE0
XMM_REG xmm15; // 0xF0
UINT32 mxcsr; // 0x100
} GUEST_XMM_REGS, *PGUEST_XMM_REGS;
#pragma pack(pop)
/**
* @brief struct for extra registers