BruceFan's Blog

Stay hungry, stay foolish

0%

gdb调试AOSP代码

这次主要是调试Android system/bt目录下的代码,也就是蓝牙相关的代码,是源于对几个CVE(cve-2018-9355~cve-2018-9362)的学习,这几个CVE是蓝牙相关的漏洞。

蓝牙相关代码分析

因为之前对蓝牙相关代码没有了解过,所以先对AOSP中关于蓝牙的代码进行学习。首先是从Android应用层编程开始,几个基本操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 获取设备Adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 表明此手机不支持蓝牙
if(mBluetoothAdapter == null){
return;
}
// 蓝牙未开启,则开启蓝牙
if(!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
}
// 查询已绑定设备,发现新设备
mBluetoothAdapter.getBondedDevices();
mBluetoothAdapter.startDiscovery();

还有一些读写之类的操作先不赘述。这些API调用的是frameworks里的代码,如getDefaultAdapter()函数对应
frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java文件里的getDefaultAdapter()函数:

1
2
3
4
5
6
7
8
9
10
11
12
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE); // 这里通过Binder通信调用packages里的Android应用程序的服务
if (b != null) {
IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
sAdapter = new BluetoothAdapter(managerService);
} else {
Log.e(TAG, "Bluetooth binder is null");
}
}
return sAdapter;
}

上述代码片段中的BLUETOOTH_MANAGER_SERVICE是在
frameworks/base/services/core/java/com/android/server/BluetoothService.java中注册的,会通过Binder机制调用到
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java,AdapterService.enableNative()在
packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp中声明,通过jni调用HAL(hardware)里的代码。hardware里的代码会调用system里的代码实现,具体代码我就不分析了,主要介绍一下如何调试。

调试system中蓝牙相关代码

首先需要编译Android的源码,烧录到真机上,可以参考我之前的一篇文章,我的系统是Android6.0.1和Ubuntu 16.04。
前面分析了system的代码会由packages里的bluetooth应用程序调用,所以可以先尝试调试bluetooth的应用程序,跟踪代码到system层。接下来就是对Android应用native代码调试的操作,先手动打开蓝牙,打开一个终端(需要adb root):

1
2
3
4
5
6
$ adb shell
root@hammerhead:/ # ps | grep bluetooth
bluetooth 9134 2265 907552 46368 sys_epoll_ b6ce9894 S com.android.bluetooth
root@hammerhead:/ # gdbserver :1234 --attach 9134
Attached; pid = 9134
Listening on port 1234

另一个终端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ cd Android6.0.1_r20
$ source build/envsetup.h
$ lunch 19
$ adb forward tcp:1234 tcp:1234
$ gdbclient 9134
(gdb) target remote :1234
Remote debugging using :1234
warning: Could not load shared library symbols for 9 libraries, e.g. /data/dalvik-cache/arm/system@framework@boot.oat.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
Reading symbols from /home/fanrong/Computer/Android6.0.1-r20/out/target/product/hammerhead/symbols/system/bin/linker...done.
Loaded symbols for /home/fanrong/Computer/Android6.0.1-r20/out/target/product/hammerhead/symbols/system/bin/linker
Reading symbols from /home/fanrong/Computer/Android6.0.1-r20/out/target/product/hammerhead/symbols/system/lib/libcutils.so...done.
Loaded symbols for /home/fanrong/Computer/Android6.0.1-r20/out/target/product/hammerhead/symbols/system/lib/libcutils.so
...
Loaded symbols for /home/fanrong/Computer/Android6.0.1-r20/out/target/product/hammerhead/symbols/system/vendor/lib/libbt-vendor.so
__epoll_pwait () at bionic/libc/arch-arm/syscalls/__epoll_pwait.S:16
16 ldmfd sp!, {r4, r5, r6, r7}
(gdb)

比如我们调试蓝牙搜索的相关代码,
/packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java中的startDiscovery()方法:

1
2
3
4
5
6
 boolean startDiscovery() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");

return startDiscoveryNative();
}

jni调用
/packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp中的startDiscoveryNative()

1
2
3
4
5
6
7
8
9
10
static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
ALOGV("%s:",__FUNCTION__);

jboolean result = JNI_FALSE;
if (!sBluetoothInterface) return result;

int ret = sBluetoothInterface->start_discovery();
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}

通过查看/packages/apps/Bluetooth/jni/Android.mk

1
LOCAL_MODULE := libbluetooth_jni

可以知道bluetooth的jni代码被编译成了libbluetooth_jni.so库,在
Android6.0.1-r20/out/target/product/hammerhead/symbols/system/lib/libbluetooth_jni.so,这个是带符号的,用IDA打开它。
打开一个终端,查看系统中so库加载的基址:

1
2
3
4
5
$ adb shell
# cat /proc/2286/maps | grep libbluetooth
b39e7000-b39fe000 r-xp 00000000 b3:19 921 /system/lib/libbluetooth_jni.so
b39ff000-b3a00000 r--p 00017000 b3:19 921 /system/lib/libbluetooth_jni.so
b3a00000-b3a01000 rw-p 00018000 b3:19 921 /system/lib/libbluetooth_jni.so

在IDA->Edit->Segments->Rebase program…,将Value改成0xb39e7000,找到android::startDiscoveryNative()函数:

在这个函数的起始地址是0xb39e9a80,在gdb中下断点,继续运行,让蓝牙对周围设备进行搜索,即可触发断点:

单步运行,可以运行到system/bt/btif/src/bluetooth.c中的start_discovery()函数(gdb中按ctrl+x+a):

/system/bin中的可执行文件调试

对于未启动进程:调试进程keystore

1
2
3
$ adb shell gdbserver :1234 /system/bin/keystore
Process /system/bin/keystore created; pid = 3990
Listening on port 1234

另一个终端(需要先source、lunch)

1
2
3
4
5
6
7
8
$ adb forward tcp:1234 tcp:1234
$ gdbclient 3990
Reading symbols from /home/fanrong/Computer/Android6.0.1-r20/out/target/product/hammerhead/symbols/system/bin/keystore...done.
(gdb) target remote :1234
__dl__start () at bionic/linker/arch/arm/begin.S:32
32 mov r0, sp
(gdb) si
33 bl __linker_init

对于已经启动的进程

1
2
$ adb shell
# gdbserver :1234 --attach pid

另一个终端

1
2
3
$ adb forward tcp:1234 tcp:1234
$ gdbclient pid
(gdb) target remote :1234

reference
蓝牙流程介绍
Android FrameWork学习(二)Android系统源码调试