diff --git a/PluginDevFolder/.gitignore b/PluginDevFolder/.gitignore new file mode 100644 index 0000000..50b0179 --- /dev/null +++ b/PluginDevFolder/.gitignore @@ -0,0 +1 @@ +PlaygroundPlugin/ \ No newline at end of file diff --git a/PluginDevFolder/SMLuaReaderPlugin/src/hooks.h b/PluginDevFolder/SMLuaReaderPlugin/src/hooks.h index 573d2fb..6681f9e 100644 --- a/PluginDevFolder/SMLuaReaderPlugin/src/hooks.h +++ b/PluginDevFolder/SMLuaReaderPlugin/src/hooks.h @@ -1,5 +1,5 @@ #include -#include +#include #include "lua.h" #include @@ -8,40 +8,40 @@ using Console::Color; // LUAL_REGISTER typedef void (*pluaL_register)(lua_State*, const char*, const luaL_Reg*); -Hook *hck_luaL_register; +GameHook* hck_luaL_register; // LUAL_LOADSTRING typedef int (*pluaL_loadstring)(lua_State*, const char*); -Hook *hck_luaL_loadstring; +GameHook *hck_luaL_loadstring; // LUA_NEWSTATE typedef lua_State *(*plua_newstate)(lua_Alloc, void*); -Hook *hck_lua_newstate; +GameHook *hck_lua_newstate; // LUAL_LOADBUFFER typedef int (*pluaL_loadbuffer)(lua_State*, const char*, size_t, const char*); -Hook *hck_luaL_loadbuffer; +GameHook *hck_luaL_loadbuffer; // ============= namespace Hooks { void hook_luaL_register(lua_State *L, const char *libname, const luaL_Reg *l) { Console::log(Color::Aqua, "hook_luaL_register: libname=[%s]", libname); - return ((pluaL_register)hck_luaL_register->Gate())(L, libname, l); + return ((pluaL_register)*hck_luaL_register)(L, libname, l); } int hook_luaL_loadstring(lua_State *L, const char *s) { Console::log(Color::Aqua, "hook_luaL_loadstring: s=[ ... ]"); - return ((pluaL_loadstring)hck_luaL_loadstring->Gate())(L, s); + return ((pluaL_loadstring)*hck_luaL_loadstring)(L, s); } lua_State *hook_lua_newstate(lua_Alloc f, void* ud) { Console::log(Color::Aqua, "hck_lua_newstate: ud=[%p]", ud); - return ((plua_newstate)hck_lua_newstate->Gate())(f, ud); + return ((plua_newstate)*hck_lua_newstate)(f, ud); } int hook_luaL_loadbuffer(lua_State *L, const char *buff, size_t sz, const char *name) { Console::log(Color::Aqua, "hck_luaL_loadbuffer: buff=[ ... ], sz=[%zu], name=[%s]", sz, name); - return ((pluaL_loadbuffer)hck_luaL_loadbuffer->Gate())(L, buff, sz, name); + return ((pluaL_loadbuffer)*hck_luaL_loadbuffer)(L, buff, sz, name); } } diff --git a/PluginDevFolder/SMLuaReaderPlugin/src/main.cpp b/PluginDevFolder/SMLuaReaderPlugin/src/main.cpp index 1b4ec67..bfa60b8 100644 --- a/PluginDevFolder/SMLuaReaderPlugin/src/main.cpp +++ b/PluginDevFolder/SMLuaReaderPlugin/src/main.cpp @@ -19,16 +19,14 @@ LIB_RESULT PluginLoad() { return PLUGIN_SUCCESSFULL; } -HookUtility* util; bool InjectLua() { Console::log(Color::Aqua, "Installing lua hooks"); - util = new HookUtility(); - hck_luaL_register = util->InjectFromName("lua51.dll", "luaL_register", &Hooks::hook_luaL_register, 15); - hck_luaL_loadstring = util->InjectFromName("lua51.dll", "luaL_loadstring", &Hooks::hook_luaL_loadstring, 16); - hck_lua_newstate = util->InjectFromName("lua51.dll", "lua_newstate", &Hooks::hook_lua_newstate, -14, 6); - hck_luaL_loadbuffer = util->InjectFromName("lua51.dll", "luaL_loadbuffer", &Hooks::hook_luaL_loadbuffer, 17, 13); - + hck_luaL_register = GameHooks::InjectFromName("lua51.dll", "luaL_register", &Hooks::hook_luaL_register, 15); + hck_luaL_loadstring = GameHooks::InjectFromName("lua51.dll", "luaL_loadstring", &Hooks::hook_luaL_loadstring, 16); + hck_lua_newstate = GameHooks::InjectFromName("lua51.dll", "lua_newstate", &Hooks::hook_lua_newstate, 6); + hck_luaL_loadbuffer = GameHooks::InjectFromName("lua51.dll", "luaL_loadbuffer", &Hooks::hook_luaL_loadbuffer, 13); + if(!hck_luaL_register) { Console::log(Color::Red, "Failed to inject 'luaL_register'"); return false; @@ -54,6 +52,6 @@ bool InjectLua() { LIB_RESULT PluginUnload() { Console::log(Color::Aqua, "Unloading this plugin!"); - util->Unload(); + //util->Unload(); return PLUGIN_SUCCESSFULL; } diff --git a/PluginDevFolder/TileEditorUnlockPlugin/src/main.cpp b/PluginDevFolder/TileEditorUnlockPlugin/src/main.cpp index 506865f..87e86d4 100644 --- a/PluginDevFolder/TileEditorUnlockPlugin/src/main.cpp +++ b/PluginDevFolder/TileEditorUnlockPlugin/src/main.cpp @@ -5,7 +5,8 @@ #include using Console::Color; -#include +#include "windows.h" +#include // debugSize == h.blueprintListCompressedSize @@ -24,10 +25,10 @@ namespace Injection { typedef longlong* _vector_ptr; typedef void(*pReadNode)(void*, _vector_ptr, void*, void*, void*, int); - Hook *hck_ReadNode; + GameHook *hck_ReadNode; typedef void(*pReadBlueprintList)(int, _vector_ptr, void*, void*, void*, int, void*, int); - Hook *hck_ReadBlueprintList; + GameHook *hck_ReadBlueprintList; longlong get_sm_handle() { return (longlong)GetModuleHandleA("ScrapMechanic.exe"); @@ -48,7 +49,7 @@ namespace Injection { void hook_ReadNode(void* a, _vector_ptr vec, void* b, void* c, void* d, int e) { Console::log(Color::Aqua, "hook_ReadNode: a=[%p], vec=[%p], b=[%p], c=[%p], d=[%p], e=[%d]", a, vec, b, c, d, e); - ((pReadNode)hck_ReadNode->Gate())(a, vec, b, c, d, e); + ((pReadNode)*hck_ReadNode)(a, vec, b, c, d, e); AddEntityToMemory(vec); return; @@ -56,7 +57,7 @@ namespace Injection { void hook_ReadBlueprintList(int a, _vector_ptr vec, void* b, void* c, void* d, int e, void* f, int g) { Console::log(Color::Aqua, "hook_ReadBlueprintList: a=[%d], vec=[%p], b=[%p], c=[%p], d=[%p], e=[%d], f=[%p], g=[%d]", a, vec, b, c, d, e, f, g); - ((pReadBlueprintList)hck_ReadBlueprintList->Gate())(a, vec, b, c, d, e, f, g); + ((pReadBlueprintList)*hck_ReadBlueprintList)(a, vec, b, c, d, e, f, g); AddEntityToMemory(vec); return; @@ -69,11 +70,8 @@ LIB_RESULT PluginLoad() { longlong sm_handle = Injection::get_sm_handle(); - Injection::hck_ReadNode = new Hook(); - Injection::hck_ReadNode->Inject((void*)(sm_handle + offset_ReadNode), &Injection::hook_ReadNode, 14); - - Injection::hck_ReadBlueprintList = new Hook(); - Injection::hck_ReadBlueprintList->Inject((void*)(sm_handle + offset_ReadBlueprintList), &Injection::hook_ReadBlueprintList, 16); + Injection::hck_ReadNode = GameHooks::Inject((void*)(sm_handle + offset_ReadNode), &Injection::hook_ReadNode, 14); + Injection::hck_ReadBlueprintList = GameHooks::Inject((void*)(sm_handle + offset_ReadBlueprintList), &Injection::hook_ReadBlueprintList, 16); return PLUGIN_SUCCESSFULL; } @@ -81,8 +79,8 @@ LIB_RESULT PluginLoad() { LIB_RESULT PluginUnload() { Console::log(Color::Red, "Unloading this plugin!"); - Injection::hck_ReadNode->Uninject(); - Injection::hck_ReadBlueprintList->Uninject(); + //Injection::hck_ReadNode->Uninject(); + //Injection::hck_ReadBlueprintList->Uninject(); return PLUGIN_SUCCESSFULL; } diff --git a/SMInjector/src/find_steam.h b/SMInjector/src/find_steam.h index ccb9fc1..2aadc88 100644 --- a/SMInjector/src/find_steam.h +++ b/SMInjector/src/find_steam.h @@ -47,6 +47,7 @@ namespace SteamFinder { int idx = 0; int len = 0; + bool next_is_path = false; bool quote = false; for(int i = 16; i < buffer.size(); i++) { char c = buffer[i]; @@ -54,16 +55,20 @@ namespace SteamFinder { if(c == '"') { temp[idx] = 0; - if(i > 16 && quote) { + if(quote) { len++; - if(len > 4 && ((len & 1) == 0)) { + + if(next_is_path) { vec.push_back(std::wstring(temp).append(L"\\steamapps\\common")); + next_is_path = false; + } else { + next_is_path = (wcscmp(temp, L"path") == 0); } temp[0] = 0; idx = 0; } - + quote = !quote; } else { if(quote) { diff --git a/SMLibrary/SMLibrary.vcxproj b/SMLibrary/SMLibrary.vcxproj index aabc594..41c4fb6 100644 --- a/SMLibrary/SMLibrary.vcxproj +++ b/SMLibrary/SMLibrary.vcxproj @@ -151,6 +151,7 @@ + diff --git a/SMLibrary/SMLibrary.vcxproj.filters b/SMLibrary/SMLibrary.vcxproj.filters index 362dd6b..3c136c5 100644 --- a/SMLibrary/SMLibrary.vcxproj.filters +++ b/SMLibrary/SMLibrary.vcxproj.filters @@ -38,5 +38,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/SMLibrary/include/gamehook.h b/SMLibrary/include/gamehook.h new file mode 100644 index 0000000..ec7743e --- /dev/null +++ b/SMLibrary/include/gamehook.h @@ -0,0 +1,181 @@ +#include "stdafx.h" + +#ifndef __GAMEHOOK_H__ +#define __GAMEHOOK_H__ + +typedef void* GameHook; +typedef long long longlong; + +#ifndef _SM_LIBRARY_BUILD_PLUGIN +#include +#include +#endif + + +namespace GameHooks { +#ifndef _SM_LIBRARY_BUILD_PLUGIN + + // Struct describing the hook + struct GateContext { + // The address of the hooked function + void* function; + + // The length in bytes of the hook + size_t length; + + // The allocated page within 2GB + void* page_address; + + // The gate that should be called + void* end_gate; + + // Last hook injected + GameHook* last_hook; + }; + + // We need to specify a map that contains information about where we have hooked stuff previously + std::map hooked_map; + + void* AllocatePageWithin2GB(void* target_address, int length) { + static ULONG dwAllocationGranularity; + + // Fetch some allocation size + if(!dwAllocationGranularity) { + SYSTEM_INFO si; + GetSystemInfo(&si); + dwAllocationGranularity = si.dwAllocationGranularity; + } + + UINT_PTR address = (UINT_PTR)target_address; + SIZE_T dwSize = length; + + UINT_PTR min, max, addr, add = dwAllocationGranularity - 1, mask = ~add; + min = address >= 0x80000000 ? (address - 0x80000000 + add) & mask : 0; + max = address < (UINTPTR_MAX - 0x80000000) ? (address + 0x80000000) & mask : UINTPTR_MAX; + + ::MEMORY_BASIC_INFORMATION mbi; + do { + // Query information about the currently requested memory + if(!VirtualQuery((void*)min, &mbi, sizeof(mbi))) return nullptr; + + // Spooky stuff + min = (UINT_PTR)mbi.BaseAddress + mbi.RegionSize; + + if(mbi.State == MEM_FREE) { + addr = ((UINT_PTR)mbi.BaseAddress + add) & mask; + + if(addr < min && dwSize <= (min - addr)) { + if(addr = (UINT_PTR)VirtualAlloc((PVOID)addr, dwSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)) { + return (PVOID)addr; + } + } + } + } while (min < max); + + return nullptr; + } + + GateContext* CreateInjectionHook(void* target_function, int length) { + GateContext* context = new GateContext(); + context->function = target_function; + context->length = length; + context->page_address = AllocatePageWithin2GB(target_function, length + 28); + context->end_gate = (void*)((long long)context->page_address + 14); + // context.last_hook + + return context; + } + + // Modify context to inject gate + + bool InjectGate(GateContext* context, void *dst, void *src) { + typedef long long longlong; + + size_t len = context->length; + void* gate = context->page_address; + + // Make the first jump into the target method + *(longlong*)((longlong)gate) = 0x25FF; // Add far jump + *(longlong*)((longlong)gate + 6) = (longlong)src; + + // Store the first 'len' bytes of the function into the newly created gate + memcpy((void*)((longlong)gate + 14), dst, len); + // Construct the far jump to the begining of the hooked function + *(longlong*)((longlong)gate + len + 14) = 0x25FF; // Add far jump + *(longlong*)((longlong)gate + len + 20) = (longlong)dst + len; + + DWORD oldProtection; + // Update the protection for the gate memory + VirtualProtect(gate, (size_t)len + 6, PAGE_EXECUTE_READ, &oldProtection); + + // Allow modifications of the target function + VirtualProtect(dst, (size_t)len, PAGE_EXECUTE_READWRITE, &oldProtection); + + memset(dst, 0x90, len); // Fill the replaced region with NOP + + // Modify the target function + // page_address - target_addres - 5 + + // Make the first 5 bytes point towards the page with the absolute jump + *(char*)((longlong)dst) = 0xE9; + // Make sure this is within the 2GB range !!!!!!!! + *(int*)((longlong)dst + 1) = (int)((longlong)context->page_address - (longlong)dst - 5); + + DWORD temp; + VirtualProtect(dst, (size_t)len, oldProtection, &temp); + + GameHook* gate_hook = new GameHook(); + *((void**)gate_hook) = context->end_gate; + context->last_hook = gate_hook; + + return true; + } + + _LIB_EXPORT GameHook* Inject(void* target_function, void* hook_function, int length) { + // First we check if we have already hooked the function + auto iter = hooked_map.find(target_function); + if(iter != hooked_map.end()) { + // target function was already injected + GateContext* context = iter->second; + + // Modify the last hooks gate to point to the new function + *((void**)context->last_hook) = hook_function; + + // Modify the next hook to point towards the end gate + GameHook* next_hook = new GameHook(); + *((void**)next_hook) = context->end_gate; + + // Update the last injected hook + context->last_hook = next_hook; + + return next_hook; + } else { + GateContext* new_context = CreateInjectionHook(target_function, length); + + if(!InjectGate(new_context, target_function, hook_function)) { + return nullptr; + } + + hooked_map[target_function] = new_context; + return new_context->last_hook; + } + } + + _LIB_EXPORT GameHook* InjectFromName(const char* module_name, const char* proc_name, void* hook_function, int length) { + HMODULE hModule = GetModuleHandleA(module_name); + if(!hModule) { + //printf("The module '%s' was not found\n", module_name); + return nullptr; + } + + void* target = GetProcAddress(hModule, proc_name); + return GameHooks::Inject(target, hook_function, length); + } +#else + _LIB_IMPORT GameHook* InjectFromName(const char* module_name, const char* proc_name, void* hook_function, int length); + _LIB_IMPORT GameHook* Inject(void* target_function, void* hook_function, int length); +#endif + +} + +#endif diff --git a/SMLibrary/include/hook.h b/SMLibrary/include/hook.h index 3008a79..1e0107e 100644 --- a/SMLibrary/include/hook.h +++ b/SMLibrary/include/hook.h @@ -1,5 +1,14 @@ #include +#ifndef _SM_LIBRARY_ALLOW_OLD_HOOKS +#error \ +The header file 'hook.h' is deprecated and will be removed in the future.\ +To enable this header use '#define _SM_LIBRARY_ALLOW_OLD_HOOKS'\ +This header will be removed in the future. +#else +#pragma message ("The header file 'hook.h' is deprecated and will be removed in the future.") +#endif + #include using std::string; diff --git a/SMLibrary/src/hook.cpp b/SMLibrary/src/hook.cpp index b424d5b..e8362c4 100644 --- a/SMLibrary/src/hook.cpp +++ b/SMLibrary/src/hook.cpp @@ -1,3 +1,4 @@ +#define _SM_LIBRARY_ALLOW_OLD_HOOKS #include "../include/hook.h" Hook::~Hook() { diff --git a/SMLibrary/src/hooks.h b/SMLibrary/src/hooks.h index 8dfcb60..c315d51 100644 --- a/SMLibrary/src/hooks.h +++ b/SMLibrary/src/hooks.h @@ -1,19 +1,19 @@ #include -#include "../include/hook.h" +#include "../include/gamehook.h" #include "../include/console.h" using Console::Color; // INIT_CONSOLE typedef void (*pinit_console)(void*, void*); -Hook *hck_init_console; +GameHook *hck_init_console; // ============= namespace Hooks { void hook_init_console(void* a, void* b) { FreeConsole(); - ((pinit_console)hck_init_console->Gate())(a, b); + ((pinit_console)*hck_init_console)(a, b); PostConsoleInjections(); return; } diff --git a/SMLibrary/src/sm_lib.cpp b/SMLibrary/src/sm_lib.cpp index 29aab28..3a833c5 100644 --- a/SMLibrary/src/sm_lib.cpp +++ b/SMLibrary/src/sm_lib.cpp @@ -7,11 +7,11 @@ #define _SM_OUTPUT_LOGS #include "../include/sm_lib.h" -#include "../include/hook.h" #include "../include/console.h" using Console::Color; +#include "../include/gamehook.h" constexpr longlong offset_InitConsole = 0x1b5410; //0x1b5090; @@ -29,7 +29,6 @@ _LIB_EXPORT void InjectPlugin(void* hModule, const char *plugin_name, LIB_CALLBA } BOOL PostConsoleInjections(); -HookUtility *util; #include "hooks.h" @@ -37,15 +36,14 @@ BOOL Startup(HMODULE hModule) { HMODULE sm_handle = GetModuleHandleA("ScrapMechanic.exe"); if(!sm_handle) return false; - hck_init_console = new Hook(); - hck_init_console->Inject((void*)((longlong)sm_handle + offset_InitConsole), &Hooks::hook_init_console, 0, 15); + hck_init_console = GameHooks::Inject((void*)((longlong)sm_handle + offset_InitConsole), &Hooks::hook_init_console, 5); + return true; } BOOL PostConsoleInjections() { Console::log_open(); Console::log(Color::Aqua, "Installing the library functions"); - util = new HookUtility(); const size_t plugins_size = plugins.size(); Console::log(Color::Aqua, "Found '%d' plugin(s)", plugins_size); @@ -65,8 +63,8 @@ BOOL PostConsoleInjections() { BOOL WINAPI DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) { switch(fdwReason) { case DLL_PROCESS_ATTACH: + Startup(hModule); MessageBox(0, L"From DLL\n", L"Process Attach", MB_ICONINFORMATION); - CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Startup, hModule, NULL, NULL); break; case DLL_PROCESS_DETACH: