init commit

master
_xeroxz 3 years ago
parent e9f681c58f
commit 3f5eaeed7e

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

@ -1,3 +1,14 @@
# luna-1
# Old code from 6/xx/2020.
### luna-1 (AMD)
Driver gets allocated inside of the kernel using a normal pool. The Nt headers of the driver are zero'ed. Communication with this driver happens via a process specific
syscall hook (meaning the hook cannot be seen in any other context). Detected on EAC, should be fine for BattlEye.
### luna-1 (INTEL)
Driver gets allocated inside of the current process (not the kernel itself) and makes a process specific syscall hook to communicate (just like the AMD one). The AMD luna-1
also works for intel. This project is using a super old version of PSKDM which is not stable, its also using an old version of PTM and its using physmeme instead of VDM.
Not sure if EAC is enumorating all processes PML4's yet, when they do this will be detected. Should be fine for BattlEye.
old project from 6/xx/2020

@ -0,0 +1,79 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luna-1", "luna-1\luna-1.vcxproj", "{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luna-1(km)", "luna-1(km)\luna-1(km).vcxproj", "{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luna-1(example)", "luna-1(example)\luna-1(example).vcxproj", "{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}"
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
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|ARM.ActiveCfg = Debug|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|ARM64.ActiveCfg = Debug|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|x64.ActiveCfg = Debug|x64
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|x64.Build.0 = Debug|x64
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|x86.ActiveCfg = Debug|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|x86.Build.0 = Debug|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|ARM.ActiveCfg = Release|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|ARM64.ActiveCfg = Release|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|x64.ActiveCfg = Release|x64
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|x64.Build.0 = Release|x64
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|x86.ActiveCfg = Release|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|x86.Build.0 = Release|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM.ActiveCfg = Debug|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM.Build.0 = Debug|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM.Deploy.0 = Debug|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM64.ActiveCfg = Debug|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM64.Build.0 = Debug|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM64.Deploy.0 = Debug|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x64.ActiveCfg = Debug|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x64.Build.0 = Debug|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x64.Deploy.0 = Debug|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x86.ActiveCfg = Debug|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x86.Build.0 = Debug|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x86.Deploy.0 = Debug|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM.ActiveCfg = Release|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM.Build.0 = Release|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM.Deploy.0 = Release|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM64.ActiveCfg = Release|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM64.Build.0 = Release|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM64.Deploy.0 = Release|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x64.ActiveCfg = Release|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x64.Build.0 = Release|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x64.Deploy.0 = Release|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x86.ActiveCfg = Release|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x86.Build.0 = Release|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x86.Deploy.0 = Release|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|ARM.ActiveCfg = Debug|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|ARM64.ActiveCfg = Debug|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|x64.ActiveCfg = Debug|x64
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|x64.Build.0 = Debug|x64
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|x86.ActiveCfg = Debug|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|x86.Build.0 = Debug|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|ARM.ActiveCfg = Release|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|ARM64.ActiveCfg = Release|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|x64.ActiveCfg = Release|x64
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|x64.Build.0 = Release|x64
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|x86.ActiveCfg = Release|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F503F818-2E0C-43DD-B842-3E2B8BE82E44}
EndGlobalSection
EndGlobal

@ -0,0 +1,157 @@
<?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>{14450ad4-f983-46e9-b7a8-f1b6313bff6d}</ProjectGuid>
<RootNamespace>luna1example</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</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>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</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>
<AdditionalDependencies>luna-1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</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>
<AdditionalDependencies>luna-1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>luna-1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>luna-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="luna-1.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,23 @@
<?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>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="luna-1.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</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>

@ -0,0 +1,66 @@
#pragma once
#include <cstddef>
#include <cstdint>
namespace i6
{
//
// please call this before making any other calls!
//
bool begin();
//
// get process id of process.
//
unsigned get_pid(const char* proc_name);
//
// get process base address.
//
std::uintptr_t get_process_base(unsigned pid);
//
// get module base
//
std::uintptr_t get_module_base(unsigned pid, const wchar_t* module_name);
//
// read/write to specific process
//
bool read(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size);
bool write(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size);
//
// read/write kernel memory (you can write to readonly with this)
//
bool rkm(std::uintptr_t addr, void* buffer, std::size_t size);
bool wkm(std::uintptr_t addr, void* buffer, std::size_t size);
template <class T>
T rkm(std::uintptr_t addr)
{
T buffer{};
rkm(addr, (void*)&buffer, sizeof(T));
return buffer;
}
template <class T>
bool wkm(std::uintptr_t addr, const T& data)
{
return wkm(addr, (void*)&data, sizeof(T));
}
template <class T>
T read(unsigned pid, std::uintptr_t addr)
{
T buffer{};
read(pid, addr, (void*)&buffer, sizeof(T));
return buffer;
}
template <class T>
bool write(unsigned pid, std::uintptr_t addr, const T& data)
{
return write(pid, addr, (void*)&data, sizeof(T));
}
}

@ -0,0 +1,24 @@
#include <iostream>
#include "luna-1.hpp"
int main()
{
if (!i6::begin()) // call this before anything else.
{
std::cout << "[!] failed to init..." << std::endl;
std::cin.get();
return -1;
}
else
{
auto notepad_pid = i6::get_pid("notepad.exe");
auto notepad_base = i6::get_process_base(notepad_pid);
std::cout << "[+] notepad pid: " << notepad_pid << std::endl;
std::cout << "[+] notepad base address: " << notepad_base << std::endl;
std::cin.get();
while (true)
std::cout << "[+] notepad MZ: " << std::hex << i6::read<short>(notepad_pid, notepad_base) << std::endl;
}
}

@ -0,0 +1,158 @@
#include "com_functions.h"
#include "memory.h"
namespace i6
{
namespace com
{
void get_process_base(const pcom_struct com_data)
{
if (!com_data || !com_data->pid)
return;
PEPROCESS peproc;
if (PsLookupProcessByProcessId((HANDLE)com_data->pid, &peproc) != STATUS_SUCCESS)
return;
com_data->data_from = PsGetProcessSectionBaseAddress(peproc);
ObDereferenceObject(peproc);
}
void get_module_base(const pcom_struct com_data)
{
if (!com_data || !com_data->pid || !com_data->data_to)
return;
PEPROCESS peproc;
if (PsLookupProcessByProcessId((HANDLE)com_data->pid, &peproc) != STATUS_SUCCESS)
return;
auto ppeb = PsGetProcessPeb(peproc);
ObDereferenceObject(peproc);
if (!ppeb)
return;
PEB peb;
i6::memory::read(
ppeb,
&peb,
sizeof(peb),
com_data->pid
);
if (!peb.Ldr)
return;
PEB_LDR_DATA module_list_entry;
i6::memory::read(
peb.Ldr,
&module_list_entry,
sizeof(module_list_entry),
com_data->pid
);
auto first_entry = (void*)module_list_entry.InMemoryOrderModuleList.Flink;
unsigned char* current_entry;
i6::memory::read(
first_entry,
&current_entry,
sizeof(current_entry),
com_data->pid
);
WCHAR full_file_name[MAX_PATH];
ULONGLONG module_base;
ULONGLONG file_name_ptr;
while (current_entry != first_entry)
{
i6::memory::read(
(unsigned char*)(current_entry)+0x40,
&file_name_ptr,
sizeof(file_name_ptr),
com_data->pid
); // read full module unicode_string structure.
i6::memory::read(
(void*)file_name_ptr,
full_file_name,
MAX_PATH,
com_data->pid
); // read full file path.
i6::memory::read(
(unsigned char*)(current_entry)+0x20,
&module_base,
sizeof(module_base),
com_data->pid
);
if (wcsstr(full_file_name, (wchar_t*)com_data->data_to))
{
com_data->data_from = reinterpret_cast<void*>(module_base);
return;
}
i6::memory::read(
current_entry,
&current_entry,
sizeof(current_entry),
com_data->pid
);
}
}
void read_process_memory(const pcom_struct com_data)
{
if (!com_data || !com_data->pid || !com_data->data_from || !com_data->data_to || !com_data->size)
return;
i6::memory::read(
com_data->data_from,
com_data->data_to,
com_data->size,
com_data->pid
);
}
void write_process_memory(const pcom_struct com_data)
{
if (!com_data || !com_data->pid || !com_data->data_from || !com_data->data_to || !com_data->size)
return;
i6::memory::write
(
com_data->data_to,
com_data->data_from,
com_data->size,
com_data->pid
);
}
void read_kernel_memory(const pcom_struct com_data)
{
if (!com_data || !com_data->data_from || !com_data->data_to)
return;
memcpy
(
com_data->data_to,
com_data->data_from,
com_data->size
);
}
void write_kernel_memory(const pcom_struct com_data)
{
if (!com_data || !com_data->data_from || !com_data->data_to)
return;
memcpy
(
com_data->data_to,
com_data->data_from,
com_data->size
);
}
}
}

@ -0,0 +1,15 @@
#pragma once
#include "types.h"
namespace i6
{
namespace com
{
void get_process_base(const pcom_struct com_data);
void get_module_base(const pcom_struct com_data);
void read_process_memory(const pcom_struct com_data);
void write_process_memory(const pcom_struct com_data);
void read_kernel_memory(const pcom_struct com_data);
void write_kernel_memory(const pcom_struct com_data);
}
}

@ -0,0 +1,37 @@
#include "com_functions.h"
void hook_handler(pcom_struct com_data)
{
if (!com_data)
return;
switch (com_data->type)
{
case READ:
i6::com::read_process_memory(com_data);
break;
case WRITE:
i6::com::write_process_memory(com_data);
break;
case WRITE_KERNEL_MEMORY:
i6::com::write_kernel_memory(com_data);
break;
case READ_KERNEL_MEMORY:
i6::com::read_kernel_memory(com_data);
break;
case GET_PROCESS_BASE:
i6::com::get_process_base(com_data);
break;
case GET_MODULE_BASE:
i6::com::get_module_base(com_data);
break;
default:
break;
}
}
NTSTATUS driver_entry(void** data_ptr)
{
*data_ptr = &hook_handler;
return STATUS_SUCCESS;
}

@ -0,0 +1,87 @@
;
; luna-1(km).inf
;
[Version]
Signature="$WINDOWS NT$"
Class=Sample ; TODO: edit Class
ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid
Provider=%ManufacturerName%
CatalogFile=luna-1(km).cat
DriverVer= ; TODO: set DriverVer in stampinf property pages
PnpLockDown=1
[DestinationDirs]
DefaultDestDir = 12
luna-1(km)_Device_CoInstaller_CopyFiles = 11
; ================= Class section =====================
[ClassInstall32]
Addreg=SampleClassReg
[SampleClassReg]
HKR,,,0,%ClassName%
HKR,,Icon,,-5
[SourceDisksNames]
1 = %DiskName%,,,""
[SourceDisksFiles]
luna-1(km).sys = 1,,
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
;*****************************************
; Install Section
;*****************************************
[Manufacturer]
%ManufacturerName%=Standard,NT$ARCH$
[Standard.NT$ARCH$]
%luna-1(km).DeviceDesc%=luna-1(km)_Device, Root\luna-1(km) ; TODO: edit hw-id
[luna-1(km)_Device.NT]
CopyFiles=Drivers_Dir
[Drivers_Dir]
luna-1(km).sys
;-------------- Service installation
[luna-1(km)_Device.NT.Services]
AddService = luna-1(km),%SPSVCINST_ASSOCSERVICE%, luna-1(km)_Service_Inst
; -------------- luna-1(km) driver install sections
[luna-1(km)_Service_Inst]
DisplayName = %luna-1(km).SVCDESC%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\luna-1(km).sys
;
;--- luna-1(km)_Device Coinstaller installation ------
;
[luna-1(km)_Device.NT.CoInstallers]
AddReg=luna-1(km)_Device_CoInstaller_AddReg
CopyFiles=luna-1(km)_Device_CoInstaller_CopyFiles
[luna-1(km)_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
[luna-1(km)_Device_CoInstaller_CopyFiles]
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
[luna-1(km)_Device.NT.Wdf]
KmdfService = luna-1(km), luna-1(km)_wdfsect
[luna-1(km)_wdfsect]
KmdfLibraryVersion = $KMDFVERSION$
[Strings]
SPSVCINST_ASSOCSERVICE= 0x00000002
ManufacturerName="<Your manufacturer name>" ;TODO: Replace with your manufacturer name
ClassName="Samples" ; TODO: edit ClassName
DiskName = "luna-1(km) Installation Disk"
luna-1(km).DeviceDesc = "luna-1(km) Device"
luna-1(km).SVCDESC = "luna-1(km) Service"

@ -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>{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}</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>luna_1_km_</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>
<SpectreMitigation>false</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>
<SpectreMitigation>false</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>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</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)'=='Release|x64'">
<ClCompile>
<TreatWarningAsError>false</TreatWarningAsError>
<LanguageStandard>stdcpp17</LanguageStandard>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<EntryPointSymbol>driver_entry</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<FilesToPackage Include="$(TargetPath)" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="com_functions.cpp" />
<ClCompile Include="hook_handler.cpp" />
<ClCompile Include="memory.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="com_functions.h" />
<ClInclude Include="memory.h" />
<ClInclude Include="types.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,35 @@
<?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>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="memory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="com_functions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hook_handler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="com_functions.h">
<Filter>Header Files</Filter>
</ClInclude>
</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>

@ -0,0 +1,70 @@
#include "memory.h"
namespace i6
{
namespace memory
{
void read(void* addr, void* buffer, size_t size, unsigned pid)
{
if (!addr || !buffer || !size)
return;
char memcpy_buffer[0x1000];
memset(memcpy_buffer, NULL, sizeof(memcpy_buffer));
KAPC_STATE state;
PEPROCESS peproc;
if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)pid, &peproc)) && peproc)
{
KeStackAttachProcess(peproc, &state);
if (MmIsAddressValid(addr))
memcpy(memcpy_buffer, addr, size);
KeUnstackDetachProcess(&state);
if(MmIsAddressValid(buffer))
memcpy(buffer, memcpy_buffer, size);
ObDereferenceObject(peproc);
}
}
void write(void* addr, void* buffer, size_t size, unsigned pid)
{
if (!addr || !buffer || !size)
return;
char memcpy_buffer[0x1000];
memset(memcpy_buffer, NULL, sizeof(memcpy_buffer));
if (MmIsAddressValid(buffer))
memcpy(memcpy_buffer, buffer, size);
KAPC_STATE state;
PEPROCESS peproc;
if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)pid, &peproc)) && peproc)
{
KeStackAttachProcess(peproc, &state);
if (MmIsAddressValid(addr))
memcpy(addr, memcpy_buffer, size);
KeUnstackDetachProcess(&state);
ObDereferenceObject(peproc);
}
}
void disable_wp()
{
_disable();
auto cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
}
void enable_wp()
{
auto cr0 = __readcr0();
cr0 |= 0x10000;
__writecr0(cr0);
_enable();
}
}
}

@ -0,0 +1,15 @@
#pragma once
#include <intrin.h>
#include "types.h"
namespace i6
{
namespace memory
{
void disable_wp();
void enable_wp();
void read(void* addr, void* buffer, size_t size, unsigned pid);
void write(void* addr, void* buffer, size_t size, unsigned pid);
}
}

@ -0,0 +1,101 @@
#pragma once
#include <ntifs.h>
#include <windef.h>
enum com_type
{
READ,
WRITE,
READ_KERNEL_MEMORY,
WRITE_KERNEL_MEMORY,
GET_PROCESS_BASE,
GET_MODULE_BASE
};
typedef struct _com_struct
{
com_type type;
unsigned pid;
unsigned size;
void* data_from;
void* data_to;
} com_struct, * pcom_struct;
extern "C" PVOID PsGetProcessSectionBaseAddress(
__in PEPROCESS Process
);
extern "C" PPEB PsGetProcessPeb(PEPROCESS process);
extern "C" NTSTATUS MmCopyVirtualMemory(
_In_ PEPROCESS FromProcess,
_In_ CONST VOID* FromAddress,
_In_ PEPROCESS ToProcess,
_Out_opt_ PVOID ToAddress,
_In_ SIZE_T BufferSize,
_In_ KPROCESSOR_MODE PreviousMode,
_Out_ PSIZE_T NumberOfBytesCopied
);
typedef struct _PEB_LDR_DATA
{
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY
{
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
PVOID Reserved3[2];
UNICODE_STRING FullDllName;
BYTE Reserved4[8];
PVOID Reserved5[3];
#pragma warning(push)
#pragma warning(disable: 4201) // we'll always use the Microsoft compiler
union
{
ULONG CheckSum;
PVOID Reserved6;
} DUMMYUNIONNAME;
#pragma warning(pop)
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _RTL_USER_PROCESS_PARAMETERS {
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
typedef
VOID
(NTAPI* PPS_POST_PROCESS_INIT_ROUTINE) (
VOID
);
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID Reserved4[3];
PVOID AtlThunkSListPtr;
PVOID Reserved5;
ULONG Reserved6;
PVOID Reserved7;
ULONG Reserved8;
ULONG AtlThunkSListPtr32;
PVOID Reserved9[45];
BYTE Reserved10[96];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved11[128];
PVOID Reserved12[1];
ULONG SessionId;
} PEB, * PPEB;

@ -0,0 +1,30 @@
_TEXT SEGMENT
__protect_virtual_memory proc
mov r10, rcx
mov eax, 050h
syscall
ret
__protect_virtual_memory endp
__write_virtual_memory proc
mov r10, rcx
mov eax, 03Ah
syscall
ret
__write_virtual_memory endp
__read_virtual_memory proc
mov r10, rcx
mov eax, 03Fh
syscall
ret
__read_virtual_memory endp
__alloc_virtual_memory proc
mov r10, rcx
mov eax, 018h
syscall
ret
__alloc_virtual_memory endp
_TEXT ENDS
end

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

@ -0,0 +1,196 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org>
!!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
#include <fstream>
#include "../drv_image/drv_image.h"
namespace nasa
{
drv_image::drv_image(std::vector<uint8_t> image) : m_image(std::move(image))
{
m_dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(m_image.data());
m_nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS64>((uintptr_t)m_dos_header + m_dos_header->e_lfanew);
m_section_header = reinterpret_cast<IMAGE_SECTION_HEADER*>((uintptr_t)(&m_nt_headers->OptionalHeader) + m_nt_headers->FileHeader.SizeOfOptionalHeader);
}
size_t drv_image::size() const
{
return m_nt_headers->OptionalHeader.SizeOfImage;
}
uintptr_t drv_image::entry_point() const
{
return m_nt_headers->OptionalHeader.AddressOfEntryPoint;
}
void drv_image::map()
{
m_image_mapped.clear();
m_image_mapped.resize(m_nt_headers->OptionalHeader.SizeOfImage);
std::copy_n(m_image.begin(), m_nt_headers->OptionalHeader.SizeOfHeaders, m_image_mapped.begin());
for (size_t i = 0; i < m_nt_headers->FileHeader.NumberOfSections; ++i)
{
const auto& section = m_section_header[i];
const auto target = (uintptr_t)m_image_mapped.data() + section.VirtualAddress;
const auto source = (uintptr_t)m_dos_header + section.PointerToRawData;
std::copy_n(m_image.begin() + section.PointerToRawData, section.SizeOfRawData, m_image_mapped.begin() + section.VirtualAddress);
}
}
bool drv_image::process_relocation(uintptr_t image_base_delta, uint16_t data, uint8_t* relocation_base)
{
#define IMR_RELOFFSET(x) (x & 0xFFF)
switch (data >> 12 & 0xF)
{
case IMAGE_REL_BASED_HIGH:
{
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(HIWORD(image_base_delta));
break;
}
case IMAGE_REL_BASED_LOW:
{
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(LOWORD(image_base_delta));
break;
}
case IMAGE_REL_BASED_HIGHLOW:
{
const auto raw_address = reinterpret_cast<size_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<size_t>(image_base_delta);
break;
}
case IMAGE_REL_BASED_DIR64:
{
auto UNALIGNED raw_address = reinterpret_cast<DWORD_PTR UNALIGNED*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += image_base_delta;
break;
}
case IMAGE_REL_BASED_ABSOLUTE: // No action required
case IMAGE_REL_BASED_HIGHADJ: // no action required
{
break;
}
default:
{
return false;
}
}
#undef IMR_RELOFFSET
return true;
}
void drv_image::relocate(void* base) const
{
if (m_nt_headers->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
return;
ULONG total_count_bytes;
const auto nt_headers = ImageNtHeader((void*)m_image_mapped.data());
auto relocation_directory = (PIMAGE_BASE_RELOCATION)::ImageDirectoryEntryToData(nt_headers, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &total_count_bytes);
auto image_base_delta = static_cast<uintptr_t>(reinterpret_cast<uintptr_t>(base) - (nt_headers->OptionalHeader.ImageBase));
auto relocation_size = total_count_bytes;
// This should check (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) too but lots of drivers do not have it set due to WDK defaults
const bool do_reloc = image_base_delta != 0 && relocation_size > 0;
if (!do_reloc)
return;
void* relocation_end = reinterpret_cast<uint8_t*>(relocation_directory) + relocation_size;
while (relocation_directory < relocation_end)
{
auto relocation_base = ::ImageRvaToVa(nt_headers, (void*)m_image_mapped.data(), relocation_directory->VirtualAddress, nullptr);
auto num_relocs = (relocation_directory->SizeOfBlock - 8) >> 1;
auto relocation_data = reinterpret_cast<PWORD>(relocation_directory + 1);
for (unsigned long i = 0; i < num_relocs; ++i, ++relocation_data)
if (process_relocation(image_base_delta, *relocation_data, (uint8_t*)relocation_base) == FALSE)
return;
relocation_directory = reinterpret_cast<PIMAGE_BASE_RELOCATION>(relocation_data);
}
}
template<typename T>
__forceinline T* ptr_add(void* base, uintptr_t offset)
{
return (T*)(uintptr_t)base + offset;
}
void drv_image::fix_imports(const std::function<uintptr_t(std::string_view)> get_module, const std::function<uintptr_t(const char*, const char*)> get_function)
{
ULONG size;
auto import_descriptors = static_cast<PIMAGE_IMPORT_DESCRIPTOR>(::ImageDirectoryEntryToData(m_image.data(), FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size));
if (import_descriptors == nullptr)
return;
for (; import_descriptors->Name; import_descriptors++)
{
IMAGE_THUNK_DATA* image_thunk_data;
const auto module_name = get_rva<char>(import_descriptors->Name);
const auto module_base = get_module(module_name);
if (import_descriptors->OriginalFirstThunk)
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->OriginalFirstThunk);
else
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->FirstThunk);
auto image_func_data = get_rva<IMAGE_THUNK_DATA64>(import_descriptors->FirstThunk);
;
for (; image_thunk_data->u1.AddressOfData; image_thunk_data++, image_func_data++)
{
uintptr_t function_address;
const auto ordinal = (image_thunk_data->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0;
const auto image_import_by_name = get_rva<IMAGE_IMPORT_BY_NAME>(*(DWORD*)image_thunk_data);
const auto name_of_import = static_cast<char*>(image_import_by_name->Name);
function_address = get_function(module_name, name_of_import);
image_func_data->u1.Function = function_address;
}
}
}
void* drv_image::data()
{
return m_image_mapped.data();
}
size_t drv_image::header_size()
{
return m_nt_headers->OptionalHeader.SizeOfHeaders;
}
}

@ -0,0 +1,77 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org>
!!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
#pragma once
#include <vector>
#define WIN32_NO_STATUS
#include <Windows.h>
#include <Winternl.h>
#undef WIN32_NO_STATUS
#include <ntstatus.h>
#include <functional>
#include <DbgHelp.h>
#include <variant>
#include "../util/nt.hpp"
#pragma comment(lib, "Dbghelp.lib")
namespace nasa
{
class drv_image
{
std::vector<uint8_t> m_image;
std::vector<uint8_t> m_image_mapped;
PIMAGE_DOS_HEADER m_dos_header = nullptr;
PIMAGE_NT_HEADERS64 m_nt_headers = nullptr;
PIMAGE_SECTION_HEADER m_section_header = nullptr;
public:
explicit drv_image(std::vector<uint8_t> image);
size_t size() const;
uintptr_t entry_point() const;
void map();
static bool process_relocation(size_t image_base_delta, uint16_t data, uint8_t* relocation_base);
void relocate(void* base) const;
template<typename T>
__forceinline T* get_rva(const unsigned long offset)
{
return (T*)::ImageRvaToVa(m_nt_headers, m_image.data(), offset, nullptr);
}
void fix_imports(
const std::function<uintptr_t(std::string_view)> get_module,
const std::function<uintptr_t(const char*, const char*)> get_function
);
void* data();
size_t header_size();
};
}

@ -0,0 +1,374 @@
#include "kernel_ctx.h"
#include "../mem_ctx/mem_ctx.hpp"
namespace nasa
{
kernel_ctx::kernel_ctx()
{
if (psyscall_func.load() || nt_page_offset || ntoskrnl_buffer)
return;
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;
ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>(LoadLibraryExA("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES));
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 = nasa::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
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;
}
nasa::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 = nasa::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())
{
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;
}
}
}
nasa::unmap_phys(page_va, 0x1000 * 512);
}
}
// map the remainder and check each page of it
auto page_va = nasa::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())
{
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;
}
}
}
nasa::unmap_phys(page_va, remainder);
}
}
}
PEPROCESS kernel_ctx::get_peprocess(unsigned pid) const
{
if (!pid)
return NULL;
PEPROCESS proc;
static auto get_peprocess_from_pid =
util::get_module_export(
"ntoskrnl.exe",
"PsLookupProcessByProcessId"
);
const auto status = 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;
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
);
}
void* kernel_ctx::allocate_pool(std::size_t size, POOL_TYPE pool_type)
{
static const auto ex_alloc_pool =
util::get_module_export(
"ntoskrnl.exe",
"ExAllocatePool"
);
return syscall<ExAllocatePool>(
ex_alloc_pool,
pool_type,
size
);
}
void kernel_ctx::zero_kernel_memory(void* addr, std::size_t size)
{
static const auto rtl_zero_memory =
util::get_module_export(
"ntoskrnl.exe",
"RtlZeroMemory"
);
syscall<decltype(&RtlSecureZeroMemory)>(
rtl_zero_memory,
addr,
size
);
}
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,124 @@
#pragma once
#include "../util/util.hpp"
#include "../physmeme/physmeme.hpp"
#include "../util/hook.hpp"
namespace nasa
{
//
// 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()
);
hook::make_hook(psyscall_func, addr);
auto result = reinterpret_cast<T>(proc)(args ...);
hook::remove(psyscall_func);
return result;
}
//
// clear piddb cache of specific process.
//
bool clear_piddb_cache(const std::string& drv_name, const std::uint32_t epoch_time);
//
// get a pointer to an eprocess given process id.
//
PEPROCESS get_peprocess(unsigned pid) const;
//
// get base address of process (used to compare and ensure we find the right page).
//
void* get_proc_base(unsigned pid) const;
void* allocate_pool(std::size_t size, POOL_TYPE pool_type);
void zero_kernel_memory(void* addr, std::size_t size);
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;
};
}

