Fix stuff

This commit is contained in:
momo5502
2019-09-24 10:30:08 +02:00
parent 0fb12bdc32
commit fbfdc30e25
48 changed files with 3950 additions and 3950 deletions

View File

@ -1,121 +1,121 @@
#include <std_include.hpp>
#include "binary_loader.hpp"
#include "utils/nt.hpp"
#include "utils/io.hpp"
#include "utils/cryptography.hpp"
#include "utils/string.hpp"
#include "utils/compression.hpp"
#define DEDI_HASH "F271C305117B79242E254E9F64BD5AA2993CAC8E57975243EBD44CD576418D20"
namespace binary_loader
{
std::string load_resource(const int id)
{
const auto res = FindResource(::utils::nt::module(), MAKEINTRESOURCE(id), RT_RCDATA);
if (!res) return {};
const auto handle = LoadResource(nullptr, res);
if (!handle) return {};
return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res));
}
std::string load_delta(const launcher::mode mode)
{
if (mode == launcher::mode::singleplayer)
{
return load_resource(BINARY_SP);
}
if (mode == launcher::mode::multiplayer)
{
return load_resource(BINARY_MP);
}
return {};
}
std::string load_base(const bool verify = true)
{
std::string data;
if (!utils::io::read_file("iw5mp_server.exe", &data))
{
throw std::runtime_error("Unable to load iw5mp_server.exe");
}
if (verify && utils::cryptography::sha256::compute(data, true) != DEDI_HASH)
{
throw std::runtime_error("Your iw5mp_server.exe is incompatible with this client.");
}
return data;
}
void create_for_file(const std::string& file, const std::string& base)
{
std::string data;
if (!utils::io::read_file(file, &data))
{
throw std::runtime_error(utils::string::va("Unable to load file %s!", file.data()));
}
const auto new_data = reinterpret_cast<const unsigned char*>(data.data());
const auto old_data = reinterpret_cast<const unsigned char*>(base.data());
std::vector<unsigned char> diff;
create_diff(new_data, new_data + data.size(), old_data, old_data + base.size(), diff);
const unsigned long long size = data.size();
std::string result(reinterpret_cast<char*>(diff.data()), diff.size());
result.append(reinterpret_cast<const char*>(&size), sizeof(size));
result = utils::compression::zlib::compress(result);
utils::io::write_file(file + ".diff", result);
}
void create()
{
const auto base = load_base(false);
utils::io::write_file("hash.txt", utils::cryptography::sha256::compute(base, true));
create_for_file("iw5sp.exe", base);
create_for_file("iw5mp.exe", base);
}
std::string build_binary(const std::string& base, const std::string& diff)
{
const auto* size = reinterpret_cast<const unsigned long long*>(diff.data() + diff.size() - sizeof(unsigned long
long));
std::string binary;
binary.resize(size_t(*size));
const auto new_data = reinterpret_cast<unsigned char*>(binary.data());
const auto old_data = reinterpret_cast<const unsigned char*>(base.data());
const auto diff_data = reinterpret_cast<const unsigned char*>(diff.data());
if (patch(new_data, new_data + binary.size(), old_data, old_data + base.size(), diff_data,
diff_data + diff.size() - sizeof(*size)) == hpatch_FALSE || binary.empty())
{
throw std::runtime_error("Unable to create binary from patch!");
}
return binary;
}
std::string load(const launcher::mode mode)
{
auto base = load_base();
if (mode == launcher::mode::server)
{
return base;
}
auto delta = load_delta(mode);
delta = utils::compression::zlib::decompress(delta);
return build_binary(base, delta);
}
}
#include <std_include.hpp>
#include "binary_loader.hpp"
#include "utils/nt.hpp"
#include "utils/io.hpp"
#include "utils/cryptography.hpp"
#include "utils/string.hpp"
#include "utils/compression.hpp"
#define DEDI_HASH "F271C305117B79242E254E9F64BD5AA2993CAC8E57975243EBD44CD576418D20"
namespace binary_loader
{
std::string load_resource(const int id)
{
const auto res = FindResource(::utils::nt::module(), MAKEINTRESOURCE(id), RT_RCDATA);
if (!res) return {};
const auto handle = LoadResource(nullptr, res);
if (!handle) return {};
return std::string(LPSTR(LockResource(handle)), SizeofResource(nullptr, res));
}
std::string load_delta(const launcher::mode mode)
{
if (mode == launcher::mode::singleplayer)
{
return load_resource(BINARY_SP);
}
if (mode == launcher::mode::multiplayer)
{
return load_resource(BINARY_MP);
}
return {};
}
std::string load_base(const bool verify = true)
{
std::string data;
if (!utils::io::read_file("iw5mp_server.exe", &data))
{
throw std::runtime_error("Unable to load iw5mp_server.exe");
}
if (verify && utils::cryptography::sha256::compute(data, true) != DEDI_HASH)
{
throw std::runtime_error("Your iw5mp_server.exe is incompatible with this client.");
}
return data;
}
void create_for_file(const std::string& file, const std::string& base)
{
std::string data;
if (!utils::io::read_file(file, &data))
{
throw std::runtime_error(utils::string::va("Unable to load file %s!", file.data()));
}
const auto new_data = reinterpret_cast<const unsigned char*>(data.data());
const auto old_data = reinterpret_cast<const unsigned char*>(base.data());
std::vector<unsigned char> diff;
create_diff(new_data, new_data + data.size(), old_data, old_data + base.size(), diff);
const unsigned long long size = data.size();
std::string result(reinterpret_cast<char*>(diff.data()), diff.size());
result.append(reinterpret_cast<const char*>(&size), sizeof(size));
result = utils::compression::zlib::compress(result);
utils::io::write_file(file + ".diff", result);
}
void create()
{
const auto base = load_base(false);
utils::io::write_file("hash.txt", utils::cryptography::sha256::compute(base, true));
create_for_file("iw5sp.exe", base);
create_for_file("iw5mp.exe", base);
}
std::string build_binary(const std::string& base, const std::string& diff)
{
const auto* size = reinterpret_cast<const unsigned long long*>(diff.data() + diff.size() - sizeof(unsigned long
long));
std::string binary;
binary.resize(size_t(*size));
const auto new_data = reinterpret_cast<unsigned char*>(binary.data());
const auto old_data = reinterpret_cast<const unsigned char*>(base.data());
const auto diff_data = reinterpret_cast<const unsigned char*>(diff.data());
if (patch(new_data, new_data + binary.size(), old_data, old_data + base.size(), diff_data,
diff_data + diff.size() - sizeof(*size)) == hpatch_FALSE || binary.empty())
{
throw std::runtime_error("Unable to create binary from patch!");
}
return binary;
}
std::string load(const launcher::mode mode)
{
auto base = load_base();
if (mode == launcher::mode::server)
{
return base;
}
auto delta = load_delta(mode);
delta = utils::compression::zlib::decompress(delta);
return build_binary(base, delta);
}
}

