这是大三时的实验课,很久以前的东西,应要求放出来,做的不是很好。linux永远都是很重要的,希望我和大家都记得这个。实际上做到第五阶段我就不会了。

实验课程名称:计算机系统基础

实验项目名称:LinkLab实验


实验目的与要求

在实验中的每一阶段n(n=1,2,3,4,5…),按照阶段的目标要求修改相应可重定位二进制目标模块phase[n].o后,使用如下命令生成可执行程序linkbomb:

$ gcc -o linkbomb main.o phase[n].o [其他附加模块——见具体阶段说明]

正确性验证:如下运行可执行程序linkbomb,应输出符合各阶段期望的字符串: 

$ ./linkbomb

$ 123456789          [仅供示例,具体目标字符串见每阶段说明]

实验结果:将修改后正确完成相应功能的各阶段模块(phase1.o, phase2.o, …)提交供评分。 

实验原理与内容

实验内容

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

阶段1:全局变量ó数据节

阶段2:指令ó代码节

阶段3:符号解析

阶段4:switch语句与重定位 

阶段5:重定位 

   阶段6:重定位( PIC)

 

实验步骤

1. 实验数据

学生实验数据包: linklab-学号.tar

数据包中包含下面文件:

main.o:主程序的二进制可重定位目标模块(实验中无需修改)

phase1.o, phase2.o, phase3.o, phase4.o, phase5.o, phase6.o:各阶段实验所针对的二进制可重定位目标模块,需在相应实验阶段中予以修改。

解压命令:tar xvf linklab-学号.tar

2. 实验工具

readelf:读取ELF格式的各.o二进制模块文件中的各类信息,如节(节名、偏移量及其中数据等)、符号表、字符串表、重定位记录等 

objdump:反汇编代码节中指令并提供上述部分类似功能 

(可选)hexedit:编辑二进制文件内容 

 

实验阶段1

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

 

       

 

 

 

实验提示: 

检查反汇编代码,获得printf输出函数的调用参数的(数据节中)地址 

使用hexedit工具(或自己编写实现二进制ELF文件编辑程序),对phase1.o数据节中相应字节进行修改 

 

实验阶段2

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

 

       

 

实验提示: 

检查反汇编代码,定位模块中的各组成函数并推断其功能作用 

修改入口函数do_phase()中的机器指令(用自己指令替换函数体中的nop指令)以实现期望的输出 

 

实验阶段3

要求:创建生成一个名为“phase3_patch.o”的二进制可重定位目标文件(不允许修改其它.o模块),使其与main.o、phase3.o链接后能够运行和输出(且仅输出)自己的学号: 

 

 

实验提示: 

phase3.o模块入口函数do_phase()依次遍历一个COOKIE字符串(由一组互不相同的英文字母组成,且总长度与学号字符串相同)中的每一字符,并将其不同可能ASCII编码取值映射为特定输出字符 

了解并利用符号解析规则 

 

实验阶段4

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

 

实验提示: 

模块入口函数do_phase()依次遍历一个COOKIE字符串(由一组互不相同的大写英文字母组成,且总长度与学号字符串相同)中的每一字符,并将其不同可能ASCII编码取值映射为特定输出字符 

了解掌握switch语句的机器表示的各组成部分及其重定位信息

实验阶段5

要求:修改二进制可重定位目标文件“phase5.o”的相关重定位节中的数据内容(不允许修改其它节的内容),补充完成其中被清零的一些重定位记录(分别对应于本模块中需要重定位的符号引用),使其与main.o链接后能够正确输出(且仅输出)自己学号的编码结果:

 

 

 

   

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

出现“Segmentation fault”出错信息——原因?“如果未对相关引用进行必要的重定位会发生什么?”

输出“Welcome to this small lab of linking. To begin lab, please link the relevant object module(s) with the main module. ”——提示模块未链接。可能原因:虽然按上述步骤在生成linkbomb程序时实际已链接进phase4.o模块,但某个重要的重定位记录未正确设置。

输出不正确的编码结果 

实验第六阶段不做强制性要求

 

 

 

实验阶段6

