前言

该实验内容对应的是“第7章 链接”。官方是没有这个实验的,是学校下发的。

有需要的人可以下载源文件:《深入理解计算机系统》实验Link Lab源文件(包含源文件和文档和答案)。

文档在下面,源文件里面我也放了。

因为是挺久之前写的,我就直接把报告上的解题过程写在下面了,不重新在做一遍了。

实验文档

实验内容

每个实验阶段(共5个)考察ELF文件组成与程序链接过程的不同方面知识

  1. 阶段1:全局变量数据节
  2. 阶段2:强符号与弱符号数据节
  3. 阶段3:代码节修改
  4. 阶段4:代码与重定位位置
  5. 阶段5:代码与重定位类型

在实验中的每一阶段n(n=1,2,3,4,5…),按照阶段的目标要求修改相应可重定位二进制目标模块phase[n].o后,使用如下命令生成可执行程序linkbomb:
$ gcc -o linkbomb main.o phase[n].o [其他附加模块——见具体阶段说明]
正确性验证:如下运行可执行程序linkbomb,应输出符合各阶段期望的字符串:
$ ./linkbomb
$ 1801010616 [仅供示例,具体目标字符为每位学生学号]
实验结果:将修改后正确完成相应功能的各阶段模块(phase1.o, phase2.o, …)提交供评分。

实验步骤

1.实验数据

学生实验数据包: linklab学号.tar
数据包中包含下面文件:
main.o:主程序的二进制可重定位目标模块(实验中无需修改)
phase1.o, phase2.o, phase3.o, phase4.o, phase5.o:各阶段实验所针对的二进制可重定位目标模块,需在相应实验阶段中予以修改。
解压命令:tar xvf linklab学号.tar

2. 实验工具

readelf:读取ELF格式的各.o二进制模块文件中的各类信息,如节(节名、偏移量及其中数据等)、符号表、字符串表、重定位记录等
objdump:反汇编代码节中指令并提供上述部分类似功能
hexedit:编辑二进制文件内容

实验阶段1

要求:修改二进制可重定位目标文件“phase1.o”的数据节内容,使其与main.o链接后能够运行输出(且仅输出)自己的学号:

linux>gcc -o linkbomb main.o phase1.o -no-pie
linux>./linkbomb
学号

实验提示:
检查反汇编代码,获得printf(根据情况有可能被编译时转换为puts)输出函数的参数的(数据节中)地址 。
使用hexedit工具(或自己编写实现二进制ELF文件编辑程序),对phase1.o数据节中相应字节进行修改。

实验阶段2

要求:根据强符号与弱符号的原则,判断符号表中的符号以及其所对应的数据区域。利用符号解析规则,创建生成一个名为“phase2_patch.o”的二进制可重定位目标文件(可以不修改phase2.o模块),使其与main.o、phase2.o链接后能够运行和输出(且仅输出)自己的学号:

linux>gcc -o linkbomb main.o phase2.o phase2_patch.o -no-pie
linux>./linkbomb
学号

实验提示:
Phase2.o模块的符号表中,包含了类型为COM的符号。此类符号的特点是:未被赋初值。所以,其在ELF的数据节中并不真实存在。所以需要另寻解决办法,创造出真实存在的数据并对其进行二进制编辑,以达到输出自己学号的目的。
解题需要运用的主要知识为强弱符号的解析规则。另外,层序中包含了一个数值转换过程,学生需要根据反汇编代码确定其修改规则,并根据修改规则进行“反制”。

实验阶段3

要求:修改二进制可重定位目标文件“phase3.o”的代码节内容,使其与main.o链接后能够运行输出(且仅输出)自己的学号:

linux>gcc -o linkbomb main.o phase3.o -no-pie
linux>./linkbomb
学号

实验提示:
检查反汇编代码,定位模块中的各组成函数并推断其功能作用。 根据反汇编程序的执行逻辑,修改函数中的机器指令(用自己指令替换函数体中的nop指令)以实现期望的输出。
为了实现输出功能,自行编写获得的二进制程序(可以通过编写汇编代码然后使用gcc -c命令的方式实现)可以“借用”其他函数中的“有用代码或数据”,比如输出函数和数据引用等具体部分。

实验阶段4

要求:修改二进制可重定位目标文件“phase4.o”中重定位节和数据节中的内容,使其与main.o链接后能够运行输出(且仅输出)自己的学号:

linux>gcc -o linkbomb main.o phase4.o -no-pie
linux>./linkbomb
学号

实验提示:
本阶段学生所拿到的.o文件中的“重定位位置”信息已经被抹除,学生需要根据实际情况确认冲重定位的发生位置,并根据重定位类型对位置信息进行恢复。若程序未能够正确修改重定位位置,则典型问题表现为段错误segmentation fault。此外,还需要学生根据程序所用到的数据情况进行数据部分的二进制修改。

实验阶段5

要求:修改二进制可重定位目标文件“phase5.o”中重定位节和数据节的内容,使其与main.o链接后能够正确输出(且仅输出)自己学号:

linux>gcc -o linkobmb main.o phase5.o -no-pie
linux>./linkbomb
学号

实验提示:如果实验中对缺失重定位信息的恢复不完整或不正确的话,链接生成linkbomb程序时可能不报错,但运行程序可能得不到正确结果。

第一题

先编译运行看看
在这里插入图片描述
使用readelf -a phase1.o命令查看phase1.o的ELF数据
在这里插入图片描述
可以看到g_data的全局变量在[3]处,即.data处,用到的偏移量是0xb
在这里插入图片描述
即0x60+b=0x6b处
用hexedit phase1.o命令来修改phase1.o
找到0x6b处
在这里插入图片描述
对比刚开始的运行结果,可以发现找对位置了,修改该处的值为学号十六进制ASCII码
。然后以ASCII码”00”结束字符。
在这里插入图片描述
编译重新运行
在这里插入图片描述
第一题正确输出学号

