From d4de7de768cbfd028803b429a5b773d246a45cf7 Mon Sep 17 00:00:00 2001 From: Karl Skomski Date: Thu, 28 May 2015 17:17:51 +0200 Subject: [PATCH] Add simple script loader --- hooking/Hooking.h | 5 + main.cc | 398 ++++++++++--------------------- witcher3-booster.vcxproj | 11 +- witcher3-booster.vcxproj.filters | 5 +- witcher3-classes.h | 262 ++++++++++++++++++++ enums.h => witcher3-enums.h | 0 6 files changed, 399 insertions(+), 282 deletions(-) create mode 100644 witcher3-classes.h rename enums.h => witcher3-enums.h (100%) diff --git a/hooking/Hooking.h b/hooking/Hooking.h index 6ee62a9..f9b5792 100644 --- a/hooking/Hooking.h +++ b/hooking/Hooking.h @@ -104,7 +104,12 @@ inline void nop(AddressType address, size_t length) { adjust_base(address); + DWORD oldProtect; + VirtualProtect((void*)address, length, PAGE_EXECUTE_READWRITE, &oldProtect); + memset((void*)address, 0x90, length); + + VirtualProtect((void*)address, length, oldProtect, &oldProtect); } template diff --git a/main.cc b/main.cc index c0ba2ec..166fddf 100644 --- a/main.cc +++ b/main.cc @@ -2,287 +2,95 @@ #include #include "vtable/vmthooks.h" -#include "hooking/Hooking.h" -#include "enums.h" +#include "witcher3-classes.h" HANDLE thread = nullptr; utils::VtableHook* game_hook = nullptr; void** global_debug_console = nullptr; - -class CRTTISystem; -struct CFunction; -struct CName; -struct CNameHash; -struct CEnum; - CRTTISystem* rtti_system = nullptr; void* native_globals_function_map = nullptr; +CGame** global_game = nullptr; -struct CNameHash { - uint32_t name_hash; - - CNameHash(const char* name) { - unsigned int hash = 2166136261; - - while (*name != 0) { - hash = 16777619 * (*name ^ hash); - - name++; - } - - name_hash = 16777619 * hash; - } - - CNameHash(const wchar_t* name) { - unsigned int hash = 2166136261; - - while (*name != 0) { - hash = 16777619 * (*name ^ hash); - auto next = (unsigned int)*name >> 8; - if (next) { - hash = 16777619 * (next ^ hash); +void DumpEnums() { + std::wofstream log_file; + log_file.open("global_enums_log.txt"); + + TDynArray enums; + enums.base_pointer = &enums.begin; + enums.count = 0; + enums.max = 0; + rtti_system->EnumEnums(enums); + + for (size_t i = 0; i < enums.count; i++) { + auto enum_ = *(CEnum**)(enums.base_pointer + i); + if (!enum_) continue; + + log_file << enum_->name.AsChar() << " " << std::dec << enum_->names_count << " " << std::dec << enum_->flags << " " << enum_->unknown << std::endl; + for (size_t i = 0; i < enum_->names_count; i++) { + CName name; + enum_->FindName(i, name); + if (name.pool_index) { + int value; + enum_->FindValue(name, value); + log_file << " " << name.AsChar() << " " << value << std::endl; } - - name++; } - - name_hash = 16777619 * hash; - } -}; -static hook::thiscall_stub CName_CreateNameFromHash([]() { - return hook::pattern("48 89 5C 24 ? 57 48 83 EC 20 8B DA 48 8B F9 85 D2 74 37").count(1).get(0).get(0); -}); + log_file.close(); +} +void DumpGlobalFunctions() { + std::wofstream log_file; + log_file.open("global_functions_log.txt"); + TDynArray functions; + functions.base_pointer = &functions.begin; + functions.count = 0; + functions.max = 0; + rtti_system->EnumFunctions(functions); -static hook::thiscall_stub CName_AsChar([]() { - return hook::pattern("40 53 48 83 EC 20 48 8B 05 ? ? ? ? 48 8B D9 48 85 C0 75 05 E8 ? ? ? ? 8B 13 48 8B 0D ? ? ? ? E8").count(1).get(0).get(0); -}); + CName* last_class = nullptr; -struct CName { - uint32_t pool_index; - CName() { pool_index = 0; }; - CName(CNameHash hash) { - CName_CreateNameFromHash(this, hash); - } + for (size_t i = 0; i < functions.count; i++) { + auto function = *(CFunction**)(functions.base_pointer + i); + if (!function) continue; // || !(function->flags & (1 << 8))) continue; - const wchar_t* AsChar() { - return CName_AsChar(this); - } -}; - -struct CClass { - virtual void Deconstructor(); - virtual CName& GetName(); - - char _0x0008[36]; - CName name; //0x002C -}; - -struct CProperty { - uint64_t vtable; - CClass* class_type; - CName name; //0x0010 - char _0x0014[4]; - uint64_t N23BE7CFD; //0x0018 - uint32_t N23BE7CFE; //0x0020 - uint32_t optional; //0x0024 - uint64_t N23BE7CFF; //0x0028 -}; - -struct CFunction { - uint64_t vtable; - uint64_t unknown_0; - CName name; - uint32_t flags; - uint64_t unknown_1; - uint64_t* property_array; - uint32_t argument_count; - uint32_t align_0; - uint64_t unknown_4; - uint64_t unknown_5; - uint64_t unknown_6; - uint64_t unknown_7; - uint64_t unknown_8; - uint64_t unknown_9; - uint32_t unknown_10; - uint32_t align_1; - char _CScriptCompiledCode[80]; - uint32_t registration_offset; // 0xB8 - char _0x00BC[12]; - uint64_t unknown_11; - - uint64_t* GetFunctionAddress() { - return (uint64_t*)((uint64_t)native_globals_function_map + (8 * this->registration_offset)); - } -}; - -static_assert(sizeof(CFunction) == 208, "CFunction has wrong size!"); - -static hook::thiscall_stub CRTTISystem_FindGlobalFunction([]() { - return hook::pattern("83 79 44 00 74 2E").count(1).get(0).get(0); -}); - - -struct TDynArray { - uint64_t* base_pointer; - uint32_t count; - uint32_t max; - uint64_t begin; -}; - -static hook::thiscall_stub CEnum_FindValue([]() { - return hook::pattern("83 79 24 00 74 32").count(1).get(0).get(0); -}); - -static hook::thiscall_stub CEnum_FindName([]() { - return hook::pattern("83 79 54 00 44 8B D2 ").count(1).get(0).get(0); -}); - -struct CEnum { - uint64_t vtable; - CName name; - DWORD N27E745C8; //0x000C - void* names; //0x0010 - DWORD names_count; //0x0018 - char _0x001C[4]; - DWORD value_count; //0x0020 - DWORD N27EF6229; //0x0024 - char _0x0028[24]; - void* values; //0x0040 - char _0x0048[56]; - DWORD flags; //0x0080 - BYTE unknown; //0x0084 - char _0x0085[3]; - - bool FindName(int index, CName& name) { return CEnum_FindName(this, index, name); } - int FindValue(CName& name, int& out) { return CEnum_FindValue(this, name, out); } -}; - -class CGame; - -static hook::thiscall_stub CGame_EnableFreeCamera([]() { - return hook::pattern("40 53 48 83 EC 40 48 8B D9 E8 ? ? ? ? 80 BB ? ? ? ? ?").count(1).get(0).get(0); -}); - -static hook::thiscall_stub CGame_ProcessFreeCameraInput([]() { - return hook::pattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 40 80 3D").count(1).get(0).get(0); -}); - -class CGame { -public: - void EnableFreeCamera(bool toggle) { CGame_EnableFreeCamera(this, toggle); } - bool ProcessFreeCameraInput(EInputKey key, EInputAction action, float tick) { return CGame_ProcessFreeCameraInput(this, key, action, tick); } -}; - -CGame** global_game = nullptr; + if (last_class && (!function->parent_class || (function->parent_class->GetName().pool_index != last_class->pool_index))) { + log_file << std::endl << "}" << std::endl; + last_class = nullptr; + } -static hook::thiscall_stub CRTTISystem_EnumFunctions([]() { - return hook::pattern("48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 55 41 56 41 57 48 83 EC 30 33 FF").count(1).get(0).get(0); -}); - -static hook::thiscall_stub CRTTISystem_EnumEnums([]() { - return hook::pattern("40 53 41 56 41 57 48 83 EC 30 33 DB 4C 8B F2 4C 8B F9 39 59 14").count(1).get(0).get(0); -}); - -class CRTTISystem { -public: - - CFunction* FindGlobalFunction(CName& name) { return CRTTISystem_FindGlobalFunction(this, name); } - void EnumFunctions(TDynArray& array) { CRTTISystem_EnumFunctions(this, array); } - void EnumEnums(TDynArray& array) { CRTTISystem_EnumEnums(this, array); } - - void DumpEnums() { - std::wofstream log_file; - log_file.open("global_enums_log.txt"); - - TDynArray enums; - enums.base_pointer = &enums.begin; - enums.count = 0; - enums.max = 0; - EnumEnums(enums); - - for (size_t i = 0; i < enums.count; i++) { - auto enum_ = *(CEnum**)(enums.base_pointer + i); - if (!enum_) continue; - - log_file << enum_->name.AsChar() << " " << std::dec << enum_->names_count << " " << std::dec << enum_->flags << " " << enum_->unknown << std::endl; - for (size_t i = 0; i < enum_->names_count; i++) { - CName name; - enum_->FindName(i, name); - if (name.pool_index) { - int value; - enum_->FindValue(name, value); - log_file << " " << name.AsChar() << " " << value << std::endl; - } + if (function->parent_class && !last_class) { + last_class = &function->parent_class->GetName(); + log_file << "import class " << last_class->AsChar(); + if (function->parent_class->parent) { + log_file << " extends " << function->parent_class->parent->GetName().AsChar(); } + log_file << " {" << std::endl; } - log_file.close(); - } - - void DumpGlobalFunctions() { - std::wofstream log_file; - log_file.open("global_functions_log.txt"); + if (function->parent_class) log_file << " "; - TDynArray functions; - functions.base_pointer = &functions.begin; - functions.count = 0; - functions.max = 0; - EnumFunctions(functions); - - for (size_t i = 0; i < functions.count; i++) { - auto function = *(CFunction**)(functions.base_pointer + i); - if (!function) continue; // || !(function->flags & (1 << 8))) continue; - - log_file << function->name.AsChar() << " " << std::dec << function->flags << std::endl; - for (size_t i = 0; i < function->argument_count; i++) { - auto property = (CProperty*)function->property_array[i]; - log_file << " " << property->class_type->GetName().AsChar() << " " << property->name.AsChar() << " " << property->optional << std::endl; + log_file << "import function " << function->name.AsChar() << "("; + for (size_t i = 0; i < function->argument_count; i++) { + auto property = (CProperty*)function->property_array[i]; + log_file << " " << property->name.AsChar() << " : " << property->class_type->GetName().AsChar(); + if (i + 1 != function->argument_count) + { + log_file << ", "; + } else { } } - - log_file.close(); - } -}; - -class CRTTISerializer; -class TString; - -static hook::thiscall_stub CRTTISerializer_Constructor([]() { - return hook::pattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 30 33 F6 48 8B D9 48 83 C1 28 48 89 71 D8 48 89 71 E0 48 89 71 E8 48 89 71 F0 48 89 71 F8").count(1).get(0).get(0); -}); - -static hook::thiscall_stub CRTTISerializer_LoadScriptDataFromFile([]() { - return hook::pattern("48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 4C 89 74 24 ? 55 48 8B EC 48 81 EC ? ? ? ? 48 8B F1").count(1).get(0).get(0); -}); - -class TString { -public: - wchar_t* buffer_address; - uint32_t length; - uint32_t max; - wchar_t buffer[512]; - - TString(wchar_t* string) { - buffer_address = buffer; - wcscpy_s(buffer, 512, string); - length = wcslen(string); - max = 512; - } -}; - -class CRTTISerializer { - char _0x00[1000]; -public: - CRTTISerializer() { - CRTTISerializer_Constructor(this); + log_file << ")"; + if (function->return_type) { + log_file << " : " << function->return_type->class_type->GetName().AsChar(); + } + log_file << "; " << " // flags: " << std::dec << function->flags << " "<< std::hex << function << std::endl; } - bool LoadScriptDataFromFile(TString* name, bool validate) { return CRTTISerializer_LoadScriptDataFromFile(this, name, validate); } -}; + log_file.close(); +} typedef bool(*OnViewportInputType) (void* thisptr, void* viewport, EInputKey input_key, EInputAction input_action, float tick); OnViewportInputType OnViewportInputDebugConsole = nullptr; @@ -302,15 +110,21 @@ void funcLogHook(struct CObject *a1, struct CScriptStackFrame *a2, void *a3) { OutputDebugStringW(L"test log"); } +uint64_t* GetFunctionAddress(CFunction* function) { + return (uint64_t*)((uint64_t)native_globals_function_map + (8 * function->registration_offset)); +} + void ReplaceFunction(const char* name, uint64_t address) { auto function = rtti_system->FindGlobalFunction(CName(name)); if (function) { + auto function_address = GetFunctionAddress(function); + std::wstringstream message; - message << "ReplaceFunction: " << name << " " << std::hex << function << " " << " " << std::hex << function->GetFunctionAddress(); + message << "ReplaceFunction: " << name << " " << std::hex << function << " " << " " << std::hex << function_address; OutputDebugStringW(message.str().c_str()); - *function->GetFunctionAddress() = address; + *function_address = address; } } @@ -328,19 +142,43 @@ static void ScriptError(void* thisptr, void* file_context, TString* message) { log_file.close(); } +std::wstring GetExecutablePath() { + wchar_t buffer[MAX_PATH]; + GetModuleFileName(NULL, buffer, MAX_PATH); + std::wstring::size_type pos = std::wstring(buffer).find_last_of(L"\\/"); + return std::wstring(buffer).substr(0, pos); +} + +std::vector GetAllFileNamesFromFolder(std::wstring folder) { + std::vector names; + wchar_t search_path[200]; + wsprintf(search_path, L"%s*.*", folder.c_str()); + WIN32_FIND_DATA fd; + HANDLE hFind = ::FindFirstFile(search_path, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + names.push_back(fd.cFileName); + } + } while (::FindNextFile(hFind, &fd)); + ::FindClose(hFind); + } + return names; +} + DWORD WINAPI InitializeHook(void* arguments) { hook::set_base(); HookFunction::RunAll(); - //char* location = hook::pattern("48 8D 35 ? ? ? ? 48 8D 54 24 ?").count(1).get(0).get(3); - //void* compilation_messages = reinterpret_cast(location + *(int32_t*)location + 4); + char* location_compilation = hook::pattern("48 8D 35 ? ? ? ? 48 8D 54 24 ?").count(1).get(0).get(3); + void* compilation_messages = reinterpret_cast(location_compilation + *(int32_t*)location_compilation + 4); - //DWORD old_protect; + DWORD old_protect; - //if (VirtualProtect((void*)((uint64_t)compilation_messages + 2 * 8), 16, PAGE_EXECUTE_READWRITE, &old_protect)) { - // *(uint64_t*)((uint64_t)compilation_messages + 2 * 8) = (uint64_t)&ScriptWarn; - // *(uint64_t*)((uint64_t)compilation_messages + 3 * 8) = (uint64_t)&ScriptError; - //} + if (VirtualProtect((void*)((uint64_t)compilation_messages + 2 * 8), 16, PAGE_EXECUTE_READWRITE, &old_protect)) { + *(uint64_t*)((uint64_t)compilation_messages + 2 * 8) = (uint64_t)&ScriptWarn; + *(uint64_t*)((uint64_t)compilation_messages + 3 * 8) = (uint64_t)&ScriptError; + } char* location = hook::pattern("48 8B 05 ? ? ? ? 48 8D 4C 24 ? C6 44 24").count(1).get(0).get(3); global_game = reinterpret_cast(location + *(int32_t*)location + 4); @@ -361,20 +199,36 @@ DWORD WINAPI InitializeHook(void* arguments) { location = hook::pattern("4C 8D 0D ? ? ? ? 49 89 14 C1").count(1).get(0).get(3); native_globals_function_map = reinterpret_cast(location + *(int32_t*)location + 4); + location = hook::pattern("48 8B 0D ? ? ? ? 48 8D 55 A0 41 B8").count(1).get(0).get(3); + FileManager* file_manager = *reinterpret_cast(location + *(int32_t*)location + 4); + game_hook = new utils::VtableHook(*global_game); game_hook->HookMethod(OnViewportInputDebugAlwaysHook, 128); - //CRTTISerializer serializer; - //TString path(L"x64.final.redscripts "); + location = hook::pattern("E8 ? ? ? ? FF C3 48 83 C7 10 48 83 C6 08").count(1).get(0).get(0); + hook::nop(location, 5); + + auto exe_path = GetExecutablePath(); + exe_path += L"\\scriptplugins\\"; + + auto plugin_names = GetAllFileNamesFromFolder(exe_path); - //if(serializer.LoadScriptDataFromFile(&path, false)) { - // OutputDebugStringW(L"Load custom script file"); - //}; + for (auto name : plugin_names) { + if (name.find(L".redscriptsplugin") == std::string::npos) continue; + + auto full_path = (L"..\\..\\bin\\x64\\scriptplugins\\" + name); + CRTTISerializer serializer; + TString path(full_path.c_str()); + + if (serializer.LoadScriptData(&path, false)) { + OutputDebugStringW((L"Loaded scriptplugin: " + name).c_str()); + }; + } - //rtti_system->DumpGlobalFunctions(); + //DumpGlobalFunctions(); - //rtti_system->DumpEnums(); + //DumpEnums(); //ReplaceFunction("Log", (uint64_t)&funcLogHook); //ReplaceFunction("LogChannel", (uint64_t)&funcLogHook); diff --git a/witcher3-booster.vcxproj b/witcher3-booster.vcxproj index e1281be..8d3227c 100644 --- a/witcher3-booster.vcxproj +++ b/witcher3-booster.vcxproj @@ -1,18 +1,10 @@  - - Debug - Win32 - Debug x64 - - Release - Win32 - Release x64 @@ -155,13 +147,14 @@ - + + diff --git a/witcher3-booster.vcxproj.filters b/witcher3-booster.vcxproj.filters index 60faf20..094f240 100644 --- a/witcher3-booster.vcxproj.filters +++ b/witcher3-booster.vcxproj.filters @@ -50,7 +50,10 @@ Header Files - + + Header Files + + Header Files diff --git a/witcher3-classes.h b/witcher3-classes.h new file mode 100644 index 0000000..c9689b5 --- /dev/null +++ b/witcher3-classes.h @@ -0,0 +1,262 @@ +#pragma once + +#include "hooking/Hooking.h" +#include "witcher3-enums.h" + +class CRTTISystem; +struct CFunction; +struct CName; +struct CNameHash; +struct CEnum; +class CRTTISerializer; +class TString; +class FileManager; +class File; +class CGame; + +struct CNameHash { + uint32_t name_hash; + + CNameHash(const char* name) { + unsigned int hash = 2166136261; + + while (*name != 0) { + hash = 16777619 * (*name ^ hash); + + name++; + } + + name_hash = 16777619 * hash; + } + + CNameHash(const wchar_t* name) { + unsigned int hash = 2166136261; + + while (*name != 0) { + hash = 16777619 * (*name ^ hash); + auto next = (unsigned int)*name >> 8; + if (next) { + hash = 16777619 * (next ^ hash); + } + + name++; + } + + name_hash = 16777619 * hash; + + } +}; + +static hook::thiscall_stub CName_CreateNameFromHash([]() { + return hook::pattern("48 89 5C 24 ? 57 48 83 EC 20 8B DA 48 8B F9 85 D2 74 37").count(1).get(0).get(0); +}); + + +static hook::thiscall_stub CName_AsChar([]() { + return hook::pattern("40 53 48 83 EC 20 48 8B 05 ? ? ? ? 48 8B D9 48 85 C0 75 05 E8 ? ? ? ? 8B 13 48 8B 0D ? ? ? ? E8").count(1).get(0).get(0); +}); + +struct CName { + uint32_t pool_index; + CName() { pool_index = 0; }; + CName(CNameHash hash) { + CName_CreateNameFromHash(this, hash); + } + + const wchar_t* AsChar() { + return CName_AsChar(this); + } +}; + + +static hook::thiscall_stub CEnum_FindValue([]() { + return hook::pattern("83 79 24 00 74 32").count(1).get(0).get(0); +}); + +static hook::thiscall_stub CEnum_FindName([]() { + return hook::pattern("83 79 54 00 44 8B D2 ").count(1).get(0).get(0); +}); + +struct CEnum { + uint64_t vtable; + CName name; + DWORD N27E745C8; //0x000C + void* names; //0x0010 + DWORD names_count; //0x0018 + char _0x001C[4]; + DWORD value_count; //0x0020 + DWORD N27EF6229; //0x0024 + char _0x0028[24]; + void* values; //0x0040 + char _0x0048[56]; + DWORD flags; //0x0080 + BYTE unknown; //0x0084 + char _0x0085[3]; + + bool FindName(int index, CName& name) { return CEnum_FindName(this, index, name); } + int FindValue(CName& name, int& out) { return CEnum_FindValue(this, name, out); } +}; + +struct CClass { + virtual void Deconstructor(); + virtual CName& GetName(); + + uint64_t unknown; + CClass* parent; +}; + +struct CProperty { + uint64_t vtable; + CClass* class_type; + CName name; //0x0010 + char _0x0014[4]; + uint64_t N23BE7CFD; //0x0018 + uint32_t N23BE7CFE; //0x0020 + uint32_t optional; //0x0024 + uint64_t N23BE7CFF; //0x0028 +}; + +struct CFunction { + uint64_t vtable; + CClass* parent_class; + CName name; + uint32_t flags; + CProperty* return_type; + uint64_t* property_array; + uint32_t argument_count; + uint32_t align_0; + uint64_t unknown_4; + uint64_t unknown_5; + uint64_t unknown_6; + uint64_t unknown_7; + uint64_t unknown_8; + uint64_t unknown_9; + uint32_t unknown_10; + uint32_t align_1; + char _CScriptCompiledCode[80]; + uint32_t registration_offset; // 0xB8 + char _0x00BC[12]; + uint64_t unknown_11; +}; + +static_assert(sizeof(CFunction) == 208, "CFunction has wrong size!"); + +struct TDynArray { + uint64_t* base_pointer; + uint32_t count; + uint32_t max; + uint64_t begin; +}; + +static hook::thiscall_stub TString_Constructor([]() { + char* location = hook::pattern("E8 ? ? ? ? 48 8D 54 24 ? 48 8D 4C 24 ? 41 83 CF 01").count(1).get(0).get(1); + return reinterpret_cast(location + *(int32_t*)location + 4); +}); + +class TString { +public: + wchar_t* buffer_address; + uint32_t length; + uint32_t max; + //wchar_t buffer[512]; + + TString(const wchar_t* string) { + TString_Constructor(this, string); + //buffer_address = buffer; + //wcscpy_s(buffer, 512, string); + //length = wcslen(string); + //max = 512; + } +}; + +static hook::thiscall_stub CGame_EnableFreeCamera([]() { + return hook::pattern("40 53 48 83 EC 40 48 8B D9 E8 ? ? ? ? 80 BB ? ? ? ? ?").count(1).get(0).get(0); +}); + +static hook::thiscall_stub CGame_ProcessFreeCameraInput([]() { + return hook::pattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 40 80 3D").count(1).get(0).get(0); +}); + +class CGame { +public: + void EnableFreeCamera(bool toggle) { CGame_EnableFreeCamera(this, toggle); } + bool ProcessFreeCameraInput(EInputKey key, EInputAction action, float tick) { return CGame_ProcessFreeCameraInput(this, key, action, tick); } +}; + +static hook::thiscall_stub CRTTISystem_FindGlobalFunction([]() { + return hook::pattern("83 79 44 00 74 2E").count(1).get(0).get(0); +}); + +static hook::thiscall_stub CRTTISystem_EnumFunctions([]() { + return hook::pattern("48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 55 41 56 41 57 48 83 EC 30 33 FF").count(1).get(0).get(0); +}); + +static hook::thiscall_stub CRTTISystem_EnumEnums([]() { + return hook::pattern("40 53 41 56 41 57 48 83 EC 30 33 DB 4C 8B F2 4C 8B F9 39 59 14").count(1).get(0).get(0); +}); + +class CRTTISystem { +public: + + CFunction* FindGlobalFunction(CName& name) { return CRTTISystem_FindGlobalFunction(this, name); } + void EnumFunctions(TDynArray& array) { CRTTISystem_EnumFunctions(this, array); } + void EnumEnums(TDynArray& array) { CRTTISystem_EnumEnums(this, array); } +}; + +static hook::thiscall_stub CRTTISerializer_Constructor([]() { + return hook::pattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 30 33 F6 48 8B D9 48 83 C1 28 48 89 71 D8 48 89 71 E0 48 89 71 E8 48 89 71 F0 48 89 71 F8").count(1).get(0).get(0); +}); + +static hook::thiscall_stub CRTTISerializer_LoadScriptData([]() { + return hook::pattern("48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 4C 89 74 24 ? 55 48 8B EC 48 81 EC ? ? ? ? 48 8B F1").count(1).get(0).get(0); +}); + +static hook::thiscall_stub CRTTISerializer_LoadScriptDataFromFile([]() { + return hook::pattern("40 53 55 56 57 41 54 41 57 48 83 EC 68").count(1).get(0).get(0); +}); + +class CRTTISerializer { + char _0x00[1000]; +public: + CRTTISerializer() { + CRTTISerializer_Constructor(this); + } + + bool LoadScriptData(TString* name, bool validate) { return CRTTISerializer_LoadScriptData(this, name, validate); } + bool LoadScriptDataFromFile(File* file) { return CRTTISerializer_LoadScriptDataFromFile(this, file); } +}; + +class CScriptsSerializer; + +static hook::thiscall_stub CScriptsSerializer_Constructor([]() { + return hook::pattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 30 33 F6 48 8B D9 48 83 C1 18 48 89 71 E8 48 89 71 F0 48 89 71 F8 E8 ? ? ? ? 48 89 73 30 40 88 73 38 39 73 10 74 32 48 8B 05 ? ? ? ? 48 8B 7B 18").count(1).get(0).get(0); +}); + +static hook::thiscall_stub CScriptsSerializer_LoadScript([]() { + return hook::pattern("48 89 5C 24 ? 57 48 83 EC 70 48 8B F9 48 8B 0D ? ? ? ? 33 DB").count(1).get(0).get(0); +}); + +static hook::thiscall_stub CScriptsSerializer_LoadScriptFile([]() { + return hook::pattern("40 53 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 58 48 8B 02").count(1).get(0).get(0); +}); + +class CScriptsSerializer { + char _0x00[1000]; +public: + CScriptsSerializer() { + CScriptsSerializer_Constructor(this); + } + + bool LoadScriptDataFromFile(TString* name) { return CScriptsSerializer_LoadScript(this, name); } + bool LoadScriptFile(void* file) { return CScriptsSerializer_LoadScriptFile(this, file); } +}; + +static hook::thiscall_stub FileManager_CreateFileReader([]() { + char* location = hook::pattern("E8 ? ? ? ? 48 8B F8 48 85 C0 74 32 4C 8B C6").count(1).get(0).get(1); + return reinterpret_cast(location + *(int32_t*)location + 4); +}); + +class FileManager { +public: + File* CreateFileReader(TString const& name, uint64_t flag1, uint64_t flag2) { return FileManager_CreateFileReader(this, name, flag1, flag2); } +}; diff --git a/enums.h b/witcher3-enums.h similarity index 100% rename from enums.h rename to witcher3-enums.h