1
0
mirror of https://github.com/momo5502/hypervisor.git synced 2025-09-04 16:07:25 +00:00

Extract into library

This commit is contained in:
Maurice Heumann
2022-12-27 16:27:33 +01:00
parent f8f636a829
commit 28dd94f2ef
31 changed files with 279 additions and 237 deletions

View File

@@ -6,15 +6,14 @@ add_executable(runner #WIN32
${runner_headers}
)
target_precompile_headers(runner
PRIVATE std_include.hpp
target_precompile_headers(runner PRIVATE
std_include.hpp
)
set_property(TARGET runner APPEND_STRING PROPERTY LINK_FLAGS " /MANIFESTUAC:\"level='requireAdministrator'\"")
target_link_libraries(runner
shared
driver_file
target_link_libraries(runner PRIVATE
library
)
set_source_files_properties(resource.rc PROPERTIES LANGUAGE RC)

View File

@@ -1,46 +0,0 @@
#include "std_include.hpp"
#include "driver.hpp"
driver::driver(const std::filesystem::path& driver_file, const std::string& service_name)
{
this->manager_ = OpenSCManagerA(nullptr, nullptr, SC_MANAGER_ALL_ACCESS);
if (!this->manager_)
{
throw std::runtime_error("Unable to open SC manager");
}
this->service_ = OpenServiceA(this->manager_, service_name.data(), SERVICE_ALL_ACCESS);
if (!this->service_)
{
this->service_ = CreateServiceA(this->manager_, service_name.data(),
service_name.data(), SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
driver_file.generic_string().data(), nullptr, nullptr,
nullptr, nullptr, nullptr);
}
if (!this->service_)
{
this->service_ = OpenServiceA(this->manager_, service_name.data(), SERVICE_ALL_ACCESS);
}
if (!this->service_)
{
this->manager_ = {};
throw std::runtime_error("Unable to create service");
}
StartServiceA(this->service_, 0, nullptr);
}
driver::~driver()
{
if (this->service_)
{
SERVICE_STATUS status{};
ControlService(this->service_, SERVICE_CONTROL_STOP, &status);
DeleteService(this->service_);
}
}

View File

@@ -1,19 +0,0 @@
#pragma once
#include "service_handle.hpp"
class driver
{
public:
driver(const std::filesystem::path& driver_file, const std::string& service_name);
~driver();
driver(const driver&) = delete;
driver& operator=(const driver&) = delete;
driver(driver&& obj) noexcept = default;;
driver& operator=(driver&& obj) noexcept = default;
private:
service_handle manager_{};
service_handle service_{};
};

View File

@@ -1,59 +0,0 @@
#include "std_include.hpp"
#include "driver_device.hpp"
driver_device::driver_device(const std::string& driver_device)
{
this->device_ = CreateFileA(driver_device.data(),
GENERIC_READ | GENERIC_WRITE,
NULL,
nullptr,
OPEN_EXISTING,
NULL,
nullptr);
if (!this->device_)
{
throw std::runtime_error("Unable to access device");
}
}
bool driver_device::send(const DWORD ioctl_code, const data& input) const
{
data output{};
return this->send(ioctl_code, input, output);
}
bool driver_device::send(const DWORD ioctl_code, const data& input, data& output) const
{
size_t out_len = output.size();
if (this->send(ioctl_code, input.data(), input.size(), output.data(), &out_len))
{
output.resize(out_len);
return true;
}
return false;
}
bool driver_device::send(const DWORD ioctl_code, const void* input, const size_t input_length, void* output,
size_t* output_length) const
{
DWORD size_returned = 0;
const auto success = DeviceIoControl(this->device_,
ioctl_code,
const_cast<void*>(input),
static_cast<DWORD>(input_length),
output,
static_cast<DWORD>(*output_length),
&size_returned,
nullptr
) != FALSE;
*output_length = 0;
if (success)
{
*output_length = size_returned;
}
return success;
}

View File

@@ -1,23 +0,0 @@
#pragma once
#include "native_handle.hpp"
class driver_device
{
public:
driver_device(const std::string& driver_device);
~driver_device() = default;
driver_device(const driver_device&) = delete;
driver_device& operator=(const driver_device&) = delete;
driver_device(driver_device&& obj) noexcept = default;
driver_device& operator=(driver_device&& obj) noexcept = default;
using data = std::vector<uint8_t>;
bool send(DWORD ioctl_code, const data& input) const;
bool send(DWORD ioctl_code, const data& input, data& output) const;
bool send(DWORD ioctl_code, const void* input, size_t input_length, void* output, size_t* output_length) const;
private:
native_handle device_{};
};

View File

@@ -1,55 +0,0 @@
#pragma once
#include <type_traits>
#include <utility>
namespace utils
{
/*
* Copied from here: https://github.com/microsoft/GSL/blob/e0880931ae5885eb988d1a8a57acf8bc2b8dacda/include/gsl/util#L57
*/
template <class F>
class final_action
{
public:
static_assert(!std::is_reference<F>::value && !std::is_const<F>::value &&
!std::is_volatile<F>::value,
"Final_action should store its callable by value");
explicit final_action(F f) noexcept : f_(std::move(f))
{
}
final_action(final_action&& other) noexcept
: f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false))
{
}
final_action(const final_action&) = delete;
final_action& operator=(const final_action&) = delete;
final_action& operator=(final_action&&) = delete;
~final_action() noexcept
{
if (invoke_) f_();
}
// Added by momo5502
void cancel()
{
invoke_ = false;
}
private:
F f_;
bool invoke_{true};
};
template <class F>
final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>
finally(F&& f) noexcept
{
return final_action<typename std::remove_cv<typename std::remove_reference<F>::type>::type>(
std::forward<F>(f));
}
}

