From fce90cf88a1bb798afe660b20b5e5c92b791039b Mon Sep 17 00:00:00 2001 From: Kavish Devar Date: Thu, 23 Apr 2026 00:46:06 +0530 Subject: [PATCH] android: add logs in xposed module --- android/app/src/xposed/cpp/l2c_fcr_hook.cpp | 96 ++++++++++++++++----- 1 file changed, 76 insertions(+), 20 deletions(-) diff --git a/android/app/src/xposed/cpp/l2c_fcr_hook.cpp b/android/app/src/xposed/cpp/l2c_fcr_hook.cpp index e663666..4910dfd 100644 --- a/android/app/src/xposed/cpp/l2c_fcr_hook.cpp +++ b/android/app/src/xposed/cpp/l2c_fcr_hook.cpp @@ -46,12 +46,12 @@ static tBTA_STATUS (*original_BTA_DmSetLocalDiRecord)( static std::atomic enableSdpHook(false); uint8_t fake_l2c_fcr_chk_chan_modes(void* p_ccb) { - LOGI("l2c_fcr_chk_chan_modes called"); + LOGI("fake_l2c_fcr_chk_chan_modes called"); uint8_t orig = 0; if (original_l2c_fcr_chk_chan_modes) orig = original_l2c_fcr_chk_chan_modes(p_ccb); - LOGI("Original returned %d, forcing 1", orig); + LOGI("fake_l2c_fcr_chk_chan_modes: orig = %d, returning 1", orig); return 1; } @@ -59,21 +59,19 @@ tBTA_STATUS fake_BTA_DmSetLocalDiRecord( tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) { - LOGI("BTA_DmSetLocalDiRecord called"); + LOGI("fake_BTA_DmSetLocalDiRecord called"); if (original_BTA_DmSetLocalDiRecord && enableSdpHook.load(std::memory_order_relaxed)) original_BTA_DmSetLocalDiRecord(p_device_info, p_handle); - LOGI("BTA_DmSetLocalDiRecord changing vendor id and source"); + LOGI("fake_BTA_DmSetLocalDiRecord: modifying vendor to 0x004C, vendor_id_source to 0x0001"); if (p_device_info) { p_device_info->vendor = 0x004C; p_device_info->vendor_id_source = 0x0001; } - if (original_BTA_DmSetLocalDiRecord) - return original_BTA_DmSetLocalDiRecord(p_device_info, p_handle); - - return 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( @@ -81,13 +79,19 @@ static bool decompressXZ( size_t input_size, std::vector& output) { + LOGI("decompressXZ called with input_size: %zu", input_size); + xz_crc32_init(); #ifdef XZ_USE_CRC64 xz_crc64_init(); #endif struct xz_dec* dec = xz_dec_init(XZ_DYNALLOC, 64U << 20); - if (!dec) return false; + if (!dec) { + LOGE("decompressXZ: xz_dec_init failed"); + return false; + } + LOGI("decompressXZ: xz_dec_init succeeded"); struct xz_buf buf{}; buf.in = input; @@ -100,19 +104,25 @@ static bool decompressXZ( buf.out_pos = 0; buf.out_size = output.size(); + 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); enum xz_ret ret = xz_dec_run(dec, &buf); + LOGI("decompressXZ: xz_dec_run returned %d", ret); + if (ret == XZ_STREAM_END) break; if (ret != XZ_OK) { + LOGE("decompressXZ: xz_dec_run error"); xz_dec_end(dec); return false; } if (buf.out_pos == buf.out_size) { size_t old = output.size(); + LOGI("decompressXZ: resizing output to %zu", old * 2); output.resize(old * 2); buf.out = output.data(); buf.out_size = output.size(); @@ -121,21 +131,30 @@ static bool decompressXZ( output.resize(buf.out_pos); xz_dec_end(dec); + LOGI("decompressXZ: decompression successful, output size: %zu", output.size()); return true; } static bool getLibraryPath(const char* name, std::string& out) { + LOGI("getLibraryPath called with name: %s", name); + FILE* fp = fopen("/proc/self/maps", "r"); - if (!fp) return false; + if (!fp) { + LOGE("getLibraryPath: fopen failed"); + return false; + } char line[1024]; + LOGI("getLibraryPath: scanning /proc/self/maps"); while (fgets(line, sizeof(line), fp)) { if (strstr(line, name)) { + LOGI("getLibraryPath: found line containing %s", name); char* path = strchr(line, '/'); if (path) { out = path; out.erase(out.find('\n')); + LOGI("getLibraryPath: path found: %s", out.c_str()); fclose(fp); return true; } @@ -143,24 +162,33 @@ static bool getLibraryPath(const char* name, std::string& out) { } fclose(fp); + LOGI("getLibraryPath: failed to find path for %s", name); return false; } static uintptr_t getModuleBase(const char* name) { + LOGI("getModuleBase called with name: %s", name); + FILE* fp = fopen("/proc/self/maps", "r"); - if (!fp) return 0; + if (!fp) { + LOGE("getModuleBase: fopen failed"); + return 0; + } char line[1024]; uintptr_t base = 0; + LOGI("getModuleBase: scanning /proc/self/maps"); while (fgets(line, sizeof(line), fp)) { if (strstr(line, name)) { base = strtoull(line, nullptr, 16); + LOGI("getModuleBase: found base at 0x%lx", base); break; } } fclose(fp); + LOGI("getModuleBase: failed to find base for %s", name); return base; } @@ -168,6 +196,8 @@ 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( elf.data() + eh->e_shoff); @@ -179,6 +209,7 @@ static uint64_t findSymbolOffset( 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; if (!strcmp(secname, ".symtab")) @@ -187,8 +218,11 @@ static uint64_t findSymbolOffset( strtab = &shdr[i]; } - if (!symtab || !strtab) + if (!symtab || !strtab) { + LOGE("findSymbolOffset: symtab or strtab not found"); return 0; + } + LOGI("findSymbolOffset: found symtab and strtab"); auto* symbols = reinterpret_cast( elf.data() + symtab->sh_offset); @@ -199,24 +233,25 @@ static uint64_t findSymbolOffset( 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; if (strstr(name, symbol_substring) && ELF64_ST_TYPE(symbols[i].st_info) == STT_FUNC) { - LOGI("Resolved %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; } } + LOGI("findSymbolOffset: no match found for %s", symbol_substring); return 0; } static bool hookLibrary(const char* libname) { + LOGI("hookLibrary called with libname: %s", libname); if (!hook_func) { LOGE("hook_func not initialized"); @@ -228,15 +263,21 @@ static bool hookLibrary(const char* libname) { LOGE("Failed to locate %s", libname); return false; } + LOGI("hookLibrary: located path: %s", path.c_str()); int fd = open(path.c_str(), O_RDONLY); - if (fd < 0) return false; + if (fd < 0) { + LOGE("hookLibrary: open failed"); + return false; + } struct stat st{}; if (fstat(fd, &st) != 0) { + LOGE("hookLibrary: fstat failed"); close(fd); return false; } + LOGI("hookLibrary: opened file, size: %lld", (long long)st.st_size); std::vector file(st.st_size); read(fd, file.data(), st.st_size); @@ -250,9 +291,11 @@ static bool hookLibrary(const char* libname) { reinterpret_cast( file.data() + shdr[eh->e_shstrndx].sh_offset); + LOGI("hookLibrary: parsing ELF header and sections"); for (int i = 0; i < eh->e_shnum; ++i) { if (!strcmp(shstr + shdr[i].sh_name, ".gnu_debugdata")) { + LOGI("hookLibrary: found .gnu_debugdata section"); std::vector compressed( file.begin() + shdr[i].sh_offset, @@ -263,11 +306,18 @@ static bool hookLibrary(const char* libname) { if (!decompressXZ( compressed.data(), compressed.size(), - decompressed)) + decompressed)) { + LOGE("hookLibrary: decompressXZ failed"); return false; + } + LOGI("hookLibrary: decompressed debug data, size: %zu", decompressed.size()); uintptr_t base = getModuleBase(libname); - if (!base) return false; + if (!base) { + LOGE("hookLibrary: getModuleBase failed"); + return false; + } + LOGI("hookLibrary: module base: 0x%lx", base); uint64_t chk_offset = findSymbolOffset(decompressed, @@ -277,6 +327,8 @@ static bool hookLibrary(const char* libname) { findSymbolOffset(decompressed, "BTA_DmSetLocalDiRecord"); + LOGI("hookLibrary: chk_offset: 0x%lx, sdp_offset: 0x%lx", chk_offset, sdp_offset); + if (chk_offset) { void* target = reinterpret_cast(base + chk_offset); @@ -285,7 +337,7 @@ static bool hookLibrary(const char* libname) { (void*)fake_l2c_fcr_chk_chan_modes, (void**)&original_l2c_fcr_chk_chan_modes); - LOGI("Hooked l2c_fcr_chk_chan_modes"); + LOGI("hookLibrary: hooked l2c_fcr_chk_chan_modes"); } if (sdp_offset) { @@ -296,17 +348,19 @@ static bool hookLibrary(const char* libname) { (void*)fake_BTA_DmSetLocalDiRecord, (void**)&original_BTA_DmSetLocalDiRecord); - LOGI("Hooked BTA_DmSetLocalDiRecord"); + LOGI("hookLibrary: hooked BTA_DmSetLocalDiRecord"); } return true; } } + LOGI("hookLibrary: failed for %s", libname); return false; } static void on_library_loaded(const char* name, void*) { + LOGI("on_library_loaded called with name: %s", name); if (strstr(name, "libbluetooth_jni.so")) { LOGI("Bluetooth JNI loaded"); @@ -323,6 +377,7 @@ extern "C" [[gnu::visibility("default")]] [[gnu::used]] 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)); return on_library_loaded; @@ -332,6 +387,7 @@ 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); LOGI("sdp hook enabled: %d", enable);