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

Implementation of different EPT hidden hooks functions. More...

#include "pch.h"

Functions

_Must_inspect_result_ _Success_ (return==TRUE)
 Check whether the desired PhysicalAddress is already in the g_EptState->HookedPagesList hooks or not.
 
VOID EptHookReservePreallocatedPoolsForEptHooks (UINT32 Count)
 Reserve pre-allocated pools for EPT hooks.
 
VOID EptHookAllocateExtraHookingPagesForMemoryMonitorsAndExecEptHooks (UINT32 Count)
 Allocate (reserve) extra pages for storing details of page hooks for memory monitor and regular hidden breakpoit exec EPT hooks.
 
PVOID ExAllocatePoolWithTagHook (POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag)
 Hook function that HooksExAllocatePoolWithTag.
 
BOOLEAN EptHookPerformPageHook (VIRTUAL_MACHINE_STATE *VCpu, PVOID TargetAddress, CR3_TYPE ProcessCr3)
 The main function that performs EPT page hook with hidden breakpoint.
 
BOOLEAN EptHookPerformHook (PVOID TargetAddress, UINT32 ProcessId, BOOLEAN ApplyDirectlyFromVmxRoot)
 This function invokes a VMCALL to set the hook and broadcast the exiting for the breakpoints on exception bitmap.
 
BOOLEAN EptHook (PVOID TargetAddress, UINT32 ProcessId)
 This function invokes a VMCALL to set the hook and broadcast the exiting for the breakpoints on exception bitmap.
 
BOOLEAN EptHookFromVmxRoot (PVOID TargetAddress)
 This function invokes a direct VMCALL to setup the hook.
 
BOOLEAN EptHookRestoreSingleHookToOriginalEntry (VIRTUAL_MACHINE_STATE *VCpu, SIZE_T PhysicalAddress, UINT64 OriginalEntry)
 Remove and Invalidate Hook in TLB (Hidden Detours and if counter of hidden breakpoint is zero)
 
VOID EptHookRestoreAllHooksToOriginalEntry (VIRTUAL_MACHINE_STATE *VCpu)
 Remove and Invalidate Hook in TLB.
 
VOID EptHookWriteAbsoluteJump (PCHAR TargetBuffer, SIZE_T TargetAddress)
 Write an absolute x64 jump to an arbitrary address to a buffer.
 
VOID EptHookWriteAbsoluteJump2 (PCHAR TargetBuffer, SIZE_T TargetAddress)
 Write an absolute x64 jump to an arbitrary address to a buffer.
 
BOOLEAN EptHookInstructionMemory (PEPT_HOOKED_PAGE_DETAIL Hook, CR3_TYPE ProcessCr3, PVOID TargetFunction, PVOID TargetFunctionInSafeMemory, PVOID HookFunction)
 Hook instructions.
 
BOOLEAN EptHookPerformPageHookMonitorAndInlineHook (VIRTUAL_MACHINE_STATE *VCpu, PVOID HookingDetails, CR3_TYPE ProcessCr3, UINT32 PageHookMask)
 The main function that performs EPT page hook with hidden detours and monitor.
 
BOOLEAN EptHookPerformMemoryOrInlineHook (VIRTUAL_MACHINE_STATE *VCpu, EPT_HOOKS_ADDRESS_DETAILS_FOR_EPTHOOK2 *EptHook2AddressDetails, EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *MemoryAddressDetails, UINT32 ProcessId, BOOLEAN EptHiddenHook2, BOOLEAN ApplyDirectlyFromVmxRoot)
 This function allocates a buffer in VMX Non Root Mode and then invokes a VMCALL to set the hook.
 
BOOLEAN EptHookInlineHook (VIRTUAL_MACHINE_STATE *VCpu, PVOID TargetAddress, PVOID HookFunction, UINT32 ProcessId)
 This function applies EPT hook 2 (inline) to the target EPT table.
 
BOOLEAN EptHookMonitorHook (VIRTUAL_MACHINE_STATE *VCpu, EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *HookingDetails, UINT32 ProcessId)
 This function applies monitor hooks to the target EPT table.
 
BOOLEAN EptHookInlineHookFromVmxRoot (VIRTUAL_MACHINE_STATE *VCpu, PVOID TargetAddress, PVOID HookFunction)
 This function applies EPT inline to the target EPT table.
 
BOOLEAN EptHookMonitorFromVmxRoot (VIRTUAL_MACHINE_STATE *VCpu, EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *MemoryAddressDetails)
 This function applies EPT monitor hooks to the target EPT table.
 
BOOLEAN EptHookHandleHookedPage (VIRTUAL_MACHINE_STATE *VCpu, EPT_HOOKED_PAGE_DETAIL *HookedEntryDetails, VMX_EXIT_QUALIFICATION_EPT_VIOLATION ViolationQualification, SIZE_T PhysicalAddress, EPT_HOOKS_CONTEXT *LastContext, BOOLEAN *IgnoreReadOrWriteOrExec, BOOLEAN *IsExecViolation)
 Handles page hooks (trigger events)
 
BOOLEAN EptHookRemoveEntryAndFreePoolFromEptHook2sDetourList (UINT64 Address)
 Remove the entry from g_EptHook2sDetourListHead in the case of !epthook2 details.
 
UINT32 EptHookGetCountOfEpthooks (BOOLEAN IsEptHook2)
 get the length of active EPT hooks (!epthook and !epthook2)
 
BOOLEAN EptHookUnHookSingleAddressDetoursAndMonitor (PEPT_HOOKED_PAGE_DETAIL HookedEntry, BOOLEAN ApplyDirectlyFromVmxRoot, EPT_SINGLE_HOOK_UNHOOKING_DETAILS *TargetUnhookingDetails)
 Remove single hook of detours type.
 
VOID EptHookHandleMonitorTrapFlag (VIRTUAL_MACHINE_STATE *VCpu)
 Handle vm-exits for Monitor Trap Flag to restore previous state.
 
BOOLEAN EptHookUnHookSingleAddressHiddenBreakpoint (PEPT_HOOKED_PAGE_DETAIL HookedEntry, UINT64 VirtualAddress, BOOLEAN ApplyDirectlyFromVmxRoot, EPT_SINGLE_HOOK_UNHOOKING_DETAILS *TargetUnhookingDetails)
 Remove single hook of hidden breakpoint type.
 
BOOLEAN EptHookPerformUnHookSingleAddress (UINT64 VirtualAddress, UINT64 PhysAddress, UINT64 HookingTag, UINT32 ProcessId, BOOLEAN ApplyDirectlyFromVmxRoot, EPT_SINGLE_HOOK_UNHOOKING_DETAILS *TargetUnhookingDetails)
 Remove single hook from the hooked pages list and invalidate TLB.
 
BOOLEAN EptHookUnHookAllByHookingTag (UINT64 HookingTag)
 Remove all hooks from the hooked pages by the given hooking tag.
 
BOOLEAN EptHookUnHookSingleHookByHookingTagFromVmxRoot (UINT64 HookingTag, EPT_SINGLE_HOOK_UNHOOKING_DETAILS *TargetUnhookingDetails)
 Remove single hook from the hooked pages by the given hooking tag.
 
BOOLEAN EptHookUnHookSingleAddress (UINT64 VirtualAddress, UINT64 PhysAddress, UINT32 ProcessId)
 Remove single hook from the hooked pages list and invalidate TLB.
 
BOOLEAN EptHookUnHookSingleAddressFromVmxRoot (UINT64 VirtualAddress, UINT64 PhysAddress, EPT_SINGLE_HOOK_UNHOOKING_DETAILS *TargetUnhookingDetails)
 Remove single hook from the hooked pages list and invalidate TLB.
 
VOID EptHookUnHookAll ()
 Remove all hooks from the hooked pages list and invalidate TLB @detailsShould be called from Vmx Non-root.
 
PVOID EptHook2GeneralDetourEventHandler (PGUEST_REGS Regs, PVOID CalledFrom)
 routines to generally handle breakpoint hit for detour
 
BOOLEAN EptHookModifyInstructionFetchState (VIRTUAL_MACHINE_STATE *VCpu, PVOID PhysicalAddress, BOOLEAN IsUnset)
 Change PML EPT state for execution (execute) @detail should be called from VMX-root.
 
BOOLEAN EptHookModifyPageReadState (VIRTUAL_MACHINE_STATE *VCpu, PVOID PhysicalAddress, BOOLEAN IsUnset)
 Change PML EPT state for read @detail should be called from VMX-root.
 
BOOLEAN EptHookModifyPageWriteState (VIRTUAL_MACHINE_STATE *VCpu, PVOID PhysicalAddress, BOOLEAN IsUnset)
 Change PML EPT state for write @detail should be called from VMX-root.
 

Detailed Description

Implementation of different EPT hidden hooks functions.

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

All the R/W hooks, Execute hooks and hardware register simulators are implemented here

Version
0.1
Date
2020-04-11

Function Documentation

◆ _Success_()

_Must_inspect_result_ _Success_ ( return = TRUE)

Check whether the desired PhysicalAddress is already in the g_EptState->HookedPagesList hooks or not.

Parameters
PhysicalBaseAddress
Returns
PEPT_HOOKED_PAGE_DETAIL if the address was already hooked, or FALSE
27{
29 {
30 if (CurrEntity->PhysicalBaseAddress == PhysicalBaseAddress)
31 {
32 return CurrEntity;
33 }
34 }
35
36 return NULL;
37}
EPT_STATE * g_EptState
Save the state and variables related to EPT.
Definition GlobalVariables.h:50
#define LIST_FOR_EACH_LINK(_head, _struct_type, _member, _var)
Definition MetaMacros.h:34
NULL()
Definition test-case-generator.py:530
Structure to save the state of each hooked pages.
Definition State.h:163
LIST_ENTRY HookedPagesList
Definition Ept.h:118

◆ EptHook()

BOOLEAN EptHook ( PVOID TargetAddress,
UINT32 ProcessId )

This function invokes a VMCALL to set the hook and broadcast the exiting for the breakpoints on exception bitmap.

Hook in VMX non-root Mode (hidden breakpoint)

this command uses hidden breakpoints (0xcc) to hook, THIS FUNCTION SHOULD BE CALLED WHEN THE VMLAUNCH ALREADY EXECUTED, it is because, broadcasting to enable exception bitmap for breakpoint is not clear here, if we want to broadcast to enable exception bitmaps on all cores when vmlaunch is not executed then that's ok but a user might call this function when we didn't configure the vmcs, it's a problem! we can solve it by giving a hint to vmcs configure function to make it ok for future configuration but that sounds stupid, I think it's better to not support this feature. Btw, debugger won't use this function in the above mentioned method, so we won't have any problem with this This function should be called from VMX non-root mode

Parameters
TargetAddressThe address of function or memory address to be hooked
ProcessIdThe process id to translate based on that process's cr3
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
606{
607 //
608 // Should be called from vmx non-root
609 //
611 {
612 return FALSE;
613 }
614
615 return EptHookPerformHook(TargetAddress, ProcessId, FALSE);
616}
#define TRUE
Definition BasicTypes.h:55
#define FALSE
Definition BasicTypes.h:54
BOOLEAN EptHookPerformHook(PVOID TargetAddress, UINT32 ProcessId, BOOLEAN ApplyDirectlyFromVmxRoot)
This function invokes a VMCALL to set the hook and broadcast the exiting for the breakpoints on excep...
Definition EptHook.c:533
BOOLEAN VmxGetCurrentExecutionMode()
Check current execution mode (vmx-root and non-root)
Definition Vmx.c:222

◆ EptHook2GeneralDetourEventHandler()

PVOID EptHook2GeneralDetourEventHandler ( PGUEST_REGS Regs,
PVOID CalledFrom )

routines to generally handle breakpoint hit for detour

