HyperDbg Debugger
Loading...
Searching...
No Matches
MsrHandlers.h File Reference

Headers to Handle for MSR-related tasks in VMX-root. More...

Go to the source code of this file.

Functions

VOID MsrHandleRdmsrVmexit (PGUEST_REGS GuestRegs)
 Handles in the cases when RDMSR causes a vm-exit.
 
VOID MsrHandleWrmsrVmexit (PGUEST_REGS GuestRegs)
 Handles in the cases when RDMSR causes a vm-exit.
 
BOOLEAN MsrHandleSetMsrBitmap (VIRTUAL_MACHINE_STATE *VCpu, UINT32 Msr, BOOLEAN ReadDetection, BOOLEAN WriteDetection)
 Set bits in Msr Bitmap.
 
BOOLEAN MsrHandleUnSetMsrBitmap (VIRTUAL_MACHINE_STATE *VCpu, UINT32 Msr, BOOLEAN ReadDetection, BOOLEAN WriteDetection)
 UnSet bits in Msr Bitmap.
 
VOID MsrHandlePerformMsrBitmapReadChange (VIRTUAL_MACHINE_STATE *VCpu, UINT32 MsrMask)
 Change MSR Bitmap for read.
 
VOID MsrHandlePerformMsrBitmapReadReset (VIRTUAL_MACHINE_STATE *VCpu)
 Reset MSR Bitmap for read.
 
VOID MsrHandlePerformMsrBitmapWriteChange (VIRTUAL_MACHINE_STATE *VCpu, UINT32 MsrMask)
 Change MSR Bitmap for write.
 
VOID MsrHandlePerformMsrBitmapWriteReset (VIRTUAL_MACHINE_STATE *VCpu)
 Reset MSR Bitmap for write.
 

Detailed Description

Headers to Handle for MSR-related tasks in VMX-root.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.1
Date
2021-12-24

Function Documentation

◆ MsrHandlePerformMsrBitmapReadChange()

VOID MsrHandlePerformMsrBitmapReadChange ( VIRTUAL_MACHINE_STATE * VCpu,
UINT32 MsrMask )

Change MSR Bitmap for read.

should be called in vmx-root mode

Parameters
VCpuThe virtual processor's state
MsrMask
Returns
VOID
423{
425 {
426 //
427 // Means all the bitmaps should be put to 1
428 //
429 memset((void *)VCpu->MsrBitmapVirtualAddress, 0xff, 2048);
430
431 //
432 // Filter MSR Bitmap for special MSRs
433 //
435 }
436 else
437 {
438 //
439 // Means only one msr bitmap is target
440 //
441 MsrHandleSetMsrBitmap(VCpu, MsrMask, TRUE, FALSE);
442 }
443}
#define TRUE
Definition BasicTypes.h:55
#define FALSE
Definition BasicTypes.h:54
#define DEBUGGER_EVENT_MSR_READ_OR_WRITE_ALL_MSRS
Apply to all Model Specific Registers.
Definition Constants.h:623
BOOLEAN MsrHandleSetMsrBitmap(VIRTUAL_MACHINE_STATE *VCpu, UINT32 Msr, BOOLEAN ReadDetection, BOOLEAN WriteDetection)
Set bits in Msr Bitmap.
Definition MsrHandlers.c:275
VOID MsrHandleFilterMsrReadBitmap(VIRTUAL_MACHINE_STATE *VCpu)
Filter to avoid msr set for MSRs that are not valid or should be ignored (RDMSR)
Definition MsrHandlers.c:371
UINT64 MsrBitmapVirtualAddress
Definition State.h:315

◆ MsrHandlePerformMsrBitmapReadReset()

VOID MsrHandlePerformMsrBitmapReadReset ( VIRTUAL_MACHINE_STATE * VCpu)

Reset MSR Bitmap for read.

should be called in vmx-root mode

Parameters
VCpuThe virtual processor's state
Returns
VOID
454{
455 //
456 // Means all the bitmaps should be put to 0
457 //
458 memset((void *)VCpu->MsrBitmapVirtualAddress, 0x0, 2048);
459}

