73 lines
1.8 KiB
Python
73 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Scan decompiled Android sources for BLE UUIDs and GATT-related calls."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import re
|
|
from pathlib import Path
|
|
|
|
UUID_RE = re.compile(
|
|
r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
|
|
)
|
|
|
|
GATT_TERMS = [
|
|
"BluetoothGatt",
|
|
"BluetoothGattCallback",
|
|
"BluetoothGattCharacteristic",
|
|
"BluetoothGattDescriptor",
|
|
"BluetoothLeScanner",
|
|
"startScan",
|
|
"startLeScan",
|
|
"connectGatt",
|
|
"createBond",
|
|
"discoverServices",
|
|
"getService",
|
|
"getCharacteristic",
|
|
"setCharacteristicNotification",
|
|
"writeCharacteristic",
|
|
"readCharacteristic",
|
|
"writeDescriptor",
|
|
"onCharacteristicChanged",
|
|
"onCharacteristicRead",
|
|
"onCharacteristicWrite",
|
|
]
|
|
|
|
|
|
def interesting(path: Path) -> bool:
|
|
return path.suffix.lower() in {".java", ".kt", ".xml", ".smali"}
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("source", type=Path, help="JADX/apktool output directory")
|
|
args = parser.parse_args()
|
|
|
|
for path in sorted(p for p in args.source.rglob("*") if p.is_file() and interesting(p)):
|
|
try:
|
|
text = path.read_text(errors="ignore")
|
|
except OSError:
|
|
continue
|
|
|
|
matches = sorted(set(UUID_RE.findall(text)))
|
|
terms = [term for term in GATT_TERMS if term in text]
|
|
if not matches and not terms:
|
|
continue
|
|
|
|
print(f"## {path}")
|
|
if matches:
|
|
print("UUIDs:")
|
|
for value in matches:
|
|
print(f"- {value.lower()}")
|
|
if terms:
|
|
print("GATT terms:")
|
|
for value in terms:
|
|
print(f"- {value}")
|
|
print()
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|