new proxy loader

- remove bootstrapper dll
- add updater exe
- remove createthread/loadlibrary calls
  - and link instead to let windows load it
- needs mac port probably?
This commit is contained in:
ConfiG 2023-06-09 15:39:35 +03:00
parent d72797334f
commit b47870e7e9
No known key found for this signature in database
GPG key ID: 44DA1983F524C11B
6 changed files with 157 additions and 131 deletions

View file

@ -1,71 +0,0 @@
#include <Windows.h>
#include <iostream>
#include <array>
#include <ghc/filesystem.hpp>
void showError(std::string const& error) {
MessageBoxA(nullptr, error.c_str(), "Error Loading Geode", MB_ICONERROR);
}
int loadGeode(PVOID module) {
if (!LoadLibraryW(L"Geode.dll")) {
auto code = GetLastError();
showError("Unable to load Geode (code " + std::to_string(code) + ")");
return code;
}
FreeLibraryAndExitThread(static_cast<HINSTANCE>(module), 0);
return 0;
}
DWORD WINAPI load(PVOID module) {
std::array<WCHAR, MAX_PATH> szFileName;
GetModuleFileNameW(NULL, szFileName.data(), MAX_PATH);
const ghc::filesystem::path path(szFileName.data());
auto workingDir = path.parent_path();
auto updatesDir = workingDir / "geode" / "update";
auto resourcesDir = workingDir / "geode" / "resources";
auto error = std::error_code();
if (ghc::filesystem::exists(updatesDir / "Geode.dll", error) && !error) {
ghc::filesystem::rename(
updatesDir / "Geode.dll",
workingDir / "Geode.dll", error
);
if (error) {
showError("Unable to update Geode: Unable to move Geode.dll - " + error.message());
return error.value();
}
}
if (ghc::filesystem::exists(updatesDir / "resources", error) && !error) {
ghc::filesystem::remove_all(resourcesDir / "geode.loader", error);
if (error) {
showError("Unable to update Geode resources: " + error.message());
} else {
ghc::filesystem::rename(
updatesDir / "resources",
resourcesDir / "geode.loader", error
);
if (error) {
showError("Unable to update Geode resources: " + error.message());
}
}
}
return loadGeode(module);
}
BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID) {
if (reason == DLL_PROCESS_ATTACH) {
HANDLE handle = CreateThread(NULL, 0, load, module, 0, NULL);
if (handle) {
CloseHandle(handle);
} else {
return FALSE;
}
}
return TRUE;
}

View file

