HyperDbg Debugger
Loading...
Searching...
No Matches
EferHook.c File Reference

Implementation of the functions related to the EFER Syscall Hook. More...

#include "pch.h"

Functions

VOID SyscallHookConfigureEFER (VIRTUAL_MACHINE_STATE *VCpu, BOOLEAN EnableEFERSyscallHook)
 This function enables or disables EFER syscall hoo.
_Use_decl_annotations_ BOOLEAN SyscallHookEmulateSYSCALL (VIRTUAL_MACHINE_STATE *VCpu)
 This function emulates the SYSCALL execution.
_Use_decl_annotations_ BOOLEAN SyscallHookEmulateSYSRET (VIRTUAL_MACHINE_STATE *VCpu)
 This function emulates the SYSRET execution.
_Use_decl_annotations_ BOOLEAN SyscallHookHandleUD (VIRTUAL_MACHINE_STATE *VCpu)
 Detect whether the #UD was because of Syscall or Sysret or not.

Detailed Description

Implementation of the functions related to the EFER Syscall Hook.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)

This is derived by the method demonstrated at

also some of the functions derived from hvpp

Version
0.1
Date
2020-04-10

Function Documentation

◆ SyscallHookConfigureEFER()

VOID SyscallHookConfigureEFER ( VIRTUAL_MACHINE_STATE * VCpu,
BOOLEAN EnableEFERSyscallHook )

This function enables or disables EFER syscall hoo.

This function should be called for the first time that we want to enable EFER hook because after calling this function EFER MSR is loaded from GUEST_EFER instead of loading from the regular EFER MSR.

