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:
@@ -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")
|
||||
@@ -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_);
|
||||
}
|
||||
}
|
||||
@@ -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_{};
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_{};
|
||||
};
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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};
|
||||
};
|
||||
@@ -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 {};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#pragma once
|
||||
@@ -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
|
||||
@@ -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_;
|
||||
}
|
||||
@@ -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};
|
||||
};
|
||||
@@ -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")
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user