Tue, Apr 14, 2020 9:02:29 PM

This commit is contained in:
Samuel Tulach
2020-04-14 21:02:29 +02:00
parent da652648b5
commit 1dc308e082
19 changed files with 934 additions and 632 deletions

View File

@@ -0,0 +1,266 @@
#include "efi_driver.hpp"
NTSTATUS efi_driver::SetSystemEnvironmentPrivilege(BOOLEAN Enable, PBOOLEAN WasEnabled)
{
if (WasEnabled != nullptr)
*WasEnabled = FALSE;
BOOLEAN SeSystemEnvironmentWasEnabled;
const NTSTATUS Status = nt::RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
Enable,
FALSE,
&SeSystemEnvironmentWasEnabled);
if (NT_SUCCESS(Status) && WasEnabled != nullptr)
*WasEnabled = SeSystemEnvironmentWasEnabled;
return Status;
}
GUID DummyGuid
= { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } };
void efi_driver::SendCommand(MemoryCommand* cmd)
{
UNICODE_STRING VariableName = RTL_CONSTANT_STRING(VARIABLE_NAME);
nt::NtSetSystemEnvironmentValueEx(&VariableName,
&DummyGuid,
cmd,
sizeof(MemoryCommand),
ATTRIBUTES);
}
bool efi_driver::Init()
{
BOOLEAN SeSystemEnvironmentWasEnabled;
NTSTATUS status = SetSystemEnvironmentPrivilege(true, &SeSystemEnvironmentWasEnabled);
return NT_SUCCESS(status);
}
bool efi_driver::MemCopy(HANDLE device_handle, uint64_t destination, uint64_t source, uint64_t size)
{
MemoryCommand* cmd = new MemoryCommand();
cmd->operation = 0;
cmd->magic = COMMAND_MAGIC;
cmd->data1 = destination;
cmd->data2 = source;
cmd->size = (int)size;
SendCommand(cmd);
return true; // yolo
}
bool efi_driver::SetMemory(HANDLE device_handle, uint64_t address, uint32_t value, uint64_t size)
{
for (int i = 0; i < size; i++)
{
MemCopy(device_handle, address + i, (uintptr_t)&value, sizeof(uint32_t));
}
return true;
}
bool efi_driver::ReadMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size)
{
return MemCopy(device_handle, reinterpret_cast<uint64_t>(buffer), address, size);
}
bool efi_driver::WriteMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size)
{
return MemCopy(device_handle, address, reinterpret_cast<uint64_t>(buffer), size);
}
uint64_t efi_driver::AllocatePool(HANDLE device_handle, nt::POOL_TYPE pool_type, uint64_t size)
{
if (!size)
return 0;
static uint64_t kernel_ExAllocatePool = 0;
if (!kernel_ExAllocatePool)
kernel_ExAllocatePool = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("ntoskrnl.exe"), "ExAllocatePool");
uint64_t allocated_pool = 0;
if (!CallKernelFunction(device_handle, &allocated_pool, kernel_ExAllocatePool, pool_type, size))
return 0;
return allocated_pool;
}
bool efi_driver::FreePool(HANDLE device_handle, uint64_t address)
{
if (!address)
return 0;
static uint64_t kernel_ExFreePool = 0;
if (!kernel_ExFreePool)
kernel_ExFreePool = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("ntoskrnl.exe"), "ExFreePool");
return CallKernelFunction<void>(device_handle, nullptr, kernel_ExFreePool, address);
}
uint64_t efi_driver::GetKernelModuleExport(HANDLE device_handle, uint64_t kernel_module_base, const std::string & function_name)
{
if (!kernel_module_base)
return 0;
IMAGE_DOS_HEADER dos_header = { 0 };
IMAGE_NT_HEADERS64 nt_headers = { 0 };
if (!ReadMemory(device_handle, kernel_module_base, &dos_header, sizeof(dos_header)) || dos_header.e_magic != IMAGE_DOS_SIGNATURE ||
!ReadMemory(device_handle, kernel_module_base + dos_header.e_lfanew, &nt_headers, sizeof(nt_headers)) || nt_headers.Signature != IMAGE_NT_SIGNATURE)
return 0;
const auto export_base = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
const auto export_base_size = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if (!export_base || !export_base_size)
return 0;
const auto export_data = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(VirtualAlloc(nullptr, export_base_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
if (!ReadMemory(device_handle, kernel_module_base + export_base, export_data, export_base_size))
{
VirtualFree(export_data, 0, MEM_RELEASE);
return 0;
}
const auto delta = reinterpret_cast<uint64_t>(export_data) - export_base;
const auto name_table = reinterpret_cast<uint32_t*>(export_data->AddressOfNames + delta);
const auto ordinal_table = reinterpret_cast<uint16_t*>(export_data->AddressOfNameOrdinals + delta);
const auto function_table = reinterpret_cast<uint32_t*>(export_data->AddressOfFunctions + delta);
for (auto i = 0u; i < export_data->NumberOfNames; ++i)
{
const std::string current_function_name = std::string(reinterpret_cast<char*>(name_table[i] + delta));
if (!_stricmp(current_function_name.c_str(), function_name.c_str()))
{
const auto function_ordinal = ordinal_table[i];
const auto function_address = kernel_module_base + function_table[function_ordinal];
if (function_address >= kernel_module_base + export_base && function_address <= kernel_module_base + export_base + export_base_size)
{
VirtualFree(export_data, 0, MEM_RELEASE);
return 0; // No forwarded exports on 64bit?
}
VirtualFree(export_data, 0, MEM_RELEASE);
return function_address;
}
}
VirtualFree(export_data, 0, MEM_RELEASE);
return 0;
}
bool efi_driver::GetNtGdiDdDDIReclaimAllocations2KernelInfo(HANDLE device_handle, uint64_t * out_kernel_function_ptr, uint64_t * out_kernel_original_function_address)
{
// 488b05650e1400 mov rax, qword ptr [rip+offset]
// ff150f211600 call cs:__guard_dispatch_icall_fptr
static uint64_t kernel_function_ptr = 0;
static uint64_t kernel_original_function_address = 0;
if (!kernel_function_ptr || !kernel_original_function_address)
{
const uint64_t kernel_NtGdiDdDDIReclaimAllocations2 = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("win32kbase.sys"), "NtGdiDdDDIReclaimAllocations2");
if (!kernel_NtGdiDdDDIReclaimAllocations2)
{
std::cout << "[-] Failed to get export win32kbase.NtGdiDdDDIReclaimAllocations2" << std::endl;
return false;
}
const uint64_t kernel_function_ptr_offset_address = kernel_NtGdiDdDDIReclaimAllocations2 + 0x7;
int32_t function_ptr_offset = 0; // offset is a SIGNED integer
if (!ReadMemory(device_handle, kernel_function_ptr_offset_address, &function_ptr_offset, sizeof(function_ptr_offset)))
return false;
kernel_function_ptr = kernel_NtGdiDdDDIReclaimAllocations2 + 0xB + function_ptr_offset;
if (!ReadMemory(device_handle, kernel_function_ptr, &kernel_original_function_address, sizeof(kernel_original_function_address)))
return false;
}
*out_kernel_function_ptr = kernel_function_ptr;
*out_kernel_original_function_address = kernel_original_function_address;
return true;
}
bool efi_driver::ClearMmUnloadedDrivers(HANDLE device_handle)
{
ULONG buffer_size = 0;
void* buffer = nullptr;
NTSTATUS status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(nt::SystemExtendedHandleInformation), buffer, buffer_size, &buffer_size);
while (status == nt::STATUS_INFO_LENGTH_MISMATCH)
{
VirtualFree(buffer, 0, MEM_RELEASE);
buffer = VirtualAlloc(nullptr, buffer_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(nt::SystemExtendedHandleInformation), buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, 0, MEM_RELEASE);
return false;
}
uint64_t object = 0;
auto system_handle_inforamtion = static_cast<nt::PSYSTEM_HANDLE_INFORMATION_EX>(buffer);
for (auto i = 0u; i < system_handle_inforamtion->HandleCount; ++i)
{
const nt::SYSTEM_HANDLE current_system_handle = system_handle_inforamtion->Handles[i];
if (current_system_handle.UniqueProcessId != reinterpret_cast<HANDLE>(static_cast<uint64_t>(GetCurrentProcessId())))
continue;
if (current_system_handle.HandleValue == device_handle)
{
object = reinterpret_cast<uint64_t>(current_system_handle.Object);
break;
}
}
VirtualFree(buffer, 0, MEM_RELEASE);
if (!object)
return false;
uint64_t device_object = 0;
if (!ReadMemory(device_handle, object + 0x8, &device_object, sizeof(device_object)))
return false;
uint64_t driver_object = 0;
if (!ReadMemory(device_handle, device_object + 0x8, &driver_object, sizeof(driver_object)))
return false;
uint64_t driver_section = 0;
if (!ReadMemory(device_handle, driver_object + 0x28, &driver_section, sizeof(driver_section)))
return false;
UNICODE_STRING us_driver_base_dll_name = { 0 };
if (!ReadMemory(device_handle, driver_section + 0x58, &us_driver_base_dll_name, sizeof(us_driver_base_dll_name)))
return false;
us_driver_base_dll_name.Length = 0;
if (!WriteMemory(device_handle, driver_section + 0x58, &us_driver_base_dll_name, sizeof(us_driver_base_dll_name)))
return false;
return true;
}

