专栏首页绿盟科技研究通讯使用QEMU chroot进行固件本地调试

使用QEMU chroot进行固件本地调试

QEMU是我们在调试一些不同架构的程序时经常使用的虚拟机软件。它有两种运行模式,全系统模拟(System mode)和单程序运行(User mode)。System mode和我们平常用的VMWare一样,模拟整个系统从加载器开始的启动和运行。在设备逆向过程中,如果仅仅是为了运行我们提取出文件系统中的某一个程序,我们就可以使用QEMU的user mode来简化整个操作流程,同时能够方便的利用 QEMU 自带的GDB服务来进行调试,免去搭建环境的烦恼。

但是,单单在命令行中调用“qemu-arm myprogram”往往没有那么简单,因为动态链接的程序都会依赖几个动态链接库。虽然可以传入 -L 参数,或者通过指定环境变量QEMU_LD_PREFIX解决,但这种方式不但不优雅,还会造成重复性的工作——每个程序依赖的库不同,因此每次都要选择不同的目录。而且使用这种方式启动的程序,所运行的程序文件夹(CWD)与原来不同,很可能访问不了程序中硬编码的一些文件的绝对路径,造成程序出错。

因此最简单直接的方法还是使用chroot配合QEMU,来完全模拟程序的文件系统环境,以固件的根目录作为chroot的根目录,程序也能够自动加载到它所需要的libc与其他各种函数库。我们绿盟的小伙伴在看雪上做过一次分享,我听过后以为很容易上手,但是操作时踩到了一些坑。这里总结一下整个流程,顺便讲解一下其中的原理。

一、编译安装

Ubuntu自带的 QEMU 版本有点老(我的18.04 LTS附带的QEMU 2.11),会遇到一些问题。在调试时会遇到类似下面的报错。

~ # ./gdbserver tcp:2333 /usr/bin/messagingagent
qemu: Unsupported syscall: 117

老版本QEMU不能够很好的处理与调试相关的ptrace系统调用,我们需要从官方的最新版源代码编译安装QEMU。

