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

Implementation of memory hooks functions. More...

#include "pch.h"

Functions

BOOLEAN DirtyLoggingInitialize ()
 Initialize the dirty logging mechanism.
 
BOOLEAN DirtyLoggingEnable (VIRTUAL_MACHINE_STATE *VCpu)
 Enables the dirty logging mechanism in VMX-root mode.
 
VOID DirtyLoggingDisable (VIRTUAL_MACHINE_STATE *VCpu)
 Disables the dirty logging mechanism in VMX-root mode.
 
VOID DirtyLoggingUninitialize ()
 Initialize the dirty logging mechanism.
 
VOID DirtyLoggingHandlePageModificationLog (VIRTUAL_MACHINE_STATE *VCpu)
 Create log from dirty log buffer.
 
BOOLEAN DirtyLoggingFlushPmlBuffer (VIRTUAL_MACHINE_STATE *VCpu)
 
VOID DirtyLoggingHandleVmexits (VIRTUAL_MACHINE_STATE *VCpu)
 Handling vm-exits of PML.
 

Detailed Description

Implementation of memory hooks functions.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.2
Date
2023-02-05

Function Documentation

◆ DirtyLoggingDisable()

VOID DirtyLoggingDisable ( VIRTUAL_MACHINE_STATE * VCpu)

Disables the dirty logging mechanism in VMX-root mode.

should be called in vmx-root mode

Parameters
VCpuThe virtual processor's state
Returns
VOID
157{
158 UNREFERENCED_PARAMETER(VCpu);
159
160 //
161 // Clear the address
162 //
163 __vmx_vmwrite(VMCS_CTRL_PML_ADDRESS, NULL64_ZERO);
164
165 //
166 // Clear the PML index
167 //
168 __vmx_vmwrite(VMCS_GUEST_PML_INDEX, 0x0);
169
170 //
171 // Disable PML Enable bit
172 //
174}
#define NULL64_ZERO
Definition BasicTypes.h:52
#define FALSE
Definition BasicTypes.h:54
VOID HvSetPmlEnableFlag(BOOLEAN Set)
Set Page Modification Logging Enable bit.
Definition Hv.c:640

◆ DirtyLoggingEnable()

BOOLEAN DirtyLoggingEnable ( VIRTUAL_MACHINE_STATE * VCpu)

Enables the dirty logging mechanism in VMX-root mode.

should be called in vmx-root mode

