diff --git a/android/app/src/xposed/cpp/l2c_fcr_hook.cpp b/android/app/src/xposed/cpp/l2c_fcr_hook.cpp index 2b58719..529f862 100644 --- a/android/app/src/xposed/cpp/l2c_fcr_hook.cpp +++ b/android/app/src/xposed/cpp/l2c_fcr_hook.cpp @@ -30,7 +30,7 @@ #include "l2c_fcr_hook.h" extern "C" { - #include "xz.h" +#include "xz.h" } #define LOG_TAG "LibrePodsHook" @@ -39,13 +39,13 @@ extern "C" { static HookFunType hook_func = nullptr; -static uint8_t (*original_l2c_fcr_chk_chan_modes)(void*) = nullptr; -static tBTA_STATUS (*original_BTA_DmSetLocalDiRecord)( - tSDP_DI_RECORD*, uint32_t*) = nullptr; +static uint8_t (*original_l2c_fcr_chk_chan_modes)(void *) = nullptr; + +static tBTA_STATUS (*original_BTA_DmSetLocalDiRecord)(tSDP_DI_RECORD *, uint32_t *) = nullptr; static std::atomic enableSdpHook(false); -uint8_t fake_l2c_fcr_chk_chan_modes(void* p_ccb) { +uint8_t fake_l2c_fcr_chk_chan_modes(void *p_ccb) { LOGI("fake_l2c_fcr_chk_chan_modes called"); uint8_t orig = 0; if (original_l2c_fcr_chk_chan_modes) @@ -55,13 +55,13 @@ uint8_t fake_l2c_fcr_chk_chan_modes(void* p_ccb) { return 1; } -tBTA_STATUS fake_BTA_DmSetLocalDiRecord( - tSDP_DI_RECORD* p_device_info, - uint32_t* p_handle) { +tBTA_STATUS fake_BTA_DmSetLocalDiRecord(tSDP_DI_RECORD *p_device_info, uint32_t *p_handle) { LOGI("fake_BTA_DmSetLocalDiRecord called"); - if (original_BTA_DmSetLocalDiRecord && enableSdpHook.load(std::memory_order_relaxed)) original_BTA_DmSetLocalDiRecord(p_device_info, p_handle); + if (original_BTA_DmSetLocalDiRecord && + enableSdpHook.load(std::memory_order_relaxed)) + original_BTA_DmSetLocalDiRecord(p_device_info, p_handle); LOGI("fake_BTA_DmSetLocalDiRecord: modifying vendor to 0x004C, vendor_id_source to 0x0001"); @@ -70,14 +70,15 @@ tBTA_STATUS fake_BTA_DmSetLocalDiRecord( p_device_info->vendor_id_source = 0x0001; } - LOGI("fake_BTA_DmSetLocalDiRecord: returning status %d", original_BTA_DmSetLocalDiRecord ? original_BTA_DmSetLocalDiRecord(p_device_info, p_handle) : BTA_FAILURE); - return original_BTA_DmSetLocalDiRecord ? original_BTA_DmSetLocalDiRecord(p_device_info, p_handle) : BTA_FAILURE; + LOGI("fake_BTA_DmSetLocalDiRecord: returning status %d", + original_BTA_DmSetLocalDiRecord ? original_BTA_DmSetLocalDiRecord(p_device_info, p_handle) + : BTA_FAILURE); + return original_BTA_DmSetLocalDiRecord ? original_BTA_DmSetLocalDiRecord(p_device_info, + p_handle) + : BTA_FAILURE; } -static bool decompressXZ( - const uint8_t* input, - size_t input_size, - std::vector& output) { +static bool decompressXZ(const uint8_t *input, size_t input_size, std::vector &output) { LOGI("decompressXZ called with input_size: %zu", input_size); @@ -86,7 +87,7 @@ static bool decompressXZ( xz_crc64_init(); #endif - struct xz_dec* dec = xz_dec_init(XZ_DYNALLOC, 64U << 20); + struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 64U << 20); if (!dec) { LOGE("decompressXZ: xz_dec_init failed"); return false; @@ -106,7 +107,8 @@ static bool decompressXZ( LOGI("decompressXZ: entering decompression loop"); while (true) { - LOGI("decompressXZ: xz_dec_run iteration, buf.in_pos: %zu, buf.out_pos: %zu", buf.in_pos, buf.out_pos); + LOGI("decompressXZ: xz_dec_run iteration, buf.in_pos: %zu, buf.out_pos: %zu", buf.in_pos, + buf.out_pos); enum xz_ret ret = xz_dec_run(dec, &buf); LOGI("decompressXZ: xz_dec_run returned %d", ret); @@ -135,10 +137,10 @@ static bool decompressXZ( return true; } -static bool getLibraryPath(const char* name, std::string& out) { +static bool getLibraryPath(const char *name, std::string &out) { LOGI("getLibraryPath called with name: %s", name); - FILE* fp = fopen("/proc/self/maps", "r"); + FILE *fp = fopen("/proc/self/maps", "r"); if (!fp) { LOGE("getLibraryPath: fopen failed"); return false; @@ -150,7 +152,7 @@ static bool getLibraryPath(const char* name, std::string& out) { while (fgets(line, sizeof(line), fp)) { if (strstr(line, name)) { LOGI("getLibraryPath: found line containing %s", name); - char* path = strchr(line, '/'); + char *path = strchr(line, '/'); if (path) { out = path; out.erase(out.find('\n')); @@ -166,10 +168,10 @@ static bool getLibraryPath(const char* name, std::string& out) { return false; } -static uintptr_t getModuleBase(const char* name) { +static uintptr_t getModuleBase(const char *name) { LOGI("getModuleBase called with name: %s", name); - FILE* fp = fopen("/proc/self/maps", "r"); + FILE *fp = fopen("/proc/self/maps", "r"); if (!fp) { LOGE("getModuleBase: fopen failed"); return 0; @@ -192,25 +194,23 @@ static uintptr_t getModuleBase(const char* name) { return base; } -static uint64_t findSymbolOffsetDynsym( - const std::vector& elf, - const char* symbol_substring) { +static uint64_t +findSymbolOffsetDynsym(const std::vector &elf, const char *symbol_substring) { LOGI("findSymbolOffsetDynsym called with %s", symbol_substring); - auto* eh = reinterpret_cast(elf.data()); - auto* shdr = reinterpret_cast( + auto *eh = reinterpret_cast(elf.data()); + auto *shdr = reinterpret_cast( elf.data() + eh->e_shoff); - const char* shstr = - reinterpret_cast( - elf.data() + shdr[eh->e_shstrndx].sh_offset); + const char *shstr = reinterpret_cast( + elf.data() + shdr[eh->e_shstrndx].sh_offset); - const Elf64_Shdr* dynsym = nullptr; - const Elf64_Shdr* dynstr = nullptr; + const Elf64_Shdr *dynsym = nullptr; + const Elf64_Shdr *dynstr = nullptr; for (int i = 0; i < eh->e_shnum; ++i) { - const char* secname = shstr + shdr[i].sh_name; + const char *secname = shstr + shdr[i].sh_name; if (!strcmp(secname, ".dynsym")) dynsym = &shdr[i]; @@ -223,25 +223,23 @@ static uint64_t findSymbolOffsetDynsym( return 0; } - auto* symbols = reinterpret_cast( + auto *symbols = reinterpret_cast( elf.data() + dynsym->sh_offset); - const char* strings = - reinterpret_cast( - elf.data() + dynstr->sh_offset); + const char *strings = reinterpret_cast( + elf.data() + dynstr->sh_offset); size_t count = dynsym->sh_size / sizeof(Elf64_Sym); LOGI("findSymbolOffsetDynsym: scanning %zu symbols", count); for (size_t i = 0; i < count; ++i) { - const char* name = strings + symbols[i].st_name; + const char *name = strings + symbols[i].st_name; - if (strstr(name, symbol_substring) && - ELF64_ST_TYPE(symbols[i].st_info) == STT_FUNC) { + if (strstr(name, symbol_substring) && ELF64_ST_TYPE(symbols[i].st_info) == STT_FUNC) { - LOGI("findSymbolOffsetDynsym: matched %s @ 0x%lx", - name, (unsigned long)symbols[i].st_value); + LOGI("findSymbolOffsetDynsym: matched %s @ 0x%lx", name, + (unsigned long) symbols[i].st_value); return symbols[i].st_value; } @@ -251,26 +249,23 @@ static uint64_t findSymbolOffsetDynsym( return 0; } -static uint64_t findSymbolOffset( - const std::vector& elf, - const char* symbol_substring) { +static uint64_t findSymbolOffset(const std::vector &elf, const char *symbol_substring) { LOGI("findSymbolOffset called with symbol_substring: %s", symbol_substring); - auto* eh = reinterpret_cast(elf.data()); - auto* shdr = reinterpret_cast( + auto *eh = reinterpret_cast(elf.data()); + auto *shdr = reinterpret_cast( elf.data() + eh->e_shoff); - const char* shstr = - reinterpret_cast( - elf.data() + shdr[eh->e_shstrndx].sh_offset); + const char *shstr = reinterpret_cast( + elf.data() + shdr[eh->e_shstrndx].sh_offset); - const Elf64_Shdr* symtab = nullptr; - const Elf64_Shdr* strtab = nullptr; + const Elf64_Shdr *symtab = nullptr; + const Elf64_Shdr *strtab = nullptr; LOGI("findSymbolOffset: parsing ELF sections"); for (int i = 0; i < eh->e_shnum; ++i) { - const char* secname = shstr + shdr[i].sh_name; + const char *secname = shstr + shdr[i].sh_name; if (!strcmp(secname, ".symtab")) symtab = &shdr[i]; if (!strcmp(secname, ".strtab")) @@ -283,23 +278,22 @@ static uint64_t findSymbolOffset( } LOGI("findSymbolOffset: found symtab and strtab"); - auto* symbols = reinterpret_cast( + auto *symbols = reinterpret_cast( elf.data() + symtab->sh_offset); - const char* strings = - reinterpret_cast( - elf.data() + strtab->sh_offset); + const char *strings = reinterpret_cast( + elf.data() + strtab->sh_offset); size_t count = symtab->sh_size / sizeof(Elf64_Sym); LOGI("findSymbolOffset: scanning %zu symbols", count); for (size_t i = 0; i < count; ++i) { - const char* name = strings + symbols[i].st_name; + const char *name = strings + symbols[i].st_name; - if (strstr(name, symbol_substring) && - ELF64_ST_TYPE(symbols[i].st_info) == STT_FUNC) { + if (strstr(name, symbol_substring) && ELF64_ST_TYPE(symbols[i].st_info) == STT_FUNC) { - LOGI("findSymbolOffset: matched symbol %s at 0x%lx", name, (unsigned long)symbols[i].st_value); + LOGI("findSymbolOffset: matched symbol %s at 0x%lx", name, + (unsigned long) symbols[i].st_value); return symbols[i].st_value; } @@ -309,7 +303,7 @@ static uint64_t findSymbolOffset( return 0; } -static bool hookLibrary(const char* libname) { +static bool hookLibrary(const char *libname) { LOGI("hookLibrary called with libname: %s", libname); if (!hook_func) { @@ -336,19 +330,18 @@ static bool hookLibrary(const char* libname) { close(fd); return false; } - LOGI("hookLibrary: opened file, size: %lld", (long long)st.st_size); + LOGI("hookLibrary: opened file, size: %lld", (long long) st.st_size); std::vector file(st.st_size); read(fd, file.data(), st.st_size); close(fd); - auto* eh = reinterpret_cast(file.data()); - auto* shdr = reinterpret_cast( + auto *eh = reinterpret_cast(file.data()); + auto *shdr = reinterpret_cast( file.data() + eh->e_shoff); - const char* shstr = - reinterpret_cast( - file.data() + shdr[eh->e_shstrndx].sh_offset); + const char *shstr = reinterpret_cast( + file.data() + shdr[eh->e_shstrndx].sh_offset); uint64_t chk_offset = 0; uint64_t sdp_offset = 0; @@ -357,22 +350,16 @@ static bool hookLibrary(const char* libname) { if (!strcmp(shstr + shdr[i].sh_name, ".gnu_debugdata")) { LOGI("hookLibrary: found .gnu_debugdata section"); - std::vector compressed( - file.begin() + shdr[i].sh_offset, - file.begin() + shdr[i].sh_offset + shdr[i].sh_size); + std::vector compressed(file.begin() + shdr[i].sh_offset, + file.begin() + shdr[i].sh_offset + shdr[i].sh_size); std::vector decompressed; - if (decompressXZ( - compressed.data(), - compressed.size(), - decompressed)) { + if (decompressXZ(compressed.data(), compressed.size(), decompressed)) { - chk_offset = findSymbolOffset(decompressed, - "l2c_fcr_chk_chan_modes"); + chk_offset = findSymbolOffset(decompressed, "l2c_fcr_chk_chan_modes"); - sdp_offset = findSymbolOffset(decompressed, - "BTA_DmSetLocalDiRecord"); + sdp_offset = findSymbolOffset(decompressed, "BTA_DmSetLocalDiRecord"); } else { LOGE("debugdata decompress failed"); } @@ -383,14 +370,12 @@ static bool hookLibrary(const char* libname) { if (!chk_offset) { LOGI("fallback dynsym chk"); - chk_offset = findSymbolOffsetDynsym(file, - "l2c_fcr_chk_chan_modes"); + chk_offset = findSymbolOffsetDynsym(file, "l2c_fcr_chk_chan_modes"); } if (!sdp_offset) { LOGI("fallback dynsym sdp"); - sdp_offset = findSymbolOffsetDynsym(file, - "BTA_DmSetLocalDiRecord"); + sdp_offset = findSymbolOffsetDynsym(file, "BTA_DmSetLocalDiRecord"); } uintptr_t base = getModuleBase(libname); @@ -400,25 +385,23 @@ static bool hookLibrary(const char* libname) { } if (chk_offset) { - void* target = reinterpret_cast(base + chk_offset); - hook_func(target, - (void*)fake_l2c_fcr_chk_chan_modes, - (void**)&original_l2c_fcr_chk_chan_modes); + void *target = reinterpret_cast(base + chk_offset); + hook_func(target, (void *) fake_l2c_fcr_chk_chan_modes, + (void **) &original_l2c_fcr_chk_chan_modes); LOGI("hooked chk"); } if (sdp_offset) { - void* target = reinterpret_cast(base + sdp_offset); - hook_func(target, - (void*)fake_BTA_DmSetLocalDiRecord, - (void**)&original_BTA_DmSetLocalDiRecord); + void *target = reinterpret_cast(base + sdp_offset); + hook_func(target, (void *) fake_BTA_DmSetLocalDiRecord, + (void **) &original_BTA_DmSetLocalDiRecord); LOGI("hooked sdp"); } return chk_offset || sdp_offset; } -static void on_library_loaded(const char* name, void*) { +static void on_library_loaded(const char *name, void *) { LOGI("on_library_loaded called with name: %s", name); if (strstr(name, "libbluetooth_jni.so")) { @@ -432,20 +415,19 @@ static void on_library_loaded(const char* name, void*) { } } -extern "C" -[[gnu::visibility("default")]] +extern "C" [[gnu::visibility("default")]] [[gnu::used]] -NativeOnModuleLoaded native_init(const NativeAPIEntries* entries) { +NativeOnModuleLoaded native_init(const NativeAPIEntries *entries) { LOGI("native_init called with entries: %p", entries); - hook_func = (HookFunType)entries->hook_func; - LOGI("LibrePodsNativeHook initialized, sdp hook enabled: %d", enableSdpHook.load(std::memory_order_relaxed)); + hook_func = (HookFunType) entries->hook_func; + LOGI("LibrePodsNativeHook initialized, sdp hook enabled: %d", + enableSdpHook.load(std::memory_order_relaxed)); return on_library_loaded; } -extern "C" -JNIEXPORT void JNICALL -Java_me_kavishdevar_librepods_utils_NativeBridge_setSdpHook( - JNIEnv*, jobject thiz, jboolean enable) { +extern "C" JNIEXPORT void JNICALL +Java_me_kavishdevar_librepods_utils_NativeBridge_setSdpHook(JNIEnv *, jobject thiz, + jboolean enable) { LOGI("setSdpHook called with enable: %d", enable); enableSdpHook.store(enable, std::memory_order_relaxed);