1
0
mirror of https://github.com/momo5502/hypervisor.git synced 2026-07-07 00:09:58 +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
+23
View File
@@ -0,0 +1,23 @@
file(GLOB_RECURSE library_sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE library_headers CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
add_library(library SHARED
${library_sources}
${library_headers}
)
target_precompile_headers(library PRIVATE
std_include.hpp
)
target_link_libraries(library PRIVATE
shared
driver_file
)
set_source_files_properties(resource.rc PROPERTIES LANGUAGE RC)
target_sources(library PRIVATE
resource.rc
)
set_target_properties(library PROPERTIES OUTPUT_NAME "hyperhook")
+46
View File
@@ -0,0 +1,46 @@
#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_);
}
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include "service_handle.hpp"
class driver
{
public:
driver() = default;
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_{};
};
+59
View File
@@ -0,0 +1,59 @@
#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;
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "native_handle.hpp"
class driver_device
{
public:
driver_device() = default;
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;
operator bool() const
{
return this->device_;
}
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_{};
};
+55
View File
@@ -0,0 +1,55 @@
#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));
}
}
+84
View File
@@ -0,0 +1,84 @@
#include "std_include.hpp"
#include <iostream>
#include <conio.h>
#include <set>
#include "driver.hpp"
#include "driver_device.hpp"
#include <driver_file.h>
#include <irp_data.hpp>
#include "resource.hpp"
#include "utils/io.hpp"
void patch_data(const driver_device& driver_device, const uint32_t pid, const uint64_t address, const uint8_t* buffer,
const size_t length)
{
hook_request hook_request{};
hook_request.process_id = pid;
hook_request.target_address = reinterpret_cast<void*>(address);
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);
}
driver_device create_driver_device()
{
return driver_device{R"(\\.\HyperHook)"};
}
driver create_driver()
{
return driver{std::filesystem::absolute(DRIVER_NAME), "HyperHook"};
}
driver_device& get_driver_device()
{
static driver hypervisor{};
static driver_device device{};
if (device)
{
return device;
}
try
{
device = create_driver_device();
}
catch (...)
{
hypervisor = create_driver();
device = create_driver_device();
}
return device;
}
extern "C" __declspec(dllexport)
int hyperhook_write(const unsigned int process_id, const unsigned long long address, const void* data,
const unsigned long long size)
{
try
{
const auto& device = get_driver_device();
if (device)
{
patch_data(device, process_id, address, static_cast<const uint8_t*>(data), size);
return 1;
}
}
catch (const std::exception& e)
{
printf("%s\n", e.what());
}
return 0;
}
+49
View File
@@ -0,0 +1,49 @@
#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;
}
+21
View File
@@ -0,0 +1,21 @@
#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};
};
+81
View File
@@ -0,0 +1,81 @@
#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 {};
}
}
+9
View File
@@ -0,0 +1,9 @@
#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);
}
+1
View File
@@ -0,0 +1 @@
#pragma once
+95
View File
@@ -0,0 +1,95 @@
// Microsoft Visual C++ generated resource script.
//
#pragma code_page(65001)
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h"
#include "resource.hpp"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"#include ""windows.h""\r\n"
"\0"
END
2 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "momo5502"
VALUE "FileDescription", "HyperHook"
VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", "HyperHook"
VALUE "LegalCopyright", "All rights reserved."
VALUE "OriginalFilename", "hyperhook.dll"
VALUE "ProductName", "hyperhook"
VALUE "ProductVersion", "1.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+44
View File
@@ -0,0 +1,44 @@
#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_;
}
+20
View File
@@ -0,0 +1,20 @@
#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};
};
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <string>
#include <vector>
#include <mutex>
#include <filesystem>
#include <functional>
#include <Windows.h>
#include <Shlwapi.h>
#include <ShlObj.h>
#include <Psapi.h>
#pragma comment(lib, "Shlwapi.lib")
+125
View File
@@ -0,0 +1,125 @@
#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);
}
}
+21
View File
@@ -0,0 +1,21 @@
#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);
}
+254
View File
@@ -0,0 +1,254 @@
#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);
}
}
+105
View File
@@ -0,0 +1,105 @@
#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);
}