要求:修改二进制可重定位目标文件“phase6.o”的相关重定位节中的数据内容(不允许修改其它节的内容),补充完成其中被清零的一些重定位记录(分别对应于本模块中需要重定位的符号引用),使其与main.o链接后能够正确输出(且仅输出)自己学号的编码结果: 

 

 

 

实验提示: 

本阶段的程序框架与阶段5相同,唯一区别是phase6.o采用了Position Independent Code (PIC)的编译方式(即编译生成可重定位目标模块时使用了GCC的“-fPIC”选项),因此模块中对数据和函数的引用方式及其重定位信息发生变化 

了解、熟悉PIC的基本实现技术 

可编写样例程序并分别加上或省略“-fPIC”选项进行编译,再通过比较各自反汇编的结果,了解相同C源代码的PIC与Non-PIC机器级实现之间的差异。

 

学生实验结果提交

将修改完成的各阶段模块(phase1.o, phase2.o, phase3_patch.o, phase4.o, phase5.o, phase6.o)和未改动的main.o、phase3.o模块一起用tar工具打包并命名为“学号.tar”: 

linux> tar cvf 学号尾数(与拿到的tar包相同).tar main.o phase1.o phase2.o phase3.o phase3_patch.o phase4.o phase5.o phase6.o

实验设备与软件环境

Linux 32-bit,C/汇编语言

 

 

实验过程与结果(可贴图)

实验阶段1

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

 

 

实验提示: 

检查反汇编代码,获得printf输出函数的调用参数的(数据节中)地址 

使用hexedit工具(或自己编写实现二进制ELF文件编辑程序),对phase1.o数据节中相应字节进行修改 

输入mydebian@Mydebian:~/23$ readelf -a phase1.o 查看elf文件内容

找到输出的.data 节中偏移量为32的位置。

如下图:

 

 

 

 

然后输入

mydebian@Mydebian:~/23$ gcc -m32 -o linkbomb1 main.o phase1.o

mydebian@Mydebian:~/23$ ./linkbomb1

Y                 On5TXwyRqWFIARrElCC3uFZ1XpL8WYFNgr2hRgaTvpwppI6UmbGZEizWx6JSTu5jfamz0LqFXDoHti9J9T1 Sn1FXeRxBm143PaIosUOhgNDjjClFjbQwoIUGG1BsTVVlFINsjooMWwgkHu7

青色的字体为输处的文字,然后输入hexedit phase1.o

再运行linkbomb程序,得到如下图所示:

 

找到了刚刚青色背景标记的字符串。

从y开始哪个字符串开始修改,对比ASCII码,我的学号为是多少,就对应的ASCII码。

 

直接修改对应的字符串:

 

删除前一个linkbomb,生成新的linkbomb,最后重新输出得到我们要的结果:

阶段一完成

 

 

 

实验阶段2

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

 

实验提示: 

检查反汇编代码,定位模块中的各组成函数并推断其功能作用 

修改入口函数do_phase()中的机器指令(用自己指令替换函数体中的nop指令)以实现期望的输出 

创建文件phase2_linkbomb2.s

输入如下文本:

movl %eax,%ebx

subl $0x8,%ebx

movl -0xc(%eax),%eax

addl %ebx, %eax

pushl $0x00003332   //我的学号为23号,ASCII码为32 33小端存放

pushl %esp

call *%eax

addl $0x8,%esp

输入gcc -m32 -c phase2_linkbomb2.s生成phase2_linkbomb2.o文件

再输入objdump -d phase2_linkbomb2.o读取文件

mydebian@Mydebian:~/23$ objdump -d phase2_linkbomb2.o

phase2_linkbomb2.o:     file format elf32-i386

Disassembly of section .text:

00000000 <.text>:

   0:   89 c3                   mov    %eax,%ebx

   2:   83 eb 08                sub    $0x8,%ebx

   5:   8b 40 f4                mov    -0xc(%eax),%eax

   8:   01 d8                   add    %ebx,%eax

   a:   68 32 33 00 00          push   $0x3332

   f:   54                      push   %esp

  10:   ff d0                   call   *%eax

  12:   83 c4 08                add    $0x8,%esp