依赖的安装可以参考官方教程(https://wiki.qemu.org/Hosts/Linux)安装好依赖后从git获取最新的源码,并使用以下参数指定编译的QEMU采用静态链接,最后进行编译。我在这里指定prefix目录为当前目录下的 staging,自己操作时可以随意更改。

git clone git://git.qemu.org/qemu.git --recurse-submodules --depth 1
cd qemu
./configure --static --prefix="$PWD/staging/user-static" --disable-system --enable-linux-user
make –j8 && make install

然后 staging/user-static 目录下就是我们编译好的核武器了。

二、安装binfmt

binfmt(Binary Format)是一个内核模块,它的用处如它的名字,通过二进制文件头来识别它的格式,从而指定用哪个解释器去启动——可以理解为二进制文件的hashbang(用处类似于在Python文件的第一行写上“#!/usr/bin/env python”)。有了它我们就可以像启动原生ELF一样启动一个ARM或其他任何QEMU支持的程序了。

sudo apt install qemu-user-binfmt
update-binfmts --display

安装这个包会依赖安装系统软件源中的qemu-user。我们用不到它,但装这个包的意义在于它包含了几个自动向内核注册QEMU binfmt的脚本,这样我们就不需要再手动指定我们的ARM可执行文件需要哪个路径下的QEMU来执行,非常方便。安装成功后在命令行中执行“update-binfmts --display”。

图 1 update-binfmts输出

我们此时可以测试一下,临时将环境变量 QEMU_LD_PREFIX 设置为我们要 chroot 进去的根目录,然后运行ARM设备中提取出的ELF可执行文件,如果不报错就可以了。图中 a.out 是我编译的 arm64 的 hello world,这个程序可在我的测试设备上正常运行。

三、复制QEMU程序

hello world可以运行之后,我们还需要准备一下我们的rootfs目录。

将第一步编译目录中的“staging/user-static/qemu-aarch64”复制到“update-binfmts”中显示的对应位置(/usr/bin/qemu-aarch64),如果必要的话,将这里的aarch64替换成你所要运行的程序架构。注意必须是相同位置!当我们启动为ARM或其他架构编译的应用程序时,系统会调用binfmts识别它的类型并调用之前注册的interpreter(如/usr/bin/qemu-aarch64)来“翻译”启动。在chroot下,依然会从这个路径中寻找。因此如果chroot后这个路径下找不到QEMU,启动任何程序都会报错No such file or directory。这个报错会有很多歧义,因此一定要自己确认一下QEMU确实在rootfs的“/usr/bin”目录中。

四、运行

sudo chroot . /bin/sh

到这里,我们就可以像在虚拟机中一样,通过shell运行这个chroot中的所有程序了!

1总结 Xxx not found 相关的问题

当我运行一个命令时,

# ./run_xxx_command

报一个错

@#@$@%:No such file or directory

我的第一反应肯定是怀疑自己。程序名称输错了?但又不对,我怎么可能这么蠢呢?一路摸爬滚打下来,我发现最蠢的还是这句模糊的报错信息。它会有很多歧义。

根据我的经验,这个报错会有以下四种原因。

  • 最容易想到的:要运行的命令不存在。
  • 动态链接器不存在。如下例,运行IDA的远程调试器。

运行objdump可以看到它需要哪个解释器来读取它。一般都是ld-xxxx.so

如果ld找不到的话,这程序能运行的概率就很小了。

  • QEMU解释器没找到。如果我们注册了binfmt却没有将qemu拷贝到“rootfs/usr/bin“中,chroot时也会报一样的错误——文件没找到。如果没有踩过这个坑,大概会很久找不出原因吧。
  • 动态链接库没找到。这种情况比较显而易见,因为他会告诉你哪个库没找到。

以后拿到一个新的固件包,只需要解压到一个文件夹里,把对应架构的qemu拷贝进去,直接运行命令chroot即可。遇到需要调试的程序,我们通过运行“qemu-aarch64 -g 2331 /path/to/binary”指定-g参数开启调试选项,也可以声明一个环境变量QEMU_GDB=2331,带上这个环境变量所启动的程序,都会自动开启GDB端口并等待调试器attach,调试起来是不是很方便呢?

参考资料:

[1]How can I chroot into a filesystem with a different architechture? - Stack Exchange https://unix.stackexchange.com/a/177122

[2]QEMU on Linux hosts https:// wiki.qemu.org/Hosts/Linux

[3]Build qemu-user-static from source code http://logan.tw/posts/2018/02/18/build-qemu-user-static-from-source-code/

内容编辑:物联网安全实验室 张浩然 责任编辑:肖晴

本文分享自微信公众号 - 绿盟科技研究通讯(nsfocus_research),作者:物联网安全

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-10-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 原创 | DIGI开发板救砖指南

    前段时间接到一个Ripple 20漏洞研究的任务,配套的设备为DIGI开发板,在研究过程中发生了悲剧的一幕——开发板变砖,为了能够继续顺利进行研究于是决定一定要...

    绿盟科技研究通讯
  • 透过隐私合规,看数据安全技术发展趋势

    近年来,全球掀起个人信息与隐私的立法热潮。欧盟2018实施GDPR,美国2020年实施CCPA,两部法规均对企业处理用户的数据提出更严、更具体的约束和要求;最近...

    绿盟科技研究通讯
  • 围绕PowerShell事件日志记录的攻防博弈

    【*绿盟科技M01N Team研究岗长期招聘CTF、Pentest、RE、PWN、WEB,请在文末进行了解!】

    绿盟科技研究通讯
  • Java Web技术经验总结(十三)

    阿杜
  • JVM性能分析神器-VisualVM

    JVM本身为我们提供了很多性能监控的工具,其中有基于命令行的也有基于图形用户界面的,而个人感觉VisualVM就是其中最优秀的一个工具。

    Java学习录
  • 干货 | 95后运维小哥20天+通过Elastic认证考试经验分享

    早上,收到95后的星友[在路上(昵称)]发的动态,得知其已经通过了Elastic认证考试。

    铭毅天下
  • Java正则速成秘籍(三)之见招拆招篇

    导读 正则表达式是什么?有什么用? 正则表达式(Regular Expression)是一种文本规则,可以用来校验、查找、替换与规则匹配的文本。 又爱又恨的正...

    静默虚空
  • 聊聊flink的slot.idle.timeout配置

    flink-release-1.7.2/flink-core/src/main/java/org/apache/flink/configuration/JobM...

    codecraft
  • Spray中的Authentication和JMeter测试

    Spray Authentication 在Spray中,如果需要对REST API添加认证,可以使用Spray提供的Authenticate功能。本质上,Au...

    张逸
  • 原创插件:网站收录查询和显示WordPress插件(自定义栏目优化版)

    十月底,张戈在博客分享了《WordPress 给文章添加百度是否已收录查询和显示功能(数据库优化版)》一文,反响不错!而且还被站长之家转载了,无奈多了个 nof...

    张戈

扫码关注云+社区

领取腾讯云代金券