Parameters
Regs
CalledFrom
Returns
PVOID
2484{
2485 PLIST_ENTRY TempList = 0;
2486 EPT_HOOKS_CONTEXT TempContext = {0};
2487
2488 //
2489 // The RSP register is the at the RCX and we just added (reverse by stack) to it's
2490 // values by the size of the GUEST_REGS
2491 //
2492 Regs->rsp = (UINT64)Regs - sizeof(GUEST_REGS);
2493
2494 //
2495 // test
2496 //
2497
2498 //
2499 // LogInfo("Hidden Hooked function Called with : rcx = 0x%llx , rdx = 0x%llx , r8 = 0x%llx , r9 = 0x%llx",
2500 // Regs->rcx,
2501 // Regs->rdx,
2502 // Regs->r8,
2503 // Regs->r9);
2504 //
2505
2506 //
2507 // Create temporary context
2508 //
2509 TempContext.VirtualAddress = (UINT64)CalledFrom;
2510 TempContext.PhysicalAddress = VirtualAddressToPhysicalAddress(CalledFrom);
2511
2512 //
2513 // Create a temporary VCpu
2514 //
2515 VIRTUAL_MACHINE_STATE * VCpu = &g_GuestState[KeGetCurrentProcessorNumberEx(NULL)];
2516
2517 //
2518 // Set the register for the temporary VCpu
2519 //
2520 VCpu->Regs = Regs;
2521
2522 //
2523 // As the context to event trigger, we send the address of function
2524 // which is current hidden hook is triggered for it
2525 //
2526 DispatchEventHiddenHookExecDetours(VCpu, &TempContext);
2527
2528 //
2529 // Iterate through the list of hooked pages details to find
2530 // and return where want to jump after this functions
2531 //
2532 TempList = &g_EptHook2sDetourListHead;
2533
2534 while (&g_EptHook2sDetourListHead != TempList->Flink)
2535 {
2536 TempList = TempList->Flink;
2537 PHIDDEN_HOOKS_DETOUR_DETAILS CurrentHookedDetails = CONTAINING_RECORD(TempList, HIDDEN_HOOKS_DETOUR_DETAILS, OtherHooksList);
2538
2539 if (CurrentHookedDetails->HookedFunctionAddress == CalledFrom)
2540 {
2541 return CurrentHookedDetails->ReturnAddress;
2542 }
2543 }
2544
2545 //
2546 // If we reach here, means that we didn't find the return address
2547 // that's an error, generally we can't do anything but as the user
2548 // might already cleaned the hook and the structures are removed
2549 // so we just return the original caller address and continue the
2550 // guest normally
2551 //
2552 return CalledFrom;
2553}
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
VOID DispatchEventHiddenHookExecDetours(VIRTUAL_MACHINE_STATE *VCpu, PVOID Context)
Handling debugger functions related to hidden hook exec detours events.
Definition Dispatch.c:984
VIRTUAL_MACHINE_STATE * g_GuestState
Save the state and variables related to virtualization on each to logical core.
Definition GlobalVariables.h:38
LIST_ENTRY g_EptHook2sDetourListHead
List header of hidden hooks detour.
Definition GlobalVariables.h:62
Temporary $context used in some EPT hook commands.
Definition DataTypes.h:320
UINT64 VirtualAddress
Definition DataTypes.h:323
UINT64 PhysicalAddress
Definition DataTypes.h:322
Details of detours style EPT hooks.
Definition Hooks.h:74
PVOID HookedFunctionAddress
Definition Hooks.h:76
PVOID ReturnAddress
Definition Hooks.h:77
The status of each core after and before VMX.
Definition State.h:290
GUEST_REGS * Regs
Definition State.h:305
Definition BasicTypes.h:70
UINT64 rsp
Definition BasicTypes.h:79

◆ EptHookAllocateExtraHookingPagesForMemoryMonitorsAndExecEptHooks()

VOID EptHookAllocateExtraHookingPagesForMemoryMonitorsAndExecEptHooks ( UINT32 Count)

Allocate (reserve) extra pages for storing details of page hooks for memory monitor and regular hidden breakpoit exec EPT hooks.

Parameters
Count
Returns
VOID
111{
112 ULONG ProcessorsCount;
113
114 //
115 // Get number of processors
116 //
117 ProcessorsCount = KeQueryActiveProcessorCount(0);
118
119 //
120 // Request pages to be allocated for converting 2MB to 4KB pages
121 // Each core needs its own splitting page-tables
122 //
124 Count * ProcessorsCount,
126
127 //
128 // Request pages to be allocated for paged hook details
129 //
131 Count,
133}
unsigned long ULONG
Definition BasicTypes.h:37
@ SPLIT_2MB_PAGING_TO_4KB_PAGE
Definition DataTypes.h:43
@ TRACKING_HOOKED_PAGES
Definition DataTypes.h:41
BOOLEAN PoolManagerRequestAllocation(SIZE_T Size, UINT32 Count, POOL_ALLOCATION_INTENTION Intention)
Request to allocate new buffers.
Definition PoolManager.c:415
Split 2MB granularity to 4 KB granularity.
Definition Ept.h:135

◆ EptHookFromVmxRoot()

BOOLEAN EptHookFromVmxRoot ( PVOID TargetAddress)

This function invokes a direct VMCALL to setup the hook.

the caller of this function should make sure to 1) broadcast to all cores to intercept breakpoints (#BPs) and after calling this function 2) the caller should broadcast to all cores to invalidate their EPTPs This function should be called from VMX root-mode

Parameters
TargetAddressThe address of function or memory address to be hooked
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
632{
633 //
634 // Should be called from VMX root-mode
635 //
637 {
638 return FALSE;
639 }
640
641 return EptHookPerformHook(TargetAddress, NULL_ZERO, TRUE);
642}
#define NULL_ZERO
Definition BasicTypes.h:51

◆ EptHookGetCountOfEpthooks()

UINT32 EptHookGetCountOfEpthooks ( BOOLEAN IsEptHook2)

get the length of active EPT hooks (!epthook and !epthook2)

Parameters
IsEptHook2Whether the length should be for !epthook or !epthook2
Returns
UINT32 Count of remained breakpoints
1866{
1867 UINT32 Count = 0;
1868
1870 {
1871 if (IsEptHook2)
1872 {
1873 if (HookedEntry->IsHiddenBreakpoint == FALSE)
1874 {
1875 Count++;
1876 }
1877 }
1878 else
1879 {
1880 if (HookedEntry->IsHiddenBreakpoint == TRUE)
1881 {
1882 Count++;
1883 }
1884 }
1885 }
1886
1887 return Count;
1888}
unsigned int UINT32
Definition BasicTypes.h:48

◆ EptHookHandleHookedPage()

BOOLEAN EptHookHandleHookedPage ( VIRTUAL_MACHINE_STATE * VCpu,
EPT_HOOKED_PAGE_DETAIL * HookedEntryDetails,
VMX_EXIT_QUALIFICATION_EPT_VIOLATION ViolationQualification,
SIZE_T PhysicalAddress,
EPT_HOOKS_CONTEXT * LastContext,
BOOLEAN * IgnoreReadOrWriteOrExec,
BOOLEAN * IsExecViolation )

Handles page hooks (trigger events)

Handle hooked pages in Vmx-root mode.

Parameters
VCpuThe virtual processor's state
HookedEntryDetailsThe entry that describes the hooked page
ViolationQualificationThe exit qualification of vm-exit
PhysicalAddressThe physical address that cause this vm-exit
LastContextThe last (current) context of the execution
IgnoreReadOrWriteOrExecWhether to ignore the event effects or not
IsExecViolationWhether it's execution violation or not executing the post triggering of the event or not
Returns
BOOLEAN Returns TRUE if the function was hook was handled or returns false if there was an unexpected ept violation
1693{
1694 UINT64 ExactAccessedVirtualAddress;
1695 UINT64 AlignedVirtualAddress;
1696 UINT64 AlignedPhysicalAddress;
1697 BOOLEAN IsTriggeringPostEventAllowed = FALSE;
1698
1699 //
1700 // Get alignment
1701 //
1702 AlignedVirtualAddress = (UINT64)PAGE_ALIGN(HookedEntryDetails->VirtualAddress);
1703 AlignedPhysicalAddress = (UINT64)PAGE_ALIGN(PhysicalAddress);
1704
1705 //
1706 // Let's read the exact address that was accessed
1707 //
1708 ExactAccessedVirtualAddress = AlignedVirtualAddress + PhysicalAddress - AlignedPhysicalAddress;
1709
1710 //
1711 // Set the last context
1712 //
1713 LastContext->HookingTag = HookedEntryDetails->HookingTag;
1714 LastContext->PhysicalAddress = PhysicalAddress;
1715 LastContext->VirtualAddress = ExactAccessedVirtualAddress;
1716
1717 if (!ViolationQualification.EptReadable && ViolationQualification.ReadAccess)
1718 {
1719 //
1720 // LogInfo("Guest RIP : 0x%llx tries to read the page at : 0x%llx", GuestRip, ExactAccessedAddress);
1721 //
1722
1723 //
1724 // Set last violation
1725 //
1726 HookedEntryDetails->LastViolation = EPT_HOOKED_LAST_VIOLATION_READ;
1727
1728 //
1729 // Trigger the event related to Monitor Read and Monitor Read & Write and
1730 // Monitor Read & Execute and Monitor Read & Write & Execute
1731 //
1732 *IgnoreReadOrWriteOrExec = DispatchEventHiddenHookPageReadWriteExecuteReadPreEvent(VCpu, LastContext, &IsTriggeringPostEventAllowed);
1733
1734 //
1735 // It's not an execution violation
1736 //
1737 *IsExecViolation = FALSE;
1738 }
1739 else if (!ViolationQualification.EptWriteable && ViolationQualification.WriteAccess)
1740 {
1741 //
1742 // LogInfo("Guest RIP : 0x%llx tries to write on the page at : 0x%llx", GuestRip, ExactAccessedAddress);
1743 //
1744
1745 //
1746 // Set last violation
1747 //
1748 HookedEntryDetails->LastViolation = EPT_HOOKED_LAST_VIOLATION_WRITE;
1749
1750 //
1751 // Trigger the event related to Monitor Write and Monitor Read & Write and
1752 // Monitor Write & Execute and Monitor Read & Write & Execute
1753 //
1754 *IgnoreReadOrWriteOrExec = DispatchEventHiddenHookPageReadWriteExecuteWritePreEvent(VCpu, LastContext, &IsTriggeringPostEventAllowed);
1755
1756 //
1757 // It's not an execution violation
1758 //
1759 *IsExecViolation = FALSE;
1760 }
1761 else if (!ViolationQualification.EptExecutable && ViolationQualification.ExecuteAccess)
1762 {
1763 //
1764 // LogInfo("Guest RIP : 0x%llx tries to execute the page at : 0x%llx", GuestRip, ExactAccessedAddress);
1765 //
1766
1767 //
1768 // Set last violation
1769 //
1770 HookedEntryDetails->LastViolation = EPT_HOOKED_LAST_VIOLATION_EXEC;
1771
1772 //
1773 // Trigger the event related to Monitor Execute and Monitor Read & Execute and
1774 // Monitor Write & Execute and Monitor Read & Write & Execute
1775 //
1776 *IgnoreReadOrWriteOrExec = DispatchEventHiddenHookPageReadWriteExecuteExecutePreEvent(VCpu, LastContext, &IsTriggeringPostEventAllowed);
1777
1778 //
1779 // It's an execution violation
1780 //
1781 *IsExecViolation = TRUE;
1782 }
1783 else
1784 {
1785 //
1786 // triggering post event is not allowed as it's not valid
1787 //
1788 HookedEntryDetails->IsPostEventTriggerAllowed = FALSE;
1789
1790 //
1791 // there was an unexpected ept violation
1792 //
1793 return FALSE;
1794 }
1795
1796 //
1797 // Set whether the post event trigger is allowed or not
1798 // If only one event short-circuit a special EPT hook the 'post' mode will be ignored for all of the same events
1799 //
1800 if (*IgnoreReadOrWriteOrExec == FALSE)
1801 {
1802 HookedEntryDetails->IsPostEventTriggerAllowed = IsTriggeringPostEventAllowed;
1803 }
1804 else
1805 {
1806 //
1807 // Ignoring read/write/exec will remove the 'post' event
1808 //
1809 HookedEntryDetails->IsPostEventTriggerAllowed = FALSE;
1810 }
1811
1812 //
1813 // Means that restore the Entry to the previous state after current
1814 // instruction executed in the guest
1815 //
1816 return TRUE;
1817}
UCHAR BOOLEAN
Definition BasicTypes.h:39
BOOLEAN DispatchEventHiddenHookPageReadWriteExecuteWritePreEvent(VIRTUAL_MACHINE_STATE *VCpu, PVOID Context, BOOLEAN *IsTriggeringPostEventAllowed)
Handling debugger functions related to read & write & execute, write events (pre)
Definition Dispatch.c:1102
BOOLEAN DispatchEventHiddenHookPageReadWriteExecuteExecutePreEvent(VIRTUAL_MACHINE_STATE *VCpu, PVOID Context, BOOLEAN *IsTriggeringPostEventAllowed)
Handling debugger functions related to read & write & execute, execute events (pre)
Definition Dispatch.c:1196
BOOLEAN DispatchEventHiddenHookPageReadWriteExecuteReadPreEvent(VIRTUAL_MACHINE_STATE *VCpu, PVOID Context, BOOLEAN *IsTriggeringPostEventAllowed)
Handling debugger functions related to read & write & execute, read events (pre)
Definition Dispatch.c:1008
@ EPT_HOOKED_LAST_VIOLATION_READ
Definition State.h:64
@ EPT_HOOKED_LAST_VIOLATION_EXEC
Definition State.h:66
@ EPT_HOOKED_LAST_VIOLATION_WRITE
Definition State.h:65
#define PAGE_ALIGN(Va)
Aligning a page.
Definition common.h:75
UINT64 VirtualAddress
The virtual address from the caller perspective view (cr3)
Definition State.h:175
UINT64 HookingTag
Tag used for notifying the caller.
Definition State.h:202
BOOLEAN IsPostEventTriggerAllowed
This field shows whether the hook should call the post event trigger after restoring the state or not...
Definition State.h:248
EPT_HOOKED_LAST_VIOLATION LastViolation
This field shows the last violation happened to this EPT hook.
Definition State.h:253
UINT64 HookingTag
Definition DataTypes.h:321

◆ EptHookHandleMonitorTrapFlag()

VOID EptHookHandleMonitorTrapFlag ( VIRTUAL_MACHINE_STATE * VCpu)

Handle vm-exits for Monitor Trap Flag to restore previous state.

Parameters
VCpuThe virtual processor's state
Returns
VOID
1964{
1965 PVOID TargetPage;
1966 //
1967 // Pointer to the page entry in the page table
1968 //
1970
1971 //
1972 // restore the hooked state
1973 //
1975 TargetPage,
1977 InveptSingleContext);
1978
1979 //
1980 // Check to trigger the post event (for events relating the !monitor command
1981 // and the emulation hardware debug registers)
1982 //
1984 {
1986 {
1987 //
1988 // This is a "read" hook
1989 //
1992 }
1994 {
1995 //
1996 // This is a "write" hook
1997 //
2000 }
2002 {
2003 //
2004 // This is a "execute" hook
2005 //
2008 }
2009 }
2010
2011 //
2012 // Check for user-mode attaching mechanisms and callback
2013 // (we call it here, because this callback might change the EPTP entries and invalidate EPTP)
2014 //
2016}
BOOLEAN VmmCallbackRestoreEptState(UINT32 CoreId)
routine callback to restore EPT state
Definition Callback.c:294
VOID DispatchEventHiddenHookPageReadWriteExecReadPostEvent(VIRTUAL_MACHINE_STATE *VCpu, PVOID Context)
Handling debugger functions related to read & write & execute, read events (post)
Definition Dispatch.c:1289
VOID DispatchEventHiddenHookPageReadWriteExecWritePostEvent(VIRTUAL_MACHINE_STATE *VCpu, PVOID Context)
Handling debugger functions related to read & write & execute, write events (post)
Definition Dispatch.c:1336
VOID DispatchEventHiddenHookPageReadWriteExecExecutePostEvent(VIRTUAL_MACHINE_STATE *VCpu, PVOID Context)
Handling debugger functions related to read & write & execute, execute events (post)
Definition Dispatch.c:1381
PEPT_PML1_ENTRY EptGetPml1Entry(PVMM_EPT_PAGE_TABLE EptPageTable, SIZE_T PhysicalAddress)
Get the PML1 entry for this physical address if the page is split.
Definition Ept.c:304
_Use_decl_annotations_ VOID EptSetPML1AndInvalidateTLB(VIRTUAL_MACHINE_STATE *VCpu, PEPT_PML1_ENTRY EntryAddress, EPT_PML1_ENTRY EntryValue, INVEPT_TYPE InvalidationType)
This function set the specific PML1 entry in a spinlock protected area then invalidate the TLB.
Definition Ept.c:1075
EPT_HOOKS_CONTEXT LastContextState
Temporary context for the post event monitors It shows the context of the last address that triggered...
Definition State.h:242
EPT_PML1_ENTRY ChangedEntry
The original page entry. Will be copied back when the hook is remove from the page.
Definition State.h:219
SIZE_T PhysicalBaseAddress
The base address of the page. Used to find this structure in the list of page hooks when a hook is hi...
Definition State.h:187
PVMM_EPT_PAGE_TABLE EptPageTable
Definition State.h:342
PEPT_HOOKED_PAGE_DETAIL MtfEptHookRestorePoint
Definition State.h:331
UINT32 CoreId
Definition State.h:306

