mirror of
https://github.com/momo5502/hypervisor.git
synced 2025-04-19 21:52:55 +00:00
Ept hooking
This commit is contained in:
parent
b141d43497
commit
2acac5bee2
@ -25,6 +25,13 @@ LEAF_END __lgdt, _TEXT$00
|
|||||||
|
|
||||||
; -----------------------------------------------------
|
; -----------------------------------------------------
|
||||||
|
|
||||||
|
LEAF_ENTRY __invept, _TEXT$00
|
||||||
|
invept rcx, OWORD PTR [rdx]
|
||||||
|
ret
|
||||||
|
LEAF_END __invept, _TEXT$00
|
||||||
|
|
||||||
|
; -----------------------------------------------------
|
||||||
|
|
||||||
LEAF_ENTRY restore_context, _TEXT$00
|
LEAF_ENTRY restore_context, _TEXT$00
|
||||||
movaps xmm0, CxXmm0[rcx]
|
movaps xmm0, CxXmm0[rcx]
|
||||||
movaps xmm1, CxXmm1[rcx]
|
movaps xmm1, CxXmm1[rcx]
|
||||||
|
@ -10,6 +10,8 @@ void __lgdt(void* gdtr);
|
|||||||
|
|
||||||
void _sgdt(void*);
|
void _sgdt(void*);
|
||||||
|
|
||||||
|
void __invept(size_t type, invept_descriptor* descriptor);
|
||||||
|
|
||||||
[[ noreturn ]] void vm_launch();
|
[[ noreturn ]] void vm_launch();
|
||||||
[[ noreturn ]] void vm_exit();
|
[[ noreturn ]] void vm_exit();
|
||||||
[[ noreturn ]] void restore_context(CONTEXT* context);
|
[[ noreturn ]] void restore_context(CONTEXT* context);
|
||||||
|
@ -4,10 +4,159 @@
|
|||||||
#include "irp.hpp"
|
#include "irp.hpp"
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
#include "hypervisor.hpp"
|
#include "hypervisor.hpp"
|
||||||
|
#include "memory.hpp"
|
||||||
|
#include "process.hpp"
|
||||||
|
|
||||||
#define DOS_DEV_NAME L"\\DosDevices\\HelloDev"
|
#define DOS_DEV_NAME L"\\DosDevices\\HelloDev"
|
||||||
#define DEV_NAME L"\\Device\\HelloDev"
|
#define DEV_NAME L"\\Device\\HelloDev"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void log_current_process_name()
|
||||||
|
{
|
||||||
|
const auto process = process::get_current_process();
|
||||||
|
const auto* name = process.get_image_filename();
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
debug_log("Denied for process: %s\n", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS (*NtCreateFileOrig)(
|
||||||
|
PHANDLE FileHandle,
|
||||||
|
ACCESS_MASK DesiredAccess,
|
||||||
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
|
PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
PLARGE_INTEGER AllocationSize,
|
||||||
|
ULONG FileAttributes,
|
||||||
|
ULONG ShareAccess,
|
||||||
|
ULONG CreateDisposition,
|
||||||
|
ULONG CreateOptions,
|
||||||
|
PVOID EaBuffer,
|
||||||
|
ULONG EaLength
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS NtCreateFileHook(
|
||||||
|
PHANDLE FileHandle,
|
||||||
|
ACCESS_MASK DesiredAccess,
|
||||||
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
|
PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
PLARGE_INTEGER AllocationSize,
|
||||||
|
ULONG FileAttributes,
|
||||||
|
ULONG ShareAccess,
|
||||||
|
ULONG CreateDisposition,
|
||||||
|
ULONG CreateOptions,
|
||||||
|
PVOID EaBuffer,
|
||||||
|
ULONG EaLength
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static WCHAR BlockedFileName[] = L"test.txt";
|
||||||
|
static SIZE_T BlockedFileNameLength = (sizeof(BlockedFileName) / sizeof(BlockedFileName[0])) - 1;
|
||||||
|
|
||||||
|
PWCH NameBuffer;
|
||||||
|
USHORT NameLength;
|
||||||
|
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
|
||||||
|
ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), 1);
|
||||||
|
|
||||||
|
NameBuffer = ObjectAttributes->ObjectName->Buffer;
|
||||||
|
NameLength = ObjectAttributes->ObjectName->Length;
|
||||||
|
|
||||||
|
ProbeForRead(NameBuffer, NameLength, 1);
|
||||||
|
|
||||||
|
/* Convert to length in WCHARs */
|
||||||
|
NameLength /= sizeof(WCHAR);
|
||||||
|
|
||||||
|
/* Does the file path (ignoring case and null terminator) end with our blocked file name? */
|
||||||
|
if (NameLength >= BlockedFileNameLength &&
|
||||||
|
_wcsnicmp(&NameBuffer[NameLength - BlockedFileNameLength], BlockedFileName,
|
||||||
|
BlockedFileNameLength) == 0)
|
||||||
|
{
|
||||||
|
log_current_process_name();
|
||||||
|
return STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
NOTHING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NtCreateFileOrig(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize,
|
||||||
|
FileAttributes,
|
||||||
|
ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID HvEptHookWriteAbsoluteJump(uint8_t* TargetBuffer, SIZE_T TargetAddress)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Use 'push ret' instead of 'jmp qword[rip+0]',
|
||||||
|
* Because 'jmp qword[rip+0]' will read hooked page 8bytes.
|
||||||
|
*
|
||||||
|
* 14 bytes hook:
|
||||||
|
* 0x68 0x12345678 ......................push 'low 32bit of TargetAddress'
|
||||||
|
* 0xC7 0x44 0x24 0x04 0x12345678........mov dword[rsp + 4], 'high 32bit of TargetAddress'
|
||||||
|
* 0xC3..................................ret
|
||||||
|
*/
|
||||||
|
|
||||||
|
UINT32 Low32;
|
||||||
|
UINT32 High32;
|
||||||
|
|
||||||
|
Low32 = (UINT32)TargetAddress;
|
||||||
|
High32 = (UINT32)(TargetAddress >> 32);
|
||||||
|
|
||||||
|
/* push 'low 32bit of TargetAddress' */
|
||||||
|
TargetBuffer[0] = 0x68;
|
||||||
|
*((UINT32*)&TargetBuffer[1]) = Low32;
|
||||||
|
|
||||||
|
/* mov dword[rsp + 4], 'high 32bit of TargetAddress' */
|
||||||
|
*((UINT32*)&TargetBuffer[5]) = 0x042444C7;
|
||||||
|
*((UINT32*)&TargetBuffer[9]) = High32;
|
||||||
|
|
||||||
|
/* ret */
|
||||||
|
TargetBuffer[13] = 0xC3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* HookCreateFile(hypervisor& hypervisor)
|
||||||
|
{
|
||||||
|
const uint8_t fixup[] = {
|
||||||
|
0x48, 0x81, 0xEC, 0x88, 0x00, 0x00, 0x00, 0x33, 0xC0, 0x48, 0x89, 0x44, 0x24, 0x78
|
||||||
|
};
|
||||||
|
|
||||||
|
auto* target = reinterpret_cast<uint8_t*>(&NtCreateFile);
|
||||||
|
if (memcmp(target, fixup, sizeof(fixup)))
|
||||||
|
{
|
||||||
|
debug_log("Fixup is invalid\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* trampoline = static_cast<uint8_t*>(memory::allocate_non_paged_memory(sizeof(fixup) + 14));
|
||||||
|
if (!trampoline)
|
||||||
|
{
|
||||||
|
debug_log("Failed to allocate trampoline\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(trampoline, fixup, sizeof(fixup));
|
||||||
|
|
||||||
|
|
||||||
|
HvEptHookWriteAbsoluteJump(trampoline + sizeof(fixup),
|
||||||
|
size_t(target) + sizeof(fixup));
|
||||||
|
|
||||||
|
/* Let the hook function call the original function */
|
||||||
|
NtCreateFileOrig = reinterpret_cast<decltype(NtCreateFileOrig)>(trampoline);
|
||||||
|
|
||||||
|
/* Write the absolute jump to our shadow page memory to jump to our hook. */
|
||||||
|
uint8_t hook[14];
|
||||||
|
HvEptHookWriteAbsoluteJump(hook, reinterpret_cast<size_t>(NtCreateFileHook));
|
||||||
|
|
||||||
|
hypervisor.install_ept_hook(target, hook, sizeof(hook));
|
||||||
|
return trampoline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class global_driver
|
class global_driver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -19,11 +168,14 @@ public:
|
|||||||
, irp_(driver_object, DEV_NAME, DOS_DEV_NAME)
|
, irp_(driver_object, DEV_NAME, DOS_DEV_NAME)
|
||||||
{
|
{
|
||||||
debug_log("Driver started\n");
|
debug_log("Driver started\n");
|
||||||
|
this->trampoline = HookCreateFile(this->hypervisor_);
|
||||||
}
|
}
|
||||||
|
|
||||||
~global_driver()
|
~global_driver()
|
||||||
{
|
{
|
||||||
debug_log("Unloading driver\n");
|
debug_log("Unloading driver\n");
|
||||||
|
this->hypervisor_.disable_all_ept_hooks();
|
||||||
|
memory::free_non_paged_memory(this->trampoline);
|
||||||
}
|
}
|
||||||
|
|
||||||
global_driver(global_driver&&) noexcept = delete;
|
global_driver(global_driver&&) noexcept = delete;
|
||||||
@ -41,6 +193,7 @@ private:
|
|||||||
hypervisor hypervisor_{};
|
hypervisor hypervisor_{};
|
||||||
sleep_callback sleep_callback_{};
|
sleep_callback sleep_callback_{};
|
||||||
irp irp_{};
|
irp irp_{};
|
||||||
|
void* trampoline{nullptr};
|
||||||
|
|
||||||
void sleep_notification(const sleep_callback::type type)
|
void sleep_notification(const sleep_callback::type type)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "std_include.hpp"
|
#include "std_include.hpp"
|
||||||
#include "ept.hpp"
|
#include "ept.hpp"
|
||||||
|
|
||||||
#include "logging.hpp"
|
#include "assembly.hpp"
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
#include "vmx.hpp"
|
#include "vmx.hpp"
|
||||||
|
|
||||||
@ -104,151 +104,6 @@ namespace vmx
|
|||||||
|
|
||||||
return candidate_memory_type;
|
return candidate_memory_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS (*NtCreateFileOrig)(
|
|
||||||
PHANDLE FileHandle,
|
|
||||||
ACCESS_MASK DesiredAccess,
|
|
||||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
||||||
PIO_STATUS_BLOCK IoStatusBlock,
|
|
||||||
PLARGE_INTEGER AllocationSize,
|
|
||||||
ULONG FileAttributes,
|
|
||||||
ULONG ShareAccess,
|
|
||||||
ULONG CreateDisposition,
|
|
||||||
ULONG CreateOptions,
|
|
||||||
PVOID EaBuffer,
|
|
||||||
ULONG EaLength
|
|
||||||
);
|
|
||||||
|
|
||||||
NTSTATUS NtCreateFileHook(
|
|
||||||
PHANDLE FileHandle,
|
|
||||||
ACCESS_MASK DesiredAccess,
|
|
||||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
||||||
PIO_STATUS_BLOCK IoStatusBlock,
|
|
||||||
PLARGE_INTEGER AllocationSize,
|
|
||||||
ULONG FileAttributes,
|
|
||||||
ULONG ShareAccess,
|
|
||||||
ULONG CreateDisposition,
|
|
||||||
ULONG CreateOptions,
|
|
||||||
PVOID EaBuffer,
|
|
||||||
ULONG EaLength
|
|
||||||
)
|
|
||||||
{
|
|
||||||
static WCHAR BlockedFileName[] = L"test.txt";
|
|
||||||
static SIZE_T BlockedFileNameLength = (sizeof(BlockedFileName) / sizeof(BlockedFileName[0])) - 1;
|
|
||||||
|
|
||||||
PWCH NameBuffer;
|
|
||||||
USHORT NameLength;
|
|
||||||
|
|
||||||
__try
|
|
||||||
{
|
|
||||||
ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
|
|
||||||
ProbeForRead(ObjectAttributes->ObjectName, sizeof(UNICODE_STRING), 1);
|
|
||||||
|
|
||||||
NameBuffer = ObjectAttributes->ObjectName->Buffer;
|
|
||||||
NameLength = ObjectAttributes->ObjectName->Length;
|
|
||||||
|
|
||||||
ProbeForRead(NameBuffer, NameLength, 1);
|
|
||||||
|
|
||||||
/* Convert to length in WCHARs */
|
|
||||||
NameLength /= sizeof(WCHAR);
|
|
||||||
|
|
||||||
/* Does the file path (ignoring case and null terminator) end with our blocked file name? */
|
|
||||||
if (NameLength >= BlockedFileNameLength &&
|
|
||||||
_wcsnicmp(&NameBuffer[NameLength - BlockedFileNameLength], BlockedFileName,
|
|
||||||
BlockedFileNameLength) == 0)
|
|
||||||
{
|
|
||||||
return STATUS_ACCESS_DENIED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
||||||
{
|
|
||||||
NOTHING;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NtCreateFileOrig(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize,
|
|
||||||
FileAttributes,
|
|
||||||
ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID HvEptHookWriteAbsoluteJump(uint8_t* TargetBuffer, SIZE_T TargetAddress)
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Use 'push ret' instead of 'jmp qword[rip+0]',
|
|
||||||
* Because 'jmp qword[rip+0]' will read hooked page 8bytes.
|
|
||||||
*
|
|
||||||
* 14 bytes hook:
|
|
||||||
* 0x68 0x12345678 ......................push 'low 32bit of TargetAddress'
|
|
||||||
* 0xC7 0x44 0x24 0x04 0x12345678........mov dword[rsp + 4], 'high 32bit of TargetAddress'
|
|
||||||
* 0xC3..................................ret
|
|
||||||
*/
|
|
||||||
|
|
||||||
UINT32 Low32;
|
|
||||||
UINT32 High32;
|
|
||||||
|
|
||||||
Low32 = (UINT32)TargetAddress;
|
|
||||||
High32 = (UINT32)(TargetAddress >> 32);
|
|
||||||
|
|
||||||
/* push 'low 32bit of TargetAddress' */
|
|
||||||
TargetBuffer[0] = 0x68;
|
|
||||||
*((UINT32*)&TargetBuffer[1]) = Low32;
|
|
||||||
|
|
||||||
/* mov dword[rsp + 4], 'high 32bit of TargetAddress' */
|
|
||||||
*((UINT32*)&TargetBuffer[5]) = 0x042444C7;
|
|
||||||
*((UINT32*)&TargetBuffer[9]) = High32;
|
|
||||||
|
|
||||||
/* ret */
|
|
||||||
TargetBuffer[13] = 0xC3;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HvEptHookInstructionMemory(ept_hook* Hook, PVOID TargetFunction, PVOID HookFunction,
|
|
||||||
PVOID* OrigFunction)
|
|
||||||
{
|
|
||||||
SIZE_T OffsetIntoPage;
|
|
||||||
|
|
||||||
OffsetIntoPage = ADDRMASK_EPT_PML1_OFFSET((SIZE_T)TargetFunction);
|
|
||||||
|
|
||||||
if ((OffsetIntoPage + 14) > PAGE_SIZE - 1)
|
|
||||||
{
|
|
||||||
debug_log(
|
|
||||||
"Function extends past a page boundary. We just don't have the technology to solve this.....\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t fixup[] = {
|
|
||||||
0x48, 0x81, 0xEC, 0x88, 0x00, 0x00, 0x00, 0x33, 0xC0, 0x48, 0x89, 0x44, 0x24, 0x78
|
|
||||||
};
|
|
||||||
|
|
||||||
//HvUtilLogDebug("Number of bytes of instruction mem: %d\n", SizeOfHookedInstructions);
|
|
||||||
|
|
||||||
/* Build a trampoline */
|
|
||||||
|
|
||||||
/* Allocate some executable memory for the trampoline */
|
|
||||||
Hook->trampoline = (uint8_t*)memory::allocate_non_paged_memory(sizeof(fixup) + 14);
|
|
||||||
|
|
||||||
if (!Hook->trampoline)
|
|
||||||
{
|
|
||||||
debug_log("Could not allocate trampoline function buffer.\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy the trampoline instructions in. */
|
|
||||||
RtlCopyMemory(Hook->trampoline, TargetFunction, sizeof(fixup));
|
|
||||||
|
|
||||||
/* Add the absolute jump back to the original function. */
|
|
||||||
HvEptHookWriteAbsoluteJump((&Hook->trampoline[sizeof(fixup)]),
|
|
||||||
(SIZE_T)TargetFunction + sizeof(fixup));
|
|
||||||
|
|
||||||
debug_log("Trampoline: 0x%llx\n", Hook->trampoline);
|
|
||||||
debug_log("HookFunction: 0x%llx\n", HookFunction);
|
|
||||||
|
|
||||||
/* Let the hook function call the original function */
|
|
||||||
*OrigFunction = Hook->trampoline;
|
|
||||||
|
|
||||||
/* Write the absolute jump to our shadow page memory to jump to our hook. */
|
|
||||||
HvEptHookWriteAbsoluteJump(&Hook->fake_page[OffsetIntoPage], (SIZE_T)HookFunction);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ept::ept()
|
ept::ept()
|
||||||
@ -270,100 +125,47 @@ namespace vmx
|
|||||||
{
|
{
|
||||||
auto* current_hook = hook;
|
auto* current_hook = hook;
|
||||||
hook = hook->next_hook;
|
hook = hook->next_hook;
|
||||||
memory::free_non_paged_memory(current_hook->trampoline);
|
|
||||||
memory::free_aligned_object(current_hook);
|
memory::free_aligned_object(current_hook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ept::install_hook(PVOID TargetFunction, PVOID HookFunction, PVOID* OrigFunction)
|
void ept::install_page_hook(void* destination, const void* source, const size_t length)
|
||||||
{
|
{
|
||||||
const auto VirtualTarget = PAGE_ALIGN(TargetFunction);
|
auto* hook = this->get_or_create_ept_hook(destination);
|
||||||
const auto PhysicalAddress = memory::get_physical_address(VirtualTarget);
|
|
||||||
|
|
||||||
if (!PhysicalAddress)
|
const auto page_offset = ADDRMASK_EPT_PML1_OFFSET(reinterpret_cast<uint64_t>(destination));
|
||||||
|
memcpy(hook->fake_page + page_offset, source, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ept::install_hook(void* destination, const void* source, const size_t length)
|
||||||
|
{
|
||||||
|
auto current_destination = reinterpret_cast<uint64_t>(destination);
|
||||||
|
auto current_source = reinterpret_cast<uint64_t>(source);
|
||||||
|
auto current_length = length;
|
||||||
|
|
||||||
|
while (current_length != 0)
|
||||||
{
|
{
|
||||||
debug_log("HvEptAddPageHook: Target address could not be mapped to physical memory!\n");
|
const auto page_offset = ADDRMASK_EPT_PML1_OFFSET(current_destination);
|
||||||
return;
|
const auto page_remaining = PAGE_SIZE - page_offset;
|
||||||
|
const auto data_to_write = min(page_remaining, current_length);
|
||||||
|
|
||||||
|
this->install_page_hook(reinterpret_cast<void*>(current_destination),
|
||||||
|
reinterpret_cast<const void*>(current_source), data_to_write);
|
||||||
|
|
||||||
|
current_length -= data_to_write;
|
||||||
|
current_destination += data_to_write;
|
||||||
|
current_source += data_to_write;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a hook object*/
|
void ept::disable_all_hooks() const
|
||||||
auto* NewHook = this->allocate_ept_hook();
|
{
|
||||||
|
auto* hook = this->ept_hooks;
|
||||||
if (!NewHook)
|
while (hook)
|
||||||
{
|
{
|
||||||
debug_log("HvEptAddPageHook: Could not allocate memory for new hook.\n");
|
hook->target_page->flags = hook->original_entry.flags;
|
||||||
return;
|
hook = hook->next_hook;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Ensure the page is split into 512 4096 byte page entries. We can only hook a 4096 byte page, not a 2MB page.
|
|
||||||
* This is due to performance hit we would get from hooking a 2MB page.
|
|
||||||
*/
|
|
||||||
this->split_large_page(PhysicalAddress);
|
|
||||||
RtlCopyMemory(&NewHook->fake_page[0], VirtualTarget, PAGE_SIZE);
|
|
||||||
|
|
||||||
/* Base address of the 4096 page. */
|
|
||||||
NewHook->physical_base_address = (SIZE_T)PAGE_ALIGN(PhysicalAddress);
|
|
||||||
|
|
||||||
/* Pointer to the page entry in the page table. */
|
|
||||||
NewHook->target_page = this->get_pml1_entry(PhysicalAddress);
|
|
||||||
|
|
||||||
/* Ensure the target is valid. */
|
|
||||||
if (!NewHook->target_page)
|
|
||||||
{
|
|
||||||
debug_log("HvEptAddPageHook: Failed to get PML1 entry for target address.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save the original permissions of the page */
|
|
||||||
NewHook->original_entry = *NewHook->target_page;
|
|
||||||
auto OriginalEntry = *NewHook->target_page;
|
|
||||||
|
|
||||||
/* Setup the new fake page table entry */
|
|
||||||
pml1 FakeEntry{};
|
|
||||||
FakeEntry.flags = 0;
|
|
||||||
|
|
||||||
/* We want this page to raise an EPT violation on RW so we can handle by swapping in the original page. */
|
|
||||||
FakeEntry.read_access = 0;
|
|
||||||
FakeEntry.write_access = 0;
|
|
||||||
FakeEntry.execute_access = 1;
|
|
||||||
|
|
||||||
/* Point to our fake page we just made */
|
|
||||||
FakeEntry.page_frame_number = memory::get_physical_address(&NewHook->fake_page) / PAGE_SIZE;
|
|
||||||
|
|
||||||
/* Save a copy of the fake entry. */
|
|
||||||
NewHook->shadow_entry.flags = FakeEntry.flags;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Lastly, mark the entry in the table as no execute. This will cause the next time that an instruction is
|
|
||||||
* fetched from this page to cause an EPT violation exit. This will allow us to swap in the fake page with our
|
|
||||||
* hook.
|
|
||||||
*/
|
|
||||||
OriginalEntry.read_access = 1;
|
|
||||||
OriginalEntry.write_access = 1;
|
|
||||||
OriginalEntry.execute_access = 0;
|
|
||||||
|
|
||||||
/* The hooked entry will be swapped in first. */
|
|
||||||
NewHook->hooked_entry.flags = OriginalEntry.flags;
|
|
||||||
|
|
||||||
if (!HvEptHookInstructionMemory(NewHook, TargetFunction, HookFunction, OrigFunction))
|
|
||||||
{
|
|
||||||
debug_log("HvEptAddPageHook: Could not build hook.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply the hook to EPT */
|
|
||||||
NewHook->target_page->flags = OriginalEntry.flags;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Invalidate the entry in the TLB caches so it will not conflict with the actual paging structure.
|
|
||||||
*/
|
|
||||||
/*if (ProcessorContext->HasLaunched)
|
|
||||||
{
|
|
||||||
Descriptor.EptPointer = ProcessorContext->EptPointer.Flags;
|
|
||||||
Descriptor.Reserved = 0;
|
|
||||||
__invept(1, &Descriptor);
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ept::handle_violation(guest_context& guest_context) const
|
void ept::handle_violation(guest_context& guest_context) const
|
||||||
@ -394,18 +196,24 @@ namespace vmx
|
|||||||
|
|
||||||
if (!violation_qualification.ept_executable && violation_qualification.execute_access)
|
if (!violation_qualification.ept_executable && violation_qualification.execute_access)
|
||||||
{
|
{
|
||||||
hook->target_page->flags = hook->shadow_entry.flags;
|
hook->target_page->flags = hook->execute_entry.flags;
|
||||||
guest_context.increment_rip = false;
|
guest_context.increment_rip = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (violation_qualification.ept_executable && (violation_qualification.read_access || violation_qualification.
|
if (violation_qualification.ept_executable && (violation_qualification.read_access || violation_qualification.
|
||||||
write_access))
|
write_access))
|
||||||
{
|
{
|
||||||
hook->target_page->flags = hook->hooked_entry.flags;
|
hook->target_page->flags = hook->readwrite_entry.flags;
|
||||||
guest_context.increment_rip = false;
|
guest_context.increment_rip = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ept::handle_misconfiguration(guest_context& guest_context) const
|
||||||
|
{
|
||||||
|
guest_context.increment_rip = false;
|
||||||
|
guest_context.exit_vm = true;
|
||||||
|
}
|
||||||
|
|
||||||
void ept::initialize()
|
void ept::initialize()
|
||||||
{
|
{
|
||||||
mtrr_list mtrr_data{};
|
mtrr_list mtrr_data{};
|
||||||
@ -452,18 +260,30 @@ namespace vmx
|
|||||||
mtrr_data, this->epde[i][j].page_frame_number * 2_mb, MEMORY_TYPE_WRITE_BACK);
|
mtrr_data, this->epde[i][j].page_frame_number * 2_mb, MEMORY_TYPE_WRITE_BACK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->install_hook((PVOID)NtCreateFile, (PVOID)NtCreateFileHook, (PVOID*)&NtCreateFileOrig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ept_pml4* ept::get_pml4()
|
ept_pointer ept::get_ept_pointer() const
|
||||||
{
|
{
|
||||||
return this->epml4;
|
const auto ept_pml4_physical_address = memory::get_physical_address(const_cast<pml4*>(&this->epml4[0]));
|
||||||
|
|
||||||
|
ept_pointer vmx_eptp{};
|
||||||
|
vmx_eptp.flags = 0;
|
||||||
|
vmx_eptp.page_walk_length = 3;
|
||||||
|
vmx_eptp.memory_type = MEMORY_TYPE_WRITE_BACK;
|
||||||
|
vmx_eptp.page_frame_number = ept_pml4_physical_address / PAGE_SIZE;
|
||||||
|
|
||||||
|
return vmx_eptp;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ept_pml4* ept::get_pml4() const
|
void ept::invalidate() const
|
||||||
{
|
{
|
||||||
return this->epml4;
|
const auto ept_pointer = this->get_ept_pointer();
|
||||||
|
|
||||||
|
invept_descriptor descriptor{};
|
||||||
|
descriptor.ept_pointer = ept_pointer.flags;
|
||||||
|
descriptor.reserved = 0;
|
||||||
|
|
||||||
|
__invept(1, &descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
pml2* ept::get_pml2_entry(const uint64_t physical_address)
|
pml2* ept::get_pml2_entry(const uint64_t physical_address)
|
||||||
@ -547,6 +367,80 @@ namespace vmx
|
|||||||
return hook;
|
return hook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ept_hook* ept::find_ept_hook(const uint64_t physical_address) const
|
||||||
|
{
|
||||||
|
auto* hook = this->ept_hooks;
|
||||||
|
while (hook)
|
||||||
|
{
|
||||||
|
if (hook->physical_base_address == physical_address)
|
||||||
|
{
|
||||||
|
return hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook = hook->next_hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ept_hook* ept::get_or_create_ept_hook(void* destination)
|
||||||
|
{
|
||||||
|
const auto virtual_target = PAGE_ALIGN(destination);
|
||||||
|
const auto physical_address = memory::get_physical_address(virtual_target);
|
||||||
|
|
||||||
|
if (!physical_address)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("No physical address for destination");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto physical_base_address = reinterpret_cast<uint64_t>(PAGE_ALIGN(physical_address));
|
||||||
|
auto* hook = this->find_ept_hook(physical_base_address);
|
||||||
|
if (hook)
|
||||||
|
{
|
||||||
|
if (hook->target_page->flags == hook->original_entry.flags)
|
||||||
|
{
|
||||||
|
hook->target_page->flags = hook->readwrite_entry.flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook = this->allocate_ept_hook();
|
||||||
|
|
||||||
|
if (!hook)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to allocate hook");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->split_large_page(physical_address);
|
||||||
|
|
||||||
|
memcpy(&hook->fake_page[0], virtual_target, PAGE_SIZE);
|
||||||
|
hook->physical_base_address = physical_base_address;
|
||||||
|
|
||||||
|
hook->target_page = this->get_pml1_entry(physical_address);
|
||||||
|
if (!hook->target_page)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to get PML1 entry for target address");
|
||||||
|
}
|
||||||
|
|
||||||
|
hook->original_entry = *hook->target_page;
|
||||||
|
hook->readwrite_entry = hook->original_entry;
|
||||||
|
|
||||||
|
hook->readwrite_entry.read_access = 1;
|
||||||
|
hook->readwrite_entry.write_access = 1;
|
||||||
|
hook->readwrite_entry.execute_access = 0;
|
||||||
|
|
||||||
|
hook->execute_entry.flags = 0;
|
||||||
|
hook->execute_entry.read_access = 0;
|
||||||
|
hook->execute_entry.write_access = 0;
|
||||||
|
hook->execute_entry.execute_access = 1;
|
||||||
|
hook->execute_entry.page_frame_number = memory::get_physical_address(&hook->fake_page) / PAGE_SIZE;
|
||||||
|
|
||||||
|
hook->target_page->flags = hook->readwrite_entry.flags;
|
||||||
|
|
||||||
|
return hook;
|
||||||
|
}
|
||||||
|
|
||||||
void ept::split_large_page(const uint64_t physical_address)
|
void ept::split_large_page(const uint64_t physical_address)
|
||||||
{
|
{
|
||||||
auto* target_entry = this->get_pml2_entry(physical_address);
|
auto* target_entry = this->get_pml2_entry(physical_address);
|
||||||
|
@ -32,10 +32,9 @@ namespace vmx
|
|||||||
|
|
||||||
pml1* target_page{};
|
pml1* target_page{};
|
||||||
pml1 original_entry{};
|
pml1 original_entry{};
|
||||||
pml1 shadow_entry{};
|
pml1 execute_entry{};
|
||||||
pml1 hooked_entry{};
|
pml1 readwrite_entry{};
|
||||||
|
|
||||||
uint8_t* trampoline{nullptr};
|
|
||||||
ept_hook* next_hook{nullptr};
|
ept_hook* next_hook{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,11 +53,14 @@ namespace vmx
|
|||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
void install_hook(PVOID TargetFunction, PVOID HookFunction, PVOID* OrigFunction);
|
void install_hook(void* destination, const void* source, size_t length);
|
||||||
void handle_violation(guest_context& guest_context) const;
|
void disable_all_hooks() const;
|
||||||
|
|
||||||
pml4* get_pml4();
|
void handle_violation(guest_context& guest_context) const;
|
||||||
const pml4* get_pml4() const;
|
void handle_misconfiguration(guest_context& guest_context) const;
|
||||||
|
|
||||||
|
ept_pointer get_ept_pointer() const;
|
||||||
|
void invalidate() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLSPEC_PAGE_ALIGN pml4 epml4[EPT_PML4E_ENTRY_COUNT]{};
|
DECLSPEC_PAGE_ALIGN pml4 epml4[EPT_PML4E_ENTRY_COUNT]{};
|
||||||
@ -74,7 +76,12 @@ namespace vmx
|
|||||||
|
|
||||||
ept_split* allocate_ept_split();
|
ept_split* allocate_ept_split();
|
||||||
ept_hook* allocate_ept_hook();
|
ept_hook* allocate_ept_hook();
|
||||||
|
ept_hook* find_ept_hook(uint64_t physical_address) const;
|
||||||
|
|
||||||
|
ept_hook* get_or_create_ept_hook(void* destination);
|
||||||
|
|
||||||
void split_large_page(uint64_t physical_address);
|
void split_large_page(uint64_t physical_address);
|
||||||
|
|
||||||
|
void install_page_hook(void* destination, const void* source, size_t length);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -159,6 +159,39 @@ bool hypervisor::is_enabled() const
|
|||||||
return is_hypervisor_present();
|
return is_hypervisor_present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hypervisor::install_ept_hook(void* destination, const void* source, const size_t length)
|
||||||
|
{
|
||||||
|
volatile long failures = 0;
|
||||||
|
thread::dispatch_on_all_cores([&]()
|
||||||
|
{
|
||||||
|
if (!this->try_install_ept_hook_on_core(destination, source, length))
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&failures);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return failures == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hypervisor::disable_all_ept_hooks() const
|
||||||
|
{
|
||||||
|
thread::dispatch_on_all_cores([&]()
|
||||||
|
{
|
||||||
|
auto* vm_state = this->get_current_vm_state();
|
||||||
|
if (!vm_state)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_state->ept.disable_all_hooks();
|
||||||
|
|
||||||
|
if (this->is_enabled())
|
||||||
|
{
|
||||||
|
vm_state->ept.invalidate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void hypervisor::enable()
|
void hypervisor::enable()
|
||||||
{
|
{
|
||||||
const auto cr3 = __readcr3();
|
const auto cr3 = __readcr3();
|
||||||
@ -263,7 +296,6 @@ bool enter_root_mode_on_cpu(vmx::state& vm_state)
|
|||||||
launch_context->vmx_on_physical_address = memory::get_physical_address(&vm_state.vmx_on);
|
launch_context->vmx_on_physical_address = memory::get_physical_address(&vm_state.vmx_on);
|
||||||
launch_context->vmcs_physical_address = memory::get_physical_address(&vm_state.vmcs);
|
launch_context->vmcs_physical_address = memory::get_physical_address(&vm_state.vmcs);
|
||||||
launch_context->msr_bitmap_physical_address = memory::get_physical_address(vm_state.msr_bitmap);
|
launch_context->msr_bitmap_physical_address = memory::get_physical_address(vm_state.msr_bitmap);
|
||||||
launch_context->ept_pml4_physical_address = memory::get_physical_address(vm_state.ept.get_pml4());
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Update CR0 with the must-be-zero and must-be-one requirements
|
// Update CR0 with the must-be-zero and must-be-one requirements
|
||||||
@ -498,7 +530,7 @@ void vmx_handle_vmx(vmx::guest_context& guest_context)
|
|||||||
__vmx_vmwrite(VMCS_GUEST_RFLAGS, guest_context.guest_e_flags);
|
__vmx_vmwrite(VMCS_GUEST_RFLAGS, guest_context.guest_e_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vmx_dispatch_vm_exit(vmx::guest_context& guest_context, vmx::state& vm_state)
|
void vmx_dispatch_vm_exit(vmx::guest_context& guest_context, const vmx::state& vm_state)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// This is the generic VM-Exit handler. Decode the reason for the exit and
|
// This is the generic VM-Exit handler. Decode the reason for the exit and
|
||||||
@ -532,6 +564,10 @@ void vmx_dispatch_vm_exit(vmx::guest_context& guest_context, vmx::state& vm_stat
|
|||||||
break;
|
break;
|
||||||
case VMX_EXIT_REASON_EPT_VIOLATION:
|
case VMX_EXIT_REASON_EPT_VIOLATION:
|
||||||
vm_state.ept.handle_violation(guest_context);
|
vm_state.ept.handle_violation(guest_context);
|
||||||
|
break;
|
||||||
|
case VMX_EXIT_REASON_EPT_MISCONFIGURATION:
|
||||||
|
vm_state.ept.handle_misconfiguration(guest_context);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -650,12 +686,7 @@ void setup_vmcs_for_cpu(vmx::state& vm_state)
|
|||||||
//
|
//
|
||||||
if (launch_context->ept_controls.flags != 0)
|
if (launch_context->ept_controls.flags != 0)
|
||||||
{
|
{
|
||||||
ept_pointer vmx_eptp{};
|
const auto vmx_eptp = vm_state.ept.get_ept_pointer();
|
||||||
vmx_eptp.flags = 0;
|
|
||||||
vmx_eptp.page_walk_length = 3;
|
|
||||||
vmx_eptp.memory_type = MEMORY_TYPE_WRITE_BACK;
|
|
||||||
vmx_eptp.page_frame_number = launch_context->ept_pml4_physical_address / PAGE_SIZE;
|
|
||||||
|
|
||||||
__vmx_vmwrite(VMCS_CTRL_EPT_POINTER, vmx_eptp.flags);
|
__vmx_vmwrite(VMCS_CTRL_EPT_POINTER, vmx_eptp.flags);
|
||||||
__vmx_vmwrite(VMCS_CTRL_VIRTUAL_PROCESSOR_IDENTIFIER, 1);
|
__vmx_vmwrite(VMCS_CTRL_VIRTUAL_PROCESSOR_IDENTIFIER, 1);
|
||||||
}
|
}
|
||||||
@ -969,10 +1000,45 @@ void hypervisor::free_vm_states()
|
|||||||
this->vm_state_count_ = 0;
|
this->vm_state_count_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hypervisor::try_install_ept_hook_on_core(void* destination, const void* source, const size_t length)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this->install_ept_hook_on_core(destination, source, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
debug_log("Failed to install ept hook on core %d: %s\n", thread::get_processor_index(), e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
debug_log("Failed to install ept hook on core %d.\n", thread::get_processor_index());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hypervisor::install_ept_hook_on_core(void* destination, const void* source, const size_t length)
|
||||||
|
{
|
||||||
|
auto* vm_state = this->get_current_vm_state();
|
||||||
|
if (!vm_state)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("No vm state available");
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_state->ept.install_hook(destination, source, length);
|
||||||
|
|
||||||
|
if (this->is_enabled())
|
||||||
|
{
|
||||||
|
vm_state->ept.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vmx::state* hypervisor::get_current_vm_state() const
|
vmx::state* hypervisor::get_current_vm_state() const
|
||||||
{
|
{
|
||||||
const auto current_core = thread::get_processor_index();
|
const auto current_core = thread::get_processor_index();
|
||||||
if (current_core >= this->vm_state_count_)
|
if (!this->vm_states_ || current_core >= this->vm_state_count_)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,9 @@ public:
|
|||||||
|
|
||||||
bool is_enabled() const;
|
bool is_enabled() const;
|
||||||
|
|
||||||
|
bool install_ept_hook(void* destination, const void* source, size_t length);
|
||||||
|
void disable_all_ept_hooks() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t vm_state_count_{0};
|
uint32_t vm_state_count_{0};
|
||||||
vmx::state** vm_states_{nullptr};
|
vmx::state** vm_states_{nullptr};
|
||||||
@ -30,5 +33,8 @@ private:
|
|||||||
void allocate_vm_states();
|
void allocate_vm_states();
|
||||||
void free_vm_states();
|
void free_vm_states();
|
||||||
|
|
||||||
|
bool try_install_ept_hook_on_core(void* destination, const void* source, size_t length);
|
||||||
|
void install_ept_hook_on_core(void* destination, const void* source, size_t length);
|
||||||
|
|
||||||
vmx::state* get_current_vm_state() const;
|
vmx::state* get_current_vm_state() const;
|
||||||
};
|
};
|
||||||
|
@ -116,6 +116,14 @@ PsGetProcessPeb(
|
|||||||
IN PEPROCESS Process
|
IN PEPROCESS Process
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
NTKERNELAPI
|
||||||
|
PCSTR
|
||||||
|
PsGetProcessImageFileName(
|
||||||
|
__in PEPROCESS Process
|
||||||
|
);
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|
||||||
__kernel_entry NTSYSCALLAPI
|
__kernel_entry NTSYSCALLAPI
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
namespace process
|
namespace process
|
||||||
{
|
{
|
||||||
process_handle::process_handle(const PEPROCESS handle)
|
process_handle::process_handle(const PEPROCESS handle, const bool own)
|
||||||
: handle_(handle)
|
: own_(own), handle_(handle)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +26,9 @@ namespace process
|
|||||||
if (this != &obj)
|
if (this != &obj)
|
||||||
{
|
{
|
||||||
this->release();
|
this->release();
|
||||||
|
this->own_ = obj.own_;
|
||||||
this->handle_ = obj.handle_;
|
this->handle_ = obj.handle_;
|
||||||
|
obj.own_ = false;
|
||||||
obj.handle_ = nullptr;
|
obj.handle_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,13 +53,25 @@ namespace process
|
|||||||
return KeWaitForSingleObject(this->handle_, Executive, KernelMode, FALSE, &zero_time) != STATUS_WAIT_0;
|
return KeWaitForSingleObject(this->handle_, Executive, KernelMode, FALSE, &zero_time) != STATUS_WAIT_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* process_handle::get_image_filename() const
|
||||||
|
{
|
||||||
|
if (!this->handle_)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PsGetProcessImageFileName(this->handle_);
|
||||||
|
}
|
||||||
|
|
||||||
void process_handle::release()
|
void process_handle::release()
|
||||||
{
|
{
|
||||||
if (this->handle_)
|
if (this->own_ && this->handle_)
|
||||||
{
|
{
|
||||||
ObDereferenceObject(this->handle_);
|
ObDereferenceObject(this->handle_);
|
||||||
this->handle_ = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->handle_ = nullptr;
|
||||||
|
this->own_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_handle find_process_by_id(const uint32_t process_id)
|
process_handle find_process_by_id(const uint32_t process_id)
|
||||||
@ -68,7 +82,12 @@ namespace process
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return process_handle{process};
|
return process_handle{process, true};
|
||||||
|
}
|
||||||
|
|
||||||
|
process_handle get_current_process()
|
||||||
|
{
|
||||||
|
return process_handle{PsGetCurrentProcess(), false};
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_process_attacher::scoped_process_attacher(const process_handle& process)
|
scoped_process_attacher::scoped_process_attacher(const process_handle& process)
|
||||||
|
@ -6,7 +6,7 @@ namespace process
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
process_handle() = default;
|
process_handle() = default;
|
||||||
process_handle(PEPROCESS handle);
|
process_handle(PEPROCESS handle, bool own = true);
|
||||||
~process_handle();
|
~process_handle();
|
||||||
|
|
||||||
process_handle(process_handle&& obj) noexcept;
|
process_handle(process_handle&& obj) noexcept;
|
||||||
@ -20,13 +20,17 @@ namespace process
|
|||||||
|
|
||||||
bool is_alive() const;
|
bool is_alive() const;
|
||||||
|
|
||||||
|
const char* get_image_filename() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool own_{true};
|
||||||
PEPROCESS handle_{nullptr};
|
PEPROCESS handle_{nullptr};
|
||||||
|
|
||||||
void release();
|
void release();
|
||||||
};
|
};
|
||||||
|
|
||||||
process_handle find_process_by_id(uint32_t process_id);
|
process_handle find_process_by_id(uint32_t process_id);
|
||||||
|
process_handle get_current_process();
|
||||||
|
|
||||||
class scoped_process_attacher
|
class scoped_process_attacher
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,6 @@ namespace vmx
|
|||||||
uint64_t vmx_on_physical_address;
|
uint64_t vmx_on_physical_address;
|
||||||
uint64_t vmcs_physical_address;
|
uint64_t vmcs_physical_address;
|
||||||
uint64_t msr_bitmap_physical_address;
|
uint64_t msr_bitmap_physical_address;
|
||||||
uint64_t ept_pml4_physical_address;
|
|
||||||
ia32_vmx_procbased_ctls2_register ept_controls;
|
ia32_vmx_procbased_ctls2_register ept_controls;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user