From fb82ecfec5893b00f68b72f912c6b3975b5fdb4f Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Mon, 6 Sep 2021 00:24:52 +0100 Subject: moving to using unpacked for launcher --- LauncherInjector/LauncherInjector.vcxproj | 10 + LauncherInjector/LauncherInjector.vcxproj.filters | 15 ++ LauncherInjector/main.cpp | 236 +++++++++------------- LauncherInjector/ns_icon.ico | Bin 0 -> 4286 bytes LauncherInjector/resource1.h | 16 ++ LauncherInjector/resources.rc | 71 +++++++ 6 files changed, 204 insertions(+), 144 deletions(-) create mode 100644 LauncherInjector/ns_icon.ico create mode 100644 LauncherInjector/resource1.h create mode 100644 LauncherInjector/resources.rc (limited to 'LauncherInjector') diff --git a/LauncherInjector/LauncherInjector.vcxproj b/LauncherInjector/LauncherInjector.vcxproj index 620303b1..07d45e75 100644 --- a/LauncherInjector/LauncherInjector.vcxproj +++ b/LauncherInjector/LauncherInjector.vcxproj @@ -24,6 +24,7 @@ {0ea82cb0-53fe-4d4c-96df-47fa970513d0} LauncherInjector 10.0 + NorthstarLauncher @@ -147,6 +148,15 @@ + + + + + + + + + diff --git a/LauncherInjector/LauncherInjector.vcxproj.filters b/LauncherInjector/LauncherInjector.vcxproj.filters index ce0c35cc..87e25fa8 100644 --- a/LauncherInjector/LauncherInjector.vcxproj.filters +++ b/LauncherInjector/LauncherInjector.vcxproj.filters @@ -19,4 +19,19 @@ Source Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + \ No newline at end of file diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp index 86c50804..c335390b 100644 --- a/LauncherInjector/main.cpp +++ b/LauncherInjector/main.cpp @@ -8,155 +8,103 @@ namespace fs = std::filesystem; DWORD GetProcessByName(std::wstring processName) { - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - - PROCESSENTRY32 processSnapshotEntry = { 0 }; - processSnapshotEntry.dwSize = sizeof(PROCESSENTRY32); - - if (snapshot == INVALID_HANDLE_VALUE) - return 0; - - if (!Process32First(snapshot, &processSnapshotEntry)) - return 0; - - while (Process32Next(snapshot, &processSnapshotEntry)) - { - if (!wcscmp(processSnapshotEntry.szExeFile, processName.c_str())) - { - CloseHandle(snapshot); - return processSnapshotEntry.th32ProcessID; - } - } - - CloseHandle(snapshot); - return 0; -} - -void InjectInjectorIntoProcess(DWORD pid) -{ - HANDLE procHandle = OpenProcess(PROCESS_ALL_ACCESS, false, pid); - - std::wstring path = (fs::current_path() / "GameInjector.dll").wstring(); - size_t length = (path.length() + 1) * 2; - LPVOID lpLibName = VirtualAllocEx(procHandle, NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - WriteProcessMemory(procHandle, lpLibName, path.c_str(), length, 0); - - // load minhook, since origin's loadlibrary won't load it from the tf directly by default - std::wstring minhookPath = (fs::current_path() / "MinHook.x86.dll").wstring(); - size_t minhookLength = (minhookPath.length() + 1) * 2; - LPVOID lpMinhookLibName = VirtualAllocEx(procHandle, NULL, minhookLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - WriteProcessMemory(procHandle, lpMinhookLibName, minhookPath.c_str(), minhookLength, 0); + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll"); - LPTHREAD_START_ROUTINE pLoadLibraryW = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW"); - HANDLE thread = CreateRemoteThread(procHandle, NULL, 0, pLoadLibraryW, lpMinhookLibName, 0, 0); - WaitForSingleObject(thread, INFINITE); + PROCESSENTRY32 processSnapshotEntry = { 0 }; + processSnapshotEntry.dwSize = sizeof(PROCESSENTRY32); - thread = CreateRemoteThread(procHandle, NULL, 0, pLoadLibraryW, lpLibName, 0, 0); - WaitForSingleObject(thread, INFINITE); + if (snapshot == INVALID_HANDLE_VALUE) + return 0; - DWORD dwExitCode; - GetExitCodeThread(thread, &dwExitCode); - std::cout << dwExitCode << std::endl; + if (!Process32First(snapshot, &processSnapshotEntry)) + return 0; - CloseHandle(procHandle); + while (Process32Next(snapshot, &processSnapshotEntry)) + { + if (!wcscmp(processSnapshotEntry.szExeFile, processName.c_str())) + { + CloseHandle(snapshot); + return processSnapshotEntry.th32ProcessID; + } + } - std::cout << pid << std::endl; + CloseHandle(snapshot); + return 0; } -void CreateAndHookUnpackedTitanfallProcess() -{ - PROCESS_INFORMATION tfPi; - memset(&tfPi, 0, sizeof(tfPi)); - STARTUPINFO si; - memset(&si, 0, sizeof(si)); - CreateProcessA("Titanfall2-unpacked.exe", (LPSTR)"", NULL, NULL, false, CREATE_SUSPENDED, NULL, NULL, (LPSTARTUPINFOA)&si, &tfPi); - - PROCESS_INFORMATION pi; - memset(&pi, 0, sizeof(pi)); - memset(&si, 0, sizeof(si)); - - std::stringstream argStream; - argStream << tfPi.dwProcessId; - argStream << " "; - argStream << tfPi.dwThreadId; - - CreateProcessA("InjectionProxy64.exe", (LPSTR)(argStream.str().c_str()), NULL, NULL, false, 0, NULL, NULL, (LPSTARTUPINFOA)&si, &pi); - WaitForSingleObject(pi.hThread, INFINITE); - - CloseHandle(pi.hThread); - CloseHandle(tfPi.hThread); -} - -int main() -{ - //AllocConsole(); - - // check if we're in the titanfall directory - if (!fs::exists("Titanfall2.exe") && !fs::exists("Titanfall2-unpacked.exe")) - { - MessageBox(NULL, L"Titanfall2.exe not found! Please launch from your titanfall 2 directory!", L"", MB_OK); - return 1; - } - - // check for steam dll and unpacked exe - bool unpacked = fs::exists("Titanfall2-unpacked.exe"); - //bool steamBuild = !unpacked && fs::exists("steam_api64.dll"); // dont actually need to check for this - - // unpacked origin - if (unpacked) - { - // check origin process - DWORD origin = GetProcessByName(L"Origin.exe"); - - if (!origin) - { - // 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) - return 1; - - char originPath[520]; - DWORD originPathLength = 520; - if (RegQueryValueExA(key, "ClientPath", 0, 0, (LPBYTE)&originPath, &originPathLength) != ERROR_SUCCESS) - return 1; - - 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); - - // bit of a hack, but wait 12.5s to give origin a sec to init - // would be nice if we could do this dynamically, but idk how rn - Sleep(12500); - } - - CreateAndHookUnpackedTitanfallProcess(); - } - // packed - else - { - // create a titanfall process, this will cause origin to start launching the game - // if we're on steam, origin will launch the steam release here, too - // we can't hook the titanfall process here unfortunately, since the titanfall process we create here dies when origin stuff starts - - PROCESS_INFORMATION pi; - memset(&pi, 0, sizeof(pi)); - STARTUPINFO si; - memset(&si, 0, sizeof(si)); - CreateProcessA("Titanfall2.exe", (LPSTR)"", NULL, NULL, false, 0, NULL, NULL, (LPSTARTUPINFOA)&si, &pi); - - // hook launcher - DWORD launcherPID; - // dont actually need to check for steam, origin launches game no matter what - //if (steamBuild) - // while (!(launcherPID = GetProcessByName(L"EASteamProxy.exe"))) Sleep(50); - //else - while (!(launcherPID = GetProcessByName(L"Origin.exe"))) Sleep(50); - - // injector should clean itself up after its job is done - InjectInjectorIntoProcess(launcherPID); - } +#define PROCESS_NAME L"Titanfall2-unpacked.exe" +#define DLL_NAME L"Northstar.dll" + +int main() { + 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; + } + + 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; + } + + if (!GetProcessByName(L"Origin.exe")) + { + // 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; + } + + 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, (LPSTR)"", 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")) + Sleep(200); + } + + STARTUPINFO startupInfo; + PROCESS_INFORMATION processInfo; + + memset(&startupInfo, 0, sizeof(startupInfo)); + memset(&processInfo, 0, sizeof(processInfo)); + + CreateProcessW(PROCESS_NAME, (LPWSTR)L"-multiple -novid", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfo); + + HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll"); + LPTHREAD_START_ROUTINE pLoadLibraryW = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW"); + + SIZE_T dwLength = (wcslen(DLL_NAME) + 1) * 2; + LPVOID lpLibName = VirtualAllocEx(processInfo.hProcess, NULL, dwLength, MEM_COMMIT, PAGE_READWRITE); + + SIZE_T written = 0; + WriteProcessMemory(processInfo.hProcess, lpLibName, DLL_NAME, dwLength, &written); + + HANDLE hThread = CreateRemoteThread(processInfo.hProcess, NULL, NULL, pLoadLibraryW, lpLibName, NULL, NULL); + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + + ResumeThread(processInfo.hThread); + + VirtualFreeEx(processInfo.hProcess, lpLibName, dwLength, MEM_RELEASE); + + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + + return 0; } \ No newline at end of file diff --git a/LauncherInjector/ns_icon.ico b/LauncherInjector/ns_icon.ico new file mode 100644 index 00000000..eb78efef Binary files /dev/null and b/LauncherInjector/ns_icon.ico differ diff --git a/LauncherInjector/resource1.h b/LauncherInjector/resource1.h new file mode 100644 index 00000000..60157c4b --- /dev/null +++ b/LauncherInjector/resource1.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resources.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/LauncherInjector/resources.rc b/LauncherInjector/resources.rc new file mode 100644 index 00000000..a51894c4 --- /dev/null +++ b/LauncherInjector/resources.rc @@ -0,0 +1,71 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource1.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United Kingdom) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource1.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "ns_icon.ico" + +#endif // English (United Kingdom) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + -- cgit v1.2.3