Add CEG patches
This commit is contained in:
parent
ff277cfa6e
commit
1d015e469f
@ -5,10 +5,6 @@ loader::loader(const launcher::mode mode) : mode_(mode)
|
||||
{
|
||||
}
|
||||
|
||||
void loader::patch()
|
||||
{
|
||||
}
|
||||
|
||||
FARPROC loader::load(const utils::nt::module& module) const
|
||||
{
|
||||
const auto buffer = this->load_binary();
|
||||
|
@ -7,7 +7,6 @@ class loader final
|
||||
public:
|
||||
explicit loader(launcher::mode mode);
|
||||
|
||||
void patch();
|
||||
FARPROC load(const utils::nt::module& module) const;
|
||||
|
||||
void set_import_resolver(const std::function<FARPROC(const std::string&, const std::string&)>& resolver);
|
||||
|
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
#include "launcher/launcher.hpp"
|
||||
|
||||
class module
|
||||
{
|
||||
public:
|
||||
virtual ~module() {};
|
||||
virtual void pre_load() {}
|
||||
virtual void post_load() {}
|
||||
virtual void pre_destroy() {}
|
||||
};
|
||||
|
@ -1,11 +1,12 @@
|
||||
#include <std_include.hpp>
|
||||
#include "module_loader.hpp"
|
||||
|
||||
launcher::mode module_loader::mode_ = launcher::mode::NONE;
|
||||
std::vector<std::unique_ptr<module>>* module_loader::modules_ = nullptr;
|
||||
|
||||
void module_loader::register_module(std::unique_ptr<module>&& module_)
|
||||
{
|
||||
if(!module_loader::modules_)
|
||||
if (!module_loader::modules_)
|
||||
{
|
||||
module_loader::modules_ = new std::vector<std::unique_ptr<module>>();
|
||||
atexit(module_loader::destroy_modules);
|
||||
@ -14,9 +15,45 @@ void module_loader::register_module(std::unique_ptr<module>&& module_)
|
||||
module_loader::modules_->push_back(std::move(module_));
|
||||
}
|
||||
|
||||
void module_loader::post_load()
|
||||
{
|
||||
static auto handled = false;
|
||||
if (handled || !module_loader::modules_) return;
|
||||
handled = true;
|
||||
|
||||
for (const auto& module_ : *module_loader::modules_)
|
||||
{
|
||||
module_->post_load();
|
||||
}
|
||||
}
|
||||
|
||||
void module_loader::pre_destroy()
|
||||
{
|
||||
static auto handled = false;
|
||||
if (handled || !module_loader::modules_) return;
|
||||
handled = true;
|
||||
|
||||
for (const auto& module_ : *module_loader::modules_)
|
||||
{
|
||||
module_->pre_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
launcher::mode module_loader::get_mode()
|
||||
{
|
||||
return module_loader::mode_;
|
||||
}
|
||||
|
||||
void module_loader::set_mode(const launcher::mode mode)
|
||||
{
|
||||
module_loader::mode_ = mode;
|
||||
}
|
||||
|
||||
void module_loader::destroy_modules()
|
||||
{
|
||||
if(!module_loader::modules_) return;
|
||||
module_loader::pre_destroy();
|
||||
|
||||
if (!module_loader::modules_) return;
|
||||
|
||||
delete module_loader::modules_;
|
||||
module_loader::modules_ = nullptr;
|
||||
|
@ -18,7 +18,14 @@ public:
|
||||
|
||||
static void register_module(std::unique_ptr<module>&& module);
|
||||
|
||||
static void post_load();
|
||||
static void pre_destroy();
|
||||
|
||||
static launcher::mode get_mode();
|
||||
static void set_mode(launcher::mode mode);
|
||||
|
||||
private:
|
||||
static launcher::mode mode_;
|
||||
static std::vector<std::unique_ptr<module>>* modules_;
|
||||
|
||||
static void destroy_modules();
|
||||
|
13
src/main.cpp
13
src/main.cpp
@ -1,6 +1,13 @@
|
||||
#include <std_include.hpp>
|
||||
#include "launcher/launcher.hpp"
|
||||
#include "loader/loader.hpp"
|
||||
#include "loader/module_loader.hpp"
|
||||
|
||||
void exit_hook(const int code)
|
||||
{
|
||||
module_loader::pre_destroy();
|
||||
exit(code);
|
||||
}
|
||||
|
||||
int CALLBACK WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nCmdShow*/)
|
||||
{
|
||||
@ -10,6 +17,8 @@ int CALLBACK WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR
|
||||
launcher launcher;
|
||||
const auto mode = launcher.run();
|
||||
|
||||
module_loader::set_mode(mode);
|
||||
|
||||
if (mode == launcher::mode::NONE) return 0;
|
||||
|
||||
loader loader(mode);
|
||||
@ -21,7 +30,7 @@ int CALLBACK WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR
|
||||
}
|
||||
else if (function == "ExitProcess")
|
||||
{
|
||||
return FARPROC(exit);
|
||||
return FARPROC(exit_hook);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -30,7 +39,7 @@ int CALLBACK WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR
|
||||
entry_point = loader.load({});
|
||||
if (!entry_point) return 1;
|
||||
|
||||
loader.patch();
|
||||
module_loader::post_load();
|
||||
}
|
||||
|
||||
return entry_point();
|
||||
|
@ -1,17 +1,71 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
|
||||
class ceg final : public module
|
||||
{
|
||||
public:
|
||||
ceg()
|
||||
void post_load() override
|
||||
{
|
||||
OutputDebugStringA("+ CEG\n");
|
||||
}
|
||||
// Only SP has CEG
|
||||
// CEG in MP has accidentally been removed due to CVE-2018-10718
|
||||
if(module_loader::get_mode() != launcher::mode::SINGLEPLAYER) return;
|
||||
|
||||
~ceg()
|
||||
{
|
||||
OutputDebugStringA("- CEG\n");
|
||||
utils::hook::signature signature;
|
||||
|
||||
signature.add({ "\x56\xE8\x00\x00\x00\x00\x8B\xF0\xE8\x00\x00\x00\x00\x50\x56\xE8", "xx????xxx????xxx", [](char* address)
|
||||
{
|
||||
utils::hook::set<DWORD>(address, 0xC301B0);
|
||||
} });
|
||||
|
||||
// Generic killer caller.
|
||||
signature.add({ "\x55\x8B\xEC\x80\x7D\x08\x00\x75\x55", "xxxxxx?xx", []( char* address)
|
||||
{
|
||||
utils::hook::set<DWORD>(address, 0xC301B0);
|
||||
} });
|
||||
|
||||
// CEG initialization.
|
||||
signature.add({ "\x55\x8B\xEC\x83\xEC\x18\x53\x56\x57\xE8\x00\x00\x00\x00", "xxxxxxxxxx????", [](char* address)
|
||||
{
|
||||
utils::hook::set<BYTE>(address, 0xC3);
|
||||
} });
|
||||
|
||||
// Some odd trap.
|
||||
signature.add({ "\x55\x8B\xEC\x81\xEC\x00\x00\x00\x00\x53\x56\x57\x8B\x3D", "xxxxx??xxxxxxx", [](char* address)
|
||||
{
|
||||
utils::hook::set<DWORD>(address, 0xC301B0);
|
||||
} });
|
||||
|
||||
// Custom shit
|
||||
signature.add({ "\x55\x8B\xEC\x68\x00\x00\x00\x00\x68\x00\x00\x00\x00\x64\xFF\x35\x00\x00\x00\x00\x64\x89\x25\x00\x00\x00\x00\xE8", "xxxx????x????xxx????xxx????x", [](char* address)
|
||||
{
|
||||
utils::hook::set<BYTE>(address, 0xC3);
|
||||
} });
|
||||
|
||||
// hkcr guid check
|
||||
signature.add({ "\x55\x8B\xEC\xB8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x84\xC0\x75\x06", "xxxx????x????x????xxxx", [](char* address)
|
||||
{
|
||||
utils::hook::nop(address + 0xD, 5); // Call
|
||||
utils::hook::nop(address + 0x14, 2); // Jump
|
||||
} });
|
||||
|
||||
// hkcr guid check 2
|
||||
signature.add({ "\x55\x8B\xEC\x81\xEC\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x84\xC0\x75\x06", "xxxxx????x????xxxx", [](char* address)
|
||||
{
|
||||
utils::hook::nop(address + 0x9, 5); // Call
|
||||
utils::hook::nop(address + 0x10, 2); // Jump
|
||||
} });
|
||||
|
||||
signature.process();
|
||||
|
||||
// Function fixup
|
||||
utils::hook(0x4CA310, 0x48A8E0, HOOK_JUMP).install()->quick(); // DB_LoadXAssets
|
||||
|
||||
// Some value obfuscation
|
||||
utils::hook(0x493B81, 0x493BFC, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Ceg uninit
|
||||
utils::hook::set<BYTE>(0x527110, 0xC3);
|
||||
}
|
||||
};
|
||||
|
||||
|
154
src/utils/hook.cpp
Normal file
154
src/utils/hook.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
#include <std_include.hpp>
|
||||
#include "hook.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
void hook::signature::process()
|
||||
{
|
||||
if (this->signatures_.empty()) return;
|
||||
|
||||
const auto start = reinterpret_cast<char*>(this->start_);
|
||||
|
||||
const unsigned int sig_count = this->signatures_.size();
|
||||
const auto containers = this->signatures_.data();
|
||||
|
||||
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 hook::signature::add(const hook::signature::container& container)
|
||||
{
|
||||
hook::signature::signatures_.push_back(container);
|
||||
}
|
||||
|
||||
hook::~hook()
|
||||
{
|
||||
if (this->initialized_)
|
||||
{
|
||||
this->uninstall();
|
||||
}
|
||||
}
|
||||
|
||||
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 (hook::installed_)
|
||||
{
|
||||
hook::installed_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
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::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);
|
||||
}
|
||||
}
|
87
src/utils/hook.hpp
Normal file
87
src/utils/hook.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#define HOOK_JUMP true
|
||||
#define HOOK_CALL false
|
||||
|
||||
namespace utils
|
||||
{
|
||||
class hook final
|
||||
{
|
||||
public:
|
||||
class signature final
|
||||
{
|
||||
public:
|
||||
struct container final
|
||||
{
|
||||
const char* signature;
|
||||
const char* mask;
|
||||
std::function<void(char*)> callback;
|
||||
};
|
||||
|
||||
signature(void* start, const size_t length) : start_(start), length_(length) {}
|
||||
signature(const DWORD start, const size_t length) : signature(reinterpret_cast<void*>(start), length) {}
|
||||
signature() : signature(0x400000, 0x800000) {}
|
||||
|
||||
void process();
|
||||
void add(const container& container);
|
||||
|
||||
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_)); }
|
||||
|
||||
hook(void* place, void* stub, const bool use_jump = true) : hook() { this->initialize(place, stub, use_jump); }
|
||||
hook(void* place, void(*stub)(), const bool use_jump = true) : 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();
|
||||
|
||||
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 quick();
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
template <typename T> static void set(const DWORD place, T value)
|
||||
{
|
||||
return set<T>(reinterpret_cast<void*>(place), value);
|
||||
}
|
||||
|
||||
private:
|
||||
bool initialized_;
|
||||
bool installed_;
|
||||
|
||||
void* place_;
|
||||
void* stub_;
|
||||
void* original_;
|
||||
char buffer_[5]{};
|
||||
bool use_jump_;
|
||||
|
||||
DWORD protection_;
|
||||
|
||||
std::mutex state_mutex_;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user