diff --git a/.gitignore b/.gitignore index 655d315..0510078 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +btl2capfix.zip + .vscode testing.py .DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..0fa26ba --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +## btl2capfix v0.0.3 +- ([#34](https://github.com/kavishdevar/aln/pull/34)) @devnoname120 Add on-device libbluetooth patcher using a Magisk/KernelSU module (arm64-only) + +_[See more here](https://github.com/kavishdevar/aln/releases)_ diff --git a/build-magisk-module.sh b/build-magisk-module.sh new file mode 100755 index 0000000..79d09bb --- /dev/null +++ b/build-magisk-module.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +set -eux + +cd root-module +rm -f ../btl2capfix.zip + +# COPYFILE_DISABLE env is a macOS fix to avoid parasitic files in ZIPs: https://superuser.com/a/260264 +export COPYFILE_DISABLE=1 + +zip -r ../btl2capfix.zip . -x \*.DS_Store \*__MACOSX \*DEBIAN ._\* .gitignore diff --git a/root-module/busybox/busybox-arm64 b/root-module/busybox/busybox-arm64 new file mode 100644 index 0000000..9a8246d Binary files /dev/null and b/root-module/busybox/busybox-arm64 differ diff --git a/root-module/busybox/xz b/root-module/busybox/xz new file mode 100644 index 0000000..d414c71 --- /dev/null +++ b/root-module/busybox/xz @@ -0,0 +1,3 @@ +#!/bin/sh + +exec /data/local/tmp/aln_unzip/busybox/busybox-arm64 xz "$@" diff --git a/root-module/customize.sh b/root-module/customize.sh index 0111076..cabe76c 100644 --- a/root-module/customize.sh +++ b/root-module/customize.sh @@ -1,59 +1,148 @@ #!/system/bin/sh -API_URL="https://aln.kavishdevar.me/api" -TEMP_DIR="$TMPDIR/aln_patch" -PATCHED_FILE_NAME="" +# Note: these two exec redirs are not strictly POSIX-compliant, so they can be commented out if we notice that it shows a syntax error in some environments (unlikely to happen) + +# Redirect stdout to ui_print otherwise it's not shown +exec 1> >(while read -r line; do ui_print "[O] $line"; done) +# Redirect stderr to ui_print otherwise it's not shown + ignore useless radare2 warning that clutters the logs +exec 2> >(while read -r line; do echo "$line" | grep -qv "Cannot determine entrypoint, using" && ui_print "[E] $line"; done) + +TEMP_DIR="/data/local/tmp/aln_patch" + +# Note: this dir cannot be changed without recompiling radare2 because this prefix are hardcoded inside the radare2 binaries: /data/local/tmp/aln_unzip/org.radare.radare2installer/radare2/ +UNZIP_DIR="/data/local/tmp/aln_unzip" SOURCE_FILE="" LIBRARY_NAME="" APEX_DIR=false -mkdir -p "$TEMP_DIR" +# Clean things up if the script crashes or exits +trap 'rm -rf "$TEMP_DIR" "$UNZIP_DIR"' EXIT INT TERM -CURL_CMD=$(command -v curl || echo "$MODPATH/system/bin/curl") -export LD_LIBRARY_PATH="$MODPATH/system/lib64:$LD_LIBRARY_PATH" +# https://github.com/Magisk-Modules-Repo/busybox-ndk/blob/master/busybox-arm64 +BUSYBOX="$UNZIP_DIR/busybox/busybox-arm64" +XZ="$UNZIP_DIR/busybox/xz" -if [ -f "/apex/com.android.btservices/lib64/libbluetooth_jni.so" ]; then - SOURCE_FILE="/apex/com.android.btservices/lib64/libbluetooth_jni.so" - LIBRARY_NAME="libbluetooth_jni.so" - PATCHED_FILE_NAME="libbluetooth_jni_patched.so" - ui_print "Detected library: libbluetooth_jni.so in /apex/com.android.btservices/lib64/" -elif [ -f "/system/lib64/libbluetooth_jni.so" ]; then - SOURCE_FILE="/system/lib64/libbluetooth_jni.so" - LIBRARY_NAME="libbluetooth_jni.so" - PATCHED_FILE_NAME="libbluetooth_jni_patched.so" - ui_print "Detected library: libbluetooth_jni.so in /system/lib64/" -elif [ -f "/system/lib64/libbluetooth_qti.so" ]; then - SOURCE_FILE="/system/lib64/libbluetooth_qti.so" - LIBRARY_NAME="libbluetooth_qti.so" - PATCHED_FILE_NAME="libbluetooth_qti_patched.so" - ui_print "Detected QTI library: libbluetooth_qti.so in /system/lib64/" -elif [ -f "/system_ext/lib64/libbluetooth_qti.so" ]; then - SOURCE_FILE="/system_ext/lib64/libbluetooth_qti.so" - LIBRARY_NAME="libbluetooth_qti.so" - PATCHED_FILE_NAME="libbluetooth_qti_patched.so" - ui_print "Detected QTI library: libbluetooth_qti.so in /system_ext/lib64/" +rm -rf "$TEMP_DIR" "$UNZIP_DIR" +mkdir -p "$TEMP_DIR" "$UNZIP_DIR" + +# Manually extract the $ZIPFILE to a temporary directory +ui_print "Extracting module files..." +unzip -d "$UNZIP_DIR" -oq "$ZIPFILE" || { + ui_print "Error: Failed to extract module files." + abort "Failed to unzip $ZIPFILE" +} + +set_perm "$BUSYBOX" 0 0 755 +set_perm "$XZ" 0 0 755 + +# The bundled radare2 is a custom build that works without Termux: https://github.com/devnoname120/radare2 +ui_print "Extracting radare2 to /data/local/tmp/aln_unzip..." +$BUSYBOX tar xzf "$UNZIP_DIR/radare2-5.9.9-android-aarch64.tar.gz" -C / || { + abort "Failed to extract "$UNZIP_DIR/radare2-5.9.9-android-aarch64.tar.gz"." +} + + +if [ "$(uname -m)" = "aarch64" ]; then + export LD_LIBRARY_PATH="$UNZIP_DIR/org.radare.radare2installer/radare2/lib:$LD_LIBRARY_PATH" + export PATH="$UNZIP_DIR/org.radare.radare2installer/radare2/bin:$PATH" + export PATH="$UNZIP_DIR/busybox:$PATH" + export RABIN2="$UNZIP_DIR/org.radare.radare2installer/radare2/bin/rabin2" + export RADARE2="$UNZIP_DIR/org.radare.radare2installer/radare2/bin/radare2" else - ui_print "No target library found. Exiting." - abort "No target library found." + abort "arm64 archicture required, arm32 not supported" fi -ui_print "Uploading $LIBRARY_NAME to the API for patching..." -ui_print "If you're concerned about privacy, review the source code of the API at https://github.com/kavishdevar/aln/blob/main/root-module-manual/server.py" -PATCHED_FILE_NAME="patched_$LIBRARY_NAME" +set_perm "$RABIN2" 0 0 755 +set_perm "$RADARE2" 0 0 755 -$CURL_CMD -s -X POST "$API_URL" \ - -F "file=@$SOURCE_FILE" \ - -F "library_name=$LIBRARY_NAME" \ - -o "$TEMP_DIR/$PATCHED_FILE_NAME" \ - -D "$TEMP_DIR/headers.txt" +if [ -f "$RABIN2" ]; then + ui_print "rabin2 binary is ready." +else + ui_print "Error: rabin2 binary not found." + abort "rabin2 binary not found." +fi -if [ -f "$TEMP_DIR/$PATCHED_FILE_NAME" ]; then - ui_print "Received patched file from the API." - ui_print "Installing patched file to the module's directory..." +if [ -f "$RADARE2" ]; then + ui_print "radare2 binary is ready." +else + ui_print "Error: radare2 binary not found." + abort "radare2 binary not found." +fi - if [[ "$SOURCE_FILE" == *"/system/lib64"* ]]; then +if [ -f "$BUSYBOX" ]; then + ui_print "busybox binary is ready." +else + ui_print "Error: busybox binary not found." + abort "busybox binary not found." +fi + +if [ -f "$XZ" ]; then + ui_print "xz shim is ready." +else + ui_print "Error: xz shim not found." + abort "xz shim not found." +fi + +for lib_path in \ + "/apex/com.android.btservices/lib64/libbluetooth_jni.so" \ + "/system/lib64/libbluetooth_jni.so" \ + "/system/lib64/libbluetooth_qti.so" \ + "/system_ext/lib64/libbluetooth_qti.so"; do + if [ -f "$lib_path" ]; then + SOURCE_FILE="$lib_path" + LIBRARY_NAME="$(basename "$lib_path")" + ui_print "Detected library: $SOURCE_FILE" + break + fi +done + +[ -z "$SOURCE_FILE" ] && { + ui_print "Error: No target library found." + abort "No target library found." +} + +ui_print "Calculating patch addresses for $SOURCE_FILE..." + +# export R2_LIBDIR="$UNZIP_DIR/radare2-android/libs/arm64-v8a" +# export R2_BINDIR="$UNZIP_DIR/radare2-android/bin/arm64-v8a" + +# $RADARE2 -H 1>&2 + +# ldd $RABIN2 1>&2 +# ldd $RADARE2 1>&2 + +symbols="$($RABIN2 -q -E "$SOURCE_FILE")" || abort "Failed to extract symbols from $SOURCE_FILE." + +get_symbol_address() { + symb_address=$(echo "$symbols" | grep "$1" | cut -d ' ' -f1 | tr -d '\n') + [ -n "$symb_address" ] || abort "Failed to obtain address for symbol $1" + echo "$symb_address" +} + +l2c_fcr_chk_chan_modes_address="$(get_symbol_address 'l2c_fcr_chk_chan_modes')" +ui_print " l2c_fcr_chk_chan_modes_address=$l2c_fcr_chk_chan_modes_address" + +l2cu_send_peer_info_req_address="$(get_symbol_address 'l2cu_send_peer_info_req')" +ui_print " l2cu_send_peer_info_req_address=$l2cu_send_peer_info_req_address" + + +cp "$SOURCE_FILE" "$TEMP_DIR" + +ui_print "Patching $LIBRARY_NAME..." + +apply_patch() { + $RADARE2 -q -e bin.cache=true -w -c "s $1; wx $2; wci" "$TEMP_DIR/$LIBRARY_NAME" || abort "Failed to apply $1 patch." +} + +apply_patch "$l2c_fcr_chk_chan_modes_address" "20008052c0035fd6" +apply_patch "$l2cu_send_peer_info_req_address" "c0035fd6" + +if [ -f "$TEMP_DIR/$LIBRARY_NAME" ]; then + ui_print "Installing patched file..." + + if echo "$SOURCE_FILE" | grep -q "/system/lib64"; then TARGET_DIR="$MODPATH/system/lib64" - elif [[ "$SOURCE_FILE" == *"/apex/"* ]]; then + elif echo "$SOURCE_FILE" | grep -q "/apex/"; then TARGET_DIR="$MODPATH/system/lib64" APEX_DIR=true else @@ -62,7 +151,7 @@ if [ -f "$TEMP_DIR/$PATCHED_FILE_NAME" ]; then mkdir -p "$TARGET_DIR" - cp "$TEMP_DIR/$PATCHED_FILE_NAME" "$TARGET_DIR/$LIBRARY_NAME" + cp "$TEMP_DIR/$LIBRARY_NAME" "$TARGET_DIR/$LIBRARY_NAME" set_perm "$TARGET_DIR/$LIBRARY_NAME" 0 0 644 ui_print "Patched file installed at $TARGET_DIR/$LIBRARY_NAME" @@ -72,10 +161,9 @@ if [ -f "$TEMP_DIR/$PATCHED_FILE_NAME" ]; then MOD_APEX_LIB_DIR="$MODPATH/apex/com.android.btservices/lib64" WORK_DIR="$MODPATH/apex/com.android.btservices/work" - mkdir -p "$MOD_APEX_LIB_DIR" - mkdir -p "$WORK_DIR" + mkdir -p "$MOD_APEX_LIB_DIR" "$WORK_DIR" - cp "$TEMP_DIR/$PATCHED_FILE_NAME" "$MOD_APEX_LIB_DIR/$LIBRARY_NAME" + cp "$TEMP_DIR/$LIBRARY_NAME" "$MOD_APEX_LIB_DIR/$LIBRARY_NAME" set_perm "$MOD_APEX_LIB_DIR/$LIBRARY_NAME" 0 0 644 cat < "$POST_DATA_FS_SCRIPT" @@ -84,13 +172,15 @@ mount -t overlay overlay -o lowerdir=$APEX_LIB_DIR,upperdir=$MOD_APEX_LIB_DIR,wo EOF set_perm "$POST_DATA_FS_SCRIPT" 0 0 755 - ui_print "Created post-data-fs.sh script for apex library handling." + ui_print "Created script for apex library handling." + ui_print "You can now restart your device and test aln!" + ui_print "Note: If your Bluetooth doesn't work anymore after restarting, then uninstall this module and report the issue at the link below." + ui_print "https://github.com/kavishdevar/aln/issues/new" fi else - ERROR_MESSAGE=$(grep -oP '(?<="error": ")[^"]+' "$TEMP_DIR/headers.txt") - ui_print "API Error: $ERROR_MESSAGE" - rm -rf "$TEMP_DIR" + ui_print "Error: patched file missing." + rm -rf "$TEMP_DIR" "$UNZIP_DIR" abort "Failed to patch the library." fi -rm -rf "$TEMP_DIR" \ No newline at end of file +rm -rf "$TEMP_DIR" "$UNZIP_DIR" diff --git a/root-module/libcurl-android/bin/arm64-v8a/curl b/root-module/libcurl-android/bin/arm64-v8a/curl deleted file mode 100644 index b70bd5b..0000000 Binary files a/root-module/libcurl-android/bin/arm64-v8a/curl and /dev/null differ diff --git a/root-module/libcurl-android/bin/arm64-v8a/curl-config b/root-module/libcurl-android/bin/arm64-v8a/curl-config deleted file mode 100644 index 4457af0..0000000 --- a/root-module/libcurl-android/bin/arm64-v8a/curl-config +++ /dev/null @@ -1,196 +0,0 @@ -#! /bin/sh -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2001 - 2022, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.se/docs/copyright.html. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -# SPDX-License-Identifier: curl -# -########################################################################### - -prefix="/app/libcurl-android/jni/build/curl/arm64-v8a" -exec_prefix=${prefix} -includedir=${prefix}/include -cppflag_curl_staticlib= - -usage() -{ - cat <&2 - exit 1 - fi - ;; - - --configure) - echo " '--host=aarch64-linux-android' '--prefix=/app/libcurl-android/jni/build/curl/arm64-v8a' '--with-ssl=/app/libcurl-android/jni/build/openssl/arm64-v8a' '--with-zlib=/app/libcurl-android/jni/build/zlib/arm64-v8a' '--enable-static' '--enable-shared' '--disable-verbose' '--enable-threaded-resolver' '--enable-ipv6' 'host_alias=aarch64-linux-android' 'CC=/app/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang' 'CFLAGS=--sysroot=/app/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64/sysroot -march=armv8-a -fPIC' 'LDFLAGS=-L/app/libcurl-android/jni/build/openssl/arm64-v8a/lib -L/app/libcurl-android/jni/build/zlib/arm64-v8a/lib' 'LIBS=-lssl -lcrypto -lc++ -lz' 'CPPFLAGS=-I/app/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include --sysroot=/app/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64/sysroot'" - ;; - - *) - echo "unknown option: $1" - usage 1 - ;; - esac - shift -done - -exit 0 diff --git a/root-module/libcurl-android/bin/arm64-v8a/openssl b/root-module/libcurl-android/bin/arm64-v8a/openssl deleted file mode 100644 index eb2846a..0000000 Binary files a/root-module/libcurl-android/bin/arm64-v8a/openssl and /dev/null differ diff --git a/root-module/libcurl-android/bin/armeabi-v7a/curl b/root-module/libcurl-android/bin/armeabi-v7a/curl deleted file mode 100644 index eda6f28..0000000 Binary files a/root-module/libcurl-android/bin/armeabi-v7a/curl and /dev/null differ diff --git a/root-module/libcurl-android/bin/armeabi-v7a/curl-config b/root-module/libcurl-android/bin/armeabi-v7a/curl-config deleted file mode 100644 index 31dd7cd..0000000 --- a/root-module/libcurl-android/bin/armeabi-v7a/curl-config +++ /dev/null @@ -1,196 +0,0 @@ -#! /bin/sh -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 2001 - 2022, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.se/docs/copyright.html. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -# SPDX-License-Identifier: curl -# -########################################################################### - -prefix="/app/libcurl-android/jni/build/curl/armeabi-v7a" -exec_prefix=${prefix} -includedir=${prefix}/include -cppflag_curl_staticlib= - -usage() -{ - cat <&2 - exit 1 - fi - ;; - - --configure) - echo " '--host=armv7a-linux-androideabi' '--prefix=/app/libcurl-android/jni/build/curl/armeabi-v7a' '--with-ssl=/app/libcurl-android/jni/build/openssl/armeabi-v7a' '--with-zlib=/app/libcurl-android/jni/build/zlib/armeabi-v7a' '--enable-static' '--enable-shared' '--disable-verbose' '--enable-threaded-resolver' '--enable-ipv6' 'host_alias=armv7a-linux-androideabi' 'CC=/app/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang' 'CFLAGS=--sysroot=/app/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64/sysroot -march=armv7-a -mfloat-abi=softfp -mfpu=neon -fPIC' 'LDFLAGS=-L/app/libcurl-android/jni/build/openssl/armeabi-v7a/lib -L/app/libcurl-android/jni/build/zlib/armeabi-v7a/lib' 'LIBS=-lssl -lcrypto -lc++ -lz' 'CPPFLAGS=-I/app/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include --sysroot=/app/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64/sysroot'" - ;; - - *) - echo "unknown option: $1" - usage 1 - ;; - esac - shift -done - -exit 0 diff --git a/root-module/libcurl-android/bin/armeabi-v7a/openssl b/root-module/libcurl-android/bin/armeabi-v7a/openssl deleted file mode 100644 index f956a40..0000000 Binary files a/root-module/libcurl-android/bin/armeabi-v7a/openssl and /dev/null differ diff --git a/root-module/libcurl-android/libs/arm64-v8a/libcrypto.so b/root-module/libcurl-android/libs/arm64-v8a/libcrypto.so deleted file mode 100644 index bb907f3..0000000 Binary files a/root-module/libcurl-android/libs/arm64-v8a/libcrypto.so and /dev/null differ diff --git a/root-module/libcurl-android/libs/arm64-v8a/libcurl.so b/root-module/libcurl-android/libs/arm64-v8a/libcurl.so deleted file mode 100644 index e314f7a..0000000 Binary files a/root-module/libcurl-android/libs/arm64-v8a/libcurl.so and /dev/null differ diff --git a/root-module/libcurl-android/libs/arm64-v8a/libssl.so b/root-module/libcurl-android/libs/arm64-v8a/libssl.so deleted file mode 100644 index 14face2..0000000 Binary files a/root-module/libcurl-android/libs/arm64-v8a/libssl.so and /dev/null differ diff --git a/root-module/libcurl-android/libs/arm64-v8a/libz.so b/root-module/libcurl-android/libs/arm64-v8a/libz.so deleted file mode 100644 index 3a78b00..0000000 Binary files a/root-module/libcurl-android/libs/arm64-v8a/libz.so and /dev/null differ diff --git a/root-module/libcurl-android/libs/armeabi-v7a/libcrypto.so b/root-module/libcurl-android/libs/armeabi-v7a/libcrypto.so deleted file mode 100644 index 5dae7e1..0000000 Binary files a/root-module/libcurl-android/libs/armeabi-v7a/libcrypto.so and /dev/null differ diff --git a/root-module/libcurl-android/libs/armeabi-v7a/libcurl.so b/root-module/libcurl-android/libs/armeabi-v7a/libcurl.so deleted file mode 100644 index e7da423..0000000 Binary files a/root-module/libcurl-android/libs/armeabi-v7a/libcurl.so and /dev/null differ diff --git a/root-module/libcurl-android/libs/armeabi-v7a/libssl.so b/root-module/libcurl-android/libs/armeabi-v7a/libssl.so deleted file mode 100644 index a13ea4a..0000000 Binary files a/root-module/libcurl-android/libs/armeabi-v7a/libssl.so and /dev/null differ diff --git a/root-module/libcurl-android/libs/armeabi-v7a/libz.so b/root-module/libcurl-android/libs/armeabi-v7a/libz.so deleted file mode 100644 index bbd6322..0000000 Binary files a/root-module/libcurl-android/libs/armeabi-v7a/libz.so and /dev/null differ diff --git a/root-module/module.prop b/root-module/module.prop index 616d101..47ee2da 100644 --- a/root-module/module.prop +++ b/root-module/module.prop @@ -1,6 +1,7 @@ id=btl2capfix name=Bluetooth L2CAP workaround for AirPods -version=v1 -versionCode=1 -author=kavishdevar -description=Fixes the Bluetooth L2CAP connection issue with AirPods \ No newline at end of file +version=v3 +versionCode=3 +author=@devnoname120 and @kavishdevar +description=Fixes the Bluetooth L2CAP connection issue with AirPods +updateJson=https://raw.githubusercontent.com/kavishdevar/aln/main/update.json diff --git a/root-module/radare2-5.9.9-android-aarch64.tar.gz b/root-module/radare2-5.9.9-android-aarch64.tar.gz new file mode 100644 index 0000000..9db1cde Binary files /dev/null and b/root-module/radare2-5.9.9-android-aarch64.tar.gz differ diff --git a/update.json b/update.json new file mode 100644 index 0000000..1fbd681 --- /dev/null +++ b/update.json @@ -0,0 +1,6 @@ +{ + "version": "v0.0.3", + "versionCode": 3, + "zipUrl": "https://github.com/kavishdevar/aln/releases/download/v0.0.3/btl2capfix-v0.0.3.zip", + "changelog": "https://raw.githubusercontent.com/kavishdevar/aln/main/CHANGELOG.md" +}