计算机基础实验五:程序链接和ELF
实验前的准备:下载相关tar包并解压
链接和ELF实验:静态数据与ELF数据节
实验内容:
本实验的内容:
实验要求:
更改每个阶段可执行文件的输出。
事例:
(第一次编译报错的原因是Linux架构和main.o和phasel.o不一样,后者是i386,需要使用-m32选项指定使用 i386 架构编译目标文件)
运行:
相关知识点:
链接的本质是合并相同的节。
链接的过程:
可重定位目标文件:
可重定位目标格式:
ELF文件:
可执行目标文件:
可重定位文件和可执行文件的区别:
可执行文件存储器映像:
每个重定位的结构:
实验工具:
readelf:
常用选项:
readelf使用案例:
-S选项打印各个节(节头表)的信息。
Ndx可以对应节头表的Nr确定改符合位于哪个节当中。Bind是访问属性。
r选项显示重定位信息:
-
x选项显示指定模块的指定节内容:
(每一行显示了该节的16字节的内容, 最左边的4字节是指定节的偏移量。最右边是把数据内容中每一字节的值ASCLL码解释出来。
hexedit工具的使用:
使用hexedit main.o后:
左边的4字节是便宜量,中间是显示二进制的内容,最右边是把中间显示的文件内容每一字节可用ascll码的就解释出来,不可的用.代替。
光标停留的位置直接输入想修改的的内容。修改结束后用ctrl+x保存修改内容。ctrl+c不保存退出。
实验过程:
1.获取phase1.o的汇编代码:
2.获取phase1.o目标模块中的重定位记录:
3.分析phase1.o汇编代码:
(call指令)
要确定call指令调用的是哪个函数要结合phase1.o的重定位记录。
call常采用的是绝对地址重定位,call后面的10就是偏移量,由于call的重定位信息存在.rel.text中,可以知道call重定位信息为:
可以看出puts函数采用的是PC相对地址重定位方式。
确定data节在phase节中的位置:
获取节头表:
(可以看出data节的偏移地址是0x60,结合前面重定位的分析输出字符串的地址相对与data节起始地址的偏移量是:0x79;输出字符串的起始地址:0x60+0x79=0xd9;
使用hexedit工具对该位置开始的内容修改:
查看data节数据:
对比输出:对比偏向量0x79发现输出没有问题
(选中的内容就是输出的字符串,输出的字符串以00接着说一看到0x00就可以判断此处为字符串的结束位置。(0x00对应的字符串不打印)
修改:data节的起始地址是0x60,其中输出字符串相对于data节的偏移量是0x79,那么输出字节地址为0x60+0x79=0xd9;
(上图中黄色的部分就是输出字符串的起始地址)从起始位置修改字符串最后以0x00结尾,实现swpu-202131061114的输出;注意修改的ascll码用16进制
重新链接输出:
指令和ELF代码节:
实验内容:
实验过程:
1.获取phase2.o的汇编代码:
部分汇编代码:
2.获取phase2.o的重定位记录:
3.在phase2,o的代码节中中找到类似put的输出函数:(结合call的偏移地址和重定位信息表)
(可以看出这个call的偏移量是c4,按照重定位信息发现偏移量c4中是puts函数,也即后面的AFPQyocF处)
可以在do_phase中修改nop指令实现对AFPQyocF函数的调用,从而实现对目标字符串的输出。
4.查找输出函数AFPQyocF在.text节中的的偏移量:
(AFPQy0cF的Ndx为1,在节头表中查找到Nr为1的是.text,所有此函数位于,.text节中)
结合上面2图可以得出该函数位于.text节中偏移量为0xa0处。同时该函数利用objdump反汇编的汇编代码中函数前也给出了该函数在所在节的偏移量。
5.构造调用上面函数的指令代码:
分析函数执行逻辑:(结合汇编代码和重定位信息表分析)
该函数先利用strcmp函数比较2个字符串的长度,然后将返回值(相同返回0,不同返回非0)送到eax寄存器中,
如果eax的值不为0就执行jne指令,为0就执行puts要输出的参数入栈执行put函数。
查看重定位表可以看出strcmp的其中一个参数位于.rodata节中,其相对与.rodata节的偏移地址分别为:0x2;
**查找该参数的内容: **
也即这个参数和第一个参数比较。
(是AFP…的第一个参数)分析上面可知:如果要输出学号,那么传递给AFP…的第一关参数是yksPHJa,第二个参数是学号。
构造指令代码:
sub $0x28,esp
mov1 $0x50736b79,-0x10(ebp)
mov1 $0x614a48,-0xc(%ebp)
mov1 $0x31323032,-0x1a(8ebp)
mov1 $0x36303133,-0x16(%ebp)
movw $0x34313131,-0x12(%ebp)
sub $0x8,esp
lea -0x1a(ebp),%eax
push %eax
lea -0x10(%ebp),%eax
push %eax
call 0x00
add $0x10,%esp
nop
leave
ret
将上述代码写入ins.s中并把其编译为可重定位目标文件
(注意这里要在头文件出加.code32,统一格式)
(这里的格式是x86-64需要转换格式)
inst.s的汇编内容:
(中间的指令就是要插入到phase2.o中do_phase函数体中替换nop的内容也就是0x90,)
6.获取目标模块机器码的插入位置:
(.text节在phase.o中的偏移量为0x34)
(首个nop指令在.text节中的偏移量是0xd3)插入机器码在文件中的起始偏移量为:0xd3+0x34=0x 107
7.使用hexedit工具修改:
注意在填写call指令的二进制的时候其后的二进制要修改使其可以相对pc寻址。修改为:
oxa0-(0xd3+0x36)=ffffff97
修改后的:
8.链接编译:
总结:
test指令:test 是一种汇编指令,它用于对两个操作数进行按位 AND 运算,并设置相应的标志位。test 指令的语法通常为:test dest, src;
less查看文件时输入:”/'起到查找的内容。