◆ EptHookInlineHook()

BOOLEAN EptHookInlineHook ( VIRTUAL_MACHINE_STATE * VCpu,
PVOID TargetAddress,
PVOID HookFunction,
UINT32 ProcessId )

This function applies EPT hook 2 (inline) to the target EPT table.

Hook in VMX non-root mode (hidden detours)

this function should be called from VMX non-root mode

Parameters
VCpuThe virtual processor's state
TargetAddressThe address of function or memory address to be hooked
HookFunctionThe function that will be called when hook triggered
ProcessIdThe process id to translate based on that process's cr3
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
1546{
1547 EPT_HOOKS_ADDRESS_DETAILS_FOR_EPTHOOK2 HookingDetail = {0};
1548
1549 //
1550 // Should be called from vmx non-root
1551 //
1553 {
1554 return FALSE;
1555 }
1556
1557 //
1558 // Set the hooking details
1559 //
1560 HookingDetail.TargetAddress = TargetAddress;
1561 HookingDetail.HookFunction = HookFunction;
1562
1564 &HookingDetail,
1565 NULL,
1566 ProcessId,
1567 TRUE,
1568 FALSE);
1569}
BOOLEAN EptHookPerformMemoryOrInlineHook(VIRTUAL_MACHINE_STATE *VCpu, EPT_HOOKS_ADDRESS_DETAILS_FOR_EPTHOOK2 *EptHook2AddressDetails, EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *MemoryAddressDetails, UINT32 ProcessId, BOOLEAN EptHiddenHook2, BOOLEAN ApplyDirectlyFromVmxRoot)
This function allocates a buffer in VMX Non Root Mode and then invokes a VMCALL to set the hook.
Definition EptHook.c:1370
Setting details for EPT Hooks (!epthook2)
Definition DataTypes.h:347
PVOID HookFunction
Definition DataTypes.h:349
PVOID TargetAddress
Definition DataTypes.h:348

◆ EptHookInlineHookFromVmxRoot()

BOOLEAN EptHookInlineHookFromVmxRoot ( VIRTUAL_MACHINE_STATE * VCpu,
PVOID TargetAddress,
PVOID HookFunction )

This function applies EPT inline to the target EPT table.

Hook in VMX root-mode (hidden detours)

this function should be called from VMX root-mode

Parameters
VCpuThe virtual processor's state
TargetAddressThe address of function or memory address to be hooked
HookFunctionThe function that will be called when hook triggered
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
1616{
1617 EPT_HOOKS_ADDRESS_DETAILS_FOR_EPTHOOK2 HookingDetail = {0};
1618
1619 //
1620 // Should be called from vmx root-mode
1621 //
1623 {
1624 return FALSE;
1625 }
1626
1627 //
1628 // Configure the details
1629 //
1630 HookingDetail.TargetAddress = TargetAddress;
1631 HookingDetail.HookFunction = HookFunction;
1632
1634 &HookingDetail,
1635 NULL,
1636 NULL_ZERO,
1637 TRUE,
1638 TRUE);
1639}

◆ EptHookInstructionMemory()

BOOLEAN EptHookInstructionMemory ( PEPT_HOOKED_PAGE_DETAIL Hook,
CR3_TYPE ProcessCr3,
PVOID TargetFunction,
PVOID TargetFunctionInSafeMemory,
PVOID HookFunction )

Hook instructions.

Parameters
HookThe details of hooked pages
ProcessCr3The target Process CR3
TargetFunctionTarget function that needs to be hooked
TargetFunctionInSafeMemoryTarget content in the safe memory (used in Length Disassembler Engine)
HookFunctionThe function that will be called when hook triggered
Returns
BOOLEAN Returns true if the hook was successful or returns false if it was not successful
839{
840 PHIDDEN_HOOKS_DETOUR_DETAILS DetourHookDetails;
841 SIZE_T SizeOfHookedInstructions;
842 SIZE_T OffsetIntoPage;
843 CR3_TYPE Cr3OfCurrentProcess;
844
845 OffsetIntoPage = ADDRMASK_EPT_PML1_OFFSET((SIZE_T)TargetFunction);
846
847 //
848 // Log offset
849 //
850 // LogInfo("OffsetIntoPage: 0x%llx", OffsetIntoPage);
851 //
852
853 if ((OffsetIntoPage + 19) > PAGE_SIZE - 1)
854 {
855 LogError("Err, function extends past a page boundary");
856 return FALSE;
857 }
858
859 //
860 // Determine the number of instructions necessary to overwrite using Length Disassembler Engine
861 // EPTHOOK2 only supports 64-bit kernel (32-bit LDE is not supported)
862 //
863 for (SizeOfHookedInstructions = 0;
864 SizeOfHookedInstructions < 19;
866 (PVOID)((UINT64)TargetFunctionInSafeMemory + SizeOfHookedInstructions),
867 FALSE))
868 {
869 //
870 // Get the full size of instructions necessary to copy
871 //
872 }
873
874 // for (SizeOfHookedInstructions = 0;
875 // SizeOfHookedInstructions < 19;
876 // SizeOfHookedInstructions += ZydisLde(((UINT64)TargetFunctionInSafeMemory + SizeOfHookedInstructions), TRUE))
877 //{
878 // //
879 // // Get the full size of instructions necessary to copy
880 // //
881 // }
882
883 //
884 // For logging purpose
885 //
886 // LogInfo("Number of bytes of instruction mem: %x", SizeOfHookedInstructions);
887
888 //
889 // Build a trampoline
890 //
891
892 //
893 // Allocate some executable memory for the trampoline
894 //
896
897 if (!Hook->Trampoline)
898 {
899 LogError("Err, could not allocate trampoline function buffer");
900 return FALSE;
901 }
902
903 //
904 // Copy the trampoline instructions in
905 //
906
907 // Switch to target process
908 //
909 Cr3OfCurrentProcess = SwitchToProcessMemoryLayoutByCr3(ProcessCr3);
910
911 //
912 // The following line can't be used in user mode addresses
913 // RtlCopyMemory(Hook->Trampoline, TargetFunction, SizeOfHookedInstructions);
914 //
915 MemoryMapperReadMemorySafe((UINT64)TargetFunction, Hook->Trampoline, SizeOfHookedInstructions);
916
917 //
918 // Restore to original process
919 //
920 SwitchToPreviousProcess(Cr3OfCurrentProcess);
921
922 //
923 // Add the absolute jump back to the original function
924 //
925 EptHookWriteAbsoluteJump2(&Hook->Trampoline[SizeOfHookedInstructions], (SIZE_T)TargetFunction + SizeOfHookedInstructions);
926
927 //
928 //
929 //
930 // LogInfo("Trampoline: 0x%llx", Hook->Trampoline);
931 // LogInfo("HookFunction: 0x%llx", HookFunction);
932
933 //
934 // Let the hook function call the original function
935 //
936 // *OrigFunction = Hook->Trampoline;
937 //
938
939 //
940 // Create the structure to return for the debugger, we do it here because it's the first
941 // function that changes the original function and if our structure is no ready after this
942 // function then we probably see BSOD on other cores
943 //
945 DetourHookDetails->HookedFunctionAddress = TargetFunction;
946 DetourHookDetails->ReturnAddress = Hook->Trampoline;
947
948 //
949 // Save the address of DetourHookDetails because we want to
950 // deallocate it when the hook is finished
951 //
952 Hook->AddressOfEptHook2sDetourListEntry = (UINT64)DetourHookDetails;
953
954 //
955 // Insert it to the list of hooked pages
956 //
958
959 //
960 // Write the absolute jump to our shadow page memory to jump to our hook
961 //
962 EptHookWriteAbsoluteJump(&Hook->FakePageContents[OffsetIntoPage], (SIZE_T)HookFunction);
963
964 return TRUE;
965}
char CHAR
Definition BasicTypes.h:31
@ EXEC_TRAMPOLINE
Definition DataTypes.h:42
@ DETOUR_HOOK_DETAILS
Definition DataTypes.h:44
UINT32 DisassemblerLengthDisassembleEngineInVmxRootOnTargetProcess(PVOID Address, BOOLEAN Is32Bit)
Disassembler length disassembler engine.
Definition Disassembler.c:297
#define ADDRMASK_EPT_PML1_OFFSET(_VAR_)
Offset into the 1st paging structure (4096 byte)
Definition Ept.h:37
VOID EptHookWriteAbsoluteJump(PCHAR TargetBuffer, SIZE_T TargetAddress)
Write an absolute x64 jump to an arbitrary address to a buffer.
Definition EptHook.c:743
VOID EptHookWriteAbsoluteJump2(PCHAR TargetBuffer, SIZE_T TargetAddress)
Write an absolute x64 jump to an arbitrary address to a buffer.
Definition EptHook.c:792
#define MAX_EXEC_TRAMPOLINE_SIZE
Maximum number of supported execution trampoline.
Definition Hooks.h:174
#define LogError(format,...)
Log in the case of error.
Definition HyperDbgHyperLogIntrinsics.h:113
_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
UINT64 PoolManagerRequestPool(POOL_ALLOCATION_INTENTION Intention, BOOLEAN RequestNewPool, UINT32 Size)
This function should be called from vmx-root in order to get a pool from the list.
Definition PoolManager.c:212
_Use_decl_annotations_ VOID SwitchToPreviousProcess(CR3_TYPE PreviousProcess)
Switch to previous process's cr3.
Definition SwitchLayout.c:125
_Use_decl_annotations_ CR3_TYPE SwitchToProcessMemoryLayoutByCr3(CR3_TYPE TargetCr3)
Switch to another process's cr3.
Definition SwitchLayout.c:99
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ PLIST_ENTRY Entry)
Definition Windows.h:115
#define PAGE_SIZE
Size of each page (4096 bytes)
Definition common.h:69
CR3 Structure.
Definition BasicTypes.h:130
UINT64 AddressOfEptHook2sDetourListEntry
The virtual address of it's entry on g_EptHook2sDetourListHead this way we can de-allocate the list w...
Definition State.h:181
CHAR FakePageContents[PAGE_SIZE]
Definition State.h:165
PCHAR Trampoline
The buffer of the trampoline function which is used in the inline hook.
Definition State.h:224
LIST_ENTRY OtherHooksList
Definition Hooks.h:75

◆ EptHookModifyInstructionFetchState()

BOOLEAN EptHookModifyInstructionFetchState ( VIRTUAL_MACHINE_STATE * VCpu,
PVOID PhysicalAddress,
BOOLEAN IsUnset )