View File

@ -1,8 +1,8 @@
#pragma once
#include "launcher/launcher.hpp"
namespace binary_loader
{
void create();
std::string load(launcher::mode mode);
}
#pragma once
#include "launcher/launcher.hpp"
namespace binary_loader
{
void create();
std::string load(launcher::mode mode);
}

View File

@ -1,165 +1,165 @@
#include <std_include.hpp>
#include "loader.hpp"
#include "binary_loader.hpp"
#include "utils/string.hpp"
loader::loader(const launcher::mode mode) : mode_(mode)
{
}
FARPROC loader::load(const utils::nt::module& module) const
{
const auto buffer = binary_loader::load(this->mode_);
if (buffer.empty()) return nullptr;
utils::nt::module source(HMODULE(buffer.data()));
if (!source) return nullptr;
this->load_sections(module, source);
this->load_imports(module, source);
if (source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size)
{
const auto target_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(module.get_ptr() + module
.get_optional_header()
->
DataDirectory
[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
const auto source_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(module.get_ptr() + source
.get_optional_header()
->
DataDirectory
[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
const auto tls_size = source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData;
const auto tls_index = *reinterpret_cast<DWORD*>(target_tls->AddressOfIndex);
*reinterpret_cast<DWORD*>(source_tls->AddressOfIndex) = tls_index;
if (tls_size > TLS_PAYLOAD_SIZE)
{
throw std::runtime_error(utils::string::va(
"TLS data is of size 0x%X, but we have only reserved 0x%X bytes!", tls_size, TLS_PAYLOAD_SIZE));
}
DWORD old_protect;
VirtualProtect(PVOID(target_tls->StartAddressOfRawData),
source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData, PAGE_READWRITE,
&old_protect);
const auto tls_base = *reinterpret_cast<LPVOID*>(__readfsdword(0x2C) + 4 * tls_index);
std::memmove(tls_base, PVOID(source_tls->StartAddressOfRawData), tls_size);
std::memmove(PVOID(target_tls->StartAddressOfRawData), PVOID(source_tls->StartAddressOfRawData), tls_size);
}
DWORD oldProtect;
VirtualProtect(module.get_nt_headers(), 0x1000, PAGE_EXECUTE_READWRITE, &oldProtect);
module.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] = source
.get_optional_header()->DataDirectory[
IMAGE_DIRECTORY_ENTRY_IMPORT];
std::memmove(module.get_nt_headers(), source.get_nt_headers(),
sizeof(IMAGE_NT_HEADERS) + (source.get_nt_headers()->FileHeader.NumberOfSections * (sizeof(
IMAGE_SECTION_HEADER))));
return FARPROC(module.get_ptr() + source.get_relative_entry_point());
}
void loader::set_import_resolver(const std::function<FARPROC(const std::string&, const std::string&)>& resolver)
{
this->import_resolver_ = resolver;
}
void loader::load_section(const utils::nt::module& target, const utils::nt::module& source,
IMAGE_SECTION_HEADER* section)
{
void* target_ptr = target.get_ptr() + section->VirtualAddress;
const void* source_ptr = source.get_ptr() + section->PointerToRawData;
if (PBYTE(target_ptr) >= (target.get_ptr() + BINARY_PAYLOAD_SIZE))
{
throw std::runtime_error("Section exceeds the binary payload size, please increase it!");
}
if (section->SizeOfRawData > 0)
{
const auto size_of_data = std::min(section->SizeOfRawData, section->Misc.VirtualSize);
std::memmove(target_ptr, source_ptr, size_of_data);
DWORD old_protect;
VirtualProtect(target_ptr, size_of_data, PAGE_EXECUTE_READWRITE, &old_protect);
}
}
void loader::load_sections(const utils::nt::module& target, const utils::nt::module& source) const
{
for (auto& section : source.get_section_headers())
{
this->load_section(target, source, section);
}
}
void loader::load_imports(const utils::nt::module& target, const utils::nt::module& source) const
{
const auto import_directory = &source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
auto descriptor = PIMAGE_IMPORT_DESCRIPTOR(target.get_ptr() + import_directory->VirtualAddress);
while (descriptor->Name)
{
std::string name = LPSTR(target.get_ptr() + descriptor->Name);
auto name_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->OriginalFirstThunk);
auto address_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->FirstThunk);
if (!descriptor->OriginalFirstThunk)
{
name_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->FirstThunk);
}
while (*name_table_entry)
{
FARPROC function = nullptr;
std::string function_name;
// is this an ordinal-only import?
if (IMAGE_SNAP_BY_ORDINAL(*name_table_entry))
{
auto module = utils::nt::module::load(name);
if (module)
{
function = GetProcAddress(module, MAKEINTRESOURCEA(IMAGE_ORDINAL(*name_table_entry)));
}
function_name = "#" + std::to_string(IMAGE_ORDINAL(*name_table_entry));
}
else
{
auto import = PIMAGE_IMPORT_BY_NAME(target.get_ptr() + *name_table_entry);
function_name = import->Name;
if (this->import_resolver_) function = this->import_resolver_(name, function_name);
if (!function)
{
auto module = utils::nt::module::load(name);
if (module)
{
function = GetProcAddress(module, function_name.data());
}
}
}
if (!function)
{
throw std::runtime_error(utils::string::va("Unable to load import '%s' from module '%s'",
function_name.data(), name.data()));
}
*address_table_entry = reinterpret_cast<uintptr_t>(function);
name_table_entry++;
address_table_entry++;
}
descriptor++;
}
}
#include <std_include.hpp>
#include "loader.hpp"
#include "binary_loader.hpp"
#include "utils/string.hpp"
loader::loader(const launcher::mode mode) : mode_(mode)
{
}
FARPROC loader::load(const utils::nt::module& module) const
{
const auto buffer = binary_loader::load(this->mode_);
if (buffer.empty()) return nullptr;
utils::nt::module source(HMODULE(buffer.data()));
if (!source) return nullptr;
this->load_sections(module, source);
this->load_imports(module, source);
if (source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size)
{
const auto target_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(module.get_ptr() + module
.get_optional_header()
->
DataDirectory
[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
const auto source_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(module.get_ptr() + source
.get_optional_header()
->
DataDirectory
[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
const auto tls_size = source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData;
const auto tls_index = *reinterpret_cast<DWORD*>(target_tls->AddressOfIndex);
*reinterpret_cast<DWORD*>(source_tls->AddressOfIndex) = tls_index;
if (tls_size > TLS_PAYLOAD_SIZE)
{
throw std::runtime_error(utils::string::va(
"TLS data is of size 0x%X, but we have only reserved 0x%X bytes!", tls_size, TLS_PAYLOAD_SIZE));
}
DWORD old_protect;
VirtualProtect(PVOID(target_tls->StartAddressOfRawData),
source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData, PAGE_READWRITE,
&old_protect);
const auto tls_base = *reinterpret_cast<LPVOID*>(__readfsdword(0x2C) + 4 * tls_index);
std::memmove(tls_base, PVOID(source_tls->StartAddressOfRawData), tls_size);
std::memmove(PVOID(target_tls->StartAddressOfRawData), PVOID(source_tls->StartAddressOfRawData), tls_size);
}
DWORD oldProtect;
VirtualProtect(module.get_nt_headers(), 0x1000, PAGE_EXECUTE_READWRITE, &oldProtect);
module.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] = source
.get_optional_header()->DataDirectory[
IMAGE_DIRECTORY_ENTRY_IMPORT];
std::memmove(module.get_nt_headers(), source.get_nt_headers(),
sizeof(IMAGE_NT_HEADERS) + (source.get_nt_headers()->FileHeader.NumberOfSections * (sizeof(
IMAGE_SECTION_HEADER))));
return FARPROC(module.get_ptr() + source.get_relative_entry_point());
}
void loader::set_import_resolver(const std::function<FARPROC(const std::string&, const std::string&)>& resolver)
{
this->import_resolver_ = resolver;
}
void loader::load_section(const utils::nt::module& target, const utils::nt::module& source,
IMAGE_SECTION_HEADER* section)
{
void* target_ptr = target.get_ptr() + section->VirtualAddress;
const void* source_ptr = source.get_ptr() + section->PointerToRawData;
if (PBYTE(target_ptr) >= (target.get_ptr() + BINARY_PAYLOAD_SIZE))
{
throw std::runtime_error("Section exceeds the binary payload size, please increase it!");
}
if (section->SizeOfRawData > 0)
{
const auto size_of_data = std::min(section->SizeOfRawData, section->Misc.VirtualSize);
std::memmove(target_ptr, source_ptr, size_of_data);
DWORD old_protect;
VirtualProtect(target_ptr, size_of_data, PAGE_EXECUTE_READWRITE, &old_protect);
}
}
void loader::load_sections(const utils::nt::module& target, const utils::nt::module& source) const
{
for (auto& section : source.get_section_headers())
{
this->load_section(target, source, section);
}
}
void loader::load_imports(const utils::nt::module& target, const utils::nt::module& source) const
{
const auto import_directory = &source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
auto descriptor = PIMAGE_IMPORT_DESCRIPTOR(target.get_ptr() + import_directory->VirtualAddress);
while (descriptor->Name)
{
std::string name = LPSTR(target.get_ptr() + descriptor->Name);
auto name_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->OriginalFirstThunk);
auto address_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->FirstThunk);
if (!descriptor->OriginalFirstThunk)
{
name_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->FirstThunk);
}
while (*name_table_entry)
{
FARPROC function = nullptr;
std::string function_name;
// is this an ordinal-only import?
if (IMAGE_SNAP_BY_ORDINAL(*name_table_entry))
{
auto module = utils::nt::module::load(name);
if (module)
{
function = GetProcAddress(module, MAKEINTRESOURCEA(IMAGE_ORDINAL(*name_table_entry)));
}
function_name = "#" + std::to_string(IMAGE_ORDINAL(*name_table_entry));
}
else
{
auto import = PIMAGE_IMPORT_BY_NAME(target.get_ptr() + *name_table_entry);
function_name = import->Name;
if (this->import_resolver_) function = this->import_resolver_(name, function_name);
if (!function)
{
auto module = utils::nt::module::load(name);
if (module)
{
function = GetProcAddress(module, function_name.data());
}
}
}
if (!function)
{
throw std::runtime_error(utils::string::va("Unable to load import '%s' from module '%s'",
function_name.data(), name.data()));
}
*address_table_entry = reinterpret_cast<uintptr_t>(function);
name_table_entry++;
address_table_entry++;
}
descriptor++;
}
}

