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

@@ -1,31 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29728.190
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client\client.vcxproj", "{73BB66C2-5447-4DA2-8790-E9CE90AF6821}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{73BB66C2-5447-4DA2-8790-E9CE90AF6821}.Debug|x64.ActiveCfg = Debug|x64
{73BB66C2-5447-4DA2-8790-E9CE90AF6821}.Debug|x64.Build.0 = Debug|x64
{73BB66C2-5447-4DA2-8790-E9CE90AF6821}.Debug|x86.ActiveCfg = Debug|Win32
{73BB66C2-5447-4DA2-8790-E9CE90AF6821}.Debug|x86.Build.0 = Debug|Win32
{73BB66C2-5447-4DA2-8790-E9CE90AF6821}.Release|x64.ActiveCfg = Release|x64
{73BB66C2-5447-4DA2-8790-E9CE90AF6821}.Release|x64.Build.0 = Release|x64
{73BB66C2-5447-4DA2-8790-E9CE90AF6821}.Release|x86.ActiveCfg = Release|Win32
{73BB66C2-5447-4DA2-8790-E9CE90AF6821}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5032EDB2-BA80-44F5-A9C5-E09C36732671}
EndGlobalSection
EndGlobal

View File

@@ -1,97 +0,0 @@
/*
Copyright (c) 2020 Samuel Tulach
Copyright (c) 2019 z175
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.
*/
#include <iostream>
#include <iomanip>
#include "nt.h"
#include "driver.h"
#include "utils.h"
#include "helper.h"
#define EXPLORER_EXE L"explorer.exe"
#define PRINT_HEX(x) std::hex << std::setw(8) << std::setfill('0') << std::uppercase << x << std::nouppercase << std::dec
int main()
{
std::cout << "[>] Enabling SE_SYSTEM_ENVIRONMENT_PRIVILEGE..." << std::endl;
bool status = Driver::Init();
if (!status)
{
std::cout << "[-] Failed to enable privilege" << std::endl;
return -1;
}
std::cout << "[>] Testing driver..." << std::endl;
status = Driver::Test();
if (!status)
{
std::cout << "[-] Driver test failed" << std::endl;
return -1;
}
std::cout << "[>] Getting current process PEPROCESS..." << std::endl;
uintptr_t current = Helper::GetCurrentProcessKrnl();
if (!current)
{
std::cout << "[-] Failed to get current process" << std::endl;
return -1;
}
std::cout << "[+] Current PEPROCESS 0x" << PRINT_HEX(current) << std::endl;
std::cout << "[>] Getting explorer.exe PEPROCESS..." << std::endl;
int pid = Utils::Find(EXPLORER_EXE);
if (!pid)
{
std::cout << "[-] Failed to find explorer.exe pid" << std::endl;
return -1;
}
uintptr_t explorer = 0;
Helper::LookupProcess(pid, &explorer);
if (!explorer)
{
std::cout << "[-] Failed to get explorer.exe PEPROCESS" << std::endl;
return -1;
}
std::cout << "[+] Target PEPROCESS 0x" << PRINT_HEX(explorer) << std::endl;
std::cout << "[>] Getting process base..." << std::endl;
uintptr_t baseaddress = Helper::GetSectionBase(explorer);
if (!baseaddress)
{
std::cout << "[-] Failed to get base address" << std::endl;
return -1;
}
std::cout << "[+] Explorer.exe base 0x" << PRINT_HEX(baseaddress) << std::endl;
std::cout << "[>] Reading DOS header..." << std::endl;
IMAGE_DOS_HEADER* header = new IMAGE_DOS_HEADER;
SIZE_T retsize = 0;
NTSTATUS copystatus = Helper::CopyVirtualMemory(explorer, baseaddress, current, (uintptr_t)header, sizeof(IMAGE_DOS_HEADER), 0, &retsize);
std::cout << "[+] Test read:" << std::endl;
std::cout << "\tStatus: 0x" << PRINT_HEX(copystatus) << std::endl;
std::cout << "\tRead: 0x" << PRINT_HEX(retsize) << std::endl;
std::cout << "\tDOS magic: 0x" << PRINT_HEX(header->e_magic) << std::endl;
std::cout << "\tNT offset: 0x" << PRINT_HEX(header->e_lfanew) << std::endl;
}

View File