◆ MsrHandlePerformMsrBitmapWriteChange()

VOID MsrHandlePerformMsrBitmapWriteChange ( VIRTUAL_MACHINE_STATE * VCpu,
UINT32 MsrMask )

Change MSR Bitmap for write.

should be called in vmx-root mode

Parameters
VCpuThe virtual processor's state
MsrMaskMSR
Returns
VOID
470{
472 {
473 //
474 // Means all the bitmaps should be put to 1
475 //
476 memset((void *)((UINT64)VCpu->MsrBitmapVirtualAddress + 2048), 0xff, 2048);
477
478 //
479 // Filter MSR Bitmap for special MSRs
480 //
482 }
483 else
484 {
485 //
486 // Means only one msr bitmap is target
487 //
488 MsrHandleSetMsrBitmap(VCpu, MsrMask, FALSE, TRUE);
489 }
490}
unsigned __int64 UINT64
Definition BasicTypes.h:21
VOID MsrHandleFilterMsrWriteBitmap(VIRTUAL_MACHINE_STATE *VCpu)
Filter to avoid msr set for MSRs that are not valid or should be ignored (wrmsr)
Definition MsrHandlers.c:393

◆ MsrHandlePerformMsrBitmapWriteReset()

VOID MsrHandlePerformMsrBitmapWriteReset ( VIRTUAL_MACHINE_STATE * VCpu)

Reset MSR Bitmap for write.

should be called in vmx-root mode

Parameters
VCpuThe virtual processor's state
Returns
VOID
501{
502 //
503 // Means all the bitmaps should be put to 0
504 //
505 memset((void *)((UINT64)VCpu->MsrBitmapVirtualAddress + 2048), 0x0, 2048);
506}

◆ MsrHandleRdmsrVmexit()

VOID MsrHandleRdmsrVmexit ( PGUEST_REGS GuestRegs)

Handles in the cases when RDMSR causes a vm-exit.

