接上文《谜题:打造极小ELF文件输出文件(通过C语言来实现)》
在本篇中,我们要写出一段直接通过系统调用的方式、且使用尽可能少的指令的汇编代码来实现目标。
- 可以省略的代码,就省略。例如,在准备系统调用的参数时,若寄存器中已有需要的内容,则无需重复赋值。
- 能使用低位寄存器,就使用低位寄存器。例如,假设
rax
已经清空,赋值一个小于,就可以给al
赋值,可节省相应的机器指令长度。 - 系统调用
sys_exit
的返回值可以不为零。
根据以上思路,经过一番努力,我们得到了以下汇编代码。
open.s
.section .bss
.equ bufSIZE, 65535
.lcomm buf, bufSIZE
.section .text
.globl _start
_start:
// 2 sys_open(const char *filename, int flags, int mode)
//xor %rax, %rax
mov $0x2, %al
mov 16(%rsp),%rdi;
//mov $0x0, %rsi
syscall
// 0 sys_read(unsigned int fd, char *buf, size_t count)
mov %rax, %rdi
xor %rax, %rax
mov $buf, %esi
mov $bufSIZE, %dx
syscall
// 1 sys_write(unsigned int fd, const char *buf, size_t count)
mov %rax, %rdx
xor %rax, %rax
mov $0x1, %al
xor %rdi, %rdi
mov $0x1, %dil
syscall
// 3, sys_close(unsigned int fd)
xor %rax, %rax
mov $0x3, %al
syscall
// 60, sys_exit(int error_code)
mov $0x3c, %al
//xor %rdi, %rdi
syscall
通过as命令汇编,ld命令链接,我们得到了64位ELF格式的可执行文件,大小952字节。
[root@i-a77ugr2f tmp]# as open.s -o open.o
[root@i-a77ugr2f tmp]# ld open.o -o open
[root@i-a77ugr2f tmp]# ll open
-rwxr-xr-x 1 root root 952 Nov 6 22:48 open
[root@i-a77ugr2f tmp]# ./open /etc/passwd
# 可以正常输出
通过查阅资料发现,节区表对ELF可执行文件的运行是没有任何影响的,因此可以直接删除。这里我们使用现成的工具sstrip
来实现。
# 编译安装sstrip
[root@i-a77ugr2f tmp]# git clone https://github.com/BR903/ELFkickers
[root@i-a77ugr2f tmp]# cd ELFkickers/sstrip/
[root@i-a77ugr2f tmp]# make
[root@i-a77ugr2f tmp]# cp sstrip /usr/bin/
# 删除ELF可执行文件的节区表
[root@i-a77ugr2f tmp]# sstrip open
[root@i-a77ugr2f tmp]# ll open
-rwxr-xr-x 1 root root 232 Oct 19 11:15 open
[root@i-a77ugr2f tmp]# ./open /etc/passwd
# 可以正常输出
到这里,我们获得了一个232字节
的ELF可执行文件。