网络空间攻防技术原理
上QQ阅读APP看书,第一时间看更新

2.2.3 二进制环境搭建

1.GCC及交叉编译环境

除了 Web 学习环境外,还需要搭建二进制相关赛题的学习环境,首先介绍二进制程序编译环境的搭建。在Ubuntu系统下,通常选择GCC(GNU Compiler Collection,GNU编译套件)作为编译器。GCC最初是一款GNU操作系统下的C语言程序编译器,由于它开放了源代码,因此开发人员可以自由地参与到对它的维护与更新中,这使得它快速发展。目前GCC 已经能够支持 C、C++、Objective-C、Fortran、Ada、Go 等高级程序设计语言,以及x86、ARM、MIPS等多种体系结构,并且可以在绝大多数类Unix操作系统(如BSD、macOS等)和一些其他操作系统(如Windows)上使用。

Ubuntu 20.04 LTS默认安装了GCC,可以通过执行命令“gcc -v”查看其版本及配置信息。但是,64位操作系统中的GCC默认只能编译64位的程序,需要通过执行下面的命令为其安装32位程序的适配库,使其能够编译32位的程序。

sudo apt install gcc-multilib g++-multilib module-assistant

安装完毕后,当需要编译32位的程序时,可以使用下面的命令。

gcc sourcecode.c -o binaryfile -m32

可以将上面的编译过程称为本地编译,也就是编译在当前体系结构的计算机上执行的程序。由于在CTF竞赛中可能涉及其他体系结构的可执行程序,因此还需要为GCC安装相应的交叉编译工具链,使其能够编译不同体系结构的程序。以64位的 ARM 体系结构为例,首先通过执行下面的命令查看可供安装的交叉编译工具链。

# sudo apt search aarch64 | grep gcc
gcc-10-aarch64-linux-gnu/focal-updates,focal-security 10.3.0-1ubuntu1~20.04cross1
amd64
gcc-10-aarch64-linux-gnu-base/focal-updates,focal-security
10.3.0-1ubuntu1~20.04cross1 amd64
gcc-10-plugin-dev-aarch64-linux-gnu/focal-updates,focal-security
10.3.0-1ubuntu1~20.04cross1 amd64
gcc-8-aarch64-linux-gnu/focal 8.4.0-3ubuntu1cross1 amd64
gcc-8-aarch64-linux-gnu-base/focal 8.4.0-3ubuntu1cross1 amd64
gcc-8-plugin-dev-aarch64-linux-gnu/focal 8.4.0-3ubuntu1cross1 amd64
gcc-9-aarch64-linux-gnu/focal-updates,focal-security  9.3.0-17ubuntu1~20.04cross2
amd64
gcc-9-aarch64-linux-gnu-base/focal-updates,focal-security
9.3.0-17ubuntu1~20.04cross2 amd64
gcc-9-plugin-dev-aarch64-linux-gnu/focal-updates,focal-security
9.3.0-17ubuntu1~20.04cross2 amd64
gcc-aarch64-linux-gnu/focal 4:9.3.0-1ubuntu2 amd64
gccgo-10-aarch64-linux-gnu/focal-updates,focal-security
10.3.0-1ubuntu1~20.04cross1 amd64
gccgo-8-aarch64-linux-gnu/focal 8.4.0-3ubuntu1cross1 amd64
gccgo-9-aarch64-linux-gnu/focal-updates,focal-security
9.3.0-17ubuntu1~20.04cross2 amd64
gccgo-aarch64-linux-gnu/focal 4:10.0-1ubuntu2 amd64

根据需要选择一个版本,假设是“gcc-aarch64-linux-gnu”,通过 apt 对其进行安装,并查看版本及配置信息。

交叉编译工具链安装完毕,可以用它来编译 arm64体系结构的程序。以下面的 C 语言代码为例。

/* sample_arm64.c */
#include <stdio.h>
int main() {
    printf("This is an arm64 program.\n");
    return 1;
}

交叉编译的方法与本地编译方法基本类似。分别进行静态编译和动态编译,并通过Linux的file工具查看得到的可执行程序文件,具体如下。

// 静态编译
# aarch64-linux-gnu-gcc -static sample_arm64.c -o sample_arm64_s
# file sample_arm64_s
sample_arm64_s: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux),
statically  linked,  BuildID[sha1]=5906a0e7fd294cfbda30eb59e27cb7267ac8de89,  for
GNU/Linux 3.7.0, not stripped
// 动态编译
# aarch64-linux-gnu-gcc sample_arm64.c -o sample_arm64_d
# file sample_arm64_d
sample_arm64_d: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically
linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=51e64a8461334e650ca0f
1930340e7c4643b7a72, for GNU/Linux 3.7.0, not stripped

编译成功,分别得到了64位的基于ARM体系结构的静态链接可执行程序sample_arm64_s和动态链接可执行程序sample_arm64_d,尝试运行这两个程序,具体如下。

# ./sample_arm64_s
-bash: ./sample_arm64_s: cannot execute binary file: Exec format error
# ./sample_arm64_d
-bash: ./sample_arm64_d: cannot execute binary file: Exec format error

两个程序均运行失败。容易想到,个人计算机并采用 ARM 体系结构,无法运行基于ARM 体系结构的程序。那么,既然能够在当前体系结构下编译其他体系结构的程序,能不能想个办法,让这些程序也能在当前体系结构下运行呢?答案是肯定的,这就是下面要讲的QEMU环境。

2.QEMU环境