Change PML EPT state for execution (execute) @detail should be called from VMX-root.

Parameters
VCpuThe virtual processor's state
PhysicalAddressTarget physical address
IsUnsetIs unsetting bit or setting bit
Returns
BOOLEAN
2569{
2570 PVOID PmlEntry = NULL;
2571 BOOLEAN IsLargePage = FALSE;
2572
2573 PmlEntry = EptGetPml1OrPml2Entry(g_EptState->EptPageTable, (SIZE_T)PhysicalAddress, &IsLargePage);
2574
2575 if (PmlEntry)
2576 {
2577 if (IsLargePage)
2578 {
2579 if (IsUnset)
2580 {
2581 ((PEPT_PML2_ENTRY)PmlEntry)->ExecuteAccess = FALSE;
2582 }
2583 else
2584 {
2585 ((PEPT_PML2_ENTRY)PmlEntry)->ExecuteAccess = TRUE;
2586 }
2587 }
2588 else
2589 {
2590 if (IsUnset)
2591 {
2592 ((PEPT_PML1_ENTRY)PmlEntry)->ExecuteAccess = FALSE;
2593 }
2594 else
2595 {
2596 ((PEPT_PML1_ENTRY)PmlEntry)->ExecuteAccess = TRUE;
2597 }
2598 }
2599 }
2600 else
2601 {
2602 return FALSE;
2603 }
2604
2605 //
2606 // Invalidate the EPTP (single-context)
2607 //
2608 EptInveptSingleContext(VCpu->EptPointer.AsUInt);
2609
2610 return TRUE;
2611}
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
UCHAR EptInveptSingleContext(_In_ UINT64 EptPointer)
Invalidates a single context in ept cache table.
Definition Invept.c:40
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 Ept.h:121
EPT_POINTER EptPointer
Definition State.h:341

◆ EptHookModifyPageReadState()

BOOLEAN EptHookModifyPageReadState ( VIRTUAL_MACHINE_STATE * VCpu,
PVOID PhysicalAddress,
BOOLEAN IsUnset )

Change PML EPT state for read @detail should be called from VMX-root.

Parameters
VCpuThe virtual processor's state
PhysicalAddressTarget physical address
IsUnsetIs unsetting bit or setting bit
Returns
BOOLEAN
2627{
2628 PVOID PmlEntry = NULL;
2629 BOOLEAN IsLargePage = FALSE;
2630
2631 PmlEntry = EptGetPml1OrPml2Entry(g_EptState->EptPageTable, (SIZE_T)PhysicalAddress, &IsLargePage);
2632
2633 if (PmlEntry)
2634 {
2635 if (IsLargePage)
2636 {
2637 if (IsUnset)
2638 {
2639 ((PEPT_PML2_ENTRY)PmlEntry)->ReadAccess = FALSE;
2640 }
2641 else
2642 {
2643 ((PEPT_PML2_ENTRY)PmlEntry)->ReadAccess = TRUE;
2644 }
2645 }
2646 else
2647 {
2648 if (IsUnset)
2649 {
2650 ((PEPT_PML1_ENTRY)PmlEntry)->ReadAccess = FALSE;
2651 }
2652 else
2653 {
2654 ((PEPT_PML1_ENTRY)PmlEntry)->ReadAccess = TRUE;
2655 }
2656 }
2657 }
2658 else
2659 {
2660 return FALSE;
2661 }
2662
2663 //
2664 // Invalidate the EPTP (single-context)
2665 //
2666 EptInveptSingleContext(VCpu->EptPointer.AsUInt);
2667
2668 return TRUE;
2669}

◆ EptHookModifyPageWriteState()

BOOLEAN EptHookModifyPageWriteState ( VIRTUAL_MACHINE_STATE * VCpu,
PVOID PhysicalAddress,
BOOLEAN IsUnset )

Change PML EPT state for write @detail should be called from VMX-root.

Parameters
VCpuThe virtual processor's state
PhysicalAddressTarget physical address
IsUnsetIs unsetting bit or setting bit
Returns
BOOLEAN
2685{
2686 PVOID PmlEntry = NULL;
2687 BOOLEAN IsLargePage = FALSE;
2688
2689 PmlEntry = EptGetPml1OrPml2Entry(g_EptState->EptPageTable, (SIZE_T)PhysicalAddress, &IsLargePage);
2690
2691 if (PmlEntry)
2692 {
2693 if (IsLargePage)
2694 {
2695 if (IsUnset)
2696 {
2697 ((PEPT_PML2_ENTRY)PmlEntry)->WriteAccess = FALSE;
2698 }
2699 else
2700 {
2701 ((PEPT_PML2_ENTRY)PmlEntry)->WriteAccess = TRUE;
2702 }
2703 }
2704 else
2705 {
2706 if (IsUnset)
2707 {
2708 ((PEPT_PML1_ENTRY)PmlEntry)->WriteAccess = FALSE;
2709 }
2710 else
2711 {
2712 ((PEPT_PML1_ENTRY)PmlEntry)->WriteAccess = TRUE;
2713 }
2714 }
2715 }
2716 else
2717 {
2718 return FALSE;
2719 }
2720
2721 //
2722 // Invalidate the EPTP (single-context)
2723 //
2724 EptInveptSingleContext(VCpu->EptPointer.AsUInt);
2725
2726 return TRUE;
2727}

◆ EptHookMonitorFromVmxRoot()

BOOLEAN EptHookMonitorFromVmxRoot ( VIRTUAL_MACHINE_STATE * VCpu,
EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR * MemoryAddressDetails )

This function applies EPT monitor hooks to the target EPT table.

this function should be called from VMX root-mode

Parameters
VCpuThe virtual processor's state
MemoryAddressDetailsdetails of the target memory
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
1653{
1654 //
1655 // Should be called from vmx root-mode
1656 //
1658 {
1659 return FALSE;
1660 }
1661
1663 NULL,
1664 MemoryAddressDetails,
1665 NULL_ZERO,
1666 FALSE,
1667 TRUE);
1668}

◆ EptHookMonitorHook()

BOOLEAN EptHookMonitorHook ( VIRTUAL_MACHINE_STATE * VCpu,
EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR * HookingDetails,
UINT32 ProcessId )

This function applies monitor hooks to the target EPT table.

this function should be called from VMX non-root mode

Parameters
VCpuThe virtual processor's state
HookingDetailsMonitor hooking details
ProcessIdThe process id to translate based on that process's cr3
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
1585{
1586 //
1587 // Should be called from vmx non-root
1588 //
1590 {
1591 return FALSE;
1592 }
1593
1595 NULL,
1596 HookingDetails,
1597 ProcessId,
1598 FALSE,
1599 FALSE);
1600}

◆ EptHookPerformHook()

BOOLEAN EptHookPerformHook ( PVOID TargetAddress,
UINT32 ProcessId,
BOOLEAN ApplyDirectlyFromVmxRoot )

This function invokes a VMCALL to set the hook and broadcast the exiting for the breakpoints on exception bitmap.

Parameters
TargetAddressThe address of function or memory address to be hooked
ProcessIdThe process id to translate based on that process's cr3
ApplyDirectlyFromVmxRootshould it be directly applied from VMX-root mode or not
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
536{
537 if (ApplyDirectlyFromVmxRoot)
538 {
539 DIRECT_VMCALL_PARAMETERS DirectVmcallOptions = {0};
540
541 //
542 // Set VMCALL options
543 //
544 DirectVmcallOptions.OptionalParam1 = (UINT64)TargetAddress;
545 DirectVmcallOptions.OptionalParam2 = LayoutGetCurrentProcessCr3().Flags;
546
547 //
548 // Perform the direct VMCALL
549 //
550 if (DirectVmcallSetHiddenBreakpointHook(KeGetCurrentProcessorNumberEx(NULL), &DirectVmcallOptions) == STATUS_SUCCESS)
551 {
552 LogDebugInfo("Hidden breakpoint hook applied from VMX Root Mode");
553
554 return TRUE;
555 }
556 }
557 else
558 {
559 //
560 // Broadcast to all cores to enable vm-exit for breakpoints (exception bitmaps)
561 //
563
565 (UINT64)TargetAddress,
566 LayoutGetCr3ByProcessId(ProcessId).Flags,
567 (UINT64)NULL64_ZERO) == STATUS_SUCCESS)
568 {
569 LogDebugInfo("Hidden breakpoint hook applied from VMX Root Mode");
570
571 //
572 // Now we have to notify all the core to invalidate their EPT
573 //
575
576 return TRUE;
577 }
578 }
579
580 //
581 // sth went wrong as we're here
582 //
583 return FALSE;
584}
#define NULL64_ZERO
Definition BasicTypes.h:52
VOID BroadcastNotifyAllToInvalidateEptAllCores()
routines to notify to invalidate their ept on all cores
Definition Broadcast.c:119
VOID BroadcastEnableBreakpointExitingOnExceptionBitmapAllCores()
routines to enable vm-exit for breakpoints (exception bitmap)
Definition Broadcast.c:63
NTSTATUS DirectVmcallSetHiddenBreakpointHook(UINT32 CoreId, DIRECT_VMCALL_PARAMETERS *DirectVmcallOptions)
routines for putting hidden breakpoints (using EPT)
Definition DirectVmcall.c:255
#define LogDebugInfo(format,...)
Log, initialize boot information and debug information.
Definition HyperDbgHyperLogIntrinsics.h:155
NTSTATUS AsmVmxVmcall(unsigned long long VmcallNumber, unsigned long long OptionalParam1, unsigned long long OptionalParam2, long long OptionalParam3)
Request Vmcall.
_Use_decl_annotations_ CR3_TYPE LayoutGetCr3ByProcessId(UINT32 ProcessId)
Converts pid to kernel cr3.
Definition Layout.c:24
CR3_TYPE LayoutGetCurrentProcessCr3()
Get cr3 of the target running process.
Definition Layout.c:55
#define VMCALL_SET_HIDDEN_CC_BREAKPOINT
VMCALL to put hidden breakpoints (using EPT)
Definition Vmcall.h:124
UINT64 Flags
Definition BasicTypes.h:133
Used for sending direct VMCALLs on the VMX root-mode.
Definition DataTypes.h:294
UINT64 OptionalParam2
Definition DataTypes.h:296
UINT64 OptionalParam1
Definition DataTypes.h:295

◆ EptHookPerformMemoryOrInlineHook()

BOOLEAN EptHookPerformMemoryOrInlineHook ( VIRTUAL_MACHINE_STATE * VCpu,
EPT_HOOKS_ADDRESS_DETAILS_FOR_EPTHOOK2 * EptHook2AddressDetails,
EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR * MemoryAddressDetails,
UINT32 ProcessId,
BOOLEAN EptHiddenHook2,
BOOLEAN ApplyDirectlyFromVmxRoot )

This function allocates a buffer in VMX Non Root Mode and then invokes a VMCALL to set the hook.

this command uses hidden detours, if it calls from VMX root-mode directly, it should also invalidate EPT caches (by the caller)