@ -0,0 +1,298 @@
/*
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(),
&reg_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(),
&reg_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(),
&reg_handle
);
result = RegGetValueA(
reg_handle,
service_name.c_str(),
"ImagePath",
REG_SZ,
NULL,
image_path,
&bytes_read
);
RegCloseKey(reg_handle);
return std::string(image_path);
}
}
inline 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;
const auto h_file = CreateFileA(
file_path.data(),
GENERIC_ALL,
NULL, NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
DWORD bytes_written;
WriteFile(
h_file,
drv_buffer.data(),
drv_buffer.size(),
&bytes_written,
NULL
);
CloseHandle(h_file);
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,233 @@
#include "luna-1.hpp"
#include "raw_driver.hpp"
#include "patch_ctx/patch_ctx.hpp"
#include "map_driver.hpp"
namespace i6
{
inline nasa::kernel_ctx* kernel_ctx;
inline nasa::mem_ctx* mem_ctx;
inline nasa::patch_ctx* kernel_patch;
inline hook::detour* win32kbase_detour;
inline std::mutex syscall_lock;
inline void* kernel_hook_handler = nullptr;
inline void* win32u_handler = nullptr;
inline void* win32kbase_handler = nullptr;
inline void* patch_address = nullptr;
enum com_type
{
READ,
WRITE,
READ_KERNEL_MEMORY,
WRITE_KERNEL_MEMORY,
GET_PROCESS_BASE,
GET_MODULE_BASE
};
typedef struct _com_struct
{
com_type type;
unsigned pid;
unsigned size;
void* data_from;
void* data_to;
} com_struct, * pcom_struct;
bool begin()
{
//
// make kernel_ctx and fix syscall page so there is no physical memory mapped into this process!
//
if (!nasa::load_drv())
return false;
//
// make driver and get the address of hook handler.
//
const auto result =
nasa::map_driver(
i6::luna_1,
sizeof(i6::luna_1),
&kernel_hook_handler
);
if (!result)
goto exit;
kernel_ctx = new nasa::kernel_ctx();
mem_ctx = new nasa::mem_ctx(*kernel_ctx, GetCurrentProcessId());
if (!kernel_ctx->clear_piddb_cache(nasa::drv_key, util::get_file_header((void*)raw_driver)->TimeDateStamp))
goto exit;
memset(i6::luna_1, NULL, sizeof(i6::luna_1));
win32kbase_handler =
util::get_module_export(
"win32kbase.sys",
"NtDCompositionBeginFrame"
);
if (!win32kbase_handler)
goto exit;
//
// needed for syscall
//
LoadLibrary("user32.dll");
win32u_handler =
::GetProcAddress(
LoadLibraryA("win32u.dll"),
"NtDCompositionBeginFrame"
);
if (!win32u_handler)
goto exit;
kernel_patch = new nasa::patch_ctx(mem_ctx);
patch_address = kernel_patch->patch(win32kbase_handler);
win32kbase_detour = new hook::detour(patch_address, kernel_hook_handler, false);
//
// enable patch and flush tlb!
//
kernel_patch->enable();
FLUSH_TLB;
exit:
if (mem_ctx) delete mem_ctx;
if (kernel_patch) delete kernel_patch;
if (kernel_ctx) delete kernel_ctx;
nasa::unmap_all();
if (!nasa::unload_drv())
return false;
return true;
}
void syscall(const pcom_struct com_data)
{
syscall_lock.lock();
win32kbase_detour->install();
reinterpret_cast<void(*)(pcom_struct)>(win32u_handler)(com_data);
win32kbase_detour->uninstall();
syscall_lock.unlock();
}
std::uintptr_t get_process_base(unsigned pid)
{
if (!pid)
return {};
com_struct com_data;
com_data.type = GET_PROCESS_BASE;
com_data.pid = pid;
syscall(&com_data);
return reinterpret_cast<std::uintptr_t>(com_data.data_from);
}
std::uintptr_t get_module_base(unsigned pid, const wchar_t* module_name)
{
if (!pid || !module_name)
return {};
com_struct com_data;
com_data.type = GET_MODULE_BASE;
com_data.data_to = (void*)module_name;
com_data.pid = pid;
syscall(&com_data);
return reinterpret_cast<std::uintptr_t>(com_data.data_from);
}
bool read(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!pid || !addr || !buffer || !size)
return false;
com_struct com_data;
com_data.type = READ;
com_data.pid = pid;
com_data.data_from = reinterpret_cast<void*>(addr);
com_data.data_to = buffer;
com_data.size = size;
syscall(&com_data);
return true;
}
bool write(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!pid || !addr || !buffer || !size)
return false;
com_struct com_data;
com_data.type = WRITE;
com_data.pid = pid;
com_data.data_from = buffer;
com_data.data_to = reinterpret_cast<void*>(addr);
com_data.size = size;
syscall(&com_data);
return true;
}
bool rkm(std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!addr || !buffer || !size)
return false;
com_struct com_data;
com_data.type = READ_KERNEL_MEMORY;
com_data.data_from = reinterpret_cast<void*>(addr);
com_data.data_to = buffer;
com_data.size = size;
syscall(&com_data);
return true;
}
bool wkm(std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!addr || !buffer || !size)
return false;
com_struct com_data;
com_data.type = WRITE_KERNEL_MEMORY;
com_data.data_from = buffer;
com_data.data_to = reinterpret_cast<void*>(addr);
com_data.size = size;
syscall(&com_data);
return true;
}
unsigned get_pid(const char* proc_name)
{
PROCESSENTRY32 proc_info;
proc_info.dwSize = sizeof(proc_info);
const auto 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 {};
}
}

@ -0,0 +1,66 @@
#pragma once
#include <cstddef>
#include <cstdint>
namespace i6
{
//
// please call this before making any other calls!
//
bool begin();
//
// get process id of process.
//
unsigned get_pid(const char* proc_name);
//
// get process base address.
//
std::uintptr_t get_process_base(unsigned pid);
//
// get module base
//
std::uintptr_t get_module_base(unsigned pid, const wchar_t* module_name);
//
// read/write to specific process
//
bool read(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size);
bool write(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size);
//
// read/write kernel memory (you can write to readonly with this)
//
bool rkm(std::uintptr_t addr, void* buffer, std::size_t size);
bool wkm(std::uintptr_t addr, void* buffer, std::size_t size);
template <class T>
T rkm(std::uintptr_t addr)
{
T buffer{};
rkm(addr, (void*)&buffer, sizeof(T));
return buffer;
}
template <class T>
bool wkm(std::uintptr_t addr, const T& data)
{
return wkm(addr, (void*)&data, sizeof(T));
}
template <class T>
T read(unsigned pid, std::uintptr_t addr)
{
T buffer{};
read(pid, addr, (void*)&buffer, sizeof(T));
return buffer;
}
template <class T>
bool write(unsigned pid, std::uintptr_t addr, const T& data)
{
return write(pid, addr, (void*)&data, sizeof(T));
}
}

@ -0,0 +1,202 @@
<?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>{334edbd9-6a7c-4f6a-8eec-022f8c2c04c3}</ProjectGuid>
<RootNamespace>luna1</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|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>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</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>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<WholeProgramOptimization>false</WholeProgramOptimization>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</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>_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<ProjectReference>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
</ProjectReference>
<Lib>
<AdditionalDependencies>
</AdditionalDependencies>
</Lib>
</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;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<Optimization>Disabled</Optimization>
<WholeProgramOptimization>false</WholeProgramOptimization>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>mapper.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
<ProjectReference>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
</ProjectReference>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="drv_image\drv_image.cpp" />
<ClCompile Include="kernel_ctx\kernel_ctx.cpp" />
<ClCompile Include="luna-1.cpp" />
<ClCompile Include="map_driver.cpp" />
<ClCompile Include="mem_ctx\mem_ctx.cpp" />
<ClCompile Include="patch_ctx\patch_ctx.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="direct.h" />
<ClInclude Include="drv_image\drv_image.h" />
<ClInclude Include="kernel_ctx\kernel_ctx.h" />
<ClInclude Include="loadup.hpp" />
<ClInclude Include="luna-1.hpp" />
<ClInclude Include="map_driver.hpp" />
<ClInclude Include="mem_ctx\mem_ctx.hpp" />
<ClInclude Include="patch_ctx\patch_ctx.hpp" />
<ClInclude Include="physmeme\physmeme.hpp" />
<ClInclude Include="raw_driver.hpp" />
<ClInclude Include="util\hook.hpp" />
<ClInclude Include="util\nt.hpp" />
<ClInclude Include="util\util.hpp" />
</ItemGroup>
<ItemGroup>
<MASM Include="direct.asm">
<FileType>Document</FileType>
</MASM>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>

@ -0,0 +1,109 @@
<?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\kernel_ctx">
<UniqueIdentifier>{dd3f6067-3dff-478f-9d68-b96fc0e5456c}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\mem_ctx">
<UniqueIdentifier>{9d152069-464d-4ad4-ae2e-df0337a07cbb}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\patch_ctx">
<UniqueIdentifier>{4177fe47-d484-4b01-99ae-696601214b53}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\kernel_ctx">
<UniqueIdentifier>{6eccd581-20cb-465a-9a1c-d9c8eb3fc399}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\mem_ctx">
<UniqueIdentifier>{c6462452-fbac-45ba-a0c8-597a3dfa2935}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\patch_ctx">
<UniqueIdentifier>{dabb66f8-2a8f-482d-a8e1-a309bbdc6421}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\physmeme">
<UniqueIdentifier>{2620ff7a-5d75-49c6-b340-6e0855fb9192}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\util">
<UniqueIdentifier>{25436615-f282-4963-8800-e3bd482e6fb2}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\drv_image">
<UniqueIdentifier>{9313adec-bfa8-4399-82f6-22840f247382}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\drv_image">
<UniqueIdentifier>{db98d7be-fa02-45f7-9d32-2f2e79f72de7}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="kernel_ctx\kernel_ctx.cpp">
<Filter>Source Files\kernel_ctx</Filter>
</ClCompile>
<ClCompile Include="mem_ctx\mem_ctx.cpp">
<Filter>Source Files\mem_ctx</Filter>
</ClCompile>
<ClCompile Include="patch_ctx\patch_ctx.cpp">
<Filter>Source Files\patch_ctx</Filter>
</ClCompile>
<ClCompile Include="luna-1.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="map_driver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="drv_image\drv_image.cpp">
<Filter>Source Files\drv_image</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="raw_driver.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_ctx\kernel_ctx.h">
<Filter>Header Files\kernel_ctx</Filter>
</ClInclude>
<ClInclude Include="mem_ctx\mem_ctx.hpp">
<Filter>Header Files\mem_ctx</Filter>
</ClInclude>
<ClInclude Include="patch_ctx\patch_ctx.hpp">
<Filter>Header Files\patch_ctx</Filter>
</ClInclude>
<ClInclude Include="loadup.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="physmeme\physmeme.hpp">
<Filter>Header Files\physmeme</Filter>
</ClInclude>
<ClInclude Include="util\hook.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="util\nt.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="util\util.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="direct.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="luna-1.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="map_driver.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="drv_image\drv_image.h">
<Filter>Header Files\drv_image</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="direct.asm">
<Filter>Source Files</Filter>
</MASM>
</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>

@ -0,0 +1,78 @@
#include <windows.h>
#include <iostream>
#include <fstream>
#include "kernel_ctx/kernel_ctx.h"
#include "drv_image/drv_image.h"
namespace nasa
{
bool __cdecl map_driver(std::vector<std::uint8_t>& raw_driver, void** hook_handler)
{
nasa::drv_image image(raw_driver);
nasa::kernel_ctx ctx;
//
// lambdas used for fixing driver 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));
};
//
// fix the driver image
//
image.fix_imports(_get_module, _get_export_name);
image.map();
//
// allocate memory in the kernel for the driver
//
const auto pool_base =
ctx.allocate_pool(
image.size(),
NonPagedPool
);
if (!pool_base)
return -1;
image.relocate(pool_base);
//
// copy driver into the kernel
//
ctx.wkm(image.data(), pool_base, image.size());
//
// driver entry
//
auto entry_point = reinterpret_cast<std::uintptr_t>(pool_base) + image.entry_point();
//
// call driver entry
//
auto result = ctx.syscall<DRIVER_INITIALIZE>(
reinterpret_cast<void*>(entry_point),
hook_handler
);
//
// zero driver headers
//
ctx.zero_kernel_memory(pool_base, image.header_size());
return !result; // 0x0 means STATUS_SUCCESS
}
bool __cdecl map_driver(std::uint8_t *image, std::size_t size, void** hook_handler)
{
auto data = std::vector<std::uint8_t>(image, image + size);
return map_driver(data, hook_handler);
}
}

@ -0,0 +1,8 @@
#pragma once
#include <vector>
namespace nasa
{
bool __cdecl map_driver(std::vector<std::uint8_t>& raw_driver, void** hook_handler);
bool __cdecl map_driver(std::uint8_t* image, std::size_t size, void** hook_handler);
}

@ -0,0 +1,466 @@
#include "mem_ctx.hpp"
#include <cassert>
namespace nasa
{
mem_ctx::mem_ctx(kernel_ctx& krnl_ctx, DWORD pid)
:
k_ctx(&krnl_ctx),
dirbase(get_dirbase(krnl_ctx, pid)),
pid(pid)
{
genesis_page.first = VirtualAlloc(
NULL,
PAGE_SIZE,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
//
// page in the page, do not remove this makes the entries.
//
*(std::uintptr_t*)genesis_page.first = 0xC0FFEE;
//
// flush tlb since we just accessed the page
//
page_accessed();
//
// get the ppte and pte of the page we allocated
//
auto [page_ppte, page_pte] = get_pte(genesis_page.first, true);
genesis_page.second = page_pte;
//
// allocate a page that will get the mapping of the first pages PT
//
genesis_cursor.first = reinterpret_cast<::ppte>(
VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
//
// page it in
//
*(std::uintptr_t*)genesis_cursor.first = 0xC0FFEE;
//
// flush tlb since we just accessed the page
//
page_accessed();
//
// get ppte and pte of the cursor page.
//
auto [cursor_ppte, cursor_pte] = get_pte(genesis_cursor.first, true);
genesis_cursor.second = cursor_pte;
//
// change the page to the PT of the first page we allocated.
//
cursor_pte.pfn = reinterpret_cast<std::uint64_t>(page_ppte) >> 12;
set_pte(genesis_cursor.first, cursor_pte, true);
//
// change the offset of genesis cursor page to genesis pages pt_index since the page is now a PT
// WARNING: pointer arithmetic, do not add pt_index * 8
//
genesis_cursor.first += +virt_addr_t{ genesis_page.first }.pt_index;
//
// since the page has been accessed we need to reset this bit in the PTE.
//
page_accessed();
}
mem_ctx::~mem_ctx()
{
set_pte(genesis_page.first, genesis_page.second, true);
set_pte(genesis_cursor.first, genesis_cursor.second, true);
}
void* mem_ctx::set_page(void* addr)
{
page_offset = virt_addr_t{ addr }.offset;
genesis_cursor.first->pfn = reinterpret_cast<uint64_t>(addr) >> 12;
page_accessed();
return get_page();
}
void* mem_ctx::get_page() const
{
return reinterpret_cast<void*>((reinterpret_cast<std::uint64_t>(genesis_page.first)) + page_offset);
}
void mem_ctx::page_accessed() const
{
Sleep(5);
}
void* mem_ctx::get_dirbase(kernel_ctx& k_ctx, DWORD pid)
{
if (!pid)
return NULL;
const auto peproc =
reinterpret_cast<std::uint64_t>(k_ctx.get_peprocess(pid));
if (!peproc)
return NULL;
pte dirbase = k_ctx.rkm<pte>(
reinterpret_cast<void*>(peproc + 0x28)
);
return reinterpret_cast<void*>(dirbase.pfn << 12);
}
void mem_ctx::set_dirbase(void* dirbase)
{
this->dirbase = dirbase;
}
bool mem_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 = k_ctx->rkm<pml4e>(
k_ctx->get_virtual(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 = k_ctx->rkm<pdpte>(
k_ctx->get_virtual(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 = k_ctx->rkm<pde>(
k_ctx->get_virtual(entries.pd.first));
// if its a 2mb page
if (entries.pd.second.page_size)
{
memcpy(
&entries.pt.second,
&entries.pd.second,
sizeof(pte)
);
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 = k_ctx->rkm<pte>(
k_ctx->get_virtual(entries.pt.first));
if (!entries.pt.second.value)
return false;
return true;
}
std::pair<ppte, pte> mem_ctx::get_pte(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if (use_hyperspace ? hyperspace_entries(entries, addr) : virt_to_phys(entries, addr))
{
::pte pte;
memcpy(&pte, &entries.pt.second, sizeof(pte));
return { entries.pt.first, pte };
}
return {};
}
void mem_ctx::set_pte(void* addr, const ::pte& pte, bool use_hyperspace)
{
if (!dirbase || !addr)
return;
pt_entries entries;
if (use_hyperspace)
if (hyperspace_entries(entries, addr))
k_ctx->wkm(
k_ctx->get_virtual(entries.pt.first),
pte
);
else
if (virt_to_phys(entries, addr))
write_phys(entries.pt.first, pte);
}
std::pair<ppde, pde> mem_ctx::get_pde(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if (use_hyperspace ? hyperspace_entries(entries, addr) : virt_to_phys(entries, addr))
{
::pde pde;
memcpy(
&pde,
&entries.pd.second,
sizeof(pde)
);
return { entries.pd.first, pde };
}
return {};
}
void mem_ctx::set_pde(void* addr, const ::pde& pde, bool use_hyperspace)
{
if (!dirbase || !addr)
return;
pt_entries entries;
if (use_hyperspace)
if (hyperspace_entries(entries, addr))
k_ctx->wkm(
k_ctx->get_virtual(entries.pd.first),
pde
);
else
if (virt_to_phys(entries, addr))
write_phys(entries.pd.first, pde);
}
std::pair<ppdpte, pdpte> mem_ctx::get_pdpte(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if (use_hyperspace ? hyperspace_entries(entries, addr) : virt_to_phys(entries, addr))
{
::pdpte pdpte;
memcpy(
&pdpte,
&entries.pdpt.second,
sizeof(pdpte)
);
return { entries.pdpt.first, pdpte };
}
return {};
}
void mem_ctx::set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace)
{
if (!dirbase || !addr)
return;
pt_entries entries;
if (use_hyperspace)
if (hyperspace_entries(entries, addr))
k_ctx->wkm(
k_ctx->get_virtual(entries.pdpt.first),
pdpte
);
else
if (virt_to_phys(entries, addr))
write_phys(entries.pdpt.first, pdpte);
}
std::pair<ppml4e, pml4e> mem_ctx::get_pml4e(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if (use_hyperspace ? hyperspace_entries(entries, addr) : virt_to_phys(entries, addr))
{
::pml4e pml4e;
memcpy(
&pml4e,
&entries.pml4.second,
sizeof(pml4e)
);
return { entries.pml4.first, pml4e };
}
return {};
}
void mem_ctx::set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace)
{
if (!dirbase || !addr)
return;
pt_entries entries;
if (use_hyperspace)
if (hyperspace_entries(entries, addr))
k_ctx->wkm(
k_ctx->get_virtual(entries.pml4.first),
pml4e
);
else
if (virt_to_phys(entries, addr))
write_phys(entries.pml4.first, pml4e);
}
std::pair<void*, void*> mem_ctx::read_virtual(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size || !dirbase)
return {};
virt_addr_t virt_addr{ addr };
if (size <= PAGE_SIZE - 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_SIZE - virt_addr.offset
);
// forward work load
return read_virtual(
new_buffer_addr,
new_addr,
size - (PAGE_SIZE - virt_addr.offset)
);
}
}
std::pair<void*, void*> mem_ctx::write_virtual(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size || !dirbase)
return {};
virt_addr_t virt_addr{ addr };
if (size <= PAGE_SIZE - 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_SIZE - virt_addr.offset
);
// forward work load
return write_virtual(
new_buffer_addr,
new_addr,
size - (PAGE_SIZE - virt_addr.offset)
);
}
}
void mem_ctx::read_phys(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size)
return;
auto temp_page = set_page(addr);
if (temp_page)
memcpy(buffer, temp_page, size);
}
void mem_ctx::write_phys(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size)
return;
auto temp_page = set_page(addr);
if (temp_page)
memcpy(temp_page, buffer, size);
}
void* mem_ctx::virt_to_phys(pt_entries& entries, void* addr)
{
if (!addr || !dirbase)
return {};
virt_addr_t virt_addr{ addr };
//
// traverse paging tables
//
auto pml4e = read_phys<::pml4e>(
reinterpret_cast<ppml4e>(dirbase) + virt_addr.pml4_index);
entries.pml4.first = reinterpret_cast<ppml4e>(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);
}
unsigned mem_ctx::get_pid() const
{
return pid;
}
void* mem_ctx::get_dirbase() const
{
return dirbase;
}
}

@ -0,0 +1,133 @@
#pragma once
#include "../util/nt.hpp"
#include "../kernel_ctx/kernel_ctx.h"
#define FLUSH_TLB Sleep(10)
struct pt_entries
{
std::pair<ppml4e, pml4e> pml4;
std::pair<ppdpte, pdpte> pdpt;
std::pair<ppde, pde> pd;
std::pair<ppte, pte> pt;
};
namespace nasa
{
class mem_ctx
{
public:
explicit mem_ctx(kernel_ctx& k_ctx, DWORD pid);
~mem_ctx();
//
// PTE manipulation
//
std::pair<ppte, pte> get_pte(void* addr, bool use_hyperspace = false);
void set_pte(void* addr, const ::pte& pte, bool use_hyperspace = false);
//
// PDE manipulation
//
std::pair<ppde, pde> get_pde(void* addr, bool use_hyperspace = false);
void set_pde(void* addr, const ::pde& pde, bool use_hyperspace = false);
//
// PDPTE manipulation
//
std::pair<ppdpte, pdpte> get_pdpte(void* addr, bool use_hyperspace = false);
void set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace = false);
//
// PML4E manipulation
//
std::pair<ppml4e, pml4e> get_pml4e(void* addr, bool use_hyperspace = false);
void set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace = false);
//
// gets dirbase (not the PTE or PFN but actual physical address)
//
void* get_dirbase() const;
static void* get_dirbase(kernel_ctx& k_ctx, DWORD pid);
void read_phys(void* buffer, void* addr, std::size_t size);
void write_phys(void* buffer, void* addr, std::size_t size);
template <class T>
T read_phys(void* addr)
{
if (!addr)
return {};
T buffer;
read_phys((void*)&buffer, addr, sizeof(T));
return buffer;
}
template <class T>
void write_phys(void* addr, const T& data)
{
if (!addr)
return;
write_phys((void*)&data, addr, sizeof(T));
}
std::pair<void*, void*> read_virtual(void* buffer, void* addr, std::size_t size);
std::pair<void*, void*> write_virtual(void* buffer, void* addr, std::size_t size);
template <class T>
T read_virtual(void* addr)
{
if (!addr)
return {};
T buffer;
read_virtual((void*)&buffer, addr, sizeof(T));
return buffer;
}
template <class T>
void write_virtual(void* addr, const T& data)
{
write_virtual((void*)&data, addr, sizeof(T));
}
//
// linear address translation (not done by hyperspace mappings)
//
void* virt_to_phys(pt_entries& entries, void* addr);
//
// given an address fill pt entries with physical addresses and entry values.
//
bool hyperspace_entries(pt_entries& entries, void* addr);
//
// these are used for the pfn backdoor, this will be removed soon
//
void* set_page(void* addr);
//
// get current page mem_ctx is set to.
//
void* get_page() const;
//
// invalidate TLB
//
void page_accessed() const;
unsigned get_pid() const;
//
// set dirbase.
//
void set_dirbase(void* dirbase);
kernel_ctx* k_ctx;
private:
std::pair<void*, pte> genesis_page;
std::pair<ppte, pte> genesis_cursor;
void* dirbase;
unsigned pid;
unsigned short page_offset;
};
}

@ -0,0 +1,249 @@
#include "patch_ctx.hpp"
namespace nasa
{
patch_ctx::patch_ctx(nasa::mem_ctx* mem_ctx)
:
mem_ctx(mem_ctx)
{}
void* patch_ctx::patch(void* kernel_addr)
{
if (!kernel_addr)
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
pt_entries kernel_entries;
if (!mem_ctx->hyperspace_entries(kernel_entries, kernel_addr))
return {};
const auto [new_pdpt_phys, new_pdpt_virt] = make_pdpt(kernel_entries, kernel_addr);
const auto [new_pd_phys, new_pd_virt] = make_pd(kernel_entries, kernel_addr);
const auto [new_pt_phys, new_pt_virt] = make_pt(kernel_entries, kernel_addr);
const auto [new_page_phys, new_page_virt] = make_page(kernel_entries, kernel_addr);
// link pdpte to pd
(reinterpret_cast<ppdpte>(new_pdpt_virt) + kernel_addr_t.pdpt_index)->pfn = reinterpret_cast<std::uintptr_t>(new_pd_phys) >> 12;
if (kernel_entries.pd.second.page_size)
// link pde to new page if its 2mb
(reinterpret_cast<ppde>(new_pd_virt) + kernel_addr_t.pd_index)->pfn = reinterpret_cast<std::uintptr_t>(new_page_phys) >> 12;
else
{
// link pde to pt
(reinterpret_cast<ppde>(new_pd_virt) + kernel_addr_t.pd_index)->pfn = reinterpret_cast<std::uintptr_t>(new_pt_phys) >> 12;
// link pte to page (1kb)
(reinterpret_cast<ppte>(new_pt_virt) + kernel_addr_t.pt_index)->pfn = reinterpret_cast<std::uintptr_t>(new_page_phys) >> 12;
}
mapped_pml4e =
reinterpret_cast<ppml4e>(
mem_ctx->set_page(
kernel_entries.pml4.first));
new_pml4e = kernel_entries.pml4.second;
new_pml4e.pfn = reinterpret_cast<std::uintptr_t>(new_pdpt_phys) >> 12;
old_pml4e = kernel_entries.pml4.second;
return reinterpret_cast<void*>((std::uintptr_t)new_page_virt + kernel_addr_t.offset);
}
std::pair<void*, void*> patch_ctx::make_pdpt(const pt_entries& kernel_entries, void* kernel_addr)
{
if (!kernel_addr)
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
const auto pdpt = reinterpret_cast<ppdpte>(
mem_ctx->set_page(reinterpret_cast<void*>(
kernel_entries.pml4.second.pfn << 12)));
const auto new_pdpt =
reinterpret_cast<ppdpte>(VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
//
// zero pdpt and lock it.
//
memset(new_pdpt, NULL, 0x1000);
if (!VirtualLock(new_pdpt, 0x1000))
return {};
//
// copy over pdpte's
//
for (auto idx = 0u; idx < 512; ++idx)
*(pdpte*)(new_pdpt + idx) = *(pdpte*)(pdpt + idx);
//
// get physical address of new pdpt
//
pt_entries new_pdpt_entries;
const auto physical_addr =
mem_ctx->virt_to_phys(
new_pdpt_entries,
new_pdpt
);
return { physical_addr, new_pdpt };
}
std::pair<void*, void*> patch_ctx::make_pd(const pt_entries& kernel_entries, void* kernel_addr)
{
if (!kernel_addr)
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
const auto new_pd = reinterpret_cast<ppde>(
VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
//
// zero page and lock it.
//
memset(new_pd, NULL, 0x1000);
if (!VirtualLock(new_pd, 0x1000))
return {};
const auto pd = reinterpret_cast<ppde>(
mem_ctx->set_page(
reinterpret_cast<void*>(
kernel_entries.pdpt.second.pfn << 12)));
//
// copy over pde's
//
for (auto idx = 0u; idx < 512; ++idx)
*(::pde*)(new_pd + idx) = *(::pde*)(pd + idx);
//
// get physical address of new pd
//
pt_entries pd_entries;
const auto physical_addr =
mem_ctx->virt_to_phys(
pd_entries,
new_pd
);
return { physical_addr, new_pd };
}
std::pair<void*, void*> patch_ctx::make_pt(const pt_entries& kernel_entries, void* kernel_addr)
{
if (!kernel_addr || kernel_entries.pd.second.page_size) // if this address is a 2mb mapping.
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
const auto new_pt = reinterpret_cast<ppte>(
VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
//
// zero pt and lock it.
//
memset(new_pt, NULL, 0x1000);
if (!VirtualLock(new_pt, 0x1000))
return {};
const auto pt = reinterpret_cast<ppde>(
mem_ctx->set_page(
reinterpret_cast<void*>(
kernel_entries.pd.second.pfn << 12)));
//
// copy over pte's
//
for (auto idx = 0u; idx < 512; ++idx)
*(::pde*)(new_pt + idx) = *(::pde*)(pt + idx);
//
// get physical address of new pt
//
pt_entries entries;
const auto physical_addr =
mem_ctx->virt_to_phys(
entries,
new_pt
);
return { physical_addr, new_pt };
}
std::pair<void*, void*> patch_ctx::make_page(const pt_entries& kernel_entries, void* kernel_addr)
{
if (!kernel_addr)
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
//
// if its a 2mb page
//
if (kernel_entries.pd.second.page_size)
{
const auto new_page = VirtualAlloc(
NULL,
0x1000 * 512 * 2, // 4mb
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
memset(new_page, NULL, 512 * 0x1000); // zero 2mb
//
// copy 2mb one page at a time.
//
for (auto idx = 0u; idx < 512; ++idx)
{
const auto old_page = mem_ctx->set_page(reinterpret_cast<void*>((kernel_entries.pt.second.pfn << 12) + (idx * 0x1000)));
memcpy((void*)((std::uintptr_t)new_page + (idx * 0x1000)), old_page, 0x1000);
}
pt_entries new_page_entries;
const auto new_page_phys = mem_ctx->virt_to_phys(new_page_entries, new_page);
return { new_page_phys, new_page };
}
else // 1kb
{
const auto new_page = VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
//
// zero and lock new page.
//
memset(new_page, NULL, 0x1000);
if (!VirtualLock(new_page, 0x1000))
return {};
const auto old_page =
mem_ctx->set_page(
reinterpret_cast<void*>(
kernel_entries.pt.second.pfn << 12));
memcpy(new_page, old_page, 0x1000);
pt_entries new_page_entries;
const auto new_page_phys =
mem_ctx->virt_to_phys(
new_page_entries,
new_page
);
return { new_page_phys, new_page };
}
}
}

@ -0,0 +1,61 @@
#pragma once
#include "../mem_ctx/mem_ctx.hpp"
namespace nasa
{
class patch_ctx
{
public:
explicit patch_ctx(mem_ctx* mem_ctx);
//
// returns a virtual address mapping of the newly patched page(s).
//
void* patch(void* kernel_addr);
__forceinline void enable()
{
mapped_pml4e->pfn = new_pml4e.pfn;
}
__forceinline void disable()
{
mapped_pml4e->pfn = old_pml4e.pfn;
}
private:
//
// std::pair< physical page, virtual address >
//
std::pair<void*, void*> make_pdpt(const pt_entries& kernel_entries, void* kernel_addr);
std::pair<void*, void*> make_pd(const pt_entries& kernel_entries, void* kernel_addr);
std::pair<void*, void*> make_pt(const pt_entries& kernel_entries, void* kernel_addr);
std::pair<void*, void*> make_page(const pt_entries& kernel_entries, void* kernel_addr);
//
// context of the current process you want to patch.
//
mem_ctx* mem_ctx;
//
// newly created table entries and table pointers (pdpte, pde, pte)
//
pt_entries new_entries;
//
// old and new pml4e
//
pml4e new_pml4e;
pml4e old_pml4e;
//
// kernel address of the patch.
//
void* kernel_addr;
//
// pointer to the mapped pml4e
// used for enable/disable patch...
//
ppml4e mapped_pml4e;
};
}

@ -0,0 +1,196 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org>
!!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
#include "pe_image.h"
namespace nasa
{
pe_image::pe_image(std::vector<uint8_t>& image) : m_image(image)
{
m_dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(m_image.data());
m_nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS64>((uintptr_t)m_dos_header + m_dos_header->e_lfanew);
m_section_header = reinterpret_cast<IMAGE_SECTION_HEADER*>((uintptr_t)(&m_nt_headers->OptionalHeader) + m_nt_headers->FileHeader.SizeOfOptionalHeader);
}
size_t pe_image::size() const
{
return m_nt_headers->OptionalHeader.SizeOfImage;
}
uintptr_t pe_image::entry_point() const
{
return m_nt_headers->OptionalHeader.AddressOfEntryPoint;
}
void pe_image::map()
{
m_image_mapped.clear();
m_image_mapped.resize(m_nt_headers->OptionalHeader.SizeOfImage);
std::copy_n(m_image.begin(), m_nt_headers->OptionalHeader.SizeOfHeaders, m_image_mapped.begin());
for (size_t i = 0; i < m_nt_headers->FileHeader.NumberOfSections; ++i)
{
const auto& section = m_section_header[i];
const auto target = (uintptr_t)m_image_mapped.data() + section.VirtualAddress;
const auto source = (uintptr_t)m_dos_header + section.PointerToRawData;
std::copy_n(m_image.begin() + section.PointerToRawData, section.SizeOfRawData, m_image_mapped.begin() + section.VirtualAddress);
}
}
bool pe_image::process_relocation(uintptr_t image_base_delta, uint16_t data, uint8_t* relocation_base)
{
#define IMR_RELOFFSET(x) (x & 0xFFF)
switch (data >> 12 & 0xF)
{
case IMAGE_REL_BASED_HIGH:
{
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(HIWORD(image_base_delta));
break;
}
case IMAGE_REL_BASED_LOW:
{
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(LOWORD(image_base_delta));
break;
}
case IMAGE_REL_BASED_HIGHLOW:
{
const auto raw_address = reinterpret_cast<size_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<size_t>(image_base_delta);
break;
}
case IMAGE_REL_BASED_DIR64:
{
auto UNALIGNED raw_address = reinterpret_cast<DWORD_PTR UNALIGNED*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += image_base_delta;
break;
}
case IMAGE_REL_BASED_ABSOLUTE: // No action required
case IMAGE_REL_BASED_HIGHADJ: // no action required
{
break;
}
default:
{
return false;
}
}
#undef IMR_RELOFFSET
return true;
}
void pe_image::relocate(uintptr_t base) const
{
if (m_nt_headers->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
return;
ULONG total_count_bytes;
const auto nt_headers = ImageNtHeader((void*)m_image_mapped.data());
auto relocation_directory = (PIMAGE_BASE_RELOCATION)::ImageDirectoryEntryToData(nt_headers, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &total_count_bytes);
auto image_base_delta = static_cast<uintptr_t>(static_cast<uintptr_t>(base) - (nt_headers->OptionalHeader.ImageBase));
auto relocation_size = total_count_bytes;
// This should check (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) too but lots of drivers do not have it set due to WDK defaults
const bool doRelocations = image_base_delta != 0 && relocation_size > 0;
if (!doRelocations)
return;
void* relocation_end = reinterpret_cast<uint8_t*>(relocation_directory) + relocation_size;
while (relocation_directory < relocation_end)
{
auto relocation_base = ::ImageRvaToVa(nt_headers, (void*)m_image_mapped.data(), relocation_directory->VirtualAddress, nullptr);
auto num_relocs = (relocation_directory->SizeOfBlock - 8) >> 1;
auto relocation_data = reinterpret_cast<PWORD>(relocation_directory + 1);
for (unsigned long i = 0; i < num_relocs; ++i, ++relocation_data)
if (process_relocation(image_base_delta, *relocation_data, (uint8_t*)relocation_base) == FALSE)
return;
relocation_directory = reinterpret_cast<PIMAGE_BASE_RELOCATION>(relocation_data);
}
}
template<typename T>
__forceinline T* ptr_add(void* base, uintptr_t offset)
{
return (T*)(uintptr_t)base + offset;
}
void pe_image::fix_imports(const std::function<uintptr_t(std::string_view)> get_module, const std::function<uintptr_t(const char*, const char*)> get_function)
{
ULONG size;
auto import_descriptors = static_cast<PIMAGE_IMPORT_DESCRIPTOR>(::ImageDirectoryEntryToData(m_image.data(), FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size));
if (import_descriptors == nullptr)
return;
for (; import_descriptors->Name; import_descriptors++)
{
IMAGE_THUNK_DATA* image_thunk_data;
const auto module_name = get_rva<char>(import_descriptors->Name);
const auto module_base = get_module(module_name);
if (import_descriptors->OriginalFirstThunk)
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->OriginalFirstThunk);
else
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->FirstThunk);
auto image_func_data = get_rva<IMAGE_THUNK_DATA64>(import_descriptors->FirstThunk);
for (; image_thunk_data->u1.AddressOfData; image_thunk_data++, image_func_data++)
{
uintptr_t function_address;
const auto ordinal = (image_thunk_data->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0;
const auto image_import_by_name = get_rva<IMAGE_IMPORT_BY_NAME>(*(DWORD*)image_thunk_data);
const auto name_of_import = static_cast<char*>(image_import_by_name->Name);
function_address = get_function(module_name, name_of_import);
image_func_data->u1.Function = function_address;
}
}
}
void* pe_image::data()
{
return m_image_mapped.data();
}
size_t pe_image::header_size()
{
return m_nt_headers->OptionalHeader.SizeOfHeaders;
}
}

@ -0,0 +1,73 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org>
!!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
#pragma once
#include <vector>
#define WIN32_NO_STATUS
#include <Windows.h>
#include <Winternl.h>
#undef WIN32_NO_STATUS
#include <ntstatus.h>
#include <functional>
#include <DbgHelp.h>
#include <variant>
#pragma comment(lib, "Dbghelp.lib")
namespace nasa
{
class pe_image
{
std::vector<uint8_t> m_image;
std::vector<uint8_t> m_image_mapped;
PIMAGE_DOS_HEADER m_dos_header = nullptr;
PIMAGE_NT_HEADERS64 m_nt_headers = nullptr;
PIMAGE_SECTION_HEADER m_section_header = nullptr;
public:
pe_image(std::vector<uint8_t>& image);
size_t size() const;
uintptr_t entry_point() const;
void map();
static bool process_relocation(size_t image_base_delta, uint16_t data, uint8_t* relocation_base);
void relocate(uintptr_t base) const;
template<typename T>
__forceinline T* get_rva(const unsigned long offset)
{
return (T*)::ImageRvaToVa(m_nt_headers, m_image.data(), offset, nullptr);
}
void fix_imports(const std::function<uintptr_t(std::string_view)> get_module, const std::function<uintptr_t(const char*, const char*)> get_function);
void* data();
size_t header_size();
};
}

@ -0,0 +1,92 @@
#pragma once
#include <windows.h>
#include <mutex>
#include <cstdint>
#include <map>
#include "../util/util.hpp"
#include "../loadup.hpp"
#include "../raw_driver.hpp"
#pragma pack ( push, 1 )
typedef struct _GIOMAP
{
unsigned long interface_type;
unsigned long bus;
std::uintptr_t physical_address;
unsigned long io_space;
unsigned long size;
} GIOMAP;
#pragma pack ( pop )
namespace nasa
{
inline std::string drv_key;
inline HANDLE drv_handle = NULL;
inline std::vector<std::pair<std::uintptr_t, std::uint32_t >> virtual_mappings;
inline bool load_drv()
{
const auto [result, key] =
driver::load(
i6::raw_driver,
sizeof(i6::raw_driver)
);
drv_key = key;
drv_handle = CreateFile(
"\\\\.\\GIO",
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
return drv_handle;
}
inline bool unload_drv()
{
return CloseHandle(drv_handle) && driver::unload(drv_key);
}
inline std::uintptr_t map_phys(
std::uintptr_t addr,
std::size_t size
)
{
GIOMAP in_buffer = { 0, 0, addr, 0, size };
uintptr_t out_buffer[2] = { 0 };
unsigned long returned = 0;
DeviceIoControl(drv_handle, 0xC3502004, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
virtual_mappings.emplace_back(std::pair<std::uintptr_t, std::size_t>(out_buffer[0], size));
return out_buffer[0];
}
inline bool unmap_phys(
std::uintptr_t addr,
std::size_t size
)
{
uintptr_t in_buffer = addr;
uintptr_t out_buffer[2] = { sizeof(out_buffer) };
unsigned long returned = NULL;
DeviceIoControl(drv_handle, 0xC3502008, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
return out_buffer[0];
}
inline void unmap_all()
{
__try
{
for (auto idx = 0u; idx < virtual_mappings.size(); ++idx)
unmap_phys(virtual_mappings[idx].first, virtual_mappings[idx].second);
}
__except (EXCEPTION_ACCESS_VIOLATION) {}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,182 @@
/*
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 <map>
#include <atomic>
#include <memory>
#if _M_IX86
#define OFFSET_TO_ADDRESS 0x1
#elif _M_X64
#define OFFSET_TO_ADDRESS 0x2
#endif
namespace hook
{
class detour
{
public:
detour(void* addr_to_hook, void* jmp_to, bool enable = true)
: hook_addr(addr_to_hook), detour_addr(jmp_to), hook_installed(false)
{
//setup hook
memcpy(
jmp_code + OFFSET_TO_ADDRESS,
&jmp_to,
sizeof(jmp_to)
);
//save bytes
memcpy(
org_bytes,
hook_addr,
sizeof(org_bytes)
);
if(enable)
install();
}
void install()
{
if (hook_installed.load())
return;
// mapped page is already read/write
memcpy(hook_addr, jmp_code, sizeof(jmp_code));
hook_installed.exchange(true);
}
void uninstall()
{
if (!hook_installed.load())
return;
// mapped page is already read/write
memcpy(hook_addr, org_bytes, sizeof(org_bytes));
hook_installed.exchange(false);
}
~detour() { uninstall(); }
bool installed() { return hook_installed; }
void* hook_address() { return hook_addr; }
void* detour_address() { return detour_addr; }
private:
std::atomic<bool> hook_installed;
void *hook_addr, *detour_addr;
#if _M_IX86
/*
0: b8 ff ff ff ff mov eax, 0xffffffff
5: ff e0 jmp eax
*/
unsigned char jmp_code[7] = {
0xb8, 0x0, 0x0, 0x0, 0x0,
0xFF, 0xE0
};
#elif _M_X64
/*
0: 48 b8 ff ff ff ff ff ff ff ff movabs rax,0xffffffffffffffff
7: ff e0 jmp rax
*/
unsigned char jmp_code[12] = {
0x48, 0xb8,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0xff, 0xe0
};
#endif
std::uint8_t org_bytes[sizeof(jmp_code)];
};
static std::map<void*, std::unique_ptr<detour>> hooks{};
/*
Author: xerox
Date: 12/19/2019
Create Hook without needing to deal with objects
*/
static void make_hook(void* addr_to_hook, void* jmp_to_addr, bool enable = true)
{
if (!addr_to_hook)
return;
hooks.insert({
addr_to_hook,
std::make_unique<detour>(
addr_to_hook,
jmp_to_addr,
enable
)}
);
}
/*
Author: xerox
Date: 12/19/2019
Enable hook given the address to hook
*/
static void enable(void* addr)
{
if (!addr)
return;
hooks.at(addr)->install();
}
/*
Author: xerox
Date: 12/19/2019
Disable hook givent the address of the hook
*/
static void disable(void* addr)
{
if (!addr)
return;
hooks.at(addr)->uninstall();
}
/*
Author: xerox
Date: 12/19/2019
Remove hook completely from vector
*/
static void remove(void* addr)
{
if (!addr)
return;
hooks.at(addr)->~detour();
hooks.erase(addr);
}
}

