From fccac400a40196d460b3a5c914d6e31a7f74ebe8 Mon Sep 17 00:00:00 2001 From: m4ko Date: Fri, 28 Aug 2026 20:33:05 +0200 Subject: [PATCH] Added native game.dll checks and fixes to combat issues with logins and spawning into the world. --- native/pt_world_fix.c | 829 ++++++++++++++++++++++++++++++++ ptlinux/native/pt-world-fix.exe | Bin 0 -> 62464 bytes 2 files changed, 829 insertions(+) create mode 100644 native/pt_world_fix.c create mode 100755 ptlinux/native/pt-world-fix.exe diff --git a/native/pt_world_fix.c b/native/pt_world_fix.c new file mode 100644 index 0000000..95d0d33 --- /dev/null +++ b/native/pt_world_fix.c @@ -0,0 +1,829 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include + + +#define GAME_DLL_MAP_ENTRY_RVA 0x007c0b40u +#define GAME_DLL_LOGIN_RETURN_RVA 0x0079f157u +#define GAME_DLL_CODE_CAVE_RVA 0x01195ce0u +#define GAME_DLL_LSTRCMPA_IAT_RVA 0x01196280u +#define GAME_DLL_VIRTUAL_PROTECT_IAT_RVA 0x01196108u +#define GAME_DLL_FLUSH_INSTRUCTION_CACHE_IAT_RVA 0x01196140u +#define GAME_DLL_GET_CURRENT_PROCESS_IAT_RVA 0x01196344u +#define GAME_DLL_MINIMUM_IMAGE_SIZE 0x01196348u + +#define REMOTE_ALLOCATION_SIZE 4096u +#define REMOTE_RECLAIM_OFFSET 0x0600u +#define REMOTE_MAP_JUMP_OFFSET 0x0680u +#define REMOTE_STATE_OFFSET 0x0700u +#define REMOTE_OLD_CAVE_PROTECT_OFFSET 0x0704u +#define REMOTE_OLD_ENTRY_PROTECT_OFFSET 0x0708u +#define REMOTE_TEMP_PROTECT_OFFSET 0x070cu + +#define WORLD_FIX_WAIT_MILLISECONDS 60000u + + +static const BYTE MAP_ENTRY_ORIGINAL[] = {0x55, 0x8b, 0xec, 0x6a, 0xff}; +static const BYTE LOGIN_COMPARE_ORIGINAL[] = { + 0x85, 0xc0, 0x0f, 0x85, 0x6b, 0x01, 0x00, 0x00, +}; +static const BYTE MAP_ENTRY_JUMP[] = {0xe9, 0x9b, 0x51, 0x9d, 0x00}; + +/* + * Exact 97-byte entity-surface reclaim routine verified for V21.75.83. + * Its relative calls and return jump are valid at GAME_DLL_CODE_CAVE_RVA. + */ +static const BYTE PROVEN_RECLAIM_HOOK[] = { + 0x9c, 0x60, 0xe8, 0x49, 0x01, 0x36, 0xff, 0x85, + 0xc0, 0x74, 0x4a, 0x89, 0xc3, 0x8d, 0x70, 0x08, + 0x8d, 0xbe, 0x50, 0x5d, 0x01, 0x00, 0x39, 0xfe, + 0x74, 0x3b, 0x80, 0xbe, 0x58, 0x03, 0x00, 0x00, + 0x00, 0x74, 0x2a, 0x8b, 0x06, 0x8b, 0x4c, 0x24, + 0x28, 0x85, 0xc9, 0x74, 0x08, 0x3b, 0x81, 0xd4, + 0x1f, 0x00, 0x00, 0x74, 0x18, 0x8b, 0x4c, 0x24, + 0x2c, 0x85, 0xc9, 0x74, 0x08, 0x3b, 0x81, 0xd4, + 0x1f, 0x00, 0x00, 0x74, 0x08, 0x50, 0x89, 0xd9, + 0xe8, 0xa3, 0x20, 0x36, 0xff, 0x81, 0xc6, 0x50, + 0x04, 0x00, 0x00, 0xeb, 0xc1, 0x61, 0x9d, 0x55, + 0x89, 0xe5, 0x6a, 0xff, 0xe9, 0x04, 0xae, 0x62, + 0xff, +}; + + +typedef struct CodeBuffer +{ + BYTE *data; + SIZE_T capacity; + SIZE_T length; + BOOL valid; +} CodeBuffer; + + +typedef struct WorldFixInstallation +{ + DWORD remote_state; + LPVOID remote_allocation; +} WorldFixInstallation; + + +static DWORD address_from_rva(DWORD base, DWORD rva) +{ + return base + rva; +} + + +static BOOL read_exact(HANDLE process, DWORD address, void *buffer, SIZE_T size) +{ + SIZE_T read_size = 0; + return ReadProcessMemory( + process, + (LPCVOID)(uintptr_t)address, + buffer, + size, + &read_size + ) && read_size == size; +} + + +static BOOL write_exact(HANDLE process, DWORD address, const void *buffer, SIZE_T size) +{ + SIZE_T written_size = 0; + return WriteProcessMemory( + process, + (LPVOID)(uintptr_t)address, + buffer, + size, + &written_size + ) && written_size == size; +} + + +static void emit_byte(CodeBuffer *code, BYTE value) +{ + if (!code->valid || code->length >= code->capacity) + { + code->valid = FALSE; + return; + } + code->data[code->length++] = value; +} + + +static void emit_dword(CodeBuffer *code, DWORD value) +{ + SIZE_T index; + for (index = 0; index < sizeof(value); ++index) + { + emit_byte(code, (BYTE)((value >> (index * 8u)) & 0xffu)); + } +} + + +static void emit_bytes(CodeBuffer *code, const BYTE *values, SIZE_T size) +{ + SIZE_T index; + for (index = 0; index < size; ++index) + { + emit_byte(code, values[index]); + } +} + + +static SIZE_T emit_near_jump_placeholder(CodeBuffer *code, BYTE condition) +{ + SIZE_T displacement_offset; + if (condition != 0) + { + emit_byte(code, 0x0f); + emit_byte(code, condition); + } + else + { + emit_byte(code, 0xe9); + } + displacement_offset = code->length; + emit_dword(code, 0); + return displacement_offset; +} + + +static void patch_near_jump(CodeBuffer *code, SIZE_T displacement_offset, SIZE_T target_offset) +{ + int32_t displacement; + if (!code->valid || displacement_offset + sizeof(displacement) > code->capacity) + { + code->valid = FALSE; + return; + } + displacement = (int32_t)(target_offset - (displacement_offset + sizeof(displacement))); + memcpy(code->data + displacement_offset, &displacement, sizeof(displacement)); +} + + +static void emit_push_immediate(CodeBuffer *code, DWORD value) +{ + emit_byte(code, 0x68); + emit_dword(code, value); +} + + +static void emit_call_iat(CodeBuffer *code, DWORD iat_address) +{ + emit_byte(code, 0xff); + emit_byte(code, 0x15); + emit_dword(code, iat_address); +} + + +static void emit_set_state(CodeBuffer *code, DWORD state_address, BYTE value) +{ + emit_byte(code, 0xc6); + emit_byte(code, 0x05); + emit_dword(code, state_address); + emit_byte(code, value); +} + + +static void emit_restore_iat( + CodeBuffer *code, + DWORD iat_address, + DWORD original_lstrcmp, + DWORD virtual_protect_iat, + DWORD original_iat_protect, + DWORD temporary_protect_address +) +{ + /* mov dword ptr [iat_address], original_lstrcmp */ + emit_byte(code, 0xc7); + emit_byte(code, 0x05); + emit_dword(code, iat_address); + emit_dword(code, original_lstrcmp); + + emit_push_immediate(code, temporary_protect_address); + emit_push_immediate(code, original_iat_protect); + emit_push_immediate(code, sizeof(DWORD)); + emit_push_immediate(code, iat_address); + emit_call_iat(code, virtual_protect_iat); +} + + +static BOOL build_remote_hook( + BYTE *image, + SIZE_T image_size, + DWORD remote_base, + DWORD game_dll_base, + DWORD original_lstrcmp, + DWORD original_iat_protect, + SIZE_T *code_size +) +{ + CodeBuffer code; + DWORD map_entry = address_from_rva(game_dll_base, GAME_DLL_MAP_ENTRY_RVA); + DWORD code_cave = address_from_rva(game_dll_base, GAME_DLL_CODE_CAVE_RVA); + DWORD login_return = address_from_rva(game_dll_base, GAME_DLL_LOGIN_RETURN_RVA); + DWORD lstrcmp_iat = address_from_rva(game_dll_base, GAME_DLL_LSTRCMPA_IAT_RVA); + DWORD virtual_protect_iat = address_from_rva( + game_dll_base, + GAME_DLL_VIRTUAL_PROTECT_IAT_RVA + ); + DWORD flush_iat = address_from_rva( + game_dll_base, + GAME_DLL_FLUSH_INSTRUCTION_CACHE_IAT_RVA + ); + DWORD get_process_iat = address_from_rva( + game_dll_base, + GAME_DLL_GET_CURRENT_PROCESS_IAT_RVA + ); + DWORD reclaim_source = remote_base + REMOTE_RECLAIM_OFFSET; + DWORD jump_source = remote_base + REMOTE_MAP_JUMP_OFFSET; + DWORD state_address = remote_base + REMOTE_STATE_OFFSET; + DWORD old_cave_protect = remote_base + REMOTE_OLD_CAVE_PROTECT_OFFSET; + DWORD old_entry_protect = remote_base + REMOTE_OLD_ENTRY_PROTECT_OFFSET; + DWORD temporary_protect = remote_base + REMOTE_TEMP_PROTECT_OFFSET; + SIZE_T nonzero_jump; + SIZE_T wrong_caller_jump; + SIZE_T already_triggered_jump; + SIZE_T cave_failure_jump; + SIZE_T entry_failure_jump; + SIZE_T success_jump; + SIZE_T finish_offset; + SIZE_T entry_failure_offset; + SIZE_T failure_offset; + SIZE_T success_offset; + + if (image_size < REMOTE_TEMP_PROTECT_OFFSET + sizeof(DWORD)) + { + return FALSE; + } + memset(image, 0, image_size); + memcpy( + image + REMOTE_RECLAIM_OFFSET, + PROVEN_RECLAIM_HOOK, + sizeof(PROVEN_RECLAIM_HOOK) + ); + memcpy(image + REMOTE_MAP_JUMP_OFFSET, MAP_ENTRY_JUMP, sizeof(MAP_ENTRY_JUMP)); + + code.data = image; + code.capacity = REMOTE_RECLAIM_OFFSET; + code.length = 0; + code.valid = TRUE; + + /* Standard-call lstrcmpA wrapper, preserving every nonvolatile register. */ + emit_bytes(&code, (const BYTE[]){0x55, 0x89, 0xe5, 0x53, 0x56, 0x57}, 6); + emit_bytes(&code, (const BYTE[]){0xff, 0x75, 0x0c, 0xff, 0x75, 0x08}, 6); + emit_byte(&code, 0xb8); + emit_dword(&code, original_lstrcmp); + emit_bytes(&code, (const BYTE[]){0xff, 0xd0, 0x85, 0xc0}, 4); + nonzero_jump = emit_near_jump_placeholder(&code, 0x85); /* jne finish */ + emit_bytes(&code, (const BYTE[]){0x81, 0x7d, 0x04}, 3); + emit_dword(&code, login_return); + wrong_caller_jump = emit_near_jump_placeholder(&code, 0x85); /* jne finish */ + emit_bytes(&code, (const BYTE[]){0x80, 0x3d}, 2); + emit_dword(&code, state_address); + emit_byte(&code, 0x00); + already_triggered_jump = emit_near_jump_placeholder(&code, 0x85); /* jne finish */ + emit_set_state(&code, state_address, 1); + + /* Make the two exact publisher-code ranges writable only after login. */ + emit_push_immediate(&code, old_cave_protect); + emit_push_immediate(&code, PAGE_EXECUTE_READWRITE); + emit_push_immediate(&code, sizeof(PROVEN_RECLAIM_HOOK)); + emit_push_immediate(&code, code_cave); + emit_call_iat(&code, virtual_protect_iat); + emit_bytes(&code, (const BYTE[]){0x85, 0xc0}, 2); + cave_failure_jump = emit_near_jump_placeholder(&code, 0x84); /* je failure */ + + emit_push_immediate(&code, old_entry_protect); + emit_push_immediate(&code, PAGE_EXECUTE_READWRITE); + emit_push_immediate(&code, sizeof(MAP_ENTRY_JUMP)); + emit_push_immediate(&code, map_entry); + emit_call_iat(&code, virtual_protect_iat); + emit_bytes(&code, (const BYTE[]){0x85, 0xc0}, 2); + entry_failure_jump = emit_near_jump_placeholder(&code, 0x84); /* je entry_failure */ + + /* Copy only after the exact account-ID comparison returned success. */ + emit_byte(&code, 0xfc); + emit_byte(&code, 0xbe); + emit_dword(&code, reclaim_source); + emit_byte(&code, 0xbf); + emit_dword(&code, code_cave); + emit_byte(&code, 0xb9); + emit_dword(&code, sizeof(PROVEN_RECLAIM_HOOK)); + emit_bytes(&code, (const BYTE[]){0xf3, 0xa4}, 2); + emit_byte(&code, 0xbe); + emit_dword(&code, jump_source); + emit_byte(&code, 0xbf); + emit_dword(&code, map_entry); + emit_byte(&code, 0xb9); + emit_dword(&code, sizeof(MAP_ENTRY_JUMP)); + emit_bytes(&code, (const BYTE[]){0xf3, 0xa4}, 2); + + /* x86 is coherent, but use the publisher's own imports for an explicit flush. */ + emit_call_iat(&code, get_process_iat); + emit_push_immediate(&code, 0); + emit_push_immediate(&code, 0); + emit_byte(&code, 0x50); + emit_call_iat(&code, flush_iat); + + /* Restore publisher section protections after the five-byte entry change. */ + emit_push_immediate(&code, temporary_protect); + emit_bytes(&code, (const BYTE[]){0xff, 0x35}, 2); + emit_dword(&code, old_entry_protect); + emit_push_immediate(&code, sizeof(MAP_ENTRY_JUMP)); + emit_push_immediate(&code, map_entry); + emit_call_iat(&code, virtual_protect_iat); + emit_push_immediate(&code, temporary_protect); + emit_bytes(&code, (const BYTE[]){0xff, 0x35}, 2); + emit_dword(&code, old_cave_protect); + emit_push_immediate(&code, sizeof(PROVEN_RECLAIM_HOOK)); + emit_push_immediate(&code, code_cave); + emit_call_iat(&code, virtual_protect_iat); + + emit_restore_iat( + &code, + lstrcmp_iat, + original_lstrcmp, + virtual_protect_iat, + original_iat_protect, + temporary_protect + ); + emit_set_state(&code, state_address, 2); + success_jump = emit_near_jump_placeholder(&code, 0); /* jmp finish */ + + entry_failure_offset = code.length; + emit_push_immediate(&code, temporary_protect); + emit_bytes(&code, (const BYTE[]){0xff, 0x35}, 2); + emit_dword(&code, old_cave_protect); + emit_push_immediate(&code, sizeof(PROVEN_RECLAIM_HOOK)); + emit_push_immediate(&code, code_cave); + emit_call_iat(&code, virtual_protect_iat); + + failure_offset = code.length; + emit_restore_iat( + &code, + lstrcmp_iat, + original_lstrcmp, + virtual_protect_iat, + original_iat_protect, + temporary_protect + ); + emit_set_state(&code, state_address, 3); + + success_offset = code.length; + emit_bytes(&code, (const BYTE[]){0x31, 0xc0}, 2); /* successful lstrcmpA result */ + finish_offset = code.length; + emit_bytes(&code, (const BYTE[]){0x5f, 0x5e, 0x5b, 0x89, 0xec, 0x5d, 0xc2, 0x08, 0x00}, 9); + + patch_near_jump(&code, nonzero_jump, finish_offset); + patch_near_jump(&code, wrong_caller_jump, finish_offset); + patch_near_jump(&code, already_triggered_jump, success_offset); + patch_near_jump(&code, cave_failure_jump, failure_offset); + patch_near_jump(&code, entry_failure_jump, entry_failure_offset); + patch_near_jump(&code, success_jump, success_offset); + + if (!code.valid) + { + return FALSE; + } + *code_size = code.length; + return TRUE; +} + + +static DWORD find_game_dll(DWORD process_id, DWORD *module_size) +{ + HANDLE snapshot; + MODULEENTRY32W module; + DWORD result = 0; + + snapshot = CreateToolhelp32Snapshot( + TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, + process_id + ); + if (snapshot == INVALID_HANDLE_VALUE) + { + return 0; + } + memset(&module, 0, sizeof(module)); + module.dwSize = sizeof(module); + if (Module32FirstW(snapshot, &module)) + { + do + { + if (_wcsicmp(module.szModule, L"game.dll") == 0) + { + result = (DWORD)(uintptr_t)module.modBaseAddr; + *module_size = module.modBaseSize; + break; + } + } + while (Module32NextW(snapshot, &module)); + } + CloseHandle(snapshot); + return result; +} + + +static DWORD wait_for_game_dll( + HANDLE process, + DWORD process_id, + DWORD *module_size +) +{ + ULONGLONG deadline = GetTickCount64() + WORLD_FIX_WAIT_MILLISECONDS; + DWORD base; + while (GetTickCount64() < deadline) + { + if (WaitForSingleObject(process, 25) == WAIT_OBJECT_0) + { + return 0; + } + base = find_game_dll(process_id, module_size); + if (base != 0) + { + return base; + } + Sleep(10); + } + return 0; +} + + +static BOOL verify_game_dll_memory(HANDLE process, DWORD base, DWORD module_size) +{ + BYTE map_entry[sizeof(MAP_ENTRY_ORIGINAL)]; + BYTE login_compare[sizeof(LOGIN_COMPARE_ORIGINAL)]; + BYTE code_cave[sizeof(PROVEN_RECLAIM_HOOK)]; + DWORD iat_values[4]; + + if (module_size < GAME_DLL_MINIMUM_IMAGE_SIZE) + { + return FALSE; + } + if (!read_exact( + process, + address_from_rva(base, GAME_DLL_MAP_ENTRY_RVA), + map_entry, + sizeof(map_entry) + ) || memcmp(map_entry, MAP_ENTRY_ORIGINAL, sizeof(map_entry)) != 0) + { + return FALSE; + } + if (!read_exact( + process, + address_from_rva(base, GAME_DLL_LOGIN_RETURN_RVA), + login_compare, + sizeof(login_compare) + ) || memcmp(login_compare, LOGIN_COMPARE_ORIGINAL, sizeof(login_compare)) != 0) + { + return FALSE; + } + if (!read_exact( + process, + address_from_rva(base, GAME_DLL_CODE_CAVE_RVA), + code_cave, + sizeof(code_cave) + )) + { + return FALSE; + } + for (SIZE_T index = 0; index < sizeof(code_cave); ++index) + { + if (code_cave[index] != 0) + { + return FALSE; + } + } + if (!read_exact( + process, + address_from_rva(base, GAME_DLL_VIRTUAL_PROTECT_IAT_RVA), + &iat_values[0], + sizeof(iat_values[0]) + ) || !read_exact( + process, + address_from_rva(base, GAME_DLL_FLUSH_INSTRUCTION_CACHE_IAT_RVA), + &iat_values[1], + sizeof(iat_values[1]) + ) || !read_exact( + process, + address_from_rva(base, GAME_DLL_GET_CURRENT_PROCESS_IAT_RVA), + &iat_values[2], + sizeof(iat_values[2]) + ) || !read_exact( + process, + address_from_rva(base, GAME_DLL_LSTRCMPA_IAT_RVA), + &iat_values[3], + sizeof(iat_values[3]) + )) + { + return FALSE; + } + return iat_values[0] != 0 && iat_values[1] != 0 + && iat_values[2] != 0 && iat_values[3] != 0; +} + + +static BOOL install_world_fix( + HANDLE process, + DWORD game_dll_base, + WorldFixInstallation *installation +) +{ + BYTE remote_image[REMOTE_ALLOCATION_SIZE]; + DWORD original_lstrcmp; + DWORD original_iat_protect; + DWORD hook_address; + DWORD lstrcmp_iat = address_from_rva( + game_dll_base, + GAME_DLL_LSTRCMPA_IAT_RVA + ); + LPVOID remote; + SIZE_T code_size; + + if (!read_exact( + process, + lstrcmp_iat, + &original_lstrcmp, + sizeof(original_lstrcmp) + )) + { + return FALSE; + } + remote = VirtualAllocEx( + process, + NULL, + REMOTE_ALLOCATION_SIZE, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE + ); + if (remote == NULL) + { + return FALSE; + } + if (!build_remote_hook( + remote_image, + sizeof(remote_image), + (DWORD)(uintptr_t)remote, + game_dll_base, + original_lstrcmp, + PAGE_READONLY, + &code_size + )) + { + VirtualFreeEx(process, remote, 0, MEM_RELEASE); + return FALSE; + } + if (!write_exact( + process, + (DWORD)(uintptr_t)remote, + remote_image, + sizeof(remote_image) + )) + { + VirtualFreeEx(process, remote, 0, MEM_RELEASE); + return FALSE; + } + if (!VirtualProtectEx( + process, + (LPVOID)(uintptr_t)lstrcmp_iat, + sizeof(DWORD), + PAGE_READWRITE, + &original_iat_protect + )) + { + VirtualFreeEx(process, remote, 0, MEM_RELEASE); + return FALSE; + } + + /* Rebuild so the callback restores the exact protection returned above. */ + if (!build_remote_hook( + remote_image, + sizeof(remote_image), + (DWORD)(uintptr_t)remote, + game_dll_base, + original_lstrcmp, + original_iat_protect, + &code_size + ) || !write_exact( + process, + (DWORD)(uintptr_t)remote, + remote_image, + sizeof(remote_image) + )) + { + DWORD ignored; + VirtualProtectEx( + process, + (LPVOID)(uintptr_t)lstrcmp_iat, + sizeof(DWORD), + original_iat_protect, + &ignored + ); + VirtualFreeEx(process, remote, 0, MEM_RELEASE); + return FALSE; + } + hook_address = (DWORD)(uintptr_t)remote; + if (!write_exact(process, lstrcmp_iat, &hook_address, sizeof(hook_address))) + { + DWORD ignored; + VirtualProtectEx( + process, + (LPVOID)(uintptr_t)lstrcmp_iat, + sizeof(DWORD), + original_iat_protect, + &ignored + ); + VirtualFreeEx(process, remote, 0, MEM_RELEASE); + return FALSE; + } + FlushInstructionCache(process, remote, code_size); + installation->remote_state = (DWORD)(uintptr_t)remote + REMOTE_STATE_OFFSET; + installation->remote_allocation = remote; + return TRUE; +} + + +static DWORD wait_for_game_and_report( + HANDLE process, + const WorldFixInstallation *installation +) +{ + BOOL reported = FALSE; + for (;;) + { + DWORD wait_result = WaitForSingleObject(process, 100); + if (wait_result == WAIT_OBJECT_0) + { + DWORD exit_code = 1; + GetExitCodeProcess(process, &exit_code); + return exit_code; + } + if (!reported && installation->remote_state != 0) + { + BYTE state = 0; + if (read_exact(process, installation->remote_state, &state, sizeof(state))) + { + if (state == 2) + { + fprintf( + stderr, + "PTWORLD: login accepted; world-transition fix activated in memory.\n" + ); + reported = TRUE; + } + else if (state == 3) + { + fprintf( + stderr, + "PTWORLD: login succeeded, but the verified memory fix could not be activated.\n" + ); + reported = TRUE; + } + } + } + } +} + + +static int run_self_test(void) +{ + BYTE image[REMOTE_ALLOCATION_SIZE]; + SIZE_T code_size = 0; + if (!build_remote_hook( + image, + sizeof(image), + 0x50000000u, + 0x10000000u, + 0x7b621000u, + PAGE_READONLY, + &code_size + ) || code_size == 0 || code_size >= REMOTE_RECLAIM_OFFSET) + { + fprintf(stderr, "PTWORLD-SELFTEST: remote hook construction failed.\n"); + return 1; + } + if (memcmp( + image + REMOTE_RECLAIM_OFFSET, + PROVEN_RECLAIM_HOOK, + sizeof(PROVEN_RECLAIM_HOOK) + ) != 0 || memcmp( + image + REMOTE_MAP_JUMP_OFFSET, + MAP_ENTRY_JUMP, + sizeof(MAP_ENTRY_JUMP) + ) != 0 || image[REMOTE_STATE_OFFSET] != 0) + { + fprintf(stderr, "PTWORLD-SELFTEST: remote payload layout failed.\n"); + return 1; + } + fprintf( + stdout, + "PTWORLD-SELFTEST: ok; remote code=%lu bytes.\n", + (unsigned long)code_size + ); + return 0; +} + + +int wmain(int argument_count, wchar_t **arguments) +{ + STARTUPINFOW startup; + PROCESS_INFORMATION process; + WorldFixInstallation installation; + WCHAR game_path[MAX_PATH]; + WCHAR command_line[MAX_PATH + 64]; + DWORD game_dll_base; + DWORD game_dll_size = 0; + DWORD exit_code; + DWORD path_length; + + if ( + argument_count == 2 + && wcscmp(arguments[1], L"--self-test") == 0 + ) + { + return run_self_test(); + } + memset(&startup, 0, sizeof(startup)); + memset(&process, 0, sizeof(process)); + memset(&installation, 0, sizeof(installation)); + startup.cb = sizeof(startup); + path_length = GetFullPathNameW(L"Game.exe", MAX_PATH, game_path, NULL); + if (path_length == 0 || path_length >= MAX_PATH) + { + fprintf(stderr, "PTWORLD: Game.exe is not available in the working directory.\n"); + return 111; + } + if (swprintf( + command_line, + MAX_PATH + 64, + L"\"%ls\" PTEU_REBORN", + game_path + ) < 0) + { + fprintf(stderr, "PTWORLD: could not construct the game command line.\n"); + return 111; + } + if (!CreateProcessW( + game_path, + command_line, + NULL, + NULL, + TRUE, + 0, + NULL, + NULL, + &startup, + &process + )) + { + fprintf( + stderr, + "PTWORLD: could not start Game.exe (Windows error %lu).\n", + (unsigned long)GetLastError() + ); + return 111; + } + CloseHandle(process.hThread); + + game_dll_base = wait_for_game_dll( + process.hProcess, + process.dwProcessId, + &game_dll_size + ); + if (game_dll_base == 0) + { + fprintf( + stderr, + "PTWORLD: game.dll was not available for verification; continuing pristine.\n" + ); + } + else if (!verify_game_dll_memory(process.hProcess, game_dll_base, game_dll_size)) + { + fprintf( + stderr, + "PTWORLD: game.dll memory did not match V21.75.83; continuing pristine.\n" + ); + } + else if (!install_world_fix(process.hProcess, game_dll_base, &installation)) + { + fprintf( + stderr, + "PTWORLD: the post-login hook could not be armed; continuing pristine.\n" + ); + } + else + { + fprintf( + stderr, + "PTWORLD: publisher game.dll verified; post-login world fix armed.\n" + ); + } + + exit_code = wait_for_game_and_report(process.hProcess, &installation); + CloseHandle(process.hProcess); + return (int)exit_code; +} diff --git a/ptlinux/native/pt-world-fix.exe b/ptlinux/native/pt-world-fix.exe new file mode 100755 index 0000000000000000000000000000000000000000..cbe14c0abbf8775624abfb973513a03a9bc898e7 GIT binary patch literal 62464 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