-
-
[翻译]为编程和逆向搭建RISC-V开发环境
-
发表于: 2022-5-7 17:30 13865
-
原文链接
作者:Rog3rSm1th
译者:阳春
翻译时间:2022/5/7
译者注:转载清注明作者、译者和出处
本文记录我如何在我的机器上为开发RISC-V汇编程序和分析RISC-V恶意软件而搭建RISC-V开发环境
首先,何为RISC-V?
RISC-V是起源于加州伯克利大学2010年的一个项目的开放标准的指令集,基于精简指令集原则(RISC)设计。不像其他的大多数指令集,RISC-V是开源且免费的。
有很多基于此指令集的应用,粗略列一下:
- 欧盟启动基于RISC-V的超级计算机项目,称为欧洲处理器计划(EPI)
- 中科院2021年6月宣布将于2022年底前建造2000台基于RV64GC的笔记本
- 为AI应用优化的低功耗RISC-V IoT处理器
- 阿里巴巴公布基于RISC-V的处理器
看到它在关键领域的日益增长,让我对其安全性非常感兴趣,因此我将来在这个博客上的文章会主要关注在RISC-V架构的安全研究,包括linux系统上的RISC-V恶意软件分析。
尽管我特别想要买一块开发板来促进我的研究,但是鼓捣这个架构的时候没找到合适的。所以我不得不在我的非RISC-V机器上设置开发环境,这就是本系列的第一个课题。
我想展示一下在没有RISC-V机器的情况下我是怎么样搭建环境快捷开发RISC-V汇编程序的。
- 我将会如何构建我的环境
- 下载Debian RISC-V 64位镜像
- 使用
QEMU
模拟RISC-V
机器 - 创建宿主机和虚拟机之间的共享文件夹
- 在宿主机上安装调试和编译工具
a.GDB
b.GCC
c.Radare2
- 示例
- 结论
- 拓展阅读
我将会如何构建我的环境
先盘点我将需要的东西:
- 一个
Debian
64位镜像,我比较了解这个linux发行版。我也可以用Fedora
,它也有个RISC-V版本 - 一个脚本文件夹,用于存放执行重复动作的脚本。(汇编代码编译,执行配置等等)
- 一个共享文件夹,用于宿主机和虚拟机之间共享文件。
- 一个代码文件夹,用用存放我写的汇编程序
可以得到如下的文件目录
1 2 3 4 5 6 7 8 9 | . / RISC - V_Setup ├── image │ └── Debian image ├── scripts │ └── All the useful scripts (run.sh, compile .sh...) ├── share │ └── Share directory between HOST (my computer) and GUEST machine (RISC - V emulator) ├── src │ └── Directory where I write RISC - V assembly code |
下载Debian RISC-V 64位镜像
我会创建一个image
文件夹并下载一个编译好的RISC-V
64位Debian
镜像
1 2 | mkdir image wget https: / / gitlab.com / api / v4 / projects / giomasce % 2Fdqib / jobs / artifacts / master / download?job = convert_riscv64 - virt" - O . / image / debian - rv64. zip |
接下来在./image
解压它
默认的用户名密码是
debian:debian
和root:root
使用QEMU模拟RISC-V机器
用词说明:接下来我会称主机为
宿主机
(host),QEMU虚拟机为客户机
(guest)。
-> 我们使用QEMU来模拟RISC-V处理器,为此需要执行 sudo apt-get install qemu-system-riscv64
安装 qemu-system-riscv64
我们使用64位的版本作为示例,当然需要32位RISC-V处理器的时候也可以安装
qemu-system-riscv32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | qemu - system - riscv64 \ - machine virt \ - cpu rv64 \ - m 1G \ - device virtio - net - device,netdev = net \ - netdev user, id = net,hostfwd = tcp:: 2222 - : 22 \ - device virtio - blk - device,drive = hd \ - drive file = . / Image / artifacts / overlay.qcow2, if = none, id = hd \ - bios / usr / lib / riscv64 - linux - gnu / opensbi / generic / fw_jump.elf \ - kernel / usr / lib / u - boot / qemu - riscv64_smode / uboot.elf \ - append "root=LABEL=rootfs console=ttyS0" \ - nographic \ - fsdev local,security_model = passthrough, id = fsdev0,path = . / share \ - device virtio - 9p - pci, id = fs0,fsdev = fsdev0,mount_tag = hostshare |
我想你可能需要理解一下这个脚本
1 | - cpu rv64 |
-> 我们选择一个RISC-V 64位cpu
1 | - m 1G |
-> 为客户机分配1GB运行内存
这个值取决于你需要并且能够分配的内存大小。
1 | - netdev user, id = net,hostfwd = tcp:: 2222 - : 22 : |
-> 这一行转发22端口到localhost:2222。这样可以在外面远程SSH连接。
1 | - bios / usr / lib / riscv64 - linux - gnu / opensbi / generic / fw_jump.elf \ |
-> 如果需要,可以指定自己的OpenBSI
位置。但是要确保是一样的配置。
1 | - append "root=LABEL=rootfs console=ttyS0" \ |
-> append参数为UNIX衍生版的内核命令行添加额外选项。
1 | - kernel / usr / lib / u - boot / qemu - riscv64_smode / uboot.elf \ |
-> 我的U-Boot镜像路径
1 | - nographic |
-> 这个参数可以完全禁用图形输出,这样QEMU就是个简单的命令行应用
1 2 | - fsdev local,security_model = passthrough, id = fsdev0,path = . / share \ - device virtio - 9p - pci, id = fs0,fsdev = fsdev0,mount_tag = hostshare |
-> 这两行允许我们在宿主机和客户机之间创建一个普通的文件夹
创建共享文件夹
我知道有些人喜欢用scp
来通讯。不过我比较喜欢使用共享文件夹.
-> 在客户机上执行这个脚本
1 2 3 4 5 | SHARED_FOLDER = "/mnt/share" # Create shared folder mkdir ${SHARED_FOLDER} mount - t 9p - o trans = virtio,version = 9p2000 .L hostshare ${SHARED_FOLDER} |
这样宿主机上面./share的内容就和客户机上的 /mnt/share 保持一致了。
安装调试和编译工具
为了逆向,我时常需要一个调试器分析二进制代码的行为。我比较熟悉 GDB 和 Radare2 ,我将展示如何在此处使用他们。
我们从安装RISC-V GNU工具链开始,它包含我们最喜欢的调试器GDB,以及其他好用的工具,比如汇编器和连接器。安装手册在这里。
GDB
我们可以这样调试RISC-V二进制文件
1 | $ ~ riscv64 - unknown - elf - gdb binary |
GCC
如果你想使用gcc
为RISC-V架构编译二进制文件,可以使用这个命令
1 | $ ~ riscv64 - unknown - elf - gcc - ggdb - static - o binary binary.c |
Radare2
Radare2
内置了RISC-V支持,很牛逼。
执行普通的命令就可以进行普通地分析.
1 | $ ~ r2 . / riscv - binary |
示例
-> 先快速过一下目录结构
1 2 3 4 5 6 7 | . / RISC - V_Setup ├── share │ └── Shared directory between HOST (my computer) and GUEST machine (RISC - V emulator) ├── src │ └── Directory where I write RISC - V assembly code ├── ... │ └── ... |
我们的汇编代码会放在./src
文件夹,编译后的文件放到./share
文件夹,这样客户机可以访问到。这里我们创建一个 program.s
文件,写点“Hello world”
RISC-V汇编代码。(程序世界的开端总是Hello world :D)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # # Risc-V Assembler program to print "Hello World!" # to stdout. # # a0-a2 - parameters to linux function services # a7 - linux function number # . global _start # Provide program starting address to linker # Setup the parameters to print hello world # and then call Linux to do it. _start: addi a0, x0, 1 # 1 = StdOut la a1, helloworld # load address of helloworld addi a2, x0, 13 # length of our string addi a7, x0, 64 # linux write system call ecall # Call linux to output the string # Setup the parameters to exit the program # and then call Linux to do it. addi a0, x0, 0 # Use 0 return code addi a7, x0, 93 # Service command code 93 terminates ecall # Call linux to terminate the program .data helloworld: .ascii "Hello World!\n" |
接下来我们要在宿主机上为64位RISC-V架构交叉编译这段代码。为此我们会用到RISC-V GNU 编译器工具链包含的几个工具。
- 我们用
riscv64-linux-gnu-as
编译程序 - 用
riscv64-linux-gnu-ld
连接obj
文件生成可执行文件
我写了个自动化脚本(放在./script
)
1 2 3 4 5 6 7 8 9 | #!/bin/bash ASSEMBLY_DIR = "$(dirname $0)/../src" SHARE_DIR = "$(dirname $0)/../share" riscv64 - linux - gnu - as - march = rv64imac - o ${SHARE_DIR} / program.o ${ASSEMBLY_DIR} / program.s riscv64 - linux - gnu - ld - o ${SHARE_DIR} / program ${SHARE_DIR} / program.o rm ${SHARE_DIR} / program.o chmod + x ${SHARE_DIR} / program |
执行一下
1 | $ ~ . / scripts / compile .sh |
现在在/mnt/share
文件夹生成了一个叫 program
的可执行程序。
-> 测试一下
1 2 | debian@debian: / mnt / share$ . / program Hello World! |
可以了!
现在可以在宿主机上用 riscv64-unknown-elf-gdb
或者 Radare2
调试它。
结论
这就是我在linux下搭建的RISC-V架构逆向研究环境的过程了。希望能对没有RISC-V机器,但是想要开发RISC-V汇编器或者逆向RISC-V程序的人有所帮助。安装指令开源在这里。任何问题和建议欢迎通过邮箱联系我。也可以关注我的推特 @Rog3rSm1th
。
希望您能喜欢这篇文章。
拓展阅读
赞赏
- [翻译]渗透测试备忘单 17994
- [翻译]为编程和逆向搭建RISC-V开发环境 13866
- [翻译]状态机的状态 11025
- [原创]看雪CTF.TSRC 2018 团队赛 第一题 初世纪 writeup 2924
- [原创]京东AI CTF大挑战Writeup 7195