Parameters
VCpuThe virtual processor's state
EnableEFERSyscallHookDetermines whether we want to enable syscall hook or disable syscall hook
Returns
VOID
32{
33 IA32_EFER_REGISTER MsrValue;
34 IA32_VMX_BASIC_REGISTER VmxBasicMsr = {0};
35 UINT32 VmEntryControls = 0;
36 UINT32 VmExitControls = 0;
37
38 //
39 // Reading IA32_VMX_BASIC_MSR
40 //
41 VmxBasicMsr.AsUInt = CpuReadMsr(IA32_VMX_BASIC);
42
43 //
44 // Read previous VM-Entry and VM-Exit controls
45 //
46 VmxVmread32P(VMCS_CTRL_VMENTRY_CONTROLS, &VmEntryControls);
47 VmxVmread32P(VMCS_CTRL_PRIMARY_VMEXIT_CONTROLS, &VmExitControls);
48
49 MsrValue.AsUInt = CpuReadMsr(IA32_EFER);
50
51 if (EnableEFERSyscallHook)
52 {
53 MsrValue.SyscallEnable = FALSE;
54
55 //
56 // Set VM-Entry controls to load EFER
57 //
58 VmxVmwrite32(VMCS_CTRL_VMENTRY_CONTROLS, HvAdjustControls(VmEntryControls | IA32_VMX_ENTRY_CTLS_LOAD_IA32_EFER_FLAG, VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_ENTRY_CTLS : IA32_VMX_ENTRY_CTLS));
59
60 //
61 // Set VM-Exit controls to save EFER
62 //
63 VmxVmwrite32(VMCS_CTRL_PRIMARY_VMEXIT_CONTROLS, HvAdjustControls(VmExitControls | IA32_VMX_EXIT_CTLS_SAVE_IA32_EFER_FLAG, VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_EXIT_CTLS : IA32_VMX_EXIT_CTLS));
64
65 //
66 // Set the GUEST EFER to use this value as the EFER
67 //
68 VmxVmwrite64(VMCS_GUEST_EFER, MsrValue.AsUInt);
69
70 //
71 // also, we have to set exception bitmap to cause vm-exit on #UDs
72 //
74 }
75 else
76 {
77 MsrValue.SyscallEnable = TRUE;
78
79 //
80 // Set VM-Entry controls to load EFER
81 //
82 VmxVmwrite32(VMCS_CTRL_VMENTRY_CONTROLS, HvAdjustControls(VmEntryControls & ~IA32_VMX_ENTRY_CTLS_LOAD_IA32_EFER_FLAG, VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_ENTRY_CTLS : IA32_VMX_ENTRY_CTLS));
83
84 //
85 // Set VM-Exit controls to save EFER
86 //
87 VmxVmwrite32(VMCS_CTRL_PRIMARY_VMEXIT_CONTROLS, HvAdjustControls(VmExitControls & ~IA32_VMX_EXIT_CTLS_SAVE_IA32_EFER_FLAG, VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_EXIT_CTLS : IA32_VMX_EXIT_CTLS));
88
89 //
90 // Set the GUEST EFER to use this value as the EFER
91 //
92 VmxVmwrite64(VMCS_GUEST_EFER, MsrValue.AsUInt);
93
94 //
95 // Because we're not save or load EFER on vm-exits so
96 // we have to set it manually
97 //
98 CpuWriteMsr(IA32_EFER, MsrValue.AsUInt);
99
100 //
101 // unset the exception to not cause vm-exit on #UDs
102 //
104 }
105}
UINT32 HvAdjustControls(UINT32 Ctl, UINT32 Msr)
Adjust controls for VMCS based on processor capability.
Definition Hv.c:23
VOID HvSetExceptionBitmap(VIRTUAL_MACHINE_STATE *VCpu, UINT32 IdtIndex)
Set exception bitmap in VMCS.
Definition Hv.c:1069
VOID CpuWriteMsr(ULONG MsrAddress, UINT64 MsrValue)
Write an MSR.
Definition PlatformIntrinsics.c:233
UINT64 CpuReadMsr(ULONG MsrAddress)
Read an MSR.
Definition PlatformIntrinsics.c:213
UCHAR VmxVmwrite64(size_t Field, UINT64 FieldValue)
VMX VMWRITE instruction (64-bit).
Definition PlatformIntrinsicsVmx.c:273
UCHAR VmxVmwrite32(size_t Field, UINT32 FieldValue)
VMX VMWRITE instruction (32-bit).
Definition PlatformIntrinsicsVmx.c:293
UCHAR VmxVmread32P(size_t Field, UINT32 *FieldValue)
VMX VMREAD instruction (32-bit, pointer variant).
Definition PlatformIntrinsicsVmx.c:227
VOID ProtectedHvRemoveUndefinedInstructionForDisablingSyscallSysretCommands(VIRTUAL_MACHINE_STATE *VCpu)
Reset exception bitmap in VMCS because of clearing !exception commands.
Definition ProtectedHv.c:161
#define TRUE
Definition BasicTypes.h:114
#define FALSE
Definition BasicTypes.h:113
unsigned int UINT32
Definition BasicTypes.h:54
@ EXCEPTION_VECTOR_UNDEFINED_OPCODE
Definition Events.h:30

◆ SyscallHookEmulateSYSCALL()

_Use_decl_annotations_ BOOLEAN SyscallHookEmulateSYSCALL ( VIRTUAL_MACHINE_STATE * VCpu)

This function emulates the SYSCALL execution.

