forked from mjkzy/s1-mod
init
This commit is contained in:
35
src/client/loader/component_interface.hpp
Normal file
35
src/client/loader/component_interface.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
class component_interface
|
||||
{
|
||||
public:
|
||||
virtual ~component_interface()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void post_start()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void post_load()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void pre_destroy()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void post_unpack()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void* load_import([[maybe_unused]] const std::string& library, [[maybe_unused]] const std::string& function)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual bool is_supported()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
127
src/client/loader/component_loader.cpp
Normal file
127
src/client/loader/component_loader.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
#include <std_include.hpp>
|
||||
#include "component_loader.hpp"
|
||||
|
||||
void component_loader::register_component(std::unique_ptr<component_interface>&& component_)
|
||||
{
|
||||
get_components().push_back(std::move(component_));
|
||||
}
|
||||
|
||||
bool component_loader::post_start()
|
||||
{
|
||||
static auto handled = false;
|
||||
if (handled) return true;
|
||||
handled = true;
|
||||
|
||||
try
|
||||
{
|
||||
for (const auto& component_ : get_components())
|
||||
{
|
||||
component_->post_start();
|
||||
}
|
||||
}
|
||||
catch (premature_shutdown_trigger&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool component_loader::post_load()
|
||||
{
|
||||
static auto handled = false;
|
||||
if (handled) return true;
|
||||
handled = true;
|
||||
|
||||
clean();
|
||||
|
||||
try
|
||||
{
|
||||
for (const auto& component_ : get_components())
|
||||
{
|
||||
component_->post_load();
|
||||
}
|
||||
}
|
||||
catch (premature_shutdown_trigger&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void component_loader::post_unpack()
|
||||
{
|
||||
static auto handled = false;
|
||||
if (handled) return;
|
||||
handled = true;
|
||||
|
||||
for (const auto& component_ : get_components())
|
||||
{
|
||||
component_->post_unpack();
|
||||
}
|
||||
}
|
||||
|
||||
void component_loader::pre_destroy()
|
||||
{
|
||||
static auto handled = false;
|
||||
if (handled) return;
|
||||
handled = true;
|
||||
|
||||
for (const auto& component_ : get_components())
|
||||
{
|
||||
component_->pre_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void component_loader::clean()
|
||||
{
|
||||
auto& components = get_components();
|
||||
for (auto i = components.begin(); i != components.end();)
|
||||
{
|
||||
if (!(*i)->is_supported())
|
||||
{
|
||||
(*i)->pre_destroy();
|
||||
i = components.erase(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* component_loader::load_import(const std::string& library, const std::string& function)
|
||||
{
|
||||
void* function_ptr = nullptr;
|
||||
|
||||
for (const auto& component_ : get_components())
|
||||
{
|
||||
auto* const component_function_ptr = component_->load_import(library, function);
|
||||
if (component_function_ptr)
|
||||
{
|
||||
function_ptr = component_function_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return function_ptr;
|
||||
}
|
||||
|
||||
void component_loader::trigger_premature_shutdown()
|
||||
{
|
||||
throw premature_shutdown_trigger();
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<component_interface>>& component_loader::get_components()
|
||||
{
|
||||
using component_vector = std::vector<std::unique_ptr<component_interface>>;
|
||||
using component_vector_container = std::unique_ptr<component_vector, std::function<void(component_vector*)>>;
|
||||
|
||||
static component_vector_container components(new component_vector, [](component_vector* component_vector)
|
||||
{
|
||||
pre_destroy();
|
||||
delete component_vector;
|
||||
});
|
||||
|
||||
return *components;
|
||||
}
|
61
src/client/loader/component_loader.hpp
Normal file
61
src/client/loader/component_loader.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include "component_interface.hpp"
|
||||
|
||||
class component_loader final
|
||||
{
|
||||
public:
|
||||
class premature_shutdown_trigger final : public std::exception
|
||||
{
|
||||
[[nodiscard]] const char* what() const noexcept override
|
||||
{
|
||||
return "Premature shutdown requested";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class installer final
|
||||
{
|
||||
static_assert(std::is_base_of<component_interface, T>::value, "component has invalid base class");
|
||||
|
||||
public:
|
||||
installer()
|
||||
{
|
||||
register_component(std::make_unique<T>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static T* get()
|
||||
{
|
||||
for (const auto& component_ : get_components())
|
||||
{
|
||||
if (typeid(*component_.get()) == typeid(T))
|
||||
{
|
||||
return reinterpret_cast<T*>(component_.get());
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void register_component(std::unique_ptr<component_interface>&& component);
|
||||
|
||||
static bool post_start();
|
||||
static bool post_load();
|
||||
static void post_unpack();
|
||||
static void pre_destroy();
|
||||
static void clean();
|
||||
|
||||
static void* load_import(const std::string& library, const std::string& function);
|
||||
|
||||
static void trigger_premature_shutdown();
|
||||
|
||||
private:
|
||||
static std::vector<std::unique_ptr<component_interface>>& get_components();
|
||||
};
|
||||
|
||||
#define REGISTER_COMPONENT(name) \
|
||||
namespace \
|
||||
{ \
|
||||
static component_loader::installer<name> __component; \
|
||||
}
|
213
src/client/loader/loader.cpp
Normal file
213
src/client/loader/loader.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader.hpp"
|
||||
#include "seh.hpp"
|
||||
#include "tls.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
FARPROC loader::load(const utils::nt::library& library, const std::string& buffer) const
|
||||
{
|
||||
if (buffer.empty()) return nullptr;
|
||||
|
||||
const utils::nt::library source(HMODULE(buffer.data()));
|
||||
if (!source) return nullptr;
|
||||
|
||||
this->load_sections(library, source);
|
||||
this->load_imports(library, source);
|
||||
this->load_exception_table(library, source);
|
||||
this->load_tls(library, source);
|
||||
|
||||
DWORD old_protect;
|
||||
VirtualProtect(library.get_nt_headers(), 0x1000, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
|
||||
library.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] = source
|
||||
.get_optional_header()->DataDirectory[
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
std::memmove(library.get_nt_headers(), source.get_nt_headers(),
|
||||
sizeof(IMAGE_NT_HEADERS) + source.get_nt_headers()->FileHeader.NumberOfSections * sizeof(
|
||||
IMAGE_SECTION_HEADER));
|
||||
|
||||
return FARPROC(library.get_ptr() + source.get_relative_entry_point());
|
||||
}
|
||||
|
||||
FARPROC loader::load_library(const std::string& filename) const
|
||||
{
|
||||
const auto target = utils::nt::library::load(filename);
|
||||
if (!target)
|
||||
{
|
||||
throw std::runtime_error{"Failed to map binary!"};
|
||||
}
|
||||
|
||||
const auto base = size_t(target.get_ptr());
|
||||
if(base != 0x140000000)
|
||||
{
|
||||
throw std::runtime_error{utils::string::va("Binary was mapped at 0x%llX (instead of 0x%llX). Something is severely broken :(", base, 0x140000000)};
|
||||
}
|
||||
|
||||
this->load_imports(target, target);
|
||||
this->load_tls(target, target);
|
||||
|
||||
return FARPROC(target.get_ptr() + target.get_relative_entry_point());
|
||||
}
|
||||
|
||||
void loader::set_import_resolver(const std::function<void*(const std::string&, const std::string&)>& resolver)
|
||||
{
|
||||
this->import_resolver_ = resolver;
|
||||
}
|
||||
|
||||
void loader::load_section(const utils::nt::library& target, const utils::nt::library& 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)
|
||||
{
|
||||
std::memmove(target_ptr, source_ptr, section->SizeOfRawData);
|
||||
|
||||
DWORD old_protect;
|
||||
VirtualProtect(target_ptr, section->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
}
|
||||
}
|
||||
|
||||
void loader::load_sections(const utils::nt::library& target, const utils::nt::library& source) const
|
||||
{
|
||||
for (auto& section : source.get_section_headers())
|
||||
{
|
||||
this->load_section(target, source, section);
|
||||
}
|
||||
}
|
||||
|
||||
void loader::load_imports(const utils::nt::library& target, const utils::nt::library& source) const
|
||||
{
|
||||
auto* const 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;
|
||||
const char* function_procname;
|
||||
|
||||
if (IMAGE_SNAP_BY_ORDINAL(*name_table_entry))
|
||||
{
|
||||
function_name = "#" + std::to_string(IMAGE_ORDINAL(*name_table_entry));
|
||||
function_procname = MAKEINTRESOURCEA(IMAGE_ORDINAL(*name_table_entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* import = PIMAGE_IMPORT_BY_NAME(target.get_ptr() + *name_table_entry);
|
||||
function_name = import->Name;
|
||||
function_procname = function_name.data();
|
||||
}
|
||||
|
||||
if (this->import_resolver_) function = FARPROC(this->import_resolver_(name, function_name));
|
||||
if (!function)
|
||||
{
|
||||
auto library = utils::nt::library::load(name);
|
||||
if (library)
|
||||
{
|
||||
function = GetProcAddress(library, function_procname);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function)
|
||||
{
|
||||
throw std::runtime_error(utils::string::va("Unable to load import '%s' from library '%s'",
|
||||
function_name.data(), name.data()));
|
||||
}
|
||||
|
||||
utils::hook::set(address_table_entry, reinterpret_cast<uintptr_t>(function));
|
||||
|
||||
name_table_entry++;
|
||||
address_table_entry++;
|
||||
}
|
||||
|
||||
descriptor++;
|
||||
}
|
||||
}
|
||||
|
||||
void loader::load_exception_table(const utils::nt::library& target, const utils::nt::library& source) const
|
||||
{
|
||||
auto* exception_directory = &source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
|
||||
|
||||
auto* function_list = PRUNTIME_FUNCTION(target.get_ptr() + exception_directory->VirtualAddress);
|
||||
const auto entry_count = ULONG(exception_directory->Size / sizeof(RUNTIME_FUNCTION));
|
||||
|
||||
if (!RtlAddFunctionTable(function_list, entry_count, DWORD64(target.get_ptr())))
|
||||
{
|
||||
game::show_error("Setting exception handlers failed.");
|
||||
}
|
||||
|
||||
{
|
||||
const utils::nt::library ntdll("ntdll.dll");
|
||||
|
||||
auto* const table_list_head = ntdll.invoke_pascal<PLIST_ENTRY>("RtlGetFunctionTableListHead");
|
||||
auto* table_list_entry = table_list_head->Flink;
|
||||
|
||||
while (table_list_entry != table_list_head)
|
||||
{
|
||||
auto* const function_table = CONTAINING_RECORD(table_list_entry, DYNAMIC_FUNCTION_TABLE, Links);
|
||||
|
||||
if (function_table->BaseAddress == ULONG_PTR(target.get_handle()))
|
||||
{
|
||||
function_table->EntryCount = entry_count;
|
||||
function_table->FunctionTable = function_list;
|
||||
}
|
||||
|
||||
table_list_entry = function_table->Links.Flink;
|
||||
}
|
||||
}
|
||||
|
||||
seh::setup_handler(target.get_ptr(), target.get_ptr() + source.get_optional_header()->SizeOfImage, function_list,
|
||||
entry_count);
|
||||
}
|
||||
|
||||
void loader::load_tls(const utils::nt::library& target, const utils::nt::library& source) const
|
||||
{
|
||||
if (source.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size)
|
||||
{
|
||||
auto* target_tls = tls::allocate_tls_index();
|
||||
/* target_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(library.get_ptr() + library.get_optional_header()
|
||||
->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); */
|
||||
auto* const source_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(target.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);
|
||||
utils::hook::set<DWORD>(source_tls->AddressOfIndex, tls_index);
|
||||
|
||||
DWORD old_protect;
|
||||
VirtualProtect(PVOID(target_tls->StartAddressOfRawData),
|
||||
source_tls->EndAddressOfRawData - source_tls->StartAddressOfRawData, PAGE_READWRITE,
|
||||
&old_protect);
|
||||
|
||||
auto* const tls_base = *reinterpret_cast<LPVOID*>(__readgsqword(0x58) + 8ull * tls_index);
|
||||
std::memmove(tls_base, PVOID(source_tls->StartAddressOfRawData), tls_size);
|
||||
std::memmove(PVOID(target_tls->StartAddressOfRawData), PVOID(source_tls->StartAddressOfRawData), tls_size);
|
||||
|
||||
VirtualProtect(target_tls, sizeof(*target_tls), PAGE_READWRITE, &old_protect);
|
||||
*target_tls = *source_tls;
|
||||
}
|
||||
}
|
21
src/client/loader/loader.hpp
Normal file
21
src/client/loader/loader.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
class loader final
|
||||
{
|
||||
public:
|
||||
FARPROC load(const utils::nt::library& library, const std::string& buffer) const;
|
||||
FARPROC load_library(const std::string& filename) const;
|
||||
|
||||
void set_import_resolver(const std::function<void*(const std::string&, const std::string&)>& resolver);
|
||||
|
||||
private:
|
||||
std::function<void*(const std::string&, const std::string&)> import_resolver_;
|
||||
|
||||
static void load_section(const utils::nt::library& target, const utils::nt::library& source,
|
||||
IMAGE_SECTION_HEADER* section);
|
||||
void load_sections(const utils::nt::library& target, const utils::nt::library& source) const;
|
||||
void load_imports(const utils::nt::library& target, const utils::nt::library& source) const;
|
||||
void load_exception_table(const utils::nt::library& target, const utils::nt::library& source) const;
|
||||
void load_tls(const utils::nt::library& target, const utils::nt::library& source) const;
|
||||
};
|
151
src/client/loader/seh.cpp
Normal file
151
src/client/loader/seh.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
#include "seh.hpp"
|
||||
|
||||
namespace seh
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void*(*rtlpx_lookup_function_table)(void*, FUNCTION_TABLE_DATA*);
|
||||
void*(*rtlpx_lookup_function_table_down_level)(void*, PDWORD64, PULONG);
|
||||
|
||||
FUNCTION_TABLE_DATA overridden_table;
|
||||
|
||||
DWORD64 override_end;
|
||||
DWORD64 override_start;
|
||||
|
||||
void* find_call_from_address(void* method_ptr, ud_mnemonic_code mnemonic = UD_Icall)
|
||||
{
|
||||
ud_t ud;
|
||||
ud_init(&ud);
|
||||
ud_set_mode(&ud, 64);
|
||||
ud_set_pc(&ud, reinterpret_cast<uint64_t>(method_ptr));
|
||||
ud_set_input_buffer(&ud, static_cast<uint8_t*>(method_ptr), INT32_MAX);
|
||||
|
||||
void* retval = nullptr;
|
||||
while (true)
|
||||
{
|
||||
ud_disassemble(&ud);
|
||||
|
||||
if (ud_insn_mnemonic(&ud) == UD_Iint3) break;
|
||||
if (ud_insn_mnemonic(&ud) == mnemonic)
|
||||
{
|
||||
const auto* const operand = ud_insn_opr(&ud, 0);
|
||||
if (operand->type == UD_OP_JIMM)
|
||||
{
|
||||
if (!retval) retval = reinterpret_cast<void*>(ud_insn_len(&ud) + ud_insn_off(&ud) + operand->
|
||||
lval.sdword);
|
||||
else
|
||||
{
|
||||
retval = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void* rtlpx_lookup_function_table_override(void* exception_address, FUNCTION_TABLE_DATA* out_data)
|
||||
{
|
||||
ZeroMemory(out_data, sizeof(*out_data));
|
||||
|
||||
auto* retval = seh::rtlpx_lookup_function_table(exception_address, out_data);
|
||||
|
||||
const auto address_num = DWORD64(exception_address);
|
||||
if (address_num >= seh::override_start && address_num <= seh::override_end)
|
||||
{
|
||||
if (address_num != 0)
|
||||
{
|
||||
*out_data = seh::overridden_table;
|
||||
retval = PVOID(seh::overridden_table.TableAddress);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void* rtlpx_lookup_function_table_override_down_level(void* exception_address, const PDWORD64 image_base,
|
||||
const PULONG length)
|
||||
{
|
||||
auto* retval = seh::rtlpx_lookup_function_table_down_level(exception_address, image_base, length);
|
||||
|
||||
const auto address_num = DWORD64(exception_address);
|
||||
if (address_num >= seh::override_start && address_num <= seh::override_end)
|
||||
{
|
||||
if (address_num != 0)
|
||||
{
|
||||
*image_base = seh::overridden_table.ImageBase;
|
||||
*length = seh::overridden_table.Size;
|
||||
|
||||
retval = PVOID(seh::overridden_table.TableAddress);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
void setup_handler(void* module_base, void* module_end, PRUNTIME_FUNCTION runtime_functions, const DWORD entryCount)
|
||||
{
|
||||
const utils::nt::library ntdll("ntdll.dll");
|
||||
|
||||
seh::override_start = DWORD64(module_base);
|
||||
seh::override_end = DWORD64(module_end);
|
||||
|
||||
seh::overridden_table.ImageBase = seh::override_start;
|
||||
seh::overridden_table.TableAddress = DWORD64(runtime_functions);
|
||||
seh::overridden_table.Size = entryCount * sizeof(RUNTIME_FUNCTION);
|
||||
|
||||
if (IsWindows8Point1OrGreater())
|
||||
{
|
||||
struct
|
||||
{
|
||||
DWORD64 field0;
|
||||
DWORD imageSize;
|
||||
DWORD fieldC;
|
||||
DWORD64 field10;
|
||||
} query_result = {0, 0, 0, 0};
|
||||
|
||||
ntdll.invoke_pascal<NTSTATUS>("NtQueryVirtualMemory", GetCurrentProcess(), module_base, 6, &query_result,
|
||||
sizeof(query_result), nullptr);
|
||||
seh::overridden_table.ImageSize = query_result.imageSize;
|
||||
}
|
||||
|
||||
auto* base_address = ntdll.get_proc<void*>("RtlLookupFunctionTable");
|
||||
auto* internal_address = find_call_from_address(base_address);
|
||||
|
||||
void* patch_function = rtlpx_lookup_function_table_override;
|
||||
auto** patch_original = reinterpret_cast<void**>(&seh::rtlpx_lookup_function_table);
|
||||
|
||||
if (!internal_address)
|
||||
{
|
||||
if (!IsWindows8Point1OrGreater())
|
||||
{
|
||||
internal_address = find_call_from_address(base_address, UD_Ijmp);
|
||||
patch_function = rtlpx_lookup_function_table_override_down_level;
|
||||
patch_original = reinterpret_cast<void**>(&seh::rtlpx_lookup_function_table_down_level);
|
||||
}
|
||||
|
||||
if (!internal_address)
|
||||
{
|
||||
if (IsWindows8OrGreater())
|
||||
{
|
||||
// TODO: Catch the error
|
||||
}
|
||||
|
||||
internal_address = base_address;
|
||||
patch_function = rtlpx_lookup_function_table_override_down_level;
|
||||
patch_original = reinterpret_cast<void**>(&seh::rtlpx_lookup_function_table_down_level);
|
||||
}
|
||||
}
|
||||
|
||||
static utils::hook::detour hook{};
|
||||
hook = utils::hook::detour(internal_address, patch_function);
|
||||
*patch_original = hook.get_original();
|
||||
}
|
||||
}
|
38
src/client/loader/seh.hpp
Normal file
38
src/client/loader/seh.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
struct FUNCTION_TABLE_DATA
|
||||
{
|
||||
DWORD64 TableAddress;
|
||||
DWORD64 ImageBase;
|
||||
DWORD ImageSize; // field +8 in ZwQueryVirtualMemory class 6
|
||||
DWORD Size;
|
||||
};
|
||||
|
||||
typedef enum _FUNCTION_TABLE_TYPE
|
||||
{
|
||||
RF_SORTED,
|
||||
RF_UNSORTED,
|
||||
RF_CALLBACK
|
||||
} FUNCTION_TABLE_TYPE;
|
||||
|
||||
typedef struct _DYNAMIC_FUNCTION_TABLE
|
||||
{
|
||||
LIST_ENTRY Links;
|
||||
PRUNTIME_FUNCTION FunctionTable;
|
||||
LARGE_INTEGER TimeStamp;
|
||||
|
||||
ULONG_PTR MinimumAddress;
|
||||
ULONG_PTR MaximumAddress;
|
||||
ULONG_PTR BaseAddress;
|
||||
|
||||
PGET_RUNTIME_FUNCTION_CALLBACK Callback;
|
||||
PVOID Context;
|
||||
PWSTR OutOfProcessCallbackDll;
|
||||
FUNCTION_TABLE_TYPE Type;
|
||||
ULONG EntryCount;
|
||||
} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE;
|
||||
|
||||
namespace seh
|
||||
{
|
||||
void setup_handler(void* module_base, void* module_end, PRUNTIME_FUNCTION runtime_functions, DWORD entryCount);
|
||||
}
|
33
src/client/loader/tls.cpp
Normal file
33
src/client/loader/tls.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include <std_include.hpp>
|
||||
#include "tls.hpp"
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/binary_resource.hpp>
|
||||
|
||||
namespace tls
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::binary_resource tls_dll_file(TLS_DLL, "s1-mod-tlsdll.dll");
|
||||
}
|
||||
|
||||
PIMAGE_TLS_DIRECTORY allocate_tls_index()
|
||||
{
|
||||
static auto already_allocated = false;
|
||||
if (already_allocated)
|
||||
{
|
||||
throw std::runtime_error("Currently only a single allocation is supported!");
|
||||
}
|
||||
|
||||
already_allocated = true;
|
||||
|
||||
const auto dll_path = tls_dll_file.get_extracted_file();
|
||||
const auto tls_dll = utils::nt::library::load(dll_path);
|
||||
if (!tls_dll)
|
||||
{
|
||||
throw std::runtime_error("Failed to load TLS DLL");
|
||||
}
|
||||
|
||||
return reinterpret_cast<PIMAGE_TLS_DIRECTORY>(tls_dll.get_ptr() + tls_dll.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
|
||||
}
|
||||
}
|
6
src/client/loader/tls.hpp
Normal file
6
src/client/loader/tls.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace tls
|
||||
{
|
||||
PIMAGE_TLS_DIRECTORY allocate_tls_index();
|
||||
}
|
Reference in New Issue
Block a user