mirror of
https://github.com/geode-sdk/android-launcher.git
synced 2026-10-22 00:42:38 +00:00
add symbol renaming to launcherfix
This commit is contained in:
4 files changed
+159
-1
No files matched your search
@@ -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 "")
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
Reference in new issue
Block a user