标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2024-582]   作者: ecawen 发表于: [2017-09-07]

本文共 [710] 位读者顶过

这篇教程中有一些示例程序,可以动手调试来加深理解。要调试 ARM 程序,我们需要能运行 ARM 程序的运行环境和支持 ARM 架构的调试器。本篇教程将基于 x86 平台的 Ubuntu 16.04 ,介绍如何搭建 ARM 的交叉编译、运行和调试环境。

交叉编译环境

Ubuntu 16.04 的源中提供了多个 arm-gcc 的软件包,以 gcc 5 为例可以通过“ apt search ”命令找到“ gcc- -arm-linux-gnueabi ”和“ gcc- -arm-linux-gnueabihf ”两个软件包。这两个软件包安装的编译工具是一样的,只是与浮点数相关的默认编译选项不同。由于我们虚拟的环境没有 FPU ,只需要安装“ gcc- -arm-linux-gnueabi ”就可以了。

安装完成后可以在“ /usr/bin/arm-linux-gnueabi-* ”找到相关的编译工具链,包含常用的 gcc 、 as 和 ld 等。只要使用如下两条命令,就可以实现对 ARM 汇编的编译:

$ arm-linux-gnueabi-as [source file] –o [object file]

$ arm-linux-gnueabi-ld [object file] –o [executable file]

可以使用如下命令编译经典的“ hello world ”程序,用于后续章节的实验:

$ arm-linux-gnueabi-gcc-5 hello.c –g –o hello -static

运行环境

I. qemu-user-static

最简单的运行环境是使用 qemu-user-static 模拟运行静态编译的可执行程序。我们可以使用如下命令模拟运行上一节创建的 hello 程序:

首先安装 qemu-user-static ,若已安装可以忽略这一步

$ sudo apt install qemu-user-static

直接执行 hello 程序

$ qemu-arm-static hello

启动 gdbserver 等待 gdb 连接

$ qemu-arm-static –g [gdbserver port] hello

上述命令运行后会启动一个 qemu 自带的 gdbserver ,监听你通过“ -g ”选项指定的端口。可以在另一个窗口中启动 gdb 进行远程调试(远程调试的细节,将在第三章介绍)。

II. 虚拟 Raspberry

qemu-user-static 的方式比较简单,但功能也很局限, Azeria-labs 的教程中介绍了另一种方法,使用 qemu 创建一台虚拟树莓派。首先你需要安装 qemu-system 

$ sudo apt install qemu-system

为了虚拟一台树莓派,你还需要下载专为树莓派定制的 debian 镜像( raspbian )和支持树莓派的内核文件。

raspbian 镜像下载地址: https://www.raspberrypi.org/downloads/raspbian/

树莓派内核下载地址: https://github.com/dhruvvyas90/qemu-rpi-kernel

Raspbian 的镜像有两个版本,一个带图形界面的完整版和一个没有图形界面的 lite 版本,对于我们的实验而言 lite 版本就足够了。内核文件有多个,选择内核版本最新的那个就可以了。下载完上述文件后,创建一个“ arm_vm ”目录,将上述文件一起放置在该目录下。然后执行如下命令:

$ unzip <image-file>.zip

$ fdisk –l <image-file>

你应该可以看到,类似如下内容:

Disk 2017-08-16-raspbian-stretch-lite.img: 1.7 GiB, 1854418944 bytes, 3621912 sectors

Units: sectors of 1 * 512 = 512 bytes

Sector size (logical/physical): 512 bytes / 512 bytes

I/O size (minimum/optimal): 512 bytes / 512 bytes

Disklabel type: dos

Disk identifier: 0xee397c53

 

Device                                 Boot Start      End Sectors   Size Id Type

2017-08-16-raspbian-stretch-lite.img1        8192    93813    85622 41.8M   c W95 FAT32 (LBA)

2017-08-16-raspbian-stretch-lite.img2       94208 3621911 3527704   1.7G 83 Linux

注意标红的部分,可以看到文件系统从 94208 扇区开始。我们将这个值乘以 512 ,本例中为“ 94208 * 512=48234496 ”,这就是文件系统起始位置的偏移字节数,在下面的命令中我们会用到:

$ sudo mkdir /mnt/raspbian

$ sudo mount -v -o offset=48234496 -t ext4 [path-of-your-img-file.img] /mnt/raspbian

$ sudo vi /mnt/raspbian/etc/ld.so.preload

将上述文件中的所有内容用“ ”注释掉,保存修改并退出。

$ sudo vi /mnt/raspbian/etc/fstab

如果 fstab 文件中有出现 mmcblk0 字符串,那么将“ /dev/mmcblk0p1 ”替换为“ /dev/sda1 ”,将“ /dev/mmcblk0p2 ”替换为“ /dev/sda2 ”,保存后退出。至此,系统配置的修改完成,可以将“ /mnt/raspbian ”卸载掉。