QEMU 是开源跨平台二进制程序动态执行模拟器,它可以模拟 x86、ARM、MIPS、PowerPC 等多种体系结构的动态执行。QEMU 的原理是将可执行文件的二进制代码翻译为TCG 微操作形式的中间代码,再根据中间代码编译得到目标体系结构的二进制代码,最后执行这些新的二进制代码。对于基于ARM、MIPS等非当前体系结构的可执行程序,QEMU能够帮助读者方便地搭建模拟执行环境。

QEMU主要有两种模拟方式,即用户模式和系统模式。用户模式下的QEMU相当于一个进程级别的虚拟机,能够执行不同体系结构的二进制程序,在Ubuntu 20.04系统中可以通过执行命令“sudo apt install qemu-user”来安装;系统模式下的QEMU则能够模拟完整的操作系统,包括处理器及配套的外设等,在Ubuntu 20.04系统中,可以通过执行命令“sudo apt install qemu-system”来安装。在路径“/usr/bin”下可以通过执行“ls | grep qemu”命令查看QEMU能够支持且当前已经安装的体系结构。

QEMU 安装完毕后,一些静态链接的非当前体系结构的程序就可以成功运行了,例如我们之前编译的静态链接可执行程序sample_arm64_s,具体如下。

# qemu-aarch64 ./sample_arm64_s
This is an arm64 program.
# ./sample_arm64_s
This is an arm64 program.

无论是执行命令“qemu-arm ./sample_arm64_s”还是直接运行sample_arm64_s都没有问题,非常方便。然而,对于动态链接的可执行程序,上述方法仍无法成功,例如前面编译的动态链接可执行程序sample_arm64_d,具体如下。

# qemu-aarch64 ./sample_arm64_d
/lib/ld-linux-aarch64.so.1: No such file or directory

提示找不到文件“/lib/ld-linux-aarch64.so.1”,该文件是arm64体系结构所需要的动态链接库文件。事实上,当我们安装交叉编译工具链时,arm64体系结构所需要的库文件及头文件已经安装到/usr目录下,只需通过设置-L参数把路径告诉QEMU即可成功运行动态链接的可执行程序。

# qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./sample_arm64_d
This is an arm64 program.

小贴士:在没有安装交叉编译工具链的情况下,也可以单独为QEMU安装所需要的库文件及头文件。首先通过执行形如“sudo apt search libc6 | grep arm”的命令查看可供安装的库,然后通过执行如“sudo apt install libc6-arm64-cross”的命令安装所需要的库,之后可以在/usr目录下找到相应的文件夹。如果留心观察交叉编译工具链的安装情况,就会发现类似libc6-arm64-cross这样的库其实是作为交叉编译工具链的依赖项同时安装的。

在 QEMU 的用户模式下,不同体系结构的程序都可以按照类似上面的方法来运行,这正是QEMU为我们带来的方便之处。限于篇幅,关于QEMU的更多使用方法,尤其是它在系统模式下的使用,这里就不再展开介绍了,读者可以自行查阅 QEMU 使用文档。现在,已经得到了一个完整的、可跨平台的二进制学习环境,该环境能够支持编写、编译及运行不同体系结构的可执行程序。

3.Docker环境

通过前面的学习可以发现,搭建二进制程序的编译及运行环境是比较复杂的,即使在GCC和QEMU的帮助下,这仍然不是一件很容易的事情。在一些CTF竞赛中,为了避免将宝贵的时间耗费在复杂的环境搭建上,可能采用Docker来发布CTF竞赛题目或提供运行环境,下面简单介绍Docker的安装及使用。

Docker 是一个开源的容器化平台,它允许构建、测试并作为可移动的容器去部署应用程序。一个 Docker 就是一个应用程序的运行环境,包含程序运行所需要的所有依赖条件,并且可以在任何系统上运行。显然,使用 Docker 将极大地方便我们快速部署各种程序运行环境。

一般推荐从仓库安装到更新 Docker,与包管理工具的更新源类似,使用国内的 Docker仓库能够更好地保证安装的速度和稳定性。以某大学的 Docker 仓库为例,可以通过执行下面的命令来安装Docker。

// 安装依赖项
sudo apt install ca-certificates curl gnupg lsb-release
// 信任 Docker 的 GPG 公钥
curl -fsSL https://download.×××.com/linux/ubuntu/gpg | sudo apt-key add
// 添加 Docker 仓库
sudo add-apt-repository "deb [arch=amd64] \
  https://mirrors.tuna.×××.edu.cn/docker-ce/linux/ubuntu \
  $(lsb_release -cs) stable"
// 安装 Docker
sudo apt install docker-ce

安装完毕后,尝试执行命令“sudo docker run hello-world”,出现下面的提示表明安装成功。

# sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:cc15c5b292d8525effc0f89cb299f1804f3a725c8d05e158653a563f15e4f685
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
...

在默认情况下,必须具有sudo权限才能够执行Docker命令,用起来不够方便。为了简化操作,可以通过执行命令“sudo usermod -aG docker $USER”将当前用户添加到Docker用户组中,其中docker即Docker用户组,它是在Docker的安装过程中自动创建的,$USER代表当前用户的环境变量。重启Ubuntu系统以刷新用户组信息,之后无须提供sudo权限就可以直接执行Docker命令了。

关于Docker的更多使用方法,可以查阅Docker使用文档。

其他二进制相关赛题可能用到的工具还包括静态分析工具、动态调试工具及一些辅助工具等,它们的安装及使用后续再进行讲解。现在,读者已经搭建好一个最基本的 CTF 学习环境,是时候来尝试拿下“First Blood”了。