diff options
author | p0358 <p0358@users.noreply.github.com> | 2021-12-29 06:38:54 +0100 |
---|---|---|
committer | p0358 <p0358@users.noreply.github.com> | 2021-12-29 06:38:54 +0100 |
commit | 213bf6412410a09b0bdce62b8598bfa23ba096cf (patch) | |
tree | 68c650c35639a71e834d4e3fc964ee5bf65a9d28 /LauncherInjector | |
parent | 8a1a2e97624d15617197248a5e292c5ead5e74a2 (diff) | |
download | NorthstarLauncher-213bf6412410a09b0bdce62b8598bfa23ba096cf.tar.gz NorthstarLauncher-213bf6412410a09b0bdce62b8598bfa23ba096cf.zip |
Add direct launcher
Diffstat (limited to 'LauncherInjector')
-rw-r--r-- | LauncherInjector/LauncherInjector.vcxproj | 8 | ||||
-rw-r--r-- | LauncherInjector/LauncherInjector.vcxproj.filters | 6 | ||||
-rw-r--r-- | LauncherInjector/main.cpp | 172 | ||||
-rw-r--r-- | LauncherInjector/memalloc.cpp | 61 | ||||
-rw-r--r-- | LauncherInjector/memalloc.h | 15 |
5 files changed, 206 insertions, 56 deletions
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 @@ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> <LanguageStandard>stdcpp17</LanguageStandard> + <AdditionalOptions>/F8000000 %(AdditionalOptions)</AdditionalOptions> </ClCompile> <Link> <SubSystem>Console</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>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)</AdditionalDependencies> + <StackReserveSize>8000000</StackReserveSize> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> @@ -137,18 +140,23 @@ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> <LanguageStandard>stdcpp17</LanguageStandard> + <AdditionalOptions>/F8000000 %(AdditionalOptions)</AdditionalOptions> </ClCompile> <Link> <SubSystem>Console</SubSystem> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>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)</AdditionalDependencies> + <StackReserveSize>8000000</StackReserveSize> </Link> </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="main.cpp" /> + <ClCompile Include="memalloc.cpp" /> </ItemGroup> <ItemGroup> + <ClInclude Include="memalloc.h" /> <ClInclude Include="resource1.h" /> </ItemGroup> <ItemGroup> 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 @@ <ClCompile Include="main.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="memalloc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="resource1.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="memalloc.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="resources.rc"> 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 <Windows.h> #include <TlHelp32.h> #include <filesystem> #include <sstream> #include <iostream> #include <fstream> +#include <Shlwapi.h> 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 <Windows.h> +#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; +}; |