mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-05-02 10:59:19 +00:00
android: add logs in xposed module
This commit is contained in:
@@ -46,12 +46,12 @@ static tBTA_STATUS (*original_BTA_DmSetLocalDiRecord)(
|
|||||||
static std::atomic<bool> enableSdpHook(false);
|
static std::atomic<bool> 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("l2c_fcr_chk_chan_modes called");
|
LOGI("fake_l2c_fcr_chk_chan_modes called");
|
||||||
uint8_t orig = 0;
|
uint8_t orig = 0;
|
||||||
if (original_l2c_fcr_chk_chan_modes)
|
if (original_l2c_fcr_chk_chan_modes)
|
||||||
orig = original_l2c_fcr_chk_chan_modes(p_ccb);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,21 +59,19 @@ tBTA_STATUS fake_BTA_DmSetLocalDiRecord(
|
|||||||
tSDP_DI_RECORD* p_device_info,
|
tSDP_DI_RECORD* p_device_info,
|
||||||
uint32_t* p_handle) {
|
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);
|
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) {
|
if (p_device_info) {
|
||||||
p_device_info->vendor = 0x004C;
|
p_device_info->vendor = 0x004C;
|
||||||
p_device_info->vendor_id_source = 0x0001;
|
p_device_info->vendor_id_source = 0x0001;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (original_BTA_DmSetLocalDiRecord)
|
LOGI("fake_BTA_DmSetLocalDiRecord: returning status %d", original_BTA_DmSetLocalDiRecord ? original_BTA_DmSetLocalDiRecord(p_device_info, p_handle) : BTA_FAILURE);
|
||||||
return original_BTA_DmSetLocalDiRecord(p_device_info, p_handle);
|
return original_BTA_DmSetLocalDiRecord ? original_BTA_DmSetLocalDiRecord(p_device_info, p_handle) : BTA_FAILURE;
|
||||||
|
|
||||||
return BTA_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool decompressXZ(
|
static bool decompressXZ(
|
||||||
@@ -81,13 +79,19 @@ static bool decompressXZ(
|
|||||||
size_t input_size,
|
size_t input_size,
|
||||||
std::vector<uint8_t>& output) {
|
std::vector<uint8_t>& output) {
|
||||||
|
|
||||||
|
LOGI("decompressXZ called with input_size: %zu", input_size);
|
||||||
|
|
||||||
xz_crc32_init();
|
xz_crc32_init();
|
||||||
#ifdef XZ_USE_CRC64
|
#ifdef XZ_USE_CRC64
|
||||||
xz_crc64_init();
|
xz_crc64_init();
|
||||||
#endif
|
#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) return false;
|
if (!dec) {
|
||||||
|
LOGE("decompressXZ: xz_dec_init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOGI("decompressXZ: xz_dec_init succeeded");
|
||||||
|
|
||||||
struct xz_buf buf{};
|
struct xz_buf buf{};
|
||||||
buf.in = input;
|
buf.in = input;
|
||||||
@@ -100,19 +104,25 @@ static bool decompressXZ(
|
|||||||
buf.out_pos = 0;
|
buf.out_pos = 0;
|
||||||
buf.out_size = output.size();
|
buf.out_size = output.size();
|
||||||
|
|
||||||
|
LOGI("decompressXZ: entering decompression loop");
|
||||||
while (true) {
|
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);
|
enum xz_ret ret = xz_dec_run(dec, &buf);
|
||||||
|
|
||||||
|
LOGI("decompressXZ: xz_dec_run returned %d", ret);
|
||||||
|
|
||||||
if (ret == XZ_STREAM_END)
|
if (ret == XZ_STREAM_END)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (ret != XZ_OK) {
|
if (ret != XZ_OK) {
|
||||||
|
LOGE("decompressXZ: xz_dec_run error");
|
||||||
xz_dec_end(dec);
|
xz_dec_end(dec);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf.out_pos == buf.out_size) {
|
if (buf.out_pos == buf.out_size) {
|
||||||
size_t old = output.size();
|
size_t old = output.size();
|
||||||
|
LOGI("decompressXZ: resizing output to %zu", old * 2);
|
||||||
output.resize(old * 2);
|
output.resize(old * 2);
|
||||||
buf.out = output.data();
|
buf.out = output.data();
|
||||||
buf.out_size = output.size();
|
buf.out_size = output.size();
|
||||||
@@ -121,21 +131,30 @@ static bool decompressXZ(
|
|||||||
|
|
||||||
output.resize(buf.out_pos);
|
output.resize(buf.out_pos);
|
||||||
xz_dec_end(dec);
|
xz_dec_end(dec);
|
||||||
|
LOGI("decompressXZ: decompression successful, output size: %zu", output.size());
|
||||||
return true;
|
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) return false;
|
if (!fp) {
|
||||||
|
LOGE("getLibraryPath: fopen failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
char line[1024];
|
char line[1024];
|
||||||
|
|
||||||
|
LOGI("getLibraryPath: scanning /proc/self/maps");
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
if (strstr(line, name)) {
|
if (strstr(line, name)) {
|
||||||
|
LOGI("getLibraryPath: found line containing %s", name);
|
||||||
char* path = strchr(line, '/');
|
char* path = strchr(line, '/');
|
||||||
if (path) {
|
if (path) {
|
||||||
out = path;
|
out = path;
|
||||||
out.erase(out.find('\n'));
|
out.erase(out.find('\n'));
|
||||||
|
LOGI("getLibraryPath: path found: %s", out.c_str());
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -143,24 +162,33 @@ static bool getLibraryPath(const char* name, std::string& out) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
LOGI("getLibraryPath: failed to find path for %s", name);
|
||||||
return false;
|
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) return 0;
|
if (!fp) {
|
||||||
|
LOGE("getModuleBase: fopen failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
char line[1024];
|
char line[1024];
|
||||||
uintptr_t base = 0;
|
uintptr_t base = 0;
|
||||||
|
|
||||||
|
LOGI("getModuleBase: scanning /proc/self/maps");
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
if (strstr(line, name)) {
|
if (strstr(line, name)) {
|
||||||
base = strtoull(line, nullptr, 16);
|
base = strtoull(line, nullptr, 16);
|
||||||
|
LOGI("getModuleBase: found base at 0x%lx", base);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
LOGI("getModuleBase: failed to find base for %s", name);
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +196,8 @@ static uint64_t findSymbolOffset(
|
|||||||
const std::vector<uint8_t>& elf,
|
const std::vector<uint8_t>& elf,
|
||||||
const char* symbol_substring) {
|
const char* symbol_substring) {
|
||||||
|
|
||||||
|
LOGI("findSymbolOffset called with symbol_substring: %s", symbol_substring);
|
||||||
|
|
||||||
auto* eh = reinterpret_cast<const Elf64_Ehdr*>(elf.data());
|
auto* eh = reinterpret_cast<const Elf64_Ehdr*>(elf.data());
|
||||||
auto* shdr = reinterpret_cast<const Elf64_Shdr*>(
|
auto* shdr = reinterpret_cast<const Elf64_Shdr*>(
|
||||||
elf.data() + eh->e_shoff);
|
elf.data() + eh->e_shoff);
|
||||||
@@ -179,6 +209,7 @@ static uint64_t findSymbolOffset(
|
|||||||
const Elf64_Shdr* symtab = nullptr;
|
const Elf64_Shdr* symtab = nullptr;
|
||||||
const Elf64_Shdr* strtab = nullptr;
|
const Elf64_Shdr* strtab = nullptr;
|
||||||
|
|
||||||
|
LOGI("findSymbolOffset: parsing ELF sections");
|
||||||
for (int i = 0; i < eh->e_shnum; ++i) {
|
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"))
|
if (!strcmp(secname, ".symtab"))
|
||||||
@@ -187,8 +218,11 @@ static uint64_t findSymbolOffset(
|
|||||||
strtab = &shdr[i];
|
strtab = &shdr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!symtab || !strtab)
|
if (!symtab || !strtab) {
|
||||||
|
LOGE("findSymbolOffset: symtab or strtab not found");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
LOGI("findSymbolOffset: found symtab and strtab");
|
||||||
|
|
||||||
auto* symbols = reinterpret_cast<const Elf64_Sym*>(
|
auto* symbols = reinterpret_cast<const Elf64_Sym*>(
|
||||||
elf.data() + symtab->sh_offset);
|
elf.data() + symtab->sh_offset);
|
||||||
@@ -199,24 +233,25 @@ static uint64_t findSymbolOffset(
|
|||||||
|
|
||||||
size_t count = symtab->sh_size / sizeof(Elf64_Sym);
|
size_t count = symtab->sh_size / sizeof(Elf64_Sym);
|
||||||
|
|
||||||
|
LOGI("findSymbolOffset: scanning %zu symbols", count);
|
||||||
for (size_t i = 0; i < count; ++i) {
|
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) &&
|
if (strstr(name, symbol_substring) &&
|
||||||
ELF64_ST_TYPE(symbols[i].st_info) == STT_FUNC) {
|
ELF64_ST_TYPE(symbols[i].st_info) == STT_FUNC) {
|
||||||
|
|
||||||
LOGI("Resolved %s at 0x%lx",
|
LOGI("findSymbolOffset: matched symbol %s at 0x%lx", name, (unsigned long)symbols[i].st_value);
|
||||||
name,
|
|
||||||
(unsigned long)symbols[i].st_value);
|
|
||||||
|
|
||||||
return symbols[i].st_value;
|
return symbols[i].st_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGI("findSymbolOffset: no match found for %s", symbol_substring);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hookLibrary(const char* libname) {
|
static bool hookLibrary(const char* libname) {
|
||||||
|
LOGI("hookLibrary called with libname: %s", libname);
|
||||||
|
|
||||||
if (!hook_func) {
|
if (!hook_func) {
|
||||||
LOGE("hook_func not initialized");
|
LOGE("hook_func not initialized");
|
||||||
@@ -228,15 +263,21 @@ static bool hookLibrary(const char* libname) {
|
|||||||
LOGE("Failed to locate %s", libname);
|
LOGE("Failed to locate %s", libname);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
LOGI("hookLibrary: located path: %s", path.c_str());
|
||||||
|
|
||||||
int fd = open(path.c_str(), O_RDONLY);
|
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{};
|
struct stat st{};
|
||||||
if (fstat(fd, &st) != 0) {
|
if (fstat(fd, &st) != 0) {
|
||||||
|
LOGE("hookLibrary: fstat failed");
|
||||||
close(fd);
|
close(fd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
LOGI("hookLibrary: opened file, size: %lld", (long long)st.st_size);
|
||||||
|
|
||||||
std::vector<uint8_t> file(st.st_size);
|
std::vector<uint8_t> file(st.st_size);
|
||||||
read(fd, file.data(), st.st_size);
|
read(fd, file.data(), st.st_size);
|
||||||
@@ -250,9 +291,11 @@ static bool hookLibrary(const char* libname) {
|
|||||||
reinterpret_cast<const char*>(
|
reinterpret_cast<const char*>(
|
||||||
file.data() + shdr[eh->e_shstrndx].sh_offset);
|
file.data() + shdr[eh->e_shstrndx].sh_offset);
|
||||||
|
|
||||||
|
LOGI("hookLibrary: parsing ELF header and sections");
|
||||||
for (int i = 0; i < eh->e_shnum; ++i) {
|
for (int i = 0; i < eh->e_shnum; ++i) {
|
||||||
|
|
||||||
if (!strcmp(shstr + shdr[i].sh_name, ".gnu_debugdata")) {
|
if (!strcmp(shstr + shdr[i].sh_name, ".gnu_debugdata")) {
|
||||||
|
LOGI("hookLibrary: found .gnu_debugdata section");
|
||||||
|
|
||||||
std::vector<uint8_t> compressed(
|
std::vector<uint8_t> compressed(
|
||||||
file.begin() + shdr[i].sh_offset,
|
file.begin() + shdr[i].sh_offset,
|
||||||
@@ -263,11 +306,18 @@ static bool hookLibrary(const char* libname) {
|
|||||||
if (!decompressXZ(
|
if (!decompressXZ(
|
||||||
compressed.data(),
|
compressed.data(),
|
||||||
compressed.size(),
|
compressed.size(),
|
||||||
decompressed))
|
decompressed)) {
|
||||||
|
LOGE("hookLibrary: decompressXZ failed");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
LOGI("hookLibrary: decompressed debug data, size: %zu", decompressed.size());
|
||||||
|
|
||||||
uintptr_t base = getModuleBase(libname);
|
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 =
|
uint64_t chk_offset =
|
||||||
findSymbolOffset(decompressed,
|
findSymbolOffset(decompressed,
|
||||||
@@ -277,6 +327,8 @@ static bool hookLibrary(const char* libname) {
|
|||||||
findSymbolOffset(decompressed,
|
findSymbolOffset(decompressed,
|
||||||
"BTA_DmSetLocalDiRecord");
|
"BTA_DmSetLocalDiRecord");
|
||||||
|
|
||||||
|
LOGI("hookLibrary: chk_offset: 0x%lx, sdp_offset: 0x%lx", chk_offset, sdp_offset);
|
||||||
|
|
||||||
if (chk_offset) {
|
if (chk_offset) {
|
||||||
void* target =
|
void* target =
|
||||||
reinterpret_cast<void*>(base + chk_offset);
|
reinterpret_cast<void*>(base + chk_offset);
|
||||||
@@ -285,7 +337,7 @@ static bool hookLibrary(const char* libname) {
|
|||||||
(void*)fake_l2c_fcr_chk_chan_modes,
|
(void*)fake_l2c_fcr_chk_chan_modes,
|
||||||
(void**)&original_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) {
|
if (sdp_offset) {
|
||||||
@@ -296,17 +348,19 @@ static bool hookLibrary(const char* libname) {
|
|||||||
(void*)fake_BTA_DmSetLocalDiRecord,
|
(void*)fake_BTA_DmSetLocalDiRecord,
|
||||||
(void**)&original_BTA_DmSetLocalDiRecord);
|
(void**)&original_BTA_DmSetLocalDiRecord);
|
||||||
|
|
||||||
LOGI("Hooked BTA_DmSetLocalDiRecord");
|
LOGI("hookLibrary: hooked BTA_DmSetLocalDiRecord");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOGI("hookLibrary: failed for %s", libname);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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")) {
|
if (strstr(name, "libbluetooth_jni.so")) {
|
||||||
LOGI("Bluetooth JNI loaded");
|
LOGI("Bluetooth JNI loaded");
|
||||||
@@ -323,6 +377,7 @@ extern "C"
|
|||||||
[[gnu::visibility("default")]]
|
[[gnu::visibility("default")]]
|
||||||
[[gnu::used]]
|
[[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;
|
hook_func = (HookFunType)entries->hook_func;
|
||||||
LOGI("LibrePodsNativeHook initialized, sdp hook enabled: %d", enableSdpHook.load(std::memory_order_relaxed));
|
LOGI("LibrePodsNativeHook initialized, sdp hook enabled: %d", enableSdpHook.load(std::memory_order_relaxed));
|
||||||
return on_library_loaded;
|
return on_library_loaded;
|
||||||
@@ -332,6 +387,7 @@ extern "C"
|
|||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_me_kavishdevar_librepods_utils_NativeBridge_setSdpHook(
|
Java_me_kavishdevar_librepods_utils_NativeBridge_setSdpHook(
|
||||||
JNIEnv*, jobject thiz, jboolean enable) {
|
JNIEnv*, jobject thiz, jboolean enable) {
|
||||||
|
LOGI("setSdpHook called with enable: %d", enable);
|
||||||
enableSdpHook.store(enable, std::memory_order_relaxed);
|
enableSdpHook.store(enable, std::memory_order_relaxed);
|
||||||
|
|
||||||
LOGI("sdp hook enabled: %d", enable);
|
LOGI("sdp hook enabled: %d", enable);
|
||||||
|
|||||||
Reference in New Issue
Block a user