了解链接的基本概念和链接过程所要完成的任务。
理解ELF目标代码和目标代码文件的基本概念和基本构成
了解ELF可重定位目标文件和可执行目标文件的差别
理解符号表中包含的全局符号、外部符号和本地符号的定义。
理解符号解析的目的和功能以及进行符号解析的过程。
每个实验阶段(共5个)考察ELF文件组成与程序链接过程的不同方面知识
阶段1:全局变量ó数据节
阶段2:强符号与弱符号ó数据节
阶段3:代码节修改
阶段4:代码与重定位位置
阶段5:代码与重定位类型
在实验中的每一阶段n(n=1,2,3,4,5…),按照阶段的目标要求修改相应可重定位二进制目标模块phase[n].o后,使用如下命令生成可执行程序linkbomb:
$ gcc -o linkbomb main.o phase[n].o [其他附加模块——见具体阶段说明]
正确性验证:如下运行可执行程序linkbomb,应输出符合各阶段期望的字符串:
$ ./linkbomb
$ 19210320303
实验结果:将修改后正确完成相应功能的各阶段模块(phase1.o, phase2.o, …)提交供评分。
Linux Ubuntu 18.04 64-bit
笔记本电脑
VMware虚拟机
先运行一遍
为了方便生成phase1.s文件
使用objdump -rd phase1.o查看elf文件内容,找到输出的.data 节中偏移量为32的位置。
使用readelf -a phase1.o命令查看phase1.o的ELF数据,
即在0x60+c=0x6c处,用hexedit phase1.o命令修改phase1.o找到0x6c处,修改0x6c+1的值为学号十六进制ASCII码。然后以ASCII码”00”结束字符。
修改的十六进制是:32 33 32 31 35 31 35 30 35 34 31
编译重新运行,正确输出学号
反汇编phase2,发现有两部分构成
Func函数主要是对数组做一些处理,处理之后返回给phase2函数
readelf -a phase2.o命令查看phase2.o的符号表
有个COM未被赋初始值,是个弱符号,根据文档提示打个补丁phase2_patch.o。里面的内容应该是cahr类型的大小为256的g_myCharArray变量的初始化,
得出偏移量为0xc
创建phase2_patch.c文件,创建一个g_myCharArray(弱符号),偏移量是0xb(12)所以前12个无用填0
采用两种方法
方法一:随机输入两个数35 35,发现打印出来的是/0,于是一个个慢慢推出来
方法二:先在phase2_patch.c填充大小为256个0
依次输入 gcc -c phase2_patch.c、gcc -no-pie main.o phase2.o phase2_patch.c、./a.out
因为我的学号是11位数,所以取最前面的11位“<=>?@ABCDEF”根据ASCII得到16进制的值
因此往phase2_patch.c填充偏移量12个0以及所得出来的字符:
\X26\X26\X24\X22\X25\X20\X23\X1D\X21\X1F\X1B
发现后面的框框不美观,于是在ASCII码找到null字符进行终止
先进行反汇编
Fun1输出函数,fun2是获取data数据,因此要将他们做一个结合调用
将所写的函数进行反汇编得到
得到text的地址码为:e8 00 00 00 48 89 c7 e8 00 00 00 00
打印文件格式:readelf -a phase3.o
找到偏移字段
查看反汇编
因此,在第60+D的位置可以看到
保存并退出,将其编译进.s文件
查看phase3.s,命令为:vim phase3.s
写进func2里的偏移:1b(myfunc2头)-36(第一个callq)=FFE5
写进func1里的偏移:0(myfunc1头)-3E(第二个callq)=FFC2
将他写进 phase3.o中
再次反汇编,命令
查看phase3.s文件
尝试编译输出,发现全都是XXXXX....
进入字符集,命令:readelf -a phase3.o
找到data字段,位置是01a0
找到位置加上偏移量,后移一位就是我们要修改的值:01A0+C=01AC+1=01AD
保存并退出ctrl+x,重新运行
查看phase4.o文件ELF数据,命令:readelf -a phase4.o
要修改上面全为0的偏移量
从↓可以看出
一个是变量:g_myCharArray
一个是变量:temp
还有一个:puts函数
且g_myCharArray是位于.data节中偏移量为0(即value值)处
temp是位于.data节中偏移量为0x14(即value值)处编译查看汇编代码
编译查看汇编代码:
截图避免待会需要,用objdump -d phase4.o查看汇编代码
观察可得
偏移量是要使变量和函数到这里
即0x6、0x11、0x19
0x18是call指令,所以它对应的是call puts函数。
要把这里的值设置为19
输入命令:Hexedit phase4.0,查看一下.rela.text段的开始是250
经过我的分析
偏移量、信息、是符号名称+加数的加数
这个是“第一组”的,以此类推可以找到”puts组”的位置,”FC FF FF FF FF FF FF”是-4的补码也验证了我们的计算
修改此处的偏移量为19
重新查看phase4.o文件的ELF数据
可以发现改对了
重新编译查看汇编代码
会发现变成了
现在还有两个偏移量要修改
这两个是数据,看下面是这两个变量的值
.data段在
一个在.data+0处,一个在.data+0x10处
前面有提到.data+0是g_myCharArray,那.data+0x10是temp
修改为学号
现在就要改对应的偏移量
可以看出0x6和0x11处
根据思考,0x11应该放学号数组,因为要赋值给%rdi传递给puts函数打印,0x6应该放temp
回到上面已经发现”.data+10”(temp)组偏移量是这里,修改为6
“.data+0”组偏移量是这里,修改为11
readelf -a phase4.o查看,修改正确
但是值有点错误
还有一个值没有修改
这里可以看出temp是一个位于.data节中偏移量为0x14处的。
从这里可以看出上面的.data+10并不是真的temp的值,而是.symtab里的value才是它的偏移量。
这里就是.data节偏移量为0x14处,改为”00”
保存退出重新运行,结果正确
编译查看汇编代码
查看一下ELF数据,命令:readelf -a phase5.o
这两个换换就好
找到偏移量,互换即可
这里可以看出g_myCharArray是一个位于.data节中偏移量为0x10处的。
.data在0x90处
g_myCharArray在0x90+0x10=0xA0处,修改为学号
编译运行,结果正确
通过此实验,我掌握了符号解析、符号定义分类、静态链接解析过程、符号表条目、重定位、动态链接、静态库的缺点、位置无关代码、数据和代码调用,还有的是关于地址的计算。基于ELF文件格式和程序链接过程的理解,修改给定二进制可重定位目标文件的数据内容、机器指令、重定位记录等部分。实验过程中,我遇到了一些困难和bug,但通过查询资料、搜索和自己思考,最后独立解决了问题。通过完成此次实验,不仅收获了许多知识,而且还锻炼了动手能力和解决问题的能力。解决问题,完成实验,感觉收获很多,也有一定的成就感。