Parameters
VCpuThe virtual processor's state
EptHook2AddressDetailsThe address details for inline EPT hooks
MemoryAddressDetailsThe address details for monitor EPT hooks
ProcessIdThe process id to translate based on that process's cr3
EptHiddenHook2epthook2 style hook
ApplyDirectlyFromVmxRootshould it be directly applied from VMX-root mode or not
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
1376{
1377 UINT32 PageHookMask = 0;
1378 PVOID HookDetailsToVmcall = NULL;
1379
1380 //
1381 // Check for the features to avoid EPT Violation problems
1382 //
1383 if (MemoryAddressDetails != NULL)
1384 {
1385 HookDetailsToVmcall = MemoryAddressDetails;
1386
1387 if (MemoryAddressDetails->SetHookForExec &&
1389 {
1390 //
1391 // In the current design of hyperdbg we use execute-only pages
1392 // to implement hidden hooks for exec page, so your processor doesn't
1393 // have this feature and you have to implement it in other ways :(
1394 //
1395 return FALSE;
1396 }
1397
1398 if (!MemoryAddressDetails->SetHookForWrite && MemoryAddressDetails->SetHookForRead)
1399 {
1400 //
1401 // The hidden hook with Write Enable and Read Disabled will cause EPT violation!
1402 // fixed
1403 return FALSE;
1404 }
1405
1406 if (MemoryAddressDetails->SetHookForRead)
1407 {
1408 PageHookMask |= PAGE_ATTRIB_READ;
1409 }
1410 if (MemoryAddressDetails->SetHookForWrite)
1411 {
1412 PageHookMask |= PAGE_ATTRIB_WRITE;
1413 }
1414 if (MemoryAddressDetails->SetHookForExec)
1415 {
1416 PageHookMask |= PAGE_ATTRIB_EXEC;
1417 }
1418 }
1419 else if (EptHook2AddressDetails != NULL)
1420 {
1421 HookDetailsToVmcall = EptHook2AddressDetails;
1422
1423 //
1424 // Initialize the list of ept hook detours if it's not already initialized
1425 //
1427 {
1429
1431 }
1432
1433 if (EptHiddenHook2)
1434 {
1435 PageHookMask |= PAGE_ATTRIB_EXEC_HIDDEN_HOOK;
1436 }
1437 }
1438 else
1439 {
1440 //
1441 // No details provided
1442 //
1443 return FALSE;
1444 }
1445
1446 //
1447 // Check if mask is valid or not
1448 //
1449 if (PageHookMask == 0)
1450 {
1451 //
1452 // nothing to hook
1453 //
1454 return FALSE;
1455 }
1456
1457 if (ApplyDirectlyFromVmxRoot)
1458 {
1459 DIRECT_VMCALL_PARAMETERS DirectVmcallOptions = {0};
1460 DirectVmcallOptions.OptionalParam1 = (UINT64)HookDetailsToVmcall;
1461 DirectVmcallOptions.OptionalParam2 = PageHookMask;
1462 DirectVmcallOptions.OptionalParam3 = LayoutGetCurrentProcessCr3().Flags; // Process id is ignored while applied directly
1463
1464 if (DirectVmcallPerformVmcall(VCpu->CoreId, VMCALL_CHANGE_PAGE_ATTRIB, &DirectVmcallOptions) == STATUS_SUCCESS)
1465 {
1466 return TRUE;
1467 }
1468 else
1469 {
1470 return FALSE;
1471 }
1472 }
1473 else
1474 {
1476 {
1478 (UINT64)HookDetailsToVmcall,
1479 PageHookMask,
1480 LayoutGetCr3ByProcessId(ProcessId).Flags) == STATUS_SUCCESS)
1481 {
1482 //
1483 // Test log
1484 //
1485 // LogInfo("Hook applied from VMX Root Mode");
1486 //
1487
1489 {
1490 //
1491 // Now we have to notify all the core to invalidate their EPT
1492 //
1494 }
1495 else
1496 {
1497 LogInfo("Err, unable to notify all cores to invalidate their TLB "
1498 "caches as you called hook on vmx-root mode, however, the "
1499 "hook is still works");
1500 }
1501
1502 return TRUE;
1503 }
1504 else
1505 {
1506 return FALSE;
1507 }
1508 }
1509 else
1510 {
1512 HookDetailsToVmcall,
1513 LayoutGetCr3ByProcessId(ProcessId),
1514 PageHookMask) == TRUE)
1515 {
1516 LogWarning("Hook applied (VM has not launched)");
1517 return TRUE;
1518 }
1519 }
1520 }
1521
1522 //
1523 // There was a error, we shouldn't reach here
1524 //
1525 LogWarning("Err, hook was not applied");
1526
1527 return FALSE;
1528}
NTSTATUS DirectVmcallPerformVmcall(UINT32 CoreId, UINT64 VmcallNumber, DIRECT_VMCALL_PARAMETERS *DirectVmcallOptions)
routines for performing a direct VMCALL
Definition DirectVmcall.c:45
#define PAGE_ATTRIB_EXEC
Definition Ept.h:24
#define PAGE_ATTRIB_READ
Page attributes for internal use.
Definition Ept.h:22
#define PAGE_ATTRIB_EXEC_HIDDEN_HOOK
Definition Ept.h:25
#define PAGE_ATTRIB_WRITE
Definition Ept.h:23
BOOLEAN EptHookPerformPageHookMonitorAndInlineHook(VIRTUAL_MACHINE_STATE *VCpu, PVOID HookingDetails, CR3_TYPE ProcessCr3, UINT32 PageHookMask)
The main function that performs EPT page hook with hidden detours and monitor.
Definition EptHook.c:980
COMPATIBILITY_CHECKS_STATUS g_CompatibilityCheck
Different attributes and compatibility checks of the current processor.
Definition GlobalVariables.h:26
BOOLEAN g_IsEptHook2sDetourListInitialized
List header of hidden hooks detour.
Definition GlobalVariables.h:68
#define LogInfo(format,...)
Define log variables.
Definition HyperDbgHyperLogIntrinsics.h:71
#define LogWarning(format,...)
Log in the case of warning.
Definition HyperDbgHyperLogIntrinsics.h:99
#define VMCALL_CHANGE_PAGE_ATTRIB
VMCALL to Hook Change the attribute bits of the EPT Table.
Definition Vmcall.h:34
BOOLEAN VmxGetCurrentLaunchState()
Check if the VMX is launched or not.
Definition Vmx.c:246
FORCEINLINE VOID InitializeListHead(_Out_ PLIST_ENTRY ListHead)
Definition Windows.h:41
BOOLEAN ExecuteOnlySupport
Definition CompatibilityChecks.h:29
UINT64 OptionalParam3
Definition DataTypes.h:297
BOOLEAN SetHookForRead
Definition DataTypes.h:334
BOOLEAN SetHookForWrite
Definition DataTypes.h:335
BOOLEAN SetHookForExec
Definition DataTypes.h:336

◆ EptHookPerformPageHook()

BOOLEAN EptHookPerformPageHook ( VIRTUAL_MACHINE_STATE * VCpu,
PVOID TargetAddress,
CR3_TYPE ProcessCr3 )

The main function that performs EPT page hook with hidden breakpoint.

Hook in VMX Root Mode with hidden breakpoints (A pre-allocated buffer should be available)

This function returns false in VMX Non-Root Mode if the VM is already initialized This function have to be called through a VMCALL in VMX Root Mode

Parameters
VCpuThe virtual processor's state
TargetAddressThe address of function or memory address to be hooked
ProcessCr3The process cr3 to translate based on that process's cr3
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
477{
478 SIZE_T PhysicalBaseAddress;
479 PVOID VirtualTarget;
480 EPT_HOOKED_PAGE_DETAIL * HookedEntry = NULL;
481
482 //
483 // Translate the page from a physical address to virtual so we can read its memory.
484 // This function will return NULL if the physical address was not already mapped in
485 // virtual memory.
486 //
487 VirtualTarget = PAGE_ALIGN(TargetAddress);
488
489 //
490 // Here we have to change the CR3, it is because we are in SYSTEM process
491 // and if the target address is not mapped in SYSTEM address space (e.g
492 // user mode address of another process) then the translation is invalid
493 //
494
495 //
496 // Find cr3 of target core
497 //
498 PhysicalBaseAddress = (SIZE_T)VirtualAddressToPhysicalAddressByProcessCr3(VirtualTarget, ProcessCr3);
499
500 if (!PhysicalBaseAddress)
501 {
503 return FALSE;
504 }
505
506 //
507 // try to see if we can find the address
508 //
509
510 HookedEntry = EptHookFindByPhysAddress(PhysicalBaseAddress);
511
512 if (HookedEntry != NULL)
513 {
514 return EptHookUpdateHookPage(TargetAddress, HookedEntry);
515 }
516 else
517 {
518 return EptHookCreateHookPage(VCpu, TargetAddress, ProcessCr3);
519 }
520}
VOID VmmCallbackSetLastError(UINT32 LastError)
routine callback to set last error
Definition Callback.c:175
_Use_decl_annotations_ UINT64 VirtualAddressToPhysicalAddressByProcessCr3(PVOID VirtualAddress, CR3_TYPE TargetCr3)
Converts Virtual Address to Physical Address based on a specific process's kernel cr3.
Definition Conversion.c:215
#define DEBUGGER_ERROR_INVALID_ADDRESS
error, invalid address specified for debugger
Definition ErrorCodes.h:63

◆ EptHookPerformPageHookMonitorAndInlineHook()

BOOLEAN EptHookPerformPageHookMonitorAndInlineHook ( VIRTUAL_MACHINE_STATE * VCpu,
PVOID HookingDetails,
CR3_TYPE ProcessCr3,
UINT32 PageHookMask )

The main function that performs EPT page hook with hidden detours and monitor.

Hook in VMX Root Mode with hidden detours and monitor (A pre-allocated buffer should be available)

This function returns false in VMX Non-Root Mode if the VM is already initialized This function have to be called through a VMCALL in VMX Root Mode