@ -0,0 +1,343 @@
#pragma once
#include <Windows.h>
#include <winternl.h>
#include <ntstatus.h>
#pragma comment(lib, "ntdll.lib")
#if false
#define DBG_ASSERT(...)
#define DBG_PRINT(...)
#else
#define DBG_ASSERT(...) assert(__VA_ARGS__)
#define DBG_PRINT(...) printf(__VA_ARGS__)
#endif
inline const char piddb_lock_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x4C\x8B\x8C\x24";
inline const char piddb_lock_mask[] = "xxx????x????xxxx";
inline const char piddb_table_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8D\x1D\x00\x00\x00\x00\x48\x85\xC0\x0F";
inline const char piddb_table_mask[] = "xxx????x????xxx????xxxx";
#define MM_COPY_MEMORY_PHYSICAL 0x1
#define MM_COPY_MEMORY_VIRTUAL 0x2
constexpr auto PAGE_SIZE = 0x1000;
constexpr auto SystemModuleInformation = 11;
constexpr auto SystemHandleInformation = 16;
constexpr auto SystemExtendedHandleInformation = 64;
typedef struct PiDDBCacheEntry
{
LIST_ENTRY list;
UNICODE_STRING driver_name;
ULONG time_stamp;
NTSTATUS load_status;
char _0x0028[16]; // data from the shim engine, or uninitialized memory for custom drivers
}PIDCacheobj;
typedef struct _SYSTEM_HANDLE
{
PVOID Object;
HANDLE UniqueProcessId;
HANDLE HandleValue;
ULONG GrantedAccess;
USHORT CreatorBackTraceIndex;
USHORT ObjectTypeIndex;
ULONG HandleAttributes;
ULONG Reserved;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
ULONG_PTR HandleCount;
ULONG_PTR Reserved;
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX;
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;
typedef CCHAR KPROCESSOR_MODE;
typedef enum _MODE {
KernelMode,
UserMode,
MaximumMode
} MODE;
typedef enum _POOL_TYPE {
NonPagedPool,
NonPagedPoolExecute,
PagedPool,
NonPagedPoolMustSucceed,
DontUseThisType,
NonPagedPoolCacheAligned,
PagedPoolCacheAligned,
NonPagedPoolCacheAlignedMustS,
MaxPoolType,
NonPagedPoolBase,
NonPagedPoolBaseMustSucceed,
NonPagedPoolBaseCacheAligned,
NonPagedPoolBaseCacheAlignedMustS,
NonPagedPoolSession,
PagedPoolSession,
NonPagedPoolMustSucceedSession,
DontUseThisTypeSession,
NonPagedPoolCacheAlignedSession,
PagedPoolCacheAlignedSession,
NonPagedPoolCacheAlignedMustSSession,
NonPagedPoolNx,
NonPagedPoolNxCacheAligned,
NonPagedPoolSessionNx
} POOL_TYPE;
typedef enum _MEMORY_CACHING_TYPE {
MmNonCached,
MmCached,
MmWriteCombined,
MmHardwareCoherentCached,
MmNonCachedUnordered,
MmUSWCCached,
MmMaximumCacheType,
MmNotMapped
} MEMORY_CACHING_TYPE;
typedef struct _KAPC_STATE {
LIST_ENTRY ApcListHead[MaximumMode];
struct _KPROCESS* Process;
union {
UCHAR InProgressFlags;
struct {
BOOLEAN KernelApcInProgress : 1;
BOOLEAN SpecialApcInProgress : 1;
};
};
BOOLEAN KernelApcPending;
union {
BOOLEAN UserApcPendingAll;
struct {
BOOLEAN SpecialUserApcPending : 1;
BOOLEAN UserApcPending : 1;
};
};
} KAPC_STATE, * PKAPC_STATE, * PRKAPC_STATE;
using PEPROCESS = PVOID;
using ZwOpenProcess = NTSYSAPI NTSTATUS (__fastcall*)(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
CLIENT_ID* ClientId
);
using ZwAllocateVirtualMemory = NTSTATUS(__fastcall*)(
_In_ HANDLE ProcessHandle,
_Inout_ PVOID* BaseAddress,
_In_ ULONG_PTR ZeroBits,
_Inout_ PSIZE_T RegionSize,
_In_ ULONG AllocationType,
_In_ ULONG Protect
);
using MmCopyVirtualMemory = NTSTATUS (__fastcall*)(
IN PEPROCESS FromProcess,
IN PVOID FromAddress,
IN PEPROCESS ToProcess,
OUT PVOID ToAddress,
IN SIZE_T BufferSize,
IN KPROCESSOR_MODE PreviousMode,
OUT PSIZE_T NumberOfBytesCopied
);
using PsLookupProcessByProcessId = NTSTATUS (__fastcall*)(
HANDLE ProcessId,
PEPROCESS* Process
);
using MmCopyMemory = NTSTATUS(__stdcall*)(
PVOID,
MM_COPY_ADDRESS,
SIZE_T,
ULONG,
PSIZE_T
);
using MmGetVirtualForPhysical = PVOID(__fastcall*)(
__in PHYSICAL_ADDRESS PhysicalAddress
);
using MmGetPhysicalAddress = PVOID (__fastcall*)(
__in PVOID BaseAddress
);
using ExAllocatePool = PVOID (__fastcall*) (
POOL_TYPE PoolType,
SIZE_T NumberOfBytes
);
using IoAllocateMdl = PVOID(__fastcall*)(
__drv_aliasesMem PVOID VirtualAddress,
ULONG Length,
BOOLEAN SecondaryBuffer,
BOOLEAN ChargeQuota,
PVOID Irp
);
using MmBuildMdlForNonPagedPool = void (__fastcall*)(
PVOID MemoryDescriptorList
);
using MmMapLockedPagesSpecifyCache = PVOID (__fastcall*)(
PVOID MemoryDescriptorList,
KPROCESSOR_MODE AccessMode,
MEMORY_CACHING_TYPE CacheType,
PVOID RequestedAddress,
ULONG BugCheckOnFailure,
ULONG Priority
);
using ExFreePool = void* (__fastcall*)(
PVOID P
);
using ExAllocatePool = PVOID(__stdcall*) (POOL_TYPE, SIZE_T);
using ExAllocatePoolWithTag = PVOID(__stdcall*)(POOL_TYPE, SIZE_T, ULONG);
using MmCopyMemory = NTSTATUS(__stdcall*)(PVOID, MM_COPY_ADDRESS, SIZE_T, ULONG, PSIZE_T);
using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(void**);
using ExAcquireResourceExclusiveLite = BOOLEAN(__stdcall*)(void*, bool);
using RtlLookupElementGenericTableAvl = PIDCacheobj * (__stdcall*) (void*, void*);
using RtlDeleteElementGenericTableAvl = bool(__stdcall*)(void*, void*);
using ExReleaseResourceLite = bool(__stdcall*)(void*);
using PsGetProcessSectionBaseAddress = void* (__fastcall*)(PEPROCESS);
typedef union _virt_addr_t
{
PVOID value;
struct
{
ULONG64 offset : 12;
ULONG64 pt_index : 9;
ULONG64 pd_index : 9;
ULONG64 pdpt_index : 9;
ULONG64 pml4_index : 9;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PDPT.
ULONG64 page_cache : 1; // Determines the memory type used to access PDPT.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Ignored1 : 1;
ULONG64 page_size : 1; // Must be 0 for PML4E.
ULONG64 Ignored2 : 4;
ULONG64 pfn : 36; // The page frame number of the PDPT of this PML4E.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 11;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 rw : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PD.
ULONG64 page_cache : 1; // Determines the memory type used to access PD.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Ignored1 : 1;
ULONG64 page_size : 1; // If 1, this entry maps a 1GB page.
ULONG64 Ignored2 : 4;
ULONG64 pfn : 36; // The page frame number of the PD of this PDPTE.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 11;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PT.
ULONG64 page_cache : 1; // Determines the memory type used to access PT.
ULONG64 Accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Ignored1 : 1;
ULONG64 page_size : 1; // If 1, this entry maps a 2MB page.
ULONG64 Ignored2 : 4;
ULONG64 pfn : 36; // The page frame number of the PT of this PDE.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 11;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access the memory.
ULONG64 page_cache : 1; // Determines the memory type used to access the memory.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Dirty : 1; // If 0, the memory backing this page has not been written to.
ULONG64 PageAccessType : 1; // Determines the memory type used to access the memory.
ULONG64 Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
ULONG64 Ignored2 : 3;
ULONG64 pfn : 36; // The page frame number of the backing physical page.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 7;
ULONG64 ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
ULONG64 nx : 1; // If 1, instruction fetches not allowed.
};
} pte, * ppte;
static_assert(sizeof(pte) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");

@ -0,0 +1,470 @@
#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 <atomic>
#include <algorithm>
#include "nt.hpp"
namespace util
{
//--- ranges of physical memory
inline std::map<std::uintptr_t, std::size_t> pmem_ranges;
//--- validates the address
inline bool is_valid(std::uintptr_t addr)
{
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;
})();
inline std::uintptr_t get_module_base(const char* module_name)
{
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;
}
inline bool enable_privilege(const std::wstring_view 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;
}
// taken from:
// http://www.cplusplus.com/forum/windows/12137/
inline DWORD get_pid(const char* proc_name)
{
PROCESSENTRY32 proc_info;
proc_info.dwSize = sizeof(proc_info);
HANDLE proc_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (proc_snapshot == INVALID_HANDLE_VALUE)
return NULL;
Process32First(proc_snapshot, &proc_info);
if (!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;
}
// this was taken from wlan's drvmapper:
// https://github.com/not-wlan/drvmap/blob/98d93cc7b5ec17875f815a9cb94e6d137b4047ee/drvmap/util.cpp#L7
inline void open_binary_file(const std::string& file, std::vector<uint8_t>& data)
{
std::ifstream fstr(file, std::ios::binary);
fstr.unsetf(std::ios::skipws);
fstr.seekg(0, std::ios::end);
const auto file_size = fstr.tellg();
fstr.seekg(NULL, std::ios::beg);
data.reserve(static_cast<uint32_t>(file_size));
data.insert(data.begin(), std::istream_iterator<uint8_t>(fstr), std::istream_iterator<uint8_t>());
}
// get base address of kernel module
//
// taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30
inline std::uintptr_t get_kernel_module_base(const char* module_name)
{
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;
}
// get base address of kernel module
//
// taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30
inline void* get_module_export(const char* module_name, const char* export_name, bool rva = false)
{
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 = LoadLibraryEx(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);
// find exported function
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;
}
inline void* get_module_export(void* module_base, const char* export_name)
{
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);
// find exported function
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;
}
inline unsigned start_runtime_broker()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
CreateProcessA(
NULL,
(LPSTR)"C:\\Windows\\System32\\RuntimeBroker.exe",
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi
);
SuspendThread(pi.hThread);
return pi.dwProcessId;
}
inline PIMAGE_FILE_HEADER get_file_header(void* base_addr)
{
if (!base_addr || *(short*)base_addr != 0x5A4D)
return NULL;
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;
}
namespace memory
{
template<std::size_t pattern_length>
inline std::uintptr_t pattern_scan_kernel(const char(&signature)[pattern_length], const char(&mask)[pattern_length])
{
static const auto kernel_addr =
LoadLibraryEx(
"ntoskrnl.exe",
NULL,
DONT_RESOLVE_DLL_REFERENCES
);
static const auto p_idh = reinterpret_cast<PIMAGE_DOS_HEADER>(kernel_addr);
if (p_idh->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
static const auto p_inh = reinterpret_cast<PIMAGE_NT_HEADERS>((LPBYTE)kernel_addr + p_idh->e_lfanew);
if (p_inh->Signature != IMAGE_NT_SIGNATURE)
return NULL;
static auto current_section = reinterpret_cast<PIMAGE_SECTION_HEADER>(p_inh + 1);
static const auto first_section = current_section;
static const auto num_sec = p_inh->FileHeader.NumberOfSections;
static std::atomic<bool> ran_before = false;
//
// only run this once.
//
if (!ran_before.exchange(true))
for (; current_section < first_section + num_sec; ++current_section)
if (!strcmp(reinterpret_cast<char*>(current_section->Name), "PAGE"))
break;
static const auto page_section_begin =
reinterpret_cast<std::uint64_t>(kernel_addr) + current_section->VirtualAddress;
const auto pattern_view = std::string_view{
reinterpret_cast<char*>(page_section_begin),
current_section->SizeOfRawData
};
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);
});
return resultant_address == pattern_view.cend() ? 0 : reinterpret_cast<std::uintptr_t>(resultant_address.operator->());
}
//
// be aware that this may not work for win8 or win7!
//
inline void* get_piddb_lock()
{
static const auto absolute_addr_instruction =
pattern_scan_kernel(
piddb_lock_sig,
piddb_lock_mask
);
static const auto ntoskrnl_in_my_process =
reinterpret_cast<std::uintptr_t>(GetModuleHandle("ntoskrnl.exe"));
if (!absolute_addr_instruction || !ntoskrnl_in_my_process)
return {};
const auto lea_rip_rva = *(PLONG)(absolute_addr_instruction + 3);
const auto real_rva = (absolute_addr_instruction + 7 + lea_rip_rva) - ntoskrnl_in_my_process;
static const auto kernel_base = util::get_module_base("ntoskrnl.exe");
if (!kernel_base)
return {};
return reinterpret_cast<void*>(kernel_base + real_rva);
}
//
// be aware that this may not work for win8 or win7!
//
inline void* get_piddb_table()
{
static const auto absolute_addr_instruction =
pattern_scan_kernel(
piddb_table_sig,
piddb_table_mask
);
static const auto ntoskrnl_in_my_process =
reinterpret_cast<std::uintptr_t>(GetModuleHandle("ntoskrnl.exe"));
if (!absolute_addr_instruction || !ntoskrnl_in_my_process)
return {};
const auto lea_rip_rva = *(PLONG)(absolute_addr_instruction + 3);
const auto real_rva = (absolute_addr_instruction + 7 + lea_rip_rva) - ntoskrnl_in_my_process;
static const auto kernel_base = util::get_module_base("ntoskrnl.exe");
if (!kernel_base)
return {};
return reinterpret_cast<void*>(kernel_base + real_rva);
}
}
}

