【技术分享】使用KGDB实现Android内核调试

admin 2023-12-07 16:36:11 AnQuanKeInfo 来源:ZONE.CI 全球网 0 阅读模式

http://p4.qhimg.com/t010571b5d62f356f5d.png

翻译:myswsun

预估稿费:140RMB

投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿


前言

内核调试给了安全研究员在分析时一个监视和控制设备的工具。在桌面平台如Windows、macOS和linux,非常简单实现。然而,在安卓设备,例如谷歌Nexus 6P,上面内核调试很困难。本文,我将描述一种在安卓设备上面内核调试的方法,而且不需要特殊硬件。


实现

Joshua J.Drake和Ryan Smith为了这个目的构建了一个UART debug cable,能很好的完成内核调试。然而一些人不擅长硬件环境构建,这将变得困难。还好,通过serial-over-usb通道也能完成内核调试。

这个方法可以追述到2010年,意味着一部分指令现在已经过时了。我发现仍然使用此方法的一些关键点可以在现代Android设备上使用。研究员用调试来判断CPU执行的状态,能加快分析。但是这个过程如何实现?

Android用的是linux内核,内置了内核调试器KGDB,KGDB依赖连接调试设备和目标设备的串口。典型场景如下:

http://p9.qhimg.com/t01f21673932332da58.jpg

图1. KGDB工作模式

目标设备和调试设备使用串口电缆相连。用户在调试设备上面使用GDB附加到串口(如/dev/ttyS1)目标设备,命令是target remote /dev/ttyS1。之后,GDB能和目标设备上的KGDB通过串口电缆通信。

KGDB的核心组件处理真正的调试任务,例如设置断点和获取内存数据。KGDB的输入输出组件连接KGDB核心组件和底层串口驱动的关键。

然而,Android设备通常没有硬件串口。第一个挑战便是如何找到一个通道,能够用GDB向外发送调试信息。多种通道被使用了,但是最特别的解决方案是USB电缆。

Linux内核USB驱动支持USB ACM class devices,能仿真一个串口设备。简言之,一个Android设备能通过USB电缆连接串口设备。所有这一切都在已经是Linux内核一部分的代码中了,因此我们不比增加代码。下面是激活调试功能的步骤:

1. 构建一个AOSP的版本和相应的linux内核,参考在此

2. 用USB电缆将目标设备和调试机器相连。

3. 用fastboot命令将映像写入设备,fastboot flashall –w。

4. 运行adb命令启动网咯服务:adb tcpip 6666。

5. 在调试机器上面,运行adb连接设备:adb connect <device ip> 6666。

6. 运行adb shell:adb shell。

7. 在adb shell中,到USB驱动控制文件夹中/sys/class/android_usb/android0/。

8. 在adb shell中,用下面的命令启动USB ACM功能:

echo 0 > enable       //close USB connection
echo tty > f_acm/acm_transports    //specific transport type
echo acm > functions           //enable ACM function on USB gadget driver
echo 1 > enable       //enable USB connection

到这里,USB ACM功能应该启用了。两步验证是否生效:首先,在adb shell中,用ls /dev/ttyGS*。一个设备文件应该存在。再者,在调试机器上面,用ls /dev/ttyACM*。也应该存在一个设备文件。调试机器和目标设备用这两个文件通信。

第二个挑战是KGDB需要底层通信驱动(串口驱动或者USB驱动)来提供一个轮询的接口用于读写。为什么?因为KGDB的通信通道需要在KGDB的内核异常处理函数中工作。在那个上下文中,中断被禁用了并且只有一个CPU起作用。底层驱动不依赖中断并且需要轮询改变寄存器或内存I/O空间。不要在这个上下文使用休眠和自旋锁。

这个Nexus 6P使用DWC3控制器来完成USB连接。这个USB驱动不直接提供轮询功能。因此我们需要在DWC3设备驱动中添加这个特性。代码后面的概念是简单的:我已经移除了中断依赖。相反的是我是用循环去查询相应的寄存器修改和内存空间。为了使事情简单,我做了以下的事情:

1. 我在kgdboc.c文件中的kgdboc_init_jack函数中硬编码了ACM设备文件名/dev/ttyGS0。

2. 我改变了f_acm/acm_transports函数启用了KGDB。这将允许用简单的命令开启KGDB: echo kgdb > f_acm/acm_transports

下图是KGDB的工作模式:

http://p9.qhimg.com/t01f177d8e236789fef.jpg

图2. 新的KGDB的工作模型

这里是整合代码到内核代码的步骤。虽然你能用任何内核代码,但是我采用谷歌自身的仓库,指定分支origin/android-msm-angler-3.10-nougat-hwbinder。

1. 用下面的配置编译内核代码:

    1. CONFIG_KGDB=y
        CONFIG_KGDB_SERIAL_CONSOLE=y
    2. CONFIG_MSM_WATCHDOG_V2 = n,如果这个启动了,内核中轮询循环是一个死循环并重启设备。
    3. CONFIG_FORCE_PAGES=y,如果这个没哟开启,软断点将不能设置。

2. 用fastboot命令刷新内核和Android映像到目标设备。

3. 在调试机器上面启动Android系统。运行以下命令启动网络服务:adb tcpip 6666。

4. 在调试机器上,运行以下命令:

adb connect <device’s ip address>:6666
adb shell

5. 在adb shell中,运行以下命令:

echo 0 > enable
echo tty > f_acm/acm_transports
echo acm > functions
echo 1 > enable
echo kgdb > f_acm/acm_transports

6. 在调试机器上面,运行gdb。Nexus 6P有一个aarch64的内核,因此需要aarch64版本的gdb

sudo <path>/aarch64-linux-android-gdb <path>/vmlinux
target remote /dev/ttyACM0

7. 在adb shell中,输入以下命令:

echo g > /proc/sysrq-trigger

注意:在第6步和第7步之间的时间间隔不能太长。越短越好。

8. 如果成功了,GDB会有以下输出:

http://p8.qhimg.com/t0180aa4475e69aab45.jpg

图3. GDB输出

我已经用这个方法在Nexus 6P上面实现了内核调试。这个方法应该也支持Google Pixel,因为他们也使用DWC3 USB控制器。


总结

我们希望分享这个技术能够帮组到其他Android研究者,使得更好的理解移动恶意软件的行为。调试有助于研究者更好的逆向分析,也能更清楚的理解Android设备上面恶意程序如何作为。

weinxin
版权声明
本站原创文章转载请注明文章出处及链接,谢谢合作!
评论:0   参与:  0