$ sudo umount /mnt/raspbian

你可以进入“ arm_vm ”目录,使用如下脚本启动虚拟机:

#!/usr/bin/env bash

 

qemu-system-arm -kernel kernel-qemu-4.4.34-jessie \

          -cpu arm1176 \

          -m 256 \

          -M versatilepb \

          -serial stdio \

          -append "root=/dev/sda2 rootfstype=ext4 rw" \

          -drive format=raw,file=2017-08-16-raspbian-stretch-lite.img \

          -redir tcp:5022::22 \              为 ssh 预留

          -redir tcp:3011::3011 \            为 gdbserver 预留,用于远程调试

          -no-reboot 1> /dev/null 2>&1 &

虚拟机启动后默认的登录密码是“ raspberry ”。为了更方便的使用虚拟机,我们需要开启 ssh 服务,并设置开机启动。

$ sudo service ssh start

$ sudo update-rc.d ssh enable

此时,你应该已经可以使用如下命令,通过 ssh 访问虚拟机了:

$ ssh pi@127.0.0.1 -p 5022

我们可以使用 scp 命令通过 ssh ,将上一节编译的 hello 程序上传到虚拟机中执行:

scp -P 5022 hello pi@127.0.0.1:/tmp

进入虚拟机的 tmp 目录,可以看到我们上传的 hello 程序尝试执行,应该会输出久违的“ hello world! ”,说明我们的交叉编译环境搭建是正确的。至此我们的虚拟树莓派环境搭建完毕。

调试环境

调试环境的搭建是最重要的也是坑最多的。为了模拟真实 IoT 安全实战中远程调试的场景,我们将介绍如何交叉编译 gdbserver 并上传至虚拟机进行远程调试。为了获得类似 pwndbg 那样强大的调试效果,我们将介绍如何安装使用专为 IoT 安全设计的 gef 增强脚本。

I. gdb-multiarch

在使用 gdb 进行调试之前,我们需要先安装 gdb-multiarch 。顾名思义,它是 gdb 支持多中硬件体系架构的版本。之所以要安装 gdb-multiarch ,是因为 Ubuntu 默认安装的 gdb 只支持 x86/x64 架构,你可以启动 gdb 然后输入命令“ set architecture arm ”查看, gdb 会提示错误。

安装 gdb-multiarch

$ sudo apt install gdb-multiarch

启动 gdb-multiarch

$ gdb-multiarch

II. 编译 gdbserver

在分析 IoT 设备的安全性时,我们往往需要上传 gdbserver 进行远程调试。在我们的实验环境中(事实上我们的 Raspbian 系统自带 gdb),我们也可以模拟搭建一个远程调试环境。首先,我们需要获取 gdb 的源码(包含了 gdb 源码和 gdbserver 源码),版本需要与我们本地的 gdb 版本一致,因为 gdbserver 需要与 gdb 版本保持一致,否则容易出现非预期的问题。你可以在这个地址,找到 gdb 各版本的源码: http://ftp.gnu.org/gnu/gdb/ 

下载解压后进入“ gdb-<version>/gdb/gdbserver ”目录,使用如下命令编译安装:

$ CC="arm-linux-gnueabi-gcc-5" CXX="arm-linux-gnueabi-g++-5" ./configure --target=arm-linux-gnueabi --host="arm-linux-gnueabi" --prefix="setup-directory"

$ make install

然后,在你通过“ --prefix ”选项指定的路径下,就可以找到编译完成的 gdbserver 了。使用 file 命令查看,应该可以看到类似如下输出: 

$ file arm-linux-gnueabi-gdbserver

arm-linux-gnueabi-gdbserver: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=32ad2025951ee428276ac2fbadb199bfd39e2278, not stripped

使用 scp 将 gdbserver 上传到我们的虚拟树莓派中并启动:

$ ln -s arm-linux-gnueabi-gdbserver gdbserver

$ gdbserver 0.0.0.0:2333 hello

Process hello created; pid = 702

Listening on port 2333

至此,我们的远程调试环境搭建完毕,下一节,我们将引入 gef 增强脚本。

III. 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> set architecture arm

我们使用 gef-remote 命令连接 gdbserver ,如果使用 gdb 自带的“ target remote ”命令会出现一些非预期的问题(参见:https://github.com/hugsy/gef/issues/7 )。

gef> gef-remote –q 127.0.0.1:2333

你应该能看到类似如下的输出:

至此,我们的调试环境配置完毕了。

扩展阅读

[出自:jiwo.org]

[1] gef 官方文档, http://gef.readthedocs.io/en/master/

[2] gdb 调试利器, http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html

[3] gdb 中应该知道的几个调试方法, https://coolshell.cn/articles/3643.html

评论

暂无
发表评论
 返回顶部 
热度(710)
 关注微信