Parameters
GuestRegsGuest's gp registers
Returns
VOID
22{
23 MSR Msr = {0};
24 UINT32 TargetMsr;
25
26 //
27 // RDMSR. The RDMSR instruction causes a VM exit if any of the following are true:
28 //
29 // The "use MSR bitmaps" VM-execution control is 0.
30 // The value of ECX is not in the ranges 00000000H - 00001FFFH and C0000000H - C0001FFFH
31 // The value of ECX is in the range 00000000H - 00001FFFH and bit n in read bitmap for low MSRs is 1,
32 // where n is the value of ECX.
33 // The value of ECX is in the range C0000000H - C0001FFFH and bit n in read bitmap for high MSRs is 1,
34 // where n is the value of ECX & 00001FFFH.
35 //
36 TargetMsr = GuestRegs->rcx & 0xffffffff;
37
38 //
39 // Execute WRMSR or RDMSR on behalf of the guest. Important that this
40 // can cause bug check when the guest tries to access unimplemented MSR
41 // even within the SEH block* because the below WRMSR or RDMSR raises
42 // #GP and are not protected by the SEH block (or cannot be protected
43 // either as this code run outside the thread stack region Windows
44 // requires to proceed SEH). Hypervisors typically handle this by noop-ing
45 // WRMSR and returning zero for RDMSR with non-architecturally defined
46 // MSRs. Alternatively, one can probe which MSRs should cause #GP prior
47 // to installation of a hypervisor and the hypervisor can emulate the
48 // results.
49 //
50
51 //
52 // Check for sanity of MSR if they're valid or they're for reserved range for WRMSR and RDMSR
53 //
54 if ((TargetMsr <= 0x00001FFF) || ((0xC0000000 <= TargetMsr) && (TargetMsr <= 0xC0001FFF)) ||
55 (TargetMsr >= RESERVED_MSR_RANGE_LOW && (TargetMsr <= RESERVED_MSR_RANGE_HI)))
56 {
57 //
58 // Apply the RDMS
59 //
60 switch (TargetMsr)
61 {
62 case IA32_SYSENTER_CS:
63 VmxVmread64P(VMCS_GUEST_SYSENTER_CS, &Msr.Flags);
64 break;
65
66 case IA32_SYSENTER_ESP:
67 VmxVmread64P(VMCS_GUEST_SYSENTER_ESP, &Msr.Flags);
68 break;
69
70 case IA32_SYSENTER_EIP:
71 VmxVmread64P(VMCS_GUEST_SYSENTER_EIP, &Msr.Flags);
72 break;
73
74 case IA32_GS_BASE:
75 VmxVmread64P(VMCS_GUEST_GS_BASE, &Msr.Flags);
76 break;
77
78 case IA32_FS_BASE:
79 VmxVmread64P(VMCS_GUEST_FS_BASE, &Msr.Flags);
80 break;
81
83
84 //
85 // VMware workstation and Hyper-V use this MSR halt the system
86 // Read more:
87 // https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/vp-properties#virtual-processor-idle-sleep-state
88 // As a top-level hypervisor, we get this MSRs VM-exit (even
89 // without setting MSR bitmap because this MSR is not a valid
90 // range MSR).
91 //
92 // This behavior is problematic for the debugger when we throw an NMI
93 // to halt all of the cores, if the core already executed RDMSR on this MSR,
94 // we'll end up notifying the core in VMX root-root (this is the expected
95 // behavior); however, after continuing the guest, we still won't get a
96 // chance to continue execution. Thus, all of the cores remain unlocked (in
97 // debuggee) and halted. So, we cannot send commands to them, and later when
98 // we continue the guest, and the guest tries to perform the steps necessary for
99 // locking, which is not expected and eventually causes a BSOD.
100 //
101 // As a quick and dirty patch (which is not a good idea for power-saving
102 // and performance reasons), we ignored these MSRs.
103 //
104 break;
105
106 default:
107
108 //
109 // Check whether the MSR should cause #GP or not
110 //
111 if (TargetMsr <= 0xfff && TestBit(TargetMsr, (unsigned long *)g_MsrBitmapInvalidMsrs) != NULL64_ZERO)
112 {
113 //
114 // Invalid MSR between 0x0 to 0xfff
115 //
117 return;
118 }
119
120 //
121 // Msr is valid
122 //
123 Msr.Flags = __readmsr(TargetMsr);
124
125 //
126 // Check if it's EFER MSR then we show a false SCE state
127 //
128 if (GuestRegs->rcx == IA32_EFER)
129 {
130 IA32_EFER_REGISTER MsrEFER;
131 MsrEFER.AsUInt = Msr.Flags;
132 MsrEFER.SyscallEnable = TRUE;
133 Msr.Flags = MsrEFER.AsUInt;
134 }
135
136 break;
137 }
138
139 GuestRegs->rax = NULL64_ZERO;
140 GuestRegs->rdx = NULL64_ZERO;
141
142 GuestRegs->rax = Msr.Fields.Low;
143 GuestRegs->rdx = Msr.Fields.High;
144 }
145 else
146 {
147 //
148 // MSR is invalid, inject #GP
149 //
151 return;
152 }
153}
#define NULL64_ZERO
Definition BasicTypes.h:52
unsigned int UINT32
Definition BasicTypes.h:48
int TestBit(int BitNumber, unsigned long *addr)
Check whether the bit is set or not.
Definition Bitwise.c:22
VOID EventInjectGeneralProtection()
Inject #GP to the guest (Event Injection)
Definition Events.c:62
UINT64 * g_MsrBitmapInvalidMsrs
Bitmap of MSRs that cause #GP.
Definition GlobalVariables.h:107
#define HV_X64_MSR_GUEST_IDLE
Definition HypervTlfs.h:232
UCHAR VmxVmread64P(size_t Field, UINT64 *FieldValue)
VMX VMREAD instruction (64-bit)
Definition Vmx.c:72
#define RESERVED_MSR_RANGE_LOW
Hypervisor reserved range for RDMSR and WRMSR.
Definition Common.h:163
#define RESERVED_MSR_RANGE_HI
Definition Common.h:164
UINT64 rax
Definition BasicTypes.h:75
UINT64 rcx
Definition BasicTypes.h:76
UINT64 rdx
Definition BasicTypes.h:77
General MSR Structure.
Definition Msr.h:23
struct _MSR::@1 Fields
UINT64 Flags
Definition Msr.h:30
ULONG Low
Definition Msr.h:26
ULONG High
Definition Msr.h:27