第二题

readelf -a phase2.o命令查看phase2.o的ELF数据
在这里插入图片描述
有个COM未被赋初始值,是个弱符号,根据文档提示打个补丁phase2_patch.o。里面的内容应该是cahr类型的大小为256的g_myCharArray变量的初始化,
在这里插入图片描述
看的出来用到的偏移量是0xb,
所以创建phase2_patch.c文件,创建一个g_myCharArray,偏移量是0xb(11)所以前10个无用填0,
在这里插入图片描述
编译成.o文件,链接运行。
在这里插入图片描述
输出”./”。phase2.o内部进行了一些逻辑运算,我也不太关心它的逻辑,因为我决定靠计算它的偏移量来输出学号
第一位输入35输出”.”
第二位输入35输出”/”
在ascii表中找到
在这里插入图片描述
因为“.”+4=”2”,”/”+2=”1”
所以
第一位输入39输出2
第二位输入37输出1
在这里插入图片描述
以此类推算出学号应该要输入的数,结束符”00”也要推上。
在这里插入图片描述
在这里插入图片描述
第二题正确输出学号

第三题

编译查看汇编代码
在这里插入图片描述
如下所示
在这里插入图片描述

根据编程思想要打印学号,那肯定打印在后,所以包含puts语句的myFunc1方法在后面,
接收一个参数,这个参数应该是学号
在这里插入图片描述
myFunc2获取一个地址的值给到%rax寄存器
在这里插入图片描述
那就是先调用myFunc2函数获取学号赋值给%rax,然后mov %rax,%rdi设置参数在调用myFunc1。
需要注入的命令是

call myFunc2
mov %rax,%rdi
call myFunc1

call指令对应的机器码是e8 xx xx xx xx。
在这里插入图片描述
如下假设

0x400554:e8 xx xx xx xx
0x400559:(下一条指令的地址)

myFunc2的地址是0x40053e
在这里插入图片描述
根据call指令的特性,计算地址0x400559到0x40053e的偏移量是-1b即补码ff ff ff e5。小端法即

0x400554:e8 e5 ff ff ff
0x400559:这里是mov %rax,%rdi

mov %rax,%rdi的机器码是48 89 c7
所以即

0x400554:e8 e5 ff ff ff		(call myFunc2)
0x400559:48 89 c7		    (movq %rax,%rdi)
0x40055c:e8 xx xx xx xx     (call myFunc1)
0x400561:(下一条指令的地址)

myFunc1的地址是0x400523
在这里插入图片描述
0x400561到0x400523的偏移量是-3e即补码ff ff ff c2

0x400554:e8 e6 ff ff ff		(call myFunc2)
0x400559:48 89 c7		    (movq %rax,%rdi)
0x40055c:e8 c2 ff ff ff     (call myFunc1)

使用readelf -a phase3.o命令查看ELF数据
已编译程序的机器代码在
在这里插入图片描述
objdump-d phase3.o查看汇编代码
在这里插入图片描述
所以要注入的代码地址就是0x40+0x31=0x71
hexedit phase3.0
在这里插入图片描述
可以看到确实是这个地方
写入

0x400554:e8 e5 ff ff ff		(call myFunc2)
0x400559:48 89 c7		    (movq %rax,%rdi)
0x40055c:e8 c2 ff ff ff     (call myFunc1)

中的机器码
在这里插入图片描述
编译查看汇编代码
在这里插入图片描述
可以看到代码已经是这样的了
在这里插入图片描述
现在就差学号赋值
在这里插入图片描述
看样子是这里
在这里插入图片描述
.data节是0x1a0
在这里插入图片描述
即0x1a0+0xb=0x1ab
hexedit phase3.o修改0x1ab后的值为学号,以”00”结尾
在这里插入图片描述
编译运行
在这里插入图片描述
第三题正确输出学号

第四题

readelf -a phase4.o
查看phase4.o文件ELF数据
在这里插入图片描述
要修改这里的偏移量
从这里可以看出
在这里插入图片描述
一个是变量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数据
在这里插入图片描述
可以发现改对了
重新编译查看汇编代码
在这里插入图片描述
会发现变成了call puts
在这里插入图片描述
现在还有两个偏移量要修改
在这里插入图片描述
这两个是数据,看下面是这两个变量的值
在这里插入图片描述
.data段在
在这里插入图片描述
一个在.data+0处,一个在.data+0x10处

hexedit phase4.o
前面有提到.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”
在这里插入图片描述
第四关正确输出学号

第五题

编译查看汇编代码
在这里插入图片描述
可以发现myFunc是关键函数,用gdb调试看
在这里插入图片描述
可以发现g_guard不等于零,查看一下,现在是等于1
在这里插入图片描述
就会走到一个g_myFakeCharArray数组看其名这是假的
在这里插入图片描述
查看一下0x601040的值,这个应该是真的。
在这里插入图片描述
观察发现只要把这两个换一下就可以了
在这里插入图片描述
readelf -a phase5.o。查看一下ELF数据,如下所示,
在这里插入图片描述
这两个换换就好
在这里插入图片描述
找到偏移量了
互换即
在这里插入图片描述
编译gdb调试
在这里插入图片描述
这样就ok了,现在就是更改数据为学号。
在这里插入图片描述
这里可以看出g_myCharArray是一个位于.data节中偏移量为0x10处的。
.data在0x90处
在这里插入图片描述
g_myCharArray在0x90+0x10=0xA0处,修改为学号
在这里插入图片描述
编译运行
在这里插入图片描述
第五题正确输出学号

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