add symbol renaming to launcherfix

This commit is contained in:
qimiko committed 2024-06-20 04:04:46 -07:00
1 parent 63b697e25c
commit c61d652229
4 files changed
+159 -1

No files matched your search

+1 -1
View File
@@ -13,7 +13,7 @@ option(USE_TULIPHOOK "enables choice of hooking library" OFF)
if (USE_TULIPHOOK)
FetchContent_Declare(TulipHook
GIT_REPOSITORY https://github.com/geode-sdk/TulipHook.git
GIT_TAG 70122be72da7787dc42813ba0a992f3612e7871e
GIT_TAG 0021301fcea265416fa8eb5372694931c1d410cb
)
set(TULIP_LINK_SOURCE ON CACHE INTERNAL "")
+150
View File
@@ -1,7 +1,9 @@
#include <dlfcn.h>
#include <jni.h>
#include <string>
#include <cstdint>
#include <android/log.h>
#include <link.h>
#ifndef DISABLE_LAUNCHER_FIX
@@ -41,6 +43,16 @@ JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_setDataPath(
env->ReleaseStringUTFChars(data_path, data_path_str);
}
#ifdef __arm__
// 32bit code
typedef Elf32_Dyn Elf_Dyn;
typedef Elf32_Sym Elf_Sym;
#else
// otherwise we're probably 64bit
typedef Elf64_Dyn Elf_Dyn;
typedef Elf64_Sym Elf_Sym;
#endif
extern "C"
JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_setOriginalDataPath(
JNIEnv *env,
@@ -55,6 +67,144 @@ JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_setOriginalDataPath(
env->ReleaseStringUTFChars(data_path, data_path_str);
}
// i copied this function from the android linker
std::uint32_t elfhash(const char *_name) {
const unsigned char *name = reinterpret_cast<const unsigned char*>(_name);
std::uint32_t h = 0, g;
while (*name) {
h = (h << 4) + *name++;
g = h & 0xf0000000;
h ^= g;
h ^= g >> 24;
}
return h;
}
bool patch_symbol(std::uint32_t* hash_table, char* str_table, Elf_Sym* sym_table, const char* orig_name) {
auto hash = elfhash(orig_name);
auto nbucket = hash_table[0];
auto nchain = hash_table[1];
auto bucket = &hash_table[2];
auto chain = &bucket[nbucket];
for (auto i = bucket[hash % nbucket]; i != 0; i = chain[i]) {
auto sym = sym_table + i;
auto sym_name = str_table + sym->st_name;
if (strcmp(sym_name, orig_name) == 0) {
// there's probably no point to checking this, honestly
if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL && ELF_ST_TYPE(sym->st_info) == STT_FUNC) {
// we found it! now go rename the symbol
std::array<std::uint8_t, 3> new_symbol{":3"};
#ifdef USE_TULIPHOOK
auto res = tulip::hook::writeMemory(sym_name, new_symbol.data(), new_symbol.size());
if (!res) {
__android_log_print(ANDROID_LOG_WARN, "GeodeLauncher-fix", "failed to patch symbol: %s", res.unwrapErr().c_str());
return false;
}
#else
DobbyCodePatch(reinterpret_cast<void*>(sym_name), new_symbol.data(), new_symbol.size());
#endif
return true;
}
}
}
__android_log_print(ANDROID_LOG_WARN, "GeodeLauncher-fix", "could not find symbol %s to patch", orig_name);
return false;
}
int on_dl_iterate(dl_phdr_info* info, size_t size, void* data) {
// this is probably going to be gd
if (strstr(info->dlpi_name, "libcocos2dcpp.so") != nullptr) {
// step 1: get the dynamic table
std::uintptr_t dyn_addr = 0u;
for (auto i = 0u; i < info->dlpi_phnum; i++) {
auto phdr = info->dlpi_phdr + i;
if (phdr->p_type == PT_DYNAMIC) {
dyn_addr = info->dlpi_addr + phdr->p_vaddr;
break;
}
}
if (dyn_addr == 0u) {
__android_log_print(ANDROID_LOG_WARN, "GeodeLauncher-fix", "failed to find libcocos dynamic section");
return 0;
}
// step 2: get the symbol table
auto dyn_entry = reinterpret_cast<Elf_Dyn*>(dyn_addr);
auto dyn_end_reached = false;
std::uintptr_t sym_table_addr = 0u;
std::uintptr_t str_table_addr = 0u;
std::uintptr_t hash_table_addr = 0u;
while (!dyn_end_reached) {
auto tag = dyn_entry->d_tag;
switch (dyn_entry->d_tag) {
case DT_SYMTAB:
sym_table_addr = info->dlpi_addr + dyn_entry->d_un.d_val;
break;
case DT_STRTAB:
str_table_addr = info->dlpi_addr + dyn_entry->d_un.d_val;
break;
case DT_HASH:
hash_table_addr = info->dlpi_addr + dyn_entry->d_un.d_val;
break;
case DT_NULL:
dyn_end_reached = true;
break;
}
dyn_entry++;
}
if (hash_table_addr == 0u || str_table_addr == 0u || sym_table_addr == 0u) {
__android_log_print(ANDROID_LOG_WARN, "GeodeLauncher-fix", "failed to parse dynamic section (at least one table is null)");
return -1;
}
// patch symbol names
auto hash_table = reinterpret_cast<std::uint32_t*>(hash_table_addr);
auto str_table = reinterpret_cast<char*>(str_table_addr);
auto sym_table = reinterpret_cast<Elf_Sym*>(sym_table_addr);
// this is every function that i thought would be relevant
patch_symbol(hash_table, str_table, sym_table, "__gxx_personality_v0");
patch_symbol(hash_table, str_table, sym_table, "__cxa_throw");
patch_symbol(hash_table, str_table, sym_table, "__cxa_rethrow");
patch_symbol(hash_table, str_table, sym_table, "__cxa_allocate_exception");
patch_symbol(hash_table, str_table, sym_table, "__cxa_end_catch");
patch_symbol(hash_table, str_table, sym_table, "__cxa_begin_catch");
patch_symbol(hash_table, str_table, sym_table, "__cxa_guard_abort");
patch_symbol(hash_table, str_table, sym_table, "__cxa_guard_acquire");
patch_symbol(hash_table, str_table, sym_table, "__cxa_guard_release");
patch_symbol(hash_table, str_table, sym_table, "__cxa_free_exception");
patch_symbol(hash_table, str_table, sym_table, "_Unwind_RaiseException");
patch_symbol(hash_table, str_table, sym_table, "_Unwind_Resume");
return 1;
}
return 0;
}
// this should be called after gd is loaded but before geode
extern "C"
JNIEXPORT int JNICALL Java_com_geode_launcher_LauncherFix_performExceptionsRenaming(JNIEnv*, jobject) {
return dl_iterate_phdr(on_dl_iterate, nullptr);
}
std::string redirect_path(const char* pathname) {
auto data_path = DataPaths::get_instance().data_path;
auto original_data_path = DataPaths::get_instance().original_data_path;
@@ -145,6 +145,12 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
tryLoadLibrary(gdPackageInfo, Constants.FMOD_LIB_NAME)
tryLoadLibrary(gdPackageInfo, Constants.COCOS_LIB_NAME)
if (GamePackageUtils.getGameVersionCode(packageManager) >= 39L) {
// this fix requires geode v3, which is 2.206+
// there is a short period in which 2.206 users will still have geode v2, but whatever. ig
LauncherFix.performExceptionsRenaming()
}
loadInternalMods()
setContentView(createView())
@@ -12,4 +12,6 @@ object LauncherFix {
external fun setDataPath(dataPath: String)
external fun setOriginalDataPath(dataPath: String)
external fun performExceptionsRenaming()
}