View File

@@ -0,0 +1,113 @@
#pragma once
#include <Windows.h>
#include <iostream>
#include <string>
#include <filesystem>
#include <atlstr.h>
#include "service.hpp"
#include "utils.hpp"
namespace efi_driver
{
typedef struct _MemoryCommand
{
int magic;
int operation;
unsigned long long data1;
unsigned long long data2;
int size;
} MemoryCommand;
#define VARIABLE_NAME L"yromeMifE" // EfiMemory
#define COMMAND_MAGIC 0xDEAD
#define EFI_VARIABLE_NON_VOLATILE 0x00000001
#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008
#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010
#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020
#define EFI_VARIABLE_APPEND_WRITE 0x00000040
#define ATTRIBUTES (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)
#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L)
bool Init();
NTSTATUS SetSystemEnvironmentPrivilege(BOOLEAN Enable, PBOOLEAN WasEnabled);
void SendCommand(MemoryCommand* cmd);
bool MemCopy(HANDLE device_handle, uint64_t destination, uint64_t source, uint64_t size);
bool SetMemory(HANDLE device_handle, uint64_t address, uint32_t value, uint64_t size);
bool ReadMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size);
bool WriteMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size);
uint64_t AllocatePool(HANDLE device_handle, nt::POOL_TYPE pool_type, uint64_t size);
bool FreePool(HANDLE device_handle, uint64_t address);
uint64_t GetKernelModuleExport(HANDLE device_handle, uint64_t kernel_module_base, const std::string& function_name);
bool GetNtGdiDdDDIReclaimAllocations2KernelInfo(HANDLE device_handle, uint64_t* out_kernel_function_ptr, uint64_t* out_kernel_original_function_address);
bool ClearMmUnloadedDrivers(HANDLE device_handle);
template<typename T, typename ...A>
bool CallKernelFunction(HANDLE device_handle, T* out_result, uint64_t kernel_function_address, const A ...arguments)
{
constexpr auto call_void = std::is_same_v<T, void>;
if constexpr (!call_void)
{
if (!out_result)
return false;
}
else
{
UNREFERENCED_PARAMETER(out_result);
}
if (!kernel_function_address)
return false;
// Setup function call
const auto NtGdiDdDDIReclaimAllocations2 = reinterpret_cast<void*>(GetProcAddress(LoadLibrary("gdi32full.dll"), "NtGdiDdDDIReclaimAllocations2"));
if (!NtGdiDdDDIReclaimAllocations2)
{
std::cout << "[-] Failed to get export gdi32full.NtGdiDdDDIReclaimAllocations2" << std::endl;
return false;
}
// Get function pointer (@win32kbase!gDxgkInterface table) used by NtGdiDdDDIReclaimAllocations2 and save the original address (dxgkrnl!DxgkReclaimAllocations2)
uint64_t kernel_function_ptr = 0;
uint64_t kernel_original_function_address = 0;
if (!GetNtGdiDdDDIReclaimAllocations2KernelInfo(device_handle, &kernel_function_ptr, &kernel_original_function_address))
return false;
// Overwrite the pointer with kernel_function_address
if (!WriteMemory(device_handle, kernel_function_ptr, &kernel_function_address, sizeof(kernel_function_address)))
return false;
// Call function
if constexpr (!call_void)
{
using FunctionFn = T(__stdcall*)(A...);
const auto Function = static_cast<FunctionFn>(NtGdiDdDDIReclaimAllocations2);
*out_result = Function(arguments...);
}
else
{
using FunctionFn = void(__stdcall*)(A...);
const auto Function = static_cast<FunctionFn>(NtGdiDdDDIReclaimAllocations2);
Function(arguments...);
}
// Restore the pointer
WriteMemory(device_handle, kernel_function_ptr, &kernel_original_function_address, sizeof(kernel_original_function_address));
return true;
}
}