@ -0,0 +1,79 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luna-1", "luna-1\luna-1.vcxproj", "{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luna-1(km)", "luna-1(km)\luna-1(km).vcxproj", "{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luna-1(example)", "luna-1(example)\luna-1(example).vcxproj", "{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}"
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
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|ARM.ActiveCfg = Debug|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|ARM64.ActiveCfg = Debug|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|x64.ActiveCfg = Debug|x64
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|x64.Build.0 = Debug|x64
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|x86.ActiveCfg = Debug|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Debug|x86.Build.0 = Debug|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|ARM.ActiveCfg = Release|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|ARM64.ActiveCfg = Release|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|x64.ActiveCfg = Release|x64
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|x64.Build.0 = Release|x64
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|x86.ActiveCfg = Release|Win32
{334EDBD9-6A7C-4F6A-8EEC-022F8C2C04C3}.Release|x86.Build.0 = Release|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM.ActiveCfg = Debug|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM.Build.0 = Debug|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM.Deploy.0 = Debug|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM64.ActiveCfg = Debug|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM64.Build.0 = Debug|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|ARM64.Deploy.0 = Debug|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x64.ActiveCfg = Debug|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x64.Build.0 = Debug|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x64.Deploy.0 = Debug|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x86.ActiveCfg = Debug|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x86.Build.0 = Debug|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Debug|x86.Deploy.0 = Debug|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM.ActiveCfg = Release|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM.Build.0 = Release|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM.Deploy.0 = Release|ARM
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM64.ActiveCfg = Release|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM64.Build.0 = Release|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|ARM64.Deploy.0 = Release|ARM64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x64.ActiveCfg = Release|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x64.Build.0 = Release|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x64.Deploy.0 = Release|x64
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x86.ActiveCfg = Release|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x86.Build.0 = Release|Win32
{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}.Release|x86.Deploy.0 = Release|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|ARM.ActiveCfg = Debug|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|ARM64.ActiveCfg = Debug|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|x64.ActiveCfg = Debug|x64
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|x64.Build.0 = Debug|x64
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|x86.ActiveCfg = Debug|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Debug|x86.Build.0 = Debug|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|ARM.ActiveCfg = Release|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|ARM64.ActiveCfg = Release|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|x64.ActiveCfg = Release|x64
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|x64.Build.0 = Release|x64
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|x86.ActiveCfg = Release|Win32
{14450AD4-F983-46E9-B7A8-F1B6313BFF6D}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F503F818-2E0C-43DD-B842-3E2B8BE82E44}
EndGlobalSection
EndGlobal

@ -0,0 +1,157 @@
<?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>{14450ad4-f983-46e9-b7a8-f1b6313bff6d}</ProjectGuid>
<RootNamespace>luna1example</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</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>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</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>
<AdditionalDependencies>luna-1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</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>
<AdditionalDependencies>luna-1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>luna-1.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>luna-1.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="luna-1.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,23 @@
<?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>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="luna-1.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</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>

@ -0,0 +1,66 @@
#pragma once
#include <cstddef>
#include <cstdint>
namespace i6
{
//
// please call this before making any other calls!
//
bool begin();
//
// get process id of process.
//
unsigned get_pid(const char* proc_name);
//
// get process base address.
//
std::uintptr_t get_process_base(unsigned pid);
//
// get module base
//
std::uintptr_t get_module_base(unsigned pid, const wchar_t* module_name);
//
// read/write to specific process
//
bool read(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size);
bool write(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size);
//
// read/write kernel memory (you can write to readonly with this)
//
bool rkm(std::uintptr_t addr, void* buffer, std::size_t size);
bool wkm(std::uintptr_t addr, void* buffer, std::size_t size);
template <class T>
T rkm(std::uintptr_t addr)
{
T buffer{};
rkm(addr, (void*)&buffer, sizeof(T));
return buffer;
}
template <class T>
bool wkm(std::uintptr_t addr, const T& data)
{
return wkm(addr, (void*)&data, sizeof(T));
}
template <class T>
T read(unsigned pid, std::uintptr_t addr)
{
T buffer{};
read(pid, addr, (void*)&buffer, sizeof(T));
return buffer;
}
template <class T>
bool write(unsigned pid, std::uintptr_t addr, const T& data)
{
return write(pid, addr, (void*)&data, sizeof(T));
}
}

@ -0,0 +1,23 @@
#include <iostream>
#include "luna-1.hpp"
int main()
{
if (!i6::begin()) // call this before anything else.
{
std::cout << "[!] failed to init..." << std::endl;
std::cin.get();
return -1;
}
else
{
auto notepad_pid = i6::get_pid("notepad.exe");
auto notepad_base = i6::get_process_base(notepad_pid);
std::cout << "[+] notepad pid: " << notepad_pid << std::endl;
std::cout << "[+] notepad base address: " << std::hex << notepad_base << std::endl;
while(true)
std::cout << "[+] notepad MZ: " << std::hex << i6::read<short>(notepad_pid, notepad_base) << std::endl;
}
}

@ -0,0 +1,158 @@
#include "com_functions.h"
#include "memory.h"
namespace i6
{
namespace com
{
void get_process_base(const pcom_struct com_data)
{
if (!com_data || !com_data->pid)
return;
PEPROCESS peproc;
if (PsLookupProcessByProcessId((HANDLE)com_data->pid, &peproc) != STATUS_SUCCESS)
return;
com_data->data_from = PsGetProcessSectionBaseAddress(peproc);
ObDereferenceObject(peproc);
}
void get_module_base(const pcom_struct com_data)
{
if (!com_data || !com_data->pid || !com_data->data_to)
return;
PEPROCESS peproc;
if (PsLookupProcessByProcessId((HANDLE)com_data->pid, &peproc) != STATUS_SUCCESS)
return;
auto ppeb = PsGetProcessPeb(peproc);
ObDereferenceObject(peproc);
if (!ppeb)
return;
PEB peb;
i6::memory::read(
ppeb,
&peb,
sizeof(peb),
com_data->pid
);
if (!peb.Ldr)
return;
PEB_LDR_DATA module_list_entry;
i6::memory::read(
peb.Ldr,
&module_list_entry,
sizeof(module_list_entry),
com_data->pid
);
auto first_entry = (void*)module_list_entry.InMemoryOrderModuleList.Flink;
unsigned char* current_entry;
i6::memory::read(
first_entry,
&current_entry,
sizeof(current_entry),
com_data->pid
);
WCHAR full_file_name[MAX_PATH];
ULONGLONG module_base;
ULONGLONG file_name_ptr;
while (current_entry != first_entry)
{
i6::memory::read(
(unsigned char*)(current_entry)+0x40,
&file_name_ptr,
sizeof(file_name_ptr),
com_data->pid
); // read full module unicode_string structure.
i6::memory::read(
(void*)file_name_ptr,
full_file_name,
MAX_PATH,
com_data->pid
); // read full file path.
i6::memory::read(
(unsigned char*)(current_entry)+0x20,
&module_base,
sizeof(module_base),
com_data->pid
);
if (wcsstr(full_file_name, (wchar_t*)com_data->data_to))
{
com_data->data_from = reinterpret_cast<void*>(module_base);
return;
}
i6::memory::read(
current_entry,
&current_entry,
sizeof(current_entry),
com_data->pid
);
}
}
void read_process_memory(const pcom_struct com_data)
{
if (!com_data || !com_data->pid || !com_data->data_from || !com_data->data_to || !com_data->size)
return;
i6::memory::read(
com_data->data_from,
com_data->data_to,
com_data->size,
com_data->pid
);
}
void write_process_memory(const pcom_struct com_data)
{
if (!com_data || !com_data->pid || !com_data->data_from || !com_data->data_to || !com_data->size)
return;
i6::memory::write
(
com_data->data_to,
com_data->data_from,
com_data->size,
com_data->pid
);
}
void read_kernel_memory(const pcom_struct com_data)
{
if (!com_data || !com_data->data_from || !com_data->data_to)
return;
memcpy
(
com_data->data_to,
com_data->data_from,
com_data->size
);
}
void write_kernel_memory(const pcom_struct com_data)
{
if (!com_data || !com_data->data_from || !com_data->data_to)
return;
memcpy
(
com_data->data_to,
com_data->data_from,
com_data->size
);
}
}
}

@ -0,0 +1,15 @@
#pragma once
#include "types.h"
namespace i6
{
namespace com
{
void get_process_base(const pcom_struct com_data);
void get_module_base(const pcom_struct com_data);
void read_process_memory(const pcom_struct com_data);
void write_process_memory(const pcom_struct com_data);
void read_kernel_memory(const pcom_struct com_data);
void write_kernel_memory(const pcom_struct com_data);
}
}

@ -0,0 +1,41 @@
#include "com_functions.h"
#include "memory.h"
void hook_handler(pcom_struct com_data)
{
if (!com_data)
return;
switch (com_data->type)
{
case READ:
i6::com::read_process_memory(com_data);
break;
case WRITE:
i6::com::write_process_memory(com_data);
break;
case WRITE_KERNEL_MEMORY:
i6::com::write_kernel_memory(com_data);
break;
case READ_KERNEL_MEMORY:
i6::com::read_kernel_memory(com_data);
break;
case GET_PROCESS_BASE:
i6::com::get_process_base(com_data);
break;
case GET_MODULE_BASE:
i6::com::get_module_base(com_data);
break;
default:
break;
}
}
NTSTATUS driver_entry(void** data_ptr)
{
if (!MmIsAddressValid(data_ptr))
return STATUS_ABANDONED;
*data_ptr = &hook_handler;
return STATUS_SUCCESS;
}

@ -0,0 +1,87 @@
;
; luna-1(km).inf
;
[Version]
Signature="$WINDOWS NT$"
Class=Sample ; TODO: edit Class
ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid
Provider=%ManufacturerName%
CatalogFile=luna-1(km).cat
DriverVer= ; TODO: set DriverVer in stampinf property pages
PnpLockDown=1
[DestinationDirs]
DefaultDestDir = 12
luna-1(km)_Device_CoInstaller_CopyFiles = 11
; ================= Class section =====================
[ClassInstall32]
Addreg=SampleClassReg
[SampleClassReg]
HKR,,,0,%ClassName%
HKR,,Icon,,-5
[SourceDisksNames]
1 = %DiskName%,,,""
[SourceDisksFiles]
luna-1(km).sys = 1,,
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames
;*****************************************
; Install Section
;*****************************************
[Manufacturer]
%ManufacturerName%=Standard,NT$ARCH$
[Standard.NT$ARCH$]
%luna-1(km).DeviceDesc%=luna-1(km)_Device, Root\luna-1(km) ; TODO: edit hw-id
[luna-1(km)_Device.NT]
CopyFiles=Drivers_Dir
[Drivers_Dir]
luna-1(km).sys
;-------------- Service installation
[luna-1(km)_Device.NT.Services]
AddService = luna-1(km),%SPSVCINST_ASSOCSERVICE%, luna-1(km)_Service_Inst
; -------------- luna-1(km) driver install sections
[luna-1(km)_Service_Inst]
DisplayName = %luna-1(km).SVCDESC%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\luna-1(km).sys
;
;--- luna-1(km)_Device Coinstaller installation ------
;
[luna-1(km)_Device.NT.CoInstallers]
AddReg=luna-1(km)_Device_CoInstaller_AddReg
CopyFiles=luna-1(km)_Device_CoInstaller_CopyFiles
[luna-1(km)_Device_CoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
[luna-1(km)_Device_CoInstaller_CopyFiles]
WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
[luna-1(km)_Device.NT.Wdf]
KmdfService = luna-1(km), luna-1(km)_wdfsect
[luna-1(km)_wdfsect]
KmdfLibraryVersion = $KMDFVERSION$
[Strings]
SPSVCINST_ASSOCSERVICE= 0x00000002
ManufacturerName="<Your manufacturer name>" ;TODO: Replace with your manufacturer name
ClassName="Samples" ; TODO: edit ClassName
DiskName = "luna-1(km) Installation Disk"
luna-1(km).DeviceDesc = "luna-1(km) Device"
luna-1(km).SVCDESC = "luna-1(km) Service"

@ -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>{D8ED4627-18E7-4E6F-8C20-8809EB66B6D6}</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>luna_1_km_</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>
<SpectreMitigation>false</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>
<SpectreMitigation>false</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>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
</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)'=='Release|x64'">
<ClCompile>
<TreatWarningAsError>false</TreatWarningAsError>
<LanguageStandard>stdcpp17</LanguageStandard>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<EntryPointSymbol>driver_entry</EntryPointSymbol>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<FilesToPackage Include="$(TargetPath)" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="com_functions.cpp" />
<ClCompile Include="hook_handler.cpp" />
<ClCompile Include="memory.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="com_functions.h" />
<ClInclude Include="memory.h" />
<ClInclude Include="types.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,35 @@
<?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>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="memory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="com_functions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="hook_handler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="com_functions.h">
<Filter>Header Files</Filter>
</ClInclude>
</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>

@ -0,0 +1,233 @@
#include "memory.h"
namespace i6
{
namespace memory
{
CURSOR_PAGE get_cursor()
{
const auto cursor =
ExAllocatePool(
NonPagedPool,
0x1000
);
memset(cursor, NULL, 0x1000);
virt_addr_t addr_t{ cursor };
const auto dirbase =
::cr3{ __readcr3() }.dirbase;
const auto pml4 =
reinterpret_cast<ppml4e>(
MmGetVirtualForPhysical(
PHYSICAL_ADDRESS{ (LONGLONG)dirbase << 12 })) + addr_t.pml4_index;
if (!MmIsAddressValid(pml4))
return {};
const auto pdpt =
reinterpret_cast<ppdpte>(
MmGetVirtualForPhysical(
PHYSICAL_ADDRESS{ (LONGLONG)pml4->pfn << 12 })) + addr_t.pdpt_index;
if (!MmIsAddressValid(pdpt))
return {};
const auto pd =
reinterpret_cast<ppde>(
MmGetVirtualForPhysical(
PHYSICAL_ADDRESS{ (LONGLONG)pdpt->pfn << 12 })) + addr_t.pd_index;
if (!MmIsAddressValid(pd))
return {};
const auto pt =
reinterpret_cast<ppte>(
MmGetVirtualForPhysical(
PHYSICAL_ADDRESS{ (LONGLONG)pd->pfn << 12 })) + addr_t.pt_index;
if (!MmIsAddressValid(pt))
return {};
return { cursor, pt, (unsigned)pt->pfn };
}
void* virt_to_phys(unsigned pid, void* addr)
{
if (!pid || !addr)
return {};
PEPROCESS peproc;
if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)pid, &peproc)) && peproc)
{
virt_addr_t addr_t{ addr };
static const auto cursor = get_cursor();
if (!cursor.pte || !cursor.org_pfn || !cursor.page)
{
ObDereferenceObject(peproc);
return {};
}
const auto dirbase = // dirbase is a pfn
*reinterpret_cast<pte*>(
reinterpret_cast<ULONGLONG>(peproc) + 0x28);
{
cursor.pte->pfn = dirbase.pfn;
KeFlushCurrentTbImmediately();
}
if (!MmIsAddressValid(reinterpret_cast<ppml4e>(cursor.page) + addr_t.pml4_index))
{
cursor.pte->pfn = cursor.org_pfn;
KeFlushCurrentTbImmediately();
ObDereferenceObject(peproc);
return {};
}
KeFlushCurrentTbImmediately();
const auto pml4e =
*reinterpret_cast<::pml4e*>(
reinterpret_cast<ppml4e>(cursor.page) + addr_t.pml4_index);
if (!pml4e.value || !pml4e.present || !pml4e.pfn)
{
cursor.pte->pfn = cursor.org_pfn;
KeFlushCurrentTbImmediately();
ObDereferenceObject(peproc);
return {};
}
{
cursor.pte->pfn = pml4e.pfn;
KeFlushCurrentTbImmediately();
}
if (!MmIsAddressValid(reinterpret_cast<ppdpte>(cursor.page) + addr_t.pdpt_index))
{
cursor.pte->pfn = cursor.org_pfn;
KeFlushCurrentTbImmediately();
ObDereferenceObject(peproc);
return {};
}
KeFlushCurrentTbImmediately();
const auto pdpte =
*reinterpret_cast<::pdpte*>(
reinterpret_cast<ppdpte>(cursor.page) + addr_t.pdpt_index);
if (!pdpte.value || !pdpte.present || !pdpte.pfn)
{
cursor.pte->pfn = cursor.org_pfn;
KeFlushCurrentTbImmediately();
ObDereferenceObject(peproc);
return {};
}
{
cursor.pte->pfn = pdpte.pfn;
KeFlushCurrentTbImmediately();
}
if (!MmIsAddressValid(reinterpret_cast<ppde>(cursor.page) + addr_t.pd_index))
{
cursor.pte->pfn = cursor.org_pfn;
KeFlushCurrentTbImmediately();
ObDereferenceObject(peproc);
return {};
}
KeFlushCurrentTbImmediately();
const auto pde =
*reinterpret_cast<::pde*>(
reinterpret_cast<ppde>(cursor.page) + addr_t.pd_index);
if (!pde.value || !pde.present || !pde.pfn)
{
cursor.pte->pfn = cursor.org_pfn;
KeFlushCurrentTbImmediately();
ObDereferenceObject(peproc);
return {};
}
{
cursor.pte->pfn = pde.pfn;
KeFlushCurrentTbImmediately();
}
if (!MmIsAddressValid(reinterpret_cast<ppte>(cursor.page) + addr_t.pt_index))
{
cursor.pte->pfn = cursor.org_pfn;
KeFlushCurrentTbImmediately();
ObDereferenceObject(peproc);
return {};
}
KeFlushCurrentTbImmediately();
const auto pte =
*reinterpret_cast<::pte*>(
reinterpret_cast<ppte>(cursor.page) + addr_t.pt_index);
if (!pte.value || !pte.present || !pte.pfn)
{
cursor.pte->pfn = cursor.org_pfn;
KeFlushCurrentTbImmediately();
ObDereferenceObject(peproc);
return {};
}
//
// reset pfn
//
{
cursor.pte->pfn = cursor.org_pfn;
KeFlushCurrentTbImmediately();
}
ObDereferenceObject(peproc);
return reinterpret_cast<void*>((pte.pfn << 12) + addr_t.offset);
}
return {};
}
void read(void* addr, void* buffer, size_t size, unsigned pid)
{
if (!addr || !MmIsAddressValid(buffer) || !size || !pid)
return;
const auto virt_addr =
MmMapIoSpace(
PHYSICAL_ADDRESS{ (LONGLONG)virt_to_phys(pid, addr) },
size + 0x1000,
MmNonCached
);
if (!MmIsAddressValid(virt_addr))
return;
memcpy(buffer, virt_addr, size);
MmUnmapIoSpace(virt_addr, size + 0x1000);
}
void write(void* addr, void* buffer, size_t size, unsigned pid)
{
if (!addr || !MmIsAddressValid(buffer) || !size || !pid)
return;
const auto virt_addr =
MmMapIoSpace(
PHYSICAL_ADDRESS{ (LONGLONG)virt_to_phys(pid, addr) },
size + 0x1000,
MmNonCached
);
if (!MmIsAddressValid(virt_addr))
return;
memcpy(virt_addr, buffer, size);
MmUnmapIoSpace(virt_addr, size + 0x1000);
}
}
}