Parameters
VCpuThe virtual processor's state
HookingDetailsThe address of function or memory address to be hooked
ProcessCr3The process cr3 to translate based on that process's cr3
PageHookMaskMask hook of the page
Returns
BOOLEAN Returns true if the hook was successful or false if there was an error
984{
985 ULONG ProcessorsCount;
986 EPT_PML1_ENTRY ChangedEntry;
987 SIZE_T PhysicalBaseAddress;
988 PVOID AlignedTargetVaOrPa;
989 PVOID TargetBuffer;
990 PVOID TargetAddress;
991 PVOID HookFunction;
992 UINT64 TargetAddressInSafeMemory;
993 PEPT_PML1_ENTRY TargetPage;
994 PEPT_HOOKED_PAGE_DETAIL HookedPage;
995 CR3_TYPE Cr3OfCurrentProcess;
996 PLIST_ENTRY TempList = 0;
997 PEPT_HOOKED_PAGE_DETAIL HookedEntry = NULL;
998 BOOLEAN UnsetExecute = FALSE;
999 BOOLEAN UnsetRead = FALSE;
1000 BOOLEAN UnsetWrite = FALSE;
1001 BOOLEAN EptHiddenHook = FALSE;
1002
1003 UnsetRead = (PageHookMask & PAGE_ATTRIB_READ) ? TRUE : FALSE;
1004 UnsetWrite = (PageHookMask & PAGE_ATTRIB_WRITE) ? TRUE : FALSE;
1005 UnsetExecute = (PageHookMask & PAGE_ATTRIB_EXEC) ? TRUE : FALSE;
1006 EptHiddenHook = (PageHookMask & PAGE_ATTRIB_EXEC_HIDDEN_HOOK) ? TRUE : FALSE;
1007
1008 //
1009 // Get number of processors
1010 //
1011 ProcessorsCount = KeQueryActiveProcessorCount(0);
1012
1013 //
1014 // Translate the page from a physical address to virtual so we can read its memory.
1015 // This function will return NULL if the physical address was not already mapped in
1016 // virtual memory.
1017 //
1018 if (EptHiddenHook)
1019 {
1020 TargetAddress = ((EPT_HOOKS_ADDRESS_DETAILS_FOR_EPTHOOK2 *)HookingDetails)->TargetAddress;
1021 }
1022 else
1023 {
1024 TargetAddress = (PVOID)((EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *)HookingDetails)->StartAddress;
1025 }
1026
1027 AlignedTargetVaOrPa = PAGE_ALIGN(TargetAddress);
1028
1029 //
1030 // Here we have to change the CR3, it is because we are in SYSTEM process
1031 // and if the target address is not mapped in SYSTEM address space (e.g
1032 // user mode address of another process) then the translation is invalid
1033 //
1034
1035 if (!EptHiddenHook &&
1037 {
1038 //
1039 // The address itself is a physical address, no need for conversion
1040 //
1041 PhysicalBaseAddress = (SIZE_T)AlignedTargetVaOrPa;
1042 }
1043 else
1044 {
1045 //
1046 // based on the CR3 of target core
1047 //
1048 PhysicalBaseAddress = (SIZE_T)VirtualAddressToPhysicalAddressByProcessCr3(AlignedTargetVaOrPa, ProcessCr3);
1049 }
1050
1051 if (!PhysicalBaseAddress)
1052 {
1054 return FALSE;
1055 }
1056
1057 //
1058 // try to see if we can find the address
1059 //
1060 TempList = &g_EptState->HookedPagesList;
1061
1062 while (&g_EptState->HookedPagesList != TempList->Flink)
1063 {
1064 TempList = TempList->Flink;
1065 HookedEntry = CONTAINING_RECORD(TempList, EPT_HOOKED_PAGE_DETAIL, PageHookList);
1066
1067 if (HookedEntry->PhysicalBaseAddress == PhysicalBaseAddress)
1068 {
1069 //
1070 // Means that we find the address and !epthook2 doesn't support
1071 // multiple breakpoints in on page
1072 //
1074 return FALSE;
1075 }
1076 }
1077
1078 //
1079 // Save the detail of hooked page to keep track of it
1080 //
1082
1083 if (!HookedPage)
1084 {
1086 return FALSE;
1087 }
1088
1089 //
1090 // Save the virtual address
1091 //
1092 HookedPage->VirtualAddress = (UINT64)TargetAddress;
1093
1094 //
1095 // Save the physical address
1096 //
1097 HookedPage->PhysicalBaseAddress = PhysicalBaseAddress;
1098
1099 //
1100 // If it's a monitor hook, then we need to hold the address of the start
1101 // physical address as well as the end physical address, plus tagging information
1102 //
1103 if (!EptHiddenHook)
1104 {
1105 //
1106 // Save the target tag
1107 //
1108 HookedPage->HookingTag = ((EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *)HookingDetails)->Tag;
1109
1110 //
1111 // Save the start of the target physical address
1112 //
1114 {
1115 //
1116 // Physical address
1117 //
1118 HookedPage->StartOfTargetPhysicalAddress = (SIZE_T)(((EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *)HookingDetails)->StartAddress);
1119 }
1120 else
1121 {
1122 //
1123 // Virtual address
1124 //
1126 (PVOID)(((EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *)HookingDetails)->StartAddress),
1127 ProcessCr3);
1128 }
1129
1130 if (!HookedPage->StartOfTargetPhysicalAddress)
1131 {
1132 PoolManagerFreePool((UINT64)HookedPage);
1133
1135 return FALSE;
1136 }
1137
1138 //
1139 // Save the end of the target physical address
1140 //
1142 {
1143 //
1144 // Physical address
1145 //
1146 HookedPage->EndOfTargetPhysicalAddress = (SIZE_T)(((EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *)HookingDetails)->EndAddress);
1147 }
1148 else
1149 {
1150 //
1151 // Virtual address
1152 //
1154 (PVOID)(((EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR *)HookingDetails)->EndAddress),
1155 ProcessCr3);
1156 }
1157
1158 if (!HookedPage->EndOfTargetPhysicalAddress)
1159 {
1160 PoolManagerFreePool((UINT64)HookedPage);
1161
1163 return FALSE;
1164 }
1165 }
1166
1167 //
1168 // Fake page content physical address
1169 //
1171
1172 if (EptHiddenHook)
1173 {
1174 //
1175 // Show that entry has hidden hooks for execution
1176 //
1177 HookedPage->IsExecutionHook = TRUE;
1178
1179 //
1180 // Switch to target process
1181 //
1182 Cr3OfCurrentProcess = SwitchToProcessMemoryLayoutByCr3(ProcessCr3);
1183
1184 //
1185 // Copy the content to the fake page
1186 // The following line can't be used in user mode addresses
1187 // RtlCopyBytes(&HookedPage->FakePageContents, VirtualTarget, PAGE_SIZE);
1188 //
1189 MemoryMapperReadMemorySafe((UINT64)AlignedTargetVaOrPa, &HookedPage->FakePageContents, PAGE_SIZE);
1190
1191 //
1192 // Restore to original process
1193 //
1194 SwitchToPreviousProcess(Cr3OfCurrentProcess);
1195
1196 //
1197 // Compute new offset of target offset into a safe bufferr
1198 // It will be used to compute the length of the detours
1199 // address because we might have a user mode code
1200 //
1201 TargetAddressInSafeMemory = EptHookCalcBreakpointOffset(TargetAddress, HookedPage);
1202
1203 //
1204 // Make sure if handler function is valid or if it's default
1205 // then we set it to the default handler
1206 //
1207 if (((EPT_HOOKS_ADDRESS_DETAILS_FOR_EPTHOOK2 *)HookingDetails)->HookFunction == NULL)
1208 {
1209 HookFunction = (PVOID)AsmGeneralDetourHook;
1210 }
1211 else
1212 {
1213 HookFunction = ((EPT_HOOKS_ADDRESS_DETAILS_FOR_EPTHOOK2 *)HookingDetails)->HookFunction;
1214 }
1215
1216 //
1217 // Create Hook
1218 //
1219 if (!EptHookInstructionMemory(HookedPage, ProcessCr3, TargetAddress, (PVOID)TargetAddressInSafeMemory, HookFunction))
1220 {
1221 PoolManagerFreePool((UINT64)HookedPage);
1222
1224 return FALSE;
1225 }
1226 }
1227
1228 for (size_t i = 0; i < ProcessorsCount; i++)
1229 {
1230 //
1231 // Set target buffer, request buffer from pool manager,
1232 // we also need to allocate new page to replace the current page
1233 //
1235
1236 if (!TargetBuffer)
1237 {
1238 PoolManagerFreePool((UINT64)HookedPage);
1239
1241 return FALSE;
1242 }
1243
1244 if (!EptSplitLargePage(g_GuestState[i].EptPageTable, TargetBuffer, PhysicalBaseAddress))
1245 {
1246 PoolManagerFreePool((UINT64)HookedPage);
1247 PoolManagerFreePool((UINT64)TargetBuffer); // Here also other previous pools should be specified, but we forget it for now
1248
1249 LogDebugInfo("Err, could not split page for the address : 0x%llx", PhysicalBaseAddress);
1251 return FALSE;
1252 }
1253
1254 //
1255 // Pointer to the page entry in the page table
1256 //
1257 TargetPage = EptGetPml1Entry(g_GuestState[i].EptPageTable, PhysicalBaseAddress);
1258
1259 //
1260 // Ensure the target is valid
1261 //
1262 if (!TargetPage)
1263 {
1264 PoolManagerFreePool((UINT64)HookedPage);
1265 PoolManagerFreePool((UINT64)TargetBuffer); // Here also other previous pools should be specified, but we forget it for now
1266
1268 return FALSE;
1269 }
1270
1271 //
1272 // Save the original entry (only one of the page tables as the base original entry
1273 // is enough)
1274 //
1275 HookedPage->OriginalEntry = *TargetPage;
1276
1277 //
1278 // Save the original permissions of the page
1279 //
1280 ChangedEntry = *TargetPage;
1281
1282 //
1283 // Execution is treated differently
1284 //
1285 if (UnsetRead)
1286 ChangedEntry.ReadAccess = 0;
1287 else
1288 ChangedEntry.ReadAccess = 1;
1289
1290 if (UnsetWrite)
1291 ChangedEntry.WriteAccess = 0;
1292 else
1293 ChangedEntry.WriteAccess = 1;
1294
1295 if (UnsetExecute)
1296 ChangedEntry.ExecuteAccess = 0;
1297 else
1298 ChangedEntry.ExecuteAccess = 1;
1299
1300 //
1301 // If it's Execution hook then we have to set extra fields
1302 //
1303 if (EptHiddenHook)
1304 {
1305 //
1306 // In execution hook, we have to make sure to unset read, write because
1307 // an EPT violation should occur for these cases and we can swap the original page
1308 //
1309 ChangedEntry.ReadAccess = 0;
1310 ChangedEntry.WriteAccess = 0;
1311 ChangedEntry.ExecuteAccess = 1;
1312
1313 //
1314 // Also set the current pfn to fake page
1315 //
1316 ChangedEntry.PageFrameNumber = HookedPage->PhysicalBaseAddressOfFakePageContents;
1317 }
1318
1319 //
1320 // Only for the first time execution of the loop, we save these details,
1321 // it is because after this condition, the hook is applied and by applying
1322 // the hook, we have to make sure that the address is saved g_EptState->HookedPagesList
1323 // because the hook might be simultaneously triggered from other cores
1324 //
1325 if (i == 0)
1326 {
1327 //
1328 // Save the modified entry
1329 //
1330 HookedPage->ChangedEntry = ChangedEntry;
1331
1332 //
1333 // Add it to the list
1334 //
1336 }
1337
1338 //
1339 // Apply the hook to EPT
1340 //
1341 TargetPage->AsUInt = ChangedEntry.AsUInt;
1342
1343 //
1344 // If it's the current core then we invalidate the EPT
1345 //
1346 if (VCpu->CoreId == i && g_GuestState[i].HasLaunched)
1347 {
1348 EptInveptSingleContext(VCpu->EptPointer.AsUInt);
1349 }
1350 }
1351
1352 return TRUE;
1353}
@ DEBUGGER_MEMORY_HOOK_PHYSICAL_ADDRESS
Definition DataTypes.h:312
BOOLEAN EptSplitLargePage(PVMM_EPT_PAGE_TABLE EptPageTable, PVOID PreAllocatedBuffer, SIZE_T PhysicalAddress)
Split 2MB (LargePage) into 4kb pages.
Definition Ept.c:462
BOOLEAN EptHookInstructionMemory(PEPT_HOOKED_PAGE_DETAIL Hook, CR3_TYPE ProcessCr3, PVOID TargetFunction, PVOID TargetFunctionInSafeMemory, PVOID HookFunction)
Hook instructions.
Definition EptHook.c:834
#define DEBUGGER_ERROR_EPT_FAILED_TO_GET_PML1_ENTRY_OF_TARGET_ADDRESS
error, failed to get PML1 entry of the target address
Definition ErrorCodes.h:264
#define DEBUGGER_ERROR_PRE_ALLOCATED_BUFFER_IS_EMPTY
error, there is no pre-allocated buffer
Definition ErrorCodes.h:251
#define DEBUGGER_ERROR_EPT_MULTIPLE_HOOKS_IN_A_SINGLE_PAGE
error, multiple EPT Hooks or Monitors are applied on a single page
Definition ErrorCodes.h:270
#define DEBUGGER_ERROR_COULD_NOT_BUILD_THE_EPT_HOOK
error, could not build the EPT Hook
Definition ErrorCodes.h:276
#define DEBUGGER_ERROR_EPT_COULD_NOT_SPLIT_THE_LARGE_PAGE_TO_4KB_PAGES
error, in the EPT handler, it could not split the 2MB pages to 512 entries of 4 KB pages
Definition ErrorCodes.h:258
void AsmGeneralDetourHook(void)
Detour hook handler.
BOOLEAN PoolManagerFreePool(UINT64 AddressToFree)
This function set a pool flag to be freed, and it will be freed on the next IOCTL when it's safe to r...
Definition PoolManager.c:136
EPT_PTE EPT_PML1_ENTRY
Definition State.h:22
SIZE_T PhysicalBaseAddressOfFakePageContents
The base address of the page with fake contents. Used to swap page with fake contents when a hook is ...
Definition State.h:208
BOOLEAN IsExecutionHook
This field shows whether the hook contains a hidden hook for execution or not.
Definition State.h:229
LIST_ENTRY PageHookList
Linked list entries for each page hook.
Definition State.h:170
SIZE_T EndOfTargetPhysicalAddress
End address of the target physical address.
Definition State.h:197
SIZE_T StartOfTargetPhysicalAddress
Start address of the target physical address.
Definition State.h:192
EPT_PML1_ENTRY OriginalEntry
The original page entry. Will be copied back when the hook is removed from the page.
Definition State.h:214
Setting details for EPT Hooks (!monitor)
Definition DataTypes.h:331
BOOLEAN HasLaunched
Definition State.h:293

◆ EptHookPerformUnHookSingleAddress()

BOOLEAN EptHookPerformUnHookSingleAddress ( UINT64 VirtualAddress,
UINT64 PhysAddress,
UINT64 HookingTag,
UINT32 ProcessId,
BOOLEAN ApplyDirectlyFromVmxRoot,
EPT_SINGLE_HOOK_UNHOOKING_DETAILS * TargetUnhookingDetails )

Remove single hook from the hooked pages list and invalidate TLB.

Parameters
VirtualAddressVirtual address to unhook
PhysAddressPhysical address to unhook (optional)
HookingTagHooking tag (optional)
ProcessIdThe process id of target process (in unhooking for some hooks only physical address is availables)
ApplyDirectlyFromVmxRootshould it be directly applied from VMX-root mode or not
TargetUnhookingDetailsTarget data for the caller to restore EPT entry and invalidate EPT caches. Only when applied in VMX-root mode directly
Returns
BOOLEAN If unhook was successful it returns true or if it was not successful returns false
2215{
2216 SIZE_T PhysicalAddress = NULL64_ZERO;
2217
2218 //
2219 // Once applied directly from VMX-root mode, the process id should be the same process Id
2220 // on current process
2221 //
2222 if (ApplyDirectlyFromVmxRoot || ProcessId == DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES || ProcessId == 0)
2223 {
2224 ProcessId = HANDLE_TO_UINT32(PsGetCurrentProcessId());
2225 }
2226
2227 //
2228 // Check if the physical address is available or not
2229 //
2230 if (PhysAddress != NULL64_ZERO)
2231 {
2232 PhysicalAddress = (SIZE_T)PAGE_ALIGN(PhysAddress);
2233 }
2234 else if (HookingTag == NULL64_ZERO)
2235 {
2236 if (ApplyDirectlyFromVmxRoot)
2237 {
2238 PhysicalAddress = (SIZE_T)(PAGE_ALIGN(VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)VirtualAddress)));
2239 }
2240 else
2241 {
2242 PhysicalAddress = (SIZE_T)(PAGE_ALIGN(VirtualAddressToPhysicalAddressByProcessId((PVOID)VirtualAddress,
2243 ProcessId)));
2244 }
2245 }
2246
2248 {
2249 //
2250 // Check if it's a hidden breakpoint or hidden detours
2251 //
2252 if (CurrEntity->IsHiddenBreakpoint)
2253 {
2254 //
2255 // It's a hidden breakpoint
2256 //
2257 for (size_t i = 0; i < CurrEntity->CountOfBreakpoints; i++)
2258 {
2259 if (CurrEntity->BreakpointAddresses[i] == VirtualAddress)
2260 {
2262 VirtualAddress,
2263 ApplyDirectlyFromVmxRoot,
2264 TargetUnhookingDetails);
2265 }
2266 }
2267 }
2268 else
2269 {
2270 //
2271 // It's either a hidden detours or a monitor (read/write/execute) entry
2272 //
2273 if ((HookingTag != NULL64_ZERO && CurrEntity->HookingTag == HookingTag) || CurrEntity->PhysicalBaseAddress == PhysicalAddress)
2274 {
2276 ApplyDirectlyFromVmxRoot,
2277 TargetUnhookingDetails);
2278 }
2279 }
2280 }
2281
2282 //
2283 // Nothing found, probably the hooking detail is not found
2284 //
2285 return FALSE;
2286}
#define DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES
Apply the event to all the processes.
Definition Constants.h:617
_Use_decl_annotations_ UINT64 VirtualAddressToPhysicalAddressByProcessId(PVOID VirtualAddress, UINT32 ProcessId)
Converts Virtual Address to Physical Address based on a specific process id's kernel cr3.
Definition Conversion.c:171
_Use_decl_annotations_ UINT64 VirtualAddressToPhysicalAddressOnTargetProcess(PVOID VirtualAddress)
Converts Virtual Address to Physical Address based on the current process's kernel cr3.
Definition Conversion.c:258
BOOLEAN EptHookUnHookSingleAddressDetoursAndMonitor(PEPT_HOOKED_PAGE_DETAIL HookedEntry, BOOLEAN ApplyDirectlyFromVmxRoot, EPT_SINGLE_HOOK_UNHOOKING_DETAILS *TargetUnhookingDetails)
Remove single hook of detours type.
Definition EptHook.c:1902
BOOLEAN EptHookUnHookSingleAddressHiddenBreakpoint(PEPT_HOOKED_PAGE_DETAIL HookedEntry, UINT64 VirtualAddress, BOOLEAN ApplyDirectlyFromVmxRoot, EPT_SINGLE_HOOK_UNHOOKING_DETAILS *TargetUnhookingDetails)
Remove single hook of hidden breakpoint type.
Definition EptHook.c:2031
#define HANDLE_TO_UINT32(_var)
Definition MetaMacros.h:39

