From fd03a49992f79618759130f9033d4ed5b48a85bd Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 13 Apr 2022 19:06:38 +0200 Subject: [PATCH] Move ept logic into ept module --- CMakeLists.txt | 3 + src/driver/ept.cpp | 168 ++++++++++++++++++++++++++++++++++++++ src/driver/ept.hpp | 15 ++++ src/driver/hypervisor.cpp | 145 +------------------------------- src/driver/memory.cpp | 8 ++ src/driver/memory.hpp | 17 ++++ src/driver/vmx.hpp | 17 ---- src/runner/main.cpp | 3 +- 8 files changed, 215 insertions(+), 161 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b30d1e..f898e63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,9 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) ########################################## +set(WDK_WINVER "0x0603" CACHE STRING "Default WINVER for WDK targets") + +########################################## set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$:Debug>) if(MSVC) diff --git a/src/driver/ept.cpp b/src/driver/ept.cpp index a5f6dd9..d6b6559 100644 --- a/src/driver/ept.cpp +++ b/src/driver/ept.cpp @@ -1,8 +1,102 @@ #include "std_include.hpp" #include "ept.hpp" +#include "memory.hpp" + +#define MTRR_PAGE_SIZE 4096 +#define MTRR_PAGE_MASK (~(MTRR_PAGE_SIZE-1)) + namespace vmx { + namespace + { + struct mtrr_range + { + uint32_t enabled; + uint32_t type; + uint64_t physical_address_min; + uint64_t physical_address_max; + }; + + using mtrr_list = mtrr_range[16]; + + void initialize_mtrr(mtrr_list& mtrr_data) + { + // + // Read the capabilities mask + // + ia32_mtrr_capabilities_register mtrr_capabilities{}; + mtrr_capabilities.flags = __readmsr(IA32_MTRR_CAPABILITIES); + + // + // Iterate over each variable MTRR + // + for (auto i = 0u; i < mtrr_capabilities.variable_range_count; i++) + { + // + // Capture the value + // + ia32_mtrr_physbase_register mtrr_base{}; + ia32_mtrr_physmask_register mtrr_mask{}; + + mtrr_base.flags = __readmsr(IA32_MTRR_PHYSBASE0 + i * 2); + mtrr_mask.flags = __readmsr(IA32_MTRR_PHYSMASK0 + i * 2); + + // + // Check if the MTRR is enabled + // + mtrr_data[i].type = static_cast(mtrr_base.type); + mtrr_data[i].enabled = static_cast(mtrr_mask.valid); + if (mtrr_data[i].enabled != FALSE) + { + // + // Set the base + // + mtrr_data[i].physical_address_min = mtrr_base.page_frame_number * + MTRR_PAGE_SIZE; + + // + // Compute the length + // + unsigned long bit; + _BitScanForward64(&bit, mtrr_mask.page_frame_number * MTRR_PAGE_SIZE); + mtrr_data[i].physical_address_max = mtrr_data[i]. + physical_address_min + + (1ULL << bit) - 1; + } + } + } + + uint32_t mtrr_adjust_effective_memory_type(const mtrr_list& mtrr_data, const uint64_t large_page_address, + uint32_t candidate_memory_type) + { + // + // Loop each MTRR range + // + for (const auto& mtrr_entry : mtrr_data) + { + // + // Check if it's active + // + if (!mtrr_entry.enabled) + { + continue; + } + // + // Check if this large page falls within the boundary. If a single + // physical page (4KB) touches it, we need to override the entire 2MB. + // + if (((large_page_address + (2_mb - 1)) >= mtrr_entry.physical_address_min) && + (large_page_address <= mtrr_entry.physical_address_max)) + { + candidate_memory_type = mtrr_entry.type; + } + } + + return candidate_memory_type; + } + } + ept::ept() { } @@ -10,4 +104,78 @@ namespace vmx ept::~ept() { } + + void ept::initialize() + { + mtrr_list mtrr_data{}; + initialize_mtrr(mtrr_data); + + // + // Fill out the EPML4E which covers the first 512GB of RAM + // + this->epml4[0].read_access = 1; + this->epml4[0].write_access = 1; + this->epml4[0].execute_access = 1; + this->epml4[0].page_frame_number = memory::get_physical_address(&this->epdpt) / + PAGE_SIZE; + + // + // Fill out a RWX PDPTE + // + epdpte temp_epdpte; + temp_epdpte.flags = 0; + temp_epdpte.read_access = 1; + temp_epdpte.write_access = 1; + temp_epdpte.execute_access = 1; + + // + // Construct EPT identity map for every 1GB of RAM + // + __stosq(reinterpret_cast(this->epdpt), temp_epdpte.flags, EPT_PDPTE_ENTRY_COUNT); + for (auto i = 0; i < EPT_PDPTE_ENTRY_COUNT; i++) + { + // + // Set the page frame number of the PDE table + // + this->epdpt[i].page_frame_number = memory::get_physical_address(&this->epde[i][0]) / PAGE_SIZE; + } + + // + // Fill out a RWX Large PDE + // + epde_2mb temp_epde{}; + temp_epde.flags = 0; + temp_epde.read_access = 1; + temp_epde.write_access = 1; + temp_epde.execute_access = 1; + temp_epde.large_page = 1; + + // + // Loop every 1GB of RAM (described by the PDPTE) + // + __stosq(reinterpret_cast(this->epde), temp_epde.flags, + EPT_PDPTE_ENTRY_COUNT * EPT_PDE_ENTRY_COUNT); + for (auto i = 0; i < EPT_PDPTE_ENTRY_COUNT; i++) + { + // + // Construct EPT identity map for every 2MB of RAM + // + for (auto j = 0; j < EPT_PDE_ENTRY_COUNT; j++) + { + this->epde[i][j].page_frame_number = (i * 512) + j; + this->epde[i][j].memory_type = mtrr_adjust_effective_memory_type( + mtrr_data, this->epde[i][j].page_frame_number * 2_mb, MEMORY_TYPE_WRITE_BACK); + } + } + } + + ept_pml4* ept::get_pml4() + { + return this->epml4; + } + + const ept_pml4* ept::get_pml4() const + { + return this->epml4; + } } diff --git a/src/driver/ept.hpp b/src/driver/ept.hpp index 2f88186..b31ec2a 100644 --- a/src/driver/ept.hpp +++ b/src/driver/ept.hpp @@ -1,5 +1,7 @@ #pragma once +#define DECLSPEC_PAGE_ALIGN DECLSPEC_ALIGN(PAGE_SIZE) + namespace vmx { class ept @@ -12,5 +14,18 @@ namespace vmx ept(const ept&) = delete; ept& operator=(ept&&) = delete; ept& operator=(const ept&) = delete; + + void initialize(); + + void install_hook(void* virtual_address, void* data, size_t length); + void install_hook(uint64_t physical_address, void* data, size_t length); + + ept_pml4* get_pml4(); + const ept_pml4* get_pml4() const; + + private: + DECLSPEC_PAGE_ALIGN ept_pml4 epml4[EPT_PML4E_ENTRY_COUNT]{}; + DECLSPEC_PAGE_ALIGN epdpte epdpt[EPT_PDPTE_ENTRY_COUNT]{}; + DECLSPEC_PAGE_ALIGN epde_2mb epde[EPT_PDPTE_ENTRY_COUNT][EPT_PDE_ENTRY_COUNT]{}; }; } diff --git a/src/driver/hypervisor.cpp b/src/driver/hypervisor.cpp index ca74524..49e554d 100644 --- a/src/driver/hypervisor.cpp +++ b/src/driver/hypervisor.cpp @@ -200,146 +200,6 @@ bool hypervisor::try_enable_core(const uint64_t system_directory_table_base) } } -#define MTRR_PAGE_SIZE 4096 -#define MTRR_PAGE_MASK (~(MTRR_PAGE_SIZE-1)) - -void initialize_mtrr(vmx::launch_context& launch_context) -{ - // - // Read the capabilities mask - // - ia32_mtrr_capabilities_register mtrr_capabilities{}; - mtrr_capabilities.flags = __readmsr(IA32_MTRR_CAPABILITIES); - - // - // Iterate over each variable MTRR - // - for (auto i = 0u; i < mtrr_capabilities.variable_range_count; i++) - { - // - // Capture the value - // - ia32_mtrr_physbase_register mtrr_base{}; - ia32_mtrr_physmask_register mtrr_mask{}; - - mtrr_base.flags = __readmsr(IA32_MTRR_PHYSBASE0 + i * 2); - mtrr_mask.flags = __readmsr(IA32_MTRR_PHYSMASK0 + i * 2); - - // - // Check if the MTRR is enabled - // - launch_context.mtrr_data[i].type = static_cast(mtrr_base.type); - launch_context.mtrr_data[i].enabled = static_cast(mtrr_mask.valid); - if (launch_context.mtrr_data[i].enabled != FALSE) - { - // - // Set the base - // - launch_context.mtrr_data[i].physical_address_min = mtrr_base.page_frame_number * - MTRR_PAGE_SIZE; - - // - // Compute the length - // - unsigned long bit; - _BitScanForward64(&bit, mtrr_mask.page_frame_number * MTRR_PAGE_SIZE); - launch_context.mtrr_data[i].physical_address_max = launch_context.mtrr_data[i]. - physical_address_min + - (1ULL << bit) - 1; - } - } -} - -uint32_t mtrr_adjust_effective_memory_type(vmx::launch_context& launch_context, const uint64_t large_page_address, - uint32_t candidate_memory_type) -{ - // - // Loop each MTRR range - // - for (const auto& mtrr_entry : launch_context.mtrr_data) - { - // - // Check if it's active - // - if (!mtrr_entry.enabled) - { - continue; - } - // - // Check if this large page falls within the boundary. If a single - // physical page (4KB) touches it, we need to override the entire 2MB. - // - if (((large_page_address + (_2MB - 1)) >= mtrr_entry.physical_address_min) && - (large_page_address <= mtrr_entry.physical_address_max)) - { - candidate_memory_type = mtrr_entry.type; - } - } - - return candidate_memory_type; -} - -void initialize_ept(vmx::state& vm_state) -{ - // - // Fill out the EPML4E which covers the first 512GB of RAM - // - vm_state.epml4[0].read_access = 1; - vm_state.epml4[0].write_access = 1; - vm_state.epml4[0].execute_access = 1; - vm_state.epml4[0].page_frame_number = memory::get_physical_address(&vm_state.epdpt) / - PAGE_SIZE; - - // - // Fill out a RWX PDPTE - // - epdpte temp_epdpte; - temp_epdpte.flags = 0; - temp_epdpte.read_access = 1; - temp_epdpte.write_access = 1; - temp_epdpte.execute_access = 1; - - // - // Construct EPT identity map for every 1GB of RAM - // - __stosq(reinterpret_cast(vm_state.epdpt), temp_epdpte.flags, EPT_PDPTE_ENTRY_COUNT); - for (auto i = 0; i < EPT_PDPTE_ENTRY_COUNT; i++) - { - // - // Set the page frame number of the PDE table - // - vm_state.epdpt[i].page_frame_number = memory::get_physical_address(&vm_state.epde[i][0]) / PAGE_SIZE; - } - - // - // Fill out a RWX Large PDE - // - epde_2mb temp_epde{}; - temp_epde.flags = 0; - temp_epde.read_access = 1; - temp_epde.write_access = 1; - temp_epde.execute_access = 1; - temp_epde.large_page = 1; - - // - // Loop every 1GB of RAM (described by the PDPTE) - // - __stosq(reinterpret_cast(vm_state.epde), temp_epde.flags, EPT_PDPTE_ENTRY_COUNT * EPT_PDE_ENTRY_COUNT); - for (auto i = 0; i < EPT_PDPTE_ENTRY_COUNT; i++) - { - // - // Construct EPT identity map for every 2MB of RAM - // - for (auto j = 0; j < EPT_PDE_ENTRY_COUNT; j++) - { - vm_state.epde[i][j].page_frame_number = (i * 512) + j; - vm_state.epde[i][j].memory_type = mtrr_adjust_effective_memory_type( - vm_state.launch_context, vm_state.epde[i][j].page_frame_number * _2MB, MEMORY_TYPE_WRITE_BACK); - } - } -} - - bool enter_root_mode_on_cpu(vmx::state& vm_state) { auto* launch_context = &vm_state.launch_context; @@ -403,7 +263,7 @@ 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->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->ept_pml4_physical_address = memory::get_physical_address(&vm_state.epml4); + 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 @@ -1013,8 +873,7 @@ void initialize_msrs(vmx::launch_context& launch_context) [[ noreturn ]] void launch_hypervisor(vmx::state& vm_state) { initialize_msrs(vm_state.launch_context); - initialize_mtrr(vm_state.launch_context); - initialize_ept(vm_state); + vm_state.ept.initialize(); if (!enter_root_mode_on_cpu(vm_state)) { diff --git a/src/driver/memory.cpp b/src/driver/memory.cpp index 95b447f..fc904b9 100644 --- a/src/driver/memory.cpp +++ b/src/driver/memory.cpp @@ -105,6 +105,14 @@ namespace memory } } + void copy_physical_data(const uint64_t address, void* destination, const size_t length) + { + size_t result{}; + MM_COPY_ADDRESS copy_address{}; + copy_address.PhysicalAddress.QuadPart = static_cast(address); + MmCopyMemory(destination, copy_address, length, MM_COPY_MEMORY_PHYSICAL, &result); + } + uint64_t query_process_physical_page(const uint32_t process_id, void* address, uint8_t buffer[PAGE_SIZE]) { diff --git a/src/driver/memory.hpp b/src/driver/memory.hpp index 6c19381..a729606 100644 --- a/src/driver/memory.hpp +++ b/src/driver/memory.hpp @@ -23,6 +23,8 @@ namespace memory _IRQL_requires_max_(DISPATCH_LEVEL) void free_non_paged_memory(void* memory); + void copy_physical_data(uint64_t address, void* destination, size_t length); + uint64_t query_process_physical_page(uint32_t process_id, void* address, uint8_t buffer[PAGE_SIZE]); template @@ -47,3 +49,18 @@ namespace memory } } } + +inline uint64_t operator"" _kb(const uint64_t size) +{ + return size * 1024; +} + +inline uint64_t operator"" _mb(const uint64_t size) +{ + return operator"" _kb(size * 1024); +} + +inline uint64_t operator"" _gb(const uint64_t size) +{ + return operator"" _mb(size * 1024); +} diff --git a/src/driver/vmx.hpp b/src/driver/vmx.hpp index 05bbbc4..ae30505 100644 --- a/src/driver/vmx.hpp +++ b/src/driver/vmx.hpp @@ -1,9 +1,6 @@ #pragma once #include "ept.hpp" -#define _1GB (1 * 1024 * 1024 * 1024) -#define _2MB (2 * 1024 * 1024) - #define HYPERV_HYPERVISOR_PRESENT_BIT 0x80000000 #define HYPERV_CPUID_INTERFACE 0x40000001 @@ -30,23 +27,12 @@ namespace vmx segment_descriptor_register_64 gdtr; }; - struct mtrr_range - { - uint32_t enabled; - uint32_t type; - uint64_t physical_address_min; - uint64_t physical_address_max; - }; - -#define DECLSPEC_PAGE_ALIGN DECLSPEC_ALIGN(PAGE_SIZE) - struct launch_context { special_registers special_registers; CONTEXT context_frame; uint64_t system_directory_table_base; ULARGE_INTEGER msr_data[17]; - mtrr_range mtrr_data[16]; uint64_t vmx_on_physical_address; uint64_t vmcs_physical_address; uint64_t msr_bitmap_physical_address; @@ -63,9 +49,6 @@ namespace vmx }; DECLSPEC_PAGE_ALIGN uint8_t msr_bitmap[PAGE_SIZE]{}; - DECLSPEC_PAGE_ALIGN ept_pml4 epml4[EPT_PML4E_ENTRY_COUNT]{}; - DECLSPEC_PAGE_ALIGN epdpte epdpt[EPT_PDPTE_ENTRY_COUNT]{}; - DECLSPEC_PAGE_ALIGN epde_2mb epde[EPT_PDPTE_ENTRY_COUNT][EPT_PDE_ENTRY_COUNT]{}; DECLSPEC_PAGE_ALIGN vmcs vmx_on{}; DECLSPEC_PAGE_ALIGN vmcs vmcs{}; diff --git a/src/runner/main.cpp b/src/runner/main.cpp index 718152f..55129a7 100644 --- a/src/runner/main.cpp +++ b/src/runner/main.cpp @@ -53,7 +53,7 @@ void unsafe_main(const int /*argc*/, char* /*argv*/[]) (void)driver_device.send(HELLO_DRV_IOCTL, input); MessageBoxA(0, "Service started!", 0, 0); - + /* hook_request hook_request{}; hook_request.process_id = GetCurrentProcessId(); hook_request.target_address = "My Message!"; @@ -64,6 +64,7 @@ void unsafe_main(const int /*argc*/, char* /*argv*/[]) (void)driver_device.send(HOOK_DRV_IOCTL, input); MessageBoxA(0, "Press ok to exit!", 0, 0); + */ } int main(const int argc, char* argv[])