@ -0,0 +1,12 @@
#pragma once
#include <intrin.h>
#include "types.h"
namespace i6
{
namespace memory
{
void read(void* addr, void* buffer, size_t size, unsigned pid);
void write(void* addr, void* buffer, size_t size, unsigned pid);
}
}

@ -0,0 +1,228 @@
#pragma once
#include <ntifs.h>
#include <windef.h>
enum com_type
{
READ,
WRITE,
READ_KERNEL_MEMORY,
WRITE_KERNEL_MEMORY,
GET_PROCESS_BASE,
GET_MODULE_BASE
};
typedef struct _com_struct
{
com_type type;
unsigned pid;
unsigned size;
void* data_from;
void* data_to;
} com_struct, * pcom_struct;
extern "C" PVOID PsGetProcessSectionBaseAddress(
__in PEPROCESS Process
);
extern "C" NTKERNELAPI NTSTATUS KeFlushCurrentTbImmediately();
extern "C" PPEB PsGetProcessPeb(PEPROCESS process);
extern "C" NTSTATUS MmCopyVirtualMemory(
_In_ PEPROCESS FromProcess,
_In_ CONST VOID* FromAddress,
_In_ PEPROCESS ToProcess,
_Out_opt_ PVOID ToAddress,
_In_ SIZE_T BufferSize,
_In_ KPROCESSOR_MODE PreviousMode,
_Out_ PSIZE_T NumberOfBytesCopied
);
typedef struct _PEB_LDR_DATA
{
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY
{
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
PVOID Reserved3[2];
UNICODE_STRING FullDllName;
BYTE Reserved4[8];
PVOID Reserved5[3];
#pragma warning(push)
#pragma warning(disable: 4201) // we'll always use the Microsoft compiler
union
{
ULONG CheckSum;
PVOID Reserved6;
} DUMMYUNIONNAME;
#pragma warning(pop)
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _RTL_USER_PROCESS_PARAMETERS {
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
typedef
VOID
(NTAPI* PPS_POST_PROCESS_INIT_ROUTINE) (
VOID
);
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID Reserved4[3];
PVOID AtlThunkSListPtr;
PVOID Reserved5;
ULONG Reserved6;
PVOID Reserved7;
ULONG Reserved8;
ULONG AtlThunkSListPtr32;
PVOID Reserved9[45];
BYTE Reserved10[96];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved11[128];
PVOID Reserved12[1];
ULONG SessionId;
} PEB, * PPEB;
typedef union _virt_addr_t
{
PVOID value;
struct
{
ULONG64 offset : 12;
ULONG64 pt_index : 9;
ULONG64 pd_index : 9;
ULONG64 pdpt_index : 9;
ULONG64 pml4_index : 9;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PDPT.
ULONG64 page_cache : 1; // Determines the memory type used to access PDPT.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Ignored1 : 1;
ULONG64 page_size : 1; // Must be 0 for PML4E.
ULONG64 Ignored2 : 4;
ULONG64 pfn : 36; // The page frame number of the PDPT of this PML4E.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 11;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 rw : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PD.
ULONG64 page_cache : 1; // Determines the memory type used to access PD.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Ignored1 : 1;
ULONG64 page_size : 1; // If 1, this entry maps a 1GB page.
ULONG64 Ignored2 : 4;
ULONG64 pfn : 36; // The page frame number of the PD of this PDPTE.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 11;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PT.
ULONG64 page_cache : 1; // Determines the memory type used to access PT.
ULONG64 Accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Ignored1 : 1;
ULONG64 page_size : 1; // If 1, this entry maps a 2MB page.
ULONG64 Ignored2 : 4;
ULONG64 pfn : 36; // The page frame number of the PT of this PDE.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 11;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access the memory.
ULONG64 page_cache : 1; // Determines the memory type used to access the memory.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Dirty : 1; // If 0, the memory backing this page has not been written to.
ULONG64 PageAccessType : 1; // Determines the memory type used to access the memory.
ULONG64 Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
ULONG64 Ignored2 : 3;
ULONG64 pfn : 36; // The page frame number of the backing physical page.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 7;
ULONG64 ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
ULONG64 nx : 1; // If 1, instruction fetches not allowed.
};
} pte, * ppte;
static_assert(sizeof(pte) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");
typedef union _cr3
{
ULONG64 flags;
struct
{
ULONG64 reserved1 : 3;
ULONG64 page_level_write_through : 1;
ULONG64 page_level_cache_disable : 1;
ULONG64 reserved2 : 7;
ULONG64 dirbase : 36;
ULONG64 reserved3 : 16;
};
} cr3;
typedef struct _CURSOR_PAGE
{
void* page; // virtual address
ppte pte;
unsigned org_pfn; // original pfn
} CURSOR_PAGE, *PCURSOR_PAGE;

@ -0,0 +1,30 @@
_TEXT SEGMENT
__protect_virtual_memory proc
mov r10, rcx
mov eax, 050h
syscall
ret
__protect_virtual_memory endp
__write_virtual_memory proc
mov r10, rcx
mov eax, 03Ah
syscall
ret
__write_virtual_memory endp
__read_virtual_memory proc
mov r10, rcx
mov eax, 03Fh
syscall
ret
__read_virtual_memory endp
__alloc_virtual_memory proc
mov r10, rcx
mov eax, 018h
syscall
ret
__alloc_virtual_memory endp
_TEXT ENDS
end

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

@ -0,0 +1,374 @@
#include "kernel_ctx.h"
#include "../mem_ctx/mem_ctx.hpp"
namespace nasa
{
kernel_ctx::kernel_ctx()
{
if (psyscall_func.load() || nt_page_offset || ntoskrnl_buffer)
return;
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;
ntoskrnl_buffer = reinterpret_cast<std::uint8_t*>(LoadLibraryExA("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES));
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 = nasa::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
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;
}
nasa::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 = nasa::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())
{
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;
}
}
}
nasa::unmap_phys(page_va, 0x1000 * 512);
}
}
// map the remainder and check each page of it
auto page_va = nasa::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())
{
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;
}
}
}
nasa::unmap_phys(page_va, remainder);
}
}
}
PEPROCESS kernel_ctx::get_peprocess(unsigned pid) const
{
if (!pid)
return NULL;
PEPROCESS proc;
static auto get_peprocess_from_pid =
util::get_module_export(
"ntoskrnl.exe",
"PsLookupProcessByProcessId"
);
const auto status = 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;
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
);
}
void* kernel_ctx::allocate_pool(std::size_t size, POOL_TYPE pool_type)
{
static const auto ex_alloc_pool =
util::get_module_export(
"ntoskrnl.exe",
"ExAllocatePool"
);
return syscall<ExAllocatePool>(
ex_alloc_pool,
pool_type,
size
);
}
void kernel_ctx::zero_kernel_memory(void* addr, std::size_t size)
{
static const auto rtl_zero_memory =
util::get_module_export(
"ntoskrnl.exe",
"RtlZeroMemory"
);
syscall<decltype(&RtlSecureZeroMemory)>(
rtl_zero_memory,
addr,
size
);
}
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,124 @@
#pragma once
#include "../util/util.hpp"
#include "../physmeme/physmeme.hpp"
#include "../util/hook.hpp"
namespace nasa
{
//
// 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()
);
hook::make_hook(psyscall_func, addr);
auto result = reinterpret_cast<T>(proc)(args ...);
hook::remove(psyscall_func);
return result;
}
//
// clear piddb cache of specific process.
//
bool clear_piddb_cache(const std::string& drv_name, const std::uint32_t epoch_time);
//
// get a pointer to an eprocess given process id.
//
PEPROCESS get_peprocess(unsigned pid) const;
//
// get base address of process (used to compare and ensure we find the right page).
//
void* get_proc_base(unsigned pid) const;
void* allocate_pool(std::size_t size, POOL_TYPE pool_type);
void zero_kernel_memory(void* addr, std::size_t size);
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;
};
}