View File

@ -1,22 +1,22 @@
#pragma once
#include "utils/nt.hpp"
#include "launcher/launcher.hpp"
class loader final
{
public:
explicit loader(launcher::mode mode);
FARPROC load(const utils::nt::module& module) const;
void set_import_resolver(const std::function<FARPROC(const std::string&, const std::string&)>& resolver);
private:
launcher::mode mode_;
std::function<FARPROC(const std::string&, const std::string&)> import_resolver_;
static void load_section(const utils::nt::module& target, const utils::nt::module& source,
IMAGE_SECTION_HEADER* section);
void load_sections(const utils::nt::module& target, const utils::nt::module& source) const;
void load_imports(const utils::nt::module& target, const utils::nt::module& source) const;
};
#pragma once
#include "utils/nt.hpp"
#include "launcher/launcher.hpp"
class loader final
{
public:
explicit loader(launcher::mode mode);
FARPROC load(const utils::nt::module& module) const;
void set_import_resolver(const std::function<FARPROC(const std::string&, const std::string&)>& resolver);
private:
launcher::mode mode_;
std::function<FARPROC(const std::string&, const std::string&)> import_resolver_;
static void load_section(const utils::nt::module& target, const utils::nt::module& source,
IMAGE_SECTION_HEADER* section);
void load_sections(const utils::nt::module& target, const utils::nt::module& source) const;
void load_imports(const utils::nt::module& target, const utils::nt::module& source) const;
};

