Skip to content

Commit

Permalink
Merge branch 'project-bo4:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Skwll committed Nov 12, 2023
2 parents b7ffdd7 + b77d42d commit d028919
Show file tree
Hide file tree
Showing 81 changed files with 1,370 additions and 455 deletions.
58 changes: 29 additions & 29 deletions source/proxy-dll/component/arxan.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"

#include <utils/hook.hpp>
#include <utils/string.hpp>
#include <utilities/hook.hpp>
#include <utilities/string.hpp>


namespace arxan
Expand All @@ -15,7 +15,7 @@ namespace arxan
{
std::vector<std::pair<uint8_t*, size_t>> texts{};

const utils::nt::library game{};
const utilities::nt::library game{};
for (const auto& section : game.get_section_headers())
{
if (section->Characteristics & IMAGE_SCN_MEM_EXECUTE)
Expand Down Expand Up @@ -95,7 +95,7 @@ namespace arxan

if (!context)
{
MessageBoxA(nullptr, utils::string::va("No frame offset for: %llX", handler_address), "Error",
MessageBoxA(nullptr, utilities::string::va("No frame offset for: %llX", handler_address), "Error",
MB_ICONERROR);
TerminateProcess(GetCurrentProcess(), 0xBAD);
return current_checksum;
Expand Down Expand Up @@ -125,11 +125,11 @@ namespace arxan

if ((next_inst & 0xFF00FFFF) != 0xFF004583)
{
throw std::runtime_error(utils::string::va("Unable to patch intact basic block: %llX", game_address));
throw std::runtime_error(utilities::string::va("Unable to patch intact basic block: %llX", game_address));
}

const auto other_frame_offset = static_cast<uint8_t>(next_inst >> 16);
static const auto stub = utils::hook::assemble([](utils::hook::assembler& a)
static const auto stub = utilities::hook::assemble([](utilities::hook::assembler& a)
{
a.push(rax);

Expand Down Expand Up @@ -164,8 +164,8 @@ namespace arxan
});

// push other_frame_offset
utils::hook::set<uint16_t>(game_address, static_cast<uint16_t>(0x6A | (other_frame_offset << 8)));
utils::hook::call(game_address + 2, stub);
utilities::hook::set<uint16_t>(game_address, static_cast<uint16_t>(0x6A | (other_frame_offset << 8)));
utilities::hook::call(game_address + 2, stub);
}

void patch_split_basic_block_integrity_check(void* address)
Expand All @@ -177,11 +177,11 @@ namespace arxan

if (*reinterpret_cast<uint8_t*>(next_inst_addr) != 0xE9)
{
throw std::runtime_error(utils::string::va("Unable to patch split basic block: %llX", game_address));
throw std::runtime_error(utilities::string::va("Unable to patch split basic block: %llX", game_address));
}

const auto jump_target = utils::hook::extract<void*>(reinterpret_cast<void*>(next_inst_addr + 1));
const auto stub = utils::hook::assemble([jump_target](utils::hook::assembler& a)
const auto jump_target = utilities::hook::extract<void*>(reinterpret_cast<void*>(next_inst_addr + 1));
const auto stub = utilities::hook::assemble([jump_target](utilities::hook::assembler& a)
{
a.push(rax);

Expand Down Expand Up @@ -209,7 +209,7 @@ namespace arxan
a.jmp(jump_target);
});

utils::hook::call(game_address, stub);
utilities::hook::call(game_address, stub);
}

void search_and_patch_integrity_checks()
Expand All @@ -235,7 +235,7 @@ namespace arxan

void** get_tls_callbacks()
{
const utils::nt::library game{};
const utilities::nt::library game{};
const auto& entry = game.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
if (!entry.VirtualAddress || !entry.Size)
{
Expand All @@ -254,25 +254,25 @@ namespace arxan
original_first_tls_callback = *tls_callbacks;
}

utils::hook::set(tls_callbacks, nullptr);
utilities::hook::set(tls_callbacks, nullptr);
}

void restore_tls_callbacks()
{
auto* tls_callbacks = get_tls_callbacks();
if (tls_callbacks)
{
utils::hook::set(tls_callbacks, original_first_tls_callback);
utilities::hook::set(tls_callbacks, original_first_tls_callback);
}
}

utils::hook::detour create_thread_hook;
utilities::hook::detour create_thread_hook;
HANDLE WINAPI create_thread_stub(const LPSECURITY_ATTRIBUTES thread_attributes, const SIZE_T stack_size,
const LPTHREAD_START_ROUTINE start_address, const LPVOID parameter,
const DWORD creation_flags,
const LPDWORD thread_id)
{
if (utils::nt::library::get_by_address(start_address) == utils::nt::library{})
if (utilities::nt::library::get_by_address(start_address) == utilities::nt::library{})
{
restore_tls_callbacks();

Expand All @@ -285,15 +285,15 @@ namespace arxan
creation_flags, thread_id);
}

utils::hook::detour get_thread_context_hook;
utilities::hook::detour get_thread_context_hook;
BOOL WINAPI get_thread_context_stub(const HANDLE thread_handle, const LPCONTEXT context)
{
constexpr auto debug_registers_flag = (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64);
if (context && (context->ContextFlags & debug_registers_flag))
{
auto* source = _ReturnAddress();
const auto game = utils::nt::library{};
const auto source_module = utils::nt::library::get_by_address(source);
const auto game = utilities::nt::library{};
const auto source_module = utilities::nt::library::get_by_address(source);

if (source_module == game)
{
Expand All @@ -304,7 +304,7 @@ namespace arxan
return get_thread_context_hook.invoke<BOOL>(thread_handle, context);
}

utils::hook::detour create_mutex_ex_a_hook;
utilities::hook::detour create_mutex_ex_a_hook;
HANDLE create_mutex_ex_a_stub(const LPSECURITY_ATTRIBUTES attributes, const LPCSTR name, const DWORD flags,
const DWORD access)
{
Expand Down Expand Up @@ -405,7 +405,7 @@ namespace arxan
return res;
}

utils::hook::detour nt_query_system_information_hook;
utilities::hook::detour nt_query_system_information_hook;
NTSTATUS NTAPI nt_query_system_information_stub(const SYSTEM_INFORMATION_CLASS system_information_class,
const PVOID system_information,
const ULONG system_information_length,
Expand All @@ -416,7 +416,7 @@ namespace arxan

if (NT_SUCCESS(status))
{
if (system_information_class == SystemProcessInformation && !utils::nt::is_shutdown_in_progress())
if (system_information_class == SystemProcessInformation && !utilities::nt::is_shutdown_in_progress())
{
auto addr = static_cast<uint8_t*>(system_information);
while (true)
Expand All @@ -437,7 +437,7 @@ namespace arxan
return status;
}

utils::hook::detour nt_query_information_process_hook;
utilities::hook::detour nt_query_information_process_hook;
NTSTATUS WINAPI nt_query_information_process_stub(const HANDLE handle, const PROCESSINFOCLASS info_class,
const PVOID info,
const ULONG info_length, const PULONG ret_length)
Expand Down Expand Up @@ -465,16 +465,16 @@ namespace arxan
disable_tls_callbacks();

create_thread_hook.create(CreateThread, create_thread_stub);
auto* get_thread_context_func = utils::nt::library("kernelbase.dll").get_proc<void*>("GetThreadContext");
auto* get_thread_context_func = utilities::nt::library("kernelbase.dll").get_proc<void*>("GetThreadContext");
get_thread_context_hook.create(get_thread_context_func, get_thread_context_stub);

create_mutex_ex_a_hook.create(CreateMutexExA, create_mutex_ex_a_stub);

utils::hook::copy(this->window_text_buffer_, GetWindowTextA, sizeof(this->window_text_buffer_));
utils::hook::jump(GetWindowTextA, get_window_text_a_stub, true, true);
utils::hook::move_hook(GetWindowTextA);
utilities::hook::copy(this->window_text_buffer_, GetWindowTextA, sizeof(this->window_text_buffer_));
utilities::hook::jump(GetWindowTextA, get_window_text_a_stub, true, true);
utilities::hook::move_hook(GetWindowTextA);

const utils::nt::library ntdll("ntdll.dll");
const utilities::nt::library ntdll("ntdll.dll");

const auto nt_query_information_process = ntdll.get_proc<void*>("NtQueryInformationProcess");
nt_query_information_process_hook.create(nt_query_information_process,
Expand Down
75 changes: 41 additions & 34 deletions source/proxy-dll/component/blackbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
#include "definitions/game.hpp"
#include "loader/component_loader.hpp"

#include <utils/hook.hpp>
#include <utils/io.hpp>
#include <utils/string.hpp>
#include <utils/thread.hpp>
#include <utils/compression.hpp>
#include <utilities/hook.hpp>
#include <utilities/io.hpp>
#include <utilities/string.hpp>
#include <utilities/thread.hpp>
#include <utilities/compression.hpp>
#include <exception/minidump.hpp>

namespace blackbox
Expand Down Expand Up @@ -64,12 +64,12 @@ namespace blackbox

void display_error_dialog()
{
const std::string error_str = utils::string::va("Fatal error (0x%08X) at 0x%p (0x%p).\n"
const std::string error_str = utilities::string::va("Fatal error (0x%08X) at 0x%p (0x%p).\n"
"A minidump has been written.\n",
exception_data.code, exception_data.address,
reverse_b(reinterpret_cast<uint64_t>(exception_data.address)));

utils::thread::suspend_other_threads();
utilities::thread::suspend_other_threads();
show_mouse_cursor();

MessageBoxA(nullptr, error_str.data(), "Project-BO4 ERROR", MB_ICONERROR);
Expand Down Expand Up @@ -98,7 +98,7 @@ namespace blackbox

size_t get_reset_state_stub()
{
static auto* stub = utils::hook::assemble([](utils::hook::assembler& a)
static auto* stub = utilities::hook::assemble([](utilities::hook::assembler& a)
{
a.sub(rsp, 0x10);
a.or_(rsp, 0x8);
Expand Down Expand Up @@ -153,19 +153,19 @@ namespace blackbox
#undef EXCEPTION_CASE
}

std::string get_memory_registers(const LPEXCEPTION_POINTERS exceptioninfo)
std::string get_memory_registers(const LPEXCEPTION_POINTERS exception_info)
{
if (IsBadReadPtr(exceptioninfo, sizeof(EXCEPTION_POINTERS)))
if (IsBadReadPtr(exception_info, sizeof(EXCEPTION_POINTERS)))
return "";

const auto* ctx = exceptioninfo->ContextRecord;
const auto* ctx = exception_info->ContextRecord;

std::string registers_scroll{};
registers_scroll.append("registers:\r\n{\r\n");

const auto x64register = [&registers_scroll](const char* key, DWORD64 value)
{
registers_scroll.append(utils::string::va("\t%s = 0x%llX\r\n", key, value));
registers_scroll.append(utilities::string::va("\t%s = 0x%llX\r\n", key, value));
};

x64register("rax", ctx->Rax);
Expand All @@ -191,29 +191,36 @@ namespace blackbox
return registers_scroll;
}

std::string get_callstack_summary(int trace_max_depth = 18)
std::string get_callstack_summary(void* exception_addr, int trace_depth = 32)
{
std::string callstack_scroll("callstack:\r\n{\r\n");
void* stack[32]; if (trace_max_depth > 32) trace_max_depth = 32;
uint16_t count = RtlCaptureStackBackTrace(1, trace_max_depth, stack, NULL);

for (uint16_t i = 0; i < count; i++)
void* backtrace_stack[32]; int backtrace_stack_size = ARRAYSIZE(backtrace_stack);
if (trace_depth > backtrace_stack_size) trace_depth = backtrace_stack_size;

size_t count = RtlCaptureStackBackTrace(0, trace_depth, backtrace_stack, NULL);

auto itr = std::find(backtrace_stack, backtrace_stack + backtrace_stack_size, exception_addr);
auto exception_start_index = std::distance(backtrace_stack, itr);

for (size_t i = exception_start_index; i < count; i++)
{
const auto prnt = utils::nt::library::get_by_address(stack[i]);
size_t rva = reinterpret_cast<uint64_t>(stack[i]) - reinterpret_cast<uint64_t>(prnt.get_ptr());
const auto from = utilities::nt::library::get_by_address(backtrace_stack[i]);
size_t rva = reinterpret_cast<uint64_t>(backtrace_stack[i]) - reinterpret_cast<uint64_t>(from.get_ptr());

if (from.get_name() == "BlackOps4.exe"s) rva += 0x140000000;

callstack_scroll.append(std::format("\t{}: {:012X}\r\n", prnt.get_name(), rva));
callstack_scroll.append(std::format("\t{}: {:012X}\r\n", from.get_name(), rva));
}
callstack_scroll.append("}");

return callstack_scroll;
return callstack_scroll.append("}");
}

std::string generate_crash_info(const LPEXCEPTION_POINTERS exceptioninfo)
{
const auto main_module = utils::nt::library{};
const auto& build_info = game::version_string;
const auto thread_id = ::GetCurrentThreadId(); // TODO: Find Thread's Name
const auto main_module = utilities::nt::library{};
const auto rip_address = exceptioninfo->ExceptionRecord->ExceptionAddress;

std::string info{};
const auto line = [&info](const std::string& text)
Expand All @@ -224,22 +231,22 @@ namespace blackbox

line(build_info + " Crash Report\r\n");

line(utils::string::va("Exception Code: 0x%08X(%s)", exceptioninfo->ExceptionRecord->ExceptionCode,
line(utilities::string::va("Exception Code: 0x%08X(%s)", exceptioninfo->ExceptionRecord->ExceptionCode,
get_exception_string(exceptioninfo->ExceptionRecord->ExceptionCode)));
line(utils::string::va("Exception Addr: 0x%llX[%s]", exceptioninfo->ExceptionRecord->ExceptionAddress,
utils::nt::library::get_by_address(exceptioninfo->ExceptionRecord->ExceptionAddress).get_name().c_str()));
line(utils::string::va("Main Module: %s[0x%llX]", main_module.get_name().c_str(), main_module.get_ptr()));
line(utils::string::va("Thread ID: %d(%s)", GetCurrentThreadId(), is_game_thread() ? "Main Thread" : "Auxiliary Threads"));
line(utilities::string::va("Exception Addr: 0x%llX[%s]", exceptioninfo->ExceptionRecord->ExceptionAddress,
utilities::nt::library::get_by_address(exceptioninfo->ExceptionRecord->ExceptionAddress).get_name().c_str()));
line(utilities::string::va("Main Module: %s[0x%llX]", main_module.get_name().c_str(), main_module.get_ptr()));
line(utilities::string::va("Thread ID: %d(%s)", GetCurrentThreadId(), is_game_thread() ? "Main Thread" : "Auxiliary Threads"));

if (exceptioninfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
line(utils::string::va("\r\nExtended Info: Attempted to %s 0x%012X",
line(utilities::string::va("\r\nExtended Info: Attempted to %s 0x%012X",
exceptioninfo->ExceptionRecord->ExceptionInformation[0] == 1 ? "write to" : "read from",
exceptioninfo->ExceptionRecord->ExceptionInformation[1]));
}

line("\r\n");
line(get_callstack_summary(18));
line(get_callstack_summary(rip_address));
line(get_memory_registers(exceptioninfo));

line("\r\nTimestamp: "s + get_timestamp());
Expand All @@ -249,10 +256,10 @@ namespace blackbox

void write_minidump(const LPEXCEPTION_POINTERS exceptioninfo)
{
const std::string crash_name = utils::string::va("minidumps/shield-crash-%s.zip",
const std::string crash_name = utilities::string::va("minidumps/shield-crash-%s.zip",
get_timestamp().data());

utils::compression::zip::archive zip_file{};
utilities::compression::zip::archive zip_file{};
zip_file.add("crash.dmp", exception::create_minidump(exceptioninfo));
zip_file.add("info.txt", generate_crash_info(exceptioninfo));
zip_file.write(crash_name, "Project-bo4 Crash Dump");
Expand Down Expand Up @@ -297,11 +304,11 @@ namespace blackbox

void pre_start() override
{
const utils::nt::library ntdll("ntdll.dll");
const utilities::nt::library ntdll("ntdll.dll");
auto* set_filter = ntdll.get_proc<void(*)(LPTOP_LEVEL_EXCEPTION_FILTER)>("RtlSetUnhandledExceptionFilter");

set_filter(exception_filter);
utils::hook::jump(set_filter, set_unhandled_exception_filter_stub);
utilities::hook::jump(set_filter, set_unhandled_exception_filter_stub);
}
};
}
Expand Down
4 changes: 2 additions & 2 deletions source/proxy-dll/component/debugging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "component/scheduler.hpp"
#include "loader/component_loader.hpp"

#include <utils/string.hpp>
#include <utilities/string.hpp>

namespace debugging
{
Expand All @@ -29,7 +29,7 @@ namespace debugging

connectionInfoString[42] = NULL;

return utils::string::va("%s", connectionInfoString);
return utilities::string::va("%s", connectionInfoString);
}

void draw_debug_info()
Expand Down
Loading

0 comments on commit d028919

Please sign in to comment.