@ -0,0 +1,298 @@
/*
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(),
&reg_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(),
&reg_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(),
&reg_handle
);
result = RegGetValueA(
reg_handle,
service_name.c_str(),
"ImagePath",
REG_SZ,
NULL,
image_path,
&bytes_read
);
RegCloseKey(reg_handle);
return std::string(image_path);
}
}
inline 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;
const auto h_file = CreateFileA(
file_path.data(),
GENERIC_ALL,
NULL, NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
DWORD bytes_written;
WriteFile(
h_file,
drv_buffer.data(),
drv_buffer.size(),
&bytes_written,
NULL
);
CloseHandle(h_file);
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,233 @@
#include "luna-1.hpp"
#include "raw_driver.hpp"
#include "patch_ctx/patch_ctx.hpp"
#include "map_driver.hpp"
namespace i6
{
inline nasa::kernel_ctx* kernel_ctx;
inline nasa::mem_ctx* mem_ctx;
inline nasa::patch_ctx* kernel_patch;
inline hook::detour* win32kbase_detour;
inline std::mutex syscall_lock;
inline void* kernel_hook_handler = nullptr;
inline void* win32u_handler = nullptr;
inline void* win32kbase_handler = nullptr;
inline void* patch_address = nullptr;
enum com_type
{
READ,
WRITE,
READ_KERNEL_MEMORY,
WRITE_KERNEL_MEMORY,
GET_PROCESS_BASE,
GET_MODULE_BASE
};
typedef struct _com_struct
{
com_type type;
unsigned pid;
unsigned size;
void* data_from;
void* data_to;
} com_struct, * pcom_struct;
bool begin()
{
//
// make kernel_ctx and fix syscall page so there is no physical memory mapped into this process!
//
if (!nasa::load_drv())
return false;
//
// make driver and get the address of hook handler.
//
const auto result =
i6::map_driver(
i6::luna_1,
sizeof(i6::luna_1),
&kernel_hook_handler
);
if (result != i6_error::error_success)
goto exit;
kernel_ctx = new nasa::kernel_ctx();
mem_ctx = new nasa::mem_ctx(*kernel_ctx, GetCurrentProcessId());
if (!kernel_ctx->clear_piddb_cache(nasa::drv_key, util::get_file_header((void*)raw_driver)->TimeDateStamp))
goto exit;
memset(i6::luna_1, NULL, sizeof(i6::luna_1));
win32kbase_handler =
util::get_module_export(
"win32kbase.sys",
"NtDCompositionBeginFrame"
);
if (!win32kbase_handler)
goto exit;
//
// needed for syscall
//
LoadLibrary("user32.dll");
win32u_handler =
::GetProcAddress(
LoadLibraryA("win32u.dll"),
"NtDCompositionBeginFrame"
);
if (!win32u_handler)
goto exit;
kernel_patch = new nasa::patch_ctx(mem_ctx);
patch_address = kernel_patch->patch(win32kbase_handler);
win32kbase_detour = new hook::detour(patch_address, kernel_hook_handler, false);
//
// enable patch and flush tlb!
//
kernel_patch->enable();
FLUSH_TLB;
exit:
if (mem_ctx) delete mem_ctx;
if (kernel_patch) delete kernel_patch;
if (kernel_ctx) delete kernel_ctx;
nasa::unmap_all();
if (!nasa::unload_drv())
return false;
return true;
}
void syscall(const pcom_struct com_data)
{
syscall_lock.lock();
win32kbase_detour->install();
reinterpret_cast<void(*)(pcom_struct)>(win32u_handler)(com_data);
win32kbase_detour->uninstall();
syscall_lock.unlock();
}
std::uintptr_t get_process_base(unsigned pid)
{
if (!pid)
return {};
com_struct com_data;
com_data.type = GET_PROCESS_BASE;
com_data.pid = pid;
syscall(&com_data);
return reinterpret_cast<std::uintptr_t>(com_data.data_from);
}
std::uintptr_t get_module_base(unsigned pid, const wchar_t* module_name)
{
if (!pid || !module_name)
return {};
com_struct com_data;
com_data.type = GET_MODULE_BASE;
com_data.data_to = (void*)module_name;
com_data.pid = pid;
syscall(&com_data);
return reinterpret_cast<std::uintptr_t>(com_data.data_from);
}
bool read(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!pid || !addr || !buffer || !size)
return false;
com_struct com_data;
com_data.type = READ;
com_data.pid = pid;
com_data.data_from = reinterpret_cast<void*>(addr);
com_data.data_to = buffer;
com_data.size = size;
syscall(&com_data);
return true;
}
bool write(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!pid || !addr || !buffer || !size)
return false;
com_struct com_data;
com_data.type = WRITE;
com_data.pid = pid;
com_data.data_from = buffer;
com_data.data_to = reinterpret_cast<void*>(addr);
com_data.size = size;
syscall(&com_data);
return true;
}
bool rkm(std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!addr || !buffer || !size)
return false;
com_struct com_data;
com_data.type = READ_KERNEL_MEMORY;
com_data.data_from = reinterpret_cast<void*>(addr);
com_data.data_to = buffer;
com_data.size = size;
syscall(&com_data);
return true;
}
bool wkm(std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!addr || !buffer || !size)
return false;
com_struct com_data;
com_data.type = WRITE_KERNEL_MEMORY;
com_data.data_from = buffer;
com_data.data_to = reinterpret_cast<void*>(addr);
com_data.size = size;
syscall(&com_data);
return true;
}
unsigned get_pid(const char* proc_name)
{
PROCESSENTRY32 proc_info;
proc_info.dwSize = sizeof(proc_info);
const auto 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 {};
}
}

@ -0,0 +1,66 @@
#pragma once
#include <cstddef>
#include <cstdint>
namespace i6
{
//
// please call this before making any other calls!
//
bool begin();
//
// get process id of process.
//
unsigned get_pid(const char* proc_name);
//
// get process base address.
//
std::uintptr_t get_process_base(unsigned pid);
//
// get module base
//
std::uintptr_t get_module_base(unsigned pid, const wchar_t* module_name);
//
// read/write to specific process
//
bool read(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size);
bool write(unsigned pid, std::uintptr_t addr, void* buffer, std::size_t size);
//
// read/write kernel memory (you can write to readonly with this)
//
bool rkm(std::uintptr_t addr, void* buffer, std::size_t size);
bool wkm(std::uintptr_t addr, void* buffer, std::size_t size);
template <class T>
T rkm(std::uintptr_t addr)
{
T buffer{};
rkm(addr, (void*)&buffer, sizeof(T));
return buffer;
}
template <class T>
bool wkm(std::uintptr_t addr, const T& data)
{
return wkm(addr, (void*)&data, sizeof(T));
}
template <class T>
T read(unsigned pid, std::uintptr_t addr)
{
T buffer{};
read(pid, addr, (void*)&buffer, sizeof(T));
return buffer;
}
template <class T>
bool write(unsigned pid, std::uintptr_t addr, const T& data)
{
return write(pid, addr, (void*)&data, sizeof(T));
}
}

@ -0,0 +1,204 @@
<?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>{334edbd9-6a7c-4f6a-8eec-022f8c2c04c3}</ProjectGuid>
<RootNamespace>luna1</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|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>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</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>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<WholeProgramOptimization>false</WholeProgramOptimization>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</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>_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<ProjectReference>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
</ProjectReference>
<Lib>
<AdditionalDependencies>
</AdditionalDependencies>
</Lib>
</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;_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<Optimization>Disabled</Optimization>
<WholeProgramOptimization>false</WholeProgramOptimization>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>mapper.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>false</LinkTimeCodeGeneration>
</Lib>
<ProjectReference>
<LinkLibraryDependencies>true</LinkLibraryDependencies>
</ProjectReference>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="kernel_ctx\kernel_ctx.cpp" />
<ClCompile Include="luna-1.cpp" />
<ClCompile Include="mapper_ctx\mapper_ctx.cpp" />
<ClCompile Include="map_driver.cpp" />
<ClCompile Include="mem_ctx\mem_ctx.cpp" />
<ClCompile Include="patch_ctx\patch_ctx.cpp" />
<ClCompile Include="pe_image\pe_image.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="direct.h" />
<ClInclude Include="kernel_ctx\kernel_ctx.h" />
<ClInclude Include="loadup.hpp" />
<ClInclude Include="luna-1.hpp" />
<ClInclude Include="mapper_ctx\mapper_ctx.hpp" />
<ClInclude Include="map_driver.hpp" />
<ClInclude Include="mem_ctx\mem_ctx.hpp" />
<ClInclude Include="patch_ctx\patch_ctx.hpp" />
<ClInclude Include="pe_image\pe_image.h" />
<ClInclude Include="physmeme\physmeme.hpp" />
<ClInclude Include="raw_driver.hpp" />
<ClInclude Include="util\hook.hpp" />
<ClInclude Include="util\nt.hpp" />
<ClInclude Include="util\util.hpp" />
</ItemGroup>
<ItemGroup>
<MASM Include="direct.asm">
<FileType>Document</FileType>
</MASM>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>

@ -0,0 +1,121 @@
<?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\kernel_ctx">
<UniqueIdentifier>{dd3f6067-3dff-478f-9d68-b96fc0e5456c}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\mem_ctx">
<UniqueIdentifier>{9d152069-464d-4ad4-ae2e-df0337a07cbb}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\patch_ctx">
<UniqueIdentifier>{4177fe47-d484-4b01-99ae-696601214b53}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\kernel_ctx">
<UniqueIdentifier>{6eccd581-20cb-465a-9a1c-d9c8eb3fc399}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\mem_ctx">
<UniqueIdentifier>{c6462452-fbac-45ba-a0c8-597a3dfa2935}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\patch_ctx">
<UniqueIdentifier>{dabb66f8-2a8f-482d-a8e1-a309bbdc6421}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\physmeme">
<UniqueIdentifier>{2620ff7a-5d75-49c6-b340-6e0855fb9192}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\util">
<UniqueIdentifier>{25436615-f282-4963-8800-e3bd482e6fb2}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\mapper_ctx">
<UniqueIdentifier>{ab0a4846-d7ec-42a7-96ba-1dcaaf32596a}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\mapper_ctx">
<UniqueIdentifier>{4b1ad9f9-ec9a-40fa-a8e2-a83545b296b7}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\pe_image">
<UniqueIdentifier>{5b0bab80-a333-4e2c-a77f-768b18b58a8e}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\pe_image">
<UniqueIdentifier>{a54ef091-f355-451f-8c9a-5f167ca4df16}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="kernel_ctx\kernel_ctx.cpp">
<Filter>Source Files\kernel_ctx</Filter>
</ClCompile>
<ClCompile Include="mem_ctx\mem_ctx.cpp">
<Filter>Source Files\mem_ctx</Filter>
</ClCompile>
<ClCompile Include="patch_ctx\patch_ctx.cpp">
<Filter>Source Files\patch_ctx</Filter>
</ClCompile>
<ClCompile Include="luna-1.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="map_driver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="mapper_ctx\mapper_ctx.cpp">
<Filter>Source Files\mapper_ctx</Filter>
</ClCompile>
<ClCompile Include="pe_image\pe_image.cpp">
<Filter>Source Files\pe_image</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="raw_driver.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_ctx\kernel_ctx.h">
<Filter>Header Files\kernel_ctx</Filter>
</ClInclude>
<ClInclude Include="mem_ctx\mem_ctx.hpp">
<Filter>Header Files\mem_ctx</Filter>
</ClInclude>
<ClInclude Include="patch_ctx\patch_ctx.hpp">
<Filter>Header Files\patch_ctx</Filter>
</ClInclude>
<ClInclude Include="loadup.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="physmeme\physmeme.hpp">
<Filter>Header Files\physmeme</Filter>
</ClInclude>
<ClInclude Include="util\hook.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="util\nt.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="util\util.hpp">
<Filter>Header Files\util</Filter>
</ClInclude>
<ClInclude Include="direct.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="luna-1.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="map_driver.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="mapper_ctx\mapper_ctx.hpp">
<Filter>Header Files\mapper_ctx</Filter>
</ClInclude>
<ClInclude Include="pe_image\pe_image.h">
<Filter>Header Files\pe_image</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="direct.asm">
<Filter>Source Files</Filter>
</MASM>
</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>

@ -0,0 +1,22 @@
#include "map_driver.hpp"
namespace i6
{
i6_error 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 i6_error::image_invalid;
nasa::kernel_ctx kernel;
nasa::mem_ctx my_proc(kernel, GetCurrentProcessId());
nasa::mapper_ctx mapper(my_proc, my_proc); // map driver into myself.
const auto [drv_base, drv_entry] = mapper.map(drv_buffer);
if (!drv_base || !drv_entry)
return i6_error::init_failed;
mapper.call_entry(drv_entry, entry_data);
return i6_error::error_success;
}
}

@ -0,0 +1,21 @@
#pragma once
#include <windows.h>
#include <fstream>
#include <cstddef>
#include <cstdint>
#include "mapper_ctx/mapper_ctx.hpp"
namespace i6
{
enum class i6_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? if so please contact for a different version)
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)
};
i6_error map_driver(std::uint8_t* drv_image, std::size_t image_size, void** entry_data);
}

@ -0,0 +1,195 @@
#include "mapper_ctx.hpp"
namespace nasa
{
mapper_ctx::mapper_ctx(
nasa::mem_ctx& map_into,
nasa::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);
const auto new_pdpt = reinterpret_cast<::ppdpte>(create_self_ref(drv_alloc));
auto [drv_ppml4e, drv_pml4e] = map_from.get_pml4e(drv_alloc);
//
// make all the ptes for the driver kernel access only.
//
make_ptes_kernel_access(drv_alloc, raw_image.size());
//
// set pfn of cloned pml4e to the newly created pdpt with a large pdpte.
//
drv_pml4e.pfn = reinterpret_cast<std::uintptr_t>(new_pdpt) >> 12;
drv_pml4e.user_supervisor = false;
//
// set new pml4e into specific process.
//
map_into.write_phys(
reinterpret_cast<std::uintptr_t*>(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;
new_addr.pdpt_index = SELF_REF_ENTRY;
new_addr.pd_index = NULL;
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));
};
nasa::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() + 0x1000 * 512, // allocate 2mb along with the size of the driver to create a new pt/pde.
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;
new_addr.pdpt_index = SELF_REF_ENTRY;
new_addr.pd_index = NULL;
//
// dont write nt headers...
//
drv_image.relocate(reinterpret_cast<std::uintptr_t>(new_addr.value));
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()
);
CloseHandle(process_handle);
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::create_self_ref(void* virt_alloc_base)
{
const auto[ppte, pte] = map_from.get_pte(virt_alloc_base);
auto [ppde, pde] = map_from.get_pde(virt_alloc_base);
auto [ppdpte, pdpte] = map_from.get_pdpte(virt_alloc_base);
const auto process_handle =
OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
map_from.get_pid()
);
const auto pdpt = reinterpret_cast<::ppdpte>(
direct::alloc_virtual_memory(
process_handle,
0x1000,
PAGE_READWRITE
));
pde.pfn = reinterpret_cast<std::uintptr_t>(ppte) >> 12;
pde.user_supervisor = false;
//
// write entry into new pdpt
//
direct::write_virtual_memory(
process_handle,
pdpt,
&pde,
sizeof(pde)
);
//
// physical address of pdpt
//
pt_entries entries;
const auto phys_addr_pdpt = map_from.virt_to_phys(entries, pdpt);
//
// make self referencing entry
//
pdpte.pfn = reinterpret_cast<std::uintptr_t>(phys_addr_pdpt) >> 12;
pdpte.user_supervisor = false;
//
// write in self referencing entry.
//
direct::write_virtual_memory(
process_handle,
pdpt + SELF_REF_ENTRY,
&pdpte,
sizeof(pdpte)
);
CloseHandle(process_handle);
return phys_addr_pdpt;
}
void mapper_ctx::make_ptes_kernel_access(void* drv_base, std::size_t drv_size)
{
if (!drv_base || !drv_size)
return;
//
// for each pte make it kernel access only.
//
const auto [ppte, pte] = map_from.get_pte(drv_base);
const auto phys_addr_pt = reinterpret_cast<::ppte>(((std::uintptr_t)ppte >> 12) << 12);
auto virt_mapping = reinterpret_cast<::ppte>(map_from.set_page(phys_addr_pt));
for (auto idx = virt_addr_t{ drv_base }.pt_index; idx < 512; ++idx)
{
auto drv_pte = *(virt_mapping + idx);
if (drv_pte.value)
{
drv_pte.user_supervisor = false;
drv_pte.nx = false;
*(virt_mapping + idx) = drv_pte;
}
}
}
}

@ -0,0 +1,27 @@
#pragma once
#include "../mem_ctx/mem_ctx.hpp"
#include "../pe_image/pe_image.h"
#include "../direct.h"
#define PML4_MAP_INDEX 153
#define SELF_REF_ENTRY 69
namespace nasa
{
class mapper_ctx
{
public:
explicit mapper_ctx(
nasa::mem_ctx& map_into,
nasa::mem_ctx& map_from
);
std::pair<void*, void*> map(std::vector<std::uint8_t>& raw_image);
bool call_entry(void* drv_entry, void** hook_handler) const;
private:
std::pair<void*, void*> allocate_driver(std::vector<std::uint8_t>& raw_image);
void* create_self_ref(void* virt_alloc_base);
void make_ptes_kernel_access(void* drv_base, std::size_t drv_size);
nasa::mem_ctx map_into;
nasa::mem_ctx map_from;
};
}

@ -0,0 +1,466 @@
#include "mem_ctx.hpp"
#include <cassert>
namespace nasa
{
mem_ctx::mem_ctx(kernel_ctx& krnl_ctx, DWORD pid)
:
k_ctx(&krnl_ctx),
dirbase(get_dirbase(krnl_ctx, pid)),
pid(pid)
{
genesis_page.first = VirtualAlloc(
NULL,
PAGE_SIZE,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
//
// page in the page, do not remove this makes the entries.
//
*(std::uintptr_t*)genesis_page.first = 0xC0FFEE;
//
// flush tlb since we just accessed the page
//
page_accessed();
//
// get the ppte and pte of the page we allocated
//
auto [page_ppte, page_pte] = get_pte(genesis_page.first, true);
genesis_page.second = page_pte;
//
// allocate a page that will get the mapping of the first pages PT
//
genesis_cursor.first = reinterpret_cast<::ppte>(
VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
//
// page it in
//
*(std::uintptr_t*)genesis_cursor.first = 0xC0FFEE;
//
// flush tlb since we just accessed the page
//
page_accessed();
//
// get ppte and pte of the cursor page.
//
auto [cursor_ppte, cursor_pte] = get_pte(genesis_cursor.first, true);
genesis_cursor.second = cursor_pte;
//
// change the page to the PT of the first page we allocated.
//
cursor_pte.pfn = reinterpret_cast<std::uint64_t>(page_ppte) >> 12;
set_pte(genesis_cursor.first, cursor_pte, true);
//
// change the offset of genesis cursor page to genesis pages pt_index since the page is now a PT
// WARNING: pointer arithmetic, do not add pt_index * 8
//
genesis_cursor.first += +virt_addr_t{ genesis_page.first }.pt_index;
//
// since the page has been accessed we need to reset this bit in the PTE.
//
page_accessed();
}
mem_ctx::~mem_ctx()
{
set_pte(genesis_page.first, genesis_page.second, true);
set_pte(genesis_cursor.first, genesis_cursor.second, true);
}
void* mem_ctx::set_page(void* addr)
{
page_offset = virt_addr_t{ addr }.offset;
genesis_cursor.first->pfn = reinterpret_cast<uint64_t>(addr) >> 12;
page_accessed();
return get_page();
}
void* mem_ctx::get_page() const
{
return reinterpret_cast<void*>((reinterpret_cast<std::uint64_t>(genesis_page.first)) + page_offset);
}
void mem_ctx::page_accessed() const
{
Sleep(5);
}
void* mem_ctx::get_dirbase(kernel_ctx& k_ctx, DWORD pid)
{
if (!pid)
return NULL;
const auto peproc =
reinterpret_cast<std::uint64_t>(k_ctx.get_peprocess(pid));
if (!peproc)
return NULL;
const auto dirbase =
k_ctx.rkm<pte>(
reinterpret_cast<void*>(peproc + 0x28));
return reinterpret_cast<void*>(dirbase.pfn << 12);
}
void mem_ctx::set_dirbase(void* dirbase)
{
this->dirbase = dirbase;
}
bool mem_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 = k_ctx->rkm<pml4e>(
k_ctx->get_virtual(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 = k_ctx->rkm<pdpte>(
k_ctx->get_virtual(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 = k_ctx->rkm<pde>(
k_ctx->get_virtual(entries.pd.first));
// if its a 2mb page
if (entries.pd.second.page_size)
{
memcpy(
&entries.pt.second,
&entries.pd.second,
sizeof(pte)
);
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 = k_ctx->rkm<pte>(
k_ctx->get_virtual(entries.pt.first));
if (!entries.pt.second.value)
return false;
return true;
}
std::pair<ppte, pte> mem_ctx::get_pte(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if (use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr))
{
::pte pte;
memcpy(&pte, &entries.pt.second, sizeof(pte));
return { entries.pt.first, pte };
}
return {};
}
void mem_ctx::set_pte(void* addr, const ::pte& pte, bool use_hyperspace)
{
if (!dirbase || !addr)
return;
pt_entries entries;
if (use_hyperspace)
if (hyperspace_entries(entries, addr))
k_ctx->wkm(
k_ctx->get_virtual(entries.pt.first),
pte
);
else
if (virt_to_phys(entries, addr))
write_phys(entries.pt.first, pte);
}
std::pair<ppde, pde> mem_ctx::get_pde(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if (use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr))
{
::pde pde;
memcpy(
&pde,
&entries.pd.second,
sizeof(pde)
);
return { entries.pd.first, pde };
}
return {};
}
void mem_ctx::set_pde(void* addr, const ::pde& pde, bool use_hyperspace)
{
if (!dirbase || !addr)
return;
pt_entries entries;
if (use_hyperspace)
if (hyperspace_entries(entries, addr))
k_ctx->wkm(
k_ctx->get_virtual(entries.pd.first),
pde
);
else
if (virt_to_phys(entries, addr))
write_phys(entries.pd.first, pde);
}
std::pair<ppdpte, pdpte> mem_ctx::get_pdpte(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if (use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr))
{
::pdpte pdpte;
memcpy(
&pdpte,
&entries.pdpt.second,
sizeof(pdpte)
);
return { entries.pdpt.first, pdpte };
}
return {};
}
void mem_ctx::set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace)
{
if (!dirbase || !addr)
return;
pt_entries entries;
if (use_hyperspace)
if (hyperspace_entries(entries, addr))
k_ctx->wkm(
k_ctx->get_virtual(entries.pdpt.first),
pdpte
);
else
if (virt_to_phys(entries, addr))
write_phys(entries.pdpt.first, pdpte);
}
std::pair<ppml4e, pml4e> mem_ctx::get_pml4e(void* addr, bool use_hyperspace)
{
if (!dirbase || !addr)
return {};
pt_entries entries;
if (use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr))
{
::pml4e pml4e;
memcpy(
&pml4e,
&entries.pml4.second,
sizeof(pml4e)
);
return { entries.pml4.first, pml4e };
}
return {};
}
void mem_ctx::set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace)
{
if (!dirbase || !addr)
return;
pt_entries entries;
if (use_hyperspace)
if (hyperspace_entries(entries, addr))
k_ctx->wkm(
k_ctx->get_virtual(entries.pml4.first),
pml4e
);
else
if (virt_to_phys(entries, addr))
write_phys(entries.pml4.first, pml4e);
}
std::pair<void*, void*> mem_ctx::read_virtual(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size || !dirbase)
return {};
virt_addr_t virt_addr{ addr };
if (size <= PAGE_SIZE - 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_SIZE - virt_addr.offset
);
// forward work load
return read_virtual(
new_buffer_addr,
new_addr,
size - (PAGE_SIZE - virt_addr.offset)
);
}
}
std::pair<void*, void*> mem_ctx::write_virtual(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size || !dirbase)
return {};
virt_addr_t virt_addr{ addr };
if (size <= PAGE_SIZE - 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_SIZE - virt_addr.offset
);
// forward work load
return write_virtual(
new_buffer_addr,
new_addr,
size - (PAGE_SIZE - virt_addr.offset)
);
}
}
void mem_ctx::read_phys(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size)
return;
auto temp_page = set_page(addr);
if (temp_page)
memcpy(buffer, temp_page, size);
}
void mem_ctx::write_phys(void* buffer, void* addr, std::size_t size)
{
if (!buffer || !addr || !size)
return;
auto temp_page = set_page(addr);
if (temp_page)
memcpy(temp_page, buffer, size);
}
void* mem_ctx::virt_to_phys(pt_entries& entries, void* addr)
{
if (!addr || !dirbase)
return {};
virt_addr_t virt_addr{ addr };
//
// traverse paging tables
//
auto pml4e = read_phys<::pml4e>(
reinterpret_cast<ppml4e>(dirbase) + virt_addr.pml4_index);
entries.pml4.first = reinterpret_cast<ppml4e>(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);
}
unsigned mem_ctx::get_pid() const
{
return pid;
}
void* mem_ctx::get_dirbase() const
{
return dirbase;
}
}

@ -0,0 +1,133 @@
#pragma once
#include "../util/nt.hpp"
#include "../kernel_ctx/kernel_ctx.h"
#define FLUSH_TLB Sleep(10)
struct pt_entries
{
std::pair<ppml4e, pml4e> pml4;
std::pair<ppdpte, pdpte> pdpt;
std::pair<ppde, pde> pd;
std::pair<ppte, pte> pt;
};
namespace nasa
{
class mem_ctx
{
public:
explicit mem_ctx(kernel_ctx& k_ctx, DWORD pid);
~mem_ctx();
//
// PTE manipulation
//
std::pair<ppte, pte> get_pte(void* addr, bool use_hyperspace = false);
void set_pte(void* addr, const ::pte& pte, bool use_hyperspace = false);
//
// PDE manipulation
//
std::pair<ppde, pde> get_pde(void* addr, bool use_hyperspace = false);
void set_pde(void* addr, const ::pde& pde, bool use_hyperspace = false);
//
// PDPTE manipulation
//
std::pair<ppdpte, pdpte> get_pdpte(void* addr, bool use_hyperspace = false);
void set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace = false);
//
// PML4E manipulation
//
std::pair<ppml4e, pml4e> get_pml4e(void* addr, bool use_hyperspace = false);
void set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace = false);
//
// gets dirbase (not the PTE or PFN but actual physical address)
//
void* get_dirbase() const;
static void* get_dirbase(kernel_ctx& k_ctx, DWORD pid);
void read_phys(void* buffer, void* addr, std::size_t size);
void write_phys(void* buffer, void* addr, std::size_t size);
template <class T>
T read_phys(void* addr)
{
if (!addr)
return {};
T buffer;
read_phys((void*)&buffer, addr, sizeof(T));
return buffer;
}
template <class T>
void write_phys(void* addr, const T& data)
{
if (!addr)
return;
write_phys((void*)&data, addr, sizeof(T));
}
std::pair<void*, void*> read_virtual(void* buffer, void* addr, std::size_t size);
std::pair<void*, void*> write_virtual(void* buffer, void* addr, std::size_t size);
template <class T>
T read_virtual(void* addr)
{
if (!addr)
return {};
T buffer;
read_virtual((void*)&buffer, addr, sizeof(T));
return buffer;
}
template <class T>
void write_virtual(void* addr, const T& data)
{
write_virtual((void*)&data, addr, sizeof(T));
}
//
// linear address translation (not done by hyperspace mappings)
//
void* virt_to_phys(pt_entries& entries, void* addr);
//
// given an address fill pt entries with physical addresses and entry values.
//
bool hyperspace_entries(pt_entries& entries, void* addr);
//
// these are used for the pfn backdoor, this will be removed soon
//
void* set_page(void* addr);
//
// get current page mem_ctx is set to.
//
void* get_page() const;
//
// invalidate TLB
//
void page_accessed() const;
unsigned get_pid() const;
//
// set dirbase.
//
void set_dirbase(void* dirbase);
kernel_ctx* k_ctx;
private:
std::pair<void*, pte> genesis_page;
std::pair<ppte, pte> genesis_cursor;
void* dirbase;
unsigned pid;
unsigned short page_offset;
};
}

@ -0,0 +1,249 @@
#include "patch_ctx.hpp"
namespace nasa
{
patch_ctx::patch_ctx(nasa::mem_ctx* mem_ctx)
:
mem_ctx(mem_ctx)
{}
void* patch_ctx::patch(void* kernel_addr)
{
if (!kernel_addr)
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
pt_entries kernel_entries;
if (!mem_ctx->hyperspace_entries(kernel_entries, kernel_addr))
return {};
const auto [new_pdpt_phys, new_pdpt_virt] = make_pdpt(kernel_entries, kernel_addr);
const auto [new_pd_phys, new_pd_virt] = make_pd(kernel_entries, kernel_addr);
const auto [new_pt_phys, new_pt_virt] = make_pt(kernel_entries, kernel_addr);
const auto [new_page_phys, new_page_virt] = make_page(kernel_entries, kernel_addr);
// link pdpte to pd
(reinterpret_cast<ppdpte>(new_pdpt_virt) + kernel_addr_t.pdpt_index)->pfn = reinterpret_cast<std::uintptr_t>(new_pd_phys) >> 12;
if (kernel_entries.pd.second.page_size)
// link pde to new page if its 2mb
(reinterpret_cast<ppde>(new_pd_virt) + kernel_addr_t.pd_index)->pfn = reinterpret_cast<std::uintptr_t>(new_page_phys) >> 12;
else
{
// link pde to pt
(reinterpret_cast<ppde>(new_pd_virt) + kernel_addr_t.pd_index)->pfn = reinterpret_cast<std::uintptr_t>(new_pt_phys) >> 12;
// link pte to page (1kb)
(reinterpret_cast<ppte>(new_pt_virt) + kernel_addr_t.pt_index)->pfn = reinterpret_cast<std::uintptr_t>(new_page_phys) >> 12;
}
mapped_pml4e =
reinterpret_cast<ppml4e>(
mem_ctx->set_page(
kernel_entries.pml4.first));
new_pml4e = kernel_entries.pml4.second;
new_pml4e.pfn = reinterpret_cast<std::uintptr_t>(new_pdpt_phys) >> 12;
old_pml4e = kernel_entries.pml4.second;
return reinterpret_cast<void*>((std::uintptr_t)new_page_virt + kernel_addr_t.offset);
}
std::pair<void*, void*> patch_ctx::make_pdpt(const pt_entries& kernel_entries, void* kernel_addr)
{
if (!kernel_addr)
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
const auto pdpt = reinterpret_cast<ppdpte>(
mem_ctx->set_page(reinterpret_cast<void*>(
kernel_entries.pml4.second.pfn << 12)));
const auto new_pdpt =
reinterpret_cast<ppdpte>(VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
//
// zero pdpt and lock it.
//
memset(new_pdpt, NULL, 0x1000);
if (!VirtualLock(new_pdpt, 0x1000))
return {};
//
// copy over pdpte's
//
for (auto idx = 0u; idx < 512; ++idx)
*(pdpte*)(new_pdpt + idx) = *(pdpte*)(pdpt + idx);
//
// get physical address of new pdpt
//
pt_entries new_pdpt_entries;
const auto physical_addr =
mem_ctx->virt_to_phys(
new_pdpt_entries,
new_pdpt
);
return { physical_addr, new_pdpt };
}
std::pair<void*, void*> patch_ctx::make_pd(const pt_entries& kernel_entries, void* kernel_addr)
{
if (!kernel_addr)
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
const auto new_pd = reinterpret_cast<ppde>(
VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
//
// zero page and lock it.
//
memset(new_pd, NULL, 0x1000);
if (!VirtualLock(new_pd, 0x1000))
return {};
const auto pd = reinterpret_cast<ppde>(
mem_ctx->set_page(
reinterpret_cast<void*>(
kernel_entries.pdpt.second.pfn << 12)));
//
// copy over pde's
//
for (auto idx = 0u; idx < 512; ++idx)
*(::pde*)(new_pd + idx) = *(::pde*)(pd + idx);
//
// get physical address of new pd
//
pt_entries pd_entries;
const auto physical_addr =
mem_ctx->virt_to_phys(
pd_entries,
new_pd
);
return { physical_addr, new_pd };
}
std::pair<void*, void*> patch_ctx::make_pt(const pt_entries& kernel_entries, void* kernel_addr)
{
if (!kernel_addr || kernel_entries.pd.second.page_size) // if this address is a 2mb mapping.
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
const auto new_pt = reinterpret_cast<ppte>(
VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
));
//
// zero pt and lock it.
//
memset(new_pt, NULL, 0x1000);
if (!VirtualLock(new_pt, 0x1000))
return {};
const auto pt = reinterpret_cast<ppde>(
mem_ctx->set_page(
reinterpret_cast<void*>(
kernel_entries.pd.second.pfn << 12)));
//
// copy over pte's
//
for (auto idx = 0u; idx < 512; ++idx)
*(::pde*)(new_pt + idx) = *(::pde*)(pt + idx);
//
// get physical address of new pt
//
pt_entries entries;
const auto physical_addr =
mem_ctx->virt_to_phys(
entries,
new_pt
);
return { physical_addr, new_pt };
}
std::pair<void*, void*> patch_ctx::make_page(const pt_entries& kernel_entries, void* kernel_addr)
{
if (!kernel_addr)
return {};
virt_addr_t kernel_addr_t{ kernel_addr };
//
// if its a 2mb page
//
if (kernel_entries.pd.second.page_size)
{
const auto new_page = VirtualAlloc(
NULL,
0x1000 * 512 * 2, // 4mb
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
memset(new_page, NULL, 512 * 0x1000); // zero 2mb
//
// copy 2mb one page at a time.
//
for (auto idx = 0u; idx < 512; ++idx)
{
const auto old_page = mem_ctx->set_page(reinterpret_cast<void*>((kernel_entries.pt.second.pfn << 12) + (idx * 0x1000)));
memcpy((void*)((std::uintptr_t)new_page + (idx * 0x1000)), old_page, 0x1000);
}
pt_entries new_page_entries;
const auto new_page_phys = mem_ctx->virt_to_phys(new_page_entries, new_page);
return { new_page_phys, new_page };
}
else // 1kb
{
const auto new_page = VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
);
//
// zero and lock new page.
//
memset(new_page, NULL, 0x1000);
if (!VirtualLock(new_page, 0x1000))
return {};
const auto old_page =
mem_ctx->set_page(
reinterpret_cast<void*>(
kernel_entries.pt.second.pfn << 12));
memcpy(new_page, old_page, 0x1000);
pt_entries new_page_entries;
const auto new_page_phys =
mem_ctx->virt_to_phys(
new_page_entries,
new_page
);
return { new_page_phys, new_page };
}
}
}

@ -0,0 +1,61 @@
#pragma once
#include "../mem_ctx/mem_ctx.hpp"
namespace nasa
{
class patch_ctx
{
public:
explicit patch_ctx(mem_ctx* mem_ctx);
//
// returns a virtual address mapping of the newly patched page(s).
//
void* patch(void* kernel_addr);
__forceinline void enable()
{
mapped_pml4e->pfn = new_pml4e.pfn;
}
__forceinline void disable()
{
mapped_pml4e->pfn = old_pml4e.pfn;
}
private:
//
// std::pair< physical page, virtual address >
//
std::pair<void*, void*> make_pdpt(const pt_entries& kernel_entries, void* kernel_addr);
std::pair<void*, void*> make_pd(const pt_entries& kernel_entries, void* kernel_addr);
std::pair<void*, void*> make_pt(const pt_entries& kernel_entries, void* kernel_addr);
std::pair<void*, void*> make_page(const pt_entries& kernel_entries, void* kernel_addr);
//
// context of the current process you want to patch.
//
mem_ctx* mem_ctx;
//
// newly created table entries and table pointers (pdpte, pde, pte)
//
pt_entries new_entries;
//
// old and new pml4e
//
pml4e new_pml4e;
pml4e old_pml4e;
//
// kernel address of the patch.
//
void* kernel_addr;
//
// pointer to the mapped pml4e
// used for enable/disable patch...
//
ppml4e mapped_pml4e;
};
}

@ -0,0 +1,196 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org>
!!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
#include "pe_image.h"
namespace nasa
{
pe_image::pe_image(std::vector<uint8_t>& image) : m_image(image)
{
m_dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(m_image.data());
m_nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS64>((uintptr_t)m_dos_header + m_dos_header->e_lfanew);
m_section_header = reinterpret_cast<IMAGE_SECTION_HEADER*>((uintptr_t)(&m_nt_headers->OptionalHeader) + m_nt_headers->FileHeader.SizeOfOptionalHeader);
}
size_t pe_image::size() const
{
return m_nt_headers->OptionalHeader.SizeOfImage;
}
uintptr_t pe_image::entry_point() const
{
return m_nt_headers->OptionalHeader.AddressOfEntryPoint;
}
void pe_image::map()
{
m_image_mapped.clear();
m_image_mapped.resize(m_nt_headers->OptionalHeader.SizeOfImage);
std::copy_n(m_image.begin(), m_nt_headers->OptionalHeader.SizeOfHeaders, m_image_mapped.begin());
for (size_t i = 0; i < m_nt_headers->FileHeader.NumberOfSections; ++i)
{
const auto& section = m_section_header[i];
const auto target = (uintptr_t)m_image_mapped.data() + section.VirtualAddress;
const auto source = (uintptr_t)m_dos_header + section.PointerToRawData;
std::copy_n(m_image.begin() + section.PointerToRawData, section.SizeOfRawData, m_image_mapped.begin() + section.VirtualAddress);
}
}
bool pe_image::process_relocation(uintptr_t image_base_delta, uint16_t data, uint8_t* relocation_base)
{
#define IMR_RELOFFSET(x) (x & 0xFFF)
switch (data >> 12 & 0xF)
{
case IMAGE_REL_BASED_HIGH:
{
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(HIWORD(image_base_delta));
break;
}
case IMAGE_REL_BASED_LOW:
{
const auto raw_address = reinterpret_cast<int16_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<unsigned long>(LOWORD(image_base_delta));
break;
}
case IMAGE_REL_BASED_HIGHLOW:
{
const auto raw_address = reinterpret_cast<size_t*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += static_cast<size_t>(image_base_delta);
break;
}
case IMAGE_REL_BASED_DIR64:
{
auto UNALIGNED raw_address = reinterpret_cast<DWORD_PTR UNALIGNED*>(relocation_base + IMR_RELOFFSET(data));
*raw_address += image_base_delta;
break;
}
case IMAGE_REL_BASED_ABSOLUTE: // No action required
case IMAGE_REL_BASED_HIGHADJ: // no action required
{
break;
}
default:
{
return false;
}
}
#undef IMR_RELOFFSET
return true;
}
void pe_image::relocate(uintptr_t base) const
{
if (m_nt_headers->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
return;
ULONG total_count_bytes;
const auto nt_headers = ImageNtHeader((void*)m_image_mapped.data());
auto relocation_directory = (PIMAGE_BASE_RELOCATION)::ImageDirectoryEntryToData(nt_headers, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &total_count_bytes);
auto image_base_delta = static_cast<uintptr_t>(static_cast<uintptr_t>(base) - (nt_headers->OptionalHeader.ImageBase));
auto relocation_size = total_count_bytes;
// This should check (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) too but lots of drivers do not have it set due to WDK defaults
const bool doRelocations = image_base_delta != 0 && relocation_size > 0;
if (!doRelocations)
return;
void* relocation_end = reinterpret_cast<uint8_t*>(relocation_directory) + relocation_size;
while (relocation_directory < relocation_end)
{
auto relocation_base = ::ImageRvaToVa(nt_headers, (void*)m_image_mapped.data(), relocation_directory->VirtualAddress, nullptr);
auto num_relocs = (relocation_directory->SizeOfBlock - 8) >> 1;
auto relocation_data = reinterpret_cast<PWORD>(relocation_directory + 1);
for (unsigned long i = 0; i < num_relocs; ++i, ++relocation_data)
if (process_relocation(image_base_delta, *relocation_data, (uint8_t*)relocation_base) == FALSE)
return;
relocation_directory = reinterpret_cast<PIMAGE_BASE_RELOCATION>(relocation_data);
}
}
template<typename T>
__forceinline T* ptr_add(void* base, uintptr_t offset)
{
return (T*)(uintptr_t)base + offset;
}
void pe_image::fix_imports(const std::function<uintptr_t(std::string_view)> get_module, const std::function<uintptr_t(const char*, const char*)> get_function)
{
ULONG size;
auto import_descriptors = static_cast<PIMAGE_IMPORT_DESCRIPTOR>(::ImageDirectoryEntryToData(m_image.data(), FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size));
if (import_descriptors == nullptr)
return;
for (; import_descriptors->Name; import_descriptors++)
{
IMAGE_THUNK_DATA* image_thunk_data;
const auto module_name = get_rva<char>(import_descriptors->Name);
const auto module_base = get_module(module_name);
if (import_descriptors->OriginalFirstThunk)
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->OriginalFirstThunk);
else
image_thunk_data = get_rva<IMAGE_THUNK_DATA>(import_descriptors->FirstThunk);
auto image_func_data = get_rva<IMAGE_THUNK_DATA64>(import_descriptors->FirstThunk);
for (; image_thunk_data->u1.AddressOfData; image_thunk_data++, image_func_data++)
{
uintptr_t function_address;
const auto ordinal = (image_thunk_data->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0;
const auto image_import_by_name = get_rva<IMAGE_IMPORT_BY_NAME>(*(DWORD*)image_thunk_data);
const auto name_of_import = static_cast<char*>(image_import_by_name->Name);
function_address = get_function(module_name, name_of_import);
image_func_data->u1.Function = function_address;
}
}
}
void* pe_image::data()
{
return m_image_mapped.data();
}
size_t pe_image::header_size()
{
return m_nt_headers->OptionalHeader.SizeOfHeaders;
}
}

@ -0,0 +1,73 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org>
!!!!!!!!!!!!!!!!!!!!!!!!!!! This code was created by not-wlan (wlan). all credit for this header and source file goes to him !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
#pragma once
#include <vector>
#define WIN32_NO_STATUS
#include <Windows.h>
#include <Winternl.h>
#undef WIN32_NO_STATUS
#include <ntstatus.h>
#include <functional>
#include <DbgHelp.h>
#include <variant>
#pragma comment(lib, "Dbghelp.lib")
namespace nasa
{
class pe_image
{
std::vector<uint8_t> m_image;
std::vector<uint8_t> m_image_mapped;
PIMAGE_DOS_HEADER m_dos_header = nullptr;
PIMAGE_NT_HEADERS64 m_nt_headers = nullptr;
PIMAGE_SECTION_HEADER m_section_header = nullptr;
public:
pe_image(std::vector<uint8_t>& image);
size_t size() const;
uintptr_t entry_point() const;
void map();
static bool process_relocation(size_t image_base_delta, uint16_t data, uint8_t* relocation_base);
void relocate(uintptr_t base) const;
template<typename T>
__forceinline T* get_rva(const unsigned long offset)
{
return (T*)::ImageRvaToVa(m_nt_headers, m_image.data(), offset, nullptr);
}
void fix_imports(const std::function<uintptr_t(std::string_view)> get_module, const std::function<uintptr_t(const char*, const char*)> get_function);
void* data();
size_t header_size();
};
}

@ -0,0 +1,92 @@
#pragma once
#include <windows.h>
#include <mutex>
#include <cstdint>
#include <map>
#include "../util/util.hpp"
#include "../loadup.hpp"
#include "../raw_driver.hpp"
#pragma pack ( push, 1 )
typedef struct _GIOMAP
{
unsigned long interface_type;
unsigned long bus;
std::uintptr_t physical_address;
unsigned long io_space;
unsigned long size;
} GIOMAP;
#pragma pack ( pop )
namespace nasa
{
inline std::string drv_key;
inline HANDLE drv_handle = NULL;
inline std::vector<std::pair<std::uintptr_t, std::uint32_t >> virtual_mappings;
inline bool load_drv()
{
const auto [result, key] =
driver::load(
i6::raw_driver,
sizeof(i6::raw_driver)
);
drv_key = key;
drv_handle = CreateFile(
"\\\\.\\GIO",
GENERIC_READ | GENERIC_WRITE,
NULL,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
return drv_handle;
}
inline bool unload_drv()
{
return CloseHandle(drv_handle) && driver::unload(drv_key);
}
inline std::uintptr_t map_phys(
std::uintptr_t addr,
std::size_t size
)
{
GIOMAP in_buffer = { 0, 0, addr, 0, size };
uintptr_t out_buffer[2] = { 0 };
unsigned long returned = 0;
DeviceIoControl(drv_handle, 0xC3502004, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
virtual_mappings.emplace_back(std::pair<std::uintptr_t, std::size_t>(out_buffer[0], size));
return out_buffer[0];
}
inline bool unmap_phys(
std::uintptr_t addr,
std::size_t size
)
{
uintptr_t in_buffer = addr;
uintptr_t out_buffer[2] = { sizeof(out_buffer) };
unsigned long returned = NULL;
DeviceIoControl(drv_handle, 0xC3502008, reinterpret_cast<LPVOID>(&in_buffer), sizeof(in_buffer),
reinterpret_cast<LPVOID>(out_buffer), sizeof(out_buffer), &returned, NULL);
return out_buffer[0];
}
inline void unmap_all()
{
__try
{
for (auto idx = 0u; idx < virtual_mappings.size(); ++idx)
unmap_phys(virtual_mappings[idx].first, virtual_mappings[idx].second);
}
__except (EXCEPTION_ACCESS_VIOLATION) {}
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,182 @@
/*
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 <map>
#include <atomic>
#include <memory>
#if _M_IX86
#define OFFSET_TO_ADDRESS 0x1
#elif _M_X64
#define OFFSET_TO_ADDRESS 0x2
#endif
namespace hook
{
class detour
{
public:
detour(void* addr_to_hook, void* jmp_to, bool enable = true)
: hook_addr(addr_to_hook), detour_addr(jmp_to), hook_installed(false)
{
//setup hook
memcpy(
jmp_code + OFFSET_TO_ADDRESS,
&jmp_to,
sizeof(jmp_to)
);
//save bytes
memcpy(
org_bytes,
hook_addr,
sizeof(org_bytes)
);
if(enable)
install();
}
void install()
{
if (hook_installed.load())
return;
// mapped page is already read/write
memcpy(hook_addr, jmp_code, sizeof(jmp_code));
hook_installed.exchange(true);
}
void uninstall()
{
if (!hook_installed.load())
return;
// mapped page is already read/write
memcpy(hook_addr, org_bytes, sizeof(org_bytes));
hook_installed.exchange(false);
}
~detour() { uninstall(); }
bool installed() { return hook_installed; }
void* hook_address() { return hook_addr; }
void* detour_address() { return detour_addr; }
private:
std::atomic<bool> hook_installed;
void *hook_addr, *detour_addr;
#if _M_IX86
/*
0: b8 ff ff ff ff mov eax, 0xffffffff
5: ff e0 jmp eax
*/
unsigned char jmp_code[7] = {
0xb8, 0x0, 0x0, 0x0, 0x0,
0xFF, 0xE0
};
#elif _M_X64
/*
0: 48 b8 ff ff ff ff ff ff ff ff movabs rax,0xffffffffffffffff
7: ff e0 jmp rax
*/
unsigned char jmp_code[12] = {
0x48, 0xb8,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0x0,
0xff, 0xe0
};
#endif
std::uint8_t org_bytes[sizeof(jmp_code)];
};
static std::map<void*, std::unique_ptr<detour>> hooks{};
/*
Author: xerox
Date: 12/19/2019
Create Hook without needing to deal with objects
*/
static void make_hook(void* addr_to_hook, void* jmp_to_addr, bool enable = true)
{
if (!addr_to_hook)
return;
hooks.insert({
addr_to_hook,
std::make_unique<detour>(
addr_to_hook,
jmp_to_addr,
enable
)}
);
}
/*
Author: xerox
Date: 12/19/2019
Enable hook given the address to hook
*/
static void enable(void* addr)
{
if (!addr)
return;
hooks.at(addr)->install();
}
/*
Author: xerox
Date: 12/19/2019
Disable hook givent the address of the hook
*/
static void disable(void* addr)
{
if (!addr)
return;
hooks.at(addr)->uninstall();
}
/*
Author: xerox
Date: 12/19/2019
Remove hook completely from vector
*/
static void remove(void* addr)
{
if (!addr)
return;
hooks.at(addr)->~detour();
hooks.erase(addr);
}
}

