34 changed files with 6179 additions and 1 deletions
@ -0,0 +1,21 @@
|
||||
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. |
@ -1,3 +1,5 @@
|
||||
# nasa-mapper |
||||
|
||||
map a driver into the current process and not into the kernel |
||||
map a driver into specific processes only, with zero allocations in the kernel. |
||||
|
||||
<center><img src="https://githacks.org/nasa-tech/nasa-mapper/raw/a84adea8a35af81a95e1c78b72133b5c856f9c64/unknown.png"/></center> |
@ -0,0 +1,173 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" 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> |
||||
<ProjectConfiguration Include="Debug|ARM"> |
||||
<Configuration>Debug</Configuration> |
||||
<Platform>ARM</Platform> |
||||
</ProjectConfiguration> |
||||
<ProjectConfiguration Include="Release|ARM"> |
||||
<Configuration>Release</Configuration> |
||||
<Platform>ARM</Platform> |
||||
</ProjectConfiguration> |
||||
<ProjectConfiguration Include="Debug|ARM64"> |
||||
<Configuration>Debug</Configuration> |
||||
<Platform>ARM64</Platform> |
||||
</ProjectConfiguration> |
||||
<ProjectConfiguration Include="Release|ARM64"> |
||||
<Configuration>Release</Configuration> |
||||
<Platform>ARM64</Platform> |
||||
</ProjectConfiguration> |
||||
</ItemGroup> |
||||
<PropertyGroup Label="Globals"> |
||||
<ProjectGuid>{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}</ProjectGuid> |
||||
<TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid> |
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
||||
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion> |
||||
<Configuration>Debug</Configuration> |
||||
<Platform Condition="'$(Platform)' == ''">Win32</Platform> |
||||
<RootNamespace>drv_example</RootNamespace> |
||||
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
||||
<TargetVersion>Windows10</TargetVersion> |
||||
<UseDebugLibraries>true</UseDebugLibraries> |
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> |
||||
<ConfigurationType>Driver</ConfigurationType> |
||||
<DriverType>KMDF</DriverType> |
||||
<DriverTargetPlatform>Universal</DriverTargetPlatform> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
||||
<TargetVersion>Windows10</TargetVersion> |
||||
<UseDebugLibraries>false</UseDebugLibraries> |
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> |
||||
<ConfigurationType>Driver</ConfigurationType> |
||||
<DriverType>KMDF</DriverType> |
||||
<DriverTargetPlatform>Universal</DriverTargetPlatform> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
||||
<TargetVersion>Windows10</TargetVersion> |
||||
<UseDebugLibraries>true</UseDebugLibraries> |
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> |
||||
<ConfigurationType>Driver</ConfigurationType> |
||||
<DriverType>KMDF</DriverType> |
||||
<DriverTargetPlatform>Universal</DriverTargetPlatform> |
||||
<Driver_SpectreMitigation>false</Driver_SpectreMitigation> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
||||
<TargetVersion>Windows10</TargetVersion> |
||||
<UseDebugLibraries>false</UseDebugLibraries> |
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> |
||||
<ConfigurationType>Driver</ConfigurationType> |
||||
<DriverType>KMDF</DriverType> |
||||
<DriverTargetPlatform>Universal</DriverTargetPlatform> |
||||
<Driver_SpectreMitigation>false</Driver_SpectreMitigation> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration"> |
||||
<TargetVersion>Windows10</TargetVersion> |
||||
<UseDebugLibraries>true</UseDebugLibraries> |
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> |
||||
<ConfigurationType>Driver</ConfigurationType> |
||||
<DriverType>KMDF</DriverType> |
||||
<DriverTargetPlatform>Universal</DriverTargetPlatform> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration"> |
||||
<TargetVersion>Windows10</TargetVersion> |
||||
<UseDebugLibraries>false</UseDebugLibraries> |
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> |
||||
<ConfigurationType>Driver</ConfigurationType> |
||||
<DriverType>KMDF</DriverType> |
||||
<DriverTargetPlatform>Universal</DriverTargetPlatform> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration"> |
||||
<TargetVersion>Windows10</TargetVersion> |
||||
<UseDebugLibraries>true</UseDebugLibraries> |
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> |
||||
<ConfigurationType>Driver</ConfigurationType> |
||||
<DriverType>KMDF</DriverType> |
||||
<DriverTargetPlatform>Universal</DriverTargetPlatform> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration"> |
||||
<TargetVersion>Windows10</TargetVersion> |
||||
<UseDebugLibraries>false</UseDebugLibraries> |
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> |
||||
<ConfigurationType>Driver</ConfigurationType> |
||||
<DriverType>KMDF</DriverType> |
||||
<DriverTargetPlatform>Universal</DriverTargetPlatform> |
||||
</PropertyGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
||||
<ImportGroup Label="ExtensionSettings"> |
||||
</ImportGroup> |
||||
<ImportGroup Label="PropertySheets"> |
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||
</ImportGroup> |
||||
<PropertyGroup Label="UserMacros" /> |
||||
<PropertyGroup /> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> |
||||
<EnableInf2cat>false</EnableInf2cat> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> |
||||
<EnableInf2cat>false</EnableInf2cat> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> |
||||
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> |
||||
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> |
||||
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> |
||||
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> |
||||
</PropertyGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||
<ClCompile> |
||||
<LanguageStandard>stdcpp17</LanguageStandard> |
||||
</ClCompile> |
||||
<Link> |
||||
<EntryPointSymbol>driver_entry</EntryPointSymbol> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||
<ClCompile> |
||||
<LanguageStandard>stdcpp17</LanguageStandard> |
||||
</ClCompile> |
||||
<Link> |
||||
<EntryPointSymbol>driver_entry</EntryPointSymbol> |
||||
</Link> |
||||
</ItemDefinitionGroup> |
||||
<ItemGroup> |
||||
<FilesToPackage Include="$(TargetPath)" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<ClCompile Include="main.cpp" /> |
||||
</ItemGroup> |
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
||||
<ImportGroup Label="ExtensionTargets"> |
||||
</ImportGroup> |
||||
</Project> |
@ -0,0 +1,14 @@
|
||||
<?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;def;odl;idl;hpj;bat;asm;asmx</Extensions> |
||||
</Filter> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<ClCompile Include="main.cpp"> |
||||
<Filter>Source Files</Filter> |
||||
</ClCompile> |
||||
</ItemGroup> |
||||
</Project> |
@ -0,0 +1,8 @@
|
||||
#include <ntifs.h> |
||||
|
||||
NTSTATUS driver_entry(void* data) |
||||
{ |
||||
DbgPrint("> Hello World"); |
||||
DbgPrint("> data -> 0x%p\n", data); |
||||
return STATUS_SUCCESS; |
||||
} |
@ -0,0 +1,83 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00 |
||||
# Visual Studio Version 16 |
||||
VisualStudioVersion = 16.0.30011.22 |
||||
MinimumVisualStudioVersion = 10.0.40219.1 |
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nasa-mapper", "nasa-mapper\nasa-mapper.vcxproj", "{A72CD068-E350-41C9-A4E5-DC7810575EA2}" |
||||
EndProject |
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "um-example", "um-example\um-example.vcxproj", "{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}" |
||||
EndProject |
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "drv-example", "drv-example\drv-example.vcxproj", "{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}" |
||||
EndProject |
||||
Global |
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
||||
Debug|ARM = Debug|ARM |
||||
Debug|ARM64 = Debug|ARM64 |
||||
Debug|x64 = Debug|x64 |
||||
Debug|x86 = Debug|x86 |
||||
Release|ARM = Release|ARM |
||||
Release|ARM64 = Release|ARM64 |
||||
Release|x64 = Release|x64 |
||||
Release|x86 = Release|x86 |
||||
EndGlobalSection |
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Debug|ARM.ActiveCfg = Debug|ARM |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Debug|ARM.Build.0 = Debug|ARM |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Debug|ARM64.ActiveCfg = Debug|ARM64 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Debug|ARM64.Build.0 = Debug|ARM64 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Debug|x64.ActiveCfg = Debug|x64 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Debug|x64.Build.0 = Debug|x64 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Debug|x86.ActiveCfg = Debug|Win32 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Debug|x86.Build.0 = Debug|Win32 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Release|ARM.ActiveCfg = Release|ARM |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Release|ARM.Build.0 = Release|ARM |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Release|ARM64.ActiveCfg = Release|ARM64 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Release|ARM64.Build.0 = Release|ARM64 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Release|x64.ActiveCfg = Release|x64 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Release|x64.Build.0 = Release|x64 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Release|x86.ActiveCfg = Release|Win32 |
||||
{A72CD068-E350-41C9-A4E5-DC7810575EA2}.Release|x86.Build.0 = Release|Win32 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Debug|ARM.ActiveCfg = Debug|Win32 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Debug|ARM64.ActiveCfg = Debug|Win32 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Debug|x64.ActiveCfg = Debug|x64 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Debug|x64.Build.0 = Debug|x64 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Debug|x86.ActiveCfg = Debug|Win32 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Debug|x86.Build.0 = Debug|Win32 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Release|ARM.ActiveCfg = Release|Win32 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Release|ARM64.ActiveCfg = Release|Win32 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Release|x64.ActiveCfg = Release|x64 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Release|x64.Build.0 = Release|x64 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Release|x86.ActiveCfg = Release|Win32 |
||||
{44064ACC-9743-4DC6-84AA-B4E2A3D8BF4D}.Release|x86.Build.0 = Release|Win32 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|ARM.ActiveCfg = Debug|ARM |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|ARM.Build.0 = Debug|ARM |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|ARM.Deploy.0 = Debug|ARM |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|ARM64.ActiveCfg = Debug|ARM64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|ARM64.Build.0 = Debug|ARM64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|ARM64.Deploy.0 = Debug|ARM64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|x64.ActiveCfg = Debug|x64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|x64.Build.0 = Debug|x64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|x64.Deploy.0 = Debug|x64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|x86.ActiveCfg = Debug|Win32 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|x86.Build.0 = Debug|Win32 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Debug|x86.Deploy.0 = Debug|Win32 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|ARM.ActiveCfg = Release|ARM |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|ARM.Build.0 = Release|ARM |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|ARM.Deploy.0 = Release|ARM |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|ARM64.ActiveCfg = Release|ARM64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|ARM64.Build.0 = Release|ARM64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|ARM64.Deploy.0 = Release|ARM64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|x64.ActiveCfg = Release|x64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|x64.Build.0 = Release|x64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|x64.Deploy.0 = Release|x64 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|x86.ActiveCfg = Release|Win32 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|x86.Build.0 = Release|Win32 |
||||
{AE6ABACF-E2C2-49CC-B973-7B2B1C6E76B4}.Release|x86.Deploy.0 = Release|Win32 |
||||
EndGlobalSection |
||||
GlobalSection(SolutionProperties) = preSolution |
||||
HideSolutionNode = FALSE |
||||
EndGlobalSection |
||||
GlobalSection(ExtensibilityGlobals) = postSolution |
||||
SolutionGuid = {8A5B6CF5-8AA9-4F53-8A9D-6CD2FFDB2552} |
||||
EndGlobalSection |
||||
EndGlobal |
@ -0,0 +1,91 @@
|
||||
#pragma once |
||||
#include <windows.h> |
||||
#include <cstdint> |
||||
#include <cstddef> |
||||
|
||||
extern "C" NTSTATUS __protect_virtual_memory( |
||||
HANDLE p_handle, |
||||
void** base_addr, |
||||
std::size_t* bytes_to_protect, |
||||
std::uint32_t new_protect, |
||||
std::uint32_t* old_protect |
||||
); |
||||
|
||||
extern "C" NTSTATUS __write_virtual_memory( |
||||
HANDLE p_handle, |
||||
void* base_addr, |
||||
void* buffer, |
||||
std::size_t size, |
||||
std::size_t* bytes_written |
||||
); |
||||
|
||||
extern "C" NTSTATUS __read_virtual_memory( |
||||
HANDLE p_handle, |
||||
void* base_addr, |
||||
void* buffer, |
||||
std::size_t size, |
||||
std::size_t* bytes_written |
||||
); |
||||
|
||||
extern "C" NTSTATUS __alloc_virtual_memory( |
||||
HANDLE p_handle, |
||||
void** base_addr, |
||||
std::uint32_t zero_bits, |
||||
std::size_t* size, |
||||
std::uint32_t alloc_type, |
||||
std::uint32_t protect |
||||
); |
||||
|
||||
namespace direct |
||||
{ |
||||
__forceinline bool protect_virtual_memory( |
||||
HANDLE p_handle, |
||||
void* base_addr, |
||||
std::size_t size, |
||||
std::uint32_t protect, |
||||
std::uint32_t* old_protect |
||||
) |
||||
{ |
||||
return ERROR_SUCCESS == ::__protect_virtual_memory(p_handle, &base_addr, &size, protect, old_protect); |
||||
} |
||||
|
||||
__forceinline bool write_virtual_memory( |
||||
HANDLE p_handle, |
||||
void* base_addr, |
||||
void* buffer, |
||||
std::size_t size |
||||
) |
||||
{ |
||||
std::size_t bytes_written; |
||||
return ERROR_SUCCESS == __write_virtual_memory(p_handle, base_addr, buffer, size, &bytes_written); |
||||
} |
||||
|
||||
__forceinline bool read_virtual_memory( |
||||
HANDLE p_handle, |
||||
void* addr, |
||||
void* buffer, |
||||
std::size_t size |
||||
) |
||||
{ |
||||
std::size_t bytes_written; |
||||
return ERROR_SUCCESS == ::__read_virtual_memory(p_handle, addr, buffer, size, &bytes_written); |
||||
} |
||||
|
||||
__forceinline void* alloc_virtual_memory( |
||||
HANDLE p_handle, |
||||
std::size_t size, |
||||
std::uint32_t protect |
||||
) |
||||
{ |
||||
void* base_addr = NULL; |
||||
::__alloc_virtual_memory( |
||||
p_handle, |
||||
&base_addr, |
||||
NULL, |
||||
&size, |
||||
MEM_COMMIT | MEM_RESERVE, |
||||
protect |
||||
); |
||||
return base_addr; |
||||
} |
||||
} |
Binary file not shown.
@ -0,0 +1,367 @@
|
||||
#include "kernel_ctx.h" |
||||
|
||||
namespace physmeme |
||||
{ |
||||
kernel_ctx::kernel_ctx() |
||||
{ |
||||
if (psyscall_func.load() || nt_page_offset || ntoskrnl_buffer) |
||||
return; |
||||
|
||||
ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>( |
||||
LoadLibraryExA( |
||||
"ntoskrnl.exe",
|
||||
NULL, |
||||
DONT_RESOLVE_DLL_REFERENCES |
||||
)); |
||||
|
||||
nt_rva = reinterpret_cast<std::uint32_t>( |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
syscall_hook.first.data(), |
||||
true |
||||
)); |
||||
|
||||
nt_page_offset = nt_rva % PAGE_SIZE; |
||||
std::vector<std::thread> search_threads; |
||||
//--- for each physical memory range, make a thread to search it
|
||||
for (auto ranges : util::pmem_ranges) |
||||
search_threads.emplace_back(std::thread( |
||||
&kernel_ctx::map_syscall, |
||||
this, |
||||
ranges.first, |
||||
ranges.second |
||||
)); |
||||
|
||||
for (std::thread& search_thread : search_threads) |
||||
search_thread.join(); |
||||
} |
||||
|
||||
void kernel_ctx::map_syscall(std::uintptr_t begin, std::uintptr_t end) const |
||||
{ |
||||
//if the physical memory range is less then or equal to 2mb
|
||||
if (begin + end <= 0x1000 * 512) |
||||
{ |
||||
auto page_va = physmeme::map_phys(begin + nt_page_offset, end); |
||||
if (page_va) |
||||
{ |
||||
// scan every page of the physical memory range
|
||||
for (auto page = page_va; page < page_va + end; page += 0x1000) |
||||
{ |
||||
if (!is_page_found.load()) // keep scanning until its found
|
||||
{ |
||||
__try |
||||
{ |
||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32)) |
||||
{ |
||||
//
|
||||
// this checks to ensure that the syscall does indeed work. if it doesnt, we keep looking!
|
||||
//
|
||||
psyscall_func.store((void*)page); |
||||
auto my_proc_base = reinterpret_cast<std::uintptr_t>(GetModuleHandleA(NULL)); |
||||
auto my_proc_base_from_syscall = reinterpret_cast<std::uintptr_t>(get_proc_base(GetCurrentProcessId())); |
||||
|
||||
if (my_proc_base != my_proc_base_from_syscall) |
||||
continue; |
||||
|
||||
is_page_found.store(true); |
||||
return; |
||||
} |
||||
} |
||||
__except (EXCEPTION_EXECUTE_HANDLER) {} |
||||
} |
||||
} |
||||
physmeme::unmap_phys(page_va, end); |
||||
} |
||||
} |
||||
else // else the range is bigger then 2mb
|
||||
{ |
||||
auto remainder = (begin + end) % (0x1000 * 512); |
||||
|
||||
// loop over 2m chunks
|
||||
for (auto range = begin; range < begin + end; range += 0x1000 * 512) |
||||
{ |
||||
auto page_va = physmeme::map_phys(range + nt_page_offset, 0x1000 * 512); |
||||
if (page_va) |
||||
{ |
||||
// loop every page of 2mbs (512)
|
||||
for (auto page = page_va; page < page_va + 0x1000 * 512; page += 0x1000) |
||||
{ |
||||
if (!is_page_found.load()) |
||||
{ |
||||
__try |
||||
{ |
||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32)) |
||||
{ |
||||
//
|
||||
// this checks to ensure that the syscall does indeed work. if it doesnt, we keep looking!
|
||||
//
|
||||
psyscall_func.store((void*)page); |
||||
auto my_proc_base = reinterpret_cast<std::uintptr_t>(GetModuleHandle(NULL)); |
||||
auto my_proc_base_from_syscall = reinterpret_cast<std::uintptr_t>(get_proc_base(GetCurrentProcessId())); |
||||
|
||||
if (my_proc_base != my_proc_base_from_syscall) |
||||
continue; |
||||
|
||||
is_page_found.store(true); |
||||
return; |
||||
} |
||||
} |
||||
__except (EXCEPTION_EXECUTE_HANDLER) {} |
||||
} |
||||
} |
||||
physmeme::unmap_phys(page_va, 0x1000 * 512); |
||||
} |
||||
} |
||||
|
||||
// map the remainder and check each page of it
|
||||
auto page_va = physmeme::map_phys(begin + end - remainder + nt_page_offset, remainder); |
||||
if (page_va) |
||||
{ |
||||
for (auto page = page_va; page < page_va + remainder; page += 0x1000) |
||||
{ |
||||
if (!is_page_found.load()) |
||||
{ |
||||
__try |
||||
{ |
||||
if (!memcmp(reinterpret_cast<void*>(page), ntoskrnl_buffer + nt_rva, 32)) |
||||
{ |
||||
//
|
||||
// this checks to ensure that the syscall does indeed work. if it doesnt, we keep looking!
|
||||
//
|
||||
psyscall_func.store((void*)page); |
||||
auto my_proc_base = reinterpret_cast<std::uintptr_t>(GetModuleHandle(NULL)); |
||||
auto my_proc_base_from_syscall = reinterpret_cast<std::uintptr_t>(get_proc_base(GetCurrentProcessId())); |
||||
|
||||
if (my_proc_base != my_proc_base_from_syscall) |
||||
continue; |
||||
|
||||
is_page_found.store(true); |
||||
return; |
||||
} |
||||
} |
||||
__except (EXCEPTION_EXECUTE_HANDLER) {} |
||||
} |
||||
} |
||||
physmeme::unmap_phys(page_va, remainder); |
||||
} |
||||
} |
||||
} |
||||
|
||||
PEPROCESS kernel_ctx::get_peprocess(DWORD pid) const |
||||
{ |
||||
if (!pid) |
||||
return NULL; |
||||
|
||||
PEPROCESS proc; |
||||
static auto get_peprocess_from_pid = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"PsLookupProcessByProcessId" |
||||
); |
||||
|
||||
syscall<PsLookupProcessByProcessId>( |
||||
get_peprocess_from_pid, |
||||
(HANDLE)pid, |
||||
&proc |
||||
); |
||||
return proc; |
||||
} |
||||
|
||||
|
||||
void* kernel_ctx::get_proc_base(unsigned pid) const |
||||
{ |
||||
if (!pid) |
||||
return {}; |
||||
|
||||
const auto peproc = get_peprocess(pid); |
||||
|
||||
if (!peproc) |
||||
return {}; |
||||
|
||||
static auto get_section_base = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"PsGetProcessSectionBaseAddress" |
||||
); |
||||
|
||||
return syscall<PsGetProcessSectionBaseAddress>( |
||||
get_section_base, |
||||
peproc |
||||
); |
||||
} |
||||
|
||||
void kernel_ctx::rkm(void* buffer, void* address, std::size_t size) |
||||
{ |
||||
if (!buffer || !address || !size) |
||||
return; |
||||
|
||||
size_t amount_copied; |
||||
static auto mm_copy_memory = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"memcpy" |
||||
); |
||||
|
||||
if (mm_copy_memory) |
||||
syscall<decltype(&memcpy)>( |
||||
mm_copy_memory, |
||||
buffer, |
||||
address, |
||||
size |
||||
); |
||||
} |
||||
|
||||
void kernel_ctx::wkm(void* buffer, void* address, std::size_t size) |
||||
{ |
||||
if (!buffer || !address || !size) |
||||
return; |
||||
|
||||
size_t amount_copied; |
||||
static auto mm_copy_memory = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"memcpy" |
||||
); |
||||
|
||||
if (mm_copy_memory) |
||||
syscall<decltype(&memcpy)>( |
||||
mm_copy_memory, |
||||
address, |
||||
buffer, |
||||
size |
||||
); |
||||
} |
||||
|
||||
void* kernel_ctx::get_physical(void* virt_addr) |
||||
{ |
||||
if (!virt_addr) |
||||
return NULL; |
||||
|
||||
static auto mm_get_physical = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"MmGetPhysicalAddress" |
||||
); |
||||
|
||||
return syscall<MmGetPhysicalAddress>( |
||||
mm_get_physical, |
||||
virt_addr |
||||
); |
||||
} |
||||
|
||||
void* kernel_ctx::get_virtual(void* addr) |
||||
{ |
||||
if (!addr) |
||||
return NULL; |
||||
|
||||
static auto mm_get_virtual = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"MmGetVirtualForPhysical" |
||||
); |
||||
|
||||
PHYSICAL_ADDRESS phys_addr; |
||||
memcpy(&phys_addr, &addr, sizeof(addr)); |
||||
return syscall<MmGetVirtualForPhysical>( |
||||
mm_get_virtual, |
||||
phys_addr |
||||
); |
||||
} |
||||
|
||||
bool kernel_ctx::clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp) |
||||
{ |
||||
static const auto piddb_lock = |
||||
util::memory::get_piddb_lock(); |
||||
|
||||
static const auto piddb_table = |
||||
util::memory::get_piddb_table(); |
||||
|
||||
if (!piddb_lock || !piddb_table) |
||||
return false; |
||||
|
||||
static const auto ex_acquire_resource = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"ExAcquireResourceExclusiveLite" |
||||
); |
||||
|
||||
static const auto lookup_element_table = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"RtlLookupElementGenericTableAvl" |
||||
); |
||||
|
||||
static const auto release_resource = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"ExReleaseResourceLite" |
||||
); |
||||
|
||||
static const auto delete_table_entry = |
||||
util::get_module_export( |
||||
"ntoskrnl.exe", |
||||
"RtlDeleteElementGenericTableAvl" |
||||
); |
||||
|
||||
if (!ex_acquire_resource || !lookup_element_table || !release_resource) |
||||
return false; |
||||
|
||||
PiDDBCacheEntry cache_entry; |
||||
const auto drv_name = std::wstring(file_name.begin(), file_name.end()); |
||||
cache_entry.time_stamp = timestamp; |
||||
RtlInitUnicodeString(&cache_entry.driver_name, drv_name.data()); |
||||
|
||||
//
|
||||
// ExAcquireResourceExclusiveLite
|
||||
//
|
||||
if (!syscall<ExAcquireResourceExclusiveLite>(ex_acquire_resource, piddb_lock, true)) |
||||
return false; |
||||
|
||||
//
|
||||
// RtlLookupElementGenericTableAvl
|
||||
//
|
||||
PIDCacheobj* found_entry_ptr = |
||||
syscall<RtlLookupElementGenericTableAvl>( |
||||
lookup_element_table, |
||||
piddb_table, |
||||
reinterpret_cast<void*>(&cache_entry) |
||||
); |
||||
|
||||
if (found_entry_ptr) |
||||
{ |
||||
|
||||
//
|
||||
// unlink entry.
|
||||
//
|
||||
PIDCacheobj found_entry = rkm<PIDCacheobj>(found_entry_ptr); |
||||
LIST_ENTRY NextEntry = rkm<LIST_ENTRY>(found_entry.list.Flink); |
||||
LIST_ENTRY PrevEntry = rkm<LIST_ENTRY>(found_entry.list.Blink); |
||||
|
||||
PrevEntry.Flink = found_entry.list.Flink; |
||||
NextEntry.Blink = found_entry.list.Blink; |
||||
|
||||
wkm<LIST_ENTRY>(found_entry.list.Blink, PrevEntry); |
||||
wkm<LIST_ENTRY>(found_entry.list.Flink, NextEntry); |
||||
|
||||
//
|
||||
// delete entry.
|
||||
//
|
||||
syscall<RtlDeleteElementGenericTableAvl>(delete_table_entry, piddb_table, found_entry_ptr); |
||||
|
||||
//
|
||||
// ensure the entry is 0
|
||||
//
|
||||
auto result = syscall<RtlLookupElementGenericTableAvl>( |
||||
lookup_element_table, |
||||
piddb_table, |
||||
reinterpret_cast<void*>(&cache_entry) |
||||
); |
||||
|
||||
syscall<ExReleaseResourceLite>(release_resource, piddb_lock); |
||||
return !result; |
||||
} |
||||
syscall<ExReleaseResourceLite>(release_resource, piddb_lock); |
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,126 @@
|
||||
#pragma once |
||||
#include "../util/util.hpp" |
||||
#include "../physmeme/physmeme.hpp" |
||||
#include "../util/hook.hpp" |
||||
|
||||
namespace physmeme |
||||
{ |
||||
//
|
||||
// offset of function into a physical page
|
||||
// used for comparing bytes when searching
|
||||
//
|
||||
inline std::uint16_t nt_page_offset{}; |
||||
|
||||
//
|
||||
// rva of nt function we are going to hook
|
||||
//
|
||||
inline std::uint32_t nt_rva{}; |
||||
|
||||
//
|
||||
// base address of ntoskrnl (inside of this process)
|
||||
//
|
||||
inline const std::uint8_t* ntoskrnl_buffer{}; |
||||
|
||||
//
|
||||
// has the page been found yet?
|
||||
//
|
||||
inline std::atomic<bool> is_page_found = false; |
||||
|
||||
//
|
||||
// mapping of a syscalls physical memory (for installing hooks)
|
||||
//
|
||||
inline std::atomic<void*> psyscall_func{}; |
||||
|
||||
//
|
||||
// you can edit this how you choose, im hooking NtShutdownSystem.
|
||||
//
|
||||
inline const std::pair<std::string_view, std::string_view> syscall_hook = { "NtShutdownSystem", "ntdll.dll" }; |
||||
|
||||
class kernel_ctx |
||||
{ |
||||
friend class mem_ctx; |
||||
public: |
||||
kernel_ctx(); |
||||
|
||||
//
|
||||
// read kernel memory into buffer
|
||||
//
|
||||
void rkm(void* buffer, void* address, std::size_t size); |
||||
|
||||
//
|
||||
// write kernel memory from buffer
|
||||
//
|
||||
void wkm(void* buffer, void* address, std::size_t size); |
||||
|
||||
template <class T> |
||||
T rkm(void* addr) |
||||
{ |
||||
if (!addr) |
||||
return {}; |
||||
T buffer; |
||||
rkm((void*)&buffer, addr, sizeof(T)); |
||||
return buffer; |
||||
} |
||||
|
||||
template <class T> |
||||
void wkm(void* addr, const T& data) |
||||
{ |
||||
if (!addr) |
||||
return; |
||||
wkm((void*)&data, addr, sizeof(T)); |
||||
} |
||||
|
||||
//
|
||||
// gets physical address from virtual
|
||||
//
|
||||
void* get_physical(void* virt_addr); |
||||
|
||||
//
|
||||
// uses the pfn database to get the virtual address
|
||||
//
|
||||
void* get_virtual(void* virt_addr); |
||||
|
||||
//
|
||||
// use this to call any function in the kernel
|
||||
//
|
||||
template <class T, class ... Ts> |
||||
std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args) const |
||||
{ |
||||
static const auto proc = |
||||
GetProcAddress( |
||||
GetModuleHandleA(syscall_hook.second.data()), |
||||
syscall_hook.first.data() |
||||
); |
||||
|
||||
if (!proc || !psyscall_func || !addr) |
||||
return {}; |
||||
|
||||
hook::make_hook(psyscall_func, addr); |
||||
auto result = reinterpret_cast<T>(proc)(args ...); |
||||
hook::remove(psyscall_func); |
||||
return result; |
||||
} |
||||
|
||||
//
|
||||
// clear piddb cache of a specific driver
|
||||
//
|
||||
bool clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp); |
||||
|
||||
private: |
||||
|
||||
//
|
||||
// find and map the physical page of a syscall into this process
|
||||
//
|
||||
void map_syscall(std::uintptr_t begin, std::uintptr_t end) const; |
||||
|
||||
//
|
||||
// get a pointer to an eprocess given process id.
|
||||
//
|
||||
PEPROCESS get_peprocess(DWORD pid) const; |
||||
|
||||
//
|
||||
// get base address of process (used to compare and ensure we find the right page).
|
||||
//
|
||||
void* get_proc_base(unsigned pid) const; |
||||
}; |
||||
} |
@ -0,0 +1,281 @@
|
||||
/*
|
||||
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 <iostream> |
||||
|
||||
#pragma comment(lib, "ntdll.lib") |
||||
using nt_load_driver_t = NTSTATUS(__fastcall*)(PUNICODE_STRING); |
||||
using nt_unload_driver_t = NTSTATUS(__fastcall*)(PUNICODE_STRING); |
||||
|
||||
namespace driver |
||||
{ |
||||
namespace util |
||||
{ |
||||
inline bool delete_service_entry(const std::string& service_name) |
||||
{ |
||||
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);; |
||||
} |
||||
|
||||
inline bool create_service_entry(const std::string& drv_path, const std::string& service_name) |
||||
{ |
||||
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; |
||||
|
||||
//
|
||||
// set type to 1 (kernel)
|
||||
//
|
||||
constexpr std::uint8_t type_value = 1; |
||||
result = RegSetValueExA( |
||||
reg_handle, |
||||
"Type", |
||||
NULL, |
||||
REG_DWORD, |
||||
&type_value, |
||||
4u |
||||
); |
||||
|
||||
if (result != ERROR_SUCCESS) |
||||
return false; |
||||
|
||||
//
|
||||
// set error control to 3
|
||||
//
|
||||
constexpr 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; |
||||
|
||||
//
|
||||
// set start to 3
|
||||
//
|
||||
constexpr std::uint8_t start_value = 3; |
||||
result = RegSetValueExA( |
||||
reg_handle, |
||||
"Start", |
||||
NULL, |
||||
REG_DWORD, |
||||
&start_value, |
||||
4u |
||||
); |
||||
|
||||
if (result != ERROR_SUCCESS) |
||||
return false; |
||||
|
||||
//
|
||||
// set image path to the driver on disk
|
||||
//
|
||||
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); |
||||
} |
||||
|
||||
// this function was coded by paracord: https://githacks.org/snippets/4#L94
|
||||
inline bool enable_privilege(const std::wstring& privilege_name) |
||||
{ |
||||
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 std::string get_service_image_path(const std::string& service_name) |
||||
{ |
||||
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); |
||||
} |
||||
} |
||||
|
||||
inline bool load(const std::string& drv_path, const std::string& service_name) |
||||
{ |
||||
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; |
||||
|
||||
static const auto lp_nt_load_drv = |
||||
::GetProcAddress( |
||||
GetModuleHandleA("ntdll.dll"), |
||||
"NtLoadDriver" |
||||
); |
||||
|
||||
if (lp_nt_load_drv) |
||||
{ |
||||
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 == reinterpret_cast<nt_load_driver_t>(lp_nt_load_drv)(&driver_reg_path_unicode); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
inline std::tuple<bool, std::string> load(const std::vector<std::uint8_t>& drv_buffer) |
||||
{ |
||||
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 }; |
||||
} |
||||
|
||||
inline std::tuple<bool, std::string> load(const std::uint8_t* buffer, const std::size_t size) |
||||
{ |
||||
std::vector<std::uint8_t> image(buffer, buffer + size); |
||||
return load(image); |
||||
} |
||||
|
||||
inline bool unload(const std::string& service_name) |
||||
{ |
||||
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); |
||||
reg_path += service_name; |
||||
|
||||
static const auto lp_nt_unload_drv = |
||||
::GetProcAddress( |
||||
GetModuleHandleA("ntdll.dll"), |
||||
"NtUnloadDriver" |
||||
); |
||||
|
||||
if (lp_nt_unload_drv) |
||||
{ |
||||
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 = !reinterpret_cast<nt_unload_driver_t>(lp_nt_unload_drv)(&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); |
||||
try
|
||||
{ |
||||
const bool delete_drv = std::filesystem::remove(image_path); |
||||
}
|
||||
catch(std::exception& e) {} |
||||
return unload_drv && delete_reg; |
||||
} |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,48 @@
|
||||
#include "map_driver.hpp" |
||||
#include "mapper_ctx/mapper_ctx.hpp" |
||||
#include "kernel_ctx/kernel_ctx.h" |
||||
|
||||
namespace mapper |
||||
{ |
||||
std::pair<mapper_error, void*> map_driver(std::uint8_t* drv_image, std::size_t image_size, void** entry_data) |
||||
{ |
||||
std::vector<std::uint8_t> drv_buffer(drv_image, image_size + drv_image); |
||||
if (!drv_buffer.size()) |
||||
return { mapper_error::image_invalid, nullptr }; |
||||
|
||||
if (!physmeme::load_drv()) |
||||
return { mapper_error::load_error, nullptr }; |
||||
|
||||
physmeme::kernel_ctx kernel; |
||||
|
||||
// after we setup the kernel_ctx we dont need any driver loaded anymore...
|
||||
if (!physmeme::unload_drv()) |
||||
return { mapper_error::unload_error, nullptr }; |
||||
|
||||
// clear piddb cache of the loaded vuln driver...
|
||||
if (!kernel.clear_piddb_cache(physmeme::drv_key, util::get_file_header((void*)raw_driver)->TimeDateStamp)) |
||||
return { mapper_error::piddb_fail, nullptr }; |
||||
|
||||
// start a runtime broker suspended...
|
||||
const auto runtime_broker_pid = util::start_runtime_broker(); |
||||
|
||||
if (!runtime_broker_pid) |
||||
return { mapper_error::failed_to_create_proc, nullptr };
|
||||
|
||||
physmeme::mem_ctx my_proc(kernel, GetCurrentProcessId()); |
||||
physmeme::mem_ctx runtime_broker(kernel, runtime_broker_pid); |
||||
physmeme::mapper_ctx mapper(my_proc, runtime_broker); |
||||
|
||||
// allocate the driver in the suspended runtime broker and expose it to this process...
|
||||
const auto [drv_base, drv_entry] = mapper.map(drv_buffer); |
||||
if (!drv_base || !drv_entry) |
||||
return { mapper_error::init_failed, nullptr }; |
||||
|
||||
mapper.call_entry(drv_entry, entry_data); |
||||
|
||||
// mem_ctx destructors need to be called before kernel_ctx destructors...
|
||||
my_proc.~mem_ctx(); |
||||
runtime_broker.~mem_ctx(); |
||||
return { mapper_error::error_success, drv_base }; |
||||
} |
||||
} |
@ -0,0 +1,27 @@
|
||||
#pragma once |
||||
#include <cstddef> |
||||
#include <cstdint> |
||||
#include <map> |
||||
|
||||
namespace mapper |
||||
{ |
||||
enum class mapper_error |
||||
{ |
||||
error_success = 0x000, // everything is good!
|
||||
image_invalid = 0x111, // the driver your trying to map is invalid (are you importing things that arent in ntoskrnl?)
|
||||
load_error = 0x222, // unable to load signed driver into the kernel (are you running as admin?)
|
||||
unload_error = 0x333, // unable to unload signed driver from kernel (are all handles to this driver closes?)
|
||||
piddb_fail = 0x444, // piddb cache clearing failed... (are you using this code below windows 10?)
|
||||
init_failed = 0x555, // setting up library dependancies failed!
|
||||
failed_to_create_proc = 0x777 // was unable to create a new process to inject driver into! (RuntimeBroker.exe)
|
||||
}; |
||||
|
||||
/// <summary>
|
||||
/// map a driver only into your current process...
|
||||
/// </summary>
|
||||
/// <param name="drv_image">base address of driver buffer</param>
|
||||
/// <param name="image_size">size of the driver buffer</param>
|
||||
/// <param name="entry_data">data to be sent to the entry point of the driver...</param>
|
||||
/// <returns>status of the driver being mapped, and base address of the driver...</returns>
|
||||
std::pair<mapper_error, void*> map_driver(std::uint8_t* drv_image, std::size_t image_size, void** entry_data); |
||||
} |
@ -0,0 +1,163 @@
|
||||
#include "mapper_ctx.hpp" |
||||
|
||||
namespace physmeme |
||||
{ |
||||
mapper_ctx::mapper_ctx |
||||
( |
||||
physmeme::mem_ctx& map_into, |
||||
physmeme::mem_ctx& map_from |
||||
) |
||||
: |
||||
map_into(map_into), |
||||
map_from(map_from) |
||||
{} |
||||
|
||||
std::pair<void*, void*> mapper_ctx::map(std::vector<std::uint8_t>& raw_image) |
||||
{ |
||||
const auto [drv_alloc, drv_entry_addr] = allocate_driver(raw_image); |
||||
auto [drv_ppml4e, drv_pml4e] = map_from.get_pml4e(drv_alloc); |
||||
|
||||
//
|
||||
// make the pde & pte's containing the driver user supervisor = false...
|
||||
//
|
||||
make_kernel_access(drv_alloc); |
||||
|
||||
//
|
||||
// set new pml4e into specific process.
|
||||
//
|
||||
drv_pml4e.nx = false; |
||||
drv_pml4e.user_supervisor = false; |
||||
|
||||
map_into.write_phys |
||||
( |
||||
reinterpret_cast<ppml4e*>(map_into.get_dirbase()) + PML4_MAP_INDEX, |
||||
drv_pml4e |
||||
); |
||||
|
||||
virt_addr_t new_addr = { reinterpret_cast<void*>(drv_alloc) }; |
||||
new_addr.pml4_index = PML4_MAP_INDEX; |
||||
return { new_addr.value, drv_entry_addr }; |
||||
} |
||||
|
||||
bool mapper_ctx::call_entry(void* drv_entry, void** hook_handler) const |
||||
{ |
||||
const auto result = map_into.k_ctx->syscall<NTSTATUS(__fastcall*)(void**)>(drv_entry, hook_handler); |
||||
return !result; |
||||
} |
||||
|
||||
std::pair<void*, void*> mapper_ctx::allocate_driver(std::vector<std::uint8_t>& raw_image) |
||||
{ |
||||
const auto _get_module = [&](std::string_view name) |
||||
{ |
||||
return util::get_module_base(name.data()); |
||||
}; |
||||
|
||||
const auto _get_export_name = [&](const char* base, const char* name) |
||||
{ |
||||
return reinterpret_cast<std::uintptr_t>(util::get_module_export(base, name)); |
||||
}; |
||||
|
||||
physmeme::pe_image drv_image(raw_image); |
||||
const auto process_handle = |
||||
OpenProcess( |
||||
PROCESS_ALL_ACCESS, |
||||
FALSE, |
||||
map_from.get_pid() |
||||
); |
||||
|
||||
if (!process_handle) |
||||
return {}; |
||||
|
||||
drv_image.fix_imports(_get_module, _get_export_name); |
||||
drv_image.map(); |
||||
|
||||
const auto drv_alloc_base =
|
||||
reinterpret_cast<std::uintptr_t>( |
||||
direct::alloc_virtual_memory( |
||||
process_handle, |
||||
drv_image.size(), |
||||
PAGE_READWRITE |
||||
)); |
||||
|
||||
if (!drv_alloc_base) |
||||
return {}; |
||||
|
||||
virt_addr_t new_addr = { reinterpret_cast<void*>(drv_alloc_base) }; |
||||
new_addr.pml4_index = PML4_MAP_INDEX; |
||||
drv_image.relocate(reinterpret_cast<std::uintptr_t>(new_addr.value)); |
||||
|
||||
//
|
||||
// dont write nt headers...
|
||||
//
|
||||
const bool result = direct::write_virtual_memory |
||||
( |
||||
process_handle, |
||||
reinterpret_cast<void*>((std::uint64_t)drv_alloc_base + drv_image.header_size()), |
||||
reinterpret_cast<void*>((std::uint64_t)drv_image.data() + drv_image.header_size()), |
||||
drv_image.size() - drv_image.header_size() |
||||
); |
||||
|
||||
if (!CloseHandle(process_handle)) |
||||
return { {}, {} }; |
||||
|
||||
return |
||||
{
|
||||
reinterpret_cast<void*>(drv_alloc_base), |
||||
reinterpret_cast<void*>(drv_image.entry_point() + reinterpret_cast<std::uintptr_t>(new_addr.value))
|
||||
}; |
||||
} |
||||
|
||||
void mapper_ctx::make_kernel_access(void* drv_base) |
||||
{ |
||||
const auto [ppdpte, pdpte] = map_from.get_pdpte(drv_base); |
||||
auto ppdpte_phys = reinterpret_cast<void*>((reinterpret_cast<std::uint64_t>(ppdpte) >> 12) << 12); // 0 the last 12 bits...
|
||||
auto pdpt_mapping = reinterpret_cast<::ppdpte>(map_from.set_page(ppdpte_phys)); |
||||
|
||||
// set pdptes to CPL0 access only and executable...
|
||||
for (auto pdpt_idx = 0u; pdpt_idx < 512; ++pdpt_idx) |
||||
{ |
||||
if (pdpt_mapping[pdpt_idx].present) |
||||
{ |
||||
pdpt_mapping[pdpt_idx].user_supervisor = false; |
||||
pdpt_mapping[pdpt_idx].nx = false; |
||||
|
||||
auto pd_mapping = reinterpret_cast<ppde>( |
||||
map_from.set_page(reinterpret_cast<void*>( |
||||
pdpt_mapping[pdpt_idx].pfn << 12))); |
||||
|
||||
// set pdes to CPL0 access only and executable...
|
||||
for (auto pd_idx = 0u; pd_idx < 512; ++pd_idx) |
||||
{ |
||||
if (pd_mapping[pd_idx].present) |
||||
{ |
||||
pd_mapping[pd_idx].user_supervisor = false; |
||||
pd_mapping[pd_idx].nx = false; |
||||
|
||||
auto pt_mapping = reinterpret_cast<ppte>( |
||||
map_from.set_page(reinterpret_cast<void*>( |
||||
pd_mapping[pd_idx].pfn << 12))); |
||||
|
||||
// set ptes to CPL0 access only and executable...
|
||||
for (auto pt_idx = 0u; pt_idx < 512; ++pt_idx) |
||||
{ |
||||
if (pt_mapping[pt_idx].present) |
||||
{ |
||||
pt_mapping[pt_idx].user_supervisor = false; |
||||
pt_mapping[pt_idx].nx = false; |
||||
} |
||||
} |
||||
|
||||
// set page back to pd...
|
||||
pd_mapping = reinterpret_cast<ppde>( |
||||
map_from.set_page(reinterpret_cast<void*>( |
||||
pdpt_mapping[pdpt_idx].pfn << 12))); |
||||
} |
||||
} |
||||
|
||||
// set page back to pdpt...
|
||||
pdpt_mapping = reinterpret_cast<::ppdpte>( |
||||
map_from.set_page(ppdpte_phys)); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
#include "../mem_ctx/mem_ctx.hpp" |
||||
#include "../pe_image/pe_image.h" |
||||
#include "../direct.h" |
||||
|
||||
#define PML4_MAP_INDEX 70 |
||||
namespace physmeme |
||||
{ |
||||
class mapper_ctx |
||||
{ |
||||
public: |
||||
explicit mapper_ctx |
||||
( |
||||
physmeme::mem_ctx& map_into,
|
||||
physmeme::mem_ctx& map_from |
||||
); |
||||
std::pair<void |