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 ++ 5 files changed, 206 insertions(+), 56 deletions(-) create mode 100644 LauncherInjector/memalloc.cpp create mode 100644 LauncherInjector/memalloc.h (limited to 'LauncherInjector') 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; +}; -- 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 'LauncherInjector') 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 'LauncherInjector') 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 'LauncherInjector') 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 'LauncherInjector') 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 'LauncherInjector') 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 24e6b264919b9125a4f78991dc0f42fc7797cbf2 Mon Sep 17 00:00:00 2001 From: geni Date: Fri, 31 Dec 2021 14:43:45 +0200 Subject: Clean up --- LauncherInjector/main.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'LauncherInjector') diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp index 1eca067a..f35a3015 100644 --- a/LauncherInjector/main.cpp +++ b/LauncherInjector/main.cpp @@ -18,7 +18,7 @@ HMODULE hHookModule; HMODULE hTier0Module; wchar_t exePath[4096]; -wchar_t buffer[8196]; +wchar_t buffer[8192]; DWORD GetProcessByName(std::wstring processName) { @@ -173,24 +173,18 @@ bool LoadNorthstar() 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; - bool noOriginStartup = false; for (int i = 0; i < argc; i++) - if (!strcmp(argv[i], "-noOriginStartup")) + if (!strcmp(argv[i], "-noOriginStartup") || !strcmp(argv[i], "-dedicated")) noOriginStartup = true; - if (!isDedicated && !noOriginStartup) + if (!noOriginStartup) { EnsureOriginStarted(); } { - - if (!GetExePathWide(exePath, 4096)) + if (!GetExePathWide(exePath, sizeof(exePath))) { MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Northstar Launcher Error", 0); return 1; -- cgit v1.2.3 From 32b1257cd62ee6ec7f1087355a2d9e181429d165 Mon Sep 17 00:00:00 2001 From: geni Date: Fri, 31 Dec 2021 14:44:15 +0200 Subject: Remove linear allocator --- LauncherInjector/main.cpp | 22 +++++------ NorthstarDedicatedTest/dllmain.cpp | 6 +-- NorthstarDedicatedTest/gameutils.cpp | 2 - NorthstarDedicatedTest/memalloc.cpp | 75 ++++++++---------------------------- NorthstarDedicatedTest/memalloc.h | 12 +++--- 5 files changed, 35 insertions(+), 82 deletions(-) (limited to 'LauncherInjector') diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp index f35a3015..761f443e 100644 --- a/LauncherInjector/main.cpp +++ b/LauncherInjector/main.cpp @@ -192,6 +192,15 @@ int main(int argc, char* argv[]) { PrependPath(); + printf("[*] Loading tier0.dll\n"); + swprintf_s(buffer, L"%s\\bin\\x64_retail\\tier0.dll", exePath); + hTier0Module = LoadLibraryExW(buffer, 0, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!hTier0Module) + { + LibraryLoadError(GetLastError(), L"tier0.dll", buffer); + return 1; + } + bool loadNorthstar = ShouldLoadNorthstar(argc, argv); if (loadNorthstar) { @@ -204,23 +213,12 @@ int main(int argc, char* argv[]) { printf("[*] Loading launcher.dll\n"); swprintf_s(buffer, L"%s\\bin\\x64_retail\\launcher.dll", exePath); - hLauncherModule = LoadLibraryExW(buffer, 0i64, 8u); + hLauncherModule = LoadLibraryExW(buffer, 0, LOAD_WITH_ALTERED_SEARCH_PATH); if (!hLauncherModule) { 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"); diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 4f8a445c..07741801 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -58,7 +58,6 @@ void WaitForDebugger(HMODULE baseAddress) if (strstr(GetCommandLineA(), "-waitfordebugger")) { spdlog::info("waiting for debugger..."); - spdlog::info("{} bytes have been statically allocated", g_iStaticAllocated); while (!IsDebuggerPresent()) Sleep(100); @@ -71,7 +70,7 @@ bool InitialiseNorthstar() { if (initialised) { - fprintf(stderr, "[info] Called InitialiseNorthstar more than once!\n"); + spdlog::warn("Called InitialiseNorthstar more than once!"); return false; } initialised = true; @@ -85,7 +84,6 @@ bool InitialiseNorthstar() g_SourceAllocator = new SourceAllocator; curl_global_init(CURL_GLOBAL_DEFAULT); - AddDllLoadCallback("tier0.dll", InitialiseTier0GameUtilFunctions); AddDllLoadCallback("engine.dll", WaitForDebugger); AddDllLoadCallback("engine.dll", InitialiseEngineGameUtilFunctions); AddDllLoadCallback("server.dll", InitialiseServerGameUtilFunctions); @@ -93,8 +91,8 @@ bool InitialiseNorthstar() // dedi patches { + AddDllLoadCallback("launcher.dll", InitialiseDedicatedOrigin); AddDllLoadCallback("engine.dll", InitialiseDedicated); - 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 3e62037c..b2c88e49 100644 --- a/NorthstarDedicatedTest/gameutils.cpp +++ b/NorthstarDedicatedTest/gameutils.cpp @@ -94,8 +94,6 @@ void InitialiseTier0GameUtilFunctions(HMODULE baseAddress) 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")); diff --git a/NorthstarDedicatedTest/memalloc.cpp b/NorthstarDedicatedTest/memalloc.cpp index c1fb70e7..c9cf4d60 100644 --- a/NorthstarDedicatedTest/memalloc.cpp +++ b/NorthstarDedicatedTest/memalloc.cpp @@ -2,43 +2,16 @@ #include "memalloc.h" #include "gameutils.h" -// so for anyone reading this code, you may be curious why the fuck i'm overriding new to alloc into a static 100k buffer -// pretty much, the issue here is that we need to use the game's memory allocator (g_pMemAllocSingleton) or risk heap corruptions, but this allocator is defined in tier0 -// as such, it doesn't exist when we inject -// initially i wanted to just call malloc and free until g_pMemAllocSingleton was initialised, but the issue then becomes that we might try to -// call g_pMemAllocSingleton->Free on memory that was allocated with malloc, which will cause game to crash -// so, the best idea i had for this was to just alloc 100k of memory, have all pre-tier0 allocations use that -// (from what i can tell we hit about 12k before tier0 is loaded atm in debug builds, so it's more than enough) -// then just use the game's allocator after that -// yes, this means we leak 100k of memory, idk how else to do this without breaking stuff - -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 extern "C" void* _malloc_base(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_pMemAllocSingleton) { - 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; + InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll")); } + return g_pMemAllocSingleton->m_vtable->Alloc(g_pMemAllocSingleton, n); } /*extern "C" void* malloc(size_t n) @@ -48,44 +21,30 @@ extern "C" void* _malloc_base(size_t 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) + if (!g_pMemAllocSingleton) { - //printf("Northstar free (prealloc): %p\n", p); - return; + InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll")); } - - //printf("Northstar free (g_pMemAllocSingleton): %p\n", p); g_pMemAllocSingleton->m_vtable->Free(g_pMemAllocSingleton, p); } -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) + +extern "C" void* _realloc_base(void* oldPtr, size_t size) { + if (!g_pMemAllocSingleton) { - 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_base(size); - } + InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll")); } - - if (g_pMemAllocSingleton) - return g_pMemAllocSingleton->m_vtable->Realloc(g_pMemAllocSingleton, old_ptr, size); - return nullptr; + return g_pMemAllocSingleton->m_vtable->Realloc(g_pMemAllocSingleton, oldPtr, size); } extern "C" void* _calloc_base(size_t n, size_t size) { - return _malloc_base(n * size); + size_t bytes = n * size; + void* memory = _malloc_base(bytes); + if (memory) { + memset(memory, 0, bytes); + } + return memory; } extern "C" char* _strdup_base(const char* src) @@ -96,7 +55,7 @@ extern "C" char* _strdup_base(const char* src) while (src[len]) len++; - str = reinterpret_cast(_malloc_base(len + 1)); + str = (char*)(_malloc_base(len + 1)); p = str; while (*src) *p++ = *src++; diff --git a/NorthstarDedicatedTest/memalloc.h b/NorthstarDedicatedTest/memalloc.h index d9277694..86d2ff58 100644 --- a/NorthstarDedicatedTest/memalloc.h +++ b/NorthstarDedicatedTest/memalloc.h @@ -3,16 +3,16 @@ #include "include/rapidjson/document.h" //#include "include/rapidjson/allocators.h" -extern size_t g_iStaticAllocated; - -extern "C" { - char* _strdup_base(const char* src); -} +extern "C" void* _malloc_base(size_t size); +extern "C" void* _calloc_base(size_t const count, size_t const size); +extern "C" void* _realloc_base(void* block, size_t size); +extern "C" void* _recalloc_base(void* const block, size_t const count, size_t const size); +extern "C" void _free_base(void* const block); +extern "C" char* _strdup_base(const char* src); void* operator new(size_t n); void operator delete(void* p); -void* _malloc_base(size_t n); //void* malloc(size_t n); class SourceAllocator { -- 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 'LauncherInjector') 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 d658c0c8374f8491e062fabe031f79185169c414 Mon Sep 17 00:00:00 2001 From: geni Date: Fri, 31 Dec 2021 16:07:09 +0200 Subject: Clean up --- LauncherInjector/LauncherInjector.vcxproj | 1 - LauncherInjector/LauncherInjector.vcxproj.filters | 3 --- NorthstarDedicatedTest/dllmain.cpp | 7 ++----- NorthstarDedicatedTest/memalloc.h | 2 +- 4 files changed, 3 insertions(+), 10 deletions(-) (limited to 'LauncherInjector') diff --git a/LauncherInjector/LauncherInjector.vcxproj b/LauncherInjector/LauncherInjector.vcxproj index 30fa690e..8870c732 100644 --- a/LauncherInjector/LauncherInjector.vcxproj +++ b/LauncherInjector/LauncherInjector.vcxproj @@ -90,7 +90,6 @@ - diff --git a/LauncherInjector/LauncherInjector.vcxproj.filters b/LauncherInjector/LauncherInjector.vcxproj.filters index 449381ca..87e25fa8 100644 --- a/LauncherInjector/LauncherInjector.vcxproj.filters +++ b/LauncherInjector/LauncherInjector.vcxproj.filters @@ -23,9 +23,6 @@ Header Files - - Header Files - diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 07741801..81bae847 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -64,8 +64,6 @@ void WaitForDebugger(HMODULE baseAddress) } } -SourceAllocator* g_SourceAllocator; - bool InitialiseNorthstar() { if (initialised) @@ -75,15 +73,14 @@ bool InitialiseNorthstar() } initialised = true; + curl_global_init(CURL_GLOBAL_DEFAULT); + InitialiseLogging(); // apply initial hooks InstallInitialHooks(); InitialiseInterfaceCreationHooks(); - g_SourceAllocator = new SourceAllocator; - curl_global_init(CURL_GLOBAL_DEFAULT); - AddDllLoadCallback("engine.dll", WaitForDebugger); AddDllLoadCallback("engine.dll", InitialiseEngineGameUtilFunctions); AddDllLoadCallback("server.dll", InitialiseServerGameUtilFunctions); diff --git a/NorthstarDedicatedTest/memalloc.h b/NorthstarDedicatedTest/memalloc.h index 86d2ff58..b98fe3c8 100644 --- a/NorthstarDedicatedTest/memalloc.h +++ b/NorthstarDedicatedTest/memalloc.h @@ -35,7 +35,7 @@ public: static void Free(void* ptr) { _free_base(ptr); } }; -extern SourceAllocator* g_SourceAllocator; +static SourceAllocator g_SourceAllocator; typedef rapidjson::GenericDocument, rapidjson::MemoryPoolAllocator, SourceAllocator> rapidjson_document; //typedef rapidjson::GenericDocument, SourceAllocator, SourceAllocator> rapidjson_document; -- cgit v1.2.3 From 9b13df7bc6f4c09c3fdab27cd51fe76d30b756b8 Mon Sep 17 00:00:00 2001 From: p0358 Date: Fri, 31 Dec 2021 22:46:45 +0100 Subject: some post-merge changes combined with my local changes --- LauncherInjector/main.cpp | 6 +++--- NorthstarDedicatedTest/dedicated.cpp | 2 +- NorthstarDedicatedTest/dllmain.cpp | 16 ++++++---------- NorthstarDedicatedTest/gameutils.cpp | 9 ++++++++- NorthstarDedicatedTest/hooks.cpp | 26 ++++++++++++++++++++++++-- NorthstarDedicatedTest/hooks.h | 4 +++- NorthstarDedicatedTest/masterserver.cpp | 4 ++-- NorthstarDedicatedTest/memalloc.cpp | 6 ++++-- NorthstarDedicatedTest/memalloc.h | 2 -- 9 files changed, 51 insertions(+), 24 deletions(-) (limited to 'LauncherInjector') diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp index 761f443e..0f70fd4b 100644 --- a/LauncherInjector/main.cpp +++ b/LauncherInjector/main.cpp @@ -81,7 +81,7 @@ void EnsureOriginStarted() 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); + MessageBoxA(0, "Error: failed reading Origin path!", "", MB_OK); return; } @@ -89,7 +89,7 @@ void EnsureOriginStarted() DWORD originPathLength = 520; if (RegQueryValueExA(key, "ClientPath", 0, 0, (LPBYTE)&originPath, &originPathLength) != ERROR_SUCCESS) { - MessageBoxA(0, "Error: failed reading origin path!", "", MB_OK); + MessageBoxA(0, "Error: failed reading Origin path!", "", MB_OK); return; } @@ -122,7 +122,7 @@ void PrependPath() { 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); + free(pPath); } else { diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index 0ecc1dba..8dedcdd9 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -394,7 +394,7 @@ void InitialiseDedicatedOrigin(HMODULE baseAddress) char* ptr = (char*)GetProcAddress(GetModuleHandleA("tier0.dll"), "Tier0_InitOrigin"); TempReadWrite rw(ptr); - *ptr = (char)0xC3; + *ptr = (char)0xC3; // ret } typedef void(*PrintFatalSquirrelErrorType)(void* sqvm); diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 81bae847..87fb4d5f 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -43,11 +43,6 @@ BOOL APIENTRY DllMain( HMODULE hModule, break; } - // pls no xD - //if (!initialised) - // InitialiseNorthstar(); - //initialised = true; - return TRUE; } @@ -71,9 +66,10 @@ bool InitialiseNorthstar() spdlog::warn("Called InitialiseNorthstar more than once!"); return false; } + initialised = true; - curl_global_init(CURL_GLOBAL_DEFAULT); + curl_global_init_mem(CURL_GLOBAL_DEFAULT, _malloc_base, _free_base, _realloc_base, _strdup_base, _calloc_base); InitialiseLogging(); @@ -81,6 +77,7 @@ bool InitialiseNorthstar() InstallInitialHooks(); InitialiseInterfaceCreationHooks(); + AddDllLoadCallback("tier0.dll", InitialiseTier0GameUtilFunctions); AddDllLoadCallback("engine.dll", WaitForDebugger); AddDllLoadCallback("engine.dll", InitialiseEngineGameUtilFunctions); AddDllLoadCallback("server.dll", InitialiseServerGameUtilFunctions); @@ -88,7 +85,7 @@ bool InitialiseNorthstar() // dedi patches { - AddDllLoadCallback("launcher.dll", InitialiseDedicatedOrigin); + AddDllLoadCallback("tier0.dll", InitialiseDedicatedOrigin); AddDllLoadCallback("engine.dll", InitialiseDedicated); AddDllLoadCallback("server.dll", InitialiseDedicatedServerGameDLL); AddDllLoadCallback("materialsystem_dx11.dll", InitialiseDedicatedMaterialSystem); @@ -128,9 +125,8 @@ 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) + // run callbacks for any libraries that are already loaded by now + CallAllPendingDLLLoadCallbacks(); return true; } \ No newline at end of file diff --git a/NorthstarDedicatedTest/gameutils.cpp b/NorthstarDedicatedTest/gameutils.cpp index b2c88e49..1cbd8648 100644 --- a/NorthstarDedicatedTest/gameutils.cpp +++ b/NorthstarDedicatedTest/gameutils.cpp @@ -78,6 +78,13 @@ void InitialiseServerGameUtilFunctions(HMODULE baseAddress) void InitialiseTier0GameUtilFunctions(HMODULE baseAddress) { + if (!baseAddress) + { + spdlog::critical("tier0 base address is null, but it should be already loaded"); + throw "tier0 base address is null, but it should be already loaded"; + } + if (g_pMemAllocSingleton) + return; // seems this function was already called CreateGlobalMemAlloc = reinterpret_cast(GetProcAddress(baseAddress, "CreateGlobalMemAlloc")); IMemAlloc** ppMemAllocSingleton = reinterpret_cast(GetProcAddress(baseAddress, "g_pMemAllocSingleton")); if (!ppMemAllocSingleton) @@ -89,7 +96,7 @@ void InitialiseTier0GameUtilFunctions(HMODULE baseAddress) { g_pMemAllocSingleton = CreateGlobalMemAlloc(); *ppMemAllocSingleton = g_pMemAllocSingleton; - spdlog::warn("Created new g_pMemAllocSingleton"); + spdlog::info("Created new g_pMemAllocSingleton"); } else { diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp index 19010e83..0e653d4e 100644 --- a/NorthstarDedicatedTest/hooks.cpp +++ b/NorthstarDedicatedTest/hooks.cpp @@ -8,12 +8,11 @@ #include #include #include +#include typedef LPSTR(*GetCommandLineAType)(); LPSTR GetCommandLineAHook(); -// 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); @@ -138,6 +137,29 @@ void CallLoadLibraryWCallbacks(LPCWSTR lpLibFileName, HMODULE moduleAddress) } } +void CallAllPendingDLLLoadCallbacks() +{ + HMODULE hMods[1024]; + HANDLE hProcess = GetCurrentProcess(); + DWORD cbNeeded; + unsigned int i; + + // Get a list of all the modules in this process. + if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) + { + for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) + { + wchar_t szModName[MAX_PATH]; + + // Get the full path to the module's file. + if (GetModuleFileNameExW(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR))) + { + CallLoadLibraryWCallbacks(szModName, hMods[i]); + } + } + } +} + HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) { HMODULE moduleAddress = LoadLibraryExAOriginal(lpLibFileName, hFile, dwFlags); diff --git a/NorthstarDedicatedTest/hooks.h b/NorthstarDedicatedTest/hooks.h index 972b38a6..10e4d4ba 100644 --- a/NorthstarDedicatedTest/hooks.h +++ b/NorthstarDedicatedTest/hooks.h @@ -4,4 +4,6 @@ void InstallInitialHooks(); typedef void(*DllLoadCallbackFuncType)(HMODULE moduleAddress); -void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback); \ No newline at end of file +void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback); + +void CallAllPendingDLLLoadCallbacks(); \ No newline at end of file diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index 2fec6c82..e25be8ab 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -1022,9 +1022,9 @@ void CHostState__State_GameShutdownHook(CHostState* hostState) CHostState__State_GameShutdown(hostState); } -MasterServerManager::MasterServerManager() +MasterServerManager::MasterServerManager() : m_pendingConnectionInfo{}, m_ownServerId{ "" }, m_ownClientAuthToken{ "" } { - 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 86215e3f..1b9eaae8 100644 --- a/NorthstarDedicatedTest/memalloc.cpp +++ b/NorthstarDedicatedTest/memalloc.cpp @@ -23,13 +23,15 @@ extern "C" void _free_base(void* p) { if (!g_pMemAllocSingleton) { + spdlog::warn("Trying to free something before g_pMemAllocSingleton was ready, this should never happen"); InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll")); } g_pMemAllocSingleton->m_vtable->Free(g_pMemAllocSingleton, p); } -extern "C" void* _realloc_base(void* oldPtr, size_t size) { +extern "C" void* _realloc_base(void* oldPtr, size_t size) +{ if (!g_pMemAllocSingleton) { InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll")); @@ -56,7 +58,7 @@ extern "C" char* _strdup_base(const char* src) while (src[len]) len++; - str = (char*)(_malloc_base(len + 1)); + str = reinterpret_cast(_malloc_base(len + 1)); p = str; while (*src) *p++ = *src++; diff --git a/NorthstarDedicatedTest/memalloc.h b/NorthstarDedicatedTest/memalloc.h index b98fe3c8..92ab9672 100644 --- a/NorthstarDedicatedTest/memalloc.h +++ b/NorthstarDedicatedTest/memalloc.h @@ -35,8 +35,6 @@ public: static void Free(void* ptr) { _free_base(ptr); } }; -static SourceAllocator g_SourceAllocator; - typedef rapidjson::GenericDocument, rapidjson::MemoryPoolAllocator, SourceAllocator> rapidjson_document; //typedef rapidjson::GenericDocument, SourceAllocator, SourceAllocator> rapidjson_document; //typedef rapidjson::Document rapidjson_document; -- cgit v1.2.3 From 23a7ac1ef5c3e5f35c40f738d9140311ef1d3fdb Mon Sep 17 00:00:00 2001 From: p0358 Date: Fri, 31 Dec 2021 23:21:01 +0100 Subject: Add more clear error message for the most common install mistake --- LauncherInjector/main.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'LauncherInjector') diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp index 0f70fd4b..7697e80d 100644 --- a/LauncherInjector/main.cpp +++ b/LauncherInjector/main.cpp @@ -65,9 +65,18 @@ FARPROC GetLauncherMain() void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location) { - char text[2048]; + char text[4096]; 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()); + + if (!fs::exists("Titanfall2.exe") && fs::exists("..\\Titanfall2.exe")) + { + auto curDir = std::filesystem::current_path().filename().string(); + auto aboveDir = std::filesystem::current_path().parent_path().filename().string(); + sprintf_s(text, "%s\n\nWe detected that in your case you have extracted the files into a *subdirectory* of your Titanfall 2 installation.\nPlease move all the files and folders from current folder (\"%s\") into the Titanfall 2 installation directory just above (\"%s\").\n\nPlease try out the above steps by yourself before reaching out to the community for support.", text, curDir.c_str(), aboveDir.c_str()); + } + MessageBoxA(GetForegroundWindow(), text, "Northstar Launcher Error", 0); } @@ -81,7 +90,7 @@ void EnsureOriginStarted() 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); + MessageBoxA(0, "Error: failed reading Origin path!", "Northstar Launcher Error", MB_OK); return; } @@ -89,7 +98,7 @@ void EnsureOriginStarted() DWORD originPathLength = 520; if (RegQueryValueExA(key, "ClientPath", 0, 0, (LPBYTE)&originPath, &originPathLength) != ERROR_SUCCESS) { - MessageBoxA(0, "Error: failed reading Origin path!", "", MB_OK); + MessageBoxA(0, "Error: failed reading Origin path!", "Northstar Launcher Error", MB_OK); return; } -- cgit v1.2.3