Parameters
VCpuThe virtual processor's state
Returns
BOOLEAN
116{
118 UINT32 InstructionLength;
119 UINT64 MsrValue;
120 UINT64 GuestRip;
121 UINT64 GuestRflags;
122 UINT64 Ssp;
123 IA32_U_CET_REGISTER UcetMsr;
124
125 //
126 // Reading guest's RIP
127 //
128 VmxVmread64P(VMCS_GUEST_RIP, &GuestRip);
129
130 //
131 // Reading instruction length
132 //
133 VmxVmread32P(VMCS_VMEXIT_INSTRUCTION_LENGTH, &InstructionLength);
134
135 //
136 // Reading guest's Rflags
137 //
138 VmxVmread64P(VMCS_GUEST_RFLAGS, &GuestRflags);
139
140 //
141 // Save the address of the instruction following SYSCALL into RCX and then
142 // load RIP from IA32_LSTAR.
143 //
144 MsrValue = CpuReadMsr(IA32_LSTAR);
145 VCpu->Regs->rcx = GuestRip + InstructionLength;
146 GuestRip = MsrValue;
147 VmxVmwrite64(VMCS_GUEST_RIP, GuestRip);
148
149 //
150 // Save RFLAGS into R11 and then mask RFLAGS using IA32_FMASK
151 //
152 MsrValue = CpuReadMsr(IA32_FMASK);
153 VCpu->Regs->r11 = GuestRflags;
154 GuestRflags &= ~(MsrValue | X86_FLAGS_RF);
155 VmxVmwrite64(VMCS_GUEST_RFLAGS, GuestRflags);
156
157 //
158 // Perform emulation of Intel CET (Shadow stacks)
159 //
160 if (g_CompatibilityCheck.CetShadowStackSupport)
161 {
162 UcetMsr.AsUInt = CpuReadMsr(IA32_U_CET);
163
164 //
165 // If the shadow stack is enabled, we have to save the current
166 //
167 if (UcetMsr.ShStkEn)
168 {
169 VmxVmread64P(VMCS_GUEST_SSP, &Ssp);
170 CpuWriteMsr(IA32_PL3_SSP, Ssp);
171 VmxVmwrite64(VMCS_GUEST_SSP, 0);
172 }
173 }
174
175 //
176 // Load the CS and SS selectors with values derived from bits 47:32 of IA32_STAR
177 //
178 MsrValue = CpuReadMsr(IA32_STAR);
179 Cs.Selector = (UINT16)((MsrValue >> 32) & ~3); // STAR[47:32] & ~RPL3
180 Cs.Base = 0; // flat segment
181 Cs.Limit = (UINT32)~0; // 4GB limit
182 Cs.Attributes.AsUInt = 0xA09B; // L+DB+P+S+DPL0+Code
183 SetGuestCs(&Cs);
184
185 Ss.Selector = (UINT16)(((MsrValue >> 32) & ~3) + 8); // STAR[47:32] + 8
186 Ss.Base = 0; // flat segment
187 Ss.Limit = (UINT32)~0; // 4GB limit
188 Ss.Attributes.AsUInt = 0xC093; // G+DB+P+S+DPL0+Data
189 SetGuestSs(&Ss);
190
191 return TRUE;
192}
UCHAR VmxVmread64P(size_t Field, UINT64 *FieldValue)
VMX VMREAD instruction (64-bit, pointer variant).
Definition PlatformIntrinsicsVmx.c:207
unsigned short UINT16
Definition BasicTypes.h:53
#define X86_FLAGS_RF
Definition Constants.h:540
struct _VMX_SEGMENT_SELECTOR VMX_SEGMENT_SELECTOR
Segment selector.
IMPORT_EXPORT_VMM VOID SetGuestSs(PVMX_SEGMENT_SELECTOR Ss)
Set the Guest Ss selector.
Definition ManageRegs.c:80
IMPORT_EXPORT_VMM VOID SetGuestCs(PVMX_SEGMENT_SELECTOR Cs)
Set the Guest Cs.
Definition ManageRegs.c:35
COMPATIBILITY_CHECKS_STATUS g_CompatibilityCheck
Different attributes and compatibility checks of the current processor.
Definition GlobalVariables.h:26
GUEST_REGS * Regs
Definition State.h:326
UINT32 Limit
Definition DataTypes.h:488
VMX_SEGMENT_ACCESS_RIGHTS_TYPE Attributes
Definition DataTypes.h:487
UINT16 Selector
Definition DataTypes.h:486
UINT64 Base
Definition DataTypes.h:489
UINT64 rcx
Definition BasicTypes.h:142
UINT64 r11
Definition BasicTypes.h:152
UINT32 AsUInt
Definition DataTypes.h:477

◆ SyscallHookEmulateSYSRET()

_Use_decl_annotations_ BOOLEAN SyscallHookEmulateSYSRET ( VIRTUAL_MACHINE_STATE * VCpu)

This function emulates the SYSRET execution.