◆ EptHookRemoveEntryAndFreePoolFromEptHook2sDetourList()

BOOLEAN EptHookRemoveEntryAndFreePoolFromEptHook2sDetourList ( UINT64 Address)

Remove the entry from g_EptHook2sDetourListHead in the case of !epthook2 details.

Remove an entry from g_EptHook2sDetourListHead.

Parameters
AddressAddress to remove
Returns
BOOLEAN TRUE if successfully removed and false if not found
1827{
1828 //
1829 // Iterate through the list of hooked pages details to find
1830 // the entry in the list
1831 //
1832 LIST_FOR_EACH_LINK(g_EptHook2sDetourListHead, HIDDEN_HOOKS_DETOUR_DETAILS, OtherHooksList, CurrentHookedDetails)
1833 {
1834 if (CurrentHookedDetails->HookedFunctionAddress == (PVOID)Address)
1835 {
1836 //
1837 // We found the address, we should remove it and add it for
1838 // future deallocation
1839 //
1840 RemoveEntryList(&CurrentHookedDetails->OtherHooksList);
1841
1842 //
1843 // Free the pool in next ioctl
1844 //
1845 if (!PoolManagerFreePool((UINT64)CurrentHookedDetails))
1846 {
1847 LogError("Err, something goes wrong, the pool not found in the list of previously allocated pools by pool manager");
1848 }
1849 return TRUE;
1850 }
1851 }
1852 //
1853 // No entry found !
1854 //
1855 return FALSE;
1856}
UINT64 Address
Definition HyperDbgScriptImports.h:67
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition Windows.h:56

◆ EptHookReservePreallocatedPoolsForEptHooks()

VOID EptHookReservePreallocatedPoolsForEptHooks ( UINT32 Count)

Reserve pre-allocated pools for EPT hooks.

Allocate pre-allocated pools for EPT hooks.

Parameters
Countnumber of hooks
Returns
VOID
71{
72 ULONG ProcessorsCount;
73
74 //
75 // Get number of processors
76 //
77 ProcessorsCount = KeQueryActiveProcessorCount(0);
78
79 //
80 // Request pages to be allocated for converting 2MB to 4KB pages
81 // Each core needs its own splitting page-tables
82 //
84
85 //
86 // Request pages to be allocated for paged hook details
87 //
89
90 //
91 // Request pages to be allocated for Trampoline of Executable hooked pages
92 //
94
95 //
96 // Request pages to be allocated for detour hooked pages details
97 //
99}

◆ EptHookRestoreAllHooksToOriginalEntry()

VOID EptHookRestoreAllHooksToOriginalEntry ( VIRTUAL_MACHINE_STATE * VCpu)

Remove and Invalidate Hook in TLB.

Remove all hooks from the hooked pages lists (Should be called in vmx-root)

Warning
This function won't remove entries from LIST_ENTRY, just invalidate the paging, use EptHookUnHookAll instead
Parameters
VCpuThe virtual processor's state
Returns
VOID
705{
706 PEPT_PML1_ENTRY TargetPage;
707
708 //
709 // Should be called from vmx-root, for calling from vmx non-root use the corresponding VMCALL
710 //
712 {
713 return;
714 }
715
717 {
718 //
719 // Pointer to the page entry in the page table
720 //
721 TargetPage = EptGetPml1Entry(VCpu->EptPageTable, HookedEntry->PhysicalBaseAddress);
722
723 //
724 // Apply the hook to EPT
725 //
726 TargetPage->AsUInt = HookedEntry->OriginalEntry.AsUInt;
727 }
728
729 //
730 // Invalidate EPT Cache
731 //
733}

◆ EptHookRestoreSingleHookToOriginalEntry()

BOOLEAN EptHookRestoreSingleHookToOriginalEntry ( VIRTUAL_MACHINE_STATE * VCpu,
SIZE_T PhysicalAddress,
UINT64 OriginalEntry )

Remove and Invalidate Hook in TLB (Hidden Detours and if counter of hidden breakpoint is zero)

Remove a special hook from the hooked pages lists.

Warning
This function won't remove entries from LIST_ENTRY, just invalidate the paging, use EptHookUnHookSingleAddress instead
Parameters
VCpuThe virtual processor's state
PhysicalAddress
OriginalEntry
Returns
BOOLEAN Return false if there was an error or returns true if it was successful
659{
660 PEPT_PML1_ENTRY TargetPage;
661
662 //
663 // Should be called from vmx-root, for calling from vmx non-root use the corresponding VMCALL
664 //
666 {
667 return FALSE;
668 }
669 //
670 // Pointer to the page entry in the page table
671 //
672 TargetPage = EptGetPml1Entry(VCpu->EptPageTable, PhysicalAddress);
673
674 if (TargetPage != NULL)
675 {
676 //
677 // Apply the hook to EPT
678 //
679 TargetPage->AsUInt = OriginalEntry;
680
681 //
682 // Invalidate EPT Cache
683 //
685
686 return TRUE;
687 }
688
689 //
690 // The PML1 entry not found
691 //
692 return FALSE;
693}

◆ EptHookUnHookAll()

VOID EptHookUnHookAll ( )

Remove all hooks from the hooked pages list and invalidate TLB @detailsShould be called from Vmx Non-root.

Remove all hooks from the hooked pages lists.

Returns
VOID
2432{
2433 //
2434 // Should be called from vmx non-root
2435 //
2437 {
2438 return;
2439 }
2440
2441 //
2442 // Remove it in all the cores
2443 //
2445
2446 //
2447 // In the case of unhooking all pages, we remove the hooked
2448 // from EPT table in vmx-root and at last, we need to deallocate
2449 // it from the buffers
2450 //
2451
2453 {
2454 //
2455 // Now that we removed this hidden detours hook, it is
2456 // time to remove it from g_EptHook2sDetourListHead
2457 // if the hook is detours
2458 //
2459 if (!CurrEntity->IsHiddenBreakpoint)
2460 {
2461 EptHookRemoveEntryAndFreePoolFromEptHook2sDetourList(CurrEntity->VirtualAddress);
2462 }
2463
2464 //
2465 // As we are in vmx-root here, we add the hooked entry to the list
2466 // of pools that will be deallocated on next IOCTL
2467 //
2468 if (!PoolManagerFreePool((UINT64)CurrEntity))
2469 {
2470 LogError("Err, something goes wrong, the pool not found in the list of previously allocated pools by pool manager");
2471 }
2472 }
2473}
BOOLEAN EptHookRemoveEntryAndFreePoolFromEptHook2sDetourList(UINT64 Address)
Remove the entry from g_EptHook2sDetourListHead in the case of !epthook2 details.
Definition EptHook.c:1826
VOID DpcRoutineRemoveHookAndInvalidateAllEntriesOnAllCores(KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
The broadcast function which removes all the hooks and invalidate TLB.
Definition DpcRoutines.c:1607

◆ EptHookUnHookAllByHookingTag()

BOOLEAN EptHookUnHookAllByHookingTag ( UINT64 HookingTag)

Remove all hooks from the hooked pages by the given hooking tag.

Should be called from Vmx Non-root

Parameters
HookingTagThe hooking tag to unhook
Returns
BOOLEAN If unhook was successful it returns true or if it was not successful returns false
2297{
2298 EPT_SINGLE_HOOK_UNHOOKING_DETAILS TargetUnhookingDetails; // not used
2299 BOOLEAN AtLeastOneUnhooked = FALSE;
2300 BOOLEAN UnhookingResult = FALSE;
2301
2302 //
2303 // Should be called from vmx non-root
2304 //
2306 {
2307 return FALSE;
2308 }
2309
2310KeepUnhooking:
2312 NULL_ZERO,
2313 HookingTag,
2314 NULL_ZERO,
2315 FALSE,
2316 &TargetUnhookingDetails);
2317
2318 if (UnhookingResult)
2319 {
2320 AtLeastOneUnhooked = TRUE;
2321
2322 //
2323 // Keep unhooking until there is no more hooking details
2324 //
2325 goto KeepUnhooking;
2326 }
2327
2328 return AtLeastOneUnhooked;
2329}
BOOLEAN EptHookPerformUnHookSingleAddress(UINT64 VirtualAddress, UINT64 PhysAddress, UINT64 HookingTag, UINT32 ProcessId, BOOLEAN ApplyDirectlyFromVmxRoot, EPT_SINGLE_HOOK_UNHOOKING_DETAILS *TargetUnhookingDetails)
Remove single hook from the hooked pages list and invalidate TLB.
Definition EptHook.c:2209
Details of unhooking single EPT hooks.
Definition DataTypes.h:358

◆ EptHookUnHookSingleAddress()

BOOLEAN EptHookUnHookSingleAddress ( UINT64 VirtualAddress,
UINT64 PhysAddress,
UINT32 ProcessId )

Remove single hook from the hooked pages list and invalidate TLB.

Remove single hook from the hooked pages list and invalidate TLB From VMX non-root mode.

Should be called from VMX non-root

Parameters
VirtualAddressVirtual address to unhook
PhysAddressPhysical address to unhook (optional)
ProcessIdThe process id of target process

in unhooking for some hooks only physical address is availables

Returns
BOOLEAN If unhook was successful it returns true or if it was not successful returns false
2373{
2374 EPT_SINGLE_HOOK_UNHOOKING_DETAILS TargetUnhookingDetails; // not used
2375
2376 //
2377 // Should be called from VMX non-root
2378 //
2380 {
2381 return FALSE;
2382 }
2383
2384 return EptHookPerformUnHookSingleAddress(VirtualAddress,
2385 PhysAddress,
2386 NULL_ZERO,
2387 ProcessId,
2388 FALSE,
2389 &TargetUnhookingDetails);
2390}

◆ EptHookUnHookSingleAddressDetoursAndMonitor()

BOOLEAN EptHookUnHookSingleAddressDetoursAndMonitor ( PEPT_HOOKED_PAGE_DETAIL HookedEntry,
BOOLEAN ApplyDirectlyFromVmxRoot,
EPT_SINGLE_HOOK_UNHOOKING_DETAILS * TargetUnhookingDetails )

Remove single hook of detours type.

