From 8a1a2e97624d15617197248a5e292c5ead5e74a2 Mon Sep 17 00:00:00 2001 From: p0358 Date: Wed, 29 Dec 2021 05:48:33 +0100 Subject: add launcher.dll proxy option --- loader_launcher_proxy/Memory.cpp | 52 ++++++ loader_launcher_proxy/Memory.h | 15 ++ loader_launcher_proxy/dllmain.cpp | 114 +++++++++++++ loader_launcher_proxy/framework.h | 5 + .../loader_launcher_proxy.vcxproj | 178 +++++++++++++++++++++ .../loader_launcher_proxy.vcxproj.filters | 39 +++++ loader_launcher_proxy/pch.cpp | 5 + loader_launcher_proxy/pch.h | 17 ++ 8 files changed, 425 insertions(+) create mode 100644 loader_launcher_proxy/Memory.cpp create mode 100644 loader_launcher_proxy/Memory.h create mode 100644 loader_launcher_proxy/dllmain.cpp create mode 100644 loader_launcher_proxy/framework.h create mode 100644 loader_launcher_proxy/loader_launcher_proxy.vcxproj create mode 100644 loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters create mode 100644 loader_launcher_proxy/pch.cpp create mode 100644 loader_launcher_proxy/pch.h (limited to 'loader_launcher_proxy') diff --git a/loader_launcher_proxy/Memory.cpp b/loader_launcher_proxy/Memory.cpp new file mode 100644 index 00000000..d8dc1dc5 --- /dev/null +++ b/loader_launcher_proxy/Memory.cpp @@ -0,0 +1,52 @@ +#include "pch.h" +#include +#include +#include + +HMODULE hTier0Module; +IMemAlloc** g_ppMemAllocSingleton; + +void LoadTier0Handle() +{ + hTier0Module = GetModuleHandleA("tier0.dll"); + if (!hTier0Module) return; + + g_ppMemAllocSingleton = (IMemAlloc**)GetProcAddress(hTier0Module, "g_pMemAllocSingleton"); +} + +const int STATIC_ALLOC_SIZE = 4096; + +size_t g_iStaticAllocated = 0; +char pStaticAllocBuf[STATIC_ALLOC_SIZE]; + +// they should never be used here, except in LibraryLoadError + +void* operator new(size_t n) +{ + // allocate into static buffer + if (g_iStaticAllocated + n <= STATIC_ALLOC_SIZE) + { + void* ret = pStaticAllocBuf + g_iStaticAllocated; + g_iStaticAllocated += n; + return ret; + } + else + { + // try to fallback to g_pMemAllocSingleton + if (!hTier0Module) LoadTier0Handle(); + if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) + (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n); + else + throw "Cannot allocate"; + } +} + +void operator delete(void* p) +{ + // if it was allocated into the static buffer, just do nothing, safest way to deal with it + if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE) + return; + + if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) + (*g_ppMemAllocSingleton)->m_vtable->Free(*g_ppMemAllocSingleton, p); +} diff --git a/loader_launcher_proxy/Memory.h b/loader_launcher_proxy/Memory.h new file mode 100644 index 00000000..928e403c --- /dev/null +++ b/loader_launcher_proxy/Memory.h @@ -0,0 +1,15 @@ +#pragma once + +class IMemAlloc +{ +public: + struct VTable + { + void* unknown[1]; + void* (*Alloc) (IMemAlloc* memAlloc, size_t nSize); + void* unknown2[3]; + void(*Free) (IMemAlloc* memAlloc, void* pMem); + }; + + VTable* m_vtable; +}; diff --git a/loader_launcher_proxy/dllmain.cpp b/loader_launcher_proxy/dllmain.cpp new file mode 100644 index 00000000..6e0d1f07 --- /dev/null +++ b/loader_launcher_proxy/dllmain.cpp @@ -0,0 +1,114 @@ +#include "pch.h" +#include +#include +#include +#include + +HMODULE hLauncherModule; +HMODULE hHookModule; + +using CreateInterfaceFn = void* (*)(const char* pName, int* pReturnCode); + +// does not seem to ever be used +extern "C" _declspec(dllexport) void* __fastcall CreateInterface(const char* pName, int* pReturnCode) +{ + //AppSystemCreateInterfaceFn(pName, pReturnCode); + printf("external CreateInterface: name: %s\n", pName); + + static CreateInterfaceFn launcher_CreateInterface = (CreateInterfaceFn)GetProcAddress(hLauncherModule, "CreateInterface"); + auto res = launcher_CreateInterface(pName, pReturnCode); + + printf("external CreateInterface: return code: %p\n", res); + return res; +} + +bool GetExePathWide(wchar_t* dest, size_t destSize) +{ + if (!dest) return NULL; + if (destSize < MAX_PATH) return NULL; + + DWORD length = GetModuleFileNameW(NULL, dest, destSize); + return length && PathRemoveFileSpecW(dest); +} + +FARPROC GetLauncherMain() +{ + static FARPROC Launcher_LauncherMain; + if (!Launcher_LauncherMain) + Launcher_LauncherMain = GetProcAddress(hLauncherModule, "LauncherMain"); + return Launcher_LauncherMain; +} + +void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location) +{ + char text[2048]; + std::string message = std::system_category().message(dwMessageId); + sprintf_s(text, "Failed to load the %ls at \"%ls\" (%lu):\n\n%hs", libName, location, dwMessageId, message.c_str()); + MessageBoxA(GetForegroundWindow(), text, "Launcher Error", 0); +} + +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: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +wchar_t exePath[4096]; +wchar_t dllPath[4096]; + +extern "C" _declspec(dllexport) void LauncherMain(__int64, __int64, __int64, uint32_t) +{ + { + + if (!GetExePathWide(exePath, 4096)) + { + MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Launcher Error", 0); + return; + } + + FARPROC Hook_Init = nullptr; + { + swprintf_s(dllPath, L"%s\\Northstar.dll", exePath); + hHookModule = LoadLibraryExW(dllPath, 0i64, 8u); + if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); + if (!hHookModule || Hook_Init == nullptr) + { + LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath); + return; + } + } + + ((void (*)()) Hook_Init)(); + } + + { + swprintf_s(dllPath, L"%s\\bin\\x64_retail\\launcher.org.dll", exePath); + hLauncherModule = LoadLibraryExW(dllPath, 0i64, 8u); + if (!hLauncherModule) + { + LibraryLoadError(GetLastError(), L"launcher.org.dll", dllPath); + return; + } + } + + auto LauncherMain = GetLauncherMain(); + //auto result = ((__int64(__fastcall*)())LauncherMain)(); + //auto result = ((signed __int64(__fastcall*)(__int64))LauncherMain)(0i64); + auto result = ((signed __int64(__fastcall*)(__int64, __int64, __int64, uint32_t))LauncherMain)(0i64, 0i64, 0i64, 0); +} + +// doubt that will help us here (in launcher.dll) though +extern "C" { + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; + __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; +} diff --git a/loader_launcher_proxy/framework.h b/loader_launcher_proxy/framework.h new file mode 100644 index 00000000..54b83e94 --- /dev/null +++ b/loader_launcher_proxy/framework.h @@ -0,0 +1,5 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj b/loader_launcher_proxy/loader_launcher_proxy.vcxproj new file mode 100644 index 00000000..ed6f5787 --- /dev/null +++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj @@ -0,0 +1,178 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {f65c322d-66df-4af1-b650-70221de334c0} + loaderlauncherproxy + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + launcher + + + false + launcher + + + + Level3 + true + WIN32;_DEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp17 + + + Windows + true + false + shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + Default + + + Windows + true + true + true + false + /HIGHENTROPYVA:NO %(AdditionalOptions) + shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters b/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters new file mode 100644 index 00000000..519ed674 --- /dev/null +++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {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 + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/loader_launcher_proxy/pch.cpp b/loader_launcher_proxy/pch.cpp new file mode 100644 index 00000000..64b7eef6 --- /dev/null +++ b/loader_launcher_proxy/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/loader_launcher_proxy/pch.h b/loader_launcher_proxy/pch.h new file mode 100644 index 00000000..f9687185 --- /dev/null +++ b/loader_launcher_proxy/pch.h @@ -0,0 +1,17 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_H +#define PCH_H + +#include "Memory.h" + +#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING + +// add headers that you want to pre-compile here +#include "framework.h" + +#endif //PCH_H -- cgit v1.2.3 From 213bf6412410a09b0bdce62b8598bfa23ba096cf Mon Sep 17 00:00:00 2001 From: p0358 Date: Wed, 29 Dec 2021 06:38:54 +0100 Subject: Add direct launcher --- LauncherInjector/LauncherInjector.vcxproj | 8 + LauncherInjector/LauncherInjector.vcxproj.filters | 6 + LauncherInjector/main.cpp | 172 +++++++++++++++------- LauncherInjector/memalloc.cpp | 61 ++++++++ LauncherInjector/memalloc.h | 15 ++ NorthstarDedicatedTest/dllmain.cpp | 6 +- NorthstarDedicatedTest/main.h | 2 +- loader_launcher_proxy/Memory.cpp | 5 +- loader_launcher_proxy/dllmain.cpp | 37 ++--- loader_launcher_proxy/pch.h | 2 - 10 files changed, 232 insertions(+), 82 deletions(-) create mode 100644 LauncherInjector/memalloc.cpp create mode 100644 LauncherInjector/memalloc.h (limited to 'loader_launcher_proxy') diff --git a/LauncherInjector/LauncherInjector.vcxproj b/LauncherInjector/LauncherInjector.vcxproj index e205207d..7ea6fccc 100644 --- a/LauncherInjector/LauncherInjector.vcxproj +++ b/LauncherInjector/LauncherInjector.vcxproj @@ -122,10 +122,13 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /F8000000 %(AdditionalOptions) Console true + shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + 8000000 @@ -137,18 +140,23 @@ NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + /F8000000 %(AdditionalOptions) Console true true true + shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + 8000000 + + diff --git a/LauncherInjector/LauncherInjector.vcxproj.filters b/LauncherInjector/LauncherInjector.vcxproj.filters index 87e25fa8..2e935b08 100644 --- a/LauncherInjector/LauncherInjector.vcxproj.filters +++ b/LauncherInjector/LauncherInjector.vcxproj.filters @@ -18,11 +18,17 @@ Source Files + + Source Files + Header Files + + Header Files + diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp index 5828e9e2..0fd41daf 100644 --- a/LauncherInjector/main.cpp +++ b/LauncherInjector/main.cpp @@ -1,12 +1,25 @@ +#define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include +#include namespace fs = std::filesystem; +extern "C" { + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; + __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; +} + +HMODULE hLauncherModule; +HMODULE hHookModule; + +wchar_t exePath[4096]; +wchar_t buffer[8196]; + DWORD GetProcessByName(std::wstring processName) { HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); @@ -33,28 +46,45 @@ DWORD GetProcessByName(std::wstring processName) return 0; } -#define PROCESS_NAME L"Titanfall2-unpacked.exe" -#define DLL_NAME L"Northstar.dll" +bool GetExePathWide(wchar_t* dest, DWORD destSize) +{ + if (!dest) return NULL; + if (destSize < MAX_PATH) return NULL; -int main(int argc, char* argv[]) { - if (!fs::exists(PROCESS_NAME)) - { - MessageBoxA(0, "Titanfall2-unpacked.exe not found! Please launch from your titanfall 2 directory and ensure you have Northstar installed correctly!", "", MB_OK); - return 1; - } + DWORD length = GetModuleFileNameW(NULL, dest, destSize); + return length && PathRemoveFileSpecW(dest); +} - if (!fs::exists(DLL_NAME)) - { - MessageBoxA(0, "Northstar.dll not found! Please launch from your titanfall 2 directory and ensure you have Northstar installed correctly!", "", MB_OK); - return 1; - } +FARPROC GetLauncherMain() +{ + static FARPROC Launcher_LauncherMain; + if (!Launcher_LauncherMain) + Launcher_LauncherMain = GetProcAddress(hLauncherModule, "LauncherMain"); + return Launcher_LauncherMain; +} + +void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location) +{ + char text[2048]; + std::string message = std::system_category().message(dwMessageId); + sprintf_s(text, "Failed to load the %ls at \"%ls\" (%lu):\n\n%hs\n\nMake sure you followed the Northstar installation instructions carefully.", libName, location, dwMessageId, message.c_str()); + MessageBoxA(GetForegroundWindow(), text, "Launcher Error", 0); +} + +int main(int argc, char* argv[]) { - bool isdedi = false; + // checked to avoid starting origin, Northstar.dll will check for -dedicated as well on its own + bool isDedicated = false; for (int i = 0; i < argc; i++) if (!strcmp(argv[i], "-dedicated")) - isdedi = true; + isDedicated = true; - if (!isdedi && !GetProcessByName(L"Origin.exe") && !GetProcessByName(L"EADesktop.exe")) + bool noOriginStartup = false; + for (int i = 0; i < argc; i++) + if (!strcmp(argv[i], "-noOriginStartup")) + noOriginStartup = true; + + if (!isDedicated && !GetProcessByName(L"Origin.exe") && !GetProcessByName(L"EADesktop.exe") && !noOriginStartup) { // unpacked exe will crash if origin isn't open on launch, so launch it // get origin path from registry, code here is reversed from OriginSDK.dll @@ -77,13 +107,20 @@ int main(int argc, char* argv[]) { memset(&pi, 0, sizeof(pi)); STARTUPINFO si; memset(&si, 0, sizeof(si)); - CreateProcessA(originPath, (LPSTR)"", NULL, NULL, false, CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, (LPSTARTUPINFOA)&si, &pi); + CreateProcessA(originPath, (char*)"", NULL, NULL, false, CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, (LPSTARTUPINFOA)&si, &pi); // wait for origin to be ready, this process is created when origin is ready enough to launch game without any errors while (!GetProcessByName(L"OriginClientService.exe") && !GetProcessByName(L"EADesktop.exe")) Sleep(200); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); } +#if 0 + // TODO: MOVE TO Northstar.dll itself and inject in some place + // for example hook GetCommandLineA() before real LauncherMain gets called (ie. during InitialiseNorthstar) + // GetCommandLineA() is always used, the parameters passed to LauncherMain are basically ignored // get cmdline args from file std::wstring args; std::ifstream cmdlineArgFile; @@ -97,7 +134,7 @@ int main(int argc, char* argv[]) { args.append(L" "); } - if (!isdedi) + if (!isDedi) cmdlineArgFile = std::ifstream("ns_startup_args.txt"); else cmdlineArgFile = std::ifstream("ns_startup_args_dedi.txt"); @@ -112,53 +149,76 @@ int main(int argc, char* argv[]) { args.append(std::wstring(str.begin(), str.end())); } - //if (isdedi) + //if (isDedicated) // // copy -dedicated into args if we have it in commandline args // args.append(L" -dedicated"); +#endif - STARTUPINFO startupInfo; - PROCESS_INFORMATION processInfo; - - memset(&startupInfo, 0, sizeof(startupInfo)); - memset(&processInfo, 0, sizeof(processInfo)); - - CreateProcessW(PROCESS_NAME, (LPWSTR)args.c_str(), 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); + bool loadNorthstar = true; + for (int i = 0; i < argc; i++) + if (!strcmp(argv[i], "-vanilla")) + loadNorthstar = false; - if (hThread == NULL) { - // injection failed - - std::string errorMessage = "Injection failed! CreateRemoteThread returned "; - errorMessage += std::to_string(GetLastError()).c_str(); - errorMessage += ", make sure bob hasn't accidentally shipped a debug build"; - MessageBoxA(0, errorMessage.c_str(), "", MB_OK); - return 0; - } - - WaitForSingleObject(hThread, INFINITE); - - //MessageBoxA(0, std::to_string(GetLastError()).c_str(), "", MB_OK); - - CloseHandle(hThread); + if (!GetExePathWide(exePath, 4096)) + { + MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Launcher Error", 0); + return 1; + } - ResumeThread(processInfo.hThread); + { + wchar_t* pPath; + size_t len; + errno_t err = _wdupenv_s(&pPath, &len, L"PATH"); + if (!err) + { + swprintf_s(buffer, L"PATH=%s\\bin\\x64_retail\\;%s", exePath, pPath); + auto result = _wputenv(buffer); + if (result == -1) + { + MessageBoxW(GetForegroundWindow(), L"Warning: could not prepend the current directory to app's PATH environment variable. Something may break because of that.", L"Launcher Warning", 0); + } + free(pPath); + } + else + { + MessageBoxW(GetForegroundWindow(), L"Warning: could not get current PATH environment variable in order to prepend the current directory to it. Something may break because of that.", L"Launcher Warning", 0); + } + } - VirtualFreeEx(processInfo.hProcess, lpLibName, dwLength, MEM_RELEASE); + if (loadNorthstar) + { + FARPROC Hook_Init = nullptr; + { + swprintf_s(buffer, L"%s\\Northstar.dll", exePath); + hHookModule = LoadLibraryExW(buffer, 0i64, 8u); + if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); + if (!hHookModule || Hook_Init == nullptr) + { + LibraryLoadError(GetLastError(), L"Northstar.dll", buffer); + return 1; + } + } + + ((bool (*)()) Hook_Init)(); + } - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); + swprintf_s(buffer, L"%s\\bin\\x64_retail\\launcher.dll", exePath); + hLauncherModule = LoadLibraryExW(buffer, 0i64, 8u); + if (!hLauncherModule) + { + LibraryLoadError(GetLastError(), L"launcher.dll", buffer); + return 1; + } + } - return 0; + auto LauncherMain = GetLauncherMain(); + if (!LauncherMain) + MessageBoxA(GetForegroundWindow(), "Failed loading launcher.dll.\nThe game cannot continue and has to exit.", "Launcher Error", 0); + //auto result = ((__int64(__fastcall*)())LauncherMain)(); + //auto result = ((signed __int64(__fastcall*)(__int64))LauncherMain)(0i64); + return ((int(__fastcall*)(HINSTANCE, HINSTANCE, LPSTR, int))LauncherMain)(NULL, NULL, NULL, 0); // the parameters aren't really used anyways } \ No newline at end of file diff --git a/LauncherInjector/memalloc.cpp b/LauncherInjector/memalloc.cpp new file mode 100644 index 00000000..64bc7b76 --- /dev/null +++ b/LauncherInjector/memalloc.cpp @@ -0,0 +1,61 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include "memalloc.h" + +HMODULE hTier0Module; +IMemAlloc** g_ppMemAllocSingleton; + +void LoadTier0Handle() +{ + hTier0Module = GetModuleHandleA("tier0.dll"); + if (!hTier0Module) return; + + g_ppMemAllocSingleton = (IMemAlloc**)GetProcAddress(hTier0Module, "g_pMemAllocSingleton"); +} + +const int STATIC_ALLOC_SIZE = 16384; + +size_t g_iStaticAllocated = 0; +char pStaticAllocBuf[STATIC_ALLOC_SIZE]; + +// they should never be used here, except in LibraryLoadError + +void* malloc(size_t n) +{ + // allocate into static buffer + if (g_iStaticAllocated + n <= STATIC_ALLOC_SIZE) + { + void* ret = pStaticAllocBuf + g_iStaticAllocated; + g_iStaticAllocated += n; + return ret; + } + else + { + // try to fallback to g_pMemAllocSingleton + if (!hTier0Module) LoadTier0Handle(); + if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) + return (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n); + else + throw "Cannot allocate"; + } +} + +void free(void* p) +{ + // if it was allocated into the static buffer, just do nothing, safest way to deal with it + if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE) + return; + + if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) + (*g_ppMemAllocSingleton)->m_vtable->Free(*g_ppMemAllocSingleton, p); +} + +void* operator new(size_t n) +{ + return malloc(n); +} + +void operator delete(void* p) +{ + free(p); +} diff --git a/LauncherInjector/memalloc.h b/LauncherInjector/memalloc.h new file mode 100644 index 00000000..928e403c --- /dev/null +++ b/LauncherInjector/memalloc.h @@ -0,0 +1,15 @@ +#pragma once + +class IMemAlloc +{ +public: + struct VTable + { + void* unknown[1]; + void* (*Alloc) (IMemAlloc* memAlloc, size_t nSize); + void* unknown2[3]; + void(*Free) (IMemAlloc* memAlloc, void* pMem); + }; + + VTable* m_vtable; +}; diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 80fc3ca4..1aa4bd3b 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -66,12 +66,12 @@ void WaitForDebugger(HMODULE baseAddress) } // in the future this will be called from launcher instead of dllmain -void InitialiseNorthstar() +bool InitialiseNorthstar() { if (initialised) { fprintf(stderr, "[WARN] Called InitialiseNorthstar more than once!\n"); - return; + return false; } initialised = true; @@ -129,4 +129,6 @@ void InitialiseNorthstar() // mod manager after everything else AddDllLoadCallback("engine.dll", InitialiseModManager); + + return true; } \ No newline at end of file diff --git a/NorthstarDedicatedTest/main.h b/NorthstarDedicatedTest/main.h index ef5d86dc..90e88912 100644 --- a/NorthstarDedicatedTest/main.h +++ b/NorthstarDedicatedTest/main.h @@ -1,3 +1,3 @@ #pragma once -extern "C" __declspec(dllexport) void InitialiseNorthstar(); \ No newline at end of file +extern "C" __declspec(dllexport) bool InitialiseNorthstar(); \ No newline at end of file diff --git a/loader_launcher_proxy/Memory.cpp b/loader_launcher_proxy/Memory.cpp index d8dc1dc5..d5642ca5 100644 --- a/loader_launcher_proxy/Memory.cpp +++ b/loader_launcher_proxy/Memory.cpp @@ -1,7 +1,4 @@ #include "pch.h" -#include -#include -#include HMODULE hTier0Module; IMemAlloc** g_ppMemAllocSingleton; @@ -35,7 +32,7 @@ void* operator new(size_t n) // try to fallback to g_pMemAllocSingleton if (!hTier0Module) LoadTier0Handle(); if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) - (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n); + return (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n); else throw "Cannot allocate"; } diff --git a/loader_launcher_proxy/dllmain.cpp b/loader_launcher_proxy/dllmain.cpp index 6e0d1f07..31360a8e 100644 --- a/loader_launcher_proxy/dllmain.cpp +++ b/loader_launcher_proxy/dllmain.cpp @@ -22,7 +22,7 @@ extern "C" _declspec(dllexport) void* __fastcall CreateInterface(const char* pNa return res; } -bool GetExePathWide(wchar_t* dest, size_t destSize) +bool GetExePathWide(wchar_t* dest, DWORD destSize) { if (!dest) return NULL; if (destSize < MAX_PATH) return NULL; @@ -66,45 +66,48 @@ BOOL APIENTRY DllMain( HMODULE hModule, wchar_t exePath[4096]; wchar_t dllPath[4096]; -extern "C" _declspec(dllexport) void LauncherMain(__int64, __int64, __int64, uint32_t) +extern "C" __declspec(dllexport) int LauncherMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { { - if (!GetExePathWide(exePath, 4096)) { MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Launcher Error", 0); - return; + return 1; } - FARPROC Hook_Init = nullptr; + bool loadNorthstar = !strstr(GetCommandLineA(), "-vanilla"); + if (loadNorthstar) { - swprintf_s(dllPath, L"%s\\Northstar.dll", exePath); - hHookModule = LoadLibraryExW(dllPath, 0i64, 8u); - if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); - if (!hHookModule || Hook_Init == nullptr) + FARPROC Hook_Init = nullptr; { - LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath); - return; + swprintf_s(dllPath, L"%s\\Northstar.dll", exePath); + hHookModule = LoadLibraryExW(dllPath, 0i64, 8u); + if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); + if (!hHookModule || Hook_Init == nullptr) + { + LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath); + return 1; + } } - } - ((void (*)()) Hook_Init)(); - } + ((bool (*)()) Hook_Init)(); + } - { swprintf_s(dllPath, L"%s\\bin\\x64_retail\\launcher.org.dll", exePath); hLauncherModule = LoadLibraryExW(dllPath, 0i64, 8u); if (!hLauncherModule) { LibraryLoadError(GetLastError(), L"launcher.org.dll", dllPath); - return; + return 1; } } auto LauncherMain = GetLauncherMain(); + if (!LauncherMain) + MessageBoxA(GetForegroundWindow(), "Failed loading launcher.org.dll.\nThe game cannot continue and has to exit.", "Launcher Error", 0); //auto result = ((__int64(__fastcall*)())LauncherMain)(); //auto result = ((signed __int64(__fastcall*)(__int64))LauncherMain)(0i64); - auto result = ((signed __int64(__fastcall*)(__int64, __int64, __int64, uint32_t))LauncherMain)(0i64, 0i64, 0i64, 0); + return ((int(__fastcall*)(HINSTANCE, HINSTANCE, LPSTR, int))LauncherMain)(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } // doubt that will help us here (in launcher.dll) though diff --git a/loader_launcher_proxy/pch.h b/loader_launcher_proxy/pch.h index f9687185..30257bb2 100644 --- a/loader_launcher_proxy/pch.h +++ b/loader_launcher_proxy/pch.h @@ -9,8 +9,6 @@ #include "Memory.h" -#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING - // add headers that you want to pre-compile here #include "framework.h" -- cgit v1.2.3 From c18b293ba739424bee6db39e2e5a3081b0010a13 Mon Sep 17 00:00:00 2001 From: p0358 Date: Wed, 29 Dec 2021 06:47:00 +0100 Subject: remove x86 configurations --- LauncherInjector/LauncherInjector.vcxproj | 65 ------------------- .../NorthstarDedicatedTest.vcxproj | 73 ---------------------- R2Northstar.sln | 13 ---- .../loader_launcher_proxy.vcxproj | 69 -------------------- 4 files changed, 220 deletions(-) (limited to 'loader_launcher_proxy') diff --git a/LauncherInjector/LauncherInjector.vcxproj b/LauncherInjector/LauncherInjector.vcxproj index 7ea6fccc..289d66ae 100644 --- a/LauncherInjector/LauncherInjector.vcxproj +++ b/LauncherInjector/LauncherInjector.vcxproj @@ -1,14 +1,6 @@ - - Debug - Win32 - - - Release - Win32 - Debug x64 @@ -27,19 +19,6 @@ NorthstarLauncher - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - Application true @@ -58,12 +37,6 @@ - - - - - - @@ -71,50 +44,12 @@ - - true - - - false - true false - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - - - Console - true - %(AdditionalDependencies) - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - - - Console - true - true - true - %(AdditionalDependencies) - - Level3 diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index 29dea6dc..479585b0 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -1,14 +1,6 @@  - - Debug - Win32 - - - Release - Win32 - Debug x64 @@ -27,19 +19,6 @@ Northstar - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - DynamicLibrary true @@ -58,12 +37,6 @@ - - - - - - @@ -71,56 +44,12 @@ - - 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 @@ -621,9 +550,7 @@ - Create Create - Create Create diff --git a/R2Northstar.sln b/R2Northstar.sln index fdc4d903..c113a437 100644 --- a/R2Northstar.sln +++ b/R2Northstar.sln @@ -12,34 +12,21 @@ 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}.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 {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Debug|x64.ActiveCfg = Debug|x64 {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Debug|x64.Build.0 = Debug|x64 - {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Debug|x86.ActiveCfg = Debug|Win32 - {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Debug|x86.Build.0 = Debug|Win32 {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x64.ActiveCfg = Release|x64 {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x64.Build.0 = Release|x64 - {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x86.ActiveCfg = Release|Win32 - {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x86.Build.0 = Release|Win32 {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x64.ActiveCfg = Debug|x64 {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x64.Build.0 = Debug|x64 - {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x86.ActiveCfg = Debug|Win32 - {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x86.Build.0 = Debug|Win32 {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x64.ActiveCfg = Release|x64 {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x64.Build.0 = Release|x64 - {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x86.ActiveCfg = Release|Win32 - {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj b/loader_launcher_proxy/loader_launcher_proxy.vcxproj index ed6f5787..65ef19ba 100644 --- a/loader_launcher_proxy/loader_launcher_proxy.vcxproj +++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj @@ -1,14 +1,6 @@ - - Debug - Win32 - - - Release - Win32 - Debug x64 @@ -26,19 +18,6 @@ 10.0 - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - DynamicLibrary true @@ -57,12 +36,6 @@ - - - - - - @@ -70,12 +43,6 @@ - - true - - - false - true launcher @@ -84,40 +51,6 @@ false launcher - - - Level3 - true - WIN32;_DEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - pch.h - - - Windows - true - false - - - - - Level3 - true - true - true - WIN32;NDEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - pch.h - - - Windows - true - true - true - false - - Level3 @@ -167,8 +100,6 @@ Create - Create - Create Create -- cgit v1.2.3 From d2ee389192aa425ef9c81b2c3367ffb0de6976d0 Mon Sep 17 00:00:00 2001 From: p0358 Date: Thu, 30 Dec 2021 02:58:19 +0100 Subject: Refactor and fix of various issues, add run_northstar.txt support --- LauncherInjector/main.cpp | 228 +++++++++++---------- LauncherInjector/memalloc.cpp | 11 +- NorthstarDedicatedTest/dllmain.cpp | 7 +- NorthstarDedicatedTest/gameutils.cpp | 19 +- NorthstarDedicatedTest/hooks.cpp | 82 ++++++-- NorthstarDedicatedTest/memalloc.cpp | 30 ++- loader_launcher_proxy/Memory.cpp | 22 +- loader_launcher_proxy/dllmain.cpp | 76 +++++-- .../loader_launcher_proxy.vcxproj | 2 +- 9 files changed, 313 insertions(+), 164 deletions(-) (limited to 'loader_launcher_proxy') diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp index 0fd41daf..4f21b200 100644 --- a/LauncherInjector/main.cpp +++ b/LauncherInjector/main.cpp @@ -16,6 +16,7 @@ extern "C" { HMODULE hLauncherModule; HMODULE hHookModule; +HMODULE hTier0Module; wchar_t exePath[4096]; wchar_t buffer[8196]; @@ -68,144 +69,147 @@ void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* char text[2048]; std::string message = std::system_category().message(dwMessageId); sprintf_s(text, "Failed to load the %ls at \"%ls\" (%lu):\n\n%hs\n\nMake sure you followed the Northstar installation instructions carefully.", libName, location, dwMessageId, message.c_str()); - MessageBoxA(GetForegroundWindow(), text, "Launcher Error", 0); + MessageBoxA(GetForegroundWindow(), text, "Northstar Launcher Error", 0); } -int main(int argc, char* argv[]) { - - // checked to avoid starting origin, Northstar.dll will check for -dedicated as well on its own - bool isDedicated = false; - for (int i = 0; i < argc; i++) - if (!strcmp(argv[i], "-dedicated")) - isDedicated = true; +void EnsureOriginStarted() +{ + if (GetProcessByName(L"Origin.exe") || GetProcessByName(L"EADesktop.exe")) + return; // already started - bool noOriginStartup = false; - for (int i = 0; i < argc; i++) - if (!strcmp(argv[i], "-noOriginStartup")) - noOriginStartup = true; + // unpacked exe will crash if origin isn't open on launch, so launch it + // get origin path from registry, code here is reversed from OriginSDK.dll + HKEY key; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\Origin", 0, KEY_READ, &key) != ERROR_SUCCESS) + { + MessageBoxA(0, "Error: failed reading origin path!", "", MB_OK); + return; + } - if (!isDedicated && !GetProcessByName(L"Origin.exe") && !GetProcessByName(L"EADesktop.exe") && !noOriginStartup) + char originPath[520]; + DWORD originPathLength = 520; + if (RegQueryValueExA(key, "ClientPath", 0, 0, (LPBYTE)&originPath, &originPathLength) != ERROR_SUCCESS) { - // unpacked exe will crash if origin isn't open on launch, so launch it - // get origin path from registry, code here is reversed from OriginSDK.dll - HKEY key; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\Origin", 0, KEY_READ, &key) != ERROR_SUCCESS) - { - MessageBoxA(0, "Error: failed reading origin path!", "", MB_OK); - return 1; - } + MessageBoxA(0, "Error: failed reading origin path!", "", MB_OK); + return; + } - char originPath[520]; - DWORD originPathLength = 520; - if (RegQueryValueExA(key, "ClientPath", 0, 0, (LPBYTE)&originPath, &originPathLength) != ERROR_SUCCESS) - { - MessageBoxA(0, "Error: failed reading origin path!", "", MB_OK); - return 1; - } + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(pi)); + STARTUPINFO si; + memset(&si, 0, sizeof(si)); + CreateProcessA(originPath, (char*)"", NULL, NULL, false, CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, (LPSTARTUPINFOA)&si, &pi); - PROCESS_INFORMATION pi; - memset(&pi, 0, sizeof(pi)); - STARTUPINFO si; - memset(&si, 0, sizeof(si)); - CreateProcessA(originPath, (char*)"", NULL, NULL, false, CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, (LPSTARTUPINFOA)&si, &pi); + printf("[*] Waiting for Origin...\n"); - // wait for origin to be ready, this process is created when origin is ready enough to launch game without any errors - while (!GetProcessByName(L"OriginClientService.exe") && !GetProcessByName(L"EADesktop.exe")) - Sleep(200); + // wait for origin to be ready, this process is created when origin is ready enough to launch game without any errors + while (!GetProcessByName(L"OriginClientService.exe") && !GetProcessByName(L"EADesktop.exe")) + Sleep(200); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +} -#if 0 - // TODO: MOVE TO Northstar.dll itself and inject in some place - // for example hook GetCommandLineA() before real LauncherMain gets called (ie. during InitialiseNorthstar) - // GetCommandLineA() is always used, the parameters passed to LauncherMain are basically ignored - // get cmdline args from file - std::wstring args; - std::ifstream cmdlineArgFile; +void PrependPath() +{ + wchar_t* pPath; + size_t len; + errno_t err = _wdupenv_s(&pPath, &len, L"PATH"); + if (!err) + { + swprintf_s(buffer, L"PATH=%s\\bin\\x64_retail\\;%s", exePath, pPath); + auto result = _wputenv(buffer); + if (result == -1) + { + MessageBoxW(GetForegroundWindow(), L"Warning: could not prepend the current directory to app's PATH environment variable. Something may break because of that.", L"Northstar Launcher Warning", 0); + } + //free(pPath); + } + else + { + MessageBoxW(GetForegroundWindow(), L"Warning: could not get current PATH environment variable in order to prepend the current directory to it. Something may break because of that.", L"Northstar Launcher Warning", 0); + } +} - args.append(L" "); +bool ShouldLoadNorthstar(int argc, char* argv[]) +{ + bool loadNorthstar = true; for (int i = 0; i < argc; i++) - { - std::string str = argv[i]; + if (!strcmp(argv[i], "-vanilla")) + loadNorthstar = false; - args.append(std::wstring(str.begin(), str.end())); - args.append(L" "); - } + if (!loadNorthstar) + return loadNorthstar; - if (!isDedi) - cmdlineArgFile = std::ifstream("ns_startup_args.txt"); - else - cmdlineArgFile = std::ifstream("ns_startup_args_dedi.txt"); + auto runNorthstarFile = std::ifstream("run_northstar.txt"); + if (runNorthstarFile) + { + std::stringstream runNorthstarFileBuffer; + runNorthstarFileBuffer << runNorthstarFile.rdbuf(); + runNorthstarFile.close(); + if (runNorthstarFileBuffer.str()._Starts_with("0")) + loadNorthstar = false; + } + return loadNorthstar; +} - if (cmdlineArgFile) +bool LoadNorthstar() +{ + FARPROC Hook_Init = nullptr; { - std::stringstream argBuffer; - argBuffer << cmdlineArgFile.rdbuf(); - cmdlineArgFile.close(); - - std::string str = argBuffer.str(); - args.append(std::wstring(str.begin(), str.end())); + swprintf_s(buffer, L"%s\\Northstar.dll", exePath); + hHookModule = LoadLibraryExW(buffer, 0i64, 8u); + if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); + if (!hHookModule || Hook_Init == nullptr) + { + LibraryLoadError(GetLastError(), L"Northstar.dll", buffer); + return false; + } } - //if (isDedicated) - // // copy -dedicated into args if we have it in commandline args - // args.append(L" -dedicated"); -#endif + ((bool (*)()) Hook_Init)(); + return true; +} - // +int main(int argc, char* argv[]) { - bool loadNorthstar = true; + // checked to avoid starting origin, Northstar.dll will check for -dedicated as well on its own + bool isDedicated = false; for (int i = 0; i < argc; i++) - if (!strcmp(argv[i], "-vanilla")) - loadNorthstar = false; + if (!strcmp(argv[i], "-dedicated")) + isDedicated = true; + + bool noOriginStartup = false; + for (int i = 0; i < argc; i++) + if (!strcmp(argv[i], "-noOriginStartup")) + noOriginStartup = true; + + if (!isDedicated && !noOriginStartup) + { + EnsureOriginStarted(); + } { if (!GetExePathWide(exePath, 4096)) { - MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Launcher Error", 0); + MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Northstar Launcher Error", 0); return 1; } - { - wchar_t* pPath; - size_t len; - errno_t err = _wdupenv_s(&pPath, &len, L"PATH"); - if (!err) - { - swprintf_s(buffer, L"PATH=%s\\bin\\x64_retail\\;%s", exePath, pPath); - auto result = _wputenv(buffer); - if (result == -1) - { - MessageBoxW(GetForegroundWindow(), L"Warning: could not prepend the current directory to app's PATH environment variable. Something may break because of that.", L"Launcher Warning", 0); - } - free(pPath); - } - else - { - MessageBoxW(GetForegroundWindow(), L"Warning: could not get current PATH environment variable in order to prepend the current directory to it. Something may break because of that.", L"Launcher Warning", 0); - } - } + PrependPath(); + bool loadNorthstar = ShouldLoadNorthstar(argc, argv); if (loadNorthstar) { - FARPROC Hook_Init = nullptr; - { - swprintf_s(buffer, L"%s\\Northstar.dll", exePath); - hHookModule = LoadLibraryExW(buffer, 0i64, 8u); - if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); - if (!hHookModule || Hook_Init == nullptr) - { - LibraryLoadError(GetLastError(), L"Northstar.dll", buffer); - return 1; - } - } - - ((bool (*)()) Hook_Init)(); + printf("[*] Loading Northstar\n"); + if (!LoadNorthstar()) + return 1; } + else + printf("[*] Going to load the vanilla game\n"); + printf("[*] Loading launcher.dll\n"); swprintf_s(buffer, L"%s\\bin\\x64_retail\\launcher.dll", exePath); hLauncherModule = LoadLibraryExW(buffer, 0i64, 8u); if (!hLauncherModule) @@ -213,12 +217,24 @@ int main(int argc, char* argv[]) { LibraryLoadError(GetLastError(), L"launcher.dll", buffer); return 1; } + + printf("[*] Loading tier0.dll\n"); + // this makes zero sense given tier0.dll is already loaded via imports on launcher.dll, but we do it for full consistency with original launcher exe + // and to also let load callbacks in Northstar work for tier0.dll + swprintf_s(buffer, L"%s\\bin\\x64_retail\\tier0.dll", exePath); + hTier0Module = LoadLibraryW(buffer); + if (!hTier0Module) + { + LibraryLoadError(GetLastError(), L"tier0.dll", buffer); + return 1; + } } + printf("[*] Launching the game...\n"); auto LauncherMain = GetLauncherMain(); if (!LauncherMain) - MessageBoxA(GetForegroundWindow(), "Failed loading launcher.dll.\nThe game cannot continue and has to exit.", "Launcher Error", 0); + MessageBoxA(GetForegroundWindow(), "Failed loading launcher.dll.\nThe game cannot continue and has to exit.", "Northstar Launcher Error", 0); //auto result = ((__int64(__fastcall*)())LauncherMain)(); //auto result = ((signed __int64(__fastcall*)(__int64))LauncherMain)(0i64); - return ((int(__fastcall*)(HINSTANCE, HINSTANCE, LPSTR, int))LauncherMain)(NULL, NULL, NULL, 0); // the parameters aren't really used anyways + return ((int(/*__fastcall*/*)(HINSTANCE, HINSTANCE, LPSTR, int))LauncherMain)(NULL, NULL, NULL, 0); // the parameters aren't really used anyways } \ No newline at end of file diff --git a/LauncherInjector/memalloc.cpp b/LauncherInjector/memalloc.cpp index 64bc7b76..1d0f13e6 100644 --- a/LauncherInjector/memalloc.cpp +++ b/LauncherInjector/memalloc.cpp @@ -1,13 +1,14 @@ #define WIN32_LEAN_AND_MEAN #include #include "memalloc.h" +#include -HMODULE hTier0Module; +extern HMODULE hTier0Module; IMemAlloc** g_ppMemAllocSingleton; void LoadTier0Handle() { - hTier0Module = GetModuleHandleA("tier0.dll"); + if (!hTier0Module) hTier0Module = GetModuleHandleA("tier0.dll"); if (!hTier0Module) return; g_ppMemAllocSingleton = (IMemAlloc**)GetProcAddress(hTier0Module, "g_pMemAllocSingleton"); @@ -18,10 +19,11 @@ const int STATIC_ALLOC_SIZE = 16384; size_t g_iStaticAllocated = 0; char pStaticAllocBuf[STATIC_ALLOC_SIZE]; -// they should never be used here, except in LibraryLoadError +// they should never be used here, except in LibraryLoadError // haha not true void* malloc(size_t n) { + //printf("NorthstarLauncher malloc: %llu\n", n); // allocate into static buffer if (g_iStaticAllocated + n <= STATIC_ALLOC_SIZE) { @@ -32,7 +34,7 @@ void* malloc(size_t n) else { // try to fallback to g_pMemAllocSingleton - if (!hTier0Module) LoadTier0Handle(); + if (!hTier0Module || !g_ppMemAllocSingleton) LoadTier0Handle(); if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) return (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n); else @@ -42,6 +44,7 @@ void* malloc(size_t n) void free(void* p) { + //printf("NorthstarLauncher free: %p\n", p); // if it was allocated into the static buffer, just do nothing, safest way to deal with it if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE) return; diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 1aa4bd3b..dfc3afe1 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -70,7 +70,7 @@ bool InitialiseNorthstar() { if (initialised) { - fprintf(stderr, "[WARN] Called InitialiseNorthstar more than once!\n"); + fprintf(stderr, "[info] Called InitialiseNorthstar more than once!\n"); return false; } initialised = true; @@ -81,8 +81,7 @@ bool InitialiseNorthstar() InstallInitialHooks(); InitialiseInterfaceCreationHooks(); - // adding a callback to tier0 won't work for some reason - AddDllLoadCallback("launcher.org.dll", InitialiseTier0GameUtilFunctions); + AddDllLoadCallback("tier0.dll", InitialiseTier0GameUtilFunctions); AddDllLoadCallback("engine.dll", WaitForDebugger); AddDllLoadCallback("engine.dll", InitialiseEngineGameUtilFunctions); AddDllLoadCallback("server.dll", InitialiseServerGameUtilFunctions); @@ -91,7 +90,7 @@ bool InitialiseNorthstar() // dedi patches { AddDllLoadCallback("engine.dll", InitialiseDedicated); - AddDllLoadCallback("launcher.org.dll", InitialiseDedicatedOrigin); + AddDllLoadCallback("tier0.dll", InitialiseDedicatedOrigin); AddDllLoadCallback("server.dll", InitialiseDedicatedServerGameDLL); AddDllLoadCallback("materialsystem_dx11.dll", InitialiseDedicatedMaterialSystem); // this fucking sucks, but seemingly we somehow load after rtech_game???? unsure how, but because of this we have to apply patches here, not on rtech_game load diff --git a/NorthstarDedicatedTest/gameutils.cpp b/NorthstarDedicatedTest/gameutils.cpp index 97011059..3e62037c 100644 --- a/NorthstarDedicatedTest/gameutils.cpp +++ b/NorthstarDedicatedTest/gameutils.cpp @@ -78,16 +78,25 @@ void InitialiseServerGameUtilFunctions(HMODULE baseAddress) void InitialiseTier0GameUtilFunctions(HMODULE baseAddress) { - baseAddress = GetModuleHandleA("tier0.dll"); - if (!baseAddress) - throw "tier0.dll is not loaded"; - CreateGlobalMemAlloc = reinterpret_cast(GetProcAddress(baseAddress, "CreateGlobalMemAlloc")); IMemAlloc** ppMemAllocSingleton = reinterpret_cast(GetProcAddress(baseAddress, "g_pMemAllocSingleton")); - if (!ppMemAllocSingleton || !*ppMemAllocSingleton) + if (!ppMemAllocSingleton) + { + spdlog::critical("Address of g_pMemAllocSingleton is a null pointer, this should never happen"); + throw "Address of g_pMemAllocSingleton is a null pointer, this should never happen"; + } + if (!*ppMemAllocSingleton) + { g_pMemAllocSingleton = CreateGlobalMemAlloc(); + *ppMemAllocSingleton = g_pMemAllocSingleton; + spdlog::warn("Created new g_pMemAllocSingleton"); + } else + { g_pMemAllocSingleton = *ppMemAllocSingleton; + extern size_t g_iStaticAllocated; + spdlog::info("Using existing g_pMemAllocSingleton for memory allocations, preallocated {} bytes beforehand", g_iStaticAllocated); + } Error = reinterpret_cast(GetProcAddress(baseAddress, "Error")); CommandLine = reinterpret_cast(GetProcAddress(baseAddress, "CommandLine")); diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp index 3de8d483..9d2be61c 100644 --- a/NorthstarDedicatedTest/hooks.cpp +++ b/NorthstarDedicatedTest/hooks.cpp @@ -6,14 +6,24 @@ #include #include +// note that these load library callbacks only support explicitly loaded dynamic libraries + typedef HMODULE(*LoadLibraryExAType)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); +typedef HMODULE(*LoadLibraryAType)(LPCSTR lpLibFileName); +HMODULE LoadLibraryAHook(LPCSTR lpLibFileName); + typedef HMODULE(*LoadLibraryExWType)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); +typedef HMODULE(*LoadLibraryWType)(LPCWSTR lpLibFileName); +HMODULE LoadLibraryWHook(LPCWSTR lpLibFileName); + LoadLibraryExAType LoadLibraryExAOriginal; +LoadLibraryAType LoadLibraryAOriginal; LoadLibraryExWType LoadLibraryExWOriginal; +LoadLibraryWType LoadLibraryWOriginal; void InstallInitialHooks() { @@ -22,7 +32,9 @@ void InstallInitialHooks() HookEnabler hook; ENABLER_CREATEHOOK(hook, &LoadLibraryExA, &LoadLibraryExAHook, reinterpret_cast(&LoadLibraryExAOriginal)); + ENABLER_CREATEHOOK(hook, &LoadLibraryA, &LoadLibraryAHook, reinterpret_cast(&LoadLibraryAOriginal)); ENABLER_CREATEHOOK(hook, &LoadLibraryExW, &LoadLibraryExWHook, reinterpret_cast(&LoadLibraryExWOriginal)); + ENABLER_CREATEHOOK(hook, &LoadLibraryW, &LoadLibraryWHook, reinterpret_cast(&LoadLibraryWOriginal)); } // dll load callback stuff @@ -46,20 +58,51 @@ void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback) dllLoadCallbacks.push_back(callbackStruct); } +void CallLoadLibraryACallbacks(LPCSTR lpLibFileName, HMODULE 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; + } + } +} + +void CallLoadLibraryWCallbacks(LPCWSTR lpLibFileName, HMODULE moduleAddress) +{ + for (auto& callbackStruct : dllLoadCallbacks) + { + std::wstring wcharStrDll = std::wstring(callbackStruct->dll.begin(), callbackStruct->dll.end()); + const wchar_t* callbackDll = wcharStrDll.c_str(); + if (!callbackStruct->called && wcsstr(lpLibFileName + (wcslen(lpLibFileName) - wcslen(callbackDll)), callbackDll) != nullptr) + { + callbackStruct->callback(moduleAddress); + callbackStruct->called = true; + } + } +} + 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; - } - } + CallLoadLibraryACallbacks(lpLibFileName, moduleAddress); + } + + return moduleAddress; +} + +HMODULE LoadLibraryAHook(LPCSTR lpLibFileName) +{ + HMODULE moduleAddress = LoadLibraryAOriginal(lpLibFileName); + + if (moduleAddress) + { + CallLoadLibraryACallbacks(lpLibFileName, moduleAddress); } return moduleAddress; @@ -71,16 +114,19 @@ HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) if (moduleAddress) { - for (auto& callbackStruct : dllLoadCallbacks) - { - std::wstring wcharStrDll = std::wstring(callbackStruct->dll.begin(), callbackStruct->dll.end()); - const wchar_t* callbackDll = wcharStrDll.c_str(); - if (!callbackStruct->called && wcsstr(lpLibFileName + (wcslen(lpLibFileName) - wcslen(callbackDll)), callbackDll) != nullptr) - { - callbackStruct->callback(moduleAddress); - callbackStruct->called = true; - } - } + CallLoadLibraryWCallbacks(lpLibFileName, moduleAddress); + } + + return moduleAddress; +} + +HMODULE LoadLibraryWHook(LPCWSTR lpLibFileName) +{ + HMODULE moduleAddress = LoadLibraryWOriginal(lpLibFileName); + + if (moduleAddress) + { + CallLoadLibraryWCallbacks(lpLibFileName, moduleAddress); } return moduleAddress; diff --git a/NorthstarDedicatedTest/memalloc.cpp b/NorthstarDedicatedTest/memalloc.cpp index 113f56b9..cff0ecac 100644 --- a/NorthstarDedicatedTest/memalloc.cpp +++ b/NorthstarDedicatedTest/memalloc.cpp @@ -17,24 +17,48 @@ const int STATIC_ALLOC_SIZE = 100000; // alot more than we need, could reduce to size_t g_iStaticAllocated = 0; char pStaticAllocBuf[STATIC_ALLOC_SIZE]; -void* operator new(size_t n) +// TODO: rename to malloc and free after removing statically compiled .libs + +void* malloc_(size_t n) { // allocate into static buffer if g_pMemAllocSingleton isn't initialised if (g_pMemAllocSingleton) + { + //printf("Northstar malloc (g_pMemAllocSingleton): %llu\n", n); return g_pMemAllocSingleton->m_vtable->Alloc(g_pMemAllocSingleton, n); + } else { + if (g_iStaticAllocated + n > STATIC_ALLOC_SIZE) + { + throw "Ran out of prealloc space"; // we could log, but spdlog probably does use allocations as well... + } + //printf("Northstar malloc (prealloc): %llu\n", n); void* ret = pStaticAllocBuf + g_iStaticAllocated; g_iStaticAllocated += n; return ret; - } + } } -void operator delete(void* p) +void free_(void* p) { // if it was allocated into the static buffer, just do nothing, safest way to deal with it if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE) + { + //printf("Northstar free (prealloc): %p\n", p); return; + } + //printf("Northstar free (g_pMemAllocSingleton): %p\n", p); g_pMemAllocSingleton->m_vtable->Free(g_pMemAllocSingleton, p); +} + +void* operator new(size_t n) +{ + return malloc_(n); +} + +void operator delete(void* p) +{ + free_(p); } \ No newline at end of file diff --git a/loader_launcher_proxy/Memory.cpp b/loader_launcher_proxy/Memory.cpp index d5642ca5..6c69d80f 100644 --- a/loader_launcher_proxy/Memory.cpp +++ b/loader_launcher_proxy/Memory.cpp @@ -1,11 +1,11 @@ #include "pch.h" -HMODULE hTier0Module; +extern HMODULE hTier0Module; IMemAlloc** g_ppMemAllocSingleton; void LoadTier0Handle() { - hTier0Module = GetModuleHandleA("tier0.dll"); + if (!hTier0Module) hTier0Module = GetModuleHandleA("tier0.dll"); if (!hTier0Module) return; g_ppMemAllocSingleton = (IMemAlloc**)GetProcAddress(hTier0Module, "g_pMemAllocSingleton"); @@ -16,9 +16,9 @@ const int STATIC_ALLOC_SIZE = 4096; size_t g_iStaticAllocated = 0; char pStaticAllocBuf[STATIC_ALLOC_SIZE]; -// they should never be used here, except in LibraryLoadError +// they should never be used here, except in LibraryLoadError? -void* operator new(size_t n) +void* malloc(size_t n) { // allocate into static buffer if (g_iStaticAllocated + n <= STATIC_ALLOC_SIZE) @@ -30,7 +30,7 @@ void* operator new(size_t n) else { // try to fallback to g_pMemAllocSingleton - if (!hTier0Module) LoadTier0Handle(); + if (!hTier0Module || !g_ppMemAllocSingleton) LoadTier0Handle(); if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) return (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n); else @@ -38,7 +38,7 @@ void* operator new(size_t n) } } -void operator delete(void* p) +void free(void* p) { // if it was allocated into the static buffer, just do nothing, safest way to deal with it if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE) @@ -47,3 +47,13 @@ void operator delete(void* p) if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) (*g_ppMemAllocSingleton)->m_vtable->Free(*g_ppMemAllocSingleton, p); } + +void* operator new(size_t n) +{ + return malloc(n); +} + +void operator delete(void* p) +{ + return free(p); +} diff --git a/loader_launcher_proxy/dllmain.cpp b/loader_launcher_proxy/dllmain.cpp index 31360a8e..6db50986 100644 --- a/loader_launcher_proxy/dllmain.cpp +++ b/loader_launcher_proxy/dllmain.cpp @@ -3,9 +3,12 @@ #include #include #include +#include +#include HMODULE hLauncherModule; HMODULE hHookModule; +HMODULE hTier0Module; using CreateInterfaceFn = void* (*)(const char* pName, int* pReturnCode); @@ -44,7 +47,7 @@ void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* char text[2048]; std::string message = std::system_category().message(dwMessageId); sprintf_s(text, "Failed to load the %ls at \"%ls\" (%lu):\n\n%hs", libName, location, dwMessageId, message.c_str()); - MessageBoxA(GetForegroundWindow(), text, "Launcher Error", 0); + MessageBoxA(GetForegroundWindow(), text, "Northstar Launcher Proxy Error", 0); } BOOL APIENTRY DllMain( HMODULE hModule, @@ -66,32 +69,61 @@ BOOL APIENTRY DllMain( HMODULE hModule, wchar_t exePath[4096]; wchar_t dllPath[4096]; +bool ShouldLoadNorthstar() +{ + bool loadNorthstar = !strstr(GetCommandLineA(), "-vanilla"); + + if (!loadNorthstar) + return loadNorthstar; + + auto runNorthstarFile = std::ifstream("run_northstar.txt"); + if (runNorthstarFile) + { + std::stringstream runNorthstarFileBuffer; + runNorthstarFileBuffer << runNorthstarFile.rdbuf(); + runNorthstarFile.close(); + if (runNorthstarFileBuffer.str()._Starts_with("0")) + loadNorthstar = false; + } + return loadNorthstar; +} + +bool LoadNorthstar() +{ + FARPROC Hook_Init = nullptr; + { + swprintf_s(dllPath, L"%s\\Northstar.dll", exePath); + hHookModule = LoadLibraryExW(dllPath, 0i64, 8u); + if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); + if (!hHookModule || Hook_Init == nullptr) + { + LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath); + return false; + } + } + + printf("WILL CALL HOOK INIT\n"); + ((bool (*)()) Hook_Init)(); + return true; +} + extern "C" __declspec(dllexport) int LauncherMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { { if (!GetExePathWide(exePath, 4096)) { - MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Launcher Error", 0); + MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Northstar Launcher Proxy Error", 0); return 1; } - bool loadNorthstar = !strstr(GetCommandLineA(), "-vanilla"); + bool loadNorthstar = ShouldLoadNorthstar(); + if (loadNorthstar) { - FARPROC Hook_Init = nullptr; - { - swprintf_s(dllPath, L"%s\\Northstar.dll", exePath); - hHookModule = LoadLibraryExW(dllPath, 0i64, 8u); - if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); - if (!hHookModule || Hook_Init == nullptr) - { - LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath); - return 1; - } - } - - ((bool (*)()) Hook_Init)(); + if (!LoadNorthstar()) + return 1; } + //else printf("\n\n WILL !!!NOT!!! LOAD NORTHSTAR\n\n"); swprintf_s(dllPath, L"%s\\bin\\x64_retail\\launcher.org.dll", exePath); hLauncherModule = LoadLibraryExW(dllPath, 0i64, 8u); @@ -100,11 +132,21 @@ extern "C" __declspec(dllexport) int LauncherMain(HINSTANCE hInstance, HINSTANCE LibraryLoadError(GetLastError(), L"launcher.org.dll", dllPath); return 1; } + + // this makes zero sense given tier0.dll is already loaded via imports on launcher.dll, but we do it for full consistency with original launcher exe + // and to also let load callbacks in Northstar work for tier0.dll + swprintf_s(dllPath, L"%s\\bin\\x64_retail\\tier0.dll", exePath); + hTier0Module = LoadLibraryW(dllPath); + if (!hTier0Module) + { + LibraryLoadError(GetLastError(), L"tier0.dll", dllPath); + return 1; + } } auto LauncherMain = GetLauncherMain(); if (!LauncherMain) - MessageBoxA(GetForegroundWindow(), "Failed loading launcher.org.dll.\nThe game cannot continue and has to exit.", "Launcher Error", 0); + MessageBoxA(GetForegroundWindow(), "Failed loading launcher.org.dll.\nThe game cannot continue and has to exit.", "Northstar Launcher Proxy Error", 0); //auto result = ((__int64(__fastcall*)())LauncherMain)(); //auto result = ((signed __int64(__fastcall*)(__int64))LauncherMain)(0i64); return ((int(__fastcall*)(HINSTANCE, HINSTANCE, LPSTR, int))LauncherMain)(hInstance, hPrevInstance, lpCmdLine, nCmdShow); diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj b/loader_launcher_proxy/loader_launcher_proxy.vcxproj index 65ef19ba..9cc7a4c7 100644 --- a/loader_launcher_proxy/loader_launcher_proxy.vcxproj +++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj @@ -78,7 +78,7 @@ true Use pch.h - Default + stdcpp17 Windows -- cgit v1.2.3 From 572f4eab6c9fd1098d1945668bfa783bd90aa8d9 Mon Sep 17 00:00:00 2001 From: p0358 Date: Thu, 30 Dec 2021 03:26:08 +0100 Subject: Restore the functionality of arguments from command line --- LauncherInjector/main.cpp | 1 - NorthstarDedicatedTest/hooks.cpp | 54 +++++++++++++++++++++++++++++++++++++++ loader_launcher_proxy/dllmain.cpp | 1 - 3 files changed, 54 insertions(+), 2 deletions(-) (limited to 'loader_launcher_proxy') diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp index 4f21b200..1eca067a 100644 --- a/LauncherInjector/main.cpp +++ b/LauncherInjector/main.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp index 9d2be61c..e58b7afc 100644 --- a/NorthstarDedicatedTest/hooks.cpp +++ b/NorthstarDedicatedTest/hooks.cpp @@ -5,6 +5,12 @@ #include #include #include +#include +#include +#include + +typedef LPSTR(*GetCommandLineAType)(); +LPSTR GetCommandLineAHook(); // note that these load library callbacks only support explicitly loaded dynamic libraries @@ -20,6 +26,7 @@ HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); typedef HMODULE(*LoadLibraryWType)(LPCWSTR lpLibFileName); HMODULE LoadLibraryWHook(LPCWSTR lpLibFileName); +GetCommandLineAType GetCommandLineAOriginal; LoadLibraryExAType LoadLibraryExAOriginal; LoadLibraryAType LoadLibraryAOriginal; LoadLibraryExWType LoadLibraryExWOriginal; @@ -31,12 +38,59 @@ void InstallInitialHooks() spdlog::error("MH_Initialize failed"); HookEnabler hook; + ENABLER_CREATEHOOK(hook, &GetCommandLineA, &GetCommandLineAHook, reinterpret_cast(&GetCommandLineAOriginal)); ENABLER_CREATEHOOK(hook, &LoadLibraryExA, &LoadLibraryExAHook, reinterpret_cast(&LoadLibraryExAOriginal)); ENABLER_CREATEHOOK(hook, &LoadLibraryA, &LoadLibraryAHook, reinterpret_cast(&LoadLibraryAOriginal)); ENABLER_CREATEHOOK(hook, &LoadLibraryExW, &LoadLibraryExWHook, reinterpret_cast(&LoadLibraryExWOriginal)); ENABLER_CREATEHOOK(hook, &LoadLibraryW, &LoadLibraryWHook, reinterpret_cast(&LoadLibraryWOriginal)); } +char* cmdlineResult; +LPSTR GetCommandLineAHook() +{ + static char* cmdlineOrg; + + if (cmdlineOrg == nullptr || cmdlineResult == nullptr) + { + cmdlineOrg = GetCommandLineAOriginal(); + bool isDedi = strstr(cmdlineOrg, "-dedicated"); // well, this one has to be a real argument + + std::string args; + std::ifstream cmdlineArgFile; + + // it looks like CommandLine() prioritizes parameters apprearing first, so we want the real commandline to take priority + // not to mention that cmdlineOrg starts with the EXE path + args.append(cmdlineOrg); + args.append(" "); + + // append those from the file + + cmdlineArgFile = std::ifstream(!isDedi ? "ns_startup_args.txt" : "ns_startup_args_dedi.txt"); + + if (cmdlineArgFile) + { + std::stringstream argBuffer; + argBuffer << cmdlineArgFile.rdbuf(); + cmdlineArgFile.close(); + + args.append(argBuffer.str()); + } + + auto len = args.length(); + cmdlineResult = reinterpret_cast(malloc(len + 1)); + if (!cmdlineResult) + { + spdlog::error("malloc failed for command line"); + return cmdlineOrg; + } + memcpy(cmdlineResult, args.c_str(), len + 1); + + spdlog::info("Command line: {}", cmdlineResult); + } + + return cmdlineResult; +} + // 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 diff --git a/loader_launcher_proxy/dllmain.cpp b/loader_launcher_proxy/dllmain.cpp index 6db50986..7a778208 100644 --- a/loader_launcher_proxy/dllmain.cpp +++ b/loader_launcher_proxy/dllmain.cpp @@ -102,7 +102,6 @@ bool LoadNorthstar() } } - printf("WILL CALL HOOK INIT\n"); ((bool (*)()) Hook_Init)(); return true; } -- cgit v1.2.3 From 2404f063433064e90059e6b3153f663e10d1f884 Mon Sep 17 00:00:00 2001 From: p0358 Date: Thu, 30 Dec 2021 04:47:16 +0100 Subject: add realloc too --- LauncherInjector/memalloc.cpp | 25 +++++++++++++++++++++++++ LauncherInjector/memalloc.h | 15 ++++++++++++--- NorthstarDedicatedTest/gameutils.h | 17 +++++++++++++---- NorthstarDedicatedTest/memalloc.cpp | 24 ++++++++++++++++++++++++ loader_launcher_proxy/Memory.cpp | 24 ++++++++++++++++++++++++ loader_launcher_proxy/Memory.h | 15 ++++++++++++--- 6 files changed, 110 insertions(+), 10 deletions(-) (limited to 'loader_launcher_proxy') diff --git a/LauncherInjector/memalloc.cpp b/LauncherInjector/memalloc.cpp index 1d0f13e6..936523d7 100644 --- a/LauncherInjector/memalloc.cpp +++ b/LauncherInjector/memalloc.cpp @@ -17,6 +17,7 @@ void LoadTier0Handle() const int STATIC_ALLOC_SIZE = 16384; size_t g_iStaticAllocated = 0; +void* g_pLastAllocated = nullptr; char pStaticAllocBuf[STATIC_ALLOC_SIZE]; // they should never be used here, except in LibraryLoadError // haha not true @@ -29,6 +30,7 @@ void* malloc(size_t n) { void* ret = pStaticAllocBuf + g_iStaticAllocated; g_iStaticAllocated += n; + g_pLastAllocated = ret; return ret; } else @@ -53,6 +55,29 @@ void free(void* p) (*g_ppMemAllocSingleton)->m_vtable->Free(*g_ppMemAllocSingleton, p); } +void* realloc(void* old_ptr, size_t size) { + // it was allocated into the static buffer + if (old_ptr >= pStaticAllocBuf && old_ptr <= pStaticAllocBuf + STATIC_ALLOC_SIZE) + { + if (g_pLastAllocated == old_ptr) + { + // nothing was allocated after this + size_t old_size = g_iStaticAllocated - ((size_t)g_pLastAllocated - (size_t)pStaticAllocBuf); + size_t diff = size - old_size; + if (diff > 0) + g_iStaticAllocated += diff; + return old_ptr; + } + else + { + return malloc(size); + } + } + + if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) + return (*g_ppMemAllocSingleton)->m_vtable->Realloc(*g_ppMemAllocSingleton, old_ptr, size); +} + void* operator new(size_t n) { return malloc(n); diff --git a/LauncherInjector/memalloc.h b/LauncherInjector/memalloc.h index 928e403c..c983966c 100644 --- a/LauncherInjector/memalloc.h +++ b/LauncherInjector/memalloc.h @@ -5,10 +5,19 @@ class IMemAlloc public: struct VTable { - void* unknown[1]; + void* unknown[1]; // alloc debug void* (*Alloc) (IMemAlloc* memAlloc, size_t nSize); - void* unknown2[3]; - void(*Free) (IMemAlloc* memAlloc, void* pMem); + void* unknown2[1]; // realloc debug + void* (*Realloc)(IMemAlloc* memAlloc, void* pMem, size_t nSize); + void* unknown3[1]; // free #1 + void (*Free) (IMemAlloc* memAlloc, void* pMem); + void* unknown4[2]; // nullsubs, maybe CrtSetDbgFlag + size_t(*GetSize) (IMemAlloc* memAlloc, void* pMem); + void* unknown5[9]; // they all do literally nothing + void (*DumpStats) (IMemAlloc* memAlloc); + void (*DumpStatsFileBase) (IMemAlloc* memAlloc, const char* pchFileBase); + void* unknown6[4]; + int (*heapchk) (IMemAlloc* memAlloc); }; VTable* m_vtable; diff --git a/NorthstarDedicatedTest/gameutils.h b/NorthstarDedicatedTest/gameutils.h index 8def57eb..43f387d1 100644 --- a/NorthstarDedicatedTest/gameutils.h +++ b/NorthstarDedicatedTest/gameutils.h @@ -7,10 +7,19 @@ class IMemAlloc public: struct VTable { - void* unknown[1]; - void* (*Alloc)(IMemAlloc* memAlloc, size_t nSize); - void* unknown2[3]; - void (*Free)(IMemAlloc* memAlloc, void* pMem); + void* unknown[1]; // alloc debug + void* (*Alloc) (IMemAlloc* memAlloc, size_t nSize); + void* unknown2[1]; // realloc debug + void* (*Realloc)(IMemAlloc* memAlloc, void* pMem, size_t nSize); + void* unknown3[1]; // free #1 + void (*Free) (IMemAlloc* memAlloc, void* pMem); + void* unknown4[2]; // nullsubs, maybe CrtSetDbgFlag + size_t(*GetSize) (IMemAlloc* memAlloc, void* pMem); + void* unknown5[9]; // they all do literally nothing + void (*DumpStats) (IMemAlloc* memAlloc); + void (*DumpStatsFileBase) (IMemAlloc* memAlloc, const char* pchFileBase); + void* unknown6[4]; + int (*heapchk) (IMemAlloc* memAlloc); }; VTable* m_vtable; diff --git a/NorthstarDedicatedTest/memalloc.cpp b/NorthstarDedicatedTest/memalloc.cpp index cff0ecac..d301f1fa 100644 --- a/NorthstarDedicatedTest/memalloc.cpp +++ b/NorthstarDedicatedTest/memalloc.cpp @@ -15,6 +15,7 @@ const int STATIC_ALLOC_SIZE = 100000; // alot more than we need, could reduce to 50k or even 25k later potentially size_t g_iStaticAllocated = 0; +void* g_pLastAllocated = nullptr; char pStaticAllocBuf[STATIC_ALLOC_SIZE]; // TODO: rename to malloc and free after removing statically compiled .libs @@ -53,6 +54,29 @@ void free_(void* p) g_pMemAllocSingleton->m_vtable->Free(g_pMemAllocSingleton, p); } +void* realloc_(void* old_ptr, size_t size) { + // it was allocated into the static buffer + if (old_ptr >= pStaticAllocBuf && old_ptr <= pStaticAllocBuf + STATIC_ALLOC_SIZE) + { + if (g_pLastAllocated == old_ptr) + { + // nothing was allocated after this + size_t old_size = g_iStaticAllocated - ((size_t)g_pLastAllocated - (size_t)pStaticAllocBuf); + size_t diff = size - old_size; + if (diff > 0) + g_iStaticAllocated += diff; + return old_ptr; + } + else + { + return malloc_(size); + } + } + + if (g_pMemAllocSingleton) + return g_pMemAllocSingleton->m_vtable->Realloc(g_pMemAllocSingleton, old_ptr, size); +} + void* operator new(size_t n) { return malloc_(n); diff --git a/loader_launcher_proxy/Memory.cpp b/loader_launcher_proxy/Memory.cpp index 6c69d80f..bd19502a 100644 --- a/loader_launcher_proxy/Memory.cpp +++ b/loader_launcher_proxy/Memory.cpp @@ -14,6 +14,7 @@ void LoadTier0Handle() const int STATIC_ALLOC_SIZE = 4096; size_t g_iStaticAllocated = 0; +void* g_pLastAllocated = nullptr; char pStaticAllocBuf[STATIC_ALLOC_SIZE]; // they should never be used here, except in LibraryLoadError? @@ -48,6 +49,29 @@ void free(void* p) (*g_ppMemAllocSingleton)->m_vtable->Free(*g_ppMemAllocSingleton, p); } +void* realloc(void* old_ptr, size_t size) { + // it was allocated into the static buffer + if (old_ptr >= pStaticAllocBuf && old_ptr <= pStaticAllocBuf + STATIC_ALLOC_SIZE) + { + if (g_pLastAllocated == old_ptr) + { + // nothing was allocated after this + size_t old_size = g_iStaticAllocated - ((size_t)g_pLastAllocated - (size_t)pStaticAllocBuf); + size_t diff = size - old_size; + if (diff > 0) + g_iStaticAllocated += diff; + return old_ptr; + } + else + { + return malloc(size); + } + } + + if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) + return (*g_ppMemAllocSingleton)->m_vtable->Realloc(*g_ppMemAllocSingleton, old_ptr, size); +} + void* operator new(size_t n) { return malloc(n); diff --git a/loader_launcher_proxy/Memory.h b/loader_launcher_proxy/Memory.h index 928e403c..c983966c 100644 --- a/loader_launcher_proxy/Memory.h +++ b/loader_launcher_proxy/Memory.h @@ -5,10 +5,19 @@ class IMemAlloc public: struct VTable { - void* unknown[1]; + void* unknown[1]; // alloc debug void* (*Alloc) (IMemAlloc* memAlloc, size_t nSize); - void* unknown2[3]; - void(*Free) (IMemAlloc* memAlloc, void* pMem); + void* unknown2[1]; // realloc debug + void* (*Realloc)(IMemAlloc* memAlloc, void* pMem, size_t nSize); + void* unknown3[1]; // free #1 + void (*Free) (IMemAlloc* memAlloc, void* pMem); + void* unknown4[2]; // nullsubs, maybe CrtSetDbgFlag + size_t(*GetSize) (IMemAlloc* memAlloc, void* pMem); + void* unknown5[9]; // they all do literally nothing + void (*DumpStats) (IMemAlloc* memAlloc); + void (*DumpStatsFileBase) (IMemAlloc* memAlloc, const char* pchFileBase); + void* unknown6[4]; + int (*heapchk) (IMemAlloc* memAlloc); }; VTable* m_vtable; -- cgit v1.2.3 From 4f7c3d02943a38941b79a638c5607b2b7f668956 Mon Sep 17 00:00:00 2001 From: p0358 Date: Thu, 30 Dec 2021 06:26:10 +0100 Subject: actually use custom allocation, override allocators of curl and rapidjson --- LauncherInjector/memalloc.cpp | 1 + NorthstarDedicatedTest/dllmain.cpp | 9 +++++++- NorthstarDedicatedTest/hooks.cpp | 2 +- NorthstarDedicatedTest/masterserver.cpp | 23 +++++++++--------- NorthstarDedicatedTest/memalloc.cpp | 41 +++++++++++++++++++++++++++------ NorthstarDedicatedTest/memalloc.h | 40 +++++++++++++++++++++++++++++++- NorthstarDedicatedTest/modmanager.cpp | 4 ++-- NorthstarDedicatedTest/modmanager.h | 3 ++- NorthstarDedicatedTest/pch.h | 2 ++ loader_launcher_proxy/Memory.cpp | 1 + 10 files changed, 101 insertions(+), 25 deletions(-) (limited to 'loader_launcher_proxy') diff --git a/LauncherInjector/memalloc.cpp b/LauncherInjector/memalloc.cpp index 936523d7..af334acf 100644 --- a/LauncherInjector/memalloc.cpp +++ b/LauncherInjector/memalloc.cpp @@ -76,6 +76,7 @@ void* realloc(void* old_ptr, size_t size) { if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) return (*g_ppMemAllocSingleton)->m_vtable->Realloc(*g_ppMemAllocSingleton, old_ptr, size); + return nullptr; } void* operator new(size_t n) diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index dfc3afe1..691c9bc7 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -65,7 +65,8 @@ void WaitForDebugger(HMODULE baseAddress) } } -// in the future this will be called from launcher instead of dllmain +SourceAllocator* g_SourceAllocator; + bool InitialiseNorthstar() { if (initialised) @@ -81,6 +82,8 @@ bool InitialiseNorthstar() InstallInitialHooks(); InitialiseInterfaceCreationHooks(); + g_SourceAllocator = new SourceAllocator; + AddDllLoadCallback("tier0.dll", InitialiseTier0GameUtilFunctions); AddDllLoadCallback("engine.dll", WaitForDebugger); AddDllLoadCallback("engine.dll", InitialiseEngineGameUtilFunctions); @@ -129,5 +132,9 @@ bool InitialiseNorthstar() // mod manager after everything else AddDllLoadCallback("engine.dll", InitialiseModManager); + // TODO: If you wanna make it more flexible and for example injectable with old Icepick injector + // in this place you should iterate over all already loaded DLLs and execute their callbacks and mark them as executed + // (as they will never get called otherwise and stuff will fail) + return true; } \ No newline at end of file diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp index e58b7afc..5723a8ab 100644 --- a/NorthstarDedicatedTest/hooks.cpp +++ b/NorthstarDedicatedTest/hooks.cpp @@ -77,7 +77,7 @@ LPSTR GetCommandLineAHook() } auto len = args.length(); - cmdlineResult = reinterpret_cast(malloc(len + 1)); + cmdlineResult = reinterpret_cast(_malloc_base(len + 1)); if (!cmdlineResult) { spdlog::error("malloc failed for command line"); diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index fa3854d3..2fec6c82 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -3,7 +3,6 @@ #include "concommand.h" #include "gameutils.h" #include "hookutils.h" -#include "libcurl/include/curl/curl.h" #include "serverauthentication.h" #include "gameutils.h" #include "rapidjson/document.h" @@ -137,7 +136,7 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* or { m_successfullyConnected = true; - rapidjson::Document originAuthInfo; + rapidjson_document originAuthInfo; originAuthInfo.Parse(readBuffer.c_str()); if (originAuthInfo.HasParseError()) @@ -209,7 +208,7 @@ void MasterServerManager::RequestServerList() { m_successfullyConnected = true; - rapidjson::Document serverInfoJson; + rapidjson_document serverInfoJson; serverInfoJson.Parse(readBuffer.c_str()); if (serverInfoJson.HasParseError()) @@ -231,7 +230,7 @@ void MasterServerManager::RequestServerList() goto REQUEST_END_CLEANUP; } - rapidjson::GenericArray serverArray = serverInfoJson.GetArray(); + rapidjson::GenericArray serverArray = serverInfoJson.GetArray(); spdlog::info("Got {} servers", serverArray.Size()); @@ -346,7 +345,7 @@ void MasterServerManager::RequestMainMenuPromos() { m_successfullyConnected = true; - rapidjson::Document mainMenuPromoJson; + rapidjson_document mainMenuPromoJson; mainMenuPromoJson.Parse(readBuffer.c_str()); if (mainMenuPromoJson.HasParseError()) @@ -456,7 +455,7 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken { m_successfullyConnected = true; - rapidjson::Document authInfoJson; + rapidjson_document authInfoJson; authInfoJson.Parse(readBuffer.c_str()); if (authInfoJson.HasParseError()) @@ -588,7 +587,7 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c { m_successfullyConnected = true; - rapidjson::Document connectionInfoJson; + rapidjson_document connectionInfoJson; connectionInfoJson.Parse(readBuffer.c_str()); if (connectionInfoJson.HasParseError()) @@ -672,9 +671,9 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name m_ownServerId[0] = 0; // build modinfo obj - rapidjson::Document modinfoDoc; + rapidjson_document modinfoDoc; modinfoDoc.SetObject(); - modinfoDoc.AddMember("Mods", rapidjson::Value(rapidjson::kArrayType), modinfoDoc.GetAllocator()); + modinfoDoc.AddMember("Mods", rapidjson_document::GenericValue(rapidjson::kArrayType), modinfoDoc.GetAllocator()); int currentModIndex = 0; for (Mod& mod : g_ModManager->m_loadedMods) @@ -682,7 +681,7 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name if (!mod.Enabled || (!mod.RequiredOnClient && !mod.Pdiff.size())) continue; - modinfoDoc["Mods"].PushBack(rapidjson::Value(rapidjson::kObjectType), modinfoDoc.GetAllocator()); + modinfoDoc["Mods"].PushBack(rapidjson_document::GenericValue(rapidjson::kObjectType), modinfoDoc.GetAllocator()); modinfoDoc["Mods"][currentModIndex].AddMember("Name", rapidjson::StringRef(&mod.Name[0]), modinfoDoc.GetAllocator()); modinfoDoc["Mods"][currentModIndex].AddMember("Version", rapidjson::StringRef(&mod.Version[0]), modinfoDoc.GetAllocator()); modinfoDoc["Mods"][currentModIndex].AddMember("RequiredOnClient", mod.RequiredOnClient, modinfoDoc.GetAllocator()); @@ -738,7 +737,7 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name { m_successfullyConnected = true; - rapidjson::Document serverAddedJson; + rapidjson_document serverAddedJson; serverAddedJson.Parse(readBuffer.c_str()); if (serverAddedJson.HasParseError()) @@ -1025,7 +1024,7 @@ void CHostState__State_GameShutdownHook(CHostState* hostState) MasterServerManager::MasterServerManager() { - curl_global_init(CURL_GLOBAL_DEFAULT); + curl_global_init_mem(CURL_GLOBAL_DEFAULT, _malloc_base, _free_base, _realloc_base, _strdup_base, _calloc_base); } void InitialiseSharedMasterServer(HMODULE baseAddress) diff --git a/NorthstarDedicatedTest/memalloc.cpp b/NorthstarDedicatedTest/memalloc.cpp index d301f1fa..c1fb70e7 100644 --- a/NorthstarDedicatedTest/memalloc.cpp +++ b/NorthstarDedicatedTest/memalloc.cpp @@ -20,7 +20,7 @@ char pStaticAllocBuf[STATIC_ALLOC_SIZE]; // TODO: rename to malloc and free after removing statically compiled .libs -void* malloc_(size_t n) +extern "C" void* _malloc_base(size_t n) { // allocate into static buffer if g_pMemAllocSingleton isn't initialised if (g_pMemAllocSingleton) @@ -41,7 +41,12 @@ void* malloc_(size_t n) } } -void free_(void* p) +/*extern "C" void* malloc(size_t n) +{ + return _malloc_base(n); +}*/ + +extern "C" void _free_base(void* p) { // if it was allocated into the static buffer, just do nothing, safest way to deal with it if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE) @@ -54,7 +59,7 @@ void free_(void* p) g_pMemAllocSingleton->m_vtable->Free(g_pMemAllocSingleton, p); } -void* realloc_(void* old_ptr, size_t size) { +extern "C" void* _realloc_base(void* old_ptr, size_t size) { // it was allocated into the static buffer if (old_ptr >= pStaticAllocBuf && old_ptr <= pStaticAllocBuf + STATIC_ALLOC_SIZE) { @@ -69,20 +74,42 @@ void* realloc_(void* old_ptr, size_t size) { } else { - return malloc_(size); + return _malloc_base(size); } } if (g_pMemAllocSingleton) return g_pMemAllocSingleton->m_vtable->Realloc(g_pMemAllocSingleton, old_ptr, size); + return nullptr; +} + +extern "C" void* _calloc_base(size_t n, size_t size) +{ + return _malloc_base(n * size); +} + +extern "C" char* _strdup_base(const char* src) +{ + char* str; + char* p; + int len = 0; + + while (src[len]) + len++; + str = reinterpret_cast(_malloc_base(len + 1)); + p = str; + while (*src) + *p++ = *src++; + *p = '\0'; + return str; } void* operator new(size_t n) { - return malloc_(n); + return _malloc_base(n); } void operator delete(void* p) { - free_(p); -} \ No newline at end of file + _free_base(p); +}// /FORCE:MULTIPLE \ No newline at end of file diff --git a/NorthstarDedicatedTest/memalloc.h b/NorthstarDedicatedTest/memalloc.h index fe3c5255..d9277694 100644 --- a/NorthstarDedicatedTest/memalloc.h +++ b/NorthstarDedicatedTest/memalloc.h @@ -1,6 +1,44 @@ #pragma once +#include "include/rapidjson/document.h" +//#include "include/rapidjson/allocators.h" + extern size_t g_iStaticAllocated; +extern "C" { + char* _strdup_base(const char* src); +} + void* operator new(size_t n); -void operator delete(void* p); \ No newline at end of file +void operator delete(void* p); + +void* _malloc_base(size_t n); +//void* malloc(size_t n); + +class SourceAllocator { +public: + static const bool kNeedFree = true; + void* Malloc(size_t size) { + if (size) // behavior of malloc(0) is implementation defined. + return _malloc_base(size); + else + return NULL; // standardize to returning NULL. + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + (void)originalSize; + if (newSize == 0) { + _free_base(originalPtr); + return NULL; + } + return _realloc_base(originalPtr, newSize); + } + static void Free(void* ptr) { _free_base(ptr); } +}; + +extern SourceAllocator* g_SourceAllocator; + +typedef rapidjson::GenericDocument, rapidjson::MemoryPoolAllocator, SourceAllocator> rapidjson_document; +//typedef rapidjson::GenericDocument, SourceAllocator, SourceAllocator> rapidjson_document; +//typedef rapidjson::Document rapidjson_document; +//using MyDocument = rapidjson::GenericDocument, MemoryAllocator>; +//using rapidjson_document = rapidjson::GenericDocument, SourceAllocator, SourceAllocator>; diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index 49c69c78..a9119075 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -22,7 +22,7 @@ Mod::Mod(fs::path modDir, char* jsonBuf) ModDirectory = modDir; - rapidjson::Document modJson; + rapidjson_document modJson; modJson.Parse(jsonBuf); // fail if parse error @@ -379,7 +379,7 @@ void ModManager::UnloadMods() // should we be doing this here or should scripts be doing this manually? // main issue with doing this here is when we reload mods for connecting to a server, we write enabled mods, which isn't necessarily what we wanna do if (!m_enabledModsCfg.HasMember(mod.Name.c_str())) - m_enabledModsCfg.AddMember(rapidjson::StringRef(mod.Name.c_str()), rapidjson::Value(false), m_enabledModsCfg.GetAllocator()); + m_enabledModsCfg.AddMember(rapidjson_document::StringRefType(mod.Name.c_str()), rapidjson_document::GenericValue(false), m_enabledModsCfg.GetAllocator()); m_enabledModsCfg[mod.Name.c_str()].SetBool(mod.Enabled); } diff --git a/NorthstarDedicatedTest/modmanager.h b/NorthstarDedicatedTest/modmanager.h index 5f2f6441..20cb0a42 100644 --- a/NorthstarDedicatedTest/modmanager.h +++ b/NorthstarDedicatedTest/modmanager.h @@ -4,6 +4,7 @@ #include #include #include "rapidjson/document.h" +#include "memalloc.h" namespace fs = std::filesystem; @@ -100,7 +101,7 @@ class ModManager private: bool m_hasLoadedMods = false; bool m_hasEnabledModsCfg; - rapidjson::Document m_enabledModsCfg; + rapidjson_document m_enabledModsCfg; // precalculated hashes size_t m_hScriptsRsonHash; diff --git a/NorthstarDedicatedTest/pch.h b/NorthstarDedicatedTest/pch.h index 9ac5b8a9..a07d1401 100644 --- a/NorthstarDedicatedTest/pch.h +++ b/NorthstarDedicatedTest/pch.h @@ -11,10 +11,12 @@ // httplib ssl // add headers that you want to pre-compile here +#include "memalloc.h" #include #include "logging.h" #include "include/MinHook.h" #include "spdlog/spdlog.h" +#include "libcurl/include/curl/curl.h" #include "hookutils.h" #endif \ No newline at end of file diff --git a/loader_launcher_proxy/Memory.cpp b/loader_launcher_proxy/Memory.cpp index bd19502a..f00c4d96 100644 --- a/loader_launcher_proxy/Memory.cpp +++ b/loader_launcher_proxy/Memory.cpp @@ -70,6 +70,7 @@ void* realloc(void* old_ptr, size_t size) { if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) return (*g_ppMemAllocSingleton)->m_vtable->Realloc(*g_ppMemAllocSingleton, old_ptr, size); + return nullptr; } void* operator new(size_t n) -- cgit v1.2.3 From 831a9a99f4c75560a0a33c2da89b5d36b55d612b Mon Sep 17 00:00:00 2001 From: geni Date: Fri, 31 Dec 2021 15:39:18 +0200 Subject: Make launcher proxy target v143 The rest of Northstar targets v143 --- loader_launcher_proxy/loader_launcher_proxy.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'loader_launcher_proxy') diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj b/loader_launcher_proxy/loader_launcher_proxy.vcxproj index 9cc7a4c7..32d2e44c 100644 --- a/loader_launcher_proxy/loader_launcher_proxy.vcxproj +++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj @@ -21,7 +21,7 @@ DynamicLibrary true - v142 + v143 Unicode -- cgit v1.2.3 From 0a0cc706e7220a6927e10d333796c12442cb84c1 Mon Sep 17 00:00:00 2001 From: geni Date: Fri, 31 Dec 2021 15:39:46 +0200 Subject: Clean up --- LauncherInjector/LauncherInjector.vcxproj | 1 - LauncherInjector/LauncherInjector.vcxproj.filters | 3 - LauncherInjector/memalloc.cpp | 90 ---------------------- LauncherInjector/memalloc.h | 24 ------ loader_launcher_proxy/framework.h | 4 +- .../loader_launcher_proxy.vcxproj | 2 - .../loader_launcher_proxy.vcxproj.filters | 6 -- loader_launcher_proxy/pch.h | 2 - 8 files changed, 3 insertions(+), 129 deletions(-) delete mode 100644 LauncherInjector/memalloc.cpp delete mode 100644 LauncherInjector/memalloc.h (limited to 'loader_launcher_proxy') diff --git a/LauncherInjector/LauncherInjector.vcxproj b/LauncherInjector/LauncherInjector.vcxproj index 289d66ae..30fa690e 100644 --- a/LauncherInjector/LauncherInjector.vcxproj +++ b/LauncherInjector/LauncherInjector.vcxproj @@ -88,7 +88,6 @@ - diff --git a/LauncherInjector/LauncherInjector.vcxproj.filters b/LauncherInjector/LauncherInjector.vcxproj.filters index 2e935b08..449381ca 100644 --- a/LauncherInjector/LauncherInjector.vcxproj.filters +++ b/LauncherInjector/LauncherInjector.vcxproj.filters @@ -18,9 +18,6 @@ Source Files - - Source Files - diff --git a/LauncherInjector/memalloc.cpp b/LauncherInjector/memalloc.cpp deleted file mode 100644 index af334acf..00000000 --- a/LauncherInjector/memalloc.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#include -#include "memalloc.h" -#include - -extern HMODULE hTier0Module; -IMemAlloc** g_ppMemAllocSingleton; - -void LoadTier0Handle() -{ - if (!hTier0Module) hTier0Module = GetModuleHandleA("tier0.dll"); - if (!hTier0Module) return; - - g_ppMemAllocSingleton = (IMemAlloc**)GetProcAddress(hTier0Module, "g_pMemAllocSingleton"); -} - -const int STATIC_ALLOC_SIZE = 16384; - -size_t g_iStaticAllocated = 0; -void* g_pLastAllocated = nullptr; -char pStaticAllocBuf[STATIC_ALLOC_SIZE]; - -// they should never be used here, except in LibraryLoadError // haha not true - -void* malloc(size_t n) -{ - //printf("NorthstarLauncher malloc: %llu\n", n); - // allocate into static buffer - if (g_iStaticAllocated + n <= STATIC_ALLOC_SIZE) - { - void* ret = pStaticAllocBuf + g_iStaticAllocated; - g_iStaticAllocated += n; - g_pLastAllocated = ret; - return ret; - } - else - { - // try to fallback to g_pMemAllocSingleton - if (!hTier0Module || !g_ppMemAllocSingleton) LoadTier0Handle(); - if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) - return (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n); - else - throw "Cannot allocate"; - } -} - -void free(void* p) -{ - //printf("NorthstarLauncher free: %p\n", p); - // if it was allocated into the static buffer, just do nothing, safest way to deal with it - if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE) - return; - - if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) - (*g_ppMemAllocSingleton)->m_vtable->Free(*g_ppMemAllocSingleton, p); -} - -void* realloc(void* old_ptr, size_t size) { - // it was allocated into the static buffer - if (old_ptr >= pStaticAllocBuf && old_ptr <= pStaticAllocBuf + STATIC_ALLOC_SIZE) - { - if (g_pLastAllocated == old_ptr) - { - // nothing was allocated after this - size_t old_size = g_iStaticAllocated - ((size_t)g_pLastAllocated - (size_t)pStaticAllocBuf); - size_t diff = size - old_size; - if (diff > 0) - g_iStaticAllocated += diff; - return old_ptr; - } - else - { - return malloc(size); - } - } - - if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton) - return (*g_ppMemAllocSingleton)->m_vtable->Realloc(*g_ppMemAllocSingleton, old_ptr, size); - return nullptr; -} - -void* operator new(size_t n) -{ - return malloc(n); -} - -void operator delete(void* p) -{ - free(p); -} diff --git a/LauncherInjector/memalloc.h b/LauncherInjector/memalloc.h deleted file mode 100644 index c983966c..00000000 --- a/LauncherInjector/memalloc.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -class IMemAlloc -{ -public: - struct VTable - { - void* unknown[1]; // alloc debug - void* (*Alloc) (IMemAlloc* memAlloc, size_t nSize); - void* unknown2[1]; // realloc debug - void* (*Realloc)(IMemAlloc* memAlloc, void* pMem, size_t nSize); - void* unknown3[1]; // free #1 - void (*Free) (IMemAlloc* memAlloc, void* pMem); - void* unknown4[2]; // nullsubs, maybe CrtSetDbgFlag - size_t(*GetSize) (IMemAlloc* memAlloc, void* pMem); - void* unknown5[9]; // they all do literally nothing - void (*DumpStats) (IMemAlloc* memAlloc); - void (*DumpStatsFileBase) (IMemAlloc* memAlloc, const char* pchFileBase); - void* unknown6[4]; - int (*heapchk) (IMemAlloc* memAlloc); - }; - - VTable* m_vtable; -}; diff --git a/loader_launcher_proxy/framework.h b/loader_launcher_proxy/framework.h index 54b83e94..d1b49600 100644 --- a/loader_launcher_proxy/framework.h +++ b/loader_launcher_proxy/framework.h @@ -1,5 +1,7 @@ #pragma once #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define WIN32_EXTRA_LEAN +#define VC_EXTRALEAN // Windows Header Files -#include +#include diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj b/loader_launcher_proxy/loader_launcher_proxy.vcxproj index 32d2e44c..24cdabc0 100644 --- a/loader_launcher_proxy/loader_launcher_proxy.vcxproj +++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj @@ -92,12 +92,10 @@ - - Create Create diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters b/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters index 519ed674..1e57c7b1 100644 --- a/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters +++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters @@ -21,9 +21,6 @@ Header Files - - Header Files - @@ -32,8 +29,5 @@ Source Files - - Source Files - \ No newline at end of file diff --git a/loader_launcher_proxy/pch.h b/loader_launcher_proxy/pch.h index 30257bb2..885d5d62 100644 --- a/loader_launcher_proxy/pch.h +++ b/loader_launcher_proxy/pch.h @@ -7,8 +7,6 @@ #ifndef PCH_H #define PCH_H -#include "Memory.h" - // add headers that you want to pre-compile here #include "framework.h" -- cgit v1.2.3 From e98e1a44aaa04f45b5cee415a882ab2d79942b7f Mon Sep 17 00:00:00 2001 From: geni Date: Fri, 31 Dec 2021 15:40:00 +0200 Subject: Fix launcher proxy --- loader_launcher_proxy/dllmain.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'loader_launcher_proxy') diff --git a/loader_launcher_proxy/dllmain.cpp b/loader_launcher_proxy/dllmain.cpp index 7a778208..9fddc8d4 100644 --- a/loader_launcher_proxy/dllmain.cpp +++ b/loader_launcher_proxy/dllmain.cpp @@ -119,6 +119,14 @@ extern "C" __declspec(dllexport) int LauncherMain(HINSTANCE hInstance, HINSTANCE if (loadNorthstar) { + swprintf_s(dllPath, L"%s\\bin\\x64_retail\\tier0.dll", exePath); + hTier0Module = LoadLibraryW(dllPath); + if (!hTier0Module) + { + LibraryLoadError(GetLastError(), L"tier0.dll", dllPath); + return 1; + } + if (!LoadNorthstar()) return 1; } @@ -131,16 +139,6 @@ extern "C" __declspec(dllexport) int LauncherMain(HINSTANCE hInstance, HINSTANCE LibraryLoadError(GetLastError(), L"launcher.org.dll", dllPath); return 1; } - - // this makes zero sense given tier0.dll is already loaded via imports on launcher.dll, but we do it for full consistency with original launcher exe - // and to also let load callbacks in Northstar work for tier0.dll - swprintf_s(dllPath, L"%s\\bin\\x64_retail\\tier0.dll", exePath); - hTier0Module = LoadLibraryW(dllPath); - if (!hTier0Module) - { - LibraryLoadError(GetLastError(), L"tier0.dll", dllPath); - return 1; - } } auto LauncherMain = GetLauncherMain(); -- cgit v1.2.3 From 664d5d434e8e31f8f74992f2f2b94ffd8a7609c0 Mon Sep 17 00:00:00 2001 From: p0358 Date: Sun, 2 Jan 2022 07:57:21 +0100 Subject: add wsock32 proxy!!! (it works quite nicely) --- R2Northstar.sln | 6 + loader_launcher_proxy/dllmain.cpp | 6 +- loader_wsock32_proxy/dllmain.cpp | 133 +++++++++++++++++++++ loader_wsock32_proxy/hookutils.cpp | 71 +++++++++++ loader_wsock32_proxy/loader.cpp | 61 ++++++++++ loader_wsock32_proxy/loader.h | 7 ++ loader_wsock32_proxy/loader_wsock32_proxy.vcxproj | 115 ++++++++++++++++++ .../loader_wsock32_proxy.vcxproj.filters | 49 ++++++++ loader_wsock32_proxy/pch.cpp | 5 + loader_wsock32_proxy/pch.h | 16 +++ loader_wsock32_proxy/wsock32.asm | 7 ++ loader_wsock32_proxy/wsock32.def | 78 ++++++++++++ 12 files changed, 551 insertions(+), 3 deletions(-) create mode 100644 loader_wsock32_proxy/dllmain.cpp create mode 100644 loader_wsock32_proxy/hookutils.cpp create mode 100644 loader_wsock32_proxy/loader.cpp create mode 100644 loader_wsock32_proxy/loader.h create mode 100644 loader_wsock32_proxy/loader_wsock32_proxy.vcxproj create mode 100644 loader_wsock32_proxy/loader_wsock32_proxy.vcxproj.filters create mode 100644 loader_wsock32_proxy/pch.cpp create mode 100644 loader_wsock32_proxy/pch.h create mode 100644 loader_wsock32_proxy/wsock32.asm create mode 100644 loader_wsock32_proxy/wsock32.def (limited to 'loader_launcher_proxy') diff --git a/R2Northstar.sln b/R2Northstar.sln index c113a437..3dfdb218 100644 --- a/R2Northstar.sln +++ b/R2Northstar.sln @@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NorthstarLauncher", "Launch EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader_launcher_proxy", "loader_launcher_proxy\loader_launcher_proxy.vcxproj", "{F65C322D-66DF-4AF1-B650-70221DE334C0}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader_wsock32_proxy", "loader_wsock32_proxy\loader_wsock32_proxy.vcxproj", "{CF55F3B5-F348-450A-9CCB-C269F21D629D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -27,6 +29,10 @@ Global {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x64.Build.0 = Debug|x64 {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x64.ActiveCfg = Release|x64 {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x64.Build.0 = Release|x64 + {CF55F3B5-F348-450A-9CCB-C269F21D629D}.Debug|x64.ActiveCfg = Debug|x64 + {CF55F3B5-F348-450A-9CCB-C269F21D629D}.Debug|x64.Build.0 = Debug|x64 + {CF55F3B5-F348-450A-9CCB-C269F21D629D}.Release|x64.ActiveCfg = Release|x64 + {CF55F3B5-F348-450A-9CCB-C269F21D629D}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/loader_launcher_proxy/dllmain.cpp b/loader_launcher_proxy/dllmain.cpp index 9fddc8d4..cf69d63e 100644 --- a/loader_launcher_proxy/dllmain.cpp +++ b/loader_launcher_proxy/dllmain.cpp @@ -93,7 +93,7 @@ bool LoadNorthstar() FARPROC Hook_Init = nullptr; { swprintf_s(dllPath, L"%s\\Northstar.dll", exePath); - hHookModule = LoadLibraryExW(dllPath, 0i64, 8u); + hHookModule = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH); if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); if (!hHookModule || Hook_Init == nullptr) { @@ -120,7 +120,7 @@ extern "C" __declspec(dllexport) int LauncherMain(HINSTANCE hInstance, HINSTANCE if (loadNorthstar) { swprintf_s(dllPath, L"%s\\bin\\x64_retail\\tier0.dll", exePath); - hTier0Module = LoadLibraryW(dllPath); + hTier0Module = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH); if (!hTier0Module) { LibraryLoadError(GetLastError(), L"tier0.dll", dllPath); @@ -133,7 +133,7 @@ extern "C" __declspec(dllexport) int LauncherMain(HINSTANCE hInstance, HINSTANCE //else printf("\n\n WILL !!!NOT!!! LOAD NORTHSTAR\n\n"); swprintf_s(dllPath, L"%s\\bin\\x64_retail\\launcher.org.dll", exePath); - hLauncherModule = LoadLibraryExW(dllPath, 0i64, 8u); + hLauncherModule = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH); if (!hLauncherModule) { LibraryLoadError(GetLastError(), L"launcher.org.dll", dllPath); diff --git a/loader_wsock32_proxy/dllmain.cpp b/loader_wsock32_proxy/dllmain.cpp new file mode 100644 index 00000000..8e3dcd72 --- /dev/null +++ b/loader_wsock32_proxy/dllmain.cpp @@ -0,0 +1,133 @@ +#include "pch.h" +#include "loader.h" + +#include +#include + +HINSTANCE hLThis = 0; +FARPROC p[857]; +HINSTANCE hL = 0; + +bool GetExePathWide(wchar_t* dest, DWORD destSize) +{ + if (!dest) return NULL; + if (destSize < MAX_PATH) return NULL; + + DWORD length = GetModuleFileNameW(NULL, dest, destSize); + return length && PathRemoveFileSpecW(dest); +} + +wchar_t exePath[4096]; +wchar_t dllPath[8192]; +wchar_t dllPath2[4096]; + +BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID) +{ + if (reason == DLL_PROCESS_ATTACH) + { + hLThis = hInst; + + if (!GetExePathWide(exePath, 4096)) + { + MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Northstar Wsock32 Proxy Error", 0); + return 1; + } + + if (!ProvisionNorthstar()) // does not call InitialiseNorthstar yet, will do it on LauncherMain hook + return 1; + + swprintf_s(dllPath, L"%s\\bin\\x64_retail\\wsock32.org.dll", exePath); + GetSystemDirectoryW(dllPath2, 4096); + swprintf_s(dllPath2, L"%s\\wsock32.dll", dllPath2); + try + { + std::filesystem::copy_file(dllPath2, dllPath); + } + catch (const std::exception& e) + { + if (!std::filesystem::exists(dllPath)) + { + swprintf_s(dllPath, L"Failed copying wsock32.dll from system32 to \"%s\"\n\n%S", dllPath, e.what()); + MessageBoxW(GetForegroundWindow(), dllPath, L"Northstar Wsock32 Proxy Error", 0); + } + } + hL = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!hL) return false; + + p[1] = GetProcAddress(hL, "EnumProtocolsA"); + p[2] = GetProcAddress(hL, "EnumProtocolsW"); + p[4] = GetProcAddress(hL, "GetAddressByNameA"); + p[5] = GetProcAddress(hL, "GetAddressByNameW"); + p[17] = GetProcAddress(hL, "WEP"); + p[30] = GetProcAddress(hL, "WSARecvEx"); + p[36] = GetProcAddress(hL, "__WSAFDIsSet"); + p[45] = GetProcAddress(hL, "getnetbyname"); + p[52] = GetProcAddress(hL, "getsockopt"); + p[56] = GetProcAddress(hL, "inet_network"); + p[67] = GetProcAddress(hL, "s_perror"); + p[72] = GetProcAddress(hL, "setsockopt"); + } + + if (reason == DLL_PROCESS_DETACH) + { + FreeLibrary(hL); + return 1; + } + + return 1; +} + +extern "C" +{ + FARPROC PA = NULL; + int RunASM(); + + void PROXY_EnumProtocolsA() { + PA = p[1]; + RunASM(); + } + void PROXY_EnumProtocolsW() { + PA = p[2]; + RunASM(); + } + void PROXY_GetAddressByNameA() { + PA = p[4]; + RunASM(); + } + void PROXY_GetAddressByNameW() { + PA = p[5]; + RunASM(); + } + void PROXY_WEP() { + PA = p[17]; + RunASM(); + } + void PROXY_WSARecvEx() { + PA = p[30]; + RunASM(); + } + void PROXY___WSAFDIsSet() { + PA = p[36]; + RunASM(); + } + void PROXY_getnetbyname() { + PA = p[45]; + RunASM(); + } + void PROXY_getsockopt() { + PA = p[52]; + RunASM(); + } + void PROXY_inet_network() { + PA = p[56]; + RunASM(); + } + void PROXY_s_perror() { + PA = p[67]; + RunASM(); + } + void PROXY_setsockopt() { + PA = p[72]; + RunASM(); + } +} \ No newline at end of file diff --git a/loader_wsock32_proxy/hookutils.cpp b/loader_wsock32_proxy/hookutils.cpp new file mode 100644 index 00000000..8603cb35 --- /dev/null +++ b/loader_wsock32_proxy/hookutils.cpp @@ -0,0 +1,71 @@ +#include "pch.h" +#include "../NorthstarDedicatedTest/hookutils.h" + +#define ERROR(...) { char err[2048]; sprintf_s(err, __VA_ARGS__); MessageBoxA(GetForegroundWindow(), err, "Northstar Wsock32 Proxy Error", 0); } + +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) +{ + // the macro for this uses ppTarget's name as targetName, and this typically starts with & + // targetname is used for debug stuff and debug output is nicer if we don't have this + if (*targetName == '&') + 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 + { + //ERROR("Enabling hook %s", hook->targetName); + } + } +} \ No newline at end of file diff --git a/loader_wsock32_proxy/loader.cpp b/loader_wsock32_proxy/loader.cpp new file mode 100644 index 00000000..19a448b2 --- /dev/null +++ b/loader_wsock32_proxy/loader.cpp @@ -0,0 +1,61 @@ +#include "pch.h" +#include "loader.h" +#include "../NorthstarDedicatedTest/hookutils.h" +#include +#include + +void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location) +{ + char text[2048]; + std::string message = std::system_category().message(dwMessageId); + sprintf_s(text, "Failed to load the %ls at \"%ls\" (%lu):\n\n%hs", libName, location, dwMessageId, message.c_str()); + MessageBoxA(GetForegroundWindow(), text, "Northstar Wsock32 Proxy Error", 0); +} + +bool LoadNorthstar() +{ + FARPROC Hook_Init = nullptr; + { + swprintf_s(dllPath, L"%s\\Northstar.dll", exePath); + auto hHookModule = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH); + if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar"); + if (!hHookModule || Hook_Init == nullptr) + { + LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath); + return false; + } + } + + ((bool (*)()) Hook_Init)(); + return true; +} + +typedef int(*LauncherMainType)(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); +LauncherMainType LauncherMainOriginal; + +int LauncherMainHook(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + LoadNorthstar(); + return LauncherMainOriginal(hInstance, hPrevInstance, lpCmdLine, nCmdShow); +} + +bool ProvisionNorthstar() +{ + if (MH_Initialize() != MH_OK) + { + MessageBoxA(GetForegroundWindow(), "MH_Initialize failed\nThe game cannot continue and has to exit.", "Northstar Wsock32 Proxy Error", 0); + return false; + } + + auto launcherHandle = GetModuleHandleA("launcher.dll"); + if (!launcherHandle) + { + MessageBoxA(GetForegroundWindow(), "Launcher isn't loaded yet.\nThe game cannot continue and has to exit.", "Northstar Wsock32 Proxy Error", 0); + return false; + } + + HookEnabler hook; + ENABLER_CREATEHOOK(hook, GetProcAddress(launcherHandle, "LauncherMain"), &LauncherMainHook, reinterpret_cast(&LauncherMainOriginal)); + + return true; +} \ No newline at end of file diff --git a/loader_wsock32_proxy/loader.h b/loader_wsock32_proxy/loader.h new file mode 100644 index 00000000..02ccb97d --- /dev/null +++ b/loader_wsock32_proxy/loader.h @@ -0,0 +1,7 @@ +#pragma once + +extern wchar_t exePath[4096]; +extern wchar_t dllPath[8192]; +extern wchar_t dllPath2[4096]; + +bool ProvisionNorthstar(); diff --git a/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj b/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj new file mode 100644 index 00000000..993a5250 --- /dev/null +++ b/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj @@ -0,0 +1,115 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {cf55f3b5-f348-450a-9ccb-c269f21d629d} + loaderwsock32proxy + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + true + + + false + wsock32 + + + + Level3 + true + _DEBUG;LOADERADVAPI32PROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;LOADERADVAPI32PROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + ..\NorthstarDedicatedTest\ + stdcpp17 + + + Windows + true + true + true + false + wsock32.def + ..\NorthstarDedicatedTest\include\MinHook.x64.lib;mswsock.lib;ws2_32.lib;Shlwapi.lib;imagehlp.lib;dbghelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;wsock32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj.filters b/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj.filters new file mode 100644 index 00000000..6d131e5b --- /dev/null +++ b/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj.filters @@ -0,0 +1,49 @@ + + + + + {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 + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/loader_wsock32_proxy/pch.cpp b/loader_wsock32_proxy/pch.cpp new file mode 100644 index 00000000..64b7eef6 --- /dev/null +++ b/loader_wsock32_proxy/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/loader_wsock32_proxy/pch.h b/loader_wsock32_proxy/pch.h new file mode 100644 index 00000000..0103ff59 --- /dev/null +++ b/loader_wsock32_proxy/pch.h @@ -0,0 +1,16 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_H +#define PCH_H + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include + +#include "include/MinHook.h" + +#endif //PCH_H diff --git a/loader_wsock32_proxy/wsock32.asm b/loader_wsock32_proxy/wsock32.asm new file mode 100644 index 00000000..22a9c384 --- /dev/null +++ b/loader_wsock32_proxy/wsock32.asm @@ -0,0 +1,7 @@ +.data +extern PA : qword +.code +RunASM proc +jmp qword ptr [PA] +RunASM endp +end diff --git a/loader_wsock32_proxy/wsock32.def b/loader_wsock32_proxy/wsock32.def new file mode 100644 index 00000000..448440b4 --- /dev/null +++ b/loader_wsock32_proxy/wsock32.def @@ -0,0 +1,78 @@ +LIBRARY wsock32 +EXPORTS + AcceptEx=mswsock.AcceptEx + EnumProtocolsA=PROXY_EnumProtocolsA + EnumProtocolsW=PROXY_EnumProtocolsW + GetAcceptExSockaddrs=mswsock.GetAcceptExSockaddrs + GetAddressByNameA=PROXY_GetAddressByNameA + GetAddressByNameW=PROXY_GetAddressByNameW + GetNameByTypeA=ws2_32.GetNameByTypeA + GetNameByTypeW=ws2_32.GetNameByTypeW + GetServiceA=ws2_32.GetServiceA + GetServiceW=ws2_32.GetServiceW + GetTypeByNameA=ws2_32.GetTypeByNameA + GetTypeByNameW=ws2_32.GetTypeByNameW + MigrateWinsockConfiguration=ws2_32.MigrateWinsockConfiguration + NPLoadNameSpaces=ws2_32.NPLoadNameSpaces + SetServiceA=ws2_32.SetServiceA + SetServiceW=ws2_32.SetServiceW + TransmitFile=mswsock.TransmitFile + WEP=PROXY_WEP + WSAAsyncGetHostByAddr=ws2_32.WSAAsyncGetHostByAddr + WSAAsyncGetHostByName=ws2_32.WSAAsyncGetHostByName + WSAAsyncGetProtoByName=ws2_32.WSAAsyncGetProtoByName + WSAAsyncGetProtoByNumber=ws2_32.WSAAsyncGetProtoByNumber + WSAAsyncGetServByName=ws2_32.WSAAsyncGetServByName + WSAAsyncGetServByPort=ws2_32.WSAAsyncGetServByPort + WSAAsyncSelect=ws2_32.WSAAsyncSelect + WSACancelAsyncRequest=ws2_32.WSACancelAsyncRequest + WSACancelBlockingCall=ws2_32.WSACancelBlockingCall + WSACleanup=ws2_32.WSACleanup @116 + WSAGetLastError=ws2_32.WSAGetLastError @111 + WSAIsBlocking=ws2_32.WSAIsBlocking + WSARecvEx=PROXY_WSARecvEx + WSASetBlockingHook=ws2_32.WSASetBlockingHook + WSASetLastError=ws2_32.WSASetLastError @112 + WSAStartup=ws2_32.WSAStartup @115 + WSAUnhookBlockingHook=ws2_32.WSAUnhookBlockingHook + WSApSetPostRoutine=ws2_32.WSApSetPostRoutine + __WSAFDIsSet=PROXY___WSAFDIsSet @151 + accept=ws2_32.accept @1 + bind=ws2_32.bind @2 + closesocket=ws2_32.closesocket @3 + connect=ws2_32.connect @4 + dn_expand=ws2_32.dn_expand @1106 + gethostbyaddr=ws2_32.gethostbyaddr + gethostbyname=ws2_32.gethostbyname @52 + gethostname=ws2_32.gethostname @57 + getnetbyname=PROXY_getnetbyname @ 1101 + getpeername=ws2_32.getpeername @5 + getprotobyname=ws2_32.getprotobyname + getprotobynumber=ws2_32.getprotobynumber + getservbyname=ws2_32.getservbyname + getservbyport=ws2_32.getservbyport + getsockname=ws2_32.getsockname @6 + getsockopt=PROXY_getsockopt @7 + htonl=ws2_32.htonl + htons=ws2_32.htons @9 + inet_addr=ws2_32.inet_addr + inet_network=PROXY_inet_network + inet_ntoa=ws2_32.inet_ntoa + ioctlsocket=ws2_32.ioctlsocket @12 + listen=ws2_32.listen @13 + ntohl=ws2_32.ntohl + ntohs=ws2_32.ntohs @15 + rcmd=ws2_32.rcmd + recv=ws2_32.recv @16 + recvfrom=ws2_32.recvfrom @17 + rexec=ws2_32.rexec + rresvport=ws2_32.rresvport + s_perror=PROXY_s_perror + select=ws2_32.select @18 + select=ws2_32.select @18 + send=ws2_32.send @19 + sendto=ws2_32.sendto @20 + sethostname=ws2_32.sethostname + setsockopt=PROXY_setsockopt @21 + shutdown=ws2_32.shutdown @22 + socket=ws2_32.socket @23 -- cgit v1.2.3