Finish process wrapper

This commit is contained in:
momo5502 2022-11-09 18:10:34 +01:00
parent c0be5d7cad
commit 908d480e59
14 changed files with 389 additions and 147 deletions

View File

@ -19,8 +19,8 @@ Reverse engineering and analysis of Call of Duty: Black Ops 3. Very experimental
- [x] Disable Integrity Checks
- [x] Demonware Emulation
- [ ] Disable Anti-Debugging Mechanisms (probably never gonna happen cause who needs that if you have printf debugging)
- [x] Process wrapper
- [x] P2P multiplayer
- [ ] Process hollowing loader
- [ ] Dedicated Servers
## Disclaimer

View File

@ -285,10 +285,10 @@ project "common"
dependencies.imports()
project "client"
kind "SharedLib"
kind "WindowedApp"
language "C++"
targetname "d3d11"
targetname "boiii"
pchheader "std_include.hpp"
pchsource "src/client/std_include.cpp"
@ -311,6 +311,18 @@ project "client"
dependencies.imports()
project "tlsdll"
kind "SharedLib"
language "C++"
files {"./src/tlsdll/**.rc", "./src/tlsdll/**.hpp", "./src/tlsdll/**.cpp", "./src/tlsdll/resources/**.*"}
includedirs {"./src/tlsdll", "%{prj.location}/src"}
links {"common"}
resincludedirs {"$(ProjectDir)src"}
project "runner"
kind "WindowedApp"

View File