输入hexedit phase2.o将上面的内容填补进nop中。

 

相当于修改上面的反汇编代码。

 

 

CTRL+W保存

再输入:

mydebian@Mydebian:~/23$ gcc -m32 -c phase2_linkbomb2.s

./linkbomb2

可以得到需要的结果。

阶段二完成。

 

 

实验阶段3

要求:创建生成一个名为“phase3_patch.o”的二进制可重定位目标文件(不允许修改其它.o模块),使其与main.o、phase3.o链接后能够运行和输出(且仅输出)自己的学号: 

 

实验提示: 

phase3.o模块入口函数do_phase()依次遍历一个COOKIE字符串(由一组互不相同的英文字母组成,且总长度与学号字符串相同)中的每一字符,并将其不同可能ASCII编码取值映射为特定输出字符 

了解并利用符号解

 

首先输入命令objdump -d -r phase3.o查询:

 

然后用命令readelf -s phase3.o读取字符串长度:

 

创建文本phase03_take.c

可以知道这个函数中存放着256个可查询的字符,编写代码如下:

#include<stdio.h>

int main(){

    for(int i=0, p=0; i<=256; ++i ){

        char ch='A'+p;

        printf("'%c',", ch);

        if(!(i%16)) printf("\n");

        if('A'+(++p)>'Z') p=0;//注意带小写

    }

    return 0;

}

输入 gcc phase03_take.c -std=gnu99&& ./a.out查看。

(-std=gnu99->C99标准)

 

 

 

这些字符用于填充zcbGMMwCmU()函数中可存放的区域。

复制建立新文本phase03_patch.c,将截图中的字符放入文本中

 

连续输入指令

mydebian@Mydebian:~/23$ gcc -c phase03_patch.c -m32

mydebian@Mydebian:~/23$  gcc main.o phase3.o phase03_patch.o -m32

mydebian@Mydebian:~/23$ ./a.out

IU//这个字符为phase03输出的字符,

也就是说将I,U字符改为2,3(这里的I,U不是说所有的字符,而是所有字符中被输出的某个字符’I’和字符’U’,为了不需要逐个寻找被输出的那两位字符)即可,如下图(可以改用其他字符,例如数字字符由’1’-’9’,但这样需要修改的位置更多)。

 

 

修改后重新输出:

mydebian@Mydebian:~/23$ gcc -c phase03_patch.c -m32

mydebian@Mydebian:~/23$ gcc main.o phase3.o phase03_patch.o -m32

mydebian@Mydebian:~/23$  ./a.out

23

阶段3完成。

 

 

实验阶段4

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

 

实验提示: 

模块入口函数do_phase()依次遍历一个COOKIE字符串(由一组互不相同的大写英文字母组成,且总长度与学号字符串相同)中的每一字符,并将其不同可能ASCII编码取值映射为特定输出字符 

了解掌握switch语句的机器表示的各组成部分及其重定位信息

连续输入指令

 

查看可得输出放入字符为这两个。那么直接用阶段一的方法,

输入hexedit phase4.o进入程序内查看

S|对应ASCII码分别为53 7C,修改为学号23对应ASCII码为32,33

 

输入命令查看结果正确:

 

 

实验阶段5

要求:修改二进制可重定位目标文件“phase5.o”的相关重定位节中的数据内容(不允许修改其它节的内容),补充完成其中被清零的一些重定位记录(分别对应于本模块中需要重定位的符号引用),使其与main.o链接后能够正确输出(且仅输出)自己学号的编码结果:

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

出现“Segmentation fault”出错信息——原因?“如果未对相关引用进行必要的重定位会发生什么?”

输出“Welcome to this small lab of linking. To begin lab, please link the relevant object module(s) with the main module. ”——提示模块未链接。可能原因:虽然按上述步骤在生成linkbomb程序时实际已链接进phase4.o模块,但某个重要的重定位记录未正确设置。

输出不正确的编码结果 

首先输入命令objdump phase5.o -d >phase5.txt转化成文本:

打开文本phase5.txt寻找偏移量:       

 

 

 

 

 

 

 

Logo

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

更多推荐