ELF-Code-Injection-Technology

实验目的

学习几种将代码注入现有 ELF 二进制文件的基本技术,从而允许修改或者扩展二进制文件的行为。

实验原理

使用常用分析工具。

实验环境

1. 使用 binary 虚拟机,即在 Lab 2 中已经配置过的环境(包括时间戳)。

2. 实验所需文件位于/home/binary/code/chapter7 目录。

Task 1:使用十六进制编辑器修改 Bare-Metal 二进制文件

观察 off-by-one 漏洞

步骤:

1、输入 gcc -o xor_encrypt.c xor_encrypt.c 指令编译出可执行文件xor_encrypt。

2、输入 ./xor_encrypt xor_encrypt.c encrypted foobar 指令,将文件xor_encrypt.c加密为文件encrypted。

3、输入 xxd xor_encrypt.c | tail 指令,查看文件xor_encrypt.c。

4、输入 xxd encrypted | tail 指令,查看文件encrypted。

输出结果

观察输出结果可以对比发现,只有最后一个字节 0x0a 未被加密。

修复 off-by-one 漏洞

步骤:

1、查找导致漏洞的字节:输入 objdump -M intel -d xor_encrypt 指令反汇编二进制文件。

输出结果

由输出结果发现与指导书不同,在 0x400b11 处发现了 test 指令,可以得知我们需要将 0x400b34 处的 jne 指令改为 jae 指令。

2、替换违规字节:输入 make 指令和 hexedit xor_encrypt 指令在十六进制编辑器中打开 xor_encrypt。按 \ 健,输入 75ea 查找 jne 指令,将其改为 73ea,即 jae 指令。

输出结果

输出结果

输入 objdump -M intel -d xor_encrypt 指令反汇编经过修改的二进制文件,发现0x400b34 处的 jne 指令已经被改为 jae 指令。

输出结果

输入 ./xor_encrypt xor_encrypt.c encrypted foobar 和 xxd encrypted | tail 指令,发现 encrypt 的最后一个字节也被加密了,且前面的字节与修改前完全一致。

输出结果

Task 2:使用 LD_PRELOAD 修改共享库行为

堆溢出漏洞

步骤:

1、输入 ./heapoverflow 13 'Hello world!' 指令,正常输出。

2、输入 ./heapoverflow 13 'perl -e 'print "A"x100'' 指令,发现程序崩溃。

输出结果

Q:根据执行结果,程序出现崩溃的具体原因是什么?

A:根据执行结果,程序尝试执行 free() 函数,由于内存分配或释放过程中出现了问题,导致了 free(): invalid next size (fast) 错误。而程序接收了命令行参数 13 和 "A"x100 作为输入,输入的100个 "A" 太长导致堆溢出。

修复堆溢出漏洞

输入 LD_PRELOAD='pwd'/heapcheck.so ./heapoverflow 13 'perl -e 'print "A"x100'' 指令,在启动 heapoverflow 程序时,改变LD_PRELOAD 环境变量的定义,这使得链接器预加载指定的库文件 heapcheck.so,成功检测到不安全的复制行为,输出错误,并安全地终止程序,因此程序没有崩溃。

输出结果

Task 3:注入代码节(Code Section)

步骤:

1、输入 ls hello.bin 指令,查看文件 hello.bin。

2、输入 ./elfinject 指令查看 elfinject 的使用方法。

3、输入 cp /bin/ls . 指令使用 /bin/ls 的副本作为主体二进制文件。

4、输入 ./ls 指令发现注入之前表现正常。

5、输入 readlf --wide --headers ls 指令查看 ls 的头部信息。

输出结果

6、输入 ./elfinject ls hello.bin ".injected" 0x800000 0 指令将 hello.bin 文件注入 ls 二进制文件中,将节附加到二进制文件的尾部。

7、输入 readelf --wide --headers ls 指令显示 ls 二进制文件现在包含了一个名为 .injecte 的代码节,以及包含此节的 PT_LOAD 类型的新可执行段。

输出结果

输出结果

8、输入 ./ls 指令发现二进制文件现在启动时会运行注入的代码,输出 hello world!
消息;然后,注入的代码将执行权交还给文件的原始入口点,以便恢复输出目录列表的正常行为。

输出结果

Task 4:调用注入的代码

入口点修改

步骤:

1、输入 gedit hello.s 指令打开 hello.s 文件,发现原始入口点为 0x4049a0。

输出结果

2、输入 nasm -f bin -o hello.bin hello.s 指令将 hello.s 汇编到原始二进制文件hello.bin中。

3、输入 cp /bin/ ls.entry 指令 将/bin/ls 二进制文件复制到 ls.entry。

4、输入 ./elfinject ls.entry hello.bin ".injected" 0x800000 -1 指令将刚刚准备好的代码注入加载地址为 0x800000 的二进制文件中。

5、输入 readelf -h ./ls.entry 指令查看 ls.entry 的头部信息,可以看到二进制文件的原始入口点 0x4049a0。

输出结果

6、输入 readelf --wide -S ls.entry 指令可以看到 0x800e78 是新地址。

输出结果

7、输入 ./ls.entry 指令发现与正常的 ls 指令一致。

8、输入 hexedit ./ls.entry 指令打开十六进制编辑器,按 \ 健,由于是小端编码,于是我们输入 a04940 查找原始入口点,将其改为780e80。

输出结果

9、输入 readelf ./ls.entry 指令查看 ls.entry 的头部信息,可以看到二进制文件的原始入口点 0x800e78。

10、输入 ./ls.entry 指令会在显示目录列表之前输出 "hello world"。此时已成功覆盖了入口点。

输出结果

劫持构造函数和析构函数

步骤:

1、输入 nasm -f bin -o hello-ctor.bin hello-ctor.s 指令将 hello-ctor.s 汇编到原始二进制文件hello-ctor.bin中。

2、输入 cp /bin/ls ls.ctor 指令 将/bin/ls 二进制文件复制到 ls.ctor。

3、输入 ./elfinject ls.ctor hello-ctor.bin ".injected" 0x800000 -1 指令将刚刚准备好的代码注入加载地址为 0x800000 的二进制文件中。

4、输入 readelf --wide -S ls.ctor 指令可以看到 0x800e78 是新地址。

输出结果

5、输入 hexedit ls.ctor 指令打开十六进制编辑器,按 \ 键,由于是小端编码,于是我们输入 a04940 查找原始入口点,将其改为 780e80。

输出结果

6、输入 objdump ls.ctor -s --section=.init_array 指令查看 .init_array 节的内容。

7、输入 ./ls.ctor 指令发现先显示"hello world"消息,然后按正常方式输出目录列表。

输出结果