◆ MsrHandleSetMsrBitmap()

BOOLEAN MsrHandleSetMsrBitmap ( VIRTUAL_MACHINE_STATE * VCpu,
UINT32 Msr,
BOOLEAN ReadDetection,
BOOLEAN WriteDetection )

Set bits in Msr Bitmap.

Parameters
VCpuThe virtual processor's state
MsrMSR Address
ReadDetectionset read bit
WriteDetectionset write bit
Returns
BOOLEAN Returns true if the MSR Bitmap is successfully applied or false if not applied
276{
277 if (!ReadDetection && !WriteDetection)
278 {
279 //
280 // Invalid Command
281 //
282 return FALSE;
283 }
284
285 if (Msr <= 0x00001FFF)
286 {
287 if (ReadDetection)
288 {
289 SetBit(Msr, (unsigned long *)VCpu->MsrBitmapVirtualAddress);
290 }
291 if (WriteDetection)
292 {
293 SetBit(Msr, (unsigned long *)VCpu->MsrBitmapVirtualAddress + 2048);
294 }
295 }
296 else if ((0xC0000000 <= Msr) && (Msr <= 0xC0001FFF))
297 {
298 if (ReadDetection)
299 {
300 SetBit(Msr - 0xC0000000, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 1024));
301 }
302 if (WriteDetection)
303 {
304 SetBit(Msr - 0xC0000000, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 3072));
305 }
306 }
307 else
308 {
309 return FALSE;
310 }
311 return TRUE;
312}
void SetBit(int BitNumber, unsigned long *addr)
set the bit
Definition Bitwise.c:46

◆ MsrHandleUnSetMsrBitmap()

BOOLEAN MsrHandleUnSetMsrBitmap ( VIRTUAL_MACHINE_STATE * VCpu,
UINT32 Msr,
BOOLEAN ReadDetection,
BOOLEAN WriteDetection )

UnSet bits in Msr Bitmap.

Parameters
VCpuThe virtual processor's state
MsrMSR Address
ReadDetectionUnset read bit
WriteDetectionUnset write bit
Returns
BOOLEAN Returns true if the MSR Bitmap is successfully applied or false if not applied
325{
326 if (!ReadDetection && !WriteDetection)
327 {
328 //
329 // Invalid Command
330 //
331 return FALSE;
332 }
333
334 if (Msr <= 0x00001FFF)
335 {
336 if (ReadDetection)
337 {
338 ClearBit(Msr, (unsigned long *)VCpu->MsrBitmapVirtualAddress);
339 }
340 if (WriteDetection)
341 {
342 ClearBit(Msr, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 2048));
343 }
344 }
345 else if ((0xC0000000 <= Msr) && (Msr <= 0xC0001FFF))
346 {
347 if (ReadDetection)
348 {
349 ClearBit(Msr - 0xC0000000, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 1024));
350 }
351 if (WriteDetection)
352 {
353 ClearBit(Msr - 0xC0000000, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 3072));
354 }
355 }
356 else
357 {
358 return FALSE;
359 }
360 return TRUE;
361}
void ClearBit(int BitNumber, unsigned long *addr)
unset the bit
Definition Bitwise.c:34

◆ MsrHandleWrmsrVmexit()

VOID MsrHandleWrmsrVmexit ( PGUEST_REGS GuestRegs)

Handles in the cases when RDMSR causes a vm-exit.

