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 = __readmsr(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 = __readmsr(IA32_EFER);
50
51 if (EnableEFERSyscallHook)
52 {
53 MsrValue.SyscallEnable = FALSE;
54
55 //
56 // Set VM-Entry controls to load EFER
57 //
58 __vmx_vmwrite(VMCS_CTRL_VMENTRY_CONTROLS, HvAdjustControls(VmEntryControls | VM_ENTRY_LOAD_IA32_EFER, VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_ENTRY_CTLS : IA32_VMX_ENTRY_CTLS));
59
60 //
61 // Set VM-Exit controls to save EFER
62 //
63 __vmx_vmwrite(VMCS_CTRL_PRIMARY_VMEXIT_CONTROLS, HvAdjustControls(VmExitControls | VM_EXIT_SAVE_IA32_EFER, 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 __vmx_vmwrite(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 __vmx_vmwrite(VMCS_CTRL_VMENTRY_CONTROLS, HvAdjustControls(VmEntryControls & ~VM_ENTRY_LOAD_IA32_EFER, VmxBasicMsr.VmxControls ? IA32_VMX_TRUE_ENTRY_CTLS : IA32_VMX_ENTRY_CTLS));
83
84 //
85 // Set VM-Exit controls to save EFER
86 //
87 __vmx_vmwrite(VMCS_CTRL_PRIMARY_VMEXIT_CONTROLS, HvAdjustControls(VmExitControls & ~VM_EXIT_SAVE_IA32_EFER, 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 __vmx_vmwrite(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 __writemsr(IA32_EFER, MsrValue.AsUInt);
99
100 //
101 // unset the exception to not cause vm-exit on #UDs
102 //
104 }
105}
#define TRUE
Definition BasicTypes.h:55
#define FALSE
Definition BasicTypes.h:54
unsigned int UINT32
Definition BasicTypes.h:48
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:1022
VOID ProtectedHvRemoveUndefinedInstructionForDisablingSyscallSysretCommands(VIRTUAL_MACHINE_STATE *VCpu)
Reset exception bitmap in VMCS because of clearing !exception commands.
Definition ProtectedHv.c:160
UCHAR VmxVmread32P(size_t Field, UINT32 *FieldValue)
VMX VMREAD instruction (32-bit)
Definition Vmx.c:86
#define VM_EXIT_SAVE_IA32_EFER
Definition Vmx.h:89
#define VM_ENTRY_LOAD_IA32_EFER
Definition Vmx.h:103
@ 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
123 //
124 // Reading guest's RIP
125 //
126 __vmx_vmread(VMCS_GUEST_RIP, &GuestRip);
127
128 //
129 // Reading instruction length
130 //
131 VmxVmread32P(VMCS_VMEXIT_INSTRUCTION_LENGTH, &InstructionLength);
132
133 //
134 // Reading guest's Rflags
135 //
136 __vmx_vmread(VMCS_GUEST_RFLAGS, &GuestRflags);
137
138 //
139 // Save the address of the instruction following SYSCALL into RCX and then
140 // load RIP from IA32_LSTAR.
141 //
142 MsrValue = __readmsr(IA32_LSTAR);
143 VCpu->Regs->rcx = GuestRip + InstructionLength;
144 GuestRip = MsrValue;
145 __vmx_vmwrite(VMCS_GUEST_RIP, GuestRip);
146
147 //
148 // Save RFLAGS into R11 and then mask RFLAGS using IA32_FMASK
149 //
150 MsrValue = __readmsr(IA32_FMASK);
151 VCpu->Regs->r11 = GuestRflags;
152 GuestRflags &= ~(MsrValue | X86_FLAGS_RF);
153 __vmx_vmwrite(VMCS_GUEST_RFLAGS, GuestRflags);
154
155 //
156 // Load the CS and SS selectors with values derived from bits 47:32 of IA32_STAR
157 //
158 MsrValue = __readmsr(IA32_STAR);
159 Cs.Selector = (UINT16)((MsrValue >> 32) & ~3); // STAR[47:32] & ~RPL3
160 Cs.Base = 0; // flat segment
161 Cs.Limit = (UINT32)~0; // 4GB limit
162 Cs.Attributes.AsUInt = 0xA09B; // L+DB+P+S+DPL0+Code
163 SetGuestCs(&Cs);
164
165 Ss.Selector = (UINT16)(((MsrValue >> 32) & ~3) + 8); // STAR[47:32] + 8
166 Ss.Base = 0; // flat segment
167 Ss.Limit = (UINT32)~0; // 4GB limit
168 Ss.Attributes.AsUInt = 0xC093; // G+DB+P+S+DPL0+Data
169 SetGuestSs(&Ss);
170
171 return TRUE;
172}
unsigned short UINT16
Definition BasicTypes.h:47
unsigned __int64 UINT64
Definition BasicTypes.h:21
VOID SetGuestSs(PVMX_SEGMENT_SELECTOR Ss)
Set the Guest Ss selector.
Definition ManageRegs.c:80
VOID SetGuestCs(PVMX_SEGMENT_SELECTOR Cs)
Set the Guest Cs.
Definition ManageRegs.c:35
#define X86_FLAGS_RF
Definition Common.h:103
GUEST_REGS * Regs
Definition State.h:305
Segment selector.
Definition DataTypes.h:436
UINT32 Limit
Definition DataTypes.h:439
VMX_SEGMENT_ACCESS_RIGHTS_TYPE Attributes
Definition DataTypes.h:438
UINT16 Selector
Definition DataTypes.h:437
UINT64 Base
Definition DataTypes.h:440
UINT64 rcx
Definition BasicTypes.h:76
UINT64 r11
Definition BasicTypes.h:86
UINT32 AsUInt
Definition DataTypes.h:428

◆ SyscallHookEmulateSYSRET()

_Use_decl_annotations_ BOOLEAN SyscallHookEmulateSYSRET ( VIRTUAL_MACHINE_STATE * VCpu)

This function emulates the SYSRET execution.

Parameters
VCpuThe virtual processor's state
Returns
BOOLEAN
183{
185 UINT64 MsrValue;
186 UINT64 GuestRip;
187 UINT64 GuestRflags;
188
189 //
190 // Load RIP from RCX
191 //
192 GuestRip = VCpu->Regs->rcx;
193 __vmx_vmwrite(VMCS_GUEST_RIP, GuestRip);
194
195 //
196 // Load RFLAGS from R11. Clear RF, VM, reserved bits
197 //
199 __vmx_vmwrite(VMCS_GUEST_RFLAGS, GuestRflags);
200
201 //
202 // SYSRET loads the CS and SS selectors with values derived from bits 63:48 of IA32_STAR
203 //
204 MsrValue = __readmsr(IA32_STAR);
205 Cs.Selector = (UINT16)(((MsrValue >> 48) + 16) | 3); // (STAR[63:48]+16) | 3 (* RPL forced to 3 *)
206 Cs.Base = 0; // Flat segment
207 Cs.Limit = (UINT32)~0; // 4GB limit
208 Cs.Attributes.AsUInt = 0xA0FB; // L+DB+P+S+DPL3+Code
209 SetGuestCs(&Cs);
210
211 Ss.Selector = (UINT16)(((MsrValue >> 48) + 8) | 3); // (STAR[63:48]+8) | 3 (* RPL forced to 3 *)
212 Ss.Base = 0; // Flat segment
213 Ss.Limit = (UINT32)~0; // 4GB limit
214 Ss.Attributes.AsUInt = 0xC0F3; // G+DB+P+S+DPL3+Data
215 SetGuestSs(&Ss);
216
217 return TRUE;
218}
#define X86_FLAGS_VM
Definition Common.h:104
#define X86_FLAGS_FIXED
Definition Common.h:113
#define X86_FLAGS_RESERVED_BITS
Definition Common.h:112

◆ 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
229{
230 CR3_TYPE GuestCr3;
231 UINT64 OriginalCr3;
232 UINT64 Rip;
233
234 //
235 // Reading guest's RIP
236 //
237 __vmx_vmread(VMCS_GUEST_RIP, &Rip);
238
240 {
241 //
242 // In some computers, we realized that safe accessing to memory
243 // is problematic. It means that our syscall approach might not
244 // working properly.
245 // Based on our tests, we realized that system doesn't generate #UD
246 // regularly. So, we can imagine that only kernel addresses are SYSRET
247 // instruction and SYSCALL is on a user-mode RIP.
248 // It's faster than our safe methods but if the system generates a #UD
249 // then a BSOD will happen. But if the system is working regularly, then
250 // no BSOD happens. For more information, see documentation at !syscall2
251 // or !sysret2 commands
252 //
253 if (Rip & 0xff00000000000000)
254 {
255 goto EmulateSYSRET;
256 }
257 else
258 {
259 goto EmulateSYSCALL;
260 }
261 }
262 else
263 {
264 //
265 // Get the guest's running process's cr3
266 //
268
269 //
270 // No, longer needs to be checked because we're sticking to system process
271 // and we have to change the cr3
272 //
273 // if ((GuestCr3.Flags & PCID_MASK) != PCID_NONE)
274
275 OriginalCr3 = __readcr3();
276
277 __writecr3(GuestCr3.Flags);
278
279 //
280 // Read the memory
281 //
282 UCHAR InstructionBuffer[3] = {0};
283
284 if (MemoryMapperCheckIfPageIsPresentByCr3((PVOID)Rip, GuestCr3))
285 {
286 //
287 // The page is safe to read (present)
288 // It's not necessary to use MemoryMapperReadMemorySafeOnTargetProcess
289 // because we already switched to the process's cr3
290 //
291 MemoryMapperReadMemorySafe(Rip, InstructionBuffer, 3);
292 }
293 else
294 {
295 //
296 // The page is not present, we have to inject a #PF
297 //
299
300 //
301 // For testing purpose
302 //
303 // LogInfo("#PF Injected");
304
305 //
306 // Inject #PF
307 //
309
310 //
311 // We should not inject #UD
312 //
313 return FALSE;
314 }
315
316 __writecr3(OriginalCr3);
317
318 if (InstructionBuffer[0] == 0x0F &&
319 InstructionBuffer[1] == 0x05)
320 {
321 goto EmulateSYSCALL;
322 }
323
324 if (InstructionBuffer[0] == 0x48 &&
325 InstructionBuffer[1] == 0x0F &&
326 InstructionBuffer[2] == 0x07)
327 {
328 goto EmulateSYSRET;
329 }
330
331 return FALSE;
332 }
333
334 //----------------------------------------------------------------------------------------
335
336 //
337 // Emulate SYSRET instruction
338 //
339EmulateSYSRET:
340
341 //
342 // Test
343 //
344 // LogInfo("SYSRET instruction => 0x%llX", Rip);
345 //
346
347 //
348 // Perform the dispatching and the emulation of the SYSRET event
349 //
350 DispatchEventEferSysret(VCpu, (PVOID)Rip);
351
352 return TRUE;
353
354 //
355 // Emulate SYSCALL instruction
356 //
357
358EmulateSYSCALL:
359
360 //
361 // Test
362 //
363 // LogInfo("SYSCALL instruction => 0x%llX , Process Id : 0x%x", Rip, PsGetCurrentProcessId());
364 //
365
366 //
367 // Perform the dispatching and the emulation of the SYSCAKK event
368 //
370
371 return TRUE;
372}
unsigned char UCHAR
Definition BasicTypes.h:35
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
BOOLEAN g_IsUnsafeSyscallOrSysretHandling
Shows whether the debuggee is waiting for an trap step or not.
Definition GlobalVariables.h:101
VOID HvSuppressRipIncrement(VIRTUAL_MACHINE_STATE *VCpu)
Suppress the incrementation of RIP.
Definition Hv.c:324
CR3_TYPE LayoutGetCurrentProcessCr3()
Get cr3 of the target running process.
Definition Layout.c:55
_Use_decl_annotations_ BOOLEAN MemoryMapperReadMemorySafe(UINT64 VaAddressToRead, PVOID BufferToSaveMemory, SIZE_T SizeToRead)
Read memory safely by mapping the buffer (It's a wrapper)
Definition MemoryMapper.c:1101
_Use_decl_annotations_ BOOLEAN MemoryMapperCheckIfPageIsPresentByCr3(PVOID Va, CR3_TYPE TargetCr3)
This function checks if the page is mapped or not.
Definition MemoryMapper.c:418
CR3 Structure.
Definition BasicTypes.h:130
UINT64 Flags
Definition BasicTypes.h:133