|
| 1 | +#include <set> |
| 2 | +#include <fstream> |
| 3 | +#include <tchar.h> |
| 4 | +#include <list> |
| 5 | +#include <vector> |
| 6 | + |
| 7 | +#include "pch.h" |
| 8 | +#include "INIReader.h" // https://github.com/jtilly/inih |
| 9 | + |
| 10 | +#include "HookLib.h" |
| 11 | +#include "PluginLoadHook.h" |
| 12 | +#pragma comment(lib, "Zydis.lib") |
| 13 | +#pragma comment(lib, "HookLib.lib") |
| 14 | + |
| 15 | +std::wstring pluginsPath; |
| 16 | +static std::wstring iniPath; |
| 17 | +static std::vector<HMODULE> loadedModules; |
| 18 | + |
| 19 | +#pragma region Hooks |
| 20 | + |
| 21 | +#pragma region Plugin Freeing |
| 22 | +using _ExitProcess = VOID(WINAPI*)(ULONG ExitCode); |
| 23 | +_ExitProcess OriginalExitProcess = NULL; |
| 24 | +VOID WINAPI ExitProcessHook(ULONG ExitCode) |
| 25 | +{ |
| 26 | + std::wcout << "Exiting Process..."; |
| 27 | + |
| 28 | + Sleep(1000); |
| 29 | + |
| 30 | + // Now free all of our other libs that we loaded |
| 31 | + for (auto&& hMod : loadedModules) { |
| 32 | + FreeLibrary(hMod); |
| 33 | + } |
| 34 | + |
| 35 | + RemoveHook(OriginalExitProcess); |
| 36 | + ExitProcess(ExitCode); |
| 37 | +} |
| 38 | + |
| 39 | +#pragma endregion |
| 40 | + |
| 41 | +#pragma region Plugin Loading |
| 42 | +void LoadPlugins() { |
| 43 | + std::wcout << "Loading Plugins..." << std::endl; |
| 44 | + |
| 45 | + std::list<std::wstring> pluginsToLoad = {}; |
| 46 | + |
| 47 | + std::fstream file; |
| 48 | + file.open(iniPath.c_str(), std::ios::out | std::ios::in | std::ios::app); |
| 49 | + if (!file) { |
| 50 | + file.open(iniPath.c_str(), std::ios::in || std::ios::out || std::ios::trunc); |
| 51 | + file << "[PluginLoader]\n"; |
| 52 | + file.flush(); |
| 53 | + file.close(); |
| 54 | + } |
| 55 | + |
| 56 | + INIReader reader(iniPath.c_str()); |
| 57 | + if (reader.ParseError() != 0) { |
| 58 | + std::wcout << "Unable to load 'pluginLoader.ini'" << std::endl; |
| 59 | + } |
| 60 | + |
| 61 | + WIN32_FIND_DATA fd; // This'll store our data about the plugin we're currently loading in. |
| 62 | + const HANDLE dllFile = FindFirstFile((pluginsPath + L"*.dll").c_str(), &fd); // Get the first DLL file in our plugins dir |
| 63 | + int dllCount = 0; |
| 64 | + |
| 65 | + if (dllFile == INVALID_HANDLE_VALUE) { |
| 66 | + std::wcout << "No Plugins Found..." << std::endl; |
| 67 | + return; // Just return now, no need to bother to execute the rest of the code |
| 68 | + } |
| 69 | + |
| 70 | + do { |
| 71 | + if ((!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))) { |
| 72 | + std::wstring pluginName = (std::wstring)fd.cFileName; |
| 73 | + std::string s(pluginName.begin(), pluginName.end()); |
| 74 | + |
| 75 | + if (reader.Sections().count(s)) { |
| 76 | + float delayTime = reader.GetFloat(s, "delaySeconds", 0); |
| 77 | + std::wcout << "Waiting " << delayTime << " seconds to load " << WidenString(s) << std::endl; |
| 78 | + Sleep(delayTime * 1000); |
| 79 | + } |
| 80 | + |
| 81 | + |
| 82 | + std::wstring filePath = pluginsPath + (pluginName); // Generate our file path + the name of our plugin to load |
| 83 | + HMODULE hMod = LoadLibrary(filePath.c_str()); |
| 84 | + if (hMod) { |
| 85 | + loadedModules.push_back(hMod); |
| 86 | + dllCount++; |
| 87 | + } |
| 88 | + else |
| 89 | + std::wcout << "Unable to load plugin: " << filePath << ": " << GetLastErrorAsString() << std::endl; |
| 90 | + } |
| 91 | + |
| 92 | + } while (FindNextFile(dllFile, &fd)); |
| 93 | + |
| 94 | + FindClose(dllFile); |
| 95 | +} |
| 96 | + |
| 97 | +using _LoadLibrary = HMODULE(WINAPI*)(LPCWSTR lpLibFileName); |
| 98 | +_LoadLibrary OriginalLoadLibrary = NULL; |
| 99 | +HMODULE WINAPI LoadLibraryWHook(LPCWSTR lpLibFileName) { |
| 100 | + std::wcout << "Loading Library: " << std::wstring(lpLibFileName) << std::endl; |
| 101 | + |
| 102 | + if (std::wstring(lpLibFileName)._Equal(L"shcore.dll")) { |
| 103 | + CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)LoadPlugins, NULL, NULL, NULL); |
| 104 | + RemoveHook(OriginalLoadLibrary); |
| 105 | + return LoadLibrary(lpLibFileName); |
| 106 | + } |
| 107 | + |
| 108 | + return OriginalLoadLibrary(lpLibFileName); |
| 109 | +} |
| 110 | + |
| 111 | +#pragma endregion |
| 112 | + |
| 113 | +#pragma endregion |
| 114 | + |
| 115 | +void InitializePluginHooks(HMODULE gameModule) { |
| 116 | + WCHAR pluginsFilePath[513] = { 0 }; |
| 117 | + GetModuleFileNameW(gameModule, pluginsFilePath, 512); |
| 118 | + std::wstring pPath = pluginsFilePath; |
| 119 | + pPath = pPath.substr(0, pPath.rfind('\\')) + L"\\Plugins\\"; |
| 120 | + std::wcout << "Plugins Path: " << pPath << std::endl; |
| 121 | + |
| 122 | + // This'll hapen if we are magically unable to create the plugins dir. |
| 123 | + if (!CreateDirectory(pPath.c_str(), nullptr) && GetLastError() != ERROR_ALREADY_EXISTS) { |
| 124 | + std::wcout << "Unable to create plugins folder..." << std::endl; |
| 125 | + return; |
| 126 | + } |
| 127 | + pluginsPath = pPath; |
| 128 | + iniPath = pluginsPath + L"pluginLoader.ini"; |
| 129 | + |
| 130 | + PVOID Target = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "ExitProcess"); |
| 131 | + |
| 132 | + if (SetHook(Target, ExitProcessHook, reinterpret_cast<PVOID*>(&OriginalExitProcess))) |
| 133 | + std::wcout << "Initialized ExitProcess(...) hook" << std::endl; |
| 134 | + else |
| 135 | + std::wcout << "Unable to initialize ExitProcess(...) hook" << std::endl; |
| 136 | + |
| 137 | + PVOID loadLibraryHook = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"); |
| 138 | + if (SetHook(loadLibraryHook, LoadLibraryWHook, reinterpret_cast<PVOID*>(&OriginalLoadLibrary))) |
| 139 | + std::wcout << "Initialized LoadLibraryW(...) hook..." << std::endl; |
| 140 | + else |
| 141 | + std::wcout << "Unable to initialize LoadLibraryW(...) hook" << std::endl; |
| 142 | + |
| 143 | +} |
0 commit comments