diff --git a/CMakeLists.txt b/CMakeLists.txt index dace711f..06aec6c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,10 +196,10 @@ if (WIN32) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") # target x86 on windows with clang - target_compile_options(${PROJECT_NAME} INTERFACE --target=i686-pc-windows-msvc) - target_link_options(${PROJECT_NAME} INTERFACE --target=i686-pc-windows-msvc) - add_compile_options(--target=i686-pc-windows-msvc) - add_link_options(--target=i686-pc-windows-msvc) + target_compile_options(${PROJECT_NAME} INTERFACE --target=x86_64-pc-windows-msvc) + target_link_options(${PROJECT_NAME} INTERFACE --target=x86_64-pc-windows-msvc) + add_compile_options(--target=x86_64-pc-windows-msvc) + add_link_options(--target=x86_64-pc-windows-msvc) endif() endif() diff --git a/loader/include/link/fmod.lib b/loader/include/link/fmod.lib new file mode 100644 index 00000000..fe39326b Binary files /dev/null and b/loader/include/link/fmod.lib differ diff --git a/loader/include/link/gdstring.lib b/loader/include/link/gdstring.lib new file mode 100644 index 00000000..574cceba Binary files /dev/null and b/loader/include/link/gdstring.lib differ diff --git a/loader/include/link/glew32.lib b/loader/include/link/glew32.lib new file mode 100644 index 00000000..fe05d6ab Binary files /dev/null and b/loader/include/link/glew32.lib differ diff --git a/loader/include/link/libExtensions.lib b/loader/include/link/libExtensions.lib new file mode 100644 index 00000000..fe6015ec Binary files /dev/null and b/loader/include/link/libExtensions.lib differ diff --git a/loader/include/link/libcocos2d.lib b/loader/include/link/libcocos2d.lib new file mode 100644 index 00000000..3275c202 Binary files /dev/null and b/loader/include/link/libcocos2d.lib differ diff --git a/loader/include/link/libcurl.lib b/loader/include/link/libcurl.lib new file mode 100644 index 00000000..9c0ed44c Binary files /dev/null and b/loader/include/link/libcurl.lib differ diff --git a/loader/include/link/z.lib b/loader/include/link/z.lib new file mode 100644 index 00000000..082ee2f4 Binary files /dev/null and b/loader/include/link/z.lib differ diff --git a/loader/src/platform/windows/main.cpp b/loader/src/platform/windows/main.cpp index f30c3193..0bb3ed7c 100644 --- a/loader/src/platform/windows/main.cpp +++ b/loader/src/platform/windows/main.cpp @@ -65,39 +65,62 @@ std::string loadGeode() { gdTimestamp = ntHeader->FileHeader.TimeDateStamp; -#ifdef GEODE_IS_WINDOWS32 - - constexpr size_t trampolineSize = 12; + constexpr size_t trampolineSize = GEODE_WINDOWS64(32) GEODE_WINDOWS32(12); mainTrampolineAddr = VirtualAlloc( nullptr, trampolineSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); - auto entryAddr = geode::base::get() + ntHeader->OptionalHeader.AddressOfEntryPoint; + const uintptr_t entryAddr = geode::base::get() + ntHeader->OptionalHeader.AddressOfEntryPoint; // function that calls main - auto preWinMainAddr = entryAddr + 5 + *reinterpret_cast(entryAddr + 6) + 5; + // 32 bit: + // e8 xx xx xx xx call (security) + // e9 xx xx xx xx jmp + // 64 bit: + // 48 83 ec 28 sub rsp, 0x28 + // e8 xx xx xx xx call (security) + // 48 83 c4 28 add rsp, 0x28 + // e9 xx xx xx xx jmp - // 6a 00 push 0 - // 68 00 00 40 00 push geode::base::get() - // e8 ... call ... - uint64_t mainSearchBytes = 0xe80000000068006a; + constexpr ptrdiff_t mainCallJmpOffset = GEODE_WINDOWS64(13) GEODE_WINDOWS32(5); + const uintptr_t mainCallJmpAddress = entryAddr + mainCallJmpOffset; + const int32_t mainCallJmpValue = *reinterpret_cast(mainCallJmpAddress + 1); + const uintptr_t preWinMainAddr = mainCallJmpAddress + mainCallJmpValue + 5; + + // the search bytes for the main function + // 32 bit: + // 6a 00 push 0 + // 68 00 00 40 00 push geode::base::get() + // e8 ... call ... + // 64 bit: + // 44 8b cb mov r9d, ebx + // 4c 8b c0 mov r8, rax + // 33 d2 xor edx, edx + // 48 8d 0d xx xx xx xx lea rcx, [rip + ...] + // e8 ... call ... + + constexpr uint64_t mainSearchBytes = GEODE_WINDOWS64(0xd233c08b4ccb8b44) GEODE_WINDOWS32(0x004000006a006800); + constexpr ptrdiff_t mainSearchCallOffset = GEODE_WINDOWS64(15) GEODE_WINDOWS32(7); + +#ifdef GEODE_IS_WINDOWS32 mainSearchBytes |= static_cast(geode::base::get()) << 24; +#endif uintptr_t patchAddr = 0; - // 0x10000 should be enough of a limit here.. - for (auto searchAddr = preWinMainAddr; searchAddr < preWinMainAddr + 0x10000; searchAddr++) { + // 0x1000 should be enough of a limit here.. + for (auto searchAddr = preWinMainAddr; searchAddr < preWinMainAddr + 0x1000; searchAddr++) { if (*reinterpret_cast(searchAddr) != mainSearchBytes) continue; // follow near call address, this is the call to main - patchAddr = searchAddr + 12 + *reinterpret_cast(searchAddr + 8); + const uintptr_t callAddress = searchAddr + mainSearchCallOffset; + const int32_t callValue = *reinterpret_cast(callAddress + 1); + patchAddr = callAddress + callValue + 5; break; } if (patchAddr == 0) return "Geode could not find the main function, not loading Geode."; - constexpr size_t patchSize = 6; - #define JMP_ADDR(from, to) (std::bit_cast(to) - std::bit_cast(from) - 5) #define JMP_BYTES(from, to) \ static_cast((JMP_ADDR(from, to) >> 0) & 0xFF), \ @@ -105,6 +128,41 @@ std::string loadGeode() { static_cast((JMP_ADDR(from, to) >> 16) & 0xFF), \ static_cast((JMP_ADDR(from, to) >> 24) & 0xFF) +#ifdef GEODE_IS_WINDOWS64 + constexpr size_t patchSize = 15; + + uintptr_t jumpAddr = patchAddr + patchSize; + uint8_t trampolineBytes[trampolineSize] = { + // mov [rsp + 8], rbx + 0x48, 0x89, 0x5c, 0x24, 0x08, + // mov [rsp + 10], rsi + 0x48, 0x89, 0x74, 0x24, 0x10, + // mov [rsp + 18], rdi + 0x48, 0x89, 0x7c, 0x24, 0x18, + // jmp [rip + 0] + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, + // pointer to main + 15 + static_cast((jumpAddr >> 0) & 0xFF), static_cast((jumpAddr >> 8) & 0xFF), static_cast((jumpAddr >> 16) & 0xFF), static_cast((jumpAddr >> 24) & 0xFF), + static_cast((jumpAddr >> 32) & 0xFF), static_cast((jumpAddr >> 40) & 0xFF), static_cast((jumpAddr >> 48) & 0xFF), static_cast((jumpAddr >> 56) & 0xFF), + // nop to pad it out, helps the asm to show up properly on debuggers + 0x90, 0x90, 0x90 + }; + + std::memcpy(mainTrampolineAddr, trampolineBytes, trampolineSize); + + auto jmpAddr = reinterpret_cast(&gdMainHook); + uint8_t patchBytes[patchSize] = { + // jmp [rip + 0] + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, + // pointer to gdMainHook + static_cast((jmpAddr >> 0) & 0xFF), static_cast((jmpAddr >> 8) & 0xFF), static_cast((jmpAddr >> 16) & 0xFF), static_cast((jmpAddr >> 24) & 0xFF), + static_cast((jmpAddr >> 32) & 0xFF), static_cast((jmpAddr >> 40) & 0xFF), static_cast((jmpAddr >> 48) & 0xFF), static_cast((jmpAddr >> 56) & 0xFF), + // nop to pad it out, helps the asm to show up properly on debuggers + 0x90 + }; +#else + constexpr size_t patchSize = 6; + uint8_t trampolineBytes[trampolineSize] = { // push ebp 0x55, @@ -124,15 +182,13 @@ std::string loadGeode() { // nop to pad it out, helps the asm to show up properly on debuggers 0x90 }; +#endif DWORD oldProtect; if (!VirtualProtectEx(process, reinterpret_cast(patchAddr), patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) return "Geode could not hook the main function, not loading Geode."; std::memcpy(reinterpret_cast(patchAddr), patchBytes, patchSize); VirtualProtectEx(process, reinterpret_cast(patchAddr), patchSize, oldProtect, &oldProtect); -#else - #pragma message("64-bit entry is not implemented yet.") -#endif return ""; } diff --git a/loader/src/utils/addresser.cpp b/loader/src/utils/addresser.cpp index 9e80a434..1811996d 100644 --- a/loader/src/utils/addresser.cpp +++ b/loader/src/utils/addresser.cpp @@ -159,16 +159,18 @@ intptr_t Addresser::followThunkFunction(intptr_t address) { auto jmpOffset = *reinterpret_cast(address + 7 + 1); auto tailMergeAddr = address + 7 + jmpOffset + 5; - // this is quite a scary offset, but lets hope it works - auto leaAddr = tailMergeAddr + 51; - // make sure leaAddr is pointing to a lea rcx, [rip + ...] - if (leaAddr && checkByteSequence(leaAddr, {0x48, 0x8d, 0x0d})) { - auto offset = *reinterpret_cast(leaAddr + 3); - auto did = reinterpret_cast(leaAddr + 7 + offset); - address = reinterpret_cast(__delayLoadHelper2(did, reinterpret_cast(leaAddress))); + // inside of the tail merge, try to find the lea rcx, [rip + ...] + for (uintptr_t leaOffset = 10; leaOffset < 100; ++leaOffset) { + auto leaAddr = tailMergeAddr + leaOffset; + if (checkByteSequence(leaAddr, {0x48, 0x8d, 0x0d})) { + auto offset = *reinterpret_cast(leaAddr + 3); + auto did = reinterpret_cast(leaAddr + 7 + offset); + address = reinterpret_cast(__delayLoadHelper2(did, reinterpret_cast(leaAddress))); - if (address == -1) { - address = 0; + if (address == -1) { + address = 0; + } + break; } } }