From cb9c3879ce101c4c24223c500794173996ee9bd3 Mon Sep 17 00:00:00 2001 From: "Drew C." Date: Fri, 27 Feb 2026 21:53:08 -0600 Subject: [PATCH] Initial commit, hook into StarWarsI.exe --- .gitignore | 8 ++ CLAUDE.md | 19 ++++ README.md | 13 ++- SWEAW Hooks.sln | 31 ++++++ SWEAW Hooks.vcxproj | 165 ++++++++++++++++++++++++++++++++ dllmain.cpp | 26 +++++ lua_hook.cpp | 116 ++++++++++++++++++++++ lua_hook.h | 13 +++ minhook/bin/MinHook.x64.exp | Bin 0 -> 2203 bytes minhook/bin/MinHook.x86.exp | Bin 0 -> 2282 bytes minhook/include/MinHook.h | 185 ++++++++++++++++++++++++++++++++++++ powrprof.def | 8 ++ proxy.cpp | 100 +++++++++++++++++++ proxy.h | 7 ++ 14 files changed, 690 insertions(+), 1 deletion(-) create mode 100644 CLAUDE.md create mode 100644 SWEAW Hooks.sln create mode 100644 SWEAW Hooks.vcxproj create mode 100644 dllmain.cpp create mode 100644 lua_hook.cpp create mode 100644 lua_hook.h create mode 100644 minhook/bin/MinHook.x64.exp create mode 100644 minhook/bin/MinHook.x86.exp create mode 100644 minhook/include/MinHook.h create mode 100644 powrprof.def create mode 100644 proxy.cpp create mode 100644 proxy.h diff --git a/.gitignore b/.gitignore index d4fb281..b92f67a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,11 @@ +x64/ +powrprof/ +.vscode/ +.vs/ + +*.vcxproj.filters +*.vcxproj.user + # Prerequisites *.d diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ad2be12 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,19 @@ +# SWEaW Hooks + +## Project Overview + +This project is a hook API for Star Wars: Empire at War: Forces of Corruption to expose custom Lua functions available for scripting. + +## Client and Debug Kits + +- StarWarsG.exe -- the binary shipped with the game for all clients. PDB unavailable. +- StarWarsI.exe -- the debug kit binary which comes with debug functionality but is too slow to run normally. PDB available. + +## DLL Hook + +- Uses MinHook to create the DLL hook into the game via powerprof.dll +- Using IDA Free to find addresses of function calls. + +## Empire at War Lua Scripting Engine + +The source code for the Lua scripting engine in Empire at War was leaked at: https://github.com/PetroglyphGames/GlyphX-Reference. Use this as a guide for what Lua functions and variables are already available, and how the engine hooks Lua scripting into the rest of the game. No other engine source code is available. \ No newline at end of file diff --git a/README.md b/README.md index 8873b1a..b41b7fd 100644 --- a/README.md +++ b/README.md @@ -1 +1,12 @@ -# SWEAW Hooks \ No newline at end of file +# SWEaW Hooks + +A powrprof.dll hook which adds custom Lua functions to Forces of Corruption. + +## Usage + +Drop powrprof.dll and MinHooks.x64.dll into the `/corruption/` folder of your Empire at War installation. +Currently only works with the debug kit `StarWarsI.exe`; `StarWarsG.exe` support is coming soon. + +## Functions + +- Global `WriteToFile(str a, str b)` - Appends a line of text `b` to the file name `a` in the game directory. \ No newline at end of file diff --git a/SWEAW Hooks.sln b/SWEAW Hooks.sln new file mode 100644 index 0000000..56a994c --- /dev/null +++ b/SWEAW Hooks.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36127.28 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SWEAW Hooks", "SWEAW Hooks.vcxproj", "{F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}.Debug|x64.ActiveCfg = Debug|x64 + {F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}.Debug|x64.Build.0 = Debug|x64 + {F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}.Debug|x86.ActiveCfg = Debug|Win32 + {F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}.Debug|x86.Build.0 = Debug|Win32 + {F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}.Release|x64.ActiveCfg = Release|x64 + {F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}.Release|x64.Build.0 = Release|x64 + {F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}.Release|x86.ActiveCfg = Release|Win32 + {F2C4477F-C9F1-4AF0-A04C-9D6ADD14E783}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A512788C-5D26-42E2-BCB7-1459395B6B39} + EndGlobalSection +EndGlobal diff --git a/SWEAW Hooks.vcxproj b/SWEAW Hooks.vcxproj new file mode 100644 index 0000000..144e66e --- /dev/null +++ b/SWEAW Hooks.vcxproj @@ -0,0 +1,165 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {f2c4477f-c9f1-4af0-a04c-9d6add14e783} + SWEAWHooks + 10.0 + powrprof + + + + DynamicLibrary + true + v145 + Unicode + + + DynamicLibrary + false + v145 + true + Unicode + + + DynamicLibrary + true + v145 + Unicode + + + DynamicLibrary + false + v145 + true + Unicode + + + + + + + + + + + + + + + + + + + + + C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;$(IncludePath) + C:\Program Files (x86)\Windows Kits\10\Lib\10.0.26100.0\ucrt\x64;$(LibraryPath) + + + C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\ucrt;$(IncludePath) + C:\Program Files (x86)\Windows Kits\10\Lib\10.0.26100.0\ucrt\x64;$(LibraryPath) + + + + Level3 + true + WIN32;_DEBUG;SWEAWHOOKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;SWEAWHOOKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + _DEBUG;SWEAWHOOKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + + + Windows + true + false + minhook\bin\;%(AdditionalLibraryDirectories) + powrprof.def + + + + + Level3 + true + true + true + NDEBUG;SWEAWHOOKS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + + + Windows + true + false + minhook\bin\;%(AdditionalLibraryDirectories) + powrprof.def + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dllmain.cpp b/dllmain.cpp new file mode 100644 index 0000000..2af5a1a --- /dev/null +++ b/dllmain.cpp @@ -0,0 +1,26 @@ +#include "proxy.h" +#include "lua_hook.h" +#include + +BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) { + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDll); + + if (!Proxy_Init()) { + return FALSE; + } + + if (!LuaHook_Init()) { + OutputDebugStringA("[SWEAW Hooks] WARNING: LuaHook_Init() failed - Lua hooks are not active.\n"); + } + break; + + case DLL_PROCESS_DETACH: + LuaHook_Shutdown(); + Proxy_Shutdown(); + break; + } + + return TRUE; +} diff --git a/lua_hook.cpp b/lua_hook.cpp new file mode 100644 index 0000000..3e41295 --- /dev/null +++ b/lua_hook.cpp @@ -0,0 +1,116 @@ +#include "lua_hook.h" +#include "minhook/include/MinHook.h" +#include + +#if defined _M_X64 +#pragma comment(lib, "MinHook.x64.lib") +#elif defined _M_IX86 +#pragma comment(lib, "MinHook.x86.lib") +#endif + +// Opaque Lua state - never dereferenced, just passed around +struct lua_State; +typedef int (*lua_CFunction)(lua_State*); + +// Function pointer types +typedef lua_State* (*fn_lua_open)(); +typedef void (*fn_lua_pushstring)(lua_State*, const char*); +typedef void (*fn_lua_pushcclosure)(lua_State*, lua_CFunction, int); +typedef void (*fn_lua_settable)(lua_State*, int); +typedef const char* (*fn_lua_tostring)(lua_State*, int); + +// Resolved function pointers +static fn_lua_open real_lua_open = nullptr; +static fn_lua_pushstring pfn_pushstring = nullptr; +static fn_lua_pushcclosure pfn_pushcclosure = nullptr; +static fn_lua_settable pfn_settable = nullptr; +static fn_lua_tostring pfn_tostring = nullptr; + +// Helper, equivalent of lua_setglobal +static void register_global(lua_State* L, const char* name, lua_CFunction fn) { + pfn_pushstring(L, name); + pfn_pushcclosure(L, fn, 0); + pfn_settable(L, LUA_GLOBALSINDEX); +} + +// ========================= +// Custom Lua file functions +// ========================= + +// WriteToFile(path, text) - appends text to a file +static int L_WriteToFile(lua_State* L) { + const char* path = pfn_tostring(L, 1); + const char* text = pfn_tostring(L, 2); + + if (!path || !text) { + return 0; + } + + HANDLE hFile = CreateFileA( + path, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile != INVALID_HANDLE_VALUE) { + DWORD written; + + SetFilePointer(hFile, 0, NULL, FILE_END); + WriteFile(hFile, text, lstrlenA(text), &written, NULL); + WriteFile(hFile, "\n", 1, &written, NULL); + CloseHandle(hFile); + } + + return 0; +} + +// ========================= +// Hooks +// ========================= + +// Fired every time the game creates a new Lua state +static lua_State* Hook_lua_open() { + lua_State* L = real_lua_open(); + + if (!L) { + return L; + } + + // Register custom Lua functions + register_global(L, "WriteToFile", L_WriteToFile); + + return L; +} + +bool LuaHook_Init() { + uintptr_t base = (uintptr_t)GetModuleHandleA(nullptr); + + pfn_pushstring = (fn_lua_pushstring)(base + RVA_lua_pushstring); + pfn_pushcclosure = (fn_lua_pushcclosure)(base + RVA_lua_pushcclosure); + pfn_settable = (fn_lua_settable)(base + RVA_lua_settable); + pfn_tostring = (fn_lua_tostring)(base + RVA_lua_tostring); + + void* const target = (void*)(base + RVA_lua_open); + + if (MH_Initialize() != MH_OK) { + return false; + } + + if (MH_CreateHook(target, &Hook_lua_open, (void**)&real_lua_open) != MH_OK) { + return false; + } + + if (MH_EnableHook(target) != MH_OK) { + return false; + } + + return true; +} + +void LuaHook_Shutdown() { + MH_DisableHook(MH_ALL_HOOKS); + MH_Uninitialize(); +} \ No newline at end of file diff --git a/lua_hook.h b/lua_hook.h new file mode 100644 index 0000000..7628a6c --- /dev/null +++ b/lua_hook.h @@ -0,0 +1,13 @@ +#pragma once +#include + +constexpr uintptr_t RVA_lua_open = 0x12AB790; +constexpr uintptr_t RVA_lua_pushstring = 0x12AC930; +constexpr uintptr_t RVA_lua_pushcclosure = 0x12AC6E0; +constexpr uintptr_t RVA_lua_settable = 0x12AD020; +constexpr uintptr_t RVA_lua_tostring = 0x12AD430; + +constexpr int LUA_GLOBALSINDEX = -10001; + +bool LuaHook_Init(); +void LuaHook_Shutdown(); \ No newline at end of file diff --git a/minhook/bin/MinHook.x64.exp b/minhook/bin/MinHook.x64.exp new file mode 100644 index 0000000000000000000000000000000000000000..ad66dd6e3392334b6903e20667348fd85eba3a6f GIT binary patch literal 2203 zcmd5-O>f*(6upU)wnS=};9h?Ib7_ZD=zg>cUd+j9;ct@z|E_ zX@>|=kSgE@Ac4e&1*kj3uFFbnSfRoKsTpCl?#T1@3SiSsx>6OR$OXz!xsavZgepXsVruQT6djmtOVME6nirB1VF zIp#ewotHWAxMtda(~i+N88ktYw1@W6KANIw+D{j>zZwKPW`C(_x}HZDR=3WCq4)l! zp6V%=!$zc>MDd{E=uD_bgq1!^%Q|*i-eAg#pO4P@I?;}&cNGtnZ3^Q>8=kbTy1~`K zg3ZK9dhtfkOd{=fc$s&7{bX7Bz7zPUhMX1-7pw%_BWxbHSJ(pZps>rpeZpP^J}1lu zP6@MshlITcoEBCE9u~&#*e|RGJRcC^dLg0+BW#IF|65!Lq zR)Op{gZjW(VdsG_2>SpyC+s5dMPVNSpAohJd`Z|1;IqOefDcej`1CA|@nl*)Wjl6P z`&V$jgSOSvo@;M5$|voX_U(1$DJNET-Ycpf(kpa&j-B)~FC=9K+Mk~iT-A<(IM_}~ z3+peJ&YxR*o4%ws=BRzm{kI)S^%XTv*%zar6FJ?|TiR1Gw$2vZ)N#-8O3kF_>cFm8 zm5ROMCn^dfjYr&U*c(CMVL}tMTs5nU=3=#G)#OE1gE+ZdTe4wx+tdDz$$R0rYjd2I z@KN6S2O)DpL(ZkZVW>t?P!~}7LzRplu77oJ`s3ez z-SY3;{O--2>mQnroO_cuZ=Kkky8X+6yC%^e7-ymW^Ks***@{#g^rE&LZh8l~YMbiq zpc|Ung^R}c)-f*(6upy4I!#(ahVMdvLCPWsWO*h-YN}Saodl&KP1{TwbzvzuV`pl`V~=c4 zGen4jgakhUi3RMsLu?Qmq)IGUflwDnl@M&YM<6P}4$i%fXZ%r#9arP?&OP^i*zeu@ zX1z2)|G>VPBC3&CNwF<6GGm7^ED>2~@1bRz$D`w?SoZFqyU=Eh?fVI$-|?hPr@0I4 z^BRfH)0{kd67BzKOEf`cnxrW@Min|v(=%H_^L?ivtPWXPaYA#~9SvFa(%wbSi5$~)4sGr#%jEitmL0Td_xziq z3EPnw4ZY&Ujkc-$`t0MNSKc3swUj6Sg48+9KE!;#~(G7xpUfNnr+X zT9^uaO4!@L8DUM})517AP6*S0&j`B#P#QF7OdyI`COxec-IH72tEiBH*LK z)_|OE6&eEPgslUg7xpf&D(njI1!3<49}~6(d{Nkkz{iD60{_5s4S9NjN<5fW&KRcA zbG#ck-%-0ea9qpSZq-j4yN+jU+OBPewvo;id)TK}=xmiUsmv3J%|iS8BSKbn0zdTk zqT1r-%eD238*kAkbgoLB1M9z5BztI6>x^+F@VkN8tG(&Cc8H~u3AdeaV7j$-G_V}s zXsC^bvFb&3&<`BE;&#i}@_iQr+MxBO(p*xOnwqM~hphQwbX{9EknD!*c>4;kg(K6d zT$VdXq*U(fszkV^IWjH-z23l4X;uF0Yy>5t*OzfVT9x;@5L_MVjd)g0N)D$|UvDCz zv??blN5%zk6sQ~p#s!2oN5>V0Vf=NR(j3SZ8-k}0 zPbsQ8hy93^^j*&H zQ>OH-%?Dei@NmQIAqhT*7xxLe{hM$`Us0x@8~5T{BI$E*Ik1R69w`eODy&Xl=9C8A z$tg?pLr!VZuQ}y4snd9^c;;nUI<1_hS-5FMqxqcjI;mNuu2L(f)ahzYX;5dR;KlHt zF*e?{_%=+mSm85IELP4XF4|b(J1MbP*-Kosv2svQc#ji{`+SzTXk+E8g7RHK`8lKf z29Gm1Tkx!83q7kG6?j363!CL^L9>!6ITkVn%)&zocO(}^X9|_O6$+HaTw(qTgs8s9 literal 0 HcmV?d00001 diff --git a/minhook/include/MinHook.h b/minhook/include/MinHook.h new file mode 100644 index 0000000..492d83f --- /dev/null +++ b/minhook/include/MinHook.h @@ -0,0 +1,185 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) + #error MinHook supports only x86 and x64 systems. +#endif + +#include + +// MinHook Error Codes. +typedef enum MH_STATUS +{ + // Unknown error. Should not be returned. + MH_UNKNOWN = -1, + + // Successful. + MH_OK = 0, + + // MinHook is already initialized. + MH_ERROR_ALREADY_INITIALIZED, + + // MinHook is not initialized yet, or already uninitialized. + MH_ERROR_NOT_INITIALIZED, + + // The hook for the specified target function is already created. + MH_ERROR_ALREADY_CREATED, + + // The hook for the specified target function is not created yet. + MH_ERROR_NOT_CREATED, + + // The hook for the specified target function is already enabled. + MH_ERROR_ENABLED, + + // The hook for the specified target function is not enabled yet, or already + // disabled. + MH_ERROR_DISABLED, + + // The specified pointer is invalid. It points the address of non-allocated + // and/or non-executable region. + MH_ERROR_NOT_EXECUTABLE, + + // The specified target function cannot be hooked. + MH_ERROR_UNSUPPORTED_FUNCTION, + + // Failed to allocate memory. + MH_ERROR_MEMORY_ALLOC, + + // Failed to change the memory protection. + MH_ERROR_MEMORY_PROTECT, + + // The specified module is not loaded. + MH_ERROR_MODULE_NOT_FOUND, + + // The specified function is not found. + MH_ERROR_FUNCTION_NOT_FOUND +} +MH_STATUS; + +// Can be passed as a parameter to MH_EnableHook, MH_DisableHook, +// MH_QueueEnableHook or MH_QueueDisableHook. +#define MH_ALL_HOOKS NULL + +#ifdef __cplusplus +extern "C" { +#endif + + // Initialize the MinHook library. You must call this function EXACTLY ONCE + // at the beginning of your program. + MH_STATUS WINAPI MH_Initialize(VOID); + + // Uninitialize the MinHook library. You must call this function EXACTLY + // ONCE at the end of your program. + MH_STATUS WINAPI MH_Uninitialize(VOID); + + // Creates a hook for the specified target function, in disabled state. + // Parameters: + // pTarget [in] A pointer to the target function, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszProcName [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApi( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszProcName [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + // ppTarget [out] A pointer to the target function, which will be used + // with other functions. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApiEx( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); + + // Removes an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); + + // Enables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // enabled in one go. + MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); + + // Disables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // disabled in one go. + MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); + + // Queues to enable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be enabled. + MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); + + // Queues to disable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be disabled. + MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); + + // Applies all queued changes in one go. + MH_STATUS WINAPI MH_ApplyQueued(VOID); + + // Translates the MH_STATUS to its name as a string. + const char * WINAPI MH_StatusToString(MH_STATUS status); + +#ifdef __cplusplus +} +#endif diff --git a/powrprof.def b/powrprof.def new file mode 100644 index 0000000..8ea05c6 --- /dev/null +++ b/powrprof.def @@ -0,0 +1,8 @@ +LIBRARY powrprof +EXPORTS + CallNtPowerInformation + PowerReadACValueIndex + PowerReadDCValueIndex + PowerGetActiveScheme + PowerSettingRegisterNotification + PowerSettingUnregisterNotification diff --git a/proxy.cpp b/proxy.cpp new file mode 100644 index 0000000..2b490ef --- /dev/null +++ b/proxy.cpp @@ -0,0 +1,100 @@ +#include "proxy.h" + +HMODULE g_hRealPowrprof = nullptr; + +// NTSTATUS = LONG, POWER_INFORMATION_LEVEL = int; using primitive types +// avoids pulling in powerbase.h / ntstatus.h for a simple passthrough. +typedef LONG (WINAPI* fn_CallNtPowerInformation)(int, PVOID, ULONG, PVOID, ULONG); +typedef DWORD (WINAPI* fn_PowerReadACValueIndex)(HKEY, const GUID*, const GUID*, const GUID*, LPDWORD); +typedef DWORD (WINAPI* fn_PowerGetActiveScheme)(HKEY, GUID**); +typedef DWORD (WINAPI* fn_PowerSettingRegisterNotification)(LPCGUID, DWORD, HANDLE, HANDLE*); +typedef DWORD (WINAPI* fn_PowerSettingUnregisterNotification)(HANDLE); + +static fn_CallNtPowerInformation real_CallNtPowerInformation = nullptr; +static fn_PowerReadACValueIndex real_PowerReadACValueIndex = nullptr; +static fn_PowerReadACValueIndex real_PowerReadDCValueIndex = nullptr; +static fn_PowerGetActiveScheme real_PowerGetActiveScheme = nullptr; +static fn_PowerSettingRegisterNotification real_PowerSettingRegisterNotification = nullptr; +static fn_PowerSettingUnregisterNotification real_PowerSettingUnregisterNotification = nullptr; + +bool Proxy_Init() { + char path[MAX_PATH]; + + GetSystemDirectoryA(path, MAX_PATH); + lstrcatA(path, "\\powrprof.dll"); + g_hRealPowrprof = LoadLibraryA(path); + + if (!g_hRealPowrprof) { + return false; + } + + real_CallNtPowerInformation = (fn_CallNtPowerInformation) + GetProcAddress(g_hRealPowrprof, "CallNtPowerInformation"); + real_PowerReadACValueIndex = (fn_PowerReadACValueIndex) + GetProcAddress(g_hRealPowrprof, "PowerReadACValueIndex"); + real_PowerReadDCValueIndex = (fn_PowerReadACValueIndex) + GetProcAddress(g_hRealPowrprof, "PowerReadDCValueIndex"); + real_PowerGetActiveScheme = (fn_PowerGetActiveScheme) + GetProcAddress(g_hRealPowrprof, "PowerGetActiveScheme"); + real_PowerSettingRegisterNotification = (fn_PowerSettingRegisterNotification) + GetProcAddress(g_hRealPowrprof, "PowerSettingRegisterNotification"); + real_PowerSettingUnregisterNotification = (fn_PowerSettingUnregisterNotification) + GetProcAddress(g_hRealPowrprof, "PowerSettingUnregisterNotification"); + + return real_CallNtPowerInformation != nullptr; +} + +void Proxy_Shutdown() { + if (g_hRealPowrprof) { + FreeLibrary(g_hRealPowrprof); + g_hRealPowrprof = nullptr; + } +} + +extern "C" { + __declspec(dllexport) LONG WINAPI CallNtPowerInformation( + int level, PVOID inBuf, ULONG inSize, PVOID outBuf, ULONG outSize) + { + return real_CallNtPowerInformation(level, inBuf, inSize, outBuf, outSize); + } + + __declspec(dllexport) DWORD WINAPI PowerReadACValueIndex( + HKEY rootKey, const GUID* scheme, const GUID* subgroup, const GUID* setting, LPDWORD index) + { + if (real_PowerReadACValueIndex) + return real_PowerReadACValueIndex(rootKey, scheme, subgroup, setting, index); + return ERROR_NOT_SUPPORTED; + } + + __declspec(dllexport) DWORD WINAPI PowerReadDCValueIndex( + HKEY rootKey, const GUID* scheme, const GUID* subgroup, const GUID* setting, LPDWORD index) + { + if (real_PowerReadDCValueIndex) + return real_PowerReadDCValueIndex(rootKey, scheme, subgroup, setting, index); + return ERROR_NOT_SUPPORTED; + } + + __declspec(dllexport) DWORD WINAPI PowerGetActiveScheme( + HKEY userRootPowerKey, GUID** activePolicyGuid) + { + if (real_PowerGetActiveScheme) + return real_PowerGetActiveScheme(userRootPowerKey, activePolicyGuid); + return ERROR_NOT_SUPPORTED; + } + + __declspec(dllexport) DWORD WINAPI PowerSettingRegisterNotification( + LPCGUID settingGuid, DWORD flags, HANDLE recipient, HANDLE* registrationHandle) + { + if (real_PowerSettingRegisterNotification) + return real_PowerSettingRegisterNotification(settingGuid, flags, recipient, registrationHandle); + return ERROR_NOT_SUPPORTED; + } + + __declspec(dllexport) DWORD WINAPI PowerSettingUnregisterNotification( + HANDLE registrationHandle) + { + if (real_PowerSettingUnregisterNotification) + return real_PowerSettingUnregisterNotification(registrationHandle); + return ERROR_NOT_SUPPORTED; + } +} diff --git a/proxy.h b/proxy.h new file mode 100644 index 0000000..f733844 --- /dev/null +++ b/proxy.h @@ -0,0 +1,7 @@ +#pragma once +#define WIN32_LEAN_AND_MEAN +#include + +extern HMODULE g_hRealPowrprof; +bool Proxy_Init(); +void Proxy_Shutdown(); \ No newline at end of file