|
24 | 24 | #include <string> |
25 | 25 | #include <sys/system_properties.h> |
26 | 26 | #include "l2c_fcr_hook.h" |
| 27 | +#include <cerrno> |
| 28 | +#include <cstdlib> |
27 | 29 |
|
28 | 30 | #define LOG_TAG "AirPodsHook" |
29 | 31 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) |
@@ -126,6 +128,9 @@ static void (*original_l2cu_process_our_cfg_req)(tL2C_CCB* p_ccb, tL2CAP_CFG_INF |
126 | 128 | static void (*original_l2c_csm_config)(tL2C_CCB* p_ccb, uint8_t event, void* p_data) = nullptr; |
127 | 129 | static void (*original_l2cu_send_peer_info_req)(tL2C_LCB* p_lcb, uint16_t info_type) = nullptr; |
128 | 130 |
|
| 131 | +// Add original pointer for BTA_DmSetLocalDiRecord |
| 132 | +static tBTA_STATUS (*original_BTA_DmSetLocalDiRecord)(tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) = nullptr; |
| 133 | + |
129 | 134 | uint8_t fake_l2c_fcr_chk_chan_modes(void* p_ccb) { |
130 | 135 | LOGI("l2c_fcr_chk_chan_modes hooked, returning true."); |
131 | 136 | return 1; |
@@ -156,6 +161,53 @@ void fake_l2cu_send_peer_info_req(tL2C_LCB* p_lcb, uint16_t info_type) { |
156 | 161 | return; |
157 | 162 | } |
158 | 163 |
|
| 164 | +// New loader for SDP hook offset (persist.librepods.sdp_offset) |
| 165 | +uintptr_t loadSdpOffset() { |
| 166 | + const char* property_name = "persist.librepods.sdp_offset"; |
| 167 | + char value[PROP_VALUE_MAX] = {0}; |
| 168 | + |
| 169 | + int len = __system_property_get(property_name, value); |
| 170 | + if (len > 0) { |
| 171 | + LOGI("Read sdp offset from property: %s", value); |
| 172 | + uintptr_t offset; |
| 173 | + char* endptr = nullptr; |
| 174 | + |
| 175 | + const char* parse_start = value; |
| 176 | + if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) { |
| 177 | + parse_start = value + 2; |
| 178 | + } |
| 179 | + |
| 180 | + errno = 0; |
| 181 | + offset = strtoul(parse_start, &endptr, 16); |
| 182 | + |
| 183 | + if (errno == 0 && endptr != parse_start && *endptr == '\0' && offset > 0) { |
| 184 | + LOGI("Parsed sdp offset: 0x%x", offset); |
| 185 | + return offset; |
| 186 | + } |
| 187 | + |
| 188 | + LOGE("Failed to parse sdp offset from property value: %s", value); |
| 189 | + } |
| 190 | + |
| 191 | + LOGI("No sdp offset property present - skipping SDP hook"); |
| 192 | + return 0; |
| 193 | +} |
| 194 | + |
| 195 | +// Fake BTA_DmSetLocalDiRecord: set vendor/vendor_id_source then call original |
| 196 | +tBTA_STATUS fake_BTA_DmSetLocalDiRecord(tSDP_DI_RECORD* p_device_info, uint32_t* p_handle) { |
| 197 | + LOGI("BTA_DmSetLocalDiRecord hooked - forcing vendor fields"); |
| 198 | + if (p_device_info) { |
| 199 | + p_device_info->vendor = 0x004C; |
| 200 | + p_device_info->vendor_id_source = 0x0001; |
| 201 | + } |
| 202 | + LOGI("Set vendor=0x%04x, vendor_id_source=0x%04x", p_device_info->vendor, p_device_info->vendor_id_source); |
| 203 | + if (original_BTA_DmSetLocalDiRecord) { |
| 204 | + return original_BTA_DmSetLocalDiRecord(p_device_info, p_handle); |
| 205 | + } |
| 206 | + |
| 207 | + LOGE("Original BTA_DmSetLocalDiRecord not available"); |
| 208 | + return BTA_FAILURE; |
| 209 | +} |
| 210 | + |
159 | 211 | uintptr_t loadHookOffset([[maybe_unused]] const char* package_name) { |
160 | 212 | const char* property_name = "persist.librepods.hook_offset"; |
161 | 213 | char value[PROP_VALUE_MAX] = {0}; |
@@ -320,6 +372,7 @@ bool findAndHookFunction(const char *library_name) { |
320 | 372 | uintptr_t l2cu_process_our_cfg_req_offset = loadL2cuProcessCfgReqOffset(); |
321 | 373 | uintptr_t l2c_csm_config_offset = loadL2cCsmConfigOffset(); |
322 | 374 | uintptr_t l2cu_send_peer_info_req_offset = loadL2cuSendPeerInfoReqOffset(); |
| 375 | + uintptr_t sdp_offset = loadSdpOffset(); |
323 | 376 |
|
324 | 377 | bool success = false; |
325 | 378 |
|
@@ -392,6 +445,21 @@ bool findAndHookFunction(const char *library_name) { |
392 | 445 | LOGI("Skipping l2cu_send_peer_info_req hook as offset is not available"); |
393 | 446 | } |
394 | 447 |
|
| 448 | + if (sdp_offset > 0) { |
| 449 | + void* target = reinterpret_cast<void*>(base_addr + sdp_offset); |
| 450 | + LOGI("Hooking BTA_DmSetLocalDiRecord at offset: 0x%x, base: %p, target: %p", |
| 451 | + sdp_offset, (void*)base_addr, target); |
| 452 | + |
| 453 | + int result = hook_func(target, (void*)fake_BTA_DmSetLocalDiRecord, (void**)&original_BTA_DmSetLocalDiRecord); |
| 454 | + if (result != 0) { |
| 455 | + LOGE("Failed to hook BTA_DmSetLocalDiRecord, error: %d", result); |
| 456 | + } else { |
| 457 | + LOGI("Successfully hooked BTA_DmSetLocalDiRecord (SDP)"); |
| 458 | + } |
| 459 | + } else { |
| 460 | + LOGI("Skipping BTA_DmSetLocalDiRecord hook as sdp offset is not available"); |
| 461 | + } |
| 462 | + |
395 | 463 | return success; |
396 | 464 | } |
397 | 465 |
|
|
0 commit comments