Parameters
VCpuThe virtual processor's state
Returns
BOOLEAN
106{
107 //
108 // Check if PML Address buffer is empty or not
109 //
110 if (VCpu->PmlBufferAddress == NULL)
111 {
112 return FALSE;
113 }
114
115 //
116 // Write the address of the buffer
117 //
119
120 // LogInfo("PML Buffer Address = %llx", PmlPhysAddr);
121
122 __vmx_vmwrite(VMCS_CTRL_PML_ADDRESS, PmlPhysAddr);
123
124 //
125 // Clear the PML index
126 //
127 __vmx_vmwrite(VMCS_GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
128
129 //
130 // If the "enable PML" VM-execution control is 1 and bit 6 of EPT pointer (EPTP)
131 // is 1 (enabling accessed and dirty flags for EPT) then we can use this feature
132 // by default we set this flag for EPTP so, we have to enable PML ENABLE Bit in the
133 // secondary proc-based controls
134 //
135
136 //
137 // Secondary processor-based VM-execution control 17 is defined as enable PML
138 //
140
141 //
142 // Initialization was successful
143 //
144 return TRUE;
145}
#define TRUE
Definition BasicTypes.h:55
unsigned __int64 UINT64
Definition BasicTypes.h:21
_Use_decl_annotations_ UINT64 VirtualAddressToPhysicalAddress(_In_ PVOID VirtualAddress)
Converts Virtual Address to Physical Address.
Definition Conversion.c:154
#define PML_ENTITY_NUM
Definition DirtyLogging.h:18
PUINT64 PmlBufferAddress
Definition State.h:302

◆ DirtyLoggingFlushPmlBuffer()

BOOLEAN DirtyLoggingFlushPmlBuffer ( VIRTUAL_MACHINE_STATE * VCpu)
229{
230 UINT64 * PmlBuf;
231 UINT16 PmlIdx;
232 BOOLEAN IsLargePage;
233 PVOID PmlEntry;
234
235 VmxVmread16P(VMCS_GUEST_PML_INDEX, &PmlIdx);
236
237 //
238 // Do nothing if PML buffer is empty
239 //
240 if (PmlIdx == (PML_ENTITY_NUM - 1))
241 return FALSE;
242
243 //
244 // PML index always points to next available PML buffer entity
245 //
246 if (PmlIdx >= PML_ENTITY_NUM)
247 {
248 PmlIdx = 0;
249 }
250 else
251 {
252 PmlIdx++;
253 }
254
255 PmlBuf = VCpu->PmlBufferAddress;
256
257 for (; PmlIdx < PML_ENTITY_NUM; PmlIdx++)
258 {
259 UINT64 AccessedPhysAddr;
260
261 AccessedPhysAddr = PmlBuf[PmlIdx];
262
263 PmlEntry = EptGetPml1OrPml2Entry(VCpu->EptPageTable, AccessedPhysAddr, &IsLargePage);
264
265 if (PmlEntry == NULL)
266 {
267 //
268 // Page PML entry is not valid
269 //
270 LogInfo("Err, null page");
271 continue;
272 }
273
274 if (IsLargePage)
275 {
276 ((PEPT_PML2_ENTRY)PmlEntry)->Dirty = FALSE;
277 }
278 else
279 {
280 ((PEPT_PML1_ENTRY)PmlEntry)->Dirty = FALSE;
281 }
282 }
283
284 //
285 // reset PML index
286 //
287 __vmx_vmwrite(VMCS_GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
288
289 return TRUE;
290}
unsigned short UINT16
Definition BasicTypes.h:47
UCHAR BOOLEAN
Definition BasicTypes.h:39
PVOID EptGetPml1OrPml2Entry(PVMM_EPT_PAGE_TABLE EptPageTable, SIZE_T PhysicalAddress, BOOLEAN *IsLargePage)
Get the PML1 entry for this physical address if the large page is available then large page of Pml2 i...
Definition Ept.c:368
#define LogInfo(format,...)
Define log variables.
Definition HyperDbgHyperLogIntrinsics.h:71
UCHAR VmxVmread16P(size_t Field, UINT16 *FieldValue)
VMX VMREAD instruction (16-bit)
Definition Vmx.c:104
EPT_PTE * PEPT_PML1_ENTRY
Definition State.h:22
EPT_PDE_2MB * PEPT_PML2_ENTRY
Definition State.h:20
PVMM_EPT_PAGE_TABLE EptPageTable
Definition State.h:342

◆ DirtyLoggingHandlePageModificationLog()

VOID DirtyLoggingHandlePageModificationLog ( VIRTUAL_MACHINE_STATE * VCpu)

Create log from dirty log buffer.

Parameters
VCpuThe virtual processor's state
Returns
VOID
217{
218 //
219 // The guest-physical address of the access is written to the page-modification log
220 //
221 for (size_t i = 0; i < PML_ENTITY_NUM; i++)
222 {
223 LogInfo("Address : %llx", VCpu->PmlBufferAddress[i]);
224 }
225}

◆ DirtyLoggingHandleVmexits()

VOID DirtyLoggingHandleVmexits ( VIRTUAL_MACHINE_STATE * VCpu)

Handling vm-exits of PML.

Parameters
VCpuThe virtual processor's state
Returns
VOID
301{
302 //
303 // *** The guest-physical address of the access is written
304 // to the page-modification log and the buffer is full ***
305 //
306
307 //
308 // Test log
309 //
310 LogInfo("Dirty Logging VM-exit");
311 // DirtyLoggingHandlePageModificationLog(VCpu);
312
313 //
314 // Flush the PML buffer
315 //
317
318 //
319 // Do not increment RIP
320 //
322}
BOOLEAN DirtyLoggingFlushPmlBuffer(VIRTUAL_MACHINE_STATE *VCpu)
Definition DirtyLogging.c:228
VOID HvSuppressRipIncrement(VIRTUAL_MACHINE_STATE *VCpu)
Suppress the incrementation of RIP.
Definition Hv.c:324

◆ DirtyLoggingInitialize()

BOOLEAN DirtyLoggingInitialize ( )

Initialize the dirty logging mechanism.

Returns
BOOLEAN
22{
23 ULONG ProcessorsCount;
24
25 //
26 // Query count of active processors
27 //
28 ProcessorsCount = KeQueryActiveProcessorCount(0);
29
30 //
31 // The explanations are copied from Intel whitepaper on PML:
32 // Link : https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/page-modification-logging-vmm-white-paper.pdf
33 //
34
35 //
36 // When PML is active each write that sets a dirty flag for EPT also generates an entry in an inmemory log,
37 // reporting the guest-physical address of the write (aligned to 4 KBytes)
38 // When the log is full, a VM exit occurs, notifying the VMM.A VMM can monitor the number of pages modified
39 // by each thread by specifying an available set of log entries
40 //
41
42 //
43 // Check for the support of PML
44 //
46 {
47 LogWarning("err, dirty logging mechanism is not initialized as the processor doesn't support PML");
48 return FALSE;
49 }
50
51 //
52 // A new 64-bit VM-execution control field is defined called the PML address. This is
53 // the 4 - KByte aligned physical address of the page - modification log.The page modification
54 // log comprises 512 64 - bit entries
55 //
56 for (size_t i = 0; i < ProcessorsCount; i++)
57 {
58 if (g_GuestState[i].PmlBufferAddress == NULL)
59 {
61 }
62
63 if (g_GuestState[i].PmlBufferAddress == NULL)
64 {
65 //
66 // Allocation failed
67 //
68 for (size_t j = 0; j < ProcessorsCount; j++)
69 {
70 if (g_GuestState[j].PmlBufferAddress != NULL)
71 {
72 PlatformMemFreePool(g_GuestState[j].PmlBufferAddress);
73 }
74 }
75
76 return FALSE;
77 }
78
79 //
80 // Clear the log buffer
81 //
82 RtlZeroBytes(g_GuestState[i].PmlBufferAddress, PAGE_SIZE);
83 }
84
85 //
86 // Broadcast VMCALL to adjust PML controls from vmx-root
87 //
89
90 //
91 // Initialization was successful
92 //
93 return TRUE;
94}
unsigned long ULONG
Definition BasicTypes.h:37
VOID BroadcastEnablePmlOnAllProcessors()
routines for enabling PML on all cores
Definition Broadcast.c:524
VIRTUAL_MACHINE_STATE * g_GuestState
Save the state and variables related to virtualization on each to logical core.
Definition GlobalVariables.h:38
COMPATIBILITY_CHECKS_STATUS g_CompatibilityCheck
Different attributes and compatibility checks of the current processor.
Definition GlobalVariables.h:26
#define LogWarning(format,...)
Log in the case of warning.
Definition HyperDbgHyperLogIntrinsics.h:99
PVOID PlatformMemAllocateNonPagedPool(SIZE_T NumberOfBytes)
Allocate a non-paged buffer.
Definition Mem.c:41
VOID PlatformMemFreePool(PVOID BufferAddress)
Free (dellocate) a non-paged buffer.
Definition Mem.c:86
#define PAGE_SIZE
Size of each page (4096 bytes)
Definition common.h:69
BOOLEAN PmlSupport
Definition CompatibilityChecks.h:27

◆ DirtyLoggingUninitialize()

VOID DirtyLoggingUninitialize ( )

Initialize the dirty logging mechanism.

Returns
VOID
183{
184 ULONG ProcessorsCount;
185
186 //
187 // Query count of active processors
188 //
189 ProcessorsCount = KeQueryActiveProcessorCount(0);
190
191 //
192 // Broadcast VMCALL to disable PML controls from vmx-root
193 //
195
196 //
197 // Free the allocated pool buffers
198 //
199 for (size_t i = 0; i < ProcessorsCount; i++)
200 {
201 if (g_GuestState[i].PmlBufferAddress != NULL)
202 {
203 PlatformMemFreePool(g_GuestState[i].PmlBufferAddress);
204 }
205 }
206}
VOID BroadcastDisablePmlOnAllProcessors()
routines for disabling PML on all cores
Definition Broadcast.c:535