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"消息,然后按正常方式输出目录列表。