aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LauncherInjector/LauncherInjector.vcxproj8
-rw-r--r--LauncherInjector/LauncherInjector.vcxproj.filters6
-rw-r--r--LauncherInjector/main.cpp172
-rw-r--r--LauncherInjector/memalloc.cpp61
-rw-r--r--LauncherInjector/memalloc.h15
-rw-r--r--NorthstarDedicatedTest/dllmain.cpp6
-rw-r--r--NorthstarDedicatedTest/main.h2
-rw-r--r--loader_launcher_proxy/Memory.cpp5
-rw-r--r--loader_launcher_proxy/dllmain.cpp37
-rw-r--r--loader_launcher_proxy/pch.h2
10 files changed, 232 insertions, 82 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;
+};
diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp
index 80fc3ca4..1aa4bd3b 100644
--- a/NorthstarDedicatedTest/dllmain.cpp
+++ b/NorthstarDedicatedTest/dllmain.cpp
@@ -66,12 +66,12 @@ void WaitForDebugger(HMODULE baseAddress)
}
// in the future this will be called from launcher instead of dllmain
-void InitialiseNorthstar()
+bool InitialiseNorthstar()
{
if (initialised)
{
fprintf(stderr, "[WARN] Called InitialiseNorthstar more than once!\n");
- return;
+ return false;
}
initialised = true;
@@ -129,4 +129,6 @@ void InitialiseNorthstar()
// mod manager after everything else
AddDllLoadCallback("engine.dll", InitialiseModManager);
+
+ return true;
} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/main.h b/NorthstarDedicatedTest/main.h
index ef5d86dc..90e88912 100644
--- a/NorthstarDedicatedTest/main.h
+++ b/NorthstarDedicatedTest/main.h
@@ -1,3 +1,3 @@
#pragma once
-extern "C" __declspec(dllexport) void InitialiseNorthstar(); \ No newline at end of file
+extern "C" __declspec(dllexport) bool InitialiseNorthstar(); \ No newline at end of file
diff --git a/loader_launcher_proxy/Memory.cpp b/loader_launcher_proxy/Memory.cpp
index d8dc1dc5..d5642ca5 100644
--- a/loader_launcher_proxy/Memory.cpp
+++ b/loader_launcher_proxy/Memory.cpp
@@ -1,7 +1,4 @@
#include "pch.h"
-#include <cstddef>
-#include <malloc.h>
-#include <stdio.h>
HMODULE hTier0Module;
IMemAlloc** g_ppMemAllocSingleton;
@@ -35,7 +32,7 @@ void* operator new(size_t n)
// try to fallback to g_pMemAllocSingleton
if (!hTier0Module) LoadTier0Handle();
if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton)
- (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n);
+ return (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n);
else
throw "Cannot allocate";
}
diff --git a/loader_launcher_proxy/dllmain.cpp b/loader_launcher_proxy/dllmain.cpp
index 6e0d1f07..31360a8e 100644
--- a/loader_launcher_proxy/dllmain.cpp
+++ b/loader_launcher_proxy/dllmain.cpp
@@ -22,7 +22,7 @@ extern "C" _declspec(dllexport) void* __fastcall CreateInterface(const char* pNa
return res;
}
-bool GetExePathWide(wchar_t* dest, size_t destSize)
+bool GetExePathWide(wchar_t* dest, DWORD destSize)
{
if (!dest) return NULL;
if (destSize < MAX_PATH) return NULL;
@@ -66,45 +66,48 @@ BOOL APIENTRY DllMain( HMODULE hModule,
wchar_t exePath[4096];
wchar_t dllPath[4096];
-extern "C" _declspec(dllexport) void LauncherMain(__int64, __int64, __int64, uint32_t)
+extern "C" __declspec(dllexport) int LauncherMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
{
-
if (!GetExePathWide(exePath, 4096))
{
MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Launcher Error", 0);
- return;
+ return 1;
}
- FARPROC Hook_Init = nullptr;
+ bool loadNorthstar = !strstr(GetCommandLineA(), "-vanilla");
+ if (loadNorthstar)
{
- swprintf_s(dllPath, L"%s\\Northstar.dll", exePath);
- hHookModule = LoadLibraryExW(dllPath, 0i64, 8u);
- if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar");
- if (!hHookModule || Hook_Init == nullptr)
+ FARPROC Hook_Init = nullptr;
{
- LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath);
- return;
+ swprintf_s(dllPath, L"%s\\Northstar.dll", exePath);
+ hHookModule = LoadLibraryExW(dllPath, 0i64, 8u);
+ if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar");
+ if (!hHookModule || Hook_Init == nullptr)
+ {
+ LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath);
+ return 1;
+ }
}
- }
- ((void (*)()) Hook_Init)();
- }
+ ((bool (*)()) Hook_Init)();
+ }
- {
swprintf_s(dllPath, L"%s\\bin\\x64_retail\\launcher.org.dll", exePath);
hLauncherModule = LoadLibraryExW(dllPath, 0i64, 8u);
if (!hLauncherModule)
{
LibraryLoadError(GetLastError(), L"launcher.org.dll", dllPath);
- return;
+ return 1;
}
}
auto LauncherMain = GetLauncherMain();
+ if (!LauncherMain)
+ MessageBoxA(GetForegroundWindow(), "Failed loading launcher.org.dll.\nThe game cannot continue and has to exit.", "Launcher Error", 0);
//auto result = ((__int64(__fastcall*)())LauncherMain)();
//auto result = ((signed __int64(__fastcall*)(__int64))LauncherMain)(0i64);
- auto result = ((signed __int64(__fastcall*)(__int64, __int64, __int64, uint32_t))LauncherMain)(0i64, 0i64, 0i64, 0);
+ return ((int(__fastcall*)(HINSTANCE, HINSTANCE, LPSTR, int))LauncherMain)(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
// doubt that will help us here (in launcher.dll) though
diff --git a/loader_launcher_proxy/pch.h b/loader_launcher_proxy/pch.h
index f9687185..30257bb2 100644
--- a/loader_launcher_proxy/pch.h
+++ b/loader_launcher_proxy/pch.h
@@ -9,8 +9,6 @@
#include "Memory.h"
-#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
-
// add headers that you want to pre-compile here
#include "framework.h"