Parameters
VCpuThe virtual processor's state
Returns
BOOLEAN
203{
205 UINT64 MsrValue;
206 UINT64 GuestRip;
207 UINT64 GuestRflags;
208 UINT64 Ssp;
209 IA32_U_CET_REGISTER UcetMsr;
210
211 //
212 // Load RIP from RCX
213 //
214 GuestRip = VCpu->Regs->rcx;
215 VmxVmwrite64(VMCS_GUEST_RIP, GuestRip);
216
217 //
218 // Load RFLAGS from R11. Clear RF, VM, reserved bits
219 //
221 VmxVmwrite64(VMCS_GUEST_RFLAGS, GuestRflags);
222
223 //
224 // Restore user-mode SPP
225 //
226 if (g_CompatibilityCheck.CetShadowStackSupport)
227 {
228 UcetMsr.AsUInt = CpuReadMsr(IA32_U_CET);
229
230 //
231 // If the shadow stack is enabled, we have to restore the current
232 //
233 if (UcetMsr.ShStkEn)
234 {
235 Ssp = CpuReadMsr(IA32_PL3_SSP);
236 VmxVmwrite64(VMCS_GUEST_SSP, Ssp);
237 }
238 }
239
240 //
241 // SYSRET loads the CS and SS selectors with values derived from bits 63:48 of IA32_STAR
242 //
243 MsrValue = CpuReadMsr(IA32_STAR);
244 Cs.Selector = (UINT16)(((MsrValue >> 48) + 16) | 3); // (STAR[63:48]+16) | 3 (* RPL forced to 3 *)
245 Cs.Base = 0; // Flat segment
246 Cs.Limit = (UINT32)~0; // 4GB limit
247 Cs.Attributes.AsUInt = 0xA0FB; // L+DB+P+S+DPL3+Code
248 SetGuestCs(&Cs);
249
250 Ss.Selector = (UINT16)(((MsrValue >> 48) + 8) | 3); // (STAR[63:48]+8) | 3 (* RPL forced to 3 *)
251 Ss.Base = 0; // Flat segment
252 Ss.Limit = (UINT32)~0; // 4GB limit
253 Ss.Attributes.AsUInt = 0xC0F3; // G+DB+P+S+DPL3+Data
254 SetGuestSs(&Ss);
255
256 return TRUE;
257}
#define X86_FLAGS_VM
Definition Constants.h:541
#define X86_FLAGS_FIXED
Definition Constants.h:550
#define X86_FLAGS_RESERVED_BITS
Definition Constants.h:549

◆ SyscallHookHandleUD()

_Use_decl_annotations_ BOOLEAN SyscallHookHandleUD ( VIRTUAL_MACHINE_STATE * VCpu)

Detect whether the #UD was because of Syscall or Sysret or not.