@@ -1,104 +0,0 @@
#pragma once
namespace 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
GUID DummyGuid
= { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } };
#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)
NTSTATUS 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;
}
void SendCommand(MemoryCommand* cmd)
{
UNICODE_STRING VariableName = RTL_CONSTANT_STRING(VARIABLE_NAME);
NTSTATUS status = nt::NtSetSystemEnvironmentValueEx(&VariableName,
&DummyGuid,
cmd,
sizeof(MemoryCommand),
ATTRIBUTES);
}
bool Init()
{
BOOLEAN SeSystemEnvironmentWasEnabled;
NTSTATUS status = SetSystemEnvironmentPrivilege(true, &SeSystemEnvironmentWasEnabled);
return NT_SUCCESS(status);
}
bool Test()
{
uintptr_t read = 0;
uintptr_t value = 123;
MemoryCommand* cmd = new MemoryCommand();
cmd->operation = 0;
cmd->magic = COMMAND_MAGIC;
cmd->data1 = (uintptr_t)&read;
cmd->data2 = (uintptr_t)&value;
cmd->size = sizeof(uintptr_t);
SendCommand(cmd);
return (read == 123);
}
void MemCopy(uintptr_t destination, uintptr_t source, int size)
{
MemoryCommand* cmd = new MemoryCommand();
cmd->operation = 0;
cmd->magic = COMMAND_MAGIC;
cmd->data1 = destination;
cmd->data2 = source;
cmd->size = size;
SendCommand(cmd);
}
// there is no way for us to check if it succeeed to it's yolooo
void ReadMemory(uint64_t address, void* buffer, uint64_t size)
{
MemCopy(reinterpret_cast<uint64_t>(buffer), address, size);
}
void WriteMemory(uint64_t address, void* buffer, uint64_t size)
{
MemCopy(address, reinterpret_cast<uint64_t>(buffer), size);
}
}

View File

@@ -1,105 +0,0 @@
#pragma once
namespace Helper
{
uint64_t AllocatePool(nt::POOL_TYPE pool_type, uint64_t size)
{
if (!size)
return 0;
static uint64_t kernel_ExAllocatePool = 0;
if (!kernel_ExAllocatePool)
kernel_ExAllocatePool = Utils::GetKernelModuleExport(Utils::GetKernelModuleAddress("ntoskrnl.exe"), "ExAllocatePool");
uint64_t allocated_pool = 0;
if (!Utils::CallKernelFunction(&allocated_pool, kernel_ExAllocatePool, pool_type, size))
return 0;
return allocated_pool;
}
bool FreePool(uint64_t address)
{
if (!address)
return 0;
static uint64_t kernel_ExFreePool = 0;
if (!kernel_ExFreePool)
kernel_ExFreePool = Utils::GetKernelModuleExport(Utils::GetKernelModuleAddress("ntoskrnl.exe"), "ExFreePool");
return Utils::CallKernelFunction<void>(nullptr, kernel_ExFreePool, address);
}
uint64_t GetCurrentProcessKrnl()
{
static uint64_t kernel_IoGetCurrentProcess = 0;
if (!kernel_IoGetCurrentProcess)
kernel_IoGetCurrentProcess = Utils::GetKernelModuleExport(Utils::GetKernelModuleAddress("ntoskrnl.exe"), "IoGetCurrentProcess");
uint64_t peprocess = 0;
if (!Utils::CallKernelFunction<uint64_t>(&peprocess, kernel_IoGetCurrentProcess))
return 0;
return peprocess;
}
NTSTATUS LookupProcess(uint32_t pid, uintptr_t* peprocess)
{
static uint64_t kernel_PsLookupProcessByProcessId = 0;
if (!kernel_PsLookupProcessByProcessId)
kernel_PsLookupProcessByProcessId = Utils::GetKernelModuleExport(Utils::GetKernelModuleAddress("ntoskrnl.exe"), "PsLookupProcessByProcessId");
NTSTATUS status;
if (!Utils::CallKernelFunction(&status, kernel_PsLookupProcessByProcessId, pid, peprocess))
return 0;
return status;
}
uint64_t GetSectionBase(uintptr_t peprocess)
{
if (!peprocess)
return 0;
static uint64_t kernel_PsGetProcessSectionBaseAddress = 0;
if (!kernel_PsGetProcessSectionBaseAddress)
kernel_PsGetProcessSectionBaseAddress = Utils::GetKernelModuleExport(Utils::GetKernelModuleAddress("ntoskrnl.exe"), "PsGetProcessSectionBaseAddress");
uint64_t baseaddr = 0;
if (!Utils::CallKernelFunction(&baseaddr, kernel_PsGetProcessSectionBaseAddress, peprocess))
return 0;
return baseaddr;
}
NTSTATUS CopyVirtualMemory(
uintptr_t sourceprocess,
uintptr_t sourceaddress,
uintptr_t destinationprocess,
uintptr_t destinationaddress,
SIZE_T size,
uint8_t mode,
PSIZE_T returnsize)
{
static uint64_t kernel_MmCopyVirtualMemory = 0;
if (!kernel_MmCopyVirtualMemory)
kernel_MmCopyVirtualMemory = Utils::GetKernelModuleExport(Utils::GetKernelModuleAddress("ntoskrnl.exe"), "MmCopyVirtualMemory");
NTSTATUS status;
if (!Utils::CallKernelFunction(&status, kernel_MmCopyVirtualMemory, sourceprocess, sourceaddress, destinationprocess, destinationaddress, size, mode, returnsize))
return 0;
return status;
}
}

View File

