mirror of
https://github.com/diamante0018/MW3ServerFreezer.git
synced 2025-04-19 19:52:53 +00:00
Remove minhook
This commit is contained in:
parent
5f754be07a
commit
7f5643dcae
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,6 +1,3 @@
|
|||||||
[submodule "deps/minhook"]
|
|
||||||
path = deps/minhook
|
|
||||||
url = https://github.com/TsudaKageyu/minhook.git
|
|
||||||
[submodule "deps/GSL"]
|
[submodule "deps/GSL"]
|
||||||
path = deps/GSL
|
path = deps/GSL
|
||||||
url = https://github.com/microsoft/GSL.git
|
url = https://github.com/microsoft/GSL.git
|
||||||
|
1
deps/minhook
vendored
1
deps/minhook
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit 4a455528f61b5a375b1f9d44e7d296d47f18bb18
|
|
32
deps/premake/minhook.lua
vendored
32
deps/premake/minhook.lua
vendored
@ -1,32 +0,0 @@
|
|||||||
minhook = {
|
|
||||||
source = path.join(dependencies.basePath, "minhook")
|
|
||||||
}
|
|
||||||
|
|
||||||
function minhook.import()
|
|
||||||
links { "minhook" }
|
|
||||||
minhook.includes()
|
|
||||||
end
|
|
||||||
|
|
||||||
function minhook.includes()
|
|
||||||
includedirs {
|
|
||||||
path.join(minhook.source, "include")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function minhook.project()
|
|
||||||
project "minhook"
|
|
||||||
language "C"
|
|
||||||
|
|
||||||
minhook.includes()
|
|
||||||
|
|
||||||
files
|
|
||||||
{
|
|
||||||
path.join(minhook.source, "src/**.h"),
|
|
||||||
path.join(minhook.source, "src/**.c")
|
|
||||||
}
|
|
||||||
|
|
||||||
warnings "Off"
|
|
||||||
kind "StaticLib"
|
|
||||||
end
|
|
||||||
|
|
||||||
table.insert(dependencies, minhook)
|
|
@ -61,10 +61,10 @@ public:
|
|||||||
cl_EnableCheats = game::Dvar_RegisterBool(
|
cl_EnableCheats = game::Dvar_RegisterBool(
|
||||||
"cl_EnableCheats", false, game::DVAR_NONE, "Enable FoF wallhack");
|
"cl_EnableCheats", false, game::DVAR_NONE, "Enable FoF wallhack");
|
||||||
|
|
||||||
utils::hook::jump(0x430561, draw_red_box_stub);
|
utils::hook(0x430561, draw_red_box_stub, HOOK_JUMP).install()->quick();
|
||||||
utils::hook::nop(0x430566, 2);
|
utils::hook::nop(0x430566, 2);
|
||||||
|
|
||||||
utils::hook::jump(0x5AA524, blind_eye_check_stub);
|
utils::hook(0x5AA524, blind_eye_check_stub, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
add_cheat_commands();
|
add_cheat_commands();
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,9 @@ void dvar_set_from_string_by_name_stub(const char* dvar_name,
|
|||||||
class component final : public component_interface {
|
class component final : public component_interface {
|
||||||
public:
|
public:
|
||||||
void post_unpack() override {
|
void post_unpack() override {
|
||||||
utils::hook::call(0x59C0EF, dvar_set_from_string_by_name_stub);
|
utils::hook(0x59C0EF, dvar_set_from_string_by_name_stub, HOOK_CALL)
|
||||||
|
.install()
|
||||||
|
->quick();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace dvar_patches
|
} // namespace dvar_patches
|
||||||
|
@ -57,8 +57,8 @@ public:
|
|||||||
add_exploit_commands();
|
add_exploit_commands();
|
||||||
add_key_hooks();
|
add_key_hooks();
|
||||||
|
|
||||||
utils::hook::call(0x420B76, write_message_sequence);
|
utils::hook(0x420B76, write_message_sequence, HOOK_CALL).install()->quick();
|
||||||
utils::hook::call(0x420B86, write_command_sequence);
|
utils::hook(0x420B86, write_command_sequence, HOOK_CALL).install()->quick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
#include "key_catcher.hpp"
|
#include "key_catcher.hpp"
|
||||||
|
|
||||||
namespace key_catcher {
|
namespace key_catcher {
|
||||||
utils::hook::detour cl_key_event_hook;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::unordered_map<std::string, key_catcher::callback>& get_key_callbacks() {
|
std::unordered_map<std::string, key_catcher::callback>& get_key_callbacks() {
|
||||||
static std::unordered_map<std::string, key_catcher::callback> key_callbacks{};
|
static std::unordered_map<std::string, key_catcher::callback> key_callbacks{};
|
||||||
@ -37,16 +35,14 @@ void cl_key_event_stub(game::LocalClientNum_t local_client, int key_id,
|
|||||||
int a3) {
|
int a3) {
|
||||||
handle_key_event(local_client, key_id);
|
handle_key_event(local_client, key_id);
|
||||||
|
|
||||||
cl_key_event_hook.invoke<void>(local_client, key_id, a3);
|
utils::hook::invoke<void>(0x4CD840, local_client, key_id, a3);
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface {
|
class component final : public component_interface {
|
||||||
public:
|
public:
|
||||||
void post_unpack() override {
|
void post_unpack() override {
|
||||||
cl_key_event_hook.create(0x4CD840, &cl_key_event_stub);
|
utils::hook(0x53CC70, cl_key_event_stub, HOOK_CALL).install()->quick();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pre_destroy() override { cl_key_event_hook.clear(); }
|
|
||||||
};
|
};
|
||||||
} // namespace key_catcher
|
} // namespace key_catcher
|
||||||
|
|
||||||
|
@ -53,7 +53,9 @@ public:
|
|||||||
void post_unpack() override {
|
void post_unpack() override {
|
||||||
add_network_commands();
|
add_network_commands();
|
||||||
|
|
||||||
utils::hook::call(0x5B27E1, packet_interception_handler);
|
utils::hook(0x5B27E1, packet_interception_handler, HOOK_CALL)
|
||||||
|
.install()
|
||||||
|
->quick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -45,8 +45,12 @@ public:
|
|||||||
void post_start() override { remove_tekno_hooks(); }
|
void post_start() override { remove_tekno_hooks(); }
|
||||||
|
|
||||||
void post_unpack() override {
|
void post_unpack() override {
|
||||||
utils::hook::call(0x4E3D42, msg_read_bits_compress_check_sv);
|
utils::hook(0x4E3D42, msg_read_bits_compress_check_sv, HOOK_CALL)
|
||||||
utils::hook::call(0x4A9F56, msg_read_bits_compress_check_cl);
|
.install()
|
||||||
|
->quick();
|
||||||
|
utils::hook(0x4A9F56, msg_read_bits_compress_check_cl, HOOK_CALL)
|
||||||
|
.install()
|
||||||
|
->quick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -144,9 +144,9 @@ public:
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
utils::hook::call(0x4E4A0D, cl_frame_stub);
|
utils::hook(0x4E4A0D, cl_frame_stub, HOOK_CALL).install()->quick();
|
||||||
utils::hook::call(0x5B54D2, r_end_frame_stub);
|
utils::hook(0x5B54D2, r_end_frame_stub, HOOK_CALL).install()->quick();
|
||||||
utils::hook::call(0x543B0E, main_frame_stub);
|
utils::hook(0x543B0E, main_frame_stub, HOOK_CALL).install()->quick();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pre_destroy() override {
|
void pre_destroy() override {
|
||||||
|
@ -1,156 +1,166 @@
|
|||||||
#include "hook.hpp"
|
#include "hook.hpp"
|
||||||
#include "string.hpp"
|
|
||||||
|
|
||||||
#include <MinHook.h>
|
namespace utils {
|
||||||
|
void hook::signature::process() {
|
||||||
namespace utils::hook {
|
if (this->signatures_.empty())
|
||||||
namespace {
|
|
||||||
[[maybe_unused]] class _ {
|
|
||||||
public:
|
|
||||||
_() {
|
|
||||||
if (MH_Initialize() != MH_OK) {
|
|
||||||
throw std::runtime_error("Failed to initialize MinHook");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~_() { MH_Uninitialize(); }
|
|
||||||
} __;
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
detour::detour(const size_t place, void* target)
|
|
||||||
: detour(reinterpret_cast<void*>(place), target) {}
|
|
||||||
|
|
||||||
detour::detour(void* place, void* target) { this->create(place, target); }
|
|
||||||
|
|
||||||
detour::~detour() { this->clear(); }
|
|
||||||
|
|
||||||
void detour::enable() const { MH_EnableHook(this->place_); }
|
|
||||||
|
|
||||||
void detour::disable() const { MH_DisableHook(this->place_); }
|
|
||||||
|
|
||||||
void detour::create(void* place, void* target) {
|
|
||||||
this->clear();
|
|
||||||
this->place_ = place;
|
|
||||||
|
|
||||||
if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
string::va("Unable to create hook at location: %p", this->place_));
|
|
||||||
}
|
|
||||||
|
|
||||||
this->enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
void detour::create(const size_t place, void* target) {
|
|
||||||
this->create(reinterpret_cast<void*>(place), target);
|
|
||||||
}
|
|
||||||
|
|
||||||
void detour::clear() {
|
|
||||||
if (this->place_) {
|
|
||||||
MH_RemoveHook(this->place_);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->place_ = nullptr;
|
|
||||||
this->original_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* detour::get_original() const { return this->original_; }
|
|
||||||
|
|
||||||
void nop(void* place, const size_t length) {
|
|
||||||
DWORD old_protect{};
|
|
||||||
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
|
||||||
|
|
||||||
std::memset(place, 0x90, length);
|
|
||||||
|
|
||||||
VirtualProtect(place, length, old_protect, &old_protect);
|
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nop(const size_t place, const size_t length) {
|
|
||||||
nop(reinterpret_cast<void*>(place), length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy(void* place, const void* data, const size_t length) {
|
|
||||||
DWORD old_protect{};
|
|
||||||
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
|
||||||
|
|
||||||
std::memmove(place, data, length);
|
|
||||||
|
|
||||||
VirtualProtect(place, length, old_protect, &old_protect);
|
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy(const size_t place, const void* data, const size_t length) {
|
|
||||||
copy(reinterpret_cast<void*>(place), data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_relatively_far(const void* pointer, const void* data,
|
|
||||||
const int offset) {
|
|
||||||
const int64_t diff = size_t(data) - (size_t(pointer) + offset);
|
|
||||||
const auto small_diff = int32_t(diff);
|
|
||||||
return diff != int64_t(small_diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void call(void* pointer, void* data) {
|
|
||||||
if (is_relatively_far(pointer, data)) {
|
|
||||||
throw std::runtime_error("Too far away to create 32bit relative branch");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* patch_pointer = PBYTE(pointer);
|
|
||||||
set<uint8_t>(patch_pointer, 0xE8);
|
|
||||||
set<int32_t>(patch_pointer + 1,
|
|
||||||
int32_t(size_t(data) - (size_t(pointer) + 5)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void call(const size_t pointer, void* data) {
|
|
||||||
return call(reinterpret_cast<void*>(pointer), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void call(const size_t pointer, const size_t data) {
|
|
||||||
return call(pointer, reinterpret_cast<void*>(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(std::uintptr_t address, std::vector<std::uint8_t>&& bytes) {
|
|
||||||
DWORD oldProtect = 0;
|
|
||||||
|
|
||||||
auto* place = reinterpret_cast<void*>(address);
|
|
||||||
VirtualProtect(place, bytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
|
|
||||||
memcpy(place, bytes.data(), bytes.size());
|
|
||||||
VirtualProtect(place, bytes.size(), oldProtect, &oldProtect);
|
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, bytes.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(std::uintptr_t address, void* buffer, size_t size) {
|
|
||||||
DWORD oldProtect = 0;
|
|
||||||
|
|
||||||
auto* place = reinterpret_cast<void*>(address);
|
|
||||||
VirtualProtect(place, size, PAGE_EXECUTE_READWRITE, &oldProtect);
|
|
||||||
memcpy(place, buffer, size);
|
|
||||||
VirtualProtect(place, size, oldProtect, &oldProtect);
|
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void jump(std::uintptr_t address, void* destination) {
|
|
||||||
if (!address)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::uint8_t* bytes = new std::uint8_t[5];
|
const auto start = static_cast<char*>(this->start_);
|
||||||
*bytes = 0xE9;
|
|
||||||
*reinterpret_cast<std::uint32_t*>(bytes + 1) =
|
|
||||||
CalculateRelativeJMPAddress(address, destination);
|
|
||||||
|
|
||||||
set(address, bytes, 5);
|
const unsigned int sig_count = this->signatures_.size();
|
||||||
|
const auto containers = this->signatures_.data();
|
||||||
|
|
||||||
delete[] bytes;
|
for (size_t i = 0; i < this->length_; ++i) {
|
||||||
|
const auto address = start + i;
|
||||||
|
|
||||||
|
for (unsigned int k = 0; k < sig_count; ++k) {
|
||||||
|
const auto container = &containers[k];
|
||||||
|
|
||||||
|
unsigned int j;
|
||||||
|
for (j = 0; j < strlen(container->mask); ++j) {
|
||||||
|
if (container->mask[j] != '?' &&
|
||||||
|
container->signature[j] != address[j]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == strlen(container->mask)) {
|
||||||
|
container->callback(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void redirect_jump(void* pointer, void* data) {
|
void hook::signature::add(const container& container) {
|
||||||
char* operand_ptr = static_cast<char*>(pointer) + 2;
|
signatures_.push_back(container);
|
||||||
int new_operand =
|
|
||||||
reinterpret_cast<int>(data) - (reinterpret_cast<int>(pointer) + 6);
|
|
||||||
set<int>(operand_ptr, new_operand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void redirect_jump(size_t pointer, void* data) {
|
hook::~hook() {
|
||||||
redirect_jump(reinterpret_cast<void*>(pointer), data);
|
if (this->initialized_) {
|
||||||
|
this->uninstall();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace utils::hook
|
|
||||||
|
hook* hook::initialize(const DWORD place, void (*stub)(), const bool use_jump) {
|
||||||
|
return this->initialize(place, reinterpret_cast<void*>(stub), use_jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
hook* hook::initialize(const DWORD place, void* stub, const bool use_jump) {
|
||||||
|
return this->initialize(reinterpret_cast<void*>(place), stub, use_jump);
|
||||||
|
}
|
||||||
|
|
||||||
|
hook* hook::initialize(void* place, void* stub, const bool use_jump) {
|
||||||
|
if (this->initialized_)
|
||||||
|
return this;
|
||||||
|
this->initialized_ = true;
|
||||||
|
|
||||||
|
this->use_jump_ = use_jump;
|
||||||
|
this->place_ = place;
|
||||||
|
this->stub_ = stub;
|
||||||
|
|
||||||
|
this->original_ =
|
||||||
|
static_cast<char*>(this->place_) + 5 +
|
||||||
|
*reinterpret_cast<DWORD*>((static_cast<char*>(this->place_) + 1));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook* hook::install(const bool unprotect, const bool keep_unprotected) {
|
||||||
|
std::lock_guard _(this->state_mutex_);
|
||||||
|
|
||||||
|
if (!this->initialized_ || this->installed_) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->installed_ = true;
|
||||||
|
|
||||||
|
if (unprotect)
|
||||||
|
VirtualProtect(this->place_, sizeof(this->buffer_), PAGE_EXECUTE_READWRITE,
|
||||||
|
&this->protection_);
|
||||||
|
std::memcpy(this->buffer_, this->place_, sizeof(this->buffer_));
|
||||||
|
|
||||||
|
const auto code = static_cast<char*>(this->place_);
|
||||||
|
|
||||||
|
*code = static_cast<char>(this->use_jump_ ? 0xE9 : 0xE8);
|
||||||
|
|
||||||
|
*reinterpret_cast<size_t*>(code + 1) =
|
||||||
|
reinterpret_cast<size_t>(this->stub_) -
|
||||||
|
(reinterpret_cast<size_t>(this->place_) + 5);
|
||||||
|
|
||||||
|
if (unprotect && !keep_unprotected)
|
||||||
|
VirtualProtect(this->place_, sizeof(this->buffer_), this->protection_,
|
||||||
|
&this->protection_);
|
||||||
|
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), this->place_,
|
||||||
|
sizeof(this->buffer_));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hook::quick() {
|
||||||
|
if (this->installed_) {
|
||||||
|
this->installed_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hook::iat(const nt::library module, const std::string& target_module,
|
||||||
|
const std::string& process, void* stub) {
|
||||||
|
if (!module.is_valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto ptr = module.get_iat_entry(target_module, process);
|
||||||
|
if (!ptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DWORD protect;
|
||||||
|
VirtualProtect(ptr, sizeof(*ptr), PAGE_EXECUTE_READWRITE, &protect);
|
||||||
|
|
||||||
|
*ptr = stub;
|
||||||
|
|
||||||
|
VirtualProtect(ptr, sizeof(*ptr), protect, &protect);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook* hook::uninstall(const bool unprotect) {
|
||||||
|
std::lock_guard _(this->state_mutex_);
|
||||||
|
|
||||||
|
if (!this->initialized_ || !this->installed_) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->installed_ = false;
|
||||||
|
|
||||||
|
if (unprotect)
|
||||||
|
VirtualProtect(this->place_, sizeof(this->buffer_), PAGE_EXECUTE_READWRITE,
|
||||||
|
&this->protection_);
|
||||||
|
|
||||||
|
std::memcpy(this->place_, this->buffer_, sizeof(this->buffer_));
|
||||||
|
|
||||||
|
if (unprotect)
|
||||||
|
VirtualProtect(this->place_, sizeof(this->buffer_), this->protection_,
|
||||||
|
&this->protection_);
|
||||||
|
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), this->place_,
|
||||||
|
sizeof(this->buffer_));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* hook::get_address() const { return this->place_; }
|
||||||
|
|
||||||
|
void* hook::get_original() const { return this->original_; }
|
||||||
|
|
||||||
|
void hook::nop(void* place, const size_t length) {
|
||||||
|
DWORD old_protect;
|
||||||
|
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||||
|
|
||||||
|
memset(place, 0x90, length);
|
||||||
|
|
||||||
|
VirtualProtect(place, length, old_protect, &old_protect);
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), place, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hook::nop(const DWORD place, const size_t length) {
|
||||||
|
nop(reinterpret_cast<void*>(place), length);
|
||||||
|
}
|
||||||
|
} // namespace utils
|
||||||
|
@ -1,102 +1,120 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "signature.hpp"
|
#include <mutex>
|
||||||
|
#include "nt.hpp"
|
||||||
|
|
||||||
#define CalculateRelativeJMPAddress(X, Y) \
|
#define HOOK_JUMP true
|
||||||
(((std::uintptr_t)Y - (std::uintptr_t)X) - 5)
|
#define HOOK_CALL false
|
||||||
|
|
||||||
namespace utils::hook {
|
namespace utils {
|
||||||
class detour {
|
class hook final {
|
||||||
public:
|
public:
|
||||||
detour() = default;
|
class signature final {
|
||||||
detour(void* place, void* target);
|
public:
|
||||||
detour(size_t place, void* target);
|
struct container final {
|
||||||
~detour();
|
const char* signature;
|
||||||
|
const char* mask;
|
||||||
|
std::function<void(char*)> callback;
|
||||||
|
};
|
||||||
|
|
||||||
detour(detour&& other) noexcept { this->operator=(std::move(other)); }
|
signature(void* start, const size_t length)
|
||||||
|
: start_(start), length_(length) {}
|
||||||
|
|
||||||
detour& operator=(detour&& other) noexcept {
|
signature(const DWORD start, const size_t length)
|
||||||
if (this != &other) {
|
: signature(reinterpret_cast<void*>(start), length) {}
|
||||||
this->~detour();
|
|
||||||
|
|
||||||
this->place_ = other.place_;
|
signature() : signature(0x400000, 0x800000) {}
|
||||||
this->original_ = other.original_;
|
|
||||||
|
|
||||||
other.place_ = nullptr;
|
void process();
|
||||||
other.original_ = nullptr;
|
void add(const container& container);
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
private:
|
||||||
|
void* start_;
|
||||||
|
size_t length_;
|
||||||
|
std::vector<container> signatures_;
|
||||||
|
};
|
||||||
|
|
||||||
|
hook()
|
||||||
|
: initialized_(false), installed_(false), place_(nullptr), stub_(nullptr),
|
||||||
|
original_(nullptr), use_jump_(false), protection_(0) {
|
||||||
|
ZeroMemory(this->buffer_, sizeof(this->buffer_));
|
||||||
}
|
}
|
||||||
|
|
||||||
detour(const detour&) = delete;
|
hook(void* place, void* stub, const bool use_jump = true) : hook() {
|
||||||
detour& operator=(const detour&) = delete;
|
this->initialize(place, stub, use_jump);
|
||||||
|
|
||||||
void enable() const;
|
|
||||||
void disable() const;
|
|
||||||
|
|
||||||
void create(void* place, void* target);
|
|
||||||
void create(size_t place, void* target);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
template <typename T> T* get() const {
|
|
||||||
return static_cast<T*>(this->get_original());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args> T invoke(Args... args) {
|
hook(void* place, void (*stub)(), const bool use_jump = true)
|
||||||
return static_cast<T (*)(Args...)>(this->get_original())(args...);
|
: hook(place, reinterpret_cast<void*>(stub), use_jump) {}
|
||||||
|
|
||||||
|
hook(const DWORD place, void* stub, const bool use_jump = true)
|
||||||
|
: hook(reinterpret_cast<void*>(place), stub, use_jump) {}
|
||||||
|
|
||||||
|
hook(const DWORD place, const DWORD stub, const bool use_jump = true)
|
||||||
|
: hook(reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub),
|
||||||
|
use_jump) {}
|
||||||
|
|
||||||
|
hook(const DWORD place, void (*stub)(), const bool use_jump = true)
|
||||||
|
: hook(reinterpret_cast<void*>(place), reinterpret_cast<void*>(stub),
|
||||||
|
use_jump) {}
|
||||||
|
|
||||||
|
hook(const hook&) = delete;
|
||||||
|
hook(const hook&&) = delete;
|
||||||
|
|
||||||
|
~hook();
|
||||||
|
|
||||||
|
hook* initialize(void* place, void* stub, bool use_jump = true);
|
||||||
|
hook* initialize(DWORD place, void* stub, bool use_jump = true);
|
||||||
|
hook* initialize(DWORD place, void (*stub)(),
|
||||||
|
bool use_jump = true); // For lambdas
|
||||||
|
hook* install(bool unprotect = true, bool keep_unprotected = false);
|
||||||
|
hook* uninstall(bool unprotect = true);
|
||||||
|
|
||||||
|
void* get_address() const;
|
||||||
|
void* get_original() const;
|
||||||
|
void quick();
|
||||||
|
|
||||||
|
static bool iat(nt::library module, const std::string& target_module,
|
||||||
|
const std::string& process, void* stub);
|
||||||
|
|
||||||
|
static void nop(void* place, size_t length);
|
||||||
|
static void nop(DWORD place, size_t length);
|
||||||
|
|
||||||
|
template <typename T> static void set(void* place, T value) {
|
||||||
|
DWORD old_protect;
|
||||||
|
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
|
||||||
|
|
||||||
|
*static_cast<T*>(place) = value;
|
||||||
|
|
||||||
|
VirtualProtect(place, sizeof(T), old_protect, &old_protect);
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] void* get_original() const;
|
template <typename T> static void set(const DWORD place, T value) {
|
||||||
|
return set<T>(reinterpret_cast<void*>(place), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
static T invoke(size_t func, Args... args) {
|
||||||
|
return reinterpret_cast<T (*)(Args...)>(func)(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
static T invoke(void* func, Args... args) {
|
||||||
|
return static_cast<T (*)(Args...)>(func)(args...);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* place_{};
|
bool initialized_;
|
||||||
void* original_{};
|
bool installed_;
|
||||||
|
|
||||||
|
void* place_;
|
||||||
|
void* stub_;
|
||||||
|
void* original_;
|
||||||
|
char buffer_[5]{};
|
||||||
|
bool use_jump_;
|
||||||
|
|
||||||
|
DWORD protection_;
|
||||||
|
|
||||||
|
std::mutex state_mutex_;
|
||||||
};
|
};
|
||||||
|
} // namespace utils
|
||||||
void nop(void* place, size_t length);
|
|
||||||
void nop(size_t place, size_t length);
|
|
||||||
|
|
||||||
void copy(void* place, const void* data, size_t length);
|
|
||||||
void copy(size_t place, const void* data, size_t length);
|
|
||||||
|
|
||||||
bool is_relatively_far(const void* pointer, const void* data, int offset = 5);
|
|
||||||
|
|
||||||
void call(void* pointer, void* data);
|
|
||||||
void call(size_t pointer, void* data);
|
|
||||||
void call(size_t pointer, size_t data);
|
|
||||||
|
|
||||||
void jump(std::uintptr_t address, void* destination);
|
|
||||||
|
|
||||||
void redirect_jump(void* pointer, void* data);
|
|
||||||
void redirect_jump(size_t pointer, void* data);
|
|
||||||
|
|
||||||
template <typename T> T extract(void* address) {
|
|
||||||
const auto data = static_cast<uint8_t*>(address);
|
|
||||||
const auto offset = *reinterpret_cast<int32_t*>(data);
|
|
||||||
return reinterpret_cast<T>(data + offset + 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> static void set(void* place, T value) {
|
|
||||||
DWORD old_protect;
|
|
||||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
|
|
||||||
|
|
||||||
*static_cast<T*>(place) = value;
|
|
||||||
|
|
||||||
VirtualProtect(place, sizeof(T), old_protect, &old_protect);
|
|
||||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> static void set(const size_t place, T value) {
|
|
||||||
return set<T>(reinterpret_cast<void*>(place), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
|
||||||
static T invoke(size_t func, Args... args) {
|
|
||||||
return reinterpret_cast<T (*)(Args...)>(func)(args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
|
||||||
static T invoke(void* func, Args... args) {
|
|
||||||
return static_cast<T (*)(Args...)>(func)(args...);
|
|
||||||
}
|
|
||||||
} // namespace utils::hook
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user