@ -0,0 +1,343 @@
#pragma once
#include <Windows.h>
#include <winternl.h>
#include <ntstatus.h>
#pragma comment(lib, "ntdll.lib")
#if false
#define DBG_ASSERT(...)
#define DBG_PRINT(...)
#else
#define DBG_ASSERT(...) assert(__VA_ARGS__)
#define DBG_PRINT(...) printf(__VA_ARGS__)
#endif
inline const char piddb_lock_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x4C\x8B\x8C\x24";
inline const char piddb_lock_mask[] = "xxx????x????xxxx";
inline const char piddb_table_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8D\x1D\x00\x00\x00\x00\x48\x85\xC0\x0F";
inline const char piddb_table_mask[] = "xxx????x????xxx????xxxx";
#define MM_COPY_MEMORY_PHYSICAL 0x1
#define MM_COPY_MEMORY_VIRTUAL 0x2
constexpr auto PAGE_SIZE = 0x1000;
constexpr auto SystemModuleInformation = 11;
constexpr auto SystemHandleInformation = 16;
constexpr auto SystemExtendedHandleInformation = 64;
typedef struct PiDDBCacheEntry
{
LIST_ENTRY list;
UNICODE_STRING driver_name;
ULONG time_stamp;
NTSTATUS load_status;
char _0x0028[16]; // data from the shim engine, or uninitialized memory for custom drivers
}PIDCacheobj;
typedef struct _SYSTEM_HANDLE
{
PVOID Object;
HANDLE UniqueProcessId;
HANDLE HandleValue;
ULONG GrantedAccess;
USHORT CreatorBackTraceIndex;
USHORT ObjectTypeIndex;
ULONG HandleAttributes;
ULONG Reserved;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
ULONG_PTR HandleCount;
ULONG_PTR Reserved;
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX;
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;
typedef CCHAR KPROCESSOR_MODE;
typedef enum _MODE {
KernelMode,
UserMode,
MaximumMode
} MODE;
typedef enum _POOL_TYPE {
NonPagedPool,
NonPagedPoolExecute,
PagedPool,
NonPagedPoolMustSucceed,
DontUseThisType,
NonPagedPoolCacheAligned,
PagedPoolCacheAligned,
NonPagedPoolCacheAlignedMustS,
MaxPoolType,
NonPagedPoolBase,
NonPagedPoolBaseMustSucceed,
NonPagedPoolBaseCacheAligned,
NonPagedPoolBaseCacheAlignedMustS,
NonPagedPoolSession,
PagedPoolSession,
NonPagedPoolMustSucceedSession,
DontUseThisTypeSession,
NonPagedPoolCacheAlignedSession,
PagedPoolCacheAlignedSession,
NonPagedPoolCacheAlignedMustSSession,
NonPagedPoolNx,
NonPagedPoolNxCacheAligned,
NonPagedPoolSessionNx
} POOL_TYPE;
typedef enum _MEMORY_CACHING_TYPE {
MmNonCached,
MmCached,
MmWriteCombined,
MmHardwareCoherentCached,
MmNonCachedUnordered,
MmUSWCCached,
MmMaximumCacheType,
MmNotMapped
} MEMORY_CACHING_TYPE;
typedef struct _KAPC_STATE {
LIST_ENTRY ApcListHead[MaximumMode];
struct _KPROCESS* Process;
union {
UCHAR InProgressFlags;
struct {
BOOLEAN KernelApcInProgress : 1;
BOOLEAN SpecialApcInProgress : 1;
};
};
BOOLEAN KernelApcPending;
union {
BOOLEAN UserApcPendingAll;
struct {
BOOLEAN SpecialUserApcPending : 1;
BOOLEAN UserApcPending : 1;
};
};
} KAPC_STATE, * PKAPC_STATE, * PRKAPC_STATE;
using PEPROCESS = PVOID;
using ZwOpenProcess = NTSYSAPI NTSTATUS (__fastcall*)(
PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
CLIENT_ID* ClientId
);
using ZwAllocateVirtualMemory = NTSTATUS(__fastcall*)(
_In_ HANDLE ProcessHandle,
_Inout_ PVOID* BaseAddress,
_In_ ULONG_PTR ZeroBits,
_Inout_ PSIZE_T RegionSize,
_In_ ULONG AllocationType,
_In_ ULONG Protect
);
using MmCopyVirtualMemory = NTSTATUS (__fastcall*)(
IN PEPROCESS FromProcess,
IN PVOID FromAddress,
IN PEPROCESS ToProcess,
OUT PVOID ToAddress,
IN SIZE_T BufferSize,
IN KPROCESSOR_MODE PreviousMode,
OUT PSIZE_T NumberOfBytesCopied
);
using PsLookupProcessByProcessId = NTSTATUS (__fastcall*)(
HANDLE ProcessId,
PEPROCESS* Process
);
using MmCopyMemory = NTSTATUS(__stdcall*)(
PVOID,
MM_COPY_ADDRESS,
SIZE_T,
ULONG,
PSIZE_T
);
using MmGetVirtualForPhysical = PVOID(__fastcall*)(
__in PHYSICAL_ADDRESS PhysicalAddress
);
using MmGetPhysicalAddress = PVOID (__fastcall*)(
__in PVOID BaseAddress
);
using ExAllocatePool = PVOID (__fastcall*) (
POOL_TYPE PoolType,
SIZE_T NumberOfBytes
);
using IoAllocateMdl = PVOID(__fastcall*)(
__drv_aliasesMem PVOID VirtualAddress,
ULONG Length,
BOOLEAN SecondaryBuffer,
BOOLEAN ChargeQuota,
PVOID Irp
);
using MmBuildMdlForNonPagedPool = void (__fastcall*)(
PVOID MemoryDescriptorList
);
using MmMapLockedPagesSpecifyCache = PVOID (__fastcall*)(
PVOID MemoryDescriptorList,
KPROCESSOR_MODE AccessMode,
MEMORY_CACHING_TYPE CacheType,
PVOID RequestedAddress,
ULONG BugCheckOnFailure,
ULONG Priority
);
using ExFreePool = void* (__fastcall*)(
PVOID P
);
using ExAllocatePool = PVOID(__stdcall*) (POOL_TYPE, SIZE_T);
using ExAllocatePoolWithTag = PVOID(__stdcall*)(POOL_TYPE, SIZE_T, ULONG);
using MmCopyMemory = NTSTATUS(__stdcall*)(PVOID, MM_COPY_ADDRESS, SIZE_T, ULONG, PSIZE_T);
using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(void**);
using ExAcquireResourceExclusiveLite = BOOLEAN(__stdcall*)(void*, bool);
using RtlLookupElementGenericTableAvl = PIDCacheobj * (__stdcall*) (void*, void*);
using RtlDeleteElementGenericTableAvl = bool(__stdcall*)(void*, void*);
using ExReleaseResourceLite = bool(__stdcall*)(void*);
using PsGetProcessSectionBaseAddress = void* (__fastcall*)(PEPROCESS);
typedef union _virt_addr_t
{
PVOID value;
struct
{
ULONG64 offset : 12;
ULONG64 pt_index : 9;
ULONG64 pd_index : 9;
ULONG64 pdpt_index : 9;
ULONG64 pml4_index : 9;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PDPT.
ULONG64 page_cache : 1; // Determines the memory type used to access PDPT.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Ignored1 : 1;
ULONG64 page_size : 1; // Must be 0 for PML4E.
ULONG64 Ignored2 : 4;
ULONG64 pfn : 36; // The page frame number of the PDPT of this PML4E.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 11;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 rw : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PD.
ULONG64 page_cache : 1; // Determines the memory type used to access PD.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Ignored1 : 1;
ULONG64 page_size : 1; // If 1, this entry maps a 1GB page.
ULONG64 Ignored2 : 4;
ULONG64 pfn : 36; // The page frame number of the PD of this PDPTE.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 11;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PT.
ULONG64 page_cache : 1; // Determines the memory type used to access PT.
ULONG64 Accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Ignored1 : 1;
ULONG64 page_size : 1; // If 1, this entry maps a 2MB page.
ULONG64 Ignored2 : 4;
ULONG64 pfn : 36; // The page frame number of the PT of this PDE.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 11;
ULONG64 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
{
ULONG64 value;
struct
{
ULONG64 present : 1; // Must be 1, region invalid if 0.
ULONG64 ReadWrite : 1; // If 0, writes not allowed.
ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed.
ULONG64 PageWriteThrough : 1; // Determines the memory type used to access the memory.
ULONG64 page_cache : 1; // Determines the memory type used to access the memory.
ULONG64 accessed : 1; // If 0, this entry has not been used for translation.
ULONG64 Dirty : 1; // If 0, the memory backing this page has not been written to.
ULONG64 PageAccessType : 1; // Determines the memory type used to access the memory.
ULONG64 Global : 1; // If 1 and the PGE bit of CR4 is set, translations are global.
ULONG64 Ignored2 : 3;
ULONG64 pfn : 36; // The page frame number of the backing physical page.
ULONG64 Reserved : 4;
ULONG64 Ignored3 : 7;
ULONG64 ProtectionKey : 4; // If the PKE bit of CR4 is set, determines the protection key.
ULONG64 nx : 1; // If 1, instruction fetches not allowed.
};
} pte, * ppte;
static_assert(sizeof(pte) == sizeof(PVOID), "Size mismatch, only 64-bit supported.");

@ -0,0 +1,470 @@
#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 <atomic>
#include <algorithm>
#include "nt.hpp"
namespace util
{
//--- ranges of physical memory
inline std::map<std::uintptr_t, std::size_t> pmem_ranges;
//--- validates the address
inline bool is_valid(std::uintptr_t addr)
{
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;
})();
inline std::uintptr_t get_module_base(const char* module_name)
{
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;
}
inline bool enable_privilege(const std::wstring_view 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;
}
// taken from:
// http://www.cplusplus.com/forum/windows/12137/
inline DWORD get_pid(const char* proc_name)
{
PROCESSENTRY32 proc_info;
proc_info.dwSize = sizeof(proc_info);
HANDLE proc_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (proc_snapshot == INVALID_HANDLE_VALUE)
return NULL;
Process32First(proc_snapshot, &proc_info);
if (!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;
}
// this was taken from wlan's drvmapper:
// https://github.com/not-wlan/drvmap/blob/98d93cc7b5ec17875f815a9cb94e6d137b4047ee/drvmap/util.cpp#L7
inline void open_binary_file(const std::string& file, std::vector<uint8_t>& data)
{
std::ifstream fstr(file, std::ios::binary);
fstr.unsetf(std::ios::skipws);
fstr.seekg(0, std::ios::end);
const auto file_size = fstr.tellg();
fstr.seekg(NULL, std::ios::beg);
data.reserve(static_cast<uint32_t>(file_size));
data.insert(data.begin(), std::istream_iterator<uint8_t>(fstr), std::istream_iterator<uint8_t>());
}
// get base address of kernel module
//
// taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30
inline std::uintptr_t get_kernel_module_base(const char* module_name)
{
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;
}
// get base address of kernel module
//
// taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30
inline void* get_module_export(const char* module_name, const char* export_name, bool rva = false)
{
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 = LoadLibraryEx(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);
// find exported function
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;
}
inline void* get_module_export(void* module_base, const char* export_name)
{
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);
// find exported function
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;
}
inline unsigned start_runtime_broker()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
CreateProcessA(
NULL,
(LPSTR)"C:\\Windows\\System32\\RuntimeBroker.exe",
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi
);
SuspendThread(pi.hThread);
return pi.dwProcessId;
}
inline PIMAGE_FILE_HEADER get_file_header(void* base_addr)
{
if (!base_addr || *(short*)base_addr != 0x5A4D)
return NULL;
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;
}
namespace memory
{
template<std::size_t pattern_length>
inline std::uintptr_t pattern_scan_kernel(const char(&signature)[pattern_length], const char(&mask)[pattern_length])
{
static const auto kernel_addr =
LoadLibraryEx(
"ntoskrnl.exe",
NULL,
DONT_RESOLVE_DLL_REFERENCES
);
static const auto p_idh = reinterpret_cast<PIMAGE_DOS_HEADER>(kernel_addr);
if (p_idh->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
static const auto p_inh = reinterpret_cast<PIMAGE_NT_HEADERS>((LPBYTE)kernel_addr + p_idh->e_lfanew);
if (p_inh->Signature != IMAGE_NT_SIGNATURE)
return NULL;
static auto current_section = reinterpret_cast<PIMAGE_SECTION_HEADER>(p_inh + 1);
static const auto first_section = current_section;
static const auto num_sec = p_inh->FileHeader.NumberOfSections;
static std::atomic<bool> ran_before = false;
//
// only run this once.
//
if (!ran_before.exchange(true))
for (; current_section < first_section + num_sec; ++current_section)
if (!strcmp(reinterpret_cast<char*>(current_section->Name), "PAGE"))
break;
static const auto page_section_begin =
reinterpret_cast<std::uint64_t>(kernel_addr) + current_section->VirtualAddress;
const auto pattern_view = std::string_view{
reinterpret_cast<char*>(page_section_begin),
current_section->SizeOfRawData
};
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);
});
return resultant_address == pattern_view.cend() ? 0 : reinterpret_cast<std::uintptr_t>(resultant_address.operator->());
}
//
// be aware that this may not work for win8 or win7!
//
inline void* get_piddb_lock()
{
static const auto absolute_addr_instruction =
pattern_scan_kernel(
piddb_lock_sig,
piddb_lock_mask
);
static const auto ntoskrnl_in_my_process =
reinterpret_cast<std::uintptr_t>(GetModuleHandle("ntoskrnl.exe"));
if (!absolute_addr_instruction || !ntoskrnl_in_my_process)
return {};
const auto lea_rip_rva = *(PLONG)(absolute_addr_instruction + 3);
const auto real_rva = (absolute_addr_instruction + 7 + lea_rip_rva) - ntoskrnl_in_my_process;
static const auto kernel_base = util::get_module_base("ntoskrnl.exe");
if (!kernel_base)
return {};
return reinterpret_cast<void*>(kernel_base + real_rva);
}
//
// be aware that this may not work for win8 or win7!
//
inline void* get_piddb_table()
{
static const auto absolute_addr_instruction =
pattern_scan_kernel(
piddb_table_sig,
piddb_table_mask
);
static const auto ntoskrnl_in_my_process =
reinterpret_cast<std::uintptr_t>(GetModuleHandle("ntoskrnl.exe"));
if (!absolute_addr_instruction || !ntoskrnl_in_my_process)
return {};
const auto lea_rip_rva = *(PLONG)(absolute_addr_instruction + 3);
const auto real_rva = (absolute_addr_instruction + 7 + lea_rip_rva) - ntoskrnl_in_my_process;
static const auto kernel_base = util::get_module_base("ntoskrnl.exe");
if (!kernel_base)
return {};
return reinterpret_cast<void*>(kernel_base + real_rva);
}
}
}
Loading…
Cancel
Save