作者: ljcnaix
这篇教程中有一些示例程序,可以动手调试来加深理解。要调试 ARM 程序,我们需要能运行 ARM 程序的运行环境和支持 ARM 架构的调试器。本篇教程将基于 x86 平台的 Ubuntu 16.04 ,介绍如何搭建 ARM 的交叉编译、运行和调试环境。
Ubuntu 16.04 的源中提供了多个 arm-gcc 的软件包,以 gcc 5 为例可以通过“ apt search ”命令找到“ gcc-5-arm-linux-gnueabi ”和“ gcc-5-arm-linux-gnueabihf ”两个软件包。这两个软件包安装的编译工具是一样的,只是与浮点数相关的默认编译选项不同。由于我们虚拟的环境没有FPU ,只需要安装“ gcc-5-arm-linux-gnueabi ”就可以了。
安装完成后可以在“/usr/bin/arm-linux-gnueabi-*”找到相关的编译工具链,包含常用的gcc、as 和ld 等。只要使用如下两条命令,就可以实现对ARM汇编的编译:
可以使用如下命令编译经典的“ hello world ”程序,用于后续章节的实验:
最简单的运行环境是使用 qemu-user-static 模拟运行静态编译的可执行程序。我们可以使用如下命令模拟运行上一节创建的 hello 程序:
首先安装 qemu-user-static ,若已安装可以忽略这一步
直接执行 hello 程序
启动 gdbserver 等待 gdb 连接
上述命令运行后会启动一个qemu自带的gdbserver ,监听你通过“-g”选项指定的端口。可以在另一个窗口中启动gdb进行远程调试(远程调试的细节,将在第三章介绍)。
qemu-user-static 的方式比较简单,但功能也很局限, Azeria-labs 的教程中介绍了另一种方法,使用 qemu 创建一台虚拟树莓派。首先你需要安装 qemu-system :
为了虚拟一台树莓派,你还需要下载专为树莓派定制的 debian 镜像( raspbian )和支持树莓派的内核文件。
raspbian 镜像下载地址: https://www.raspberrypi.org/downloads/raspbian/
树莓派内核下载地址: https://github.com/dhruvvyas90/qemu-rpi-kernel
Raspbian 的镜像有两个版本,一个带图形界面的完整版和一个没有图形界面的 lite 版本,对于我们的实验而言 lite 版本就足够了。内核文件有多个,选择内核版本最新的那个就可以了。下载完上述文件后,创建一个“ arm_vm ”目录,将上述文件一起放置在该目录下。然后执行如下命令:
你应该可以看到,类似如下内容:
注意标红的部分,可以看到文件系统从 94208 扇区开始。我们将这个值乘以 512 ,本例中为“ 94208 * 512=48234496 ”,这就是文件系统起始位置的偏移字节数,在下面的命令中我们会用到:
将上述文件中的所有内容用“ # ”注释掉,保存修改并退出。
如果 fstab 文件中有出现 mmcblk0 字符串,那么将“ /dev/mmcblk0p1 ”替换为“ /dev/sda1 ”,将“ /dev/mmcblk0p2 ”替换为“ /dev/sda2 ”,保存后退出。至此,系统配置的修改完成,可以将“ /mnt/raspbian ”卸载掉。
你可以进入“ arm_vm ”目录,使用如下脚本启动虚拟机:
虚拟机启动后默认的登录密码是“ raspberry ”。为了更方便的使用虚拟机,我们需要开启 ssh 服务,并设置开机启动。
此时,你应该已经可以使用如下命令,通过 ssh 访问虚拟机了:
我们可以使用 scp 命令通过 ssh ,将上一节编译的 hello 程序上传到虚拟机中执行:
进入虚拟机的 tmp 目录,可以看到我们上传的 hello 程序尝试执行,应该会输出久违的“ hello world! ”,说明我们的交叉编译环境搭建是正确的。至此我们的虚拟树莓派环境搭建完毕。
调试环境的搭建是最重要的也是坑最多的。为了模拟真实 IoT 安全实战中远程调试的场景,我们将介绍如何交叉编译 gdbserver 并上传至虚拟机进行远程调试。为了获得类似 pwndbg 那样强大的调试效果,我们将介绍如何安装使用专为 IoT 安全设计的 gef 增强脚本。
在使用 gdb 进行调试之前,我们需要先安装 gdb-multiarch 。顾名思义,它是 gdb 支持多中硬件体系架构的版本。之所以要安装 gdb-multiarch ,是因为 Ubuntu 默认安装的 gdb 只支持 x86/x64 架构,你可以启动 gdb 然后输入命令“ set architecture arm ”查看, gdb 会提示错误。
安装 gdb-multiarch
启动 gdb-multiarch
在分析 IoT 设备的安全性时,我们往往需要上传 gdbserver 进行远程调试。在我们的实验环境中(事实上我们的 Raspbian 系统自带 gdb ),我们也可以模拟搭建一个远程调试环境。首先,我们需要获取 gdb 的源码(包含了 gdb 源码和 gdbserver 源码),版本需要与我们本地的 gdb 版本一致,因为 gdbserver 需要与 gdb 版本保持一致,否则容易出现非预期的问题。你可以在这个地址,找到 gdb 各版本的源码: http://ftp.gnu.org/gnu/gdb/。
下载解压后进入“ gdb-<version>/gdb/gdbserver ”目录,使用如下命令编译安装:
然后,在你通过“ --prefix ”选项指定的路径下,就可以找到编译完成的 gdbserver 了。使用 file 命令查看,应该可以看到类似如下输出:
使用 scp 将 gdbserver 上传到我们的虚拟树莓派中并启动:
至此,我们的远程调试环境搭建完毕,下一节,我们将引入 gef 增强脚本。
gef 是一个支持多种硬件体系结构的 gdb 增强脚本,非常适合 IoT 安全领域应对多变的硬件平台。你可以参考 github 主页( https://github.com/hugsy/gef )的 README ,进行安装配置。不过需要注意的是, gef 依赖的第三方模块 keystone-engine 需要手动安装,因为 pip 源提供的安装是无效的。建议先通过 pip 安装,如果安装后 gef 的部分功能仍无法使用,可以卸载通过 pip 安装的第三方模块,在 github 上( https://github.com/keystone-engine/keystone)下载最新源码,手动编译安装(参见:http://www.keystone-engine.org/docs/)。
安装完成后开启 gdb 调试,你将看到类似如下的界面:
首先设置目标硬件体系架构为 arm :
我们使用 gef-remote 命令连接 gdbserver ,如果使用 gdb 自带的“ target remote ”命令会出现一些非预期的问题(参见: https://github.com/hugsy/gef/issues/7)。
你应该能看到类似如下的输出:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!