@ -384,7 +384,7 @@ namespace arxan
{
continue;
}
if (!loaded)
{
memcpy(buffers[i], func, sizeof(buffer));
@ -698,14 +698,11 @@ namespace arxan
class component final : public component_interface
{
public:
component()
void pre_start() override
{
auto* dll_characteristics = &utils::nt::library().get_optional_header()->DllCharacteristics;
utils::hook::set<WORD>(dll_characteristics, *dll_characteristics | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE);
}
void pre_start() override
{
disable_tls_callbacks();
restore_debug_functions();

View File

@ -18,13 +18,13 @@ namespace game
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x1420EC8B0};
WEAK symbol<void(const char* cmdName, xcommand_t function, cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{
0x1420ED530_g
0x1420ED530
};
WEAK symbol<void(char* text, int maxSize)> Con_GetTextCopy{0x14133A7D0};
// DB
WEAK symbol<void(XZoneInfo* zoneInfo, uint32_t zoneCount, bool sync, bool suppressSync)> DB_LoadXAssets{
0x1414236A0_g
0x1414236A0
};
// Live
@ -50,12 +50,12 @@ namespace game
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetDebugName{0x1422BDCB0};
WEAK symbol<const char*(const dvar_t* dvar)> Dvar_GetString{0x1422BFFF0};
WEAK symbol<void(const char* dvarName, const char* string, bool createIfMissing)> Dvar_SetFromStringByName{
0x1422C7F60_g
0x1422C7F60
};
// Rendering
WEAK symbol<void(const char*, int, void*, float, float, float, float, float, float*, int)> R_AddCmdDrawText{
0x141CD98D0_g
0x141CD98D0
};
// Variables

View File

@ -138,8 +138,16 @@ std::vector<std::unique_ptr<component_interface>>& component_loader::get_compone
size_t get_base()
{
static auto base = size_t(utils::nt::library{}.get_ptr());
assert(base && "Failed to resolve base");
static auto base = []
{
const utils::nt::library host{};
if(!host || host == utils::nt::library::get_by_address(get_base))
{
throw std::runtime_error("Invalid host application");
}
return size_t(host.get_ptr());
}();
return base;
}

View File

@ -0,0 +1,118 @@
#include <std_include.hpp>
#include "loader.hpp"
#include "tls.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
namespace loader
{
namespace
{
void load_imports(const utils::nt::library& target)
{
const auto* const import_directory = &target.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
{
const auto* import = PIMAGE_IMPORT_BY_NAME(target.get_ptr() + *name_table_entry);
function_name = import->Name;
function_procname = function_name.data();
}
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 load_tls(const utils::nt::library& target)
{
if (target.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size)
{
auto* target_tls = tls::allocate_tls_index();
const auto* const source_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(target.get_ptr() + target.
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);
if (target_tls->AddressOfCallBacks)
{
utils::hook::set<void*>(target_tls->AddressOfCallBacks, nullptr);
}
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;
}
}
}
utils::nt::library load_binary(const std::string& filename)
{
const auto target = utils::nt::library::load(filename);
if (!target)
{
throw std::runtime_error{"Failed to map binary!"};
}
load_imports(target);
load_tls(target);
return target;
}
}

View File

@ -0,0 +1,7 @@
#pragma once
#include <utils/nt.hpp>
namespace loader
{
utils::nt::library load_binary(const std::string& filename);
}

42
src/client/loader/tls.cpp Normal file
View File

@ -0,0 +1,42 @@
#include <std_include.hpp>
#include "tls.hpp"
#include <utils/nt.hpp>
#include <utils/binary_resource.hpp>
#include "resource.hpp"
namespace tls
{
namespace
{
utils::binary_resource tls_dll_file(TLS_DLL, "boiii-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");
}
const auto tls_dir_entry = tls_dll.get_optional_header()
->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress;
if (!tls_dir_entry)
{
throw std::runtime_error("TLS DLL is invalid");
}
return reinterpret_cast<PIMAGE_TLS_DIRECTORY>(tls_dll.get_ptr() + tls_dir_entry);
}
}

View File

@ -0,0 +1,6 @@
#pragma once
namespace tls
{
PIMAGE_TLS_DIRECTORY allocate_tls_index();
}

View File

@ -1,6 +1,7 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "loader/loader.hpp"
#include <utils/finally.hpp>
#include <utils/hook.hpp>
@ -11,6 +12,7 @@
namespace
{
volatile bool g_call_tls_callbacks = false;
std::pair<void**, void*> g_original_import{};
DECLSPEC_NORETURN void WINAPI exit_hook(const uint32_t code)
@ -84,8 +86,61 @@ namespace
utils::io::remove_file(game_path.generic_string());
}
bool run()
PIMAGE_TLS_CALLBACK* get_tls_callbacks()
{
const utils::nt::library game{};
const auto& entry = game.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
if (!entry.VirtualAddress || !entry.Size)
{
return nullptr;
}
const auto* tls_dir = reinterpret_cast<IMAGE_TLS_DIRECTORY*>(game.get_ptr() + entry.VirtualAddress);
return reinterpret_cast<PIMAGE_TLS_CALLBACK*>(tls_dir->AddressOfCallBacks);
}
void run_tls_callbacks(const DWORD reason)
{
if (!g_call_tls_callbacks)
{
return;
}
auto* callback = get_tls_callbacks();
while (callback && *callback)
{
(*callback)(GetModuleHandleA(nullptr), reason, nullptr);
++callback;
}
}
[[maybe_unused]] thread_local struct tls_runner
{
tls_runner()
{
run_tls_callbacks(DLL_THREAD_ATTACH);
}
~tls_runner()
{
run_tls_callbacks(DLL_THREAD_DETACH);
}
} tls_runner;
FARPROC load_process(const std::string& procname)
{
const auto proc = loader::load_binary(procname);
auto* const peb = reinterpret_cast<PPEB>(__readgsqword(0x60));
peb->Reserved3[1] = proc.get_ptr();
static_assert(offsetof(PEB, Reserved3[1]) == 0x10);
return FARPROC(proc.get_ptr() + proc.get_relative_entry_point());
}
int main()
{
FARPROC entry_point{};
srand(uint32_t(time(nullptr)) ^ ~(GetTickCount() * GetCurrentProcessId()));
{
@ -100,12 +155,19 @@ namespace
try
{
patch_imports();
remove_crash_file();
entry_point = load_process("BlackOps3.exe");
if (!entry_point)
{
throw std::runtime_error("Unable to load binary into memory");
}
patch_imports();
if (!component_loader::pre_start())
{
return false;
return 1;
}
premature_shutdown = false;
@ -113,141 +175,17 @@ namespace
catch (std::exception& e)
{
MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR);
return false;
return 1;
}
}
return true;
}
class patch
{
public:
patch() = default;
patch(void* source, void* target)
: source_(source)
{
memcpy(this->data_, source, sizeof(this->data_));
utils::hook::jump(this->source_, target, true, true);
}
~patch()
{
if (source_)
{
utils::hook::copy(this->source_, this->data_, sizeof(this->data_));
}
}
patch(patch&& obj) noexcept
: patch()
{
this->operator=(std::move(obj));
}
patch& operator=(patch&& obj) noexcept
{
if (this != &obj)
{
this->~patch();
this->source_ = obj.source_;
memcpy(this->data_, obj.data_, sizeof(this->data_));
obj.source_ = nullptr;
}
return *this;
}
private:
void* source_{nullptr};
uint8_t data_[15]{};
};
std::vector<patch> initialization_hooks{};
uint8_t* get_entry_point()
{
const utils::nt::library game{};
return game.get_ptr() + game.get_optional_header()->AddressOfEntryPoint;
}
std::vector<uint8_t*> get_tls_callbacks()
{
const utils::nt::library game{};
const auto& entry = game.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
if (!entry.VirtualAddress || !entry.Size)
{
return {};
}
const auto* tls_dir = reinterpret_cast<IMAGE_TLS_DIRECTORY*>(game.get_ptr() + entry.VirtualAddress);
auto* callback = reinterpret_cast<uint8_t**>(tls_dir->AddressOfCallBacks);
std::vector<uint8_t*> addresses{};
while (callback && *callback)
{
addresses.emplace_back(*callback);
++callback;
}
return addresses;
}
int patch_main()
{
if (!run())
{
return 1;
}
initialization_hooks.clear();
return reinterpret_cast<int(*)()>(get_entry_point())();
}
void nullsub()
{
}
void patch_entry_point()
{
initialization_hooks.emplace_back(get_entry_point(), patch_main);
for (auto* tls_callback : get_tls_callbacks())
{
initialization_hooks.emplace_back(tls_callback, nullsub);
}
g_call_tls_callbacks = true;
return static_cast<int>(entry_point());
}
}
BOOL WINAPI DllMain(HINSTANCE, const DWORD reason, LPVOID)
int __stdcall WinMain(HINSTANCE, HINSTANCE, PSTR, int)
{
if (reason == DLL_PROCESS_ATTACH)
{
patch_entry_point();
}
return TRUE;
}
extern "C" __declspec(dllexport)
HRESULT D3D11CreateDevice(void* adapter, const uint64_t driver_type,
const HMODULE software, const UINT flags,
const void* p_feature_levels, const UINT feature_levels,
const UINT sdk_version, void** device, void* feature_level,
void** immediate_context)
{
static auto func = []
{
char dir[MAX_PATH]{0};
GetSystemDirectoryA(dir, sizeof(dir));
const auto d3d11 = utils::nt::library::load(dir + "/d3d11.dll"s);
return d3d11.get_proc<decltype(&D3D11CreateDevice)>("D3D11CreateDevice");
}();
return func(adapter, driver_type, software, flags, p_feature_levels, feature_levels, sdk_version, device,
feature_level, immediate_context);
return main();
}

View File

@ -13,3 +13,4 @@
#define DW_QOSCONFIG 307
#define RUNNER 308
#define TLS_DLL 309

View File

@ -108,6 +108,12 @@ RUNNER RCDATA "../../build/bin/x64/Debug/runner.exe"
RUNNER RCDATA "../../build/bin/x64/Release/runner.exe"
#endif
#ifdef _DEBUG
TLS_DLL RCDATA "../../build/bin/x64/Debug/tlsdll.dll"
#else
TLS_DLL RCDATA "../../build/bin/x64/Release/tlsdll.dll"
#endif
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////

7
src/tlsdll/dllmain.cpp Normal file
View File

@ -0,0 +1,7 @@
#define TLS_PAYLOAD_SIZE 0x2000
thread_local char tls_data[TLS_PAYLOAD_SIZE];
__declspec(dllexport) void* get_tls_data()
{
return &tls_data[0];
}

100
src/tlsdll/resource.rc Normal file
View File

@ -0,0 +1,100 @@
// Microsoft Visual C++ generated resource script.
//
#pragma code_page(65001)
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"#include ""windows.h""\r\n"
"\0"
END
2 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "X Labs"
VALUE "FileDescription", "TLS index allocation dll"
VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", "TLS DLL"
VALUE "LegalCopyright", "All rights reserved."
VALUE "OriginalFilename", "tlsdll.dll"
VALUE "ProductName", "tlsdll"
VALUE "ProductVersion", "1.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Binary Data
//
// Nothing here
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED