aboutsummaryrefslogtreecommitdiff
path: root/LauncherInjector/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'LauncherInjector/main.cpp')
-rw-r--r--LauncherInjector/main.cpp266
1 files changed, 171 insertions, 95 deletions
diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp
index 5828e9e2..7697e80d 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;
+HMODULE hTier0Module;
+
+wchar_t exePath[4096];
+wchar_t buffer[8192];
+
DWORD GetProcessByName(std::wstring processName)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@@ -33,132 +46,195 @@ 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))
+ DWORD length = GetModuleFileNameW(NULL, dest, destSize);
+ return length && PathRemoveFileSpecW(dest);
+}
+
+FARPROC GetLauncherMain()
+{
+ static FARPROC Launcher_LauncherMain;
+ if (!Launcher_LauncherMain)
+ Launcher_LauncherMain = GetProcAddress(hLauncherModule, "LauncherMain");
+ return Launcher_LauncherMain;
+}
+
+void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location)
+{
+ char text[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"))
{
- 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;
+ 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());
}
- if (!fs::exists(DLL_NAME))
+ MessageBoxA(GetForegroundWindow(), text, "Northstar Launcher Error", 0);
+}
+
+void EnsureOriginStarted()
+{
+ if (GetProcessByName(L"Origin.exe") || GetProcessByName(L"EADesktop.exe"))
+ return; // already started
+
+ // 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, "Northstar.dll not found! Please launch from your titanfall 2 directory and ensure you have Northstar installed correctly!", "", MB_OK);
- return 1;
+ MessageBoxA(0, "Error: failed reading Origin path!", "Northstar Launcher Error", MB_OK);
+ return;
}
- bool isdedi = false;
- for (int i = 0; i < argc; i++)
- if (!strcmp(argv[i], "-dedicated"))
- isdedi = true;
-
- if (!isdedi && !GetProcessByName(L"Origin.exe") && !GetProcessByName(L"EADesktop.exe"))
+ 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!", "Northstar Launcher Error", 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, (LPSTR)"", 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);
- // get cmdline args from file
- std::wstring args;
- std::ifstream cmdlineArgFile;
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+}
- args.append(L" ");
- for (int i = 0; i < argc; i++)
+void PrependPath()
+{
+ wchar_t* pPath;
+ size_t len;
+ errno_t err = _wdupenv_s(&pPath, &len, L"PATH");
+ if (!err)
{
- std::string str = argv[i];
-
- args.append(std::wstring(str.begin(), str.end()));
- args.append(L" ");
+ 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);
}
-
- if (!isdedi)
- cmdlineArgFile = std::ifstream("ns_startup_args.txt");
else
- cmdlineArgFile = std::ifstream("ns_startup_args_dedi.txt");
-
- if (cmdlineArgFile)
{
- std::stringstream argBuffer;
- argBuffer << cmdlineArgFile.rdbuf();
- cmdlineArgFile.close();
-
- std::string str = argBuffer.str();
- args.append(std::wstring(str.begin(), str.end()));
+ 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);
}
+}
- //if (isdedi)
- // // copy -dedicated into args if we have it in commandline args
- // args.append(L" -dedicated");
-
- STARTUPINFO startupInfo;
- PROCESS_INFORMATION processInfo;
+bool ShouldLoadNorthstar(int argc, char* argv[])
+{
+ bool loadNorthstar = true;
+ for (int i = 0; i < argc; i++)
+ if (!strcmp(argv[i], "-vanilla"))
+ loadNorthstar = false;
- memset(&startupInfo, 0, sizeof(startupInfo));
- memset(&processInfo, 0, sizeof(processInfo));
+ if (!loadNorthstar)
+ return loadNorthstar;
- CreateProcessW(PROCESS_NAME, (LPWSTR)args.c_str(), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfo);
+ 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;
+}
- HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
- LPTHREAD_START_ROUTINE pLoadLibraryW = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW");
+bool 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 false;
+ }
+ }
- SIZE_T dwLength = (wcslen(DLL_NAME) + 1) * 2;
- LPVOID lpLibName = VirtualAllocEx(processInfo.hProcess, NULL, dwLength, MEM_COMMIT, PAGE_READWRITE);
+ ((bool (*)()) Hook_Init)();
+ return true;
+}
- SIZE_T written = 0;
- WriteProcessMemory(processInfo.hProcess, lpLibName, DLL_NAME, dwLength, &written);
+int main(int argc, char* argv[]) {
- HANDLE hThread = CreateRemoteThread(processInfo.hProcess, NULL, NULL, pLoadLibraryW, lpLibName, NULL, NULL);
+ // checked to avoid starting origin, Northstar.dll will check for -dedicated as well on its own
+ bool noOriginStartup = false;
+ for (int i = 0; i < argc; i++)
+ if (!strcmp(argv[i], "-noOriginStartup") || !strcmp(argv[i], "-dedicated"))
+ noOriginStartup = true;
- if (hThread == NULL)
+ if (!noOriginStartup)
{
- // 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;
+ EnsureOriginStarted();
}
- WaitForSingleObject(hThread, INFINITE);
-
- //MessageBoxA(0, std::to_string(GetLastError()).c_str(), "", MB_OK);
+ {
+ 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;
+ }
- CloseHandle(hThread);
+ PrependPath();
- ResumeThread(processInfo.hThread);
+ 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;
+ }
- VirtualFreeEx(processInfo.hProcess, lpLibName, dwLength, MEM_RELEASE);
+ bool loadNorthstar = ShouldLoadNorthstar(argc, argv);
+ if (loadNorthstar)
+ {
+ printf("[*] Loading Northstar\n");
+ if (!LoadNorthstar())
+ return 1;
+ }
+ else
+ printf("[*] Going to load the vanilla game\n");
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
+ printf("[*] Loading launcher.dll\n");
+ swprintf_s(buffer, L"%s\\bin\\x64_retail\\launcher.dll", exePath);
+ hLauncherModule = LoadLibraryExW(buffer, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hLauncherModule)
+ {
+ LibraryLoadError(GetLastError(), L"launcher.dll", buffer);
+ return 1;
+ }
+ }
- return 0;
+ printf("[*] Launching the game...\n");
+ auto LauncherMain = GetLauncherMain();
+ if (!LauncherMain)
+ 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
} \ No newline at end of file