View File

@ -1,100 +1,100 @@
#include <std_include.hpp>
#include "module_loader.hpp"
std::vector<std::unique_ptr<module>>* module_loader::modules_ = nullptr;
void module_loader::register_module(std::unique_ptr<module>&& module_)
{
if (!modules_)
{
modules_ = new std::vector<std::unique_ptr<module>>();
atexit(destroy_modules);
}
modules_->push_back(std::move(module_));
}
bool module_loader::post_start()
{
static auto handled = false;
if (handled || !modules_) return true;
handled = true;
try
{
for (const auto& module_ : *modules_)
{
module_->post_start();
}
}
catch(premature_shutdown_trigger&)
{
return false;
}
return true;
}
bool module_loader::post_load()
{
static auto handled = false;
if (handled || !modules_) return true;
handled = true;
try
{
for (const auto& module_ : *modules_)
{
module_->post_load();
}
}
catch (premature_shutdown_trigger&)
{
return false;
}
return true;
}
void module_loader::pre_destroy()
{
static auto handled = false;
if (handled || !modules_) return;
handled = true;
for (const auto& module_ : *modules_)
{
module_->pre_destroy();
}
}
void* module_loader::load_import(const std::string& module, const std::string& function)
{
void* function_ptr = nullptr;
for (const auto& module_ : *modules_)
{
const auto module_function_ptr = module_->load_import(module, function);
if(module_function_ptr)
{
function_ptr = module_function_ptr;
}
}
return function_ptr;
}
void module_loader::destroy_modules()
{
pre_destroy();
if (!modules_) return;
delete modules_;
modules_ = nullptr;
}
void module_loader::trigger_premature_shutdown()
{
throw premature_shutdown_trigger();
}
#include <std_include.hpp>
#include "module_loader.hpp"
std::vector<std::unique_ptr<module>>* module_loader::modules_ = nullptr;
void module_loader::register_module(std::unique_ptr<module>&& module_)
{
if (!modules_)
{
modules_ = new std::vector<std::unique_ptr<module>>();
atexit(destroy_modules);
}
modules_->push_back(std::move(module_));
}
bool module_loader::post_start()
{
static auto handled = false;
if (handled || !modules_) return true;
handled = true;
try
{
for (const auto& module_ : *modules_)
{
module_->post_start();
}
}
catch(premature_shutdown_trigger&)
{
return false;
}
return true;
}
bool module_loader::post_load()
{
static auto handled = false;
if (handled || !modules_) return true;
handled = true;
try
{
for (const auto& module_ : *modules_)
{
module_->post_load();
}
}
catch (premature_shutdown_trigger&)
{
return false;
}
return true;
}
void module_loader::pre_destroy()
{
static auto handled = false;
if (handled || !modules_) return;
handled = true;
for (const auto& module_ : *modules_)
{
module_->pre_destroy();
}
}
void* module_loader::load_import(const std::string& module, const std::string& function)
{
void* function_ptr = nullptr;
for (const auto& module_ : *modules_)
{
const auto module_function_ptr = module_->load_import(module, function);
if(module_function_ptr)
{
function_ptr = module_function_ptr;
}
}
return function_ptr;
}
void module_loader::destroy_modules()
{
pre_destroy();
if (!modules_) return;
delete modules_;
modules_ = nullptr;
}
void module_loader::trigger_premature_shutdown()
{
throw premature_shutdown_trigger();
}