许多人可能对Hook技术有些陌生,其实从字面意思上理解这就类似一个钩子,挂在了系统中的某些地方,然后当执行流程经过该处时会被勾住,可以选择放行或截获,或做点手脚偷偷改改参数,或记录日志,或检查权限,或post到别的上下文去执行,应用场景还挺多。
本文会重点讨论蓝牙相关的Hook,要全局监测所有BLE蓝牙设备的操作,对于不那么活跃的设备我们会断开连接并释放资源,毕竟蓝牙通信信道是有限的。那么如何全局监测所有蓝牙设备的操作呢?可以在所有操作设备的地方打点,不过这样太麻烦,给代码搞乱了不说,即便漏了也不知道。好一点的办法是封装一套接口供所有人调用,打点在接口内做好,外部不用关心。不过如果有人不守规矩不走这套接口则依然会漏了。接下来本文会提出一种新的解决思路,不用到处打点,也不用封装这么一套公共接口。其核心原理就是在系统api内部挂一个钩子,用户操作设备总要调系统api的,这样就能被我们拦截到并且万无一失。现在的问题是如何在系统内部打入这么一个钩子而不被察觉呢?
第一步,我们需要调研这个钩子下在哪里。我们注意到BLE设备操作都需要有gatt句柄,我们就以gatt为入口,先看这个gatt是在哪里获取的,如下:
public BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager managerService = adapter.getBluetoothManager();
try {
IBluetoothGatt iGatt = managerService.getBluetoothGatt();
if (iGatt == null) {
// BLE is not supported
return null;
}
BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
gatt.connect(autoConnect, callback);
return gatt;
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
这个gatt核心其实是IBluetoothGatt,是IBluetoothManager调用getBluetoothGatt返回的。而这个IBluetoothManager是BluetoothAdapter中的,我们将目光转移到BluetoothAdapter中,如下:
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
IBinder b = ServiceM