@@ -1,215 +0,0 @@
#pragma once
namespace Utils
{
uint32_t Find(const wchar_t* proc)
{
auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
auto pe = PROCESSENTRY32{ sizeof(PROCESSENTRY32) };
if (Process32First(snapshot, &pe)) {
do {
if (wcscmp(proc, pe.szExeFile) == 0) {
CloseHandle(snapshot);
return pe.th32ProcessID;
}
} while (Process32Next(snapshot, &pe));
}
CloseHandle(snapshot);
return 0;
}
uint64_t 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;
}
uint64_t GetKernelModuleExport(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 };
Driver::ReadMemory(kernel_module_base, &dos_header, sizeof(dos_header));
if (dos_header.e_magic != IMAGE_DOS_SIGNATURE)
return 0;
Driver::ReadMemory(kernel_module_base + dos_header.e_lfanew, &nt_headers, sizeof(nt_headers));
if (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));
Driver::ReadMemory(kernel_module_base + export_base, export_data, export_base_size);
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 GetNtGdiDdDDIReclaimAllocations2KernelInfo(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(GetKernelModuleAddress("win32kbase.sys"), "NtGdiDdDDIReclaimAllocations2");
if (!kernel_NtGdiDdDDIReclaimAllocations2)
{
return false;
}
const uint64_t kernel_function_ptr_offset_address = kernel_NtGdiDdDDIReclaimAllocations2 + 0x7;
int32_t function_ptr_offset = 0; // offset is a SIGNED integer
Driver::ReadMemory(kernel_function_ptr_offset_address, &function_ptr_offset, sizeof(function_ptr_offset));
kernel_function_ptr = kernel_NtGdiDdDDIReclaimAllocations2 + 0xB + function_ptr_offset;
Driver::ReadMemory(kernel_function_ptr, &kernel_original_function_address, sizeof(kernel_original_function_address));
}
*out_kernel_function_ptr = kernel_function_ptr;
*out_kernel_original_function_address = kernel_original_function_address;
return true;
}
template<typename T, typename ...A>
bool CallKernelFunction(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(LoadLibraryA("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(&kernel_function_ptr, &kernel_original_function_address))
return false;
// Overwrite the pointer with kernel_function_address
Driver::WriteMemory(kernel_function_ptr, &kernel_function_address, sizeof(kernel_function_address));
// 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
Driver::WriteMemory(kernel_function_ptr, &kernel_original_function_address, sizeof(kernel_original_function_address));
return true;
}
}

View File

@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2019
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kdmapper", "kdmapper\kdmapper.vcxproj", "{518E0636-BA8F-459D-ACAC-81BD33475E3E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{518E0636-BA8F-459D-ACAC-81BD33475E3E}.Debug|x64.ActiveCfg = Debug|x64
{518E0636-BA8F-459D-ACAC-81BD33475E3E}.Debug|x64.Build.0 = Debug|x64
{518E0636-BA8F-459D-ACAC-81BD33475E3E}.Debug|x86.ActiveCfg = Debug|Win32
{518E0636-BA8F-459D-ACAC-81BD33475E3E}.Debug|x86.Build.0 = Debug|Win32
{518E0636-BA8F-459D-ACAC-81BD33475E3E}.Release|x64.ActiveCfg = Release|x64
{518E0636-BA8F-459D-ACAC-81BD33475E3E}.Release|x64.Build.0 = Release|x64
{518E0636-BA8F-459D-ACAC-81BD33475E3E}.Release|x86.ActiveCfg = Release|Win32
{518E0636-BA8F-459D-ACAC-81BD33475E3E}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {83D5D338-2A6D-49D5-B1DF-BDD34FB5CC9F}
EndGlobalSection
EndGlobal

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

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -19,10 +19,9 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{73BB66C2-5447-4DA2-8790-E9CE90AF6821}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>client</RootNamespace>
<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" />
@@ -30,20 +29,20 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<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>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
@@ -51,7 +50,8 @@
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -71,93 +71,69 @@
<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)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)build\bin\</OutDir>
<IntDir>$(SolutionDir)build\int\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<TreatWarningAsError>false</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<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>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<TreatWarningAsError>true</TreatWarningAsError>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="client.cpp" />
<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="driver.h" />
<ClInclude Include="helper.h" />
<ClInclude Include="nt.h" />
<ClInclude Include="utils.h" />
<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">

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

@@ -1,7 +1,6 @@
#pragma once
#include <Windows.h>
#include <winternl.h>
#include <Tlhelp32.h>
#pragma comment(lib, "ntdll.lib")
namespace nt
@@ -12,7 +11,7 @@ namespace nt
constexpr auto SystemModuleInformation = 11;
constexpr auto SystemHandleInformation = 16;
constexpr auto SystemExtendedHandleInformation = 64;
typedef struct _SYSTEM_HANDLE
{
PVOID Object;
@@ -23,14 +22,14 @@ namespace nt
USHORT ObjectTypeIndex;
ULONG HandleAttributes;
ULONG Reserved;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;
} 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;
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
typedef enum _POOL_TYPE {
NonPagedPool,
@@ -70,37 +69,37 @@ namespace nt
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
} 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;
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
extern "C"
extern "C"
{
NTSYSAPI
NTSTATUS
NTAPI
RtlAdjustPrivilege(
_In_ ULONG Privilege,
_In_ BOOLEAN Enable,
_In_ BOOLEAN Client,
_Out_ PBOOLEAN WasEnabled
);
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
);
}
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);
}