Parameters
VCpuThe virtual processor's state
Returns
BOOLEAN Shows whether the caller should inject #UD on the guest or not
268{
269 CR3_TYPE GuestCr3;
270 UINT64 OriginalCr3;
271 UINT64 Rip;
272
273 //
274 // Reading guest's RIP
275 //
276 VmxVmread64P(VMCS_GUEST_RIP, &Rip);
277
279 {
280 //
281 // In some computers, we realized that safe accessing to memory
282 // is problematic. It means that our syscall approach might not
283 // working properly.
284 // Based on our tests, we realized that system doesn't generate #UD
285 // regularly. So, we can imagine that only kernel addresses are SYSRET
286 // instruction and SYSCALL is on a user-mode RIP.
287 // It's faster than our safe methods but if the system generates a #UD
288 // then a BSOD will happen. But if the system is working regularly, then
289 // no BSOD happens. For more information, see documentation at !syscall2
290 // or !sysret2 commands
291 //
292 if (Rip & 0xff00000000000000)
293 {
294 goto EmulateSYSRET;
295 }
296 else
297 {
298 goto EmulateSYSCALL;
299 }
300 }
301 else
302 {
303 //
304 // Get the guest's running process's cr3
305 //
307
308 //
309 // No, longer needs to be checked because we're sticking to system process
310 // and we have to change the cr3
311 //
312 // if ((GuestCr3.Flags & PCID_MASK) != PCID_NONE)
313
314 OriginalCr3 = CpuReadCr3();
315
316 CpuWriteCr3(GuestCr3.Flags);
317
318 //
319 // Read the memory
320 //
321 UCHAR InstructionBuffer[3] = {0};
322
324 {
325 //
326 // The page is safe to read (present)
327 // It's not necessary to use MemoryMapperReadMemorySafeOnTargetProcess
328 // because we already switched to the process's cr3
329 //
330 MemoryMapperReadMemorySafe(Rip, InstructionBuffer, 3);
331 }
332 else
333 {
334 //
335 // The page is not present, we have to inject a #PF
336 //
338
339 //
340 // For testing purpose
341 //
342 // LogInfo("#PF Injected");
343
344 //
345 // Inject #PF
346 //
348
349 //
350 // We should not inject #UD
351 //
352 return FALSE;
353 }
354
355 CpuWriteCr3(OriginalCr3);
356
357 if (InstructionBuffer[0] == 0x0F &&
358 InstructionBuffer[1] == 0x05)
359 {
360 goto EmulateSYSCALL;
361 }
362
363 if (InstructionBuffer[0] == 0x48 &&
364 InstructionBuffer[1] == 0x0F &&
365 InstructionBuffer[2] == 0x07)
366 {
367 goto EmulateSYSRET;
368 }
369
370 return FALSE;
371 }
372
373 //----------------------------------------------------------------------------------------
374
375 //
376 // Emulate SYSRET instruction
377 //
378EmulateSYSRET:
379
380 //
381 // Test
382 //
383 // LogInfo("SYSRET instruction => 0x%llX", Rip);
384 //
385
386 //
387 // Perform the dispatching and the emulation of the SYSRET event
388 //
389 DispatchEventEferSysret(VCpu, (PVOID)Rip);
390
391 return TRUE;
392
393 //
394 // Emulate SYSCALL instruction
395 //
396
397EmulateSYSCALL:
398
399 //
400 // Test
401 //
402 // LogInfo("SYSCALL instruction => 0x%llX , Process Id : 0x%x", Rip, PsGetCurrentProcessId());
403 //
404
405 //
406 // Perform the dispatching and the emulation of the SYSCAKK event
407 //
409
410 return TRUE;
411}
VOID DispatchEventEferSyscall(VIRTUAL_MACHINE_STATE *VCpu)
Handling debugger functions related to SYSCALL events.
Definition Dispatch.c:69
VOID DispatchEventEferSysret(VIRTUAL_MACHINE_STATE *VCpu, PVOID Context)
Handling debugger functions related to SYSRET events.
Definition Dispatch.c:25
VOID EventInjectPageFaultWithoutErrorCode(UINT64 PageFaultAddress)
Inject PF to the guest (Page-Fault for EFER Injector).
Definition Events.c:124
VOID HvSuppressRipIncrement(VIRTUAL_MACHINE_STATE *VCpu)
Suppress the incrementation of RIP.
Definition Hv.c:320
_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPageIsPresentByCr3(PVOID Va, CR3_TYPE TargetCr3)
This function checks if the page is mapped or not.
Definition MemoryMapper.c:418
ULONG_PTR CpuReadCr3(VOID)
Read CR3.
Definition PlatformIntrinsics.c:100
VOID CpuWriteCr3(ULONG_PTR Cr3Value)
Write CR3.
Definition PlatformIntrinsics.c:119
void * PVOID
Definition BasicTypes.h:56
unsigned char UCHAR
Definition BasicTypes.h:34
struct _CR3_TYPE CR3_TYPE
CR3 Structure.
IMPORT_EXPORT_VMM BOOLEAN MemoryMapperReadMemorySafe(_In_ UINT64 VaAddressToRead, _Inout_ PVOID BufferToSaveMemory, _In_ SIZE_T SizeToRead)
IMPORT_EXPORT_VMM CR3_TYPE LayoutGetCurrentProcessCr3()
Get cr3 of the target running process.
Definition Layout.c:55
BOOLEAN g_IsUnsafeSyscallOrSysretHandling
Shows whether the debuggee is waiting for an trap step or not.
Definition GlobalVariables.h:94
UINT64 Flags
Definition BasicTypes.h:239