首页
社区
课程
招聘
[翻译]为编程和逆向搭建RISC-V开发环境
发表于: 2022-5-7 17:30 13810

[翻译]为编程和逆向搭建RISC-V开发环境

2022-5-7 17:30
13810

原文链接
作者:Rog3rSm1th
译者:阳春
翻译时间:2022/5/7
译者注:转载清注明作者、译者和出处

本文记录我如何在我的机器上为开发RISC-V汇编程序和分析RISC-V恶意软件而搭建RISC-V开发环境

首先,何为RISC-V?

RISC-V是起源于加州伯克利大学2010年的一个项目的开放标准的指令集,基于精简指令集原则(RISC)设计。不像其他的大多数指令集,RISC-V是开源且免费的。

 

有很多基于此指令集的应用,粗略列一下:

看到它在关键领域的日益增长,让我对其安全性非常感兴趣,因此我将来在这个博客上的文章会主要关注在RISC-V架构的安全研究,包括linux系统上的RISC-V恶意软件分析。

 

尽管我特别想要买一块开发板来促进我的研究,但是鼓捣这个架构的时候没找到合适的。所以我不得不在我的非RISC-V机器上设置开发环境,这就是本系列的第一个课题。

 

我想展示一下在没有RISC-V机器的情况下我是怎么样搭建环境快捷开发RISC-V汇编程序的。

  1. 我将会如何构建我的环境
  2. 下载Debian RISC-V 64位镜像
  3. 使用QEMU模拟RISC-V机器
  4. 创建宿主机和虚拟机之间的共享文件夹
  5. 在宿主机上安装调试和编译工具
    a. GDB
    b. GCC
    c. Radare2
  6. 示例
  7. 结论
  8. 拓展阅读

我将会如何构建我的环境

先盘点我将需要的东西:

  • 一个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:debianroot: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

 

希望您能喜欢这篇文章。

拓展阅读


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-5-9 11:11 被阳春编辑 ,原因: 添加链接
收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//