mirror of
https://github.com/momo5502/hypervisor.git
synced 2025-07-03 17:51:52 +00:00
Ept hooking
This commit is contained in:
@ -4,10 +4,159 @@
|
||||
#include "irp.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "hypervisor.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "process.hpp"
|
||||
|
||||
#define DOS_DEV_NAME L"\\DosDevices\\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
|
||||
{
|
||||
public:
|
||||
@ -19,11 +168,14 @@ public:
|
||||
, irp_(driver_object, DEV_NAME, DOS_DEV_NAME)
|
||||
{
|
||||
debug_log("Driver started\n");
|
||||
this->trampoline = HookCreateFile(this->hypervisor_);
|
||||
}
|
||||
|
||||
~global_driver()
|
||||
{
|
||||
debug_log("Unloading driver\n");
|
||||
this->hypervisor_.disable_all_ept_hooks();
|
||||
memory::free_non_paged_memory(this->trampoline);
|
||||
}
|
||||
|
||||
global_driver(global_driver&&) noexcept = delete;
|
||||
@ -41,6 +193,7 @@ private:
|
||||
hypervisor hypervisor_{};
|
||||
sleep_callback sleep_callback_{};
|
||||
irp irp_{};
|
||||
void* trampoline{nullptr};
|
||||
|
||||
void sleep_notification(const sleep_callback::type type)
|
||||
{
|
||||
|
Reference in New Issue
Block a user