View File

@@ -1,110 +1,28 @@
#include "std_include.hpp"
#include <iostream>
#include <filesystem>
#include <conio.h>
#include <fstream>
#include <set>
#include "driver.hpp"
#include "driver_device.hpp"
#include "process.hpp"
#include <irp_data.hpp>
#include "resource.hpp"
#include "utils/io.hpp"
#include "utils/nt.hpp"
#pragma comment(lib, "Shlwapi.lib")
extern "C" __declspec(dllimport)
int hyperhook_write(unsigned int process_id, unsigned long long address, const void* data,
unsigned long long size);
void patch_data(const driver_device& driver_device, const uint32_t pid, const uint64_t addr, const uint8_t* buffer,
bool patch_data(const uint32_t process_id, const uint64_t address, const void* buffer,
const size_t length)
{
hook_request hook_request{};
hook_request.process_id = pid;
hook_request.target_address = reinterpret_cast<void*>(addr);
hook_request.source_data = buffer;
hook_request.source_data_size = length;
driver_device::data input{};
input.assign(reinterpret_cast<uint8_t*>(&hook_request),
reinterpret_cast<uint8_t*>(&hook_request) + sizeof(hook_request));
(void)driver_device.send(HOOK_DRV_IOCTL, input);
return hyperhook_write(process_id, address, buffer, length) != 0;
}
void insert_nop(const driver_device& driver_device, const uint32_t pid, const uint64_t addr, const size_t length)
bool insert_nop(const uint32_t process_id, const uint64_t address, const size_t length)
{
std::vector<uint8_t> buffer{};
buffer.resize(length);
memset(buffer.data(), 0x90, buffer.size());
patch_data(driver_device, pid, addr, buffer.data(), buffer.size());
}
void remove_hooks(const driver_device& driver_device)
{
(void)driver_device.send(UNHOOK_DRV_IOCTL, driver_device::data{});
}
std::vector<uint8_t> load_resource(const int id)
{
auto* const res = FindResource(GetModuleHandleA(nullptr), MAKEINTRESOURCE(id), RT_RCDATA);
if (!res) return {};
auto* const handle = LoadResource(nullptr, res);
if (!handle) return {};
const auto* data_ptr = static_cast<uint8_t*>(LockResource(handle));
const auto data_size = SizeofResource(nullptr, res);
std::vector<uint8_t> data{};
data.assign(data_ptr, data_ptr + data_size);
return data;
}
std::filesystem::path extract_driver()
{
const auto data = load_resource(DRIVER_BINARY);
auto driver_file = std::filesystem::temp_directory_path() / "driver.sys";
std::ofstream out_file{};
out_file.open(driver_file.generic_string(), std::ios::out | std::ios::binary);
out_file.write(reinterpret_cast<const char*>(data.data()), static_cast<std::streamsize>(data.size()));
out_file.close();
return driver_file;
}
std::vector<std::pair<size_t, size_t>> find_executable_regions(const std::string& pe_file)
{
std::string data{};
if (!utils::io::read_file(pe_file, &data))
{
return {};
}
const utils::nt::library library(reinterpret_cast<HMODULE>(data.data()));
if (!library.is_valid())
{
return {};
}
const auto section_headers = library.get_section_headers();
std::vector<std::pair<size_t, size_t>> regions{};
for (const auto& section_header : section_headers)
{
if (section_header->Characteristics & IMAGE_SCN_MEM_EXECUTE)
{
regions.emplace_back(section_header->VirtualAddress, section_header->Misc.VirtualSize);
}
}
return regions;
return patch_data(process_id, address, buffer.data(), buffer.size());
}
uint32_t get_process_id()
@@ -116,152 +34,50 @@ uint32_t get_process_id()
return atoi(pid_str.data());
}
void watch_regions(const driver_device& driver_device, const uint32_t pid, const HMODULE module,
const std::vector<std::pair<size_t, size_t>>& regions)
void activate_patches(const uint32_t pid)
{
std::vector<watch_region> watch_regions{};
watch_regions.reserve(regions.size());
for (const auto& region : regions)
{
watch_region watch_region{};
watch_region.virtual_address = reinterpret_cast<uint8_t*>(module) + region.first;
watch_region.length = region.second;
watch_regions.push_back(watch_region);
}
watch_request request{};
request.process_id = pid;
request.watch_regions = watch_regions.data();
request.watch_region_count = watch_regions.size();
driver_device::data out{};
size_t out_len = 0;
driver_device.send(WATCH_DRV_IOCTL, &request, sizeof(request), out.data(), &out_len);
}
std::vector<uint64_t> query_records(const driver_device& driver_device, const size_t current_size = 0)
{
std::vector<uint64_t> result{};
result.resize(std::max(size_t(1024), current_size * 2));
while (true)
{
char in[1];
constexpr auto element_len = sizeof(decltype(result)::value_type);
const size_t initial_len = result.size() * element_len;
size_t out_len = initial_len;
if (!driver_device.send(GET_RECORDS_DRV_IOCTL, in, 0, result.data(), &out_len))
{
return {};
}
//if (out_len <= initial_len)
if (result.back() == 0)
{
//result.resize(out_len / element_len);
break;
}
//result.resize((out_len / element_len) + 10);
//const auto new_size = result.size() * 2;
result = {};
result.resize(result.size() * 2);
}
// Shrink
size_t i;
for (i = result.size(); i > 0; --i)
{
if (result[i - 1] != 0)
{
break;
}
}
result.resize(i);
return result;
}
void report_records(const std::atomic_bool& flag, const driver_device& driver_device, const uint32_t pid,
const HMODULE target_module, const std::vector<std::pair<size_t, size_t>>& regions)
{
std::set<uint64_t> access_addresses{};
int i = 0;
while (!flag)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
const auto new_records = query_records(driver_device, access_addresses.size());
for (const auto& new_record : new_records)
{
if (access_addresses.emplace(new_record).second)
{
printf("%p\n", reinterpret_cast<void*>(new_record));
}
}
if ((++i) % 5 == 0)
{
watch_regions(driver_device, pid, target_module, regions);
}
}
}
void unsafe_main(const int /*argc*/, char* /*argv*/[])
{
const auto driver_file = extract_driver();
driver driver{driver_file, "HyperHook"};
const driver_device driver_device{R"(\\.\HyperHook)"};
const auto pid = get_process_id();
printf("Opening process...\n");
auto proc = process::open(pid, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ);
if (!proc)
{
printf("Failed to open process...\n");
return;
}
// IW5
insert_nop(driver_device, pid, 0x4488A8, 2); // Force calling CG_DrawFriendOrFoeTargetBoxes
insert_nop(driver_device, pid, 0x47F6C7, 2); // Ignore blind-eye perks
insert_nop(pid, 0x4488A8, 2); // Force calling CG_DrawFriendOrFoeTargetBoxes
insert_nop(pid, 0x47F6C7, 2); // Ignore blind-eye perks
//insert_nop(driver_device, pid, 0x44894C, 2); // Miniconsole
// Always full alpha
constexpr uint8_t data1[] = {0xD9, 0xE8, 0xC3};
patch_data(driver_device, pid, 0x47F0D0, data1, sizeof(data1));
patch_data(pid, 0x47F0D0, data1, sizeof(data1));
// Compass show enemies
constexpr uint8_t data2[] = {0xEB, 0x13};
patch_data(driver_device, pid, 0x4437A8, data2, sizeof(data2));
patch_data(pid, 0x4437A8, data2, sizeof(data2));
// Enemy arrows
constexpr uint8_t data3[] = {0xEB};
patch_data(driver_device, pid, 0x443A2A, data3, sizeof(data3));
patch_data(driver_device, pid, 0x443978, data3, sizeof(data3));
patch_data(pid, 0x443A2A, data3, sizeof(data3));
patch_data(pid, 0x443978, data3, sizeof(data3));
}
printf("Press any key to disable all hooks!\n");
(void)_getch();
int safe_main(const int /*argc*/, char* /*argv*/[])
{
const auto pid = get_process_id();
remove_hooks(driver_device);
while (true)
{
activate_patches(pid);
printf("Press any key to exit!\n");
(void)_getch();
printf("Press any key to exit!\n");
if (_getch() != 'r')
{
break;
}
}
return 0;
}
int main(const int argc, char* argv[])
{
try
{
unsafe_main(argc, argv);
return 0;
return safe_main(argc, argv);
}
catch (std::exception& e)
{

View File

@@ -1,49 +0,0 @@
#include "std_include.hpp"
#include "native_handle.hpp"
native_handle::native_handle()
: native_handle(INVALID_HANDLE_VALUE)
{
}
native_handle::native_handle(const HANDLE handle)
: handle_{handle}
{
}
native_handle::~native_handle()
{
if (this->operator bool())
{
CloseHandle(this->handle_);
this->handle_ = INVALID_HANDLE_VALUE;
}
}
native_handle::native_handle(native_handle&& obj) noexcept
: native_handle()
{
this->operator=(std::move(obj));
}
native_handle& native_handle::operator=(native_handle&& obj) noexcept
{
if (this != &obj)
{
this->~native_handle();
this->handle_ = obj.handle_;
obj.handle_ = INVALID_HANDLE_VALUE;
}
return *this;
}
native_handle::operator HANDLE() const
{
return this->handle_;
}
native_handle::operator bool() const
{
return this->handle_ != INVALID_HANDLE_VALUE;
}

View File

@@ -1,21 +0,0 @@
#pragma once
class native_handle
{
public:
native_handle();
native_handle(HANDLE handle);
~native_handle();
native_handle(const native_handle&) = delete;
native_handle& operator=(const native_handle&) = delete;
native_handle(native_handle&& obj) noexcept;
native_handle& operator=(native_handle&& obj) noexcept;
operator HANDLE() const;
operator bool() const;
private:
HANDLE handle_{INVALID_HANDLE_VALUE};
};

View File

@@ -1,81 +0,0 @@
#include "std_include.hpp"
#include "process.hpp"
namespace process
{
native_handle open(const uint32_t process_id, const DWORD access)
{
const auto handle = ::OpenProcess(access, FALSE, process_id);
if (handle)
{
return {handle};
}
return {};
}
std::vector<HMODULE> get_modules(const native_handle& process)
{
if (!process)
{
return {};
}
DWORD needed = 1024;
std::vector<HMODULE> result{};
do
{
result.resize(needed);
if (!EnumProcessModulesEx(process, result.data(), static_cast<DWORD>(result.size()), &needed,
LIST_MODULES_ALL))
{
return {};
}
}
while (needed > result.size());
result.resize(needed);
// Remove duplicates
std::ranges::sort(result);
const auto last = std::ranges::unique(result).begin();
result.erase(last, result.end());
// Remove nullptr
for (auto i = result.begin(); i != result.end();)
{
if (*i == nullptr)
{
i = result.erase(i);
break;
}
else
{
++i;
}
}
return result;
}
std::string get_module_filename(const native_handle& process, const HMODULE module)
{
if (!process)
{
return {};
}
std::string buffer{};
buffer.resize(1024);
const auto length = GetModuleFileNameExA(process, module, &buffer[0], static_cast<DWORD>(buffer.size()));
if (length > 0)
{
buffer.resize(length);
return buffer;
}
return {};
}
}

View File

@@ -1,9 +0,0 @@
#pragma once
#include "native_handle.hpp"
namespace process
{
native_handle open(uint32_t process_id, DWORD access);
std::vector<HMODULE> get_modules(const native_handle& process);
std::string get_module_filename(const native_handle& process, HMODULE module);
}

View File

@@ -1,3 +1 @@
#pragma once
#define DRIVER_BINARY 300

View File

@@ -9,7 +9,6 @@
//
#include "windows.h"
#include "resource.hpp"
#include <driver_file.h>
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@@ -63,12 +62,12 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "momo5502"
VALUE "FileDescription", "Open-IW5"
VALUE "FileDescription", "HyperHook Runner"
VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", "Open-IW5"
VALUE "InternalName", "HyperHook Runner"
VALUE "LegalCopyright", "All rights reserved."
VALUE "OriginalFilename", "open-iw5.exe"
VALUE "ProductName", "open-iw5"
VALUE "OriginalFilename", "hyperhook.exe"
VALUE "ProductName", "hyperhook"
VALUE "ProductVersion", "1.0.0.0"
END
END
@@ -84,7 +83,6 @@ END
//
102 ICON "resources/icon.ico"
DRIVER_BINARY RCDATA DRIVER_FILE

View File

@@ -1,44 +0,0 @@
#include "std_include.hpp"
#include "service_handle.hpp"
service_handle::service_handle()
: service_handle(nullptr)
{
}
service_handle::service_handle(const SC_HANDLE handle)
: handle_{handle}
{
}
service_handle::~service_handle()
{
if (this->handle_)
{
CloseServiceHandle(this->handle_);
this->handle_ = nullptr;
}
}
service_handle::service_handle(service_handle&& obj) noexcept
: service_handle()
{
this->operator=(std::move(obj));
}
service_handle& service_handle::operator=(service_handle&& obj) noexcept
{
if (this != &obj)
{
this->~service_handle();
this->handle_ = obj.handle_;
obj.handle_ = nullptr;
}
return *this;
}
service_handle::operator SC_HANDLE() const
{
return this->handle_;
}

View File

@@ -1,20 +0,0 @@
#pragma once
class service_handle
{
public:
service_handle();
service_handle(SC_HANDLE handle);
~service_handle();
service_handle(const service_handle&) = delete;
service_handle& operator=(const service_handle&) = delete;
service_handle(service_handle&& obj) noexcept;
service_handle& operator=(service_handle&& obj) noexcept;
operator SC_HANDLE() const;
private:
SC_HANDLE handle_{nullptr};
};

View File

@@ -1,125 +0,0 @@
#include "io.hpp"
#include "nt.hpp"
#include <fstream>
namespace utils::io
{
bool remove_file(const std::string& file)
{
return DeleteFileA(file.data()) == TRUE;
}
bool move_file(const std::string& src, const std::string& target)
{
return MoveFileA(src.data(), target.data()) == TRUE;
}
bool file_exists(const std::string& file)
{
return std::ifstream(file).good();
}
bool write_file(const std::string& file, const std::string& data, const bool append)
{
const auto pos = file.find_last_of("/\\");
if (pos != std::string::npos)
{
create_directory(file.substr(0, pos));
}
std::ofstream stream(
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : 0));
if (stream.is_open())
{
stream.write(data.data(), data.size());
stream.close();
return true;
}
return false;
}
std::string read_file(const std::string& file)
{
std::string data;
read_file(file, &data);
return data;
}
bool read_file(const std::string& file, std::string* data)
{
if (!data) return false;
data->clear();
if (file_exists(file))
{
std::ifstream stream(file, std::ios::binary);
if (!stream.is_open()) return false;
stream.seekg(0, std::ios::end);
const std::streamsize size = stream.tellg();
stream.seekg(0, std::ios::beg);
if (size > -1)
{
data->resize(static_cast<uint32_t>(size));
stream.read(const_cast<char*>(data->data()), size);
stream.close();
return true;
}
}
return false;
}
size_t file_size(const std::string& file)
{
if (file_exists(file))
{
std::ifstream stream(file, std::ios::binary);
if (stream.good())
{
stream.seekg(0, std::ios::end);
return static_cast<size_t>(stream.tellg());
}
}
return 0;
}
bool create_directory(const std::string& directory)
{
return std::filesystem::create_directories(directory);
}
bool directory_exists(const std::string& directory)
{
return std::filesystem::is_directory(directory);
}
bool directory_is_empty(const std::string& directory)
{
return std::filesystem::is_empty(directory);
}
std::vector<std::string> list_files(const std::string& directory)
{
std::vector<std::string> files;
for (auto& file : std::filesystem::directory_iterator(directory))
{
files.push_back(file.path().generic_string());
}
return files;
}
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target)
{
std::filesystem::copy(src, target,
std::filesystem::copy_options::overwrite_existing |
std::filesystem::copy_options::recursive);
}
}

