一次简单的蓝牙相关安卓代码逆向记录

前言

  本来工作方面和安卓根本没任何交集,把这个过程记录下来,只是一个小总结。涉及到的知识点有

  • Apktool可以用于逆向apk。
  • 使用apktool合成的apk,需要apksigner签名才能安装成功。
  • 较新版本安卓,扫描蓝牙需要定位权限。
  • connectGatt在较新的Android版本上,可能要传递额外参数,才能连接到低功耗蓝牙。
  • Smali中invoke-virtual添加函数参数时,要同步修改形参和实参列表。

基本需求

  手里有一个设备,是支持双模蓝牙的。也就是经典蓝牙使用的名称和MAC地址,和低功耗蓝牙使用的是一样的。之前其他人开发过一个安卓应用,采用经典蓝牙和设备通讯并对设备进行测试。想要抓取下安卓应用和设备之间的通讯数据,进行一些分析。

解决思路

  因为设备上的代码不能修改,也没有调试接口,就不考虑从这里下手了。对于蓝牙通讯,虽然有专门的监听设备,也不考虑购买。发现nRF Connect可以显示一些蓝牙上的数据,但是只支持低功耗蓝牙,所以考虑让安卓应用使用低功耗蓝牙来和设备进行通讯。
  安卓应用只有部分源代码,无法重新编译。而且本身也不是做安卓开发的,重新开发一个应用,时间成本太高。搜索到了Apktool这个工具,可以对安卓apk文件进行逆向工程。想着修改的地方应该不多,就朝着这一步进行了。
  蓝牙连接方式这一块的Java源代码是有的,而且逻辑也比较简单。就是根据应用自己的蓝牙连接方式,以及设备支持的蓝牙模式来选择是低功耗蓝牙还是经典蓝牙。想要使用低功耗蓝牙,只要把一些变量强制修改成低功耗蓝牙需要的值就可以了。对照着蓝牙连接的Java源代码,将逆向出来的Smali文件进行了修改,这一步主要理解了put用法,以及switch语句生成的Smali指令流程,使用了const和move指令来强行修改变量的值。
  修改之后,再使用Apktool合成新的apk,但是在安装到手机时出现问题。查阅网上资料,可能的原因是没有签名。在Ubuntu系统上安装了apksigner工具,并进行签名后,在手机上安装成功。
  安卓应用扫描蓝牙时,没有任何设备出现。使用该应用另外一个测试菜单时,询问要获取定位权限,之后可以扫描出蓝牙。和设备进行连接,确实使用的是低功耗蓝牙,但是却不能连接成功。
  查看蓝牙连接代码,使用的是connectGatt。以函数名为关键字进行搜索,发现有人碰到了类似的问题。原来这个函数最开始只有三个参数。在Android M之后,这个函数被重载了,增加了几个参数。第四个参数可以是BluetoothDevice.TRANSPORT_AUTO,BluetoothDevice.TRANSPORT_BREDR或BluetoothDevice.TRANSPORT_LE。默认是AUTO,要连接到低功耗,就要使用LE。再修改Smali指令,加入第四个参数,取值是2。重新安装应用后,运行时出现闪退。
  怀疑和在Smali中增加参数有关,搜索invoke-virtual相关,发现不仅有实参列表,还有形参列表。同步修改形参列表,增加I表示整型参数。重新安装应用,可以以低功耗蓝牙方式进行连接。但是和设备通讯不稳定,之前可以和设备完成整个测试流程,使用新的应用会概率性地出现测试流程中断。
  控制测试流程的源代码没有了,只好另外想办法。在现有的代码中看到有日志功能,并且使用了android.util.Log类,可以使用adb logcat提取出相应日志。日志功能默认是没开启的,再次修改Smali文件,合成新的apk。安装后的日志可以通过adb logcat提取出来。
  从日志中看到有一次向设备发送蓝牙数据后,没有得到回应,之后测试就中断了。本来想要继续分析日志,来看为什么没有得到回应时,突然想到既然可以通过logcat查看到日志,那么在原来的应用基础上进行一点修改,不就可以看到蓝牙通讯数据了,也不用强制使用低功耗蓝牙了。
  在最开始的应用上,使能日志功能,经典蓝牙通讯没有出现问题,也可以通过logcat看到蓝牙通讯数据。至此,最开始的需求已经得到满足。

随想

  如果对于安卓足够熟悉,可能一开始就会想到使用adb来查看日志这个选项。而不会走到要强制使用低功耗蓝牙,并解决后续若干问题的路上。也再次提醒要注意XY问题

posted @ 2023-06-07 14:07  watsondd  阅读(165)  评论(0编辑  收藏  举报