Add CEG patches

This commit is contained in:
momo5502 2018-12-24 19:54:44 +01:00
parent ff277cfa6e
commit 1d015e469f
9 changed files with 359 additions and 16 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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() {}
};

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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
View 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
View 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_;
};
}