View File

@@ -1,21 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include <filesystem>
namespace utils::io
{
bool remove_file(const std::string& file);
bool move_file(const std::string& src, const std::string& target);
bool file_exists(const std::string& file);
bool write_file(const std::string& file, const std::string& data, bool append = false);
bool read_file(const std::string& file, std::string* data);
std::string read_file(const std::string& file);
size_t file_size(const std::string& file);
bool create_directory(const std::string& directory);
bool directory_exists(const std::string& directory);
bool directory_is_empty(const std::string& directory);
std::vector<std::string> list_files(const std::string& directory);
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target);
}

View File

@@ -1,254 +0,0 @@
#include "nt.hpp"
namespace utils::nt
{
library library::load(const std::string& name)
{
return library(LoadLibraryA(name.data()));
}
library library::load(const std::filesystem::path& path)
{
return library::load(path.generic_string());
}
library library::get_by_address(void* address)
{
HMODULE handle = nullptr;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, static_cast<LPCSTR>(address), &handle);
return library(handle);
}
library::library()
{
this->module_ = GetModuleHandleA(nullptr);
}
library::library(const std::string& name)
{
this->module_ = GetModuleHandleA(name.data());
}
library::library(const HMODULE handle)
{
this->module_ = handle;
}
bool library::operator==(const library& obj) const
{
return this->module_ == obj.module_;
}
library::operator bool() const
{
return this->is_valid();
}
library::operator HMODULE() const
{
return this->get_handle();
}
PIMAGE_NT_HEADERS library::get_nt_headers() const
{
if (!this->is_valid()) return nullptr;
return reinterpret_cast<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
}
PIMAGE_DOS_HEADER library::get_dos_header() const
{
return reinterpret_cast<PIMAGE_DOS_HEADER>(this->get_ptr());
}
PIMAGE_OPTIONAL_HEADER library::get_optional_header() const
{
if (!this->is_valid()) return nullptr;
return &this->get_nt_headers()->OptionalHeader;
}
std::vector<PIMAGE_SECTION_HEADER> library::get_section_headers() const
{
std::vector<PIMAGE_SECTION_HEADER> headers;
auto nt_headers = this->get_nt_headers();
auto section = IMAGE_FIRST_SECTION(nt_headers);
for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section)
{
if (section) headers.push_back(section);
else OutputDebugStringA("There was an invalid section :O");
}
return headers;
}
std::uint8_t* library::get_ptr() const
{
return reinterpret_cast<std::uint8_t*>(this->module_);
}
void library::unprotect() const
{
if (!this->is_valid()) return;
DWORD protection;
VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE,
&protection);
}
size_t library::get_relative_entry_point() const
{
if (!this->is_valid()) return 0;
return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint;
}
void* library::get_entry_point() const
{
if (!this->is_valid()) return nullptr;
return this->get_ptr() + this->get_relative_entry_point();
}
bool library::is_valid() const
{
return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE;
}
std::string library::get_name() const
{
if (!this->is_valid()) return "";
auto path = this->get_path();
const auto pos = path.find_last_of("/\\");
if (pos == std::string::npos) return path;
return path.substr(pos + 1);
}
std::string library::get_path() const
{
if (!this->is_valid()) return "";
char name[MAX_PATH] = {0};
GetModuleFileNameA(this->module_, name, sizeof name);
return name;
}
std::string library::get_folder() const
{
if (!this->is_valid()) return "";
const auto path = std::filesystem::path(this->get_path());
return path.parent_path().generic_string();
}
void library::free()
{
if (this->is_valid())
{
FreeLibrary(this->module_);
this->module_ = nullptr;
}
}
HMODULE library::get_handle() const
{
return this->module_;
}
void** library::get_iat_entry(const std::string& module_name, const std::string& proc_name) const
{
if (!this->is_valid()) return nullptr;
const library other_module(module_name);
if (!other_module.is_valid()) return nullptr;
auto* const target_function = other_module.get_proc<void*>(proc_name);
if (!target_function) return nullptr;
auto* header = this->get_optional_header();
if (!header) return nullptr;
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (import_descriptor->Name)
{
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data()))
{
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->
OriginalFirstThunk + this->get_ptr());
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->FirstThunk + this->
get_ptr());
while (original_thunk_data->u1.AddressOfData)
{
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
if (ordinal_number > 0xFFFF) continue;
if (GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number)) ==
target_function)
{
return reinterpret_cast<void**>(&thunk_data->u1.Function);
}
++original_thunk_data;
++thunk_data;
}
//break;
}
++import_descriptor;
}
return nullptr;
}
void raise_hard_exception()
{
int data = false;
const library ntdll("ntdll.dll");
ntdll.invoke_pascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
}
std::string load_resource(const int id)
{
auto* const res = FindResource(library(), MAKEINTRESOURCE(id), RT_RCDATA);
if (!res) return {};
auto* const handle = LoadResource(nullptr, res);
if (!handle) return {};
return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res));
}
void relaunch_self()
{
const utils::nt::library self;
STARTUPINFOA startup_info;
PROCESS_INFORMATION process_info;
ZeroMemory(&startup_info, sizeof(startup_info));
ZeroMemory(&process_info, sizeof(process_info));
startup_info.cb = sizeof(startup_info);
char current_dir[MAX_PATH];
GetCurrentDirectoryA(sizeof(current_dir), current_dir);
auto* const command_line = GetCommandLineA();
CreateProcessA(self.get_path().data(), command_line, nullptr, nullptr, false, NULL, nullptr, current_dir,
&startup_info, &process_info);
if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread);
if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) CloseHandle(process_info.hProcess);
}
void terminate(const uint32_t code)
{
TerminateProcess(GetCurrentProcess(), code);
}
}