Parameters
HookedEntryentry detail of hooked address
ApplyDirectlyFromVmxRootshould it be directly applied from VMX-root mode or not
TargetUnhookingDetailsTarget data for the caller to restore EPT entry and invalidate EPT caches. Only when applied in VMX-root mode directly
Returns
BOOLEAN If unhook was successful it returns true or if it was not successful returns false
1905{
1906 //
1907 // Set the unhooking details
1908 //
1909 TargetUnhookingDetails->PhysicalAddress = HookedEntry->PhysicalBaseAddress;
1910 TargetUnhookingDetails->OriginalEntry = HookedEntry->OriginalEntry.AsUInt;
1911
1912 //
1913 // If applied directly from VMX-root mode, it's the responsibility of the
1914 // caller to remove the hook and invalidate EPT caches for the target physical address
1915 //
1916 if (ApplyDirectlyFromVmxRoot)
1917 {
1918 TargetUnhookingDetails->CallerNeedsToRestoreEntryAndInvalidateEpt = TRUE;
1919 }
1920 else
1921 {
1922 //
1923 // Remove it in all the cores
1924 //
1925 TargetUnhookingDetails->CallerNeedsToRestoreEntryAndInvalidateEpt = FALSE;
1926 KeGenericCallDpc(DpcRoutineRemoveHookAndInvalidateSingleEntryOnAllCores, TargetUnhookingDetails);
1927 }
1928
1929 //
1930 // Now that we removed this hidden detours hook, it is
1931 // time to remove it from g_EptHook2sDetourListHead
1932 //
1933 if (HookedEntry->IsExecutionHook)
1934 {
1936 }
1937
1938 //
1939 // remove the entry from the list
1940 //
1941 RemoveEntryList(&HookedEntry->PageHookList);
1942
1943 //
1944 // we add the hooked entry to the list
1945 // of pools that will be deallocated on next IOCTL
1946 //
1947 if (!PoolManagerFreePool((UINT64)HookedEntry))
1948 {
1949 LogError("Err, something goes wrong, the pool not found in the list of previously allocated pools by pool manager");
1950 return FALSE;
1951 }
1952
1953 return TRUE;
1954}
VOID DpcRoutineRemoveHookAndInvalidateSingleEntryOnAllCores(KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
The broadcast function which removes the single hook and invalidate TLB.
Definition DpcRoutines.c:1638
BOOLEAN CallerNeedsToRestoreEntryAndInvalidateEpt
Definition DataTypes.h:359
SIZE_T PhysicalAddress
Definition DataTypes.h:361
UINT64 OriginalEntry
Definition DataTypes.h:362

◆ EptHookUnHookSingleAddressFromVmxRoot()

BOOLEAN EptHookUnHookSingleAddressFromVmxRoot ( UINT64 VirtualAddress,
UINT64 PhysAddress,
EPT_SINGLE_HOOK_UNHOOKING_DETAILS * TargetUnhookingDetails )

Remove single hook from the hooked pages list and invalidate TLB.

Remove single hook from the hooked pages list and invalidate TLB From VMX root-mode.

Should be called from VMX root-mode

Parameters
VirtualAddressVirtual address to unhook
PhysAddressPhysical address to unhook (optional)
TargetUnhookingDetailsTarget data for the caller to restore EPT entry and invalidate EPT caches. Only when applied in VMX-root mode directly
Returns
BOOLEAN If unhook was successful it returns true or if it was not successful returns false
2407{
2408 //
2409 // Should be called from VMX root-mode
2410 //
2412 {
2413 return FALSE;
2414 }
2415
2416 return EptHookPerformUnHookSingleAddress(VirtualAddress,
2417 PhysAddress,
2419 NULL_ZERO,
2420 TRUE,
2421 TargetUnhookingDetails);
2422}

◆ EptHookUnHookSingleAddressHiddenBreakpoint()

BOOLEAN EptHookUnHookSingleAddressHiddenBreakpoint ( PEPT_HOOKED_PAGE_DETAIL HookedEntry,
UINT64 VirtualAddress,
BOOLEAN ApplyDirectlyFromVmxRoot,
EPT_SINGLE_HOOK_UNHOOKING_DETAILS * TargetUnhookingDetails )

Remove single hook of hidden breakpoint type.

Parameters
HookedEntryentry detail of hooked address
VirtualAddressvirtual address to unhook
ApplyDirectlyFromVmxRootshould it be directly applied from VMX-root mode or not
TargetUnhookingDetailsTarget data for the caller to restore EPT entry and invalidate EPT caches. Only when applied in VMX-root mode directly
Returns
BOOLEAN If unhook was successful it returns true or if it was not successful returns false
2035{
2036 UINT64 TargetAddressInFakePageContent;
2037 UINT32 CountOfEntriesWithSameAddr = 0;
2038
2039 //
2040 // By default, the caller doesn't need to remove #BPs interceptions if directly
2041 // applied from VMX-root mode
2042 //
2043 TargetUnhookingDetails->RemoveBreakpointInterception = FALSE;
2044
2045 //
2046 // It's a hidden breakpoint (we have to search through an array of addresses)
2047 // We count it from top to down because if there are two ept hooks at the
2048 // same address, then the last one has an invalid PreviousByte and this
2049 // is the HookedEntry that should be remove (not the first one as it has the
2050 // correct PreviousByte)
2051 //
2052 for (size_t i = 0; i < HookedEntry->CountOfBreakpoints; i++)
2053 {
2054 if (HookedEntry->BreakpointAddresses[i] == VirtualAddress)
2055 {
2056 //
2057 // Check if it's a single breakpoint
2058 //
2059 if (HookedEntry->CountOfBreakpoints == 1)
2060 {
2061 //
2062 // Set the unhooking details
2063 //
2064 TargetUnhookingDetails->PhysicalAddress = HookedEntry->PhysicalBaseAddress;
2065 TargetUnhookingDetails->OriginalEntry = HookedEntry->OriginalEntry.AsUInt;
2066
2067 //
2068 // If applied directly from VMX-root mode, it's the responsibility of the
2069 // caller to remove the hook and invalidate EPT caches for the target physical address
2070 //
2071 if (ApplyDirectlyFromVmxRoot)
2072 {
2073 //
2074 // The caller is responsible for restoring EPT entry and invalidate caches
2075 //
2076 TargetUnhookingDetails->CallerNeedsToRestoreEntryAndInvalidateEpt = TRUE;
2077 }
2078 else
2079 {
2080 //
2081 // Remove the hook entirely on all cores
2082 //
2083 TargetUnhookingDetails->CallerNeedsToRestoreEntryAndInvalidateEpt = FALSE;
2084 KeGenericCallDpc(DpcRoutineRemoveHookAndInvalidateSingleEntryOnAllCores, TargetUnhookingDetails);
2085 }
2086
2087 //
2088 // remove the entry from the list
2089 //
2090 RemoveEntryList(&HookedEntry->PageHookList);
2091
2092 //
2093 // we add the hooked entry to the list
2094 // of pools that will be deallocated on next IOCTL
2095 //
2096 if (!PoolManagerFreePool((UINT64)HookedEntry))
2097 {
2098 LogError("Err, something goes wrong, the pool not found in the list of previously allocated pools by pool manager");
2099 }
2100
2101 //
2102 // Check if there is any other breakpoints, if no then we have to disable
2103 // exception bitmaps on vm-exits for breakpoint, for this purpose, we have
2104 // to visit all the entries to see if there is any entries
2105 //
2107 {
2108 //
2109 // If applied directly from VMX-root mode, it's the responsibility of the
2110 // caller to broadcast to disable breakpoint exceptions on all cores
2111 //
2112 if (ApplyDirectlyFromVmxRoot)
2113 {
2114 //
2115 // Set whether it was the last hook (and the caller if applied from VMX-root needed
2116 // to broadcast to disable #BPs interception on exception bitmaps or not)
2117 //
2118 TargetUnhookingDetails->RemoveBreakpointInterception = TRUE;
2119 }
2120 else
2121 {
2122 //
2123 // Did not find any entry, let's disable the breakpoints vm-exits
2124 // on exception bitmaps
2125 //
2126 TargetUnhookingDetails->RemoveBreakpointInterception = FALSE;
2128 }
2129 }
2130
2131 return TRUE;
2132 }
2133 else
2134 {
2135 //
2136 // Set 0xcc to its previous value
2137 //
2138 TargetAddressInFakePageContent = EptHookCalcBreakpointOffset((PVOID)VirtualAddress, HookedEntry);
2139
2140 //
2141 // We'll check if there is another hooked address with the same virtual address
2142 // in the array, then we'll ignore setting the previous bit as previous bit might
2143 // be modified for the previous command
2144 //
2145 for (size_t j = 0; j < HookedEntry->CountOfBreakpoints; j++)
2146 {
2147 if (HookedEntry->BreakpointAddresses[j] == VirtualAddress)
2148 {
2149 CountOfEntriesWithSameAddr++;
2150 }
2151 }
2152
2153 if (CountOfEntriesWithSameAddr == 1)
2154 {
2155 //
2156 // Set the previous value
2157 //
2158 *(BYTE *)TargetAddressInFakePageContent = HookedEntry->PreviousBytesOnBreakpointAddresses[i];
2159 }
2160
2161 //
2162 // Remove just that special entry
2163 // BTW, No need to remove it, it will be replaced automatically
2164 //
2165 HookedEntry->BreakpointAddresses[i] = NULL64_ZERO;
2166 HookedEntry->PreviousBytesOnBreakpointAddresses[i] = 0x0;
2167
2168 //
2169 // all addresses to a lower array index (because one entry is
2170 // missing and might) be in the middle of the array
2171 //
2172 for (size_t j = i /* IndexToRemove */; j < HookedEntry->CountOfBreakpoints - 1; j++)
2173 {
2174 HookedEntry->BreakpointAddresses[j] = HookedEntry->BreakpointAddresses[j + 1];
2175 HookedEntry->PreviousBytesOnBreakpointAddresses[j] = HookedEntry->PreviousBytesOnBreakpointAddresses[j + 1];
2176 }
2177
2178 //
2179 // Decrease the count of breakpoints
2180 //
2181 HookedEntry->CountOfBreakpoints = HookedEntry->CountOfBreakpoints - 1;
2182
2183 return TRUE;
2184 }
2185 }
2186 }
2187
2188 //
2189 // If we reach here, sth went wrong
2190 //
2191 return FALSE;
2192}
unsigned char BYTE
Definition BasicTypes.h:24
VOID BroadcastDisableBreakpointExitingOnExceptionBitmapAllCores()
routines to disable vm-exit for breakpoints (exception bitmap)
Definition Broadcast.c:77
UINT32 EptHookGetCountOfEpthooks(BOOLEAN IsEptHook2)
get the length of active EPT hooks (!epthook and !epthook2)
Definition EptHook.c:1865
UINT64 BreakpointAddresses[MaximumHiddenBreakpointsOnPage]
Address of hooked pages (multiple breakpoints on a single page) this is only used in hidden breakpoin...
Definition State.h:259
UINT64 CountOfBreakpoints
Count of breakpoints (multiple breakpoints on a single page) this is only used in hidden breakpoints ...
Definition State.h:271
BOOLEAN RemoveBreakpointInterception
Definition DataTypes.h:360

◆ EptHookUnHookSingleHookByHookingTagFromVmxRoot()

BOOLEAN EptHookUnHookSingleHookByHookingTagFromVmxRoot ( UINT64 HookingTag,
EPT_SINGLE_HOOK_UNHOOKING_DETAILS * TargetUnhookingDetails )

Remove single hook from the hooked pages by the given hooking tag.

Should be called from Vmx root-mode

Parameters
HookingTagThe hooking tag to unhook
Returns
BOOLEAN If unhook was successful it returns true or if it was not successful returns false
2341{
2342 //
2343 // Should be called from VMX root-mode
2344 //
2346 {
2347 return FALSE;
2348 }
2349
2352 HookingTag,
2353 NULL_ZERO,
2354 TRUE,
2355 TargetUnhookingDetails);
2356}

◆ EptHookWriteAbsoluteJump()

VOID EptHookWriteAbsoluteJump ( PCHAR TargetBuffer,
SIZE_T TargetAddress )

Write an absolute x64 jump to an arbitrary address to a buffer.

Parameters
TargetBuffer
TargetAddress
Returns
VOID
744{
745 //
746 // call $ + 5 ; A 64-bit call instruction is still 5 bytes wide!
747 //
748
749 TargetBuffer[0] = 0xe8;
750 TargetBuffer[1] = 0x00;
751 TargetBuffer[2] = 0x00;
752 TargetBuffer[3] = 0x00;
753 TargetBuffer[4] = 0x00;
754
755 //
756 // push Lower 4-byte TargetAddress
757 //
758 TargetBuffer[5] = 0x68;
759
760 //
761 // Lower 4-byte TargetAddress
762 //
763 *((PUINT32)&TargetBuffer[6]) = (UINT32)TargetAddress;
764
765 //
766 // mov [rsp+4],High 4-byte TargetAddress
767 //
768 TargetBuffer[10] = 0xC7;
769 TargetBuffer[11] = 0x44;
770 TargetBuffer[12] = 0x24;
771 TargetBuffer[13] = 0x04;
772
773 //
774 // High 4-byte TargetAddress
775 //
776 *((PUINT32)&TargetBuffer[14]) = (UINT32)(TargetAddress >> 32);
777
778 //
779 // ret
780 //
781 TargetBuffer[18] = 0xC3;
782}
unsigned int * PUINT32
Definition BasicTypes.h:48

◆ EptHookWriteAbsoluteJump2()

VOID EptHookWriteAbsoluteJump2 ( PCHAR TargetBuffer,
SIZE_T TargetAddress )

Write an absolute x64 jump to an arbitrary address to a buffer.

Parameters
TargetBuffer
TargetAddress
Returns
VOID
793{
794 //
795 // push Lower 4-byte TargetAddress
796 //
797 TargetBuffer[0] = 0x68;
798
799 //
800 // Lower 4-byte TargetAddress
801 //
802 *((PUINT32)&TargetBuffer[1]) = (UINT32)TargetAddress;
803
804 //
805 // mov [rsp+4],High 4-byte TargetAddress
806 //
807 TargetBuffer[5] = 0xC7;
808 TargetBuffer[6] = 0x44;
809 TargetBuffer[7] = 0x24;
810 TargetBuffer[8] = 0x04;
811
812 //
813 // High 4-byte TargetAddress
814 //
815 *((PUINT32)&TargetBuffer[9]) = (UINT32)(TargetAddress >> 32);
816
817 //
818 // ret
819 //
820 TargetBuffer[13] = 0xC3;
821}

◆ ExAllocatePoolWithTagHook()

PVOID ExAllocatePoolWithTagHook ( POOL_TYPE PoolType,
SIZE_T NumberOfBytes,
ULONG Tag )

Hook function that HooksExAllocatePoolWithTag.

Parameters
PoolType
NumberOfBytes
Tag
Returns
PVOID
454{
455 LogInfo("ExAllocatePoolWithTag Called with : Tag = 0x%x, Number Of Bytes = 0x%x, Pool Type = 0x%x ",
456 Tag,
458 PoolType);
459
460 return ExAllocatePoolWithTagOrig(PoolType, NumberOfBytes, Tag);
461}
POOL_TYPE PoolType
Definition Hooks.h:166
POOL_TYPE SIZE_T NumberOfBytes
Definition Hooks.h:167
POOL_TYPE SIZE_T ULONG Tag
Definition Hooks.h:168