From 4c4d605d10109e02708984755405bbe0947ef5c4 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Thu, 8 Jul 2021 15:33:31 +0100 Subject: initial commit --- InjectorTest/InjectorTest.vcxproj | 147 +++++++++++++++ InjectorTest/InjectorTest.vcxproj.filters | 22 +++ InjectorTest/main.cpp | 68 +++++++ .../NorthstarDedicatedTest.vcxproj | 209 +++++++++++++++++++++ .../NorthstarDedicatedTest.vcxproj.filters | 123 ++++++++++++ NorthstarDedicatedTest/context.cpp | 16 ++ NorthstarDedicatedTest/context.h | 11 ++ NorthstarDedicatedTest/dedicated.cpp | 101 ++++++++++ NorthstarDedicatedTest/dedicated.h | 30 +++ NorthstarDedicatedTest/dllmain.cpp | 49 +++++ NorthstarDedicatedTest/hooks.cpp | 90 +++++++++ NorthstarDedicatedTest/hooks.h | 7 + NorthstarDedicatedTest/hookutils.cpp | 57 ++++++ NorthstarDedicatedTest/hookutils.h | 34 ++++ NorthstarDedicatedTest/include/MinHook.h | 186 ++++++++++++++++++ NorthstarDedicatedTest/include/MinHook.x64.dll | Bin 0 -> 15360 bytes NorthstarDedicatedTest/include/MinHook.x64.lib | Bin 0 -> 4048 bytes NorthstarDedicatedTest/include/MinHook.x86.dll | Bin 0 -> 12288 bytes NorthstarDedicatedTest/include/MinHook.x86.lib | Bin 0 -> 4238 bytes NorthstarDedicatedTest/include/tier0.def | 10 + NorthstarDedicatedTest/include/tier0.exp | Bin 0 -> 1636 bytes NorthstarDedicatedTest/include/tier0.lib | Bin 0 -> 2840 bytes NorthstarDedicatedTest/logging.cpp | 52 +++++ NorthstarDedicatedTest/logging.h | 11 ++ NorthstarDedicatedTest/main.h | 3 + NorthstarDedicatedTest/pch.cpp | 5 + NorthstarDedicatedTest/pch.h | 11 ++ NorthstarDedicatedTest/sigscanning.cpp | 39 ++++ NorthstarDedicatedTest/sigscanning.h | 7 + NorthstarDedicatedTest/sourceconsole.cpp | 14 ++ NorthstarDedicatedTest/sourceconsole.h | 90 +++++++++ NorthstarDedicatedTest/sourceinterface.cpp | 13 ++ NorthstarDedicatedTest/sourceinterface.h | 24 +++ NorthstarDedicatedTest/squirrel.cpp | 67 +++++++ NorthstarDedicatedTest/squirrel.h | 26 +++ NorthstarDedicatedTest/tier0.cpp | 33 ++++ NorthstarDedicatedTest/tier0.h | 9 + R2Northstar.sln | 46 +++++ 38 files changed, 1610 insertions(+) create mode 100644 InjectorTest/InjectorTest.vcxproj create mode 100644 InjectorTest/InjectorTest.vcxproj.filters create mode 100644 InjectorTest/main.cpp create mode 100644 NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj create mode 100644 NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters create mode 100644 NorthstarDedicatedTest/context.cpp create mode 100644 NorthstarDedicatedTest/context.h create mode 100644 NorthstarDedicatedTest/dedicated.cpp create mode 100644 NorthstarDedicatedTest/dedicated.h create mode 100644 NorthstarDedicatedTest/dllmain.cpp create mode 100644 NorthstarDedicatedTest/hooks.cpp create mode 100644 NorthstarDedicatedTest/hooks.h create mode 100644 NorthstarDedicatedTest/hookutils.cpp create mode 100644 NorthstarDedicatedTest/hookutils.h create mode 100644 NorthstarDedicatedTest/include/MinHook.h create mode 100644 NorthstarDedicatedTest/include/MinHook.x64.dll create mode 100644 NorthstarDedicatedTest/include/MinHook.x64.lib create mode 100644 NorthstarDedicatedTest/include/MinHook.x86.dll create mode 100644 NorthstarDedicatedTest/include/MinHook.x86.lib create mode 100644 NorthstarDedicatedTest/include/tier0.def create mode 100644 NorthstarDedicatedTest/include/tier0.exp create mode 100644 NorthstarDedicatedTest/include/tier0.lib create mode 100644 NorthstarDedicatedTest/logging.cpp create mode 100644 NorthstarDedicatedTest/logging.h create mode 100644 NorthstarDedicatedTest/main.h create mode 100644 NorthstarDedicatedTest/pch.cpp create mode 100644 NorthstarDedicatedTest/pch.h create mode 100644 NorthstarDedicatedTest/sigscanning.cpp create mode 100644 NorthstarDedicatedTest/sigscanning.h create mode 100644 NorthstarDedicatedTest/sourceconsole.cpp create mode 100644 NorthstarDedicatedTest/sourceconsole.h create mode 100644 NorthstarDedicatedTest/sourceinterface.cpp create mode 100644 NorthstarDedicatedTest/sourceinterface.h create mode 100644 NorthstarDedicatedTest/squirrel.cpp create mode 100644 NorthstarDedicatedTest/squirrel.h create mode 100644 NorthstarDedicatedTest/tier0.cpp create mode 100644 NorthstarDedicatedTest/tier0.h create mode 100644 R2Northstar.sln diff --git a/InjectorTest/InjectorTest.vcxproj b/InjectorTest/InjectorTest.vcxproj new file mode 100644 index 00000000..f2e52e25 --- /dev/null +++ b/InjectorTest/InjectorTest.vcxproj @@ -0,0 +1,147 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {3c3fc37c-d4b9-4413-aadf-c52fd2f428e6} + InjectorTest + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/InjectorTest/InjectorTest.vcxproj.filters b/InjectorTest/InjectorTest.vcxproj.filters new file mode 100644 index 00000000..ce0c35cc --- /dev/null +++ b/InjectorTest/InjectorTest.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/InjectorTest/main.cpp b/InjectorTest/main.cpp new file mode 100644 index 00000000..351708c3 --- /dev/null +++ b/InjectorTest/main.cpp @@ -0,0 +1,68 @@ +#include + +#define PROC_NAME L"Titanfall2-unpacked.exe" +#define DLL_NAME L"Northstar.dll" + +int main() { + STARTUPINFO startupInfo; + PROCESS_INFORMATION processInfo; + + memset(&startupInfo, 0, sizeof(startupInfo)); + memset(&processInfo, 0, sizeof(processInfo)); + + CreateProcessW(PROC_NAME, (LPWSTR)L"", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfo); + + HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll"); + LPTHREAD_START_ROUTINE pLoadLibraryW = + (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW"); + + SIZE_T dwLength = (wcslen(DLL_NAME) + 1) * 2; + LPVOID lpLibName = VirtualAllocEx(processInfo.hProcess, NULL, dwLength, MEM_COMMIT, PAGE_READWRITE); + + SIZE_T written = 0; + WriteProcessMemory(processInfo.hProcess, lpLibName, DLL_NAME, dwLength, &written); + + HANDLE hThread = CreateRemoteThread(processInfo.hProcess, NULL, NULL, pLoadLibraryW, lpLibName, NULL, NULL); + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + + // TODO: need to call initialisenorthstar in the new process + // also rewrite injector to be clean lol + // (this does not currently work!!! ) + //LPTHREAD_START_ROUTINE pInitNorthstar = (LPTHREAD_START_ROUTINE)GetProcAddress((HMODULE)lpLibName, "InitialiseNorthstar"); + //HANDLE hInitThread = CreateRemoteThread(processInfo.hProcess, NULL, NULL, pInitNorthstar, NULL, NULL, NULL); + //WaitForSingleObject(hInitThread, INFINITE); + //CloseHandle(hInitThread); + + ResumeThread(processInfo.hThread); + + VirtualFreeEx(processInfo.hProcess, lpLibName, dwLength, MEM_RELEASE); + + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + + return 0; +} + +/* +#define DEFAULT_PROCESS_NAME = L"Titanfall2.exe" + +int main(int argc, char** argv) +{ + STARTUPINFO startupInfo; + PROCESS_INFORMATION processInfo; + + memset(&startupInfo, 0, sizeof(startupInfo)); + memset(&processInfo, 0, sizeof(processInfo)); + + LPCWSTR processName; + if (argc > 0) + { + processName = *argv; + } + else + processName = DEFAULT_PROCESS_NAME; + + CreateProcessW() +} +*/ \ No newline at end of file diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj new file mode 100644 index 00000000..8af2d3e0 --- /dev/null +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -0,0 +1,209 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {cfad2623-064f-453c-8196-79ee10292e32} + NorthstarDedicatedTest + 10.0 + Northstar + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp17 + + + Windows + true + false + %(AdditionalDependencies) + + + + + Level3 + true + true + true + WIN32;NDEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp17 + + + Windows + true + true + true + false + %(AdditionalDependencies) + + + + + Level3 + true + _DEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp17 + $(ProjectDir)include;%(AdditionalIncludeDirectories) + + + Windows + true + false + $(ProjectDir)include\MinHook.x64.lib;%(AdditionalDependencies) + + + + + + + + + Level3 + true + true + true + NDEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp17 + $(ProjectDir)include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + false + $(ProjectDir)include\MinHook.x64.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + \ No newline at end of file diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters new file mode 100644 index 00000000..e9e523e8 --- /dev/null +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -0,0 +1,123 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {d4199e4b-10d2-43ce-af9c-e1fa79e1e64e} + + + {4d322431-dcaa-4f75-aee0-3b6371cf52a6} + + + {94259c8c-5411-48bf-af4f-46ca32b7d0bb} + + + {4f525372-34a8-40b3-8a95-81d77cdfcf7f} + + + {4db0d1e9-9035-457f-87f1-5dc3f13b6b9e} + + + {947835db-67d6-42c0-870d-62743f85231f} + + + {8b8ed12a-9269-4dc3-b932-0daefdf6a388} + + + {b6f79919-9735-476d-8798-067a75cbeca0} + + + {ca657be5-c2d8-4322-a689-1154aaafe57b} + + + + + Header Files + + + Header Files\include + + + Header Files\Shared\Hooks + + + Header Files\Shared\Hooks + + + Header Files\Shared + + + Header Files + + + Header Files\Dedicated + + + Header Files\Client + + + Header Files\Shared + + + Header Files\Shared\Hooks + + + Header Files\Shared + + + Header Files\Shared + + + Header Files\Shared + + + + + Source Files + + + Source Files + + + Source Files\Shared\Hooks + + + Source Files\Shared + + + Source Files\Shared\Hooks + + + Source Files\Dedicated + + + Source Files\Client + + + Source Files\Shared + + + Source Files\Shared\Hooks + + + Source Files\Shared + + + Source Files\Shared + + + Source Files\Shared + + + \ No newline at end of file diff --git a/NorthstarDedicatedTest/context.cpp b/NorthstarDedicatedTest/context.cpp new file mode 100644 index 00000000..6cd9d885 --- /dev/null +++ b/NorthstarDedicatedTest/context.cpp @@ -0,0 +1,16 @@ +#include "pch.h" +#include "context.h" + +const char* GetContextName(Context context) +{ + if (context == NONE) + return ""; + if (context == CLIENT) + return "CLIENT"; + else if (context == SERVER) + return "SERVER"; + else if (context == UI) + return "UI"; + + return nullptr; +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/context.h b/NorthstarDedicatedTest/context.h new file mode 100644 index 00000000..05506973 --- /dev/null +++ b/NorthstarDedicatedTest/context.h @@ -0,0 +1,11 @@ +#pragma once + +enum Context +{ + NONE, + CLIENT, + SERVER, + UI // this is used exclusively in scripts +}; + +const char* GetContextName(Context context); \ No newline at end of file diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp new file mode 100644 index 00000000..ce4723cb --- /dev/null +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -0,0 +1,101 @@ +#include "pch.h" +#include "dedicated.h" +#include "hookutils.h" + +#include + +bool IsDedicated() +{ + // temp: should get this from commandline + return false; +} + +void InitialiseDedicated(HMODULE engineAddress) +{ + std::cout << "InitialiseDedicated()" << std::endl; + + while (!IsDebuggerPresent()) + Sleep(100); + + // create binary patches + { + // CEngineAPI::SetStartupInfo + // prevents englishclient_frontend from loading + + char* ptr = (char*)engineAddress + 0x1C7CBE; + TempReadWrite rw(ptr); + + // je => jmp + *ptr = (char)0xEB; + } + + { + // CModAppSystemGroup::Create + // force the engine into dedicated mode by changing the first comparison to IsServerOnly to an assignment + char* ptr = (char*)engineAddress + 0x1C4EBD; + TempReadWrite rw(ptr); + + // cmp => mov + *(ptr + 1) = (char)0xC6; + *(ptr + 2) = (char)0x87; + + // 00 => 01 + *((char*)ptr + 7) = (char)0x01; + } + + { + // Some init that i'm not sure of that crashes + char* ptr = (char*)engineAddress + 0x156A63; + TempReadWrite rw(ptr); + + // nop the call to it + *ptr = (char)0x90; + *(ptr + 1) = (char)0x90; + *(ptr + 2) = (char)0x90; + *(ptr + 3) = (char)0x90; + *(ptr + 4) = (char)0x90; + } + + CDedicatedExports* dedicatedApi = new CDedicatedExports; + dedicatedApi->Sys_Printf = Sys_Printf; + dedicatedApi->RunServer = RunServer; + + // double ptr to dedicatedApi + intptr_t* ptr = (intptr_t*)((char*)engineAddress + 0x13F0B668); + + // ptr to dedicatedApi + intptr_t* doublePtr = new intptr_t; + *doublePtr = (intptr_t)dedicatedApi; + + // ptr to ptr + *ptr = (intptr_t)doublePtr; +} + +void Sys_Printf(CDedicatedExports* dedicated, char* msg) +{ + std::cout << msg << std::endl; +} + +void RunServer(CDedicatedExports* dedicated) +{ + Sys_Printf(dedicated, (char*)"CDedicatedServerAPI::RunServer(): starting"); + + HMODULE engine = GetModuleHandleA("engine.dll"); + CEngine__Frame engineFrame = (CEngine__Frame)((char*)engine + 0x1C8650); + CEngineAPI__ActivateSimulation engineApiStartSimulation = (CEngineAPI__ActivateSimulation)((char*)engine + 0x1C4370); + + void* cEnginePtr = (void*)((char*)engine + 0x7D70C8); + + CEngineAPI__SetMap engineApiSetMap = (CEngineAPI__SetMap)((char*)engine + 0x1C7B30); + + engineApiSetMap(nullptr, "mp_lobby; net_usesocketsforloopback 1"); + Sys_Printf(dedicated, (char*)"CDedicatedServerAPI::RunServer(): map mp_lobby"); + + while (true) + { + engineFrame(cEnginePtr); + //engineApiStartSimulation(nullptr, true); + Sys_Printf(dedicated, (char*)"engine->Frame()"); + Sleep(50); + } +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/dedicated.h b/NorthstarDedicatedTest/dedicated.h new file mode 100644 index 00000000..61d430ac --- /dev/null +++ b/NorthstarDedicatedTest/dedicated.h @@ -0,0 +1,30 @@ +#pragma once + +bool IsDedicated(); + +struct CDedicatedExports; // forward declare + +// functions for CDedicatedServerAPI +typedef void (*DedicatedSys_Printf)(CDedicatedExports* dedicated, char* msg); +typedef void (*DedicatedRunServer)(CDedicatedExports* dedicated); + +void Sys_Printf(CDedicatedExports* dedicated, char* msg); +void RunServer(CDedicatedExports* dedicated); + +// functions for running dedicated server +typedef bool (*CEngine__Frame)(void* engineSelf); +typedef void (*CEngineAPI__SetMap)(void* engineApiSelf, const char* pMapName); +typedef void (*CEngineAPI__ActivateSimulation)(void* engineApiSelf, bool bActive); + +// struct used internally +struct CDedicatedExports +{ + char unused[64]; + DedicatedSys_Printf Sys_Printf; // base + 64 + DedicatedRunServer RunServer; // base + 72 +}; + +// hooking stuff +extern bool bDedicatedHooksInitialised; +void InitialiseDedicated(HMODULE moduleAddress); + diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp new file mode 100644 index 00000000..f71a39a8 --- /dev/null +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -0,0 +1,49 @@ +#include "pch.h" +#include "hooks.h" +#include "main.h" +#include "squirrel.h" +#include "dedicated.h" +#include "sourceconsole.h" +#include + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + DisableThreadLibraryCalls(hModule); + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + + InitialiseNorthstar(); + + return TRUE; +} + +// this is called from the injector and initialises stuff, dllmain is called multiple times while this should only be called once +void InitialiseNorthstar() +{ + AllocConsole(); + freopen("CONOUT$", "w", stdout); + AddLoggingSink(DefaultLoggingSink); + + // apply hooks + InstallInitialHooks(); + + if (IsDedicated()) + AddDllLoadCallback("engine.dll", InitialiseDedicated); + + if (!IsDedicated()) + { + AddDllLoadCallback("client.dll", InitialiseClientSquirrel); + AddDllLoadCallback("client.dll", InitialiseSourceConsole); + } + + AddDllLoadCallback("server.dll", InitialiseServerSquirrel); +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp new file mode 100644 index 00000000..a3be154d --- /dev/null +++ b/NorthstarDedicatedTest/hooks.cpp @@ -0,0 +1,90 @@ +#include "pch.h" +#include "hooks.h" +#include "hookutils.h" +#include "dedicated.h" +#include "tier0.h" + +#include +#include +#include + +typedef HMODULE(*LoadLibraryExAType)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); +HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); + +typedef HMODULE(*LoadLibraryExWType)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); +HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); + +LoadLibraryExAType LoadLibraryExAOriginal; +LoadLibraryExWType LoadLibraryExWOriginal; + +void InstallInitialHooks() +{ + //AllocConsole(); + + if (MH_Initialize() != MH_OK) + Error("MH_Initialize failed"); + + HookEnabler hook; + ENABLER_CREATEHOOK(hook, &LoadLibraryExA, &LoadLibraryExAHook, reinterpret_cast(&LoadLibraryExAOriginal)); + ENABLER_CREATEHOOK(hook, &LoadLibraryExW, &LoadLibraryExWHook, reinterpret_cast(&LoadLibraryExWOriginal)); +} + +// dll load callback stuff +// this allows for code to register callbacks to be run as soon as a dll is loaded, mainly to allow for patches to be made on dll load +struct DllLoadCallback +{ + std::string dll; + DllLoadCallbackFuncType callback; + bool called; +}; + +std::vector dllLoadCallbacks; + +void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback) +{ + DllLoadCallback* callbackStruct = new DllLoadCallback; + callbackStruct->dll = dll; + callbackStruct->callback = callback; + callbackStruct->called = false; + + dllLoadCallbacks.push_back(callbackStruct); +} + +HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) +{ + HMODULE moduleAddress = LoadLibraryExAOriginal(lpLibFileName, hFile, dwFlags); + + if (moduleAddress) + { + for (auto& callbackStruct : dllLoadCallbacks) + { + if (!callbackStruct->called && strstr(lpLibFileName + (strlen(lpLibFileName) - strlen(callbackStruct->dll.c_str())), callbackStruct->dll.c_str()) != nullptr) + { + callbackStruct->callback(moduleAddress); + callbackStruct->called = true; + } + } + } + + return moduleAddress; +} + +HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) +{ + HMODULE moduleAddress = LoadLibraryExWOriginal(lpLibFileName, hFile, dwFlags); + + if (moduleAddress) + { + for (auto& callbackStruct : dllLoadCallbacks) + { + const wchar_t* callbackDll = std::wstring(callbackStruct->dll.begin(), callbackStruct->dll.end()).c_str(); + if (!callbackStruct->called && wcsstr(lpLibFileName + (wcslen(lpLibFileName) - wcslen(callbackDll)), callbackDll) != nullptr) + { + callbackStruct->callback(moduleAddress); + callbackStruct->called = true; + } + } + } + + return moduleAddress; +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/hooks.h b/NorthstarDedicatedTest/hooks.h new file mode 100644 index 00000000..972b38a6 --- /dev/null +++ b/NorthstarDedicatedTest/hooks.h @@ -0,0 +1,7 @@ +#pragma once +#include + +void InstallInitialHooks(); + +typedef void(*DllLoadCallbackFuncType)(HMODULE moduleAddress); +void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback); \ No newline at end of file diff --git a/NorthstarDedicatedTest/hookutils.cpp b/NorthstarDedicatedTest/hookutils.cpp new file mode 100644 index 00000000..c5472b57 --- /dev/null +++ b/NorthstarDedicatedTest/hookutils.cpp @@ -0,0 +1,57 @@ +#include "pch.h" +#include "hookutils.h" +#include "tier0.h" + +#include + +TempReadWrite::TempReadWrite(void* ptr) +{ + m_ptr = ptr; + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(m_ptr, &mbi, sizeof(mbi)); + VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect); + m_origProtection = mbi.Protect; +} + +TempReadWrite::~TempReadWrite() +{ + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(m_ptr, &mbi, sizeof(mbi)); + VirtualProtect(mbi.BaseAddress, mbi.RegionSize, m_origProtection, &mbi.Protect); +} + + +void HookEnabler::CreateHook(LPVOID ppTarget, LPVOID ppDetour, LPVOID* ppOriginal, const char* targetName) +{ + if (MH_CreateHook(ppTarget, ppDetour, ppOriginal) == MH_OK) + { + HookTarget *target = new HookTarget; + target->targetAddress = ppTarget; + target->targetName = (char*)targetName; + + m_hookTargets.push_back(target); + } + else + { + if (targetName != nullptr) + Error("MH_CreateHook failed for function %s", targetName); + else + Error("MH_CreateHook failed for unknown function"); + } +} + +HookEnabler::~HookEnabler() +{ + for (auto& hook : m_hookTargets) + { + if (MH_EnableHook(hook->targetAddress) != MH_OK) + { + if (hook->targetName != nullptr) + Error("MH_EnableHook failed for function %s", hook->targetName); + else + Error("MH_EnableHook failed for unknown function"); + } + else + std::cout << "enabling hook " << hook->targetName << std::endl; + } +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/hookutils.h b/NorthstarDedicatedTest/hookutils.h new file mode 100644 index 00000000..dd3b15b1 --- /dev/null +++ b/NorthstarDedicatedTest/hookutils.h @@ -0,0 +1,34 @@ +#pragma once +#include + +// Sets an area of memory as writeable until the TempReadWrite object goes out of scope +class TempReadWrite +{ +private: + DWORD m_origProtection; + void* m_ptr; + +public: + TempReadWrite(void* ptr); + ~TempReadWrite(); +}; + +// Enables all hooks created with the HookEnabler object when it goes out of scope and handles hook errors +class HookEnabler +{ +private: + struct HookTarget + { + char* targetName; + LPVOID targetAddress; + }; + + std::vector m_hookTargets; + +public: + void CreateHook(LPVOID ppTarget, LPVOID ppDetour, LPVOID* ppOriginal, const char* targetName = nullptr); + ~HookEnabler(); +}; + +// macro to call HookEnabler::CreateHook with the hook's name +#define ENABLER_CREATEHOOK(enabler, ppTarget, ppDetour, ppOriginal) enabler.CreateHook(ppTarget, ppDetour, ppOriginal, #ppDetour) \ No newline at end of file diff --git a/NorthstarDedicatedTest/include/MinHook.h b/NorthstarDedicatedTest/include/MinHook.h new file mode 100644 index 00000000..15c0a875 --- /dev/null +++ b/NorthstarDedicatedTest/include/MinHook.h @@ -0,0 +1,186 @@ +/* + * 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. + // pszTarget [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. + // pszTarget [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/NorthstarDedicatedTest/include/MinHook.x64.dll b/NorthstarDedicatedTest/include/MinHook.x64.dll new file mode 100644 index 00000000..b4f51c2e Binary files /dev/null and b/NorthstarDedicatedTest/include/MinHook.x64.dll differ diff --git a/NorthstarDedicatedTest/include/MinHook.x64.lib b/NorthstarDedicatedTest/include/MinHook.x64.lib new file mode 100644 index 00000000..909fe682 Binary files /dev/null and b/NorthstarDedicatedTest/include/MinHook.x64.lib differ diff --git a/NorthstarDedicatedTest/include/MinHook.x86.dll b/NorthstarDedicatedTest/include/MinHook.x86.dll new file mode 100644 index 00000000..d6167c83 Binary files /dev/null and b/NorthstarDedicatedTest/include/MinHook.x86.dll differ diff --git a/NorthstarDedicatedTest/include/MinHook.x86.lib b/NorthstarDedicatedTest/include/MinHook.x86.lib new file mode 100644 index 00000000..02f351c2 Binary files /dev/null and b/NorthstarDedicatedTest/include/MinHook.x86.lib differ diff --git a/NorthstarDedicatedTest/include/tier0.def b/NorthstarDedicatedTest/include/tier0.def new file mode 100644 index 00000000..6834b009 --- /dev/null +++ b/NorthstarDedicatedTest/include/tier0.def @@ -0,0 +1,10 @@ +LIBRARY tier0.dll +EXPORTS +CreateGlobalMemAlloc +g_pMemAllocSingleton +ThreadInMainThread + +Error + +LoggingSystem_RegisterLoggingListener +LoggingSystem_Log \ No newline at end of file diff --git a/NorthstarDedicatedTest/include/tier0.exp b/NorthstarDedicatedTest/include/tier0.exp new file mode 100644 index 00000000..706b6de8 Binary files /dev/null and b/NorthstarDedicatedTest/include/tier0.exp differ diff --git a/NorthstarDedicatedTest/include/tier0.lib b/NorthstarDedicatedTest/include/tier0.lib new file mode 100644 index 00000000..6b0ffa5c Binary files /dev/null and b/NorthstarDedicatedTest/include/tier0.lib differ diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp new file mode 100644 index 00000000..021613d9 --- /dev/null +++ b/NorthstarDedicatedTest/logging.cpp @@ -0,0 +1,52 @@ +#include "pch.h" +#include "logging.h" +#include "context.h" +#include "dedicated.h" +#include +#include +#include + +std::vector loggingSinks; + +void Log(Context context, char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + + Log(context, fmt, args); + va_end(args); +} + +void Log(Context context, char* fmt, va_list args) +{ + char buf[1024]; + vsnprintf_s(buf, _TRUNCATE, fmt, args); + + for (LoggingSink& sink : loggingSinks) + sink(context, fmt); +} + +void AddLoggingSink(LoggingSink sink) +{ + loggingSinks.push_back(sink); +} + +// default logging sink +void DefaultLoggingSink(Context context, char* message) +{ + time_t now = time(0); + tm* localTime = localtime(&now); + char timeBuf[10]; + strftime(timeBuf, sizeof(timeBuf), "%X", localTime); + + std::cout << "[" << timeBuf << "] "; + if (context != NONE) + std::cout << "[" << GetContextName(context) << "] "; + + std::cout << message; + + if (!IsDedicated()) + { + + } +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/logging.h b/NorthstarDedicatedTest/logging.h new file mode 100644 index 00000000..aa19b8f1 --- /dev/null +++ b/NorthstarDedicatedTest/logging.h @@ -0,0 +1,11 @@ +#pragma once +#include "context.h" + +typedef void(*LoggingSink)(Context context, char* fmt); + +void Log(Context context, char* fmt, ...); +void Log(Context context, char* fmt, va_list args); +void AddLoggingSink(LoggingSink sink); + +// default logging sink +void DefaultLoggingSink(Context context, char* message); \ No newline at end of file diff --git a/NorthstarDedicatedTest/main.h b/NorthstarDedicatedTest/main.h new file mode 100644 index 00000000..ef5d86dc --- /dev/null +++ b/NorthstarDedicatedTest/main.h @@ -0,0 +1,3 @@ +#pragma once + +extern "C" __declspec(dllexport) void InitialiseNorthstar(); \ No newline at end of file diff --git a/NorthstarDedicatedTest/pch.cpp b/NorthstarDedicatedTest/pch.cpp new file mode 100644 index 00000000..64b7eef6 --- /dev/null +++ b/NorthstarDedicatedTest/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/NorthstarDedicatedTest/pch.h b/NorthstarDedicatedTest/pch.h new file mode 100644 index 00000000..1ad845c9 --- /dev/null +++ b/NorthstarDedicatedTest/pch.h @@ -0,0 +1,11 @@ +#ifndef PCH_H +#define PCH_H + +#define _CRT_SECURE_NO_WARNINGS + +// add headers that you want to pre-compile here +#include +#include "logging.h" +#include "include/MinHook.h" + +#endif \ No newline at end of file diff --git a/NorthstarDedicatedTest/sigscanning.cpp b/NorthstarDedicatedTest/sigscanning.cpp new file mode 100644 index 00000000..c75c80f0 --- /dev/null +++ b/NorthstarDedicatedTest/sigscanning.cpp @@ -0,0 +1,39 @@ +#include "pch.h" +#include "sigscanning.h" +#include + +// note: sigscanning is only really intended to be used for resolving stuff like shared function definitions +// we mostly use raw function addresses for stuff + +size_t GetDLLLength(HMODULE moduleHandle) +{ + // based on sigscn code from ttf2sdk, which is in turn based on CSigScan from https://wiki.alliedmods.net/Signature_Scanning + MEMORY_BASIC_INFORMATION mem; + VirtualQuery(moduleHandle, &mem, sizeof(mem)); + + IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)mem.AllocationBase; + IMAGE_NT_HEADERS* pe = (IMAGE_NT_HEADERS*)((unsigned char*)dos + dos->e_lfanew); + + return pe->OptionalHeader.SizeOfImage; +} + +void* FindSignature(std::string dllName, const char* sig, const char* mask) +{ + HMODULE dllAddress = GetModuleHandleA(dllName.c_str()); + char* dllEnd = (char*)(dllAddress + GetDLLLength(dllAddress)); + + size_t sigLength = strlen(mask); + + for (char* i = (char*)dllAddress; i < dllEnd - sigLength; i++) + { + int j = 0; + for (; j < sigLength; j++) + if (mask[j] != '?' && sig[j] != i[j]) + break; + + if (j == sigLength) // loop finished of its own accord + return (void*)i; + } + + return nullptr; +} diff --git a/NorthstarDedicatedTest/sigscanning.h b/NorthstarDedicatedTest/sigscanning.h new file mode 100644 index 00000000..56979fbc --- /dev/null +++ b/NorthstarDedicatedTest/sigscanning.h @@ -0,0 +1,7 @@ +#pragma once +#include + +// note: sigscanning is only really intended to be used for resolving stuff like shared function definitions +// we mostly use raw function addresses for stuff + +void* FindSignature(std::string dllName, const char* sig, const char* mask); \ No newline at end of file diff --git a/NorthstarDedicatedTest/sourceconsole.cpp b/NorthstarDedicatedTest/sourceconsole.cpp new file mode 100644 index 00000000..c862356e --- /dev/null +++ b/NorthstarDedicatedTest/sourceconsole.cpp @@ -0,0 +1,14 @@ +#include "pch.h" +#include "sourceconsole.h" +#include "sourceinterface.h" + +SourceInterface* g_SourceGameConsole; + +void InitialiseSourceConsole(HMODULE baseAddress) +{ + SourceInterface console = SourceInterface("client.dll", "CGameConsole"); + console->Initialize(); + console->Activate(); + + g_SourceGameConsole = &console; +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/sourceconsole.h b/NorthstarDedicatedTest/sourceconsole.h new file mode 100644 index 00000000..7f494dca --- /dev/null +++ b/NorthstarDedicatedTest/sourceconsole.h @@ -0,0 +1,90 @@ +#pragma once +#include "pch.h" +#include "sourceinterface.h" + +void InitialiseSourceConsole(HMODULE baseAddress); + +class EditablePanel +{ +public: + virtual ~EditablePanel() = 0; + unsigned char unknown[0x2B0]; +}; + +struct SourceColor +{ + unsigned char R; + unsigned char G; + unsigned char B; + unsigned char A; + + SourceColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a) + { + R = r; + G = g; + B = b; + A = a; + } + + SourceColor() + { + R = 0; + G = 0; + B = 0; + A = 0; + } +}; + +class IConsoleDisplayFunc +{ +public: + virtual void ColorPrint(const SourceColor& clr, const char* pMessage) = 0; + virtual void Print(const char* pMessage) = 0; + virtual void DPrint(const char* pMessage) = 0; +}; + +class CConsolePanel : public EditablePanel, public IConsoleDisplayFunc +{ + +}; + +class CConsoleDialog +{ +public: + struct VTable + { + void* unknown[298]; + void(*OnCommandSubmitted)(CConsoleDialog* consoleDialog, const char* pCommand); + }; + + VTable* m_vtable; + unsigned char unknown[0x398]; + CConsolePanel* m_pConsolePanel; +}; + +class CGameConsole +{ +public: + virtual ~CGameConsole() = 0; + + // activates the console, makes it visible and brings it to the foreground + virtual void Activate() = 0; + + virtual void Initialize() = 0; + + // hides the console + virtual void Hide() = 0; + + // clears the console + virtual void Clear() = 0; + + // return true if the console has focus + virtual bool IsConsoleVisible() = 0; + + virtual void SetParent(int parent) = 0; + + bool m_bInitialized; + CConsoleDialog* m_pConsole; +}; + +extern SourceInterface* g_SourceGameConsole; \ No newline at end of file diff --git a/NorthstarDedicatedTest/sourceinterface.cpp b/NorthstarDedicatedTest/sourceinterface.cpp new file mode 100644 index 00000000..49a2f164 --- /dev/null +++ b/NorthstarDedicatedTest/sourceinterface.cpp @@ -0,0 +1,13 @@ +#include "pch.h" +#include "sourceinterface.h" +#include +#include "tier0.h" + +template SourceInterface::SourceInterface(const std::string& moduleName, const std::string& interfaceName) +{ + HMODULE handle = GetModuleHandleA(moduleName.c_str()); + CreateInterfaceFn createInterface = (CreateInterfaceFn)GetProcAddress(handle, interfaceName.c_str()); + m_interface = (T*)createInterface(interfaceName.c_str(), NULL); + if (m_interface == nullptr) + Error("Failed to call CreateInterface for %s in %s", interfaceName, moduleName); +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/sourceinterface.h b/NorthstarDedicatedTest/sourceinterface.h new file mode 100644 index 00000000..bc4767f5 --- /dev/null +++ b/NorthstarDedicatedTest/sourceinterface.h @@ -0,0 +1,24 @@ +#pragma once +#include + +// literally just copied from ttf2sdk definition +typedef void* (*CreateInterfaceFn)(const char* pName, int* pReturnCode); + +template class SourceInterface +{ +private: + T* m_interface; + +public: + SourceInterface(const std::string& moduleName, const std::string& interfaceName); + + T* operator->() const + { + return m_interface; + } + + operator T* () const + { + return m_interface; + } +}; diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp new file mode 100644 index 00000000..66bf755c --- /dev/null +++ b/NorthstarDedicatedTest/squirrel.cpp @@ -0,0 +1,67 @@ +#include "pch.h" +#include "squirrel.h" +#include "hooks.h" +#include "hookutils.h" +#include "sigscanning.h" +#include + +// hook forward declarations +typedef SQInteger(*SQPrintType)(void* sqvm, char* fmt, ...); +SQPrintType ClientSQPrint; +SQPrintType UISQPrint; +SQPrintType ServerSQPrint; +template SQInteger SQPrintHook(void* sqvm, char* fmt, ...); + + +// inits +SquirrelManager* g_ClientSquirrelManager; +SquirrelManager* g_ServerSquirrelManager; + +void InitialiseClientSquirrel(HMODULE baseAddress) +{ + g_ClientSquirrelManager = new SquirrelManager(); + + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x12B00, &SQPrintHook, reinterpret_cast(&ClientSQPrint)); + + // ui inits + // currently these are mostly incomplete + + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x12BA0, &SQPrintHook, reinterpret_cast(&UISQPrint)); +} + +void InitialiseServerSquirrel(HMODULE baseAddress) +{ + g_ServerSquirrelManager = new SquirrelManager(); + + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1FE90, &SQPrintHook, reinterpret_cast(&ServerSQPrint)); +} + +// hooks +template SQInteger SQPrintHook(void* sqvm, char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + + SQChar buf[1024]; + int charsWritten = vsnprintf_s(buf, _TRUNCATE, fmt, va); + + if (charsWritten > 0) + { + if (buf[charsWritten - 1] == '\n') + buf[charsWritten - 1] == '\0'; + + Log(context, buf, ""); + } + + va_end(va); + return 0; +} + + +// manager +template SquirrelManager::SquirrelManager() +{ + +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/squirrel.h b/NorthstarDedicatedTest/squirrel.h new file mode 100644 index 00000000..627ceeaf --- /dev/null +++ b/NorthstarDedicatedTest/squirrel.h @@ -0,0 +1,26 @@ +#pragma once + +void InitialiseClientSquirrel(HMODULE baseAddress); +void InitialiseServerSquirrel(HMODULE baseAddress); + +// stolen from ttf2sdk: sqvm types +typedef float SQFloat; +typedef long SQInteger; +typedef unsigned long SQUnsignedInteger; +typedef char SQChar; + +typedef SQUnsignedInteger SQBool; +typedef SQInteger SQRESULT; + +template class SquirrelManager +{ +public: + + +public: + SquirrelManager(); +}; + +extern SquirrelManager* g_ClientSquirrelManager; +extern SquirrelManager* g_ServerSquirrelManager; +//extern SquirrelManager g_UISquirrelManager \ No newline at end of file diff --git a/NorthstarDedicatedTest/tier0.cpp b/NorthstarDedicatedTest/tier0.cpp new file mode 100644 index 00000000..a52c72ce --- /dev/null +++ b/NorthstarDedicatedTest/tier0.cpp @@ -0,0 +1,33 @@ +#include "pch.h" +#include "tier0.h" +#include +#include + +void* ResolveTier0Function(const char* name) +{ + HMODULE tier0 = GetModuleHandle(L"tier0.dll"); + + // todo: maybe cache resolved funcs? idk the performance hit of getprocaddress + std::cout << "ResolveTier0Function " << name << " " << tier0 << "::" << GetProcAddress(tier0, name) << std::endl; + return GetProcAddress(tier0, name); +} + +typedef void(*Tier0Error)(const char* fmt, ...); +void Error(const char* fmt, ...) +{ + Tier0Error tier0Func = (Tier0Error)ResolveTier0Function("Error"); + + // reformat args because you can't pass varargs between funcs + char buf[1024]; + + va_list args; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + // tier0 isn't loaded yet + if (tier0Func) + tier0Func(buf); + else + std::cout << "FATAL ERROR " << buf << std::endl; +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/tier0.h b/NorthstarDedicatedTest/tier0.h new file mode 100644 index 00000000..dddd9479 --- /dev/null +++ b/NorthstarDedicatedTest/tier0.h @@ -0,0 +1,9 @@ +#pragma once +#include "pch.h" + +// get exported tier0 by name +void* ResolveTier0Function(const char* name); + +// actual function defs +// would've liked to resolve these at compile time, but we load before tier0 so not really possible +void Error(const char* fmt, ...); \ No newline at end of file diff --git a/R2Northstar.sln b/R2Northstar.sln new file mode 100644 index 00000000..8c259ed0 --- /dev/null +++ b/R2Northstar.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30621.155 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Northstar", "NorthstarDedicatedTest\NorthstarDedicatedTest.vcxproj", "{CFAD2623-064F-453C-8196-79EE10292E32}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectorTest", "InjectorTest\InjectorTest.vcxproj", "{3C3FC37C-D4B9-4413-AADF-C52FD2F428E6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Injector", "Injector", "{DEFD24BD-9918-4DC1-BAD5-3F3A49E467E9}" +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 + {CFAD2623-064F-453C-8196-79EE10292E32}.Debug|x64.ActiveCfg = Debug|x64 + {CFAD2623-064F-453C-8196-79EE10292E32}.Debug|x64.Build.0 = Debug|x64 + {CFAD2623-064F-453C-8196-79EE10292E32}.Debug|x86.ActiveCfg = Debug|Win32 + {CFAD2623-064F-453C-8196-79EE10292E32}.Debug|x86.Build.0 = Debug|Win32 + {CFAD2623-064F-453C-8196-79EE10292E32}.Release|x64.ActiveCfg = Release|x64 + {CFAD2623-064F-453C-8196-79EE10292E32}.Release|x64.Build.0 = Release|x64 + {CFAD2623-064F-453C-8196-79EE10292E32}.Release|x86.ActiveCfg = Release|Win32 + {CFAD2623-064F-453C-8196-79EE10292E32}.Release|x86.Build.0 = Release|Win32 + {3C3FC37C-D4B9-4413-AADF-C52FD2F428E6}.Debug|x64.ActiveCfg = Debug|x64 + {3C3FC37C-D4B9-4413-AADF-C52FD2F428E6}.Debug|x64.Build.0 = Debug|x64 + {3C3FC37C-D4B9-4413-AADF-C52FD2F428E6}.Debug|x86.ActiveCfg = Debug|Win32 + {3C3FC37C-D4B9-4413-AADF-C52FD2F428E6}.Debug|x86.Build.0 = Debug|Win32 + {3C3FC37C-D4B9-4413-AADF-C52FD2F428E6}.Release|x64.ActiveCfg = Release|x64 + {3C3FC37C-D4B9-4413-AADF-C52FD2F428E6}.Release|x64.Build.0 = Release|x64 + {3C3FC37C-D4B9-4413-AADF-C52FD2F428E6}.Release|x86.ActiveCfg = Release|Win32 + {3C3FC37C-D4B9-4413-AADF-C52FD2F428E6}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3C3FC37C-D4B9-4413-AADF-C52FD2F428E6} = {DEFD24BD-9918-4DC1-BAD5-3F3A49E467E9} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E617E95C-9157-454C-84C5-8EEC2B5D1032} + EndGlobalSection +EndGlobal -- cgit v1.2.3