View File

@@ -1,105 +0,0 @@
#pragma once
#include "../std_include.hpp"
// min and max is required by gdi, therefore NOMINMAX won't work
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
namespace utils::nt
{
class library final
{
public:
static library load(const std::string& name);
static library load(const std::filesystem::path& path);
static library get_by_address(void* address);
library();
explicit library(const std::string& name);
explicit library(HMODULE handle);
library(const library& a) : module_(a.module_)
{
}
bool operator!=(const library& obj) const { return !(*this == obj); };
bool operator==(const library& obj) const;
operator bool() const;
operator HMODULE() const;
void unprotect() const;
void* get_entry_point() const;
size_t get_relative_entry_point() const;
bool is_valid() const;
std::string get_name() const;
std::string get_path() const;
std::string get_folder() const;
std::uint8_t* get_ptr() const;
void free();
HMODULE get_handle() const;
template <typename T>
T get_proc(const std::string& process) const
{
if (!this->is_valid()) T{};
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
}
template <typename T>
std::function<T> get(const std::string& process) const
{
if (!this->is_valid()) return std::function<T>();
return static_cast<T*>(this->get_proc<void*>(process));
}
template <typename T, typename... Args>
T invoke(const std::string& process, Args ... args) const
{
auto method = this->get<T(__cdecl)(Args ...)>(process);
if (method) return method(args...);
return T();
}
template <typename T, typename... Args>
T invoke_pascal(const std::string& process, Args ... args) const
{
auto method = this->get<T(__stdcall)(Args ...)>(process);
if (method) return method(args...);
return T();
}
template <typename T, typename... Args>
T invoke_this(const std::string& process, void* this_ptr, Args ... args) const
{
auto method = this->get<T(__thiscall)(void*, Args ...)>(this_ptr, process);
if (method) return method(args...);
return T();
}
std::vector<PIMAGE_SECTION_HEADER> get_section_headers() const;
PIMAGE_NT_HEADERS get_nt_headers() const;
PIMAGE_DOS_HEADER get_dos_header() const;
PIMAGE_OPTIONAL_HEADER get_optional_header() const;
void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const;
private:
HMODULE module_;
};
__declspec(noreturn) void raise_hard_exception();
std::string load_resource(int id);
void relaunch_self();
__declspec(noreturn) void terminate(uint32_t code = 0);
}