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,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));
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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,
|
||||
¤t_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,
|
||||
¤t_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,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(),
|
||||
®_handle
|
||||
);
|
||||
|
||||
return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) && ERROR_SUCCESS == RegCloseKey(reg_handle);
|
||||
}
|
||||
|
||||
inline bool create_service_entry(const std::string& drv_path, const std::string& service_name)
|
||||
{
|
||||
HKEY reg_handle;
|
||||
std::string reg_key("System\\CurrentControlSet\\Services\\");
|
||||
reg_key += service_name;
|
||||
|
||||
auto result = RegCreateKeyA(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
reg_key.c_str(),
|
||||
®_handle
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
//
|
||||
// set type to 1 (kernel)
|
||||
//
|
||||
constexpr std::uint8_t type_value = 1;
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"Type",
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
&type_value,
|
||||
4u
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
//
|
||||
// set error control to 3
|
||||
//
|
||||
constexpr std::uint8_t error_control_value = 3;
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"ErrorControl",
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
&error_control_value,
|
||||
4u
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
//
|
||||
// set start to 3
|
||||
//
|
||||
constexpr std::uint8_t start_value = 3;
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"Start",
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
&start_value,
|
||||
4u
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
//
|
||||
// set image path to the driver on disk
|
||||
//
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"ImagePath",
|
||||
NULL,
|
||||
REG_SZ,
|
||||
(std::uint8_t*) drv_path.c_str(),
|
||||
drv_path.size()
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
return ERROR_SUCCESS == RegCloseKey(reg_handle);
|
||||
}
|
||||
|
||||
// this function was coded by paracord: https://githacks.org/snippets/4#L94
|
||||
inline bool enable_privilege(const std::wstring& privilege_name)
|
||||
{
|
||||
HANDLE token_handle = nullptr;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
|
||||
return false;
|
||||
|
||||
LUID luid{};
|
||||
if (!LookupPrivilegeValueW(nullptr, privilege_name.data(), &luid))
|
||||
return false;
|
||||
|
||||
TOKEN_PRIVILEGES token_state{};
|
||||
token_state.PrivilegeCount = 1;
|
||||
token_state.Privileges[0].Luid = luid;
|
||||
token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if (!AdjustTokenPrivileges(token_handle, FALSE, &token_state, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
CloseHandle(token_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::string get_service_image_path(const std::string& service_name)
|
||||
{
|
||||
HKEY reg_handle;
|
||||
DWORD bytes_read;
|
||||
char image_path[0xFF];
|
||||
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
|
||||
|
||||
auto result = RegOpenKeyA(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
reg_key.c_str(),
|
||||
®_handle
|
||||
);
|
||||
|
||||
result = RegGetValueA(
|
||||
reg_handle,
|
||||
service_name.c_str(),
|
||||
"ImagePath",
|
||||
REG_SZ,
|
||||
NULL,
|
||||
image_path,
|
||||
&bytes_read
|
||||
);
|
||||
|
||||
RegCloseKey(reg_handle);
|
||||
return std::string(image_path);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool load(const std::string& drv_path, const std::string& service_name)
|
||||
{
|
||||
if (!util::enable_privilege(L"SeLoadDriverPrivilege"))
|
||||
return false;
|
||||
|
||||
if (!util::create_service_entry("\\??\\" + std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
|
||||
return false;
|
||||
|
||||
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
|
||||
reg_path += service_name;
|
||||
|
||||
static const auto lp_nt_load_drv =
|
||||
::GetProcAddress(
|
||||
GetModuleHandleA("ntdll.dll"),
|
||||
"NtLoadDriver"
|
||||
);
|
||||
|
||||
if (lp_nt_load_drv)
|
||||
{
|
||||
ANSI_STRING driver_rep_path_cstr;
|
||||
UNICODE_STRING driver_reg_path_unicode;
|
||||
|
||||
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
|
||||
RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
|
||||
return ERROR_SUCCESS == reinterpret_cast<nt_load_driver_t>(lp_nt_load_drv)(&driver_reg_path_unicode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::tuple<bool, std::string> load(const std::vector<std::uint8_t>& drv_buffer)
|
||||
{
|
||||
static const auto random_file_name = [](std::size_t length) -> std::string
|
||||
{
|
||||
static const auto randchar = []() -> char
|
||||
{
|
||||
const char charset[] =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const std::size_t max_index = (sizeof(charset) - 1);
|
||||
return charset[rand() % max_index];
|
||||
};
|
||||
std::string str(length, 0);
|
||||
std::generate_n(str.begin(), length, randchar);
|
||||
return str;
|
||||
};
|
||||
|
||||
const auto service_name = random_file_name(16);
|
||||
const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
|
||||
|
||||
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,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));
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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,
|
||||
¤t_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,
|
||||
¤t_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,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(),
|
||||
®_handle
|
||||
);
|
||||
|
||||
return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) && ERROR_SUCCESS == RegCloseKey(reg_handle);
|
||||
}
|
||||
|
||||
inline bool create_service_entry(const std::string& drv_path, const std::string& service_name)
|
||||
{
|
||||
HKEY reg_handle;
|
||||
std::string reg_key("System\\CurrentControlSet\\Services\\");
|
||||
reg_key += service_name;
|
||||
|
||||
auto result = RegCreateKeyA(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
reg_key.c_str(),
|
||||
®_handle
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
//
|
||||
// set type to 1 (kernel)
|
||||
//
|
||||
constexpr std::uint8_t type_value = 1;
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"Type",
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
&type_value,
|
||||
4u
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
//
|
||||
// set error control to 3
|
||||
//
|
||||
constexpr std::uint8_t error_control_value = 3;
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"ErrorControl",
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
&error_control_value,
|
||||
4u
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
//
|
||||
// set start to 3
|
||||
//
|
||||
constexpr std::uint8_t start_value = 3;
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"Start",
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
&start_value,
|
||||
4u
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
//
|
||||
// set image path to the driver on disk
|
||||
//
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"ImagePath",
|
||||
NULL,
|
||||
REG_SZ,
|
||||
(std::uint8_t*) drv_path.c_str(),
|
||||
drv_path.size()
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
return ERROR_SUCCESS == RegCloseKey(reg_handle);
|
||||
}
|
||||
|
||||
// this function was coded by paracord: https://githacks.org/snippets/4#L94
|
||||
inline bool enable_privilege(const std::wstring& privilege_name)
|
||||
{
|
||||
HANDLE token_handle = nullptr;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
|
||||
return false;
|
||||
|
||||
LUID luid{};
|
||||
if (!LookupPrivilegeValueW(nullptr, privilege_name.data(), &luid))
|
||||
return false;
|
||||
|
||||
TOKEN_PRIVILEGES token_state{};
|
||||
token_state.PrivilegeCount = 1;
|
||||
token_state.Privileges[0].Luid = luid;
|
||||
token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if (!AdjustTokenPrivileges(token_handle, FALSE, &token_state, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
CloseHandle(token_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::string get_service_image_path(const std::string& service_name)
|
||||
{
|
||||
HKEY reg_handle;
|
||||
DWORD bytes_read;
|
||||
char image_path[0xFF];
|
||||
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
|
||||
|
||||
auto result = RegOpenKeyA(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
reg_key.c_str(),
|
||||
®_handle
|
||||
);
|
||||
|
||||
result = RegGetValueA(
|
||||
reg_handle,
|
||||
service_name.c_str(),
|
||||
"ImagePath",
|
||||
REG_SZ,
|
||||
NULL,
|
||||
image_path,
|
||||
&bytes_read
|
||||
);
|
||||
|
||||
RegCloseKey(reg_handle);
|
||||
return std::string(image_path);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool load(const std::string& drv_path, const std::string& service_name)
|
||||
{
|
||||
if (!util::enable_privilege(L"SeLoadDriverPrivilege"))
|
||||
return false;
|
||||
|
||||
if (!util::create_service_entry("\\??\\" + std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
|
||||
return false;
|
||||
|
||||
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
|
||||
reg_path += service_name;
|
||||
|
||||
static const auto lp_nt_load_drv =
|
||||
::GetProcAddress(
|
||||
GetModuleHandleA("ntdll.dll"),
|
||||
"NtLoadDriver"
|
||||
);
|
||||
|
||||
if (lp_nt_load_drv)
|
||||
{
|
||||
ANSI_STRING driver_rep_path_cstr;
|
||||
UNICODE_STRING driver_reg_path_unicode;
|
||||
|
||||
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
|
||||
RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
|
||||
return ERROR_SUCCESS == reinterpret_cast<nt_load_driver_t>(lp_nt_load_drv)(&driver_reg_path_unicode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::tuple<bool, std::string> load(const std::vector<std::uint8_t>& drv_buffer)
|
||||
{
|
||||
static const auto random_file_name = [](std::size_t length) -> std::string
|
||||
{
|
||||
static const auto randchar = []() -> char
|
||||
{
|
||||
const char charset[] =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const std::size_t max_index = (sizeof(charset) - 1);
|
||||
return charset[rand() % max_index];
|
||||
};
|
||||
std::string str(length, 0);
|
||||
std::generate_n(str.begin(), length, randchar);
|
||||
return str;
|
||||
};
|
||||
|
||||
const auto service_name = random_file_name(16);
|
||||
const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
|
||||
|
||||
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…
Reference in new issue