Parameters
GuestRegsGuest's gp registers
Returns
VOID
163{
164 MSR Msr = {0};
165 UINT32 TargetMsr;
166 BOOLEAN UnusedIsKernel;
167
168 //
169 // Execute WRMSR or RDMSR on behalf of the guest. Important that this
170 // can cause bug check when the guest tries to access unimplemented MSR
171 // even within the SEH block* because the below WRMSR or RDMSR raises
172 // #GP and are not protected by the SEH block (or cannot be protected
173 // either as this code run outside the thread stack region Windows
174 // requires to proceed SEH). Hypervisors typically handle this by noop-ing
175 // WRMSR and returning zero for RDMSR with non-architecturally defined
176 // MSRs. Alternatively, one can probe which MSRs should cause #GP prior
177 // to installation of a hypervisor and the hypervisor can emulate the
178 // results.
179 //
180 TargetMsr = GuestRegs->rcx & 0xffffffff;
181
182 Msr.Fields.Low = (ULONG)GuestRegs->rax;
183 Msr.Fields.High = (ULONG)GuestRegs->rdx;
184
185 //
186 // Check for sanity of MSR if they're valid or they're for reserved range for WRMSR and RDMSR
187 //
188 if ((TargetMsr <= 0x00001FFF) || ((0xC0000000 <= TargetMsr) && (TargetMsr <= 0xC0001FFF)) ||
189 (TargetMsr >= RESERVED_MSR_RANGE_LOW && (TargetMsr <= RESERVED_MSR_RANGE_HI)))
190 {
191 //
192 // If the source register contains a non-canonical address and ECX specifies
193 // one of the following MSRs:
194 //
195 // IA32_DS_AREA, IA32_FS_BASE, IA32_GS_BASE, IA32_KERNEL_GSBASE, IA32_LSTAR,
196 // IA32_SYSENTER_EIP, IA32_SYSENTER_ESP
197 //
198 switch (TargetMsr)
199 {
200 case IA32_DS_AREA:
201 case IA32_FS_BASE:
202 case IA32_GS_BASE:
203 case IA32_KERNEL_GS_BASE:
204 case IA32_LSTAR:
205 case IA32_SYSENTER_EIP:
206 case IA32_SYSENTER_ESP:
207
208 if (!CheckAddressCanonicality(Msr.Flags, &UnusedIsKernel))
209 {
210 //
211 // Address is not canonical, inject #GP
212 //
214
215 return;
216 }
217
218 break;
219 }
220
221 //
222 // Perform MSR change
223 //
224 switch (TargetMsr)
225 {
226 case IA32_SYSENTER_CS:
227 VmxVmwrite64(VMCS_GUEST_SYSENTER_CS, Msr.Flags);
228 break;
229
230 case IA32_SYSENTER_ESP:
231 VmxVmwrite64(VMCS_GUEST_SYSENTER_ESP, Msr.Flags);
232 break;
233
234 case IA32_SYSENTER_EIP:
235 VmxVmwrite64(VMCS_GUEST_SYSENTER_EIP, Msr.Flags);
236 break;
237
238 case IA32_GS_BASE:
239 VmxVmwrite64(VMCS_GUEST_GS_BASE, Msr.Flags);
240 break;
241
242 case IA32_FS_BASE:
243 VmxVmwrite64(VMCS_GUEST_FS_BASE, Msr.Flags);
244 break;
245
246 default:
247
248 //
249 // Perform the WRMSR
250 //
251 __writemsr((unsigned long)GuestRegs->rcx, Msr.Flags);
252 break;
253 }
254 }
255 else
256 {
257 //
258 // Msr is invalid, inject #GP
259 //
261 return;
262 }
263}
BOOLEAN CheckAddressCanonicality(UINT64 VAddr, PBOOLEAN IsKernelAddress)
Checks if the address is canonical based on x86 processor's virtual address width or not.
Definition AddressCheck.c:66
UCHAR BOOLEAN
Definition BasicTypes.h:39
unsigned long ULONG
Definition BasicTypes.h:37
UCHAR VmxVmwrite64(size_t Field, UINT64 FieldValue)
VMX VMWRITE instruction (64-bit)
Definition Vmx.c:122