@ -20,25 +20,23 @@ set_target_properties(ProxyLoader PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
ARCHIVE_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
)
add_library(fake-geode-loader SHARED fakeGeode.c)
set_target_properties(fake-geode-loader PROPERTIES OUTPUT_NAME "Geode")
target_link_libraries(ProxyLoader PRIVATE fake-geode-loader)
add_library(Bootstrapper SHARED Bootstrapper.cpp)
target_compile_features(Bootstrapper PUBLIC cxx_std_17)
set_target_properties(Bootstrapper PROPERTIES
add_executable(Updater Updater.cpp)
target_compile_features(Updater PUBLIC cxx_std_17)
set_target_properties(Updater PROPERTIES
PREFIX ""
OUTPUT_NAME "GeodeBootstrapper"
OUTPUT_NAME "GeodeUpdater"
RUNTIME_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
LIBRARY_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${GEODE_BIN_PATH}/nightly"
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${GEODE_BIN_PATH}/nightly"
ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${GEODE_BIN_PATH}/nightly"
LIBRARY_OUTPUT_DIRECTORY_RELEASE "${GEODE_BIN_PATH}/nightly"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${GEODE_BIN_PATH}/nightly"
ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${GEODE_BIN_PATH}/nightly"
LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${GEODE_BIN_PATH}/nightly"
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${GEODE_BIN_PATH}/nightly"
ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${GEODE_BIN_PATH}/nightly"
LIBRARY_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
RUNTIME_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
ARCHIVE_OUTPUT_DIRECTORY "${GEODE_BIN_PATH}/nightly"
)
target_link_libraries(Bootstrapper PUBLIC ghc_filesystem)
target_link_libraries(Updater PUBLIC ghc_filesystem)

View file

@ -0,0 +1,79 @@
#include <Windows.h>
#include <iostream>
#include <array>
#include <ghc/filesystem.hpp>
void showError(std::string const& error) {
MessageBoxA(nullptr, error.c_str(), "Error Loading Geode", MB_ICONERROR);
}
int main(int argc, char* argv[]) {
std::array<WCHAR, MAX_PATH> szFileName;
GetModuleFileNameW(NULL, szFileName.data(), MAX_PATH);
const ghc::filesystem::path path(szFileName.data());
auto workingDir = path.parent_path();
auto updatesDir = workingDir / "geode" / "update";
auto resourcesDir = workingDir / "geode" / "resources";
// wait for geode.dll to be writable
int delay = 10;
HANDLE hFile;
while ((hFile = CreateFile((workingDir / "Geode.dll").string().c_str(), FILE_GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_SHARING_VIOLATION) {
Sleep(delay);
if (delay < 5120)
delay *= 2;
}
else
break;
}
if (hFile)
CloseHandle(hFile);
else {
showError("Unable to update Geode: Geode.dll is open by another process.");
return 1;
}
auto error = std::error_code();
if (ghc::filesystem::exists(updatesDir / "Geode.dll", error) && !error) {
ghc::filesystem::rename(updatesDir / "Geode.dll", workingDir / "Geode.dll", error);
if (error) {
showError("Unable to update Geode: Unable to move Geode.dll - " + error.message());
return error.value();
}
}
if (ghc::filesystem::exists(updatesDir / "XInput9_1_0.dll", error) && !error) {
ghc::filesystem::rename(updatesDir / "XInput9_1_0.dll", workingDir / "XInput9_1_0.dll", error);
if (error) {
showError("Unable to update Geode: Unable to move XInput9_1_0.dll - " + error.message());
return error.value();
}
}
if (ghc::filesystem::exists(updatesDir / "resources", error) && !error) {
ghc::filesystem::remove_all(resourcesDir / "geode.loader", error);
if (error) {
showError("Unable to update Geode resources: " + error.message());
} else {
ghc::filesystem::rename(
updatesDir / "resources",
resourcesDir / "geode.loader", error
);
if (error) {
showError("Unable to update Geode resources: " + error.message());
}
}
}
if(argc < 2)
return 0;
// restart gd using the provided path
ShellExecute(NULL, "open", (workingDir / argv[1]).string().c_str(), "", workingDir.string().c_str(), TRUE);
return 0;
}

View file

@ -0,0 +1,2 @@
#include <Windows.h>
__declspec(dllexport) DWORD WINAPI loadGeode(void*);

View file

@ -11,24 +11,16 @@ DWORD XInputGetDSoundAudioDeviceGuids(DWORD user, GUID* render, GUID* capture) {
#pragma comment(linker, "/export:XInputGetDSoundAudioDeviceGuids=_XInputGetDSoundAudioDeviceGuids")
DWORD WINAPI load(PVOID _) {
if (!LoadLibraryW(L"GeodeBootstrapper.dll")) {
char msg[256];
sprintf(msg,
"Unable to load Geode: Unable to load "
"bootstrapper (error code %d)", GetLastError()
);
MessageBoxA(NULL, msg, "Error Loading Geode", MB_ICONERROR);
}
return 0;
}
__declspec(dllimport) DWORD WINAPI loadGeode(void*);
BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID _) {
if (reason == DLL_PROCESS_ATTACH) {
HANDLE handle = CreateThread(NULL, 0, load, module, 0, NULL);
if (handle)
CloseHandle(handle);
else
// Prevents threads from notifying this DLL on creation or destruction.
// Kind of redundant for a game that isn't multi-threaded but will provide
// some slight optimizations if a mod frequently creates and deletes threads.
DisableThreadLibraryCalls(module);
DWORD code = loadGeode(module);
if (code != 0)
return FALSE;
}
return TRUE;

View file

@ -66,46 +66,72 @@ extern "C" [[gnu::visibility("default")]] jint JNI_OnLoad(JavaVM* vm, void* rese
#elif defined(GEODE_IS_WINDOWS)
#include <Windows.h>
DWORD WINAPI loadThread(void* arg) {
bool canMoveBootstrapper = true;
if (auto mod = GetModuleHandleA("GeodeBootstrapper.dll")) {
if (WaitForSingleObject(mod, 1000) != WAIT_OBJECT_0) {
canMoveBootstrapper = false;
}
int WINAPI gdMainHook(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
auto workingDir = dirs::getGameDir();
auto updatesDir = workingDir / "geode" / "update";
auto error = std::error_code();
if (ghc::filesystem::exists(updatesDir / "GeodeUpdater.exe", error) && !error) {
ghc::filesystem::rename(updatesDir / "GeodeUpdater.exe", workingDir / "GeodeUpdater.exe", error);
if (error)
return error.value();
// launch updater
auto updaterPath = (workingDir / "GeodeUpdater.exe").string().c_str();
char gdPath[MAX_PATH];
GetModuleFileName(nullptr, gdPath, MAX_PATH);
// for some reason updater receives garbage as the arg if i dont copy the string like that first
auto gdName = ghc::filesystem::path(gdPath).filename().string().c_str();
char gdName2[MAX_PATH];
strcpy(gdName2, gdName);
ShellExecute(NULL, "open", updaterPath, gdName2, workingDir.string().c_str(), FALSE);
// quit gd before it can even start
exit(0);
return 0;
}
if (canMoveBootstrapper) {
auto workingDir = dirs::getGameDir();
auto updatesDir = workingDir / "geode" / "update";
auto error = std::error_code();
if (ghc::filesystem::exists(updatesDir / "GeodeBootstrapper.dll", error) && !error) {
ghc::filesystem::rename(
updatesDir / "GeodeBootstrapper.dll", workingDir / "GeodeBootstrapper.dll", error
);
if (error) return error.value();
}
}
return geodeEntry(arg);
int exitCode = geodeEntry(hInstance);
if (exitCode != 0)
return exitCode;
return reinterpret_cast<decltype(&wWinMain)>(geode::base::get() + 0x260ff8)(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
BOOL WINAPI DllMain(HINSTANCE lib, DWORD reason, LPVOID) {
switch (reason) {
case DLL_PROCESS_ATTACH:
// Prevents threads from notifying this DLL on creation or destruction.
// Kind of redundant for a game that isn't multi-threaded but will provide
// some slight optimizations if a mod frequently creates and deletes threads.
DisableThreadLibraryCalls(lib);
extern "C" __declspec(dllexport) DWORD WINAPI loadGeode(void* arg) {
auto process = GetCurrentProcess();
// loading thread
HANDLE _ = CreateThread(0, 0, loadThread, lib, 0, nullptr);
if (_) CloseHandle(_);
auto patchAddr = reinterpret_cast<void*>(geode::base::get() + 0x260ff8);
constexpr SIZE_T patchLength = 13;
auto detourAddr = reinterpret_cast<uintptr_t>(&gdMainHook) - geode::base::get() - 0x261005;
auto detourAddrPtr = reinterpret_cast<uint8_t*>(&detourAddr);
break;
uint8_t patchBytes[patchLength] = {
0x55,
0x8b, 0xec,
0x83, 0xe4, 0xf8,
0xeb, 0x06,
0xe9, detourAddrPtr[0], detourAddrPtr[1], detourAddrPtr[2], detourAddrPtr[3]
};
DWORD oldProtect;
BOOL res = TRUE;
res = res && VirtualProtectEx(process, patchAddr, patchLength, PAGE_EXECUTE_READWRITE, &oldProtect);
res = res && WriteProcessMemory(process, patchAddr, patchBytes, patchLength, nullptr);
res = res && VirtualProtectEx(process, patchAddr, patchLength, oldProtect, &oldProtect);
if (!res) {
LoaderImpl::get()->platformMessageBox(
"Unable to Load Geode!",
"There was an unknown fatal error hooking "
"the GD main function and Geode can not be loaded."
);
return 1;
}
return TRUE;
return 0;
}
#endif