From 63d9cfd68c2d2ee7184f4b6245281a524e9919d9 Mon Sep 17 00:00:00 2001 From: Raony Reis <75029692+raonygamer@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:21:31 -0300 Subject: [PATCH 1/8] Basic dependency order system! --- src/Zenova/Helper.cpp | 2 +- src/Zenova/Profile/Manager.cpp | 45 ++++++++++++++++++++-------------- src/Zenova/Profile/Manager.h | 1 + src/Zenova/Profile/ModInfo.cpp | 37 +++++++++++++++++++++++----- src/Zenova/Profile/ModInfo.h | 14 +++++++++-- 5 files changed, 72 insertions(+), 27 deletions(-) diff --git a/src/Zenova/Helper.cpp b/src/Zenova/Helper.cpp index 507ae90..c8965a7 100644 --- a/src/Zenova/Helper.cpp +++ b/src/Zenova/Helper.cpp @@ -26,7 +26,7 @@ namespace Zenova { bool run = (PlatformImpl::Init(platformArgs) && !manager.dataFolder.empty()); if (run) { - logger.info("Zenova Started"); + logger.info("Zenova Started (Dev)"); logger.info("ZenovaData Location: {}", manager.dataFolder); logger.info("Minecraft's Version: {}", Minecraft::version().toString()); diff --git a/src/Zenova/Profile/Manager.cpp b/src/Zenova/Profile/Manager.cpp index 09020e6..bcd67bb 100644 --- a/src/Zenova/Profile/Manager.cpp +++ b/src/Zenova/Profile/Manager.cpp @@ -92,24 +92,7 @@ namespace Zenova { mods.reserve(profile.modNames.size()); for (auto& modName : profile.modNames) { - logger.info("Loading {}", modName); - - // todo: verify path - std::string folder = manager.dataFolder + "\\mods\\" + modName + "\\"; - ModInfo mod(folder); - - if (mod.mHandle) { - ModContext ctx = { folder }; - CALL_MOD_FUNC(mod, ModLoad, ctx); - - PackManager::addMod(folder); - - mods.push_back(std::move(mod)); - } - else { - logger.warn("Failed to load {}", mod.mName); - Platform::ErrorPrinter(); - } + loadMod(modName); } } @@ -119,6 +102,32 @@ namespace Zenova { load(profile); } + void Manager::loadMod(const std::string& modName) + { + if (std::find_if(mods.begin(), mods.end(), + [&modName](const ModInfo& mod) { return mod.mNameId == modName; }) != mods.end()) + return; + + logger.info("Loading {}", modName); + + // todo: verify path + std::string folder = manager.dataFolder + "\\mods\\" + modName + "\\"; + ModInfo mod(folder); + + if (mod.loadModule()) { + ModContext ctx = { folder }; + CALL_MOD_FUNC(mod, ModLoad, ctx) + + PackManager::addMod(folder); + + mods.push_back(std::move(mod)); + } + else { + logger.warn("Failed to load {}", mod.mName); + Platform::ErrorPrinter(); + } + } + std::string Manager::getVersion() { return launched.versionId; } diff --git a/src/Zenova/Profile/Manager.h b/src/Zenova/Profile/Manager.h index bca62f4..8a8dee6 100644 --- a/src/Zenova/Profile/Manager.h +++ b/src/Zenova/Profile/Manager.h @@ -28,6 +28,7 @@ namespace Zenova { void update(); void load(const ProfileInfo& profile); void swap(const ProfileInfo& profile); + void loadMod(const std::string& modName); std::string getVersion(); size_t getModCount(); diff --git a/src/Zenova/Profile/ModInfo.cpp b/src/Zenova/Profile/ModInfo.cpp index dd4bb56..6ad4bb2 100644 --- a/src/Zenova/Profile/ModInfo.cpp +++ b/src/Zenova/Profile/ModInfo.cpp @@ -8,27 +8,52 @@ #include "Zenova/JsonHelper.h" namespace Zenova { - ModInfo::ModInfo(const std::string& modFolder) { - json::Document modDocument = JsonHelper::OpenFile(modFolder + "modinfo.json"); + ModInfo::ModInfo(const std::string& modFolder) : + mModFolder(modFolder) + { + json::Document modDocument = JsonHelper::OpenFile(mModFolder + "modinfo.json"); if(!modDocument.IsNull()) { mNameId = JsonHelper::FindString(modDocument, "nameId"); mName = JsonHelper::FindString(modDocument, "name"); mDescription = JsonHelper::FindString(modDocument, "description"); mVersion = JsonHelper::FindString(modDocument, "version"); - - mHandle = Platform::LoadModule(modFolder + mNameId); + auto& dependenciesObject = JsonHelper::FindMember(modDocument, "dependencies", false); + if (!dependenciesObject.IsNull() && dependenciesObject.IsArray()) + { + for (auto& object : dependenciesObject.GetArray()) + { + mDependencies.push_back(object.GetString()); + } + } } } ModInfo::ModInfo(ModInfo&& mod) noexcept : mHandle(std::exchange(mod.mHandle, nullptr)), + mModFolder(std::move(mod.mModFolder)), mNameId(std::move(mod.mNameId)), mName(std::move(mod.mName)), mDescription(std::move(mod.mDescription)), - mVersion(std::move(mod.mVersion)) + mVersion(std::move(mod.mVersion)), + mDependencies(std::move(mod.mDependencies)) {} ModInfo::~ModInfo() { if(mHandle) Platform::CloseModule(mHandle); } -} \ No newline at end of file + + void* ModInfo::loadModule() + { + loadDependencies(); + mHandle = Platform::LoadModule(mModFolder + mNameId); + return mHandle; + } + + void ModInfo::loadDependencies() const + { + for (auto& dependencyName : mDependencies) + { + manager.loadMod(dependencyName); + } + } +} diff --git a/src/Zenova/Profile/ModInfo.h b/src/Zenova/Profile/ModInfo.h index 0d70a89..54194d7 100644 --- a/src/Zenova/Profile/ModInfo.h +++ b/src/Zenova/Profile/ModInfo.h @@ -1,18 +1,28 @@ #pragma once #include +#include #include +#include "Zenova/Minecraft/Version.h" + namespace Zenova { class Mod; struct ModInfo { void* mHandle = nullptr; - std::string mNameId, mName = "", mDescription = ""; + std::string mModFolder = ""; + std::string mNameId = ""; + std::string mName = ""; + std::string mDescription = ""; std::string mVersion = ""; + std::vector mDependencies = {}; ModInfo(const std::string& modFolder); ModInfo(ModInfo&&) noexcept; ~ModInfo(); + + void* loadModule(); + void loadDependencies() const; }; -} \ No newline at end of file +} From 21cb8ab79c6628983beab72dfdbd1609a98ec553 Mon Sep 17 00:00:00 2001 From: Raony Reis <75029692+raonygamer@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:57:44 -0300 Subject: [PATCH 2/8] Removed "(Dev)" from Helper.cpp --- src/Zenova/Helper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Zenova/Helper.cpp b/src/Zenova/Helper.cpp index c8965a7..972cd35 100644 --- a/src/Zenova/Helper.cpp +++ b/src/Zenova/Helper.cpp @@ -26,7 +26,7 @@ namespace Zenova { bool run = (PlatformImpl::Init(platformArgs) && !manager.dataFolder.empty()); if (run) { - logger.info("Zenova Started (Dev)"); + logger.info("Zenova Started"); logger.info("ZenovaData Location: {}", manager.dataFolder); logger.info("Minecraft's Version: {}", Minecraft::version().toString()); @@ -59,4 +59,4 @@ namespace Zenova { PlatformImpl::Destroy(); return 0; } -} \ No newline at end of file +} From a4a2d29514bf64972ce0cb8ee44c655673620fb5 Mon Sep 17 00:00:00 2001 From: Raony Reis <75029692+raonygamer@users.noreply.github.com> Date: Mon, 29 Jan 2024 00:21:27 -0300 Subject: [PATCH 3/8] Dependency work and manual module import table resolver No need to specify the dependency array anymore, the import resolver will automatically load the dependency mod if it isn't loaded and populate the (Import Address Table) with the right addresses from the GetProcAddress with the names from the (Import Lookup Table) of the mod dll. --- inc/Zenova/Mod.h | 6 +++ inc/Zenova/Platform.h | 4 ++ {src => inc}/Zenova/Profile/ModInfo.h | 5 +- src/Zenova/Hooks/InputHooks.h | 4 +- src/Zenova/Mod.cpp | 7 +++ src/Zenova/Platform/Windows.cpp | 78 +++++++++++++++++++++++++++ src/Zenova/Profile/Manager.cpp | 14 +++-- src/Zenova/Profile/Manager.h | 5 +- src/Zenova/Profile/ModInfo.cpp | 24 ++------- src/Zenova/Utils/Memory.cpp | 14 +++++ src/Zenova/Utils/Memory.h | 8 +++ src/dllmain.cpp | 5 +- 12 files changed, 141 insertions(+), 33 deletions(-) rename {src => inc}/Zenova/Profile/ModInfo.h (84%) create mode 100644 src/Zenova/Mod.cpp create mode 100644 src/Zenova/Utils/Memory.cpp create mode 100644 src/Zenova/Utils/Memory.h diff --git a/inc/Zenova/Mod.h b/inc/Zenova/Mod.h index 3280deb..6e2d19f 100644 --- a/inc/Zenova/Mod.h +++ b/inc/Zenova/Mod.h @@ -1,8 +1,10 @@ #pragma once #include +#include #include "Common.h" +#include "Zenova/Profile/ModInfo.h" #define MOD_FUNCTION extern "C" __declspec(dllexport) @@ -10,6 +12,10 @@ struct EXPORT ModContext { std::string folder; }; +namespace Zenova { + EXPORT std::vector& GetMods(); +} + // Define any/all of these functions // Called when the Mod is loaded diff --git a/inc/Zenova/Platform.h b/inc/Zenova/Platform.h index b47dd6f..fea451e 100644 --- a/inc/Zenova/Platform.h +++ b/inc/Zenova/Platform.h @@ -22,6 +22,8 @@ namespace Zenova { Execute = 8 }; + struct ModInfo; + inline ProtectionFlags operator|(ProtectionFlags a, ProtectionFlags b) { return static_cast(enum_cast(a) | enum_cast(b)); } @@ -45,6 +47,8 @@ namespace Zenova { static uintptr_t GetModuleBaseAddress(const std::wstring& modName); static u32 GetModuleSize(const char*); static void* LoadModule(const std::string& module); + static void* LoadModModuleAndResolveImports(const ModInfo& modInfo, const std::string& module); + static void ResolveModModuleImports(const ModInfo& modInfo, void* hModule, const std::string& moduleName); static bool CloseModule(void*); static void* GetModuleFunction(void* module, const std::string& function); diff --git a/src/Zenova/Profile/ModInfo.h b/inc/Zenova/Profile/ModInfo.h similarity index 84% rename from src/Zenova/Profile/ModInfo.h rename to inc/Zenova/Profile/ModInfo.h index 54194d7..7c170f7 100644 --- a/src/Zenova/Profile/ModInfo.h +++ b/inc/Zenova/Profile/ModInfo.h @@ -16,13 +16,12 @@ namespace Zenova { std::string mName = ""; std::string mDescription = ""; std::string mVersion = ""; - std::vector mDependencies = {}; - +#ifdef ZENOVA_API ModInfo(const std::string& modFolder); ModInfo(ModInfo&&) noexcept; ~ModInfo(); void* loadModule(); - void loadDependencies() const; +#endif }; } diff --git a/src/Zenova/Hooks/InputHooks.h b/src/Zenova/Hooks/InputHooks.h index bd8a853..6a6363f 100644 --- a/src/Zenova/Hooks/InputHooks.h +++ b/src/Zenova/Hooks/InputHooks.h @@ -92,7 +92,7 @@ namespace Zenova { static void (*__handleDuplicates)(ControlsSettingsScreenController*, RemappingLayout&); void _handleDuplicates(ControlsSettingsScreenController* self, RemappingLayout& a2) {} - + inline void createInputHooks() { Zenova_Hook(MinecraftInputHandler::_registerInputHandlers, &_registerInputHandlers, &__registerInputHandlers); @@ -102,7 +102,7 @@ namespace Zenova { Zenova_Hook(VanillaClientInputMappingFactory::_populateGamepadDefaults, &_populateGamepadDefaults, &__populateGamepadDefaults); Zenova_Hook(VanillaClientInputMappingFactory::_addFullKeyboardGamePlayControls, &_addFullKeyboardGamePlayControls, &__addFullKeyboardGamePlayControls); Zenova_Hook(VanillaClientInputMappingFactory::_addInvariantGamePlayGameControllerControls, &_addInvariantGamePlayGameControllerControls, &__addInvariantGamePlayGameControllerControls); - Zenova_Hook(ControlsSettingsScreenController::_handleDuplicates, &_handleDuplicates, &__handleDuplicates); + } } \ No newline at end of file diff --git a/src/Zenova/Mod.cpp b/src/Zenova/Mod.cpp new file mode 100644 index 0000000..a5498b7 --- /dev/null +++ b/src/Zenova/Mod.cpp @@ -0,0 +1,7 @@ +#include "Zenova/Mod.h" +#include "Zenova/Globals.h" + +EXPORT std::vector& Zenova::GetMods() +{ + return manager.getMods(); +} \ No newline at end of file diff --git a/src/Zenova/Platform/Windows.cpp b/src/Zenova/Platform/Windows.cpp index 2373bb0..48b476e 100644 --- a/src/Zenova/Platform/Windows.cpp +++ b/src/Zenova/Platform/Windows.cpp @@ -22,9 +22,16 @@ #include "Zenova.h" #include "Zenova/Globals.h" #include "Zenova/Utils/Utils.h" +#include "Zenova/Utils/Memory.h" #include "MinHook.h" +#if 0 +#define ZenovaDLog(severity, format, ...) logger.write(severity, format, __VA_ARGS__) +#else +#define ZenovaDLog(severity, format, ...) +#endif + namespace Zenova::PlatformImpl { inline void* CleanupVariables = nullptr; inline FILE* console = nullptr; @@ -196,6 +203,77 @@ namespace Zenova { return LoadLibraryA((module + ".dll").c_str()); } + + + void* Platform::LoadModModuleAndResolveImports(const ModInfo& modInfo, const std::string& module) + { + void* hModule = LoadLibraryExA((module + ".dll").c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES); + ResolveModModuleImports(modInfo, hModule, module); + return hModule; + } + + typedef BOOL(APIENTRY* DllMainFunction)(HMODULE, DWORD, LPVOID); + void Platform::ResolveModModuleImports(const ModInfo& modInfo, void* hModule, const std::string& moduleName) + { + IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)hModule; + IMAGE_NT_HEADERS* pNTHeaders = (IMAGE_NT_HEADERS*)((BYTE*)pDOSHeader + pDOSHeader->e_lfanew); + IMAGE_DATA_DIRECTORY importDir = pNTHeaders->OptionalHeader.DataDirectory[1]; + IMAGE_IMPORT_DESCRIPTOR* imports = reinterpret_cast((uintptr_t)hModule + importDir.VirtualAddress); + + while (imports->Characteristics != 0) { + PIMAGE_THUNK_DATA thunkILT = (PIMAGE_THUNK_DATA)((uintptr_t)hModule + imports->OriginalFirstThunk); + PIMAGE_THUNK_DATA thunkIAT = (PIMAGE_THUNK_DATA)((uintptr_t)hModule + imports->FirstThunk); + LPCSTR moduleName = reinterpret_cast((uintptr_t)hModule + imports->Name); + std::string importModNameId(moduleName); + { + size_t dot = importModNameId.find_last_of('.'); + if (dot != std::string::npos) { + importModNameId = importModNameId.substr(0, dot); + } + } + + std::unordered_map iatAddresses{}; + while (thunkILT->u1.AddressOfData != 0) { + if (!(thunkILT->u1.Ordinal & IMAGE_ORDINAL_FLAG)) { + PIMAGE_IMPORT_BY_NAME nameData = + reinterpret_cast((uintptr_t)hModule + thunkILT->u1.AddressOfData); + + iatAddresses.insert({ nameData->Name, &thunkIAT->u1.Function }); + } + thunkILT++; + thunkIAT++; + } + + uintptr_t moduleBase = Platform::GetModuleBaseAddress(moduleName); + if (!moduleBase) { + moduleBase = (uintptr_t)manager.loadMod(importModNameId); + if (moduleBase) + ZenovaDLog(Log::Severity::Info, "Loaded {} earlier because {} depends on it.", importModNameId, modInfo.mNameId); + else + moduleBase = (uintptr_t)LoadLibraryA(moduleName); + } + + if (moduleBase != 0) { + for (auto& [name, address] : iatAddresses) { + FARPROC proc = (FARPROC)Platform::GetModuleFunction((void*)moduleBase, name.c_str()); + if (proc) { + Memory::WriteOnProtectedAddress(address, &proc, sizeof(ULONGLONG)); + } + } + } + else { + ZenovaDLog(Log::Severity::Error, "Could not load the IAT {}::{} because the dependency or module {} doesn't exist.", modInfo.mNameId, importModNameId, importModNameId); + } + + imports++; + } + + DllMainFunction dllMain = reinterpret_cast((uintptr_t)hModule + pNTHeaders->OptionalHeader.AddressOfEntryPoint); + if (dllMain) { + dllMain((HMODULE)hModule, DLL_PROCESS_ATTACH, nullptr); + } + } + bool Platform::CloseModule(void* module) { return FreeLibrary(reinterpret_cast(module)); } diff --git a/src/Zenova/Profile/Manager.cpp b/src/Zenova/Profile/Manager.cpp index bcd67bb..96182a9 100644 --- a/src/Zenova/Profile/Manager.cpp +++ b/src/Zenova/Profile/Manager.cpp @@ -102,32 +102,40 @@ namespace Zenova { load(profile); } - void Manager::loadMod(const std::string& modName) + void* Manager::loadMod(const std::string& modName) { if (std::find_if(mods.begin(), mods.end(), [&modName](const ModInfo& mod) { return mod.mNameId == modName; }) != mods.end()) - return; + return nullptr; logger.info("Loading {}", modName); // todo: verify path std::string folder = manager.dataFolder + "\\mods\\" + modName + "\\"; ModInfo mod(folder); + void* modHandle = mod.loadModule(); - if (mod.loadModule()) { + if (modHandle) { ModContext ctx = { folder }; CALL_MOD_FUNC(mod, ModLoad, ctx) PackManager::addMod(folder); mods.push_back(std::move(mod)); + return modHandle; } else { logger.warn("Failed to load {}", mod.mName); Platform::ErrorPrinter(); + return nullptr; } } + std::vector& Manager::getMods() + { + return mods; + } + std::string Manager::getVersion() { return launched.versionId; } diff --git a/src/Zenova/Profile/Manager.h b/src/Zenova/Profile/Manager.h index 8a8dee6..4b0f196 100644 --- a/src/Zenova/Profile/Manager.h +++ b/src/Zenova/Profile/Manager.h @@ -5,7 +5,7 @@ #include #include "ProfileInfo.h" -#include "ModInfo.h" +#include "Zenova/Profile/ModInfo.h" namespace Zenova { class Manager { @@ -28,7 +28,8 @@ namespace Zenova { void update(); void load(const ProfileInfo& profile); void swap(const ProfileInfo& profile); - void loadMod(const std::string& modName); + void* loadMod(const std::string& modName); + std::vector& getMods(); std::string getVersion(); size_t getModCount(); diff --git a/src/Zenova/Profile/ModInfo.cpp b/src/Zenova/Profile/ModInfo.cpp index 6ad4bb2..65db5e1 100644 --- a/src/Zenova/Profile/ModInfo.cpp +++ b/src/Zenova/Profile/ModInfo.cpp @@ -1,4 +1,4 @@ -#include "ModInfo.h" +#include "Zenova/Profile/ModInfo.h" #include #include @@ -17,14 +17,6 @@ namespace Zenova { mName = JsonHelper::FindString(modDocument, "name"); mDescription = JsonHelper::FindString(modDocument, "description"); mVersion = JsonHelper::FindString(modDocument, "version"); - auto& dependenciesObject = JsonHelper::FindMember(modDocument, "dependencies", false); - if (!dependenciesObject.IsNull() && dependenciesObject.IsArray()) - { - for (auto& object : dependenciesObject.GetArray()) - { - mDependencies.push_back(object.GetString()); - } - } } } @@ -34,8 +26,7 @@ namespace Zenova { mNameId(std::move(mod.mNameId)), mName(std::move(mod.mName)), mDescription(std::move(mod.mDescription)), - mVersion(std::move(mod.mVersion)), - mDependencies(std::move(mod.mDependencies)) + mVersion(std::move(mod.mVersion)) {} ModInfo::~ModInfo() { @@ -44,16 +35,7 @@ namespace Zenova { void* ModInfo::loadModule() { - loadDependencies(); - mHandle = Platform::LoadModule(mModFolder + mNameId); + mHandle = Platform::LoadModModuleAndResolveImports(*this, mModFolder + mNameId); return mHandle; } - - void ModInfo::loadDependencies() const - { - for (auto& dependencyName : mDependencies) - { - manager.loadMod(dependencyName); - } - } } diff --git a/src/Zenova/Utils/Memory.cpp b/src/Zenova/Utils/Memory.cpp new file mode 100644 index 0000000..f0597d7 --- /dev/null +++ b/src/Zenova/Utils/Memory.cpp @@ -0,0 +1,14 @@ +#include "Memory.h" +#include "Windows.h" + +namespace Zenova { + void Memory::WriteOnProtectedAddress(void* address, void* data, size_t size) { + if (!address || !data || !size) + return; + + DWORD old = 0; + VirtualProtect(address, size, PAGE_EXECUTE_READWRITE, &old); + memcpy_s(address, size, data, size); + VirtualProtect(address, size, old, NULL); + } +} \ No newline at end of file diff --git a/src/Zenova/Utils/Memory.h b/src/Zenova/Utils/Memory.h new file mode 100644 index 0000000..b94a316 --- /dev/null +++ b/src/Zenova/Utils/Memory.h @@ -0,0 +1,8 @@ +#pragma once + +namespace Zenova { + class Memory { + public: + static void WriteOnProtectedAddress(void* address, void* data, size_t dataSize); + }; +} \ No newline at end of file diff --git a/src/dllmain.cpp b/src/dllmain.cpp index acb67cf..00df408 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -1,14 +1,16 @@ // // This is for the Windows version of Zenova // - #include #include "Zenova/Platform.h" #include "Zenova/Helper.h" #include "generated/initcpp.h" +#include "Zenova/Log.h" +#include "winnt.h" DWORD WINAPI call_run(LPVOID args) { + return Zenova::run(); } @@ -16,7 +18,6 @@ BOOL APIENTRY DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { // avoid being attached to anything besides Minecraft Win10 if ((fdwReason == DLL_PROCESS_ATTACH) && Zenova::Platform::GetMinecraftBaseAddress()) { InitBedrockPointers(); - auto args = reinterpret_cast(hinstDLL); // block run till everything is initialized if (Zenova::start(args)) { From dc05143c7759b7469eb3236a5891b6226901dcc0 Mon Sep 17 00:00:00 2001 From: Raony Reis <75029692+raonygamer@users.noreply.github.com> Date: Mon, 29 Jan 2024 00:46:35 -0300 Subject: [PATCH 4/8] Update ModInfo.cpp --- src/Zenova/Profile/ModInfo.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Zenova/Profile/ModInfo.cpp b/src/Zenova/Profile/ModInfo.cpp index af3bb8f..65db5e1 100644 --- a/src/Zenova/Profile/ModInfo.cpp +++ b/src/Zenova/Profile/ModInfo.cpp @@ -26,8 +26,7 @@ namespace Zenova { mNameId(std::move(mod.mNameId)), mName(std::move(mod.mName)), mDescription(std::move(mod.mDescription)), - mVersion(std::move(mod.mVersion)), - mDependencies(std::move(mod.mDependencies)) + mVersion(std::move(mod.mVersion)) {} ModInfo::~ModInfo() { From a1e826c5c64385eff814d630adbb130c274cd842 Mon Sep 17 00:00:00 2001 From: Raony Reis <75029692+raonygamer@users.noreply.github.com> Date: Mon, 29 Jan 2024 13:15:23 -0300 Subject: [PATCH 5/8] Update Platform::ResolveModModuleImports Added some error handling, fixed the error of DllMain being called even if there is no DllMain, and changed the C-style casts to be reinterpret_casts --- src/Zenova/Platform/Windows.cpp | 113 ++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 48 deletions(-) diff --git a/src/Zenova/Platform/Windows.cpp b/src/Zenova/Platform/Windows.cpp index 48b476e..4eed10c 100644 --- a/src/Zenova/Platform/Windows.cpp +++ b/src/Zenova/Platform/Windows.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "Zenova.h" #include "Zenova/Globals.h" @@ -26,12 +27,6 @@ #include "MinHook.h" -#if 0 -#define ZenovaDLog(severity, format, ...) logger.write(severity, format, __VA_ARGS__) -#else -#define ZenovaDLog(severity, format, ...) -#endif - namespace Zenova::PlatformImpl { inline void* CleanupVariables = nullptr; inline FILE* console = nullptr; @@ -215,62 +210,84 @@ namespace Zenova { typedef BOOL(APIENTRY* DllMainFunction)(HMODULE, DWORD, LPVOID); void Platform::ResolveModModuleImports(const ModInfo& modInfo, void* hModule, const std::string& moduleName) { - IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)hModule; - IMAGE_NT_HEADERS* pNTHeaders = (IMAGE_NT_HEADERS*)((BYTE*)pDOSHeader + pDOSHeader->e_lfanew); - IMAGE_DATA_DIRECTORY importDir = pNTHeaders->OptionalHeader.DataDirectory[1]; - IMAGE_IMPORT_DESCRIPTOR* imports = reinterpret_cast((uintptr_t)hModule + importDir.VirtualAddress); + if (!hModule) { + throw std::invalid_argument(fmt::format("[{}] Could not resolve the imports for the module because it was nullptr.", __FUNCTION__)); + Platform::DebugPause(); + return; + } + uintptr_t hModuleAddress = reinterpret_cast(hModule); + PIMAGE_DOS_HEADER dosHeader = reinterpret_cast(hModuleAddress); + PIMAGE_NT_HEADERS ntHeader = reinterpret_cast(hModuleAddress + dosHeader->e_lfanew); + + IMAGE_DATA_DIRECTORY importDir = ntHeader->OptionalHeader.DataDirectory[1]; + PIMAGE_IMPORT_DESCRIPTOR imports = reinterpret_cast(hModuleAddress + importDir.VirtualAddress); + if (!imports) { + throw std::exception(fmt::format("[{}] Could not resolve the imports for the module because the imports data directory could not be found in the PE.", __FUNCTION__).c_str()); + Platform::DebugPause(); + return; + } + + std::map, ULONGLONG*> symbolTableAddresses; while (imports->Characteristics != 0) { - PIMAGE_THUNK_DATA thunkILT = (PIMAGE_THUNK_DATA)((uintptr_t)hModule + imports->OriginalFirstThunk); - PIMAGE_THUNK_DATA thunkIAT = (PIMAGE_THUNK_DATA)((uintptr_t)hModule + imports->FirstThunk); - LPCSTR moduleName = reinterpret_cast((uintptr_t)hModule + imports->Name); - std::string importModNameId(moduleName); - { - size_t dot = importModNameId.find_last_of('.'); - if (dot != std::string::npos) { - importModNameId = importModNameId.substr(0, dot); + PIMAGE_THUNK_DATA importLookupTable = reinterpret_cast(hModuleAddress + imports->OriginalFirstThunk); + PIMAGE_THUNK_DATA importAddressTable = reinterpret_cast(hModuleAddress + imports->FirstThunk); + + if (imports->OriginalFirstThunk && imports->FirstThunk) { + LPCSTR moduleName = reinterpret_cast(hModuleAddress + imports->Name); + std::string importModNameId(moduleName); + { + size_t dot = importModNameId.find_last_of('.'); + if (dot != std::string::npos) { + importModNameId = importModNameId.substr(0, dot); + } } - } - - std::unordered_map iatAddresses{}; - while (thunkILT->u1.AddressOfData != 0) { - if (!(thunkILT->u1.Ordinal & IMAGE_ORDINAL_FLAG)) { - PIMAGE_IMPORT_BY_NAME nameData = - reinterpret_cast((uintptr_t)hModule + thunkILT->u1.AddressOfData); - iatAddresses.insert({ nameData->Name, &thunkIAT->u1.Function }); + uintptr_t moduleBase = Platform::GetModuleBaseAddress(moduleName); + if (!moduleBase) { + moduleBase = (uintptr_t)manager.loadMod(importModNameId); + if (!moduleBase) + moduleBase = (uintptr_t)LoadLibraryA(moduleName); } - thunkILT++; - thunkIAT++; - } - uintptr_t moduleBase = Platform::GetModuleBaseAddress(moduleName); - if (!moduleBase) { - moduleBase = (uintptr_t)manager.loadMod(importModNameId); - if (moduleBase) - ZenovaDLog(Log::Severity::Info, "Loaded {} earlier because {} depends on it.", importModNameId, modInfo.mNameId); - else - moduleBase = (uintptr_t)LoadLibraryA(moduleName); - } + while (importLookupTable->u1.AddressOfData != 0) { + if (!(importLookupTable->u1.Ordinal & IMAGE_ORDINAL_FLAG)) { + PIMAGE_IMPORT_BY_NAME nameData = + reinterpret_cast(hModuleAddress + importLookupTable->u1.AddressOfData); - if (moduleBase != 0) { - for (auto& [name, address] : iatAddresses) { - FARPROC proc = (FARPROC)Platform::GetModuleFunction((void*)moduleBase, name.c_str()); - if (proc) { - Memory::WriteOnProtectedAddress(address, &proc, sizeof(ULONGLONG)); + symbolTableAddresses.insert({ { moduleBase, nameData->Name }, &(importAddressTable->u1.Function) }); } + importLookupTable++; + importAddressTable++; } } - else { - ZenovaDLog(Log::Severity::Error, "Could not load the IAT {}::{} because the dependency or module {} doesn't exist.", modInfo.mNameId, importModNameId, importModNameId); - } imports++; } + + for (auto& [infos, function] : symbolTableAddresses) { + auto& [moduleBase, entrySymbol] = infos; + if (moduleBase) { + ULONGLONG procAddress = reinterpret_cast( + Platform::GetModuleFunction(reinterpret_cast(moduleBase), entrySymbol.c_str())); + + if (procAddress && function) { + Memory::WriteOnProtectedAddress(function, &procAddress, sizeof(ULONGLONG)); + } + } + else { + throw std::exception(fmt::format("[{}] Could not resolve the address for '{}' because the module could not be loaded.", __FUNCTION__, entrySymbol).c_str()); + Platform::DebugPause(); + return; + } + } - DllMainFunction dllMain = reinterpret_cast((uintptr_t)hModule + pNTHeaders->OptionalHeader.AddressOfEntryPoint); - if (dllMain) { - dllMain((HMODULE)hModule, DLL_PROCESS_ATTACH, nullptr); + if (ntHeader->OptionalHeader.AddressOfEntryPoint) { + reinterpret_cast(hModuleAddress + ntHeader->OptionalHeader.AddressOfEntryPoint)( + reinterpret_cast(hModule), + DLL_PROCESS_ATTACH, + nullptr + ); } } From c14603240108d97c0a22ceaad3a2cc12e94d6c2e Mon Sep 17 00:00:00 2001 From: Raony Reis <75029692+raonygamer@users.noreply.github.com> Date: Mon, 29 Jan 2024 18:34:55 -0300 Subject: [PATCH 6/8] Fixed the requested changes on "MinecraftZenova/ZenovaAPI#20" --- inc/Zenova/Mod.h | 6 - inc/Zenova/Platform.h | 2 - src/Zenova/Hooks/InputHooks.h | 4 +- src/Zenova/Mod.cpp | 7 - src/Zenova/Platform/PlatformImpl.h | 2 + src/Zenova/Platform/Windows.cpp | 184 +++++++++++++------------- src/Zenova/Profile/ModInfo.cpp | 2 +- {inc => src}/Zenova/Profile/ModInfo.h | 0 src/dllmain.cpp | 5 +- 9 files changed, 98 insertions(+), 114 deletions(-) delete mode 100644 src/Zenova/Mod.cpp rename {inc => src}/Zenova/Profile/ModInfo.h (100%) diff --git a/inc/Zenova/Mod.h b/inc/Zenova/Mod.h index 6e2d19f..3280deb 100644 --- a/inc/Zenova/Mod.h +++ b/inc/Zenova/Mod.h @@ -1,10 +1,8 @@ #pragma once #include -#include #include "Common.h" -#include "Zenova/Profile/ModInfo.h" #define MOD_FUNCTION extern "C" __declspec(dllexport) @@ -12,10 +10,6 @@ struct EXPORT ModContext { std::string folder; }; -namespace Zenova { - EXPORT std::vector& GetMods(); -} - // Define any/all of these functions // Called when the Mod is loaded diff --git a/inc/Zenova/Platform.h b/inc/Zenova/Platform.h index fea451e..dd7944c 100644 --- a/inc/Zenova/Platform.h +++ b/inc/Zenova/Platform.h @@ -47,8 +47,6 @@ namespace Zenova { static uintptr_t GetModuleBaseAddress(const std::wstring& modName); static u32 GetModuleSize(const char*); static void* LoadModule(const std::string& module); - static void* LoadModModuleAndResolveImports(const ModInfo& modInfo, const std::string& module); - static void ResolveModModuleImports(const ModInfo& modInfo, void* hModule, const std::string& moduleName); static bool CloseModule(void*); static void* GetModuleFunction(void* module, const std::string& function); diff --git a/src/Zenova/Hooks/InputHooks.h b/src/Zenova/Hooks/InputHooks.h index 6a6363f..bd8a853 100644 --- a/src/Zenova/Hooks/InputHooks.h +++ b/src/Zenova/Hooks/InputHooks.h @@ -92,7 +92,7 @@ namespace Zenova { static void (*__handleDuplicates)(ControlsSettingsScreenController*, RemappingLayout&); void _handleDuplicates(ControlsSettingsScreenController* self, RemappingLayout& a2) {} - + inline void createInputHooks() { Zenova_Hook(MinecraftInputHandler::_registerInputHandlers, &_registerInputHandlers, &__registerInputHandlers); @@ -102,7 +102,7 @@ namespace Zenova { Zenova_Hook(VanillaClientInputMappingFactory::_populateGamepadDefaults, &_populateGamepadDefaults, &__populateGamepadDefaults); Zenova_Hook(VanillaClientInputMappingFactory::_addFullKeyboardGamePlayControls, &_addFullKeyboardGamePlayControls, &__addFullKeyboardGamePlayControls); Zenova_Hook(VanillaClientInputMappingFactory::_addInvariantGamePlayGameControllerControls, &_addInvariantGamePlayGameControllerControls, &__addInvariantGamePlayGameControllerControls); + Zenova_Hook(ControlsSettingsScreenController::_handleDuplicates, &_handleDuplicates, &__handleDuplicates); - } } \ No newline at end of file diff --git a/src/Zenova/Mod.cpp b/src/Zenova/Mod.cpp deleted file mode 100644 index a5498b7..0000000 --- a/src/Zenova/Mod.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "Zenova/Mod.h" -#include "Zenova/Globals.h" - -EXPORT std::vector& Zenova::GetMods() -{ - return manager.getMods(); -} \ No newline at end of file diff --git a/src/Zenova/Platform/PlatformImpl.h b/src/Zenova/Platform/PlatformImpl.h index a8e9d43..36d4af7 100644 --- a/src/Zenova/Platform/PlatformImpl.h +++ b/src/Zenova/Platform/PlatformImpl.h @@ -6,5 +6,7 @@ namespace Zenova { namespace PlatformImpl { bool Init(void*); void Destroy(); + void* LoadModModuleAndResolveImports(const std::string& module); + void ResolveModModuleImports(void* hModule, const std::string& moduleName); } } \ No newline at end of file diff --git a/src/Zenova/Platform/Windows.cpp b/src/Zenova/Platform/Windows.cpp index 4eed10c..0f2aa9e 100644 --- a/src/Zenova/Platform/Windows.cpp +++ b/src/Zenova/Platform/Windows.cpp @@ -89,6 +89,97 @@ namespace Zenova::PlatformImpl { FreeLibraryAndExitThread(reinterpret_cast(CleanupVariables), 0); } } + + void* LoadModModuleAndResolveImports(const std::string& module) + { + void* hModule = LoadLibraryExA(module.c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES); + ResolveModModuleImports(hModule, module); + return hModule; + } + + typedef BOOL(APIENTRY* DllMainFunction)(HMODULE, DWORD, LPVOID); + void ResolveModModuleImports(void* hModule, const std::string& moduleName) + { + if (!hModule) { + throw std::invalid_argument(fmt::format("[{}] Could not resolve the imports for the module because it was nullptr.", __FUNCTION__)); + Platform::DebugPause(); + return; + } + + uintptr_t hModuleAddress = reinterpret_cast(hModule); + PIMAGE_DOS_HEADER dosHeader = reinterpret_cast(hModuleAddress); + PIMAGE_NT_HEADERS ntHeader = reinterpret_cast(hModuleAddress + dosHeader->e_lfanew); + + IMAGE_DATA_DIRECTORY importDir = ntHeader->OptionalHeader.DataDirectory[1]; + PIMAGE_IMPORT_DESCRIPTOR imports = reinterpret_cast(hModuleAddress + importDir.VirtualAddress); + if (!imports) { + throw std::exception(fmt::format("[{}] Could not resolve the imports for the module because the imports data directory could not be found in the PE.", __FUNCTION__).c_str()); + Platform::DebugPause(); + return; + } + + std::map, ULONGLONG*> symbolTableAddresses; + while (imports->Characteristics != 0) { + PIMAGE_THUNK_DATA importLookupTable = reinterpret_cast(hModuleAddress + imports->OriginalFirstThunk); + PIMAGE_THUNK_DATA importAddressTable = reinterpret_cast(hModuleAddress + imports->FirstThunk); + + if (imports->OriginalFirstThunk && imports->FirstThunk) { + LPCSTR moduleName = reinterpret_cast(hModuleAddress + imports->Name); + std::string importModNameId(moduleName); + { + size_t dot = importModNameId.find_last_of('.'); + if (dot != std::string::npos) { + importModNameId = importModNameId.substr(0, dot); + } + } + + uintptr_t moduleBase = Platform::GetModuleBaseAddress(moduleName); + if (!moduleBase) { + moduleBase = (uintptr_t)manager.loadMod(importModNameId); + if (!moduleBase) + moduleBase = (uintptr_t)LoadLibraryA(moduleName); + } + + while (importLookupTable->u1.AddressOfData != 0) { + if (!(importLookupTable->u1.Ordinal & IMAGE_ORDINAL_FLAG)) { + PIMAGE_IMPORT_BY_NAME nameData = + reinterpret_cast(hModuleAddress + importLookupTable->u1.AddressOfData); + + symbolTableAddresses.insert({ { moduleBase, nameData->Name }, &(importAddressTable->u1.Function) }); + } + importLookupTable++; + importAddressTable++; + } + } + + imports++; + } + + for (auto& [infos, function] : symbolTableAddresses) { + auto& [moduleBase, entrySymbol] = infos; + if (moduleBase) { + ULONGLONG procAddress = reinterpret_cast( + Platform::GetModuleFunction(reinterpret_cast(moduleBase), entrySymbol.c_str())); + + if (procAddress && function) { + Memory::WriteOnProtectedAddress(function, &procAddress, sizeof(ULONGLONG)); + } + } + else { + throw std::exception(fmt::format("[{}] Could not resolve the address for '{}' because the module could not be loaded.", __FUNCTION__, entrySymbol).c_str()); + Platform::DebugPause(); + return; + } + } + + if (ntHeader->OptionalHeader.AddressOfEntryPoint) { + reinterpret_cast(hModuleAddress + ntHeader->OptionalHeader.AddressOfEntryPoint)( + reinterpret_cast(hModule), + DLL_PROCESS_ATTACH, + nullptr + ); + } + } } namespace Zenova { @@ -198,99 +289,6 @@ namespace Zenova { return LoadLibraryA((module + ".dll").c_str()); } - - - void* Platform::LoadModModuleAndResolveImports(const ModInfo& modInfo, const std::string& module) - { - void* hModule = LoadLibraryExA((module + ".dll").c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES); - ResolveModModuleImports(modInfo, hModule, module); - return hModule; - } - - typedef BOOL(APIENTRY* DllMainFunction)(HMODULE, DWORD, LPVOID); - void Platform::ResolveModModuleImports(const ModInfo& modInfo, void* hModule, const std::string& moduleName) - { - if (!hModule) { - throw std::invalid_argument(fmt::format("[{}] Could not resolve the imports for the module because it was nullptr.", __FUNCTION__)); - Platform::DebugPause(); - return; - } - - uintptr_t hModuleAddress = reinterpret_cast(hModule); - PIMAGE_DOS_HEADER dosHeader = reinterpret_cast(hModuleAddress); - PIMAGE_NT_HEADERS ntHeader = reinterpret_cast(hModuleAddress + dosHeader->e_lfanew); - - IMAGE_DATA_DIRECTORY importDir = ntHeader->OptionalHeader.DataDirectory[1]; - PIMAGE_IMPORT_DESCRIPTOR imports = reinterpret_cast(hModuleAddress + importDir.VirtualAddress); - if (!imports) { - throw std::exception(fmt::format("[{}] Could not resolve the imports for the module because the imports data directory could not be found in the PE.", __FUNCTION__).c_str()); - Platform::DebugPause(); - return; - } - - std::map, ULONGLONG*> symbolTableAddresses; - while (imports->Characteristics != 0) { - PIMAGE_THUNK_DATA importLookupTable = reinterpret_cast(hModuleAddress + imports->OriginalFirstThunk); - PIMAGE_THUNK_DATA importAddressTable = reinterpret_cast(hModuleAddress + imports->FirstThunk); - - if (imports->OriginalFirstThunk && imports->FirstThunk) { - LPCSTR moduleName = reinterpret_cast(hModuleAddress + imports->Name); - std::string importModNameId(moduleName); - { - size_t dot = importModNameId.find_last_of('.'); - if (dot != std::string::npos) { - importModNameId = importModNameId.substr(0, dot); - } - } - - uintptr_t moduleBase = Platform::GetModuleBaseAddress(moduleName); - if (!moduleBase) { - moduleBase = (uintptr_t)manager.loadMod(importModNameId); - if (!moduleBase) - moduleBase = (uintptr_t)LoadLibraryA(moduleName); - } - - while (importLookupTable->u1.AddressOfData != 0) { - if (!(importLookupTable->u1.Ordinal & IMAGE_ORDINAL_FLAG)) { - PIMAGE_IMPORT_BY_NAME nameData = - reinterpret_cast(hModuleAddress + importLookupTable->u1.AddressOfData); - - symbolTableAddresses.insert({ { moduleBase, nameData->Name }, &(importAddressTable->u1.Function) }); - } - importLookupTable++; - importAddressTable++; - } - } - - imports++; - } - - for (auto& [infos, function] : symbolTableAddresses) { - auto& [moduleBase, entrySymbol] = infos; - if (moduleBase) { - ULONGLONG procAddress = reinterpret_cast( - Platform::GetModuleFunction(reinterpret_cast(moduleBase), entrySymbol.c_str())); - - if (procAddress && function) { - Memory::WriteOnProtectedAddress(function, &procAddress, sizeof(ULONGLONG)); - } - } - else { - throw std::exception(fmt::format("[{}] Could not resolve the address for '{}' because the module could not be loaded.", __FUNCTION__, entrySymbol).c_str()); - Platform::DebugPause(); - return; - } - } - - if (ntHeader->OptionalHeader.AddressOfEntryPoint) { - reinterpret_cast(hModuleAddress + ntHeader->OptionalHeader.AddressOfEntryPoint)( - reinterpret_cast(hModule), - DLL_PROCESS_ATTACH, - nullptr - ); - } - } - bool Platform::CloseModule(void* module) { return FreeLibrary(reinterpret_cast(module)); } diff --git a/src/Zenova/Profile/ModInfo.cpp b/src/Zenova/Profile/ModInfo.cpp index 65db5e1..00b6548 100644 --- a/src/Zenova/Profile/ModInfo.cpp +++ b/src/Zenova/Profile/ModInfo.cpp @@ -35,7 +35,7 @@ namespace Zenova { void* ModInfo::loadModule() { - mHandle = Platform::LoadModModuleAndResolveImports(*this, mModFolder + mNameId); + mHandle = Zenova::PlatformImpl::LoadModModuleAndResolveImports(mModFolder + mNameId); return mHandle; } } diff --git a/inc/Zenova/Profile/ModInfo.h b/src/Zenova/Profile/ModInfo.h similarity index 100% rename from inc/Zenova/Profile/ModInfo.h rename to src/Zenova/Profile/ModInfo.h diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 00df408..acb67cf 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -1,16 +1,14 @@ // // This is for the Windows version of Zenova // + #include #include "Zenova/Platform.h" #include "Zenova/Helper.h" #include "generated/initcpp.h" -#include "Zenova/Log.h" -#include "winnt.h" DWORD WINAPI call_run(LPVOID args) { - return Zenova::run(); } @@ -18,6 +16,7 @@ BOOL APIENTRY DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { // avoid being attached to anything besides Minecraft Win10 if ((fdwReason == DLL_PROCESS_ATTACH) && Zenova::Platform::GetMinecraftBaseAddress()) { InitBedrockPointers(); + auto args = reinterpret_cast(hinstDLL); // block run till everything is initialized if (Zenova::start(args)) { From 1925cfd79273168a69a2a2adaf09806aa65d8017 Mon Sep 17 00:00:00 2001 From: Raony Reis <75029692+raonygamer@users.noreply.github.com> Date: Tue, 30 Jan 2024 16:05:56 -0300 Subject: [PATCH 7/8] Update Manager::loadMod to check if the folder exists before trying to read the mod and cause a crash --- src/Zenova/Profile/Manager.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Zenova/Profile/Manager.cpp b/src/Zenova/Profile/Manager.cpp index 96182a9..2a1f22a 100644 --- a/src/Zenova/Profile/Manager.cpp +++ b/src/Zenova/Profile/Manager.cpp @@ -1,5 +1,5 @@ #include "Manager.h" - +#include #include "Zenova/Log.h" #include "Zenova/Mod.h" #include "Zenova/Globals.h" @@ -108,10 +108,13 @@ namespace Zenova { [&modName](const ModInfo& mod) { return mod.mNameId == modName; }) != mods.end()) return nullptr; + std::string folder = manager.dataFolder + "\\mods\\" + modName + "\\"; + if (!std::filesystem::exists(folder)) + return nullptr; + logger.info("Loading {}", modName); // todo: verify path - std::string folder = manager.dataFolder + "\\mods\\" + modName + "\\"; ModInfo mod(folder); void* modHandle = mod.loadModule(); From 4d5a6db3b4c4137a1927fa7938d59ded363f7d31 Mon Sep 17 00:00:00 2001 From: Raony Reis <75029692+raonygamer@users.noreply.github.com> Date: Tue, 30 Jan 2024 19:44:08 -0300 Subject: [PATCH 8/8] Fixed the requested changes of the second review for "MinecraftZenova/ZenovaAPI#20" --- inc/Zenova/Platform.h | 2 -- src/Zenova/Platform/Windows.cpp | 12 ++++++------ src/Zenova/Profile/Manager.cpp | 5 ----- src/Zenova/Profile/Manager.h | 1 - src/Zenova/Profile/ModInfo.cpp | 2 +- src/Zenova/Profile/ModInfo.h | 2 -- src/Zenova/Utils/Memory.cpp | 14 -------------- src/Zenova/Utils/Memory.h | 8 -------- 8 files changed, 7 insertions(+), 39 deletions(-) delete mode 100644 src/Zenova/Utils/Memory.cpp delete mode 100644 src/Zenova/Utils/Memory.h diff --git a/inc/Zenova/Platform.h b/inc/Zenova/Platform.h index dd7944c..b47dd6f 100644 --- a/inc/Zenova/Platform.h +++ b/inc/Zenova/Platform.h @@ -22,8 +22,6 @@ namespace Zenova { Execute = 8 }; - struct ModInfo; - inline ProtectionFlags operator|(ProtectionFlags a, ProtectionFlags b) { return static_cast(enum_cast(a) | enum_cast(b)); } diff --git a/src/Zenova/Platform/Windows.cpp b/src/Zenova/Platform/Windows.cpp index 0f2aa9e..08e7541 100644 --- a/src/Zenova/Platform/Windows.cpp +++ b/src/Zenova/Platform/Windows.cpp @@ -23,7 +23,6 @@ #include "Zenova.h" #include "Zenova/Globals.h" #include "Zenova/Utils/Utils.h" -#include "Zenova/Utils/Memory.h" #include "MinHook.h" @@ -101,7 +100,7 @@ namespace Zenova::PlatformImpl { void ResolveModModuleImports(void* hModule, const std::string& moduleName) { if (!hModule) { - throw std::invalid_argument(fmt::format("[{}] Could not resolve the imports for the module because it was nullptr.", __FUNCTION__)); + Zenova_Log(Warning, "[{}] Could not resolve the imports for the module because it was nullptr.", __FUNCTION__); Platform::DebugPause(); return; } @@ -113,7 +112,7 @@ namespace Zenova::PlatformImpl { IMAGE_DATA_DIRECTORY importDir = ntHeader->OptionalHeader.DataDirectory[1]; PIMAGE_IMPORT_DESCRIPTOR imports = reinterpret_cast(hModuleAddress + importDir.VirtualAddress); if (!imports) { - throw std::exception(fmt::format("[{}] Could not resolve the imports for the module because the imports data directory could not be found in the PE.", __FUNCTION__).c_str()); + Zenova_Log(Warning, "[{}] Could not resolve the imports for the module because the imports data directory could not be found in the PE.", __FUNCTION__); Platform::DebugPause(); return; } @@ -162,12 +161,13 @@ namespace Zenova::PlatformImpl { Platform::GetModuleFunction(reinterpret_cast(moduleBase), entrySymbol.c_str())); if (procAddress && function) { - Memory::WriteOnProtectedAddress(function, &procAddress, sizeof(ULONGLONG)); + u32 oldPageProtection = Platform::SetPageProtect(function, sizeof(ULONGLONG), ProtectionFlags::Execute | ProtectionFlags::Read | ProtectionFlags::Write); + (*function) = procAddress; + Platform::SetPageProtect(function, sizeof(ULONGLONG), oldPageProtection); } } else { - throw std::exception(fmt::format("[{}] Could not resolve the address for '{}' because the module could not be loaded.", __FUNCTION__, entrySymbol).c_str()); - Platform::DebugPause(); + Zenova_Log(Warning, "[{}] Could not resolve the address for '{}' because the module could not be loaded.", __FUNCTION__, entrySymbol); return; } } diff --git a/src/Zenova/Profile/Manager.cpp b/src/Zenova/Profile/Manager.cpp index 2a1f22a..9a31a63 100644 --- a/src/Zenova/Profile/Manager.cpp +++ b/src/Zenova/Profile/Manager.cpp @@ -134,11 +134,6 @@ namespace Zenova { } } - std::vector& Manager::getMods() - { - return mods; - } - std::string Manager::getVersion() { return launched.versionId; } diff --git a/src/Zenova/Profile/Manager.h b/src/Zenova/Profile/Manager.h index 4b0f196..3360e52 100644 --- a/src/Zenova/Profile/Manager.h +++ b/src/Zenova/Profile/Manager.h @@ -29,7 +29,6 @@ namespace Zenova { void load(const ProfileInfo& profile); void swap(const ProfileInfo& profile); void* loadMod(const std::string& modName); - std::vector& getMods(); std::string getVersion(); size_t getModCount(); diff --git a/src/Zenova/Profile/ModInfo.cpp b/src/Zenova/Profile/ModInfo.cpp index 00b6548..a2f06bc 100644 --- a/src/Zenova/Profile/ModInfo.cpp +++ b/src/Zenova/Profile/ModInfo.cpp @@ -35,7 +35,7 @@ namespace Zenova { void* ModInfo::loadModule() { - mHandle = Zenova::PlatformImpl::LoadModModuleAndResolveImports(mModFolder + mNameId); + mHandle = PlatformImpl::LoadModModuleAndResolveImports(mModFolder + mNameId); return mHandle; } } diff --git a/src/Zenova/Profile/ModInfo.h b/src/Zenova/Profile/ModInfo.h index 7c170f7..0f63ce1 100644 --- a/src/Zenova/Profile/ModInfo.h +++ b/src/Zenova/Profile/ModInfo.h @@ -16,12 +16,10 @@ namespace Zenova { std::string mName = ""; std::string mDescription = ""; std::string mVersion = ""; -#ifdef ZENOVA_API ModInfo(const std::string& modFolder); ModInfo(ModInfo&&) noexcept; ~ModInfo(); void* loadModule(); -#endif }; } diff --git a/src/Zenova/Utils/Memory.cpp b/src/Zenova/Utils/Memory.cpp deleted file mode 100644 index f0597d7..0000000 --- a/src/Zenova/Utils/Memory.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Memory.h" -#include "Windows.h" - -namespace Zenova { - void Memory::WriteOnProtectedAddress(void* address, void* data, size_t size) { - if (!address || !data || !size) - return; - - DWORD old = 0; - VirtualProtect(address, size, PAGE_EXECUTE_READWRITE, &old); - memcpy_s(address, size, data, size); - VirtualProtect(address, size, old, NULL); - } -} \ No newline at end of file diff --git a/src/Zenova/Utils/Memory.h b/src/Zenova/Utils/Memory.h deleted file mode 100644 index b94a316..0000000 --- a/src/Zenova/Utils/Memory.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace Zenova { - class Memory { - public: - static void WriteOnProtectedAddress(void* address, void* data, size_t dataSize); - }; -} \ No newline at end of file