View File

@@ -0,0 +1,145 @@
#include "kdmapper.hpp"
uint64_t kdmapper::MapDriver(HANDLE iqvw64e_device_handle, const std::string& driver_path)
{
std::vector<uint8_t> raw_image = { 0 };
if (!utils::ReadFileToMemory(driver_path, &raw_image))
{
std::cout << "[-] Failed to read image to memory" << std::endl;
return 0;
}
const PIMAGE_NT_HEADERS64 nt_headers = portable_executable::GetNtHeaders(raw_image.data());
if (!nt_headers)
{
std::cout << "[-] Invalid format of PE image" << std::endl;
return 0;
}
if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
std::cout << "[-] Image is not 64 bit" << std::endl;
return 0;
}
const uint32_t image_size = nt_headers->OptionalHeader.SizeOfImage;
void* local_image_base = VirtualAlloc(nullptr, image_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
uint64_t kernel_image_base = efi_driver::AllocatePool(iqvw64e_device_handle, nt::NonPagedPool, image_size);
do
{
if (!kernel_image_base)
{
std::cout << "[-] Failed to allocate remote image in kernel" << std::endl;
break;
}
std::cout << "[+] Image base has been allocated at 0x" << reinterpret_cast<void*>(kernel_image_base) << std::endl;
// Copy image headers
memcpy(local_image_base, raw_image.data(), nt_headers->OptionalHeader.SizeOfHeaders);
// Copy image sections
const PIMAGE_SECTION_HEADER current_image_section = IMAGE_FIRST_SECTION(nt_headers);
for (auto i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i)
{
auto local_section = reinterpret_cast<void*>(reinterpret_cast<uint64_t>(local_image_base) + current_image_section[i].VirtualAddress);
memcpy(local_section, reinterpret_cast<void*>(reinterpret_cast<uint64_t>(raw_image.data()) + current_image_section[i].PointerToRawData), current_image_section[i].SizeOfRawData);
}
// Resolve relocs and imports
RelocateImageByDelta(portable_executable::GetRelocs(local_image_base), kernel_image_base - nt_headers->OptionalHeader.ImageBase);
if (!ResolveImports(iqvw64e_device_handle, portable_executable::GetImports(local_image_base)))
{
std::cout << "[-] Failed to resolve imports" << std::endl;
break;
}
// Write fixed image to kernel
if (!efi_driver::WriteMemory(iqvw64e_device_handle, kernel_image_base, local_image_base, image_size))
{
std::cout << "[-] Failed to write local image to remote image" << std::endl;
break;
}
VirtualFree(local_image_base, 0, MEM_RELEASE);
// Call driver entry point
const uint64_t address_of_entry_point = kernel_image_base + nt_headers->OptionalHeader.AddressOfEntryPoint;
std::cout << "[<] Calling DriverEntry 0x" << reinterpret_cast<void*>(address_of_entry_point) << std::endl;
NTSTATUS status = 0;
if (!efi_driver::CallKernelFunction(iqvw64e_device_handle, &status, address_of_entry_point))
{
std::cout << "[-] Failed to call driver entry" << std::endl;
break;
}
std::cout << "[+] DriverEntry returned 0x" << std::hex << std::setw(8) << std::setfill('0') << std::uppercase << status << std::nouppercase << std::dec << std::endl;
// Erase PE headers
efi_driver::SetMemory(iqvw64e_device_handle, kernel_image_base, 0, nt_headers->OptionalHeader.SizeOfHeaders);
return kernel_image_base;
} while (false);
VirtualFree(local_image_base, 0, MEM_RELEASE);
efi_driver::FreePool(iqvw64e_device_handle, kernel_image_base);
return 0;
}
void kdmapper::RelocateImageByDelta(portable_executable::vec_relocs relocs, const uint64_t delta)
{
for (const auto& current_reloc : relocs)
{
for (auto i = 0u; i < current_reloc.count; ++i)
{
const uint16_t type = current_reloc.item[i] >> 12;
const uint16_t offset = current_reloc.item[i] & 0xFFF;
if (type == IMAGE_REL_BASED_DIR64)
* reinterpret_cast<uint64_t*>(current_reloc.address + offset) += delta;
}
}
}
bool kdmapper::ResolveImports(HANDLE iqvw64e_device_handle, portable_executable::vec_imports imports)
{
for (const auto& current_import : imports)
{
if (!utils::GetKernelModuleAddress(current_import.module_name))
{
std::cout << "[-] Dependency " << current_import.module_name << " wasn't found" << std::endl;
return false;
}
for (auto& current_function_data : current_import.function_datas)
{
const uint64_t function_address = efi_driver::GetKernelModuleExport(iqvw64e_device_handle, utils::GetKernelModuleAddress(current_import.module_name), current_function_data.name);
if (!function_address)
{
std::cout << "[-] Failed to resolve import " << current_function_data.name << " (" << current_import.module_name << ")" << std::endl;
return false;
}
*current_function_data.address = function_address;
}
}
return true;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <Windows.h>
#include <stdint.h>
#include <iostream>
#include <vector>
#include <string>
#include <filesystem>
#include "portable_executable.hpp"
#include "utils.hpp"
#include "nt.hpp"
#include "efi_driver.hpp"
namespace kdmapper
{
uint64_t MapDriver(HANDLE iqvw64e_device_handle, const std::string& driver_path);
void RelocateImageByDelta(portable_executable::vec_relocs relocs, const uint64_t delta);
bool ResolveImports(HANDLE iqvw64e_device_handle, portable_executable::vec_imports imports);
}

View File

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{518E0636-BA8F-459D-ACAC-81BD33475E3E}</ProjectGuid>
<RootNamespace>kdmapper</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 />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<TreatWarningAsError>false</TreatWarningAsError>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<TreatWarningAsError>true</TreatWarningAsError>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="efi_driver.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="kdmapper.cpp" />
<ClCompile Include="portable_executable.cpp" />
<ClCompile Include="service.cpp" />
<ClCompile Include="utils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="efi_driver.hpp" />
<ClInclude Include="kdmapper.hpp" />
<ClInclude Include="nt.hpp" />
<ClInclude Include="portable_executable.hpp" />
<ClInclude Include="service.hpp" />
<ClInclude Include="utils.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,35 @@
#include "kdmapper.hpp"
int main(const int argc, char** argv)
{
if (argc != 2 || std::filesystem::path(argv[1]).extension().string().compare(".sys"))
{
std::cout << "[-] Incorrect usage" << std::endl;
return -1;
}
const std::string driver_path = argv[1];
if (!std::filesystem::exists(driver_path))
{
std::cout << "[-] File " << driver_path << " doesn't exist" << std::endl;
return -1;
}
HANDLE iqvw64e_device_handle = nullptr; // dummy handle because I am lazy piece of shit
bool status = efi_driver::Init();
if (!status)
{
std::cout << "[-] Failed to init driver" << std::endl;
return -1;
}
if (!kdmapper::MapDriver(iqvw64e_device_handle, driver_path))
{
std::cout << "[-] Failed to map " << driver_path << std::endl;
return -1;
}
std::cout << "[+] success" << std::endl;
}

View File

@@ -0,0 +1,105 @@
#pragma once
#include <Windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll.lib")
namespace nt
{
constexpr auto PAGE_SIZE = 0x1000;
constexpr auto STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
constexpr auto SystemModuleInformation = 11;
constexpr auto SystemHandleInformation = 16;
constexpr auto SystemExtendedHandleInformation = 64;
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 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 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;
extern "C"
{
NTSYSAPI
NTSTATUS
NTAPI
RtlAdjustPrivilege(
_In_ ULONG Privilege,
_In_ BOOLEAN Enable,
_In_ BOOLEAN Client,
_Out_ PBOOLEAN WasEnabled
);
NTSYSCALLAPI
NTSTATUS
NTAPI
NtSetSystemEnvironmentValueEx(
_In_ PUNICODE_STRING VariableName,
_In_ LPGUID VendorGuid,
_In_reads_bytes_opt_(ValueLength) PVOID Value,
_In_ ULONG ValueLength,
_In_ ULONG Attributes
);
}
#define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof((s)[0]), sizeof(s), (PWSTR)s }
}

View File

@@ -0,0 +1,86 @@
#include "portable_executable.hpp"
PIMAGE_NT_HEADERS64 portable_executable::GetNtHeaders(void* image_base)
{
const auto dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>(image_base);
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
return nullptr;
const auto nt_headers = reinterpret_cast<PIMAGE_NT_HEADERS64>(reinterpret_cast<uint64_t>(image_base) + dos_header->e_lfanew);
if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
return nullptr;
return nt_headers;
}
portable_executable::vec_relocs portable_executable::GetRelocs(void* image_base)
{
const PIMAGE_NT_HEADERS64 nt_headers = GetNtHeaders(image_base);
if (!nt_headers)
return {};
vec_relocs relocs;
auto current_base_relocation = reinterpret_cast<PIMAGE_BASE_RELOCATION>(reinterpret_cast<uint64_t>(image_base) + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
const auto reloc_end = reinterpret_cast<uint64_t>(current_base_relocation) + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
while (current_base_relocation->VirtualAddress && current_base_relocation->VirtualAddress < reloc_end && current_base_relocation->SizeOfBlock)
{
RelocInfo reloc_info;
reloc_info.address = reinterpret_cast<uint64_t>(image_base) + current_base_relocation->VirtualAddress;
reloc_info.item = reinterpret_cast<uint16_t*>(reinterpret_cast<uint64_t>(current_base_relocation) + sizeof(IMAGE_BASE_RELOCATION));
reloc_info.count = (current_base_relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t);
relocs.push_back(reloc_info);
current_base_relocation = reinterpret_cast<PIMAGE_BASE_RELOCATION>(reinterpret_cast<uint64_t>(current_base_relocation) + current_base_relocation->SizeOfBlock);
}
return relocs;
}
portable_executable::vec_imports portable_executable::GetImports(void* image_base)
{
const PIMAGE_NT_HEADERS64 nt_headers = GetNtHeaders(image_base);
if (!nt_headers)
return {};
vec_imports imports;
auto current_import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(reinterpret_cast<uint64_t>(image_base) + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (current_import_descriptor->FirstThunk)
{
ImportInfo import_info;
import_info.module_name = std::string(reinterpret_cast<char*>(reinterpret_cast<uint64_t>(image_base) + current_import_descriptor->Name));
auto current_first_thunk = reinterpret_cast<PIMAGE_THUNK_DATA64>(reinterpret_cast<uint64_t>(image_base) + current_import_descriptor->FirstThunk);
auto current_originalFirstThunk = reinterpret_cast<PIMAGE_THUNK_DATA64>(reinterpret_cast<uint64_t>(image_base) + current_import_descriptor->OriginalFirstThunk);
while (current_originalFirstThunk->u1.Function)
{
ImportFunctionInfo import_function_data;
auto thunk_data = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(reinterpret_cast<uint64_t>(image_base) + current_originalFirstThunk->u1.AddressOfData);
import_function_data.name = thunk_data->Name;
import_function_data.address = &current_first_thunk->u1.Function;
import_info.function_datas.push_back(import_function_data);
++current_originalFirstThunk;
++current_first_thunk;
}
imports.push_back(import_info);
++current_import_descriptor;
}
return imports;
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include <Windows.h>
#include <stdint.h>
#include <vector>
#include <string>
namespace portable_executable
{
struct RelocInfo
{
uint64_t address;
uint16_t* item;
uint32_t count;
};
struct ImportFunctionInfo
{
std::string name;
uint64_t* address;
};
struct ImportInfo
{
std::string module_name;
std::vector<ImportFunctionInfo> function_datas;
};
using vec_sections = std::vector<IMAGE_SECTION_HEADER>;
using vec_relocs = std::vector<RelocInfo>;
using vec_imports = std::vector<ImportInfo>;
PIMAGE_NT_HEADERS64 GetNtHeaders(void* image_base);
vec_relocs GetRelocs(void* image_base);
vec_imports GetImports(void* image_base);
}

View File

@@ -0,0 +1,54 @@
#include "service.hpp"
bool service::RegisterAndStart(const std::string& driver_path)
{
const std::string driver_name = std::filesystem::path(driver_path).filename().string();
const SC_HANDLE sc_manager_handle = OpenSCManager(nullptr, nullptr, SC_MANAGER_CREATE_SERVICE);
if (!sc_manager_handle)
return false;
SC_HANDLE service_handle = CreateService(sc_manager_handle, driver_name.c_str(), driver_name.c_str(), SERVICE_START | SERVICE_STOP | DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, driver_path.c_str(), nullptr, nullptr, nullptr, nullptr, nullptr);
if (!service_handle)
{
service_handle = OpenService(sc_manager_handle, driver_name.c_str(), SERVICE_START);
if (!service_handle)
{
CloseServiceHandle(sc_manager_handle);
return false;
}
}
const bool result = StartService(service_handle, 0, nullptr);
CloseServiceHandle(service_handle);
CloseServiceHandle(sc_manager_handle);
return result;
}
bool service::StopAndRemove(const std::string& driver_name)
{
const SC_HANDLE sc_manager_handle = OpenSCManager(nullptr, nullptr, SC_MANAGER_CREATE_SERVICE);
if (!sc_manager_handle)
return false;
const SC_HANDLE service_handle = OpenService(sc_manager_handle, driver_name.c_str(), SERVICE_STOP | DELETE);
if (!service_handle)
{
CloseServiceHandle(sc_manager_handle);
return false;
}
SERVICE_STATUS status = { 0 };
const bool result = ControlService(service_handle, SERVICE_CONTROL_STOP, &status) && DeleteService(service_handle);
CloseServiceHandle(service_handle);
CloseServiceHandle(sc_manager_handle);
return result;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <Windows.h>
#include <string>
#include <filesystem>
namespace service
{
bool RegisterAndStart(const std::string& driver_path);
bool StopAndRemove(const std::string& driver_name);
};

View File

@@ -0,0 +1,68 @@
#include "utils.hpp"
bool utils::ReadFileToMemory(const std::string& file_path, std::vector<uint8_t>* out_buffer)
{
std::ifstream file_ifstream(file_path, std::ios::binary);
if (!file_ifstream)
return false;
out_buffer->assign((std::istreambuf_iterator<char>(file_ifstream)), std::istreambuf_iterator<char>());
file_ifstream.close();
return true;
}
bool utils::CreateFileFromMemory(const std::string& desired_file_path, const char* address, size_t size)
{
std::ofstream file_ofstream(desired_file_path.c_str(), std::ios_base::out | std::ios_base::binary);
if (!file_ofstream.write(address, size))
{
file_ofstream.close();
return false;
}
file_ofstream.close();
return true;
}
uint64_t utils::GetKernelModuleAddress(const std::string& module_name)
{
void* buffer = nullptr;
DWORD buffer_size = 0;
NTSTATUS status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(nt::SystemModuleInformation), buffer, buffer_size, &buffer_size);
while (status == nt::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>(nt::SystemModuleInformation), buffer, buffer_size, &buffer_size);
}
if (!NT_SUCCESS(status))
{
VirtualFree(buffer, 0, MEM_RELEASE);
return 0;
}
const auto modules = static_cast<nt::PRTL_PROCESS_MODULES>(buffer);
for (auto i = 0u; i < modules->NumberOfModules; ++i)
{
const std::string current_module_name = std::string(reinterpret_cast<char*>(modules->Modules[i].FullPathName) + modules->Modules[i].OffsetToFileName);
if (!_stricmp(current_module_name.c_str(), module_name.c_str()))
{
const uint64_t result = reinterpret_cast<uint64_t>(modules->Modules[i].ImageBase);
VirtualFree(buffer, 0, MEM_RELEASE);
return result;
}
}
VirtualFree(buffer, 0, MEM_RELEASE);
return 0;
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include <Windows.h>
#include <TlHelp32.h>
#include <stdint.h>
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include "nt.hpp"
namespace utils
{
bool ReadFileToMemory(const std::string& file_path, std::vector<uint8_t>* out_buffer);
bool CreateFileFromMemory(const std::string& desired_file_path, const char* address, size_t size);
uint64_t GetKernelModuleAddress(const std::string& module_name);
}