Link Lab CMU无此实验,HIT增加
每个实验阶段考察 ELF 文件组成与程序链接过程的不同方面知识
阶段1:全局变量 <=> 数据节
阶段2:指令 <=> 代码节
阶段3:符号解析
阶段4:switch语句与重定位
阶段5:重定位
实验文件
main.o:主程序的可重定位目标模块(实验中无需修改)
phase1.o …….. phase5.o:各阶段实验所针对的二进制可重定位目标模块,需在相应实验阶段中予以修改或补充
linkbombn:验证文件
在实验中的每一阶段,按照阶段的目标要求修改相应可重定位二进制目标模块 phasen.o 后,使用如下命令生成可执行程序 linkbomb:
1 2 linux > gcc -m32 -o linkbomb main.o phase[n].o ./linkbomb
使用工具 hexedit
hexedit 不仅仅是十六进制编辑器,它提供了获取文件差异的信息,可用于比较二进制文件,它的用户界面基于 ncurses
我们可以像下面这样安装它:(可能需要 root 权限)
1 linux > apt install hexedit
打开终端输入以下指令即可运行:
1 linux > hexedit filename
用方向键移动,ctrl+w保存,ctrl+x退出,man hexedit
readelf
-a —all 等同于同时使用:-h -l -S -s -r -d -V -A -l
-h —file-header 显示ELF文件头
-l —program-headers 显示程序头
-S —section-headers 显示节头
-t —section-details 显示节详细信息
-s —syms 显示符号表(symbol table)
-r —relocs 显示重定位信息
-d —dynamic 显示动态节(dynamic section)
-x —hex-dump= 以字节形式显示输出指定节的内容
-p —string-dump= 以字符串形式显示输出指定节的内容
-R —relocated-dump= 以重定位后的字节形式显示输出指定节内容
符号相关知识 符号表
在计算机科学中,符号表是一种用于语言翻译器(例如:编译器和解释器)中的数据结构,在符号表中,程序源代码中的每个标识符都和它的声明或使用信息绑定在一起,比如其数据类型、作用域以及内存地址
1 2 3 4 5 6 7 8 9 typedef struct { Elf32_Word st_name; Elf32_Word st_value; Elf32_Word st_size; unsigned char type: 4 , binding: 4 ; unsigned char st_other; Elf32_Section st_shndx; }Elf32_Sym;
散列表
散列表是用来实现符号表的一种常用技术,编译器可能会使用一个很大的符号表来包含所有的符号,或是针对不同的作用域使用层次结构的多个独立的符号表
符号
Global symbols(模块内部定义的全局符号)
由模块m定义并能被其他模块引用的符号(非static函数,非static全局变量)
External symbols(外部定义的全局符号)
Local symbols(本模块的局部符号)
仅由模块m定义和引用的本地符号(带有static的函数和全局变量)
注意:局部变量不会在过程外被引用(分配在栈中),因此不是符号定义
符号变量
自动变量(动态局部变量):auto
离开函数,值就消失
不写 static 就默认是 auto
静态局部变量:static
离开函数,值任然保留
变量的值只在函数内部生效
带有 static 的变量只会初始化一次(数据存储在 data 段)
当上一级函数多次调用本函数时,带有 static 的变量数值不变(并且不会进行初始化)
寄存器变量:register
全局变量:在 main 之外
允许 main 中所有函数访问
允许外部其他文件访问
静态全局变量:在 main 之外,static
允许 main 中所有函数访问
变量的值只在文件内部生效
节简析 使用目标文件的节头表,可以定位文件的所有节,节头表是 Elf32_Shdr
或 Elf64_Shdr
结构的数组
节头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 typedef struct { elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr; typedef struct { Elf64_Word sh_name; Elf64_Word sh_type; Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; Elf64_Xword sh_addralign; Elf64_Xword sh_entsize; } Elf64_Shdr;
参考:节 - 链接程序和库指南
节分配
节简述
ELF头:包括16字节的标识信息,文件类型(.o,exec,.so),机器类型(如Intel 80386),节头表的偏移,节头表的表项大小及表项个数
.text节:编译后的代码部分
.rodata节:只读数据,如 printf 用到的格式串,switch 跳转表等
.data节:已初始化的全局变量和静态变量
.bss节:未初始化全局变量和静态变量,仅是占位符,不占据任何磁盘空间,区分初始化和非初始化是为了空间效率
.symtab节:存放函数和全局变量(符号表)的信息,它不包括局部变量
.rel.text节:.text节的重定位信息,用于重新修改代码段的指令中的地址信息
.debug节:调试用的符号表(gcc -g)
.strtab节:包含 .symtab节和 .debug节 中的符号及节名
示例 (可能会有不同,比如:在我的电脑上 .data 为第4节)
ABS:表示不该被重定位
UND:表示未定义
COM:表示未初始化数据(.bss)
value:表示对齐要求,size:给出最小大小
编译器驱动程序 编译器驱动程序的工作:调用语言预处理器,编译器,汇编器,链接器
详细过程:
预处理阶段 :预处理器(cpp)根据以字符 “#” 开头的命令,修改原始的 C 程序(比如 hello.c 中第 1 行的#include
命令告诉预处理器读取系统头文件 stdio.h 的内容)并把它直接插入程序文本中,结果就得到了另一个 C 程序
通常是以 .i 作为文件扩展名
所谓的头文件,里面装的其实就是函数声明(libc库中的函数:scanf,printf 等)
编译阶段 :编译器(ccl)将文本文件 hello.i 翻译成文本文件 hello.s,它包含一个汇编语言程序
汇编阶段 :汇编器(as)将 hello.s 翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序(relocatable object program)的格式,并将结果保存在目标文件 hello.o 中
hello.o 文件是一个二进制文件,它包含的 17 个字节是函数 main 的指令编码
如果我们在文本编辑器中打开 hello.o文件,将看到一堆乱码(二进制)
链接阶段 :链接器(ld)就负责处理合并各个 hello.o 文件,结果就得到 hello 文件,它是一个可执行目标文件(或者简称为可执行文件),可以被加载到内存中,由系统执行
请注意,hello 程序调用了 printf 函数,它是每个 C 编译器都提供的标准 C 库中的一个函数
printf 函数存在于一个名为 printf.o 的单独的预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的 hello.o 程序中
通过修改 hello.o 可以影响最终文件 hello 的效果
强符号与弱符号 在C语言中:
函数和初始化的全局变量(包括显示初始化为0)是强符号
未初始化的全局变量是弱符号
对于它们,下列三条规则使用:
同名的强符号只能有一个,否则编译器报”重复定义”错误
允许一个强符号和多个弱符号,但定义会选择强符号的
当有多个弱符号相同时,链接器选择最先出现那个,也就是与链接顺序有关
实验一 步骤一:使用 readelf 和 bjdump 工具,首先确定 printf(具体为 puts )输出函数的第2个调用参数对应的字符串地址(在 .data 节中)
步骤二:使用readelf 或 objdump 工具,查看 .data 节中的字符串内容并与未修改的 phase1.o 链接后程序输出的字符串比较,确定该字符串为修改的目标
步骤三:使用 hexedit 或自己写程序该字符串前若干字符替换为目标学号中的字符
实验一的程序框架:
1 2 3 4 5 6 7 8 9 10 #include <stdio.h> #include "config.h" void (*phase)(); int main ( int argc, const char * argv[] ) { if ( phase ) (*phase)(); else printf ("To run lab, please link the relevant object module with the main module.\n" ); return 0 ; }
直接运行输出这个结果:
1 2 ➜ [/home/ywhkkx/ex1.linklab/l1] ./linkbomb1 173000209U Vv00d3vyFALuMYjxuPCr5m38uiiwLQwlzRxr80BxYnv7r6zz9aChMvWou2DL9e4tc6EidF1olhqrhH3gxYChAckMo7uMXJHwSDfiEmlYH hhJElIl RzCWKPcuNvdHAIt h7487zkd39QJEm4Rqwyer L 0 gauz1N2w9g PyaHAl
现在先收集信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ➜ [/home/ywhkkx/ex1.linklab/l1] readelf -s phase1.o Symbol table '.symtab' contains 17 entries: Num: Value Size Type Bind Vis Ndx Name 0 : 00000000 0 NOTYPE LOCAL DEFAULT UND 1 : 00000000 0 FILE LOCAL DEFAULT ABS phase1.c 2 : 00000000 0 SECTION LOCAL DEFAULT 2 3 : 00000000 0 SECTION LOCAL DEFAULT 4 4 : 00000000 0 SECTION LOCAL DEFAULT 5 5 : 00000000 200 OBJECT LOCAL DEFAULT 4 ALJsLxmF 6 : 00000000 0 SECTION LOCAL DEFAULT 6 7 : 00000000 0 SECTION LOCAL DEFAULT 8 8 : 00000000 0 SECTION LOCAL DEFAULT 10 9 : 00000000 0 SECTION LOCAL DEFAULT 11 10 : 00000000 0 SECTION LOCAL DEFAULT 9 11 : 00000000 0 SECTION LOCAL DEFAULT 1 12 : 00000000 43 FUNC GLOBAL DEFAULT 2 do_phase 13 : 00000000 0 FUNC GLOBAL HIDDEN 8 __x86.get_pc_thunk.ax 14 : 00000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_ 15 : 00000000 0 NOTYPE GLOBAL DEFAULT UND puts 16 : 00000000 4 OBJECT GLOBAL DEFAULT 6 phase
发现可疑目标:ALJsLxmF
Bind:LOCAL(局部符号)
Ndx:4(第4节 .data)
Value:0(节内偏移为0)
Type:OBJECT(全局变量)
局部全局变量,大小为 200,位于 .data 节,节内偏移为 0
接下来只需要查看 data 节在 .o 文件中的偏移是多少应该就可了:
1 2 3 4 5 6 7 8 9 10 11 12 ➜ [/home/ywhkkx/ex1.linklab/l1] readelf -S phase1.o There are 16 section headers, starting at offset 0x3f0 : 节头: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0 ] NULL 00000000 000000 000000 00 0 0 0 [ 1 ] .group GROUP 00000000 000034 000008 04 13 13 4 [ 2 ] .text PROGBITS 00000000 00003 c 00002b 00 AX 0 0 1 [ 3 ] .rel.text REL 00000000 000328 000020 08 I 13 2 4 [ 4 ] .data PROGBITS 00000000 000080 0000 c8 00 WA 0 0 32 [ 5 ] .bss NOBITS 00000000 000148 000000 00 WA 0 0 1 [ 6 ] .data.rel.local PROGBITS 00000000 000148 000004 00 WA 0 0 4
.data节 偏移为“0x80”,在 HexEdit 中定为偏移为“0x80+0x0”(节偏移+节内偏移)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 00000000 7F 45 4 C 46 01 01 01 00 00 00 00 00 00 00 00 00 .ELF............00000010 01 00 03 00 01 00 00 00 00 00 00 00 00 00 00 00 ................00000020 F0 03 00 00 00 00 00 00 34 00 00 00 00 00 28 00 ........4 .....(.00000030 10 00 0F 00 01 00 00 00 08 00 00 00 55 89 E5 53 ............U..S00000040 83 EC 04 E8 FC FF FF FF 05 01 00 00 00 8 D 90 11 ................00000050 00 00 00 83 EC 0 C 52 89 C3 E8 FC FF FF FF 83 C4 ......R.........00000060 10 90 8B 5 D FC C9 C3 00 00 00 00 00 00 00 00 00 ...]............00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................00000080 37 30 6 C 4 C 39 46 39 09 39 68 6B 52 58 55 38 41 70l L9F9.9 hkRXU8A00000090 31 31 37 33 30 30 30 32 30 39 55 56 76 30 30 64 1173000209U Vv00d000000 A0 33 76 79 46 41 4 C 75 4 D 59 6 A 78 75 50 43 72 35 3 vyFALuMYjxuPCr5000000B 0 6 D 33 38 75 69 69 77 4 C 51 77 6 C 7 A 52 78 72 38 m38uiiwLQwlzRxr8000000 C0 30 42 78 59 6 E 76 37 72 36 7 A 7 A 39 61 43 68 4 D 0B xYnv7r6zz9aChM000000 D0 76 57 6F 75 32 44 4 C 39 65 34 74 63 36 45 69 64 vWou2DL9e4tc6Eid000000E0 46 31 6F 6 C 68 71 72 68 48 33 67 78 59 43 68 41 F1olhqrhH3gxYChA000000F 0 63 6B 4 D 6F 37 75 4 D 58 4 A 48 77 53 44 66 69 45 ckMo7uMXJHwSDfiE00000100 6 D 6 C 59 48 09 68 68 4 A 45 6 C 49 6 C 20 52 7 A 43 mlYH.hhJElIl RzC00000110 57 4B 50 63 75 4 E 76 64 48 41 49 74 09 68 37 34 WKPcuNvdHAIt.h7400000120 38 37 7 A 6B 64 33 39 51 4 A 45 6 D 34 52 71 77 79 87 zkd39QJEm4Rqwy00000130 65 72 09 4 C 20 30 67 61 75 7 A 31 4 E 32 77 39 67 er.L 0 gauz1N2w9g00000140 20 50 79 61 48 41 6 C 00 00 00 00 00 8B 04 24 C3 PyaHAl.......$.00000150 00 47 43 43 3 A 20 28 55 62 75 6 E 74 75 20 37 2 E .GCC: (Ubuntu 7. 00000160 33 2 E 30 2 D 31 36 75 62 75 6 E 74 75 33 29 20 37 3.0 -16u buntu3) 7 00000170 2 E 33 2 E 30 00 00 00 00 14 00 00 00 00 00 00 00 .3 .0 ............--- phase1.o --0x0 /0x670 ------------------------------------------------
可以发现 printf 并没有从变量 ALJsLxmF 的头部开始打印,对原字符串进行搜索,发现偏移多了“0x11”,利用 objdump 反汇编进行检查:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ➜ [/home/ywhkkx/ex1.linklab/l1] objdump -d phase1.o phase1.o: 文件格式 elf32-i386 Disassembly of section .text: 00000000 <do_phase>: 0 : 55 push %ebp 1 : 89 e5 mov %esp,%ebp 3 : 53 push %ebx 4 : 83 ec 04 sub $0x4 ,%esp 7 : e8 fc ff ff ff call 8 <do_phase+0x8 > c: 05 01 00 00 00 add $0x1 ,%eax 11 : 8 d 90 11 00 00 00 lea 0x11 (%eax),%edx 17 : 83 ec 0 c sub $0xc ,%esp 1 a: 52 push %edx 1b : 89 c3 mov %eax,%ebx 1 d: e8 fc ff ff ff call 1 e <do_phase+0x1e > 22 : 83 c4 10 add $0x10 ,%esp 25 : 90 nop 26 : 8b 5 d fc mov -0x4 (%ebp),%ebx 29 : c9 leave 2 a: c3 ret Disassembly of section .text.__x86.get_pc_thunk.ax: 00000000 <__x86.get_pc_thunk.ax>: 0 : 8b 04 24 mov (%esp),%eax 3 : c3 ret
现在可以用 HexEdit 修改二进制数据了,我将把它改为 “YHellow”
1 2 3 ➜ [/home/ywhkkx/ex1.linklab/l1] gcc -m32 -o linkbomb main.o phase1.o ➜ [/home/ywhkkx/ex1.linklab/l1] ./linkbomb YHellow
实验二 修改二进制可重定位目标文件 phase2.o 的代码节内容,使其与 main.o 链接后能够运行输出(且仅输出)自己的学号
1 2 3 4 5 6 7 8 9 10 #include <stdio.h> #include "config.h" void (*phase)(); int main ( int argc, const char * argv[] ) { if ( phase ) (*phase)(); else printf ("To run lab, please link the relevant object module with the main module.\n" ); return 0 ; }
1 2 3 4 5 6 7 8 9 static void OUTPUT_FUNC_NAME (const char *id) { if (strcmp (id,MYID) != 0 ) return ; printf ("%s\n" , id); } void do_phase () { asm ( “nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\t…” ); }
// 这个实验要求我们在 do_phase 中执行 OUTPUT_FUNC_NAME,打印 ID
步骤一:使用 objdump 工具,定位 phase2.o 代码节中包含对 printf(会被优化为 puts)输出函数调用的函数的偏移量地址
步骤二:使用 objdump 工具,分析 do_phase 函数的反汇编指令,确定加入对前述输出函数的调用指令的 .text 节中的偏移量位置
步骤三:构造调用输出函数(通过相对PC的偏移量)的机器指令,并替换 do_phase 函数中预留的 nop 指令偏移量
注:目标输出函数为 static 类型,可通过偏移量直接调用跳转(无需重定位)
直接执行程序:
1 ➜ [/home/ywhkkx/ex1.linklab/l2] ./linkbomb2
信息收集:
1 2 ➜ [/home/ywhkkx/ex1.linklab/l2] file linkbomb2 linkbomb2: ELF 32 -bit LSB shared object, Intel 80386 , version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2 , for GNU/Linux 3.2 .0 , BuildID[sha1]=32f a54a562f55fda7e482d48180dc3e162fcea98, not stripped
发现 linkbomb2 是 dynamically,函数采用懒加载(利用PLT/GOT进行加载)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ➜ [/home/ywhkkx/ex1.linklab/l2] readelf -s phase2.o Symbol table '.symtab' contains 22 entries: Num: Value Size Type Bind Vis Ndx Name 0 : 00000000 0 NOTYPE LOCAL DEFAULT UND 1 : 00000000 0 FILE LOCAL DEFAULT ABS phase2.c 2 : 00000000 0 SECTION LOCAL DEFAULT 3 3 : 00000000 0 SECTION LOCAL DEFAULT 5 4 : 00000000 0 SECTION LOCAL DEFAULT 6 5 : 00000000 0 SECTION LOCAL DEFAULT 7 6 : 00000000 65 FUNC LOCAL DEFAULT 3 yeDfwUkv 7 : 00000000 0 SECTION LOCAL DEFAULT 8 8 : 00000000 0 SECTION LOCAL DEFAULT 10 9 : 00000000 0 SECTION LOCAL DEFAULT 11 10 : 00000000 0 SECTION LOCAL DEFAULT 13 11 : 00000000 0 SECTION LOCAL DEFAULT 14 12 : 00000000 0 SECTION LOCAL DEFAULT 12 13 : 00000000 0 SECTION LOCAL DEFAULT 1 14 : 00000000 0 SECTION LOCAL DEFAULT 2 15 : 00000000 0 FUNC GLOBAL HIDDEN 11 __x86.get_pc_thunk.bx 16 : 00000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_ 17 : 00000000 0 NOTYPE GLOBAL DEFAULT UND strcmp 18 : 00000000 0 NOTYPE GLOBAL DEFAULT UND puts 19 : 00000041 48 FUNC GLOBAL DEFAULT 3 do_phase 20 : 00000000 0 FUNC GLOBAL HIDDEN 10 __x86.get_pc_thunk.ax 21 : 00000000 4 OBJECT GLOBAL DEFAULT 8 phase
目标在:第3节,节内偏移为“0x41”的地方
1 2 3 4 5 6 7 8 9 ➜ [/home/ywhkkx/ex1.linklab/l2] readelf -S phase2.o There are 19 section headers, starting at offset 0x458 : 节头: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0 ] NULL 00000000 000000 000000 00 0 0 0 [ 1 ] .group GROUP 00000000 000034 000008 04 16 20 4 [ 2 ] .group GROUP 00000000 00003 c 000008 04 16 15 4 [ 3 ] .text PROGBITS 00000000 000044 000071 00 AX 0 0 1
在 .text 节中找到指定的 do_phase 位置(需要修改的函数),偏移为“0x44+0x41”(注意,puts,strcmp等函数是要在链接重定向完成之后才能确定地址,在反汇编代码中显示出来)
1 2 3 4 5 6 7 8 9 10 11 00000000 7F 45 4 C 46 01 01 01 00 00 00 00 00 00 00 00 00 .ELF............00000010 01 00 03 00 01 00 00 00 00 00 00 00 00 00 00 00 ................00000020 58 04 00 00 00 00 00 00 34 00 00 00 00 00 28 00 X.......4 .....(.00000030 13 00 12 00 01 00 00 00 0 A 00 00 00 01 00 00 00 ................00000040 0B 00 00 00 55 89 E5 53 83 EC 04 E8 FC FF FF FF ....U..S........00000050 81 C3 02 00 00 00 83 EC 08 8 D 83 00 00 00 00 50 ...............P00000060 FF 75 08 E8 FC FF FF FF 83 C4 10 85 C0 75 10 83 .u...........u..00000070 EC 0 C FF 75 08 E8 FC FF FF FF 83 C4 10 EB 01 90 ...u............00000080 8B 5 D FC C9 C3 55 89 E5 E8 FC FF FF FF 05 01 00 .]...U..........00000090 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................000000 A0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
1 2 3 4 5 6 7 8 9 00000041 <do_phase>: 41 : 55 push %ebp 42 : 89 e5 mov %esp,%ebp 44 : e8 fc ff ff ff call 45 <do_phase+0x4 > 49 : 05 01 00 00 00 add $0x1 ,%eax 4 a: 90 nop 4b : 90 nop 4 c: 90 nop 4 d: 90 nop
在“0x86”处发现 do_phase (55 89 e5 e8 …….. )
先输入:gcc -m32 -o linkbomb2 main.o phase2.o 进行链接重定向(phase2.o 没有变)
然后用 objdump 进行打印:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ➜ [/home/ywhkkx/ex1.linklab/l2] objdump -d linkbomb2 .................... 00001215 <yeDfwUkv>: 1215 : 55 push %ebp 1216 : 89 e5 mov %esp,%ebp 1218 : 53 push %ebx 1219 : 83 ec 04 sub $0x4 ,%esp 121 c: e8 9f fe ff ff call 10 c0 <__x86.get_pc_thunk.bx> 1221 : 81 c3 b3 2 d 00 00 add $0x2db3 ,%ebx 1227 : 83 ec 08 sub $0x8 ,%esp 122 a: 8 d 83 a8 e0 ff ff lea -0x1f58 (%ebx),%eax 1230 : 50 push %eax 1231 : ff 75 08 pushl 0x8 (%ebp) 1234 : e8 07 fe ff ff call 1040 <strcmp @plt> 1239 : 83 c4 10 add $0x10 ,%esp 123 c: 85 c0 test %eax,%eax 123 e: 75 10 jne 1250 <yeDfwUkv+0x3b > 1240 : 83 ec 0 c sub $0xc ,%esp 1243 : ff 75 08 pushl 0x8 (%ebp) 1246 : e8 05 fe ff ff call 1050 <puts @plt> 124b : 83 c4 10 add $0x10 ,%esp 124 e: eb 01 jmp 1251 <yeDfwUkv+0x3c > 1250 : 90 nop 1251 : 8b 5 d fc mov -0x4 (%ebp),%ebx 1254 : c9 leave 1255 : c3 ret
想要在 do_phase 中执行 OUTPUT_FUNC_NAME,打印 ID,必须先传入参数 ID,因为“strcmp(id,MYID)”,参数 ID 在 MYID 中,所以改为传入 MYID 的地址
但是 MYID 的地址是变化的(PIE保护),不能直接获取其地址
但是在动态链接中,地址可以通过GOT表来获取,确定MYID在GOT中的偏移
1 2 3 4 5 6 7 121 c: e8 9f fe ff ff call 10 c0 <__x86.get_pc_thunk.bx> 1221 : 81 c3 b3 2 d 00 00 add $0x2db3 ,%ebx ............ 122 a: 8 d 83 a8 e0 ff ff lea -0x1f58 (%ebx),%eax 1230 : 50 push %eax 1231 : ff 75 08 pushl 0x8 (%ebp)1234 : e8 07 fe ff ff call 1040 <strcmp @plt>
“121c”和“1221”这两步就是为了获取GOT表,装入ebx
“122a”这一步取出了位于偏移为“-0x1f58”的数组,装入eax
“1230”和“1231”这两步显然是把“strcmp”的参数压栈(MYID 和 id,从右往左依次入栈)
而“strcmp”的参数就是 MYID ,反推得“-0x1f58”为MYID在GOT表中的偏移,MYID的地址有了
可以在构思注入 do_phase 的汇编了:
1 2 3 4 5 .code32 lea -0x1f58 (%eax), %eax push %eax call -86 pop %eax
查看二进制代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 ➜ [/home/ywhkkx/ex1.linklab/l2] gcc -c 2. s -o 2. o ➜ [/home/ywhkkx/ex1.linklab/l2] objdump -d 2. o 2. o: 文件格式 elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0 : 8 d 80 a8 e0 ff ff lea -0x1f58 (%rax),%eax 6 : 50 push %rax 7 : e8 00 00 00 00 callq 0xc c: 58 pop %rax
1 2 3 ➜ [/home/ywhkkx/ex1.linklab/l2] gcc -m32 -o linkbomb2 main.o phase2.o ➜ [/home/ywhkkx/ex1.linklab/l2] ./linkbomb2 1180300330
成功了,最后再看一眼链接后的 linkbomb2
1 2 3 4 5 6 7 8 9 10 00001256 <do_phase>: 1256 : 55 push %ebp 1257 : 89 e5 mov %esp,%ebp 1259 : e8 b3 ff ff ff call 1211 <__x86.get_pc_thunk.ax> 125 e: 05 76 2 d 00 00 add $0x2d76 ,%eax 1263 : 8 d 80 a8 e0 ff ff lea -0x1f58 (%eax),%eax 1269 : 50 push %eax 126 a: e8 a6 ff ff ff call 1215 <yeDfwUkv> 126f : 58 pop %eax
实验三 创建生成一个名为 “phase3_patch.o” 的二进制可重定位目标文件,使其与 main.o phase3.o 链接后能够运行和输出(且仅输出)自己的学号
模块入口函数 do_phase() 依次遍历一个 COOKIE 字符串(由一组互不相同的英文字母组成,且总长度与学号字符串相同)中的每一字符,并通过一个映射数组将该字符的不同可能 ASCII 编码取值映射为输出字符
1 2 3 4 5 6 7 char PHASE3_CODEBOOK[256 ];void do_phase () { const char char cookie[] = PHASE3_COOKIE; for ( int i=0 ; i<sizeof (cookie)-1 ; i++ ) printf ( "%c" , PHASE3_CODEBOOK[ (unsigned char )(cookie[i]) ] ); printf ( "\n" ); }
分析 do_phase 函数反汇编指令,获知 COOKIE 字符串(保存于栈帧中的局部字符数组中)的组成内容和起始地址
定位循环结构,根据 cookie 中字符的使用,定位映射数组的引用位置,结合重定位记录,确定映射数组的变量名
通过符号表,发现该数组为一未初始化变量(类型为COM,长度为256字节)
要改变程序输出(为学号),必须改变该映射数组的内容,因此,可利用强弱全局符号的解析规则,在 patch 模块中定义同名且按输出要求正确初始化映射关系的数组变量——从而在链接时替换对原数组的引用
先执行文件:
1 ➜ [/home/ywhkkx/ex1.linklab/l3] ./linkbomb3
PHASE3_CODEBOOK 未知,没有进行初始化,如果我们想要让 do_phase 打印我们需要的数据,就需要另写一个重定位文件对 PHASE3_CODEBOOK 进行初始化
反汇编 linkbomb3 寻找 COOKIE :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 00001225 <do_phase>: 1225 : 55 push %ebp 1226 : 89 e5 mov %esp,%ebp 1228 : 53 push %ebx 1229 : 83 ec 24 sub $0x24 ,%esp 122 c: e8 9f fe ff ff call 10 d0 <__x86.get_pc_thunk.bx> 1231 : 81 c3 9f 2 d 00 00 add $0x2d9f ,%ebx 1237 : 65 a1 14 00 00 00 mov %gs:0x14 ,%eax 123 d: 89 45 f4 mov %eax,-0xc (%ebp) 1240 : 31 c0 xor %eax,%eax 1242 : c7 45 e9 61 73 74 70 movl $0x70747361 ,-0x17 (%ebp) 1249 : c7 45 ed 71 72 77 68 movl $0x68777271 ,-0x13 (%ebp) 1250 : 66 c7 45 f1 62 66 movw $0x6662 ,-0xf (%ebp) 1256 : c6 45 f3 00 movb $0x0 ,-0xd (%ebp) 125 a: c7 45 e4 00 00 00 00 movl $0x0 ,-0x1c (%ebp) 1261 : eb 2b jmp 128 e <do_phase+0x69 > 1263 : 8 d 55 e9 lea -0x17 (%ebp),%edx 1266 : 8b 45 e4 mov -0x1c (%ebp),%eax 1269 : 01 d0 add %edx,%eax 126b : 0f b6 00 movzbl (%eax),%eax 126 e: 0f b6 c0 movzbl %al,%eax 1271 : 8 d 93 70 00 00 00 lea 0x70 (%ebx),%edx 1277 : 0f b6 04 02 movzbl (%edx,%eax,1 ),%eax 127b : 0f be c0 movsbl %al,%eax 127 e: 83 ec 0 c sub $0xc ,%esp 1281 : 50 push %eax 1282 : e8 e9 fd ff ff call 1070 <putchar @plt> 1287 : 83 c4 10 add $0x10 ,%esp 128 a: 83 45 e4 01 addl $0x1 ,-0x1c (%ebp) 128 e: 8b 45 e4 mov -0x1c (%ebp),%eax 1291 : 83 f8 09 cmp $0x9 ,%eax 1294 : 76 cd jbe 1263 <do_phase+0x3e > 1296 : 83 ec 0 c sub $0xc ,%esp 1299 : 6 a 0 a push $0xa 129b : e8 d0 fd ff ff call 1070 <putchar @plt> 12 a0: 83 c4 10 add $0x10 ,%esp 12 a3: 90 nop 12 a4: 8b 45 f4 mov -0xc (%ebp),%eax 12 a7: 65 33 05 14 00 00 00 xor %gs:0x14 ,%eax 12 ae: 74 05 je 12b 5 <do_phase+0x90 > 12b 0: e8 8b 00 00 00 call 1340 <__stack_chk_fail_local> 12b 5: 8b 5 d fc mov -0x4 (%ebp),%ebx 12b 8: c9 leave 12b 9: c3 ret 12b a: 66 90 xchg %ax,%ax 12b c: 66 90 xchg %ax,%ax 12b e: 66 90 xchg %ax,%ax
COOKIE 在栈中分配(看到与ebp有关的操作,和密之数字,基本猜到了)
1 2 3 1242 : c7 45 e9 61 73 74 70 movl $0x70747361 ,-0x17 (%ebp) 1249 : c7 45 ed 71 72 77 68 movl $0x68777271 ,-0x13 (%ebp) 1250 : 66 c7 45 f1 62 66 movw $0x6662 ,-0xf (%ebp)
1 2 3 4 5 6 In [5 ]: a=[0x61 ,0x73 ,0x74 ,0x70 ,0x71 ,0x72 ,0x77 ,0x68 ,0x62 ,0x66 ] In [6 ]: data='' In [7 ]: for i in range (len (a)): ...: data+=chr (a[i])
1 2 In [9 ]: data Out[9 ]: 'astpqrwhbf'
再在 GDB 中看看:
1 2 3 04 :0010 │ 0xffffcf00 ◂— 0x747361fc 05 :0014 │ 0xffffcf04 ◂— 'pqrwhbf' 06 :0018 │ 0xffffcf08 ◂— 0x666268
1 2 pwndbg> x/s 0xffffcf00 +1 0xffffcf01 : "astpqrwhbf"
文本中的 PHASE3_CODEBOOK 是弱符号(未初始化的全局变量),我们就在 phase3_patch.o 中定义一个强符号来替换它(强符号会优先被定义)
假设我们想让程序输出:YHelow
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ➜ [/home/ywhkkx/ex1.linklab/l3] readelf -s phase3.o Symbol table '.symtab' contains 18 entries: Num: Value Size Type Bind Vis Ndx Name 0 : 00000000 0 NOTYPE LOCAL DEFAULT UND 1 : 00000000 0 FILE LOCAL DEFAULT ABS phase3.c 2 : 00000000 0 SECTION LOCAL DEFAULT 2 3 : 00000000 0 SECTION LOCAL DEFAULT 4 4 : 00000000 0 SECTION LOCAL DEFAULT 5 5 : 00000000 0 SECTION LOCAL DEFAULT 6 6 : 00000000 0 SECTION LOCAL DEFAULT 8 7 : 00000000 0 SECTION LOCAL DEFAULT 10 8 : 00000000 0 SECTION LOCAL DEFAULT 11 9 : 00000000 0 SECTION LOCAL DEFAULT 9 10 : 00000000 0 SECTION LOCAL DEFAULT 1 11 : 00000020 256 OBJECT GLOBAL DEFAULT COM cDBDohBAOo 12 : 00000000 149 FUNC GLOBAL DEFAULT 2 do_phase 13 : 00000000 0 FUNC GLOBAL HIDDEN 8 __x86.get_pc_thunk.bx 14 : 00000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_ 15 : 00000000 0 NOTYPE GLOBAL DEFAULT UND putchar 16 : 00000000 0 NOTYPE GLOBAL HIDDEN UND __stack_chk_fail_local 17 : 00000000 4 OBJECT GLOBAL DEFAULT 6 phase
1 2 char cDBDohBAOo[256 ] = "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111Y01119121111111lloHe11w" ;
1 2 3 4 ➜ [/home/ywhkkx/ex1.linklab/l3] gcc -m32 -c phase3_patch.c -o phase3_patch.o ➜ [/home/ywhkkx/ex1.linklab/l3] gcc -m32 -o linkbomb3 main.o phase3.o phase3_patch.o ➜ [/home/ywhkkx/ex1.linklab/l3] ./linkbomb3 YHellow209
实验四 修改二进制可重定位目标文件 “phase4.o” 中相应节中的数据内容(注意不允许修改 .text 节的内容),使其与 main.o 链接后能够运行输出(且仅输出)自己的学号
本阶段学生所拿到的.o文件中的“重定位位置”信息已经被抹除,学生需要根据实际情况确认冲重定位的发生位置,并根据重定位类型对位置信息进行恢复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void do_phase () { const char cookie[] = PHASE4_COOKIE; char c; for ( int i = 0 ; i < sizeof (cookie)-1 ; i++ ) { c = cookie[i]; switch (c) { case ‘A’: { c = 48 ; break ; } case ‘B’: { c = 121 ; break ; } … case ‘Z’: { c = 93 ; break ; } } printf ("%c" , c); } }
通过分析 do_phase 函数的反汇编程序获知 COOKIE 字符串(保存于栈帧中的局部字符数组中)的组成内容
确定 switch 跳转表在 .rodata 节中的偏移量(“A”,“B”,“C” …… 这些字符都在 .rodata 节中)
定位 COOKIE 中每一字符’c’在switch跳转表中的对应表项(索引为’c’-0x41),将其值设为输出目标学号中对应字符的 case 首指令的偏移量
直接运行:
1 2 ➜ [/home/ywhkkx/ex1.linklab/l4] ./linkbomb4 wl0_TZb3vJ
和 实验三 一样的套路,只不过这个在外面包装了 switch-case
故技重施,先反汇编 linkbomb4 寻找 COOKIE :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 00001225 <do_phase>: 1225 : 55 push %ebp 1226 : 89 e5 mov %esp,%ebp 1228 : 53 push %ebx 1229 : 83 ec 24 sub $0x24 ,%esp 122 c: e8 9f fe ff ff call 10 d0 <__x86.get_pc_thunk.bx> 1231 : 81 c3 9f 2 d 00 00 add $0x2d9f ,%ebx 1237 : 65 a1 14 00 00 00 mov %gs:0x14 ,%eax 123 d: 89 45 f4 mov %eax,-0xc (%ebp) 1240 : 31 c0 xor %eax,%eax 1242 : c7 45 e9 42 47 4f 4 d movl $0x4d4f4742 ,-0x17 (%ebp) 1249 : c7 45 ed 45 49 55 46 movl $0x46554945 ,-0x13 (%ebp) 1250 : 66 c7 45 f1 51 4 a movw $0x4a51 ,-0xf (%ebp) 1256 : c6 45 f3 00 movb $0x0 ,-0xd (%ebp) 125 a: c7 45 e4 00 00 00 00 movl $0x0 ,-0x1c (%ebp) 1261 : e9 e7 00 00 00 jmp 134 d <.L30+0x19 > 1266 : 8 d 55 e9 lea -0x17 (%ebp),%edx 1269 : 8b 45 e4 mov -0x1c (%ebp),%eax 126 c: 01 d0 add %edx,%eax 126 e: 0f b6 00 movzbl (%eax),%eax 1271 : 88 45 e3 mov %al,-0x1d (%ebp) 1274 : 0f be 45 e3 movsbl -0x1d (%ebp),%eax 1278 : 83 e8 41 sub $0x41 ,%eax 127b : 83 f8 19 cmp $0x19 ,%eax 127 e: 0f 87 b5 00 00 00 ja 1339 <.L30+0x5 > 1284 : c1 e0 02 shl $0x2 ,%eax 1287 : 8b 84 18 ac e0 ff ff mov -0x1f54 (%eax,%ebx,1 ),%eax 128 e: 01 d8 add %ebx,%eax 1290 : ff e0 jmp *%eax
这次直接在GDB中获取 COOKIE 了:
1 2 pwndbg> x/xs 0xffffcf00 +1 0xffffcf01 : "BGOMEIUFQJ"
在 Switch-Case 中:“BGOMEIUFQJ” 对应“跳转表”表项的顺序为:2 7 15 13 5 9 21 6 17 10
先看下汇编:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 00001225 <do_phase>: 1225 : 55 push %ebp 1226 : 89 e5 mov %esp,%ebp 1228 : 53 push %ebx 1229 : 83 ec 24 sub $0x24 ,%esp 122 c: e8 9f fe ff ff call 10 d0 <__x86.get_pc_thunk.bx> 1231 : 81 c3 9f 2 d 00 00 add $0x2d9f ,%ebx 1237 : 65 a1 14 00 00 00 mov %gs:0x14 ,%eax 123 d: 89 45 f4 mov %eax,-0xc (%ebp) 1240 : 31 c0 xor %eax,%eax 1242 : c7 45 e9 42 47 4f 4 d movl $0x4d4f4742 ,-0x17 (%ebp) 1249 : c7 45 ed 45 49 55 46 movl $0x46554945 ,-0x13 (%ebp) 1250 : 66 c7 45 f1 51 4 a movw $0x4a51 ,-0xf (%ebp) 1256 : c6 45 f3 00 movb $0x0 ,-0xd (%ebp) 125 a: c7 45 e4 00 00 00 00 movl $0x0 ,-0x1c (%ebp) 1261 : e9 e7 00 00 00 jmp 134 d <.L30+0x19 > 1266 : 8 d 55 e9 lea -0x17 (%ebp),%edx 1269 : 8b 45 e4 mov -0x1c (%ebp),%eax 126 c: 01 d0 add %edx,%eax 126 e: 0f b6 00 movzbl (%eax),%eax 1271 : 88 45 e3 mov %al,-0x1d (%ebp) 1274 : 0f be 45 e3 movsbl -0x1d (%ebp),%eax 1278 : 83 e8 41 sub $0x41 ,%eax 127b : 83 f8 19 cmp $0x19 ,%eax 127 e: 0f 87 b5 00 00 00 ja 1339 <.L30+0x5 > 1284 : c1 e0 02 shl $0x2 ,%eax 1287 : 8b 84 18 ac e0 ff ff mov -0x1f54 (%eax,%ebx,1 ),%eax 128 e: 01 d8 add %ebx,%eax 1290 : ff e0 jmp *%eax 00001292 <.L4>: 1292 : c6 45 e3 54 movb $0x54 ,-0x1d (%ebp) 1296 : e9 9 e 00 00 00 jmp 1339 <.L30+0x5 > 0000129b <.L6>: 129b : c6 45 e3 77 movb $0x77 ,-0x1d (%ebp) 129f : e9 95 00 00 00 jmp 1339 <.L30+0x5 > 000012 a4 <.L7>: 12 a4: c6 45 e3 70 movb $0x70 ,-0x1d (%ebp) 12 a8: e9 8 c 00 00 00 jmp 1339 <.L30+0x5 > 000012 ad <.L8>: 12 ad: c6 45 e3 36 movb $0x36 ,-0x1d (%ebp) 12b 1: e9 83 00 00 00 jmp 1339 <.L30+0x5 > 000012b 6 <.L9>: 12b 6: c6 45 e3 54 movb $0x54 ,-0x1d (%ebp) 12b a: eb 7 d jmp 1339 <.L30+0x5 > 000012b c <.L10>: 12b c: c6 45 e3 33 movb $0x33 ,-0x1d (%ebp) 12 c0: eb 77 jmp 1339 <.L30+0x5 > 000012 c2 <.L11>: 12 c2: c6 45 e3 6 c movb $0x6c ,-0x1d (%ebp) 12 c6: eb 71 jmp 1339 <.L30+0x5 > 000012 c8 <.L12>: 12 c8: c6 45 e3 34 movb $0x34 ,-0x1d (%ebp) 12 cc: eb 6b jmp 1339 <.L30+0x5 > 000012 ce <.L13>: 12 ce: c6 45 e3 5 a movb $0x5a ,-0x1d (%ebp) 12 d2: eb 65 jmp 1339 <.L30+0x5 > 000012 d4 <.L14>: 12 d4: c6 45 e3 4 a movb $0x4a ,-0x1d (%ebp) 12 d8: eb 5f jmp 1339 <.L30+0x5 > 000012 da <.L15>: 12 da: c6 45 e3 51 movb $0x51 ,-0x1d (%ebp) 12 de: eb 59 jmp 1339 <.L30+0x5 > 000012e0 <.L16>: 12e0 : c6 45 e3 4 d movb $0x4d ,-0x1d (%ebp) 12e4 : eb 53 jmp 1339 <.L30+0x5 > 000012e6 <.L17>: 12e6 : c6 45 e3 5f movb $0x5f ,-0x1d (%ebp) 12 ea: eb 4 d jmp 1339 <.L30+0x5 > 000012 ec <.L18>: 12 ec: c6 45 e3 38 movb $0x38 ,-0x1d (%ebp) 12f 0: eb 47 jmp 1339 <.L30+0x5 > 000012f 2 <.L19>: 12f 2: c6 45 e3 30 movb $0x30 ,-0x1d (%ebp) 12f 6: eb 41 jmp 1339 <.L30+0x5 > 000012f 8 <.L20>: 12f 8: c6 45 e3 32 movb $0x32 ,-0x1d (%ebp) 12f c: eb 3b jmp 1339 <.L30+0x5 > 000012f e <.L21>: 12f e: c6 45 e3 76 movb $0x76 ,-0x1d (%ebp) 1302 : eb 35 jmp 1339 <.L30+0x5 > 00001304 <.L22>: 1304 : c6 45 e3 35 movb $0x35 ,-0x1d (%ebp) 1308 : eb 2f jmp 1339 <.L30+0x5 > 0000130 a <.L23>: 130 a: c6 45 e3 3 c movb $0x3c ,-0x1d (%ebp) 130 e: eb 29 jmp 1339 <.L30+0x5 > 00001310 <.L24>: 1310 : c6 45 e3 39 movb $0x39 ,-0x1d (%ebp) 1314 : eb 23 jmp 1339 <.L30+0x5 > 00001316 <.L25>: 1316 : c6 45 e3 62 movb $0x62 ,-0x1d (%ebp) 131 a: eb 1 d jmp 1339 <.L30+0x5 > 0000131 c <.L26>: 131 c: c6 45 e3 57 movb $0x57 ,-0x1d (%ebp) 1320 : eb 17 jmp 1339 <.L30+0x5 > 00001322 <.L27>: 1322 : c6 45 e3 60 movb $0x60 ,-0x1d (%ebp) 1326 : eb 11 jmp 1339 <.L30+0x5 > 00001328 <.L28>: 1328 : c6 45 e3 4 d movb $0x4d ,-0x1d (%ebp) 132 c: eb 0b jmp 1339 <.L30+0x5 > 0000132 e <.L29>: 132 e: c6 45 e3 31 movb $0x31 ,-0x1d (%ebp) 1332 : eb 05 jmp 1339 <.L30+0x5 > 00001334 <.L30>: 1334 : c6 45 e3 37 movb $0x37 ,-0x1d (%ebp) 1338 : 90 nop 1339 : 0f be 45 e3 movsbl -0x1d (%ebp),%eax 133 d: 83 ec 0 c sub $0xc ,%esp 1340 : 50 push %eax 1341 : e8 2 a fd ff ff call 1070 <putchar @plt> 1346 : 83 c4 10 add $0x10 ,%esp 1349 : 83 45 e4 01 addl $0x1 ,-0x1c (%ebp) 134 d: 8b 45 e4 mov -0x1c (%ebp),%eax 1350 : 83 f8 09 cmp $0x9 ,%eax 1353 : 0f 86 0 d ff ff ff jbe 1266 <do_phase+0x41 > 1359 : 83 ec 0 c sub $0xc ,%esp 135 c: 6 a 0 a push $0xa 135 e: e8 0 d fd ff ff call 1070 <putchar @plt> 1363 : 83 c4 10 add $0x10 ,%esp 1366 : 90 nop 1367 : 8b 45 f4 mov -0xc (%ebp),%eax 136 a: 65 33 05 14 00 00 00 xor %gs:0x14 ,%eax 1371 : 74 05 je 1378 <.L30+0x44 > 1373 : e8 88 00 00 00 call 1400 <__stack_chk_fail_local> 1378 : 8b 5 d fc mov -0x4 (%ebp),%ebx 137b : c9 leave 137 c: c3 ret 137 d: 66 90 xchg %ax,%ax 137f : 90 nop
这些奇怪的 L4 L6 L7 就是字符了(主要是因为它们有26个)
“jmp 1339 <.L30+0x5>”应该就是“break”,可以通过 movb 来获取对应的打印数据(已标记)
实验四想要我们修改“phase4.o”,但不让我们修改 .text 节的内容(可执行指令的集合),所以我们只能改 .rodata 节中的“跳转表”
// 可采用以下代码证明:L4 L6 L7 就是 A,B,C,D ……
1 2 ➜ [/home/ywhkkx/ex1.linklab/l4] readelf -s phase4.o ➜ [/home/ywhkkx/ex1.linklab/l4] readelf -S phase4.o
用 readelf 打印重定位节:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 重定位节 '.rel.rodata' at offset 0x648 contains 26 entries: 偏移量 信息 类型 符号值 符号名称 00000000 00000 a09 R_386_GOTOFF 0000006 d .L400000004 00000b 09 R_386_GOTOFF 00000076 .L600000008 00000 c09 R_386_GOTOFF 0000007f .L70000000 c 00000 d09 R_386_GOTOFF 00000088 .L800000010 00000e09 R_386_GOTOFF 00000091 .L900000014 00000f 09 R_386_GOTOFF 00000097 .L1000000018 00001009 R_386_GOTOFF 0000009 d .L110000001 c 00001109 R_386_GOTOFF 000000 a3 .L1200000020 00001209 R_386_GOTOFF 000000 a9 .L1300000024 00001309 R_386_GOTOFF 000000 af .L1400000028 00001409 R_386_GOTOFF 000000b 5 .L150000002 c 00001509 R_386_GOTOFF 000000b b .L1600000030 00001609 R_386_GOTOFF 000000 c1 .L1700000034 00001709 R_386_GOTOFF 000000 c7 .L1800000038 00001809 R_386_GOTOFF 000000 cd .L190000003 c 00001909 R_386_GOTOFF 000000 d3 .L2000000040 00001 a09 R_386_GOTOFF 000000 d9 .L2100000044 00001b 09 R_386_GOTOFF 000000 df .L2200000048 00001 c09 R_386_GOTOFF 000000e5 .L230000004 c 00001 d09 R_386_GOTOFF 000000 eb .L2400000050 00001e09 R_386_GOTOFF 000000f 1 .L2500000054 00001f 09 R_386_GOTOFF 000000f 7 .L2600000058 00002009 R_386_GOTOFF 000000f d .L270000005 c 00002109 R_386_GOTOFF 00000103 .L2800000060 00002209 R_386_GOTOFF 00000109 .L2900000064 00002309 R_386_GOTOFF 0000010f .L30
获取各个元素的节内偏移
1 2 3 4 5 6 7 8 9 10 11 12 13 ➜ [/home/ywhkkx/ex1.linklab/l4] readelf -S phase4.o There are 18 section headers, starting at offset 0x7cc : 节头: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0 ] NULL 00000000 000000 000000 00 0 0 0 [ 1 ] .group GROUP 00000000 000034 000008 04 15 39 4 [ 2 ] .text PROGBITS 00000000 00003 c 000158 00 AX 0 0 1 [ 3 ] .rel.text REL 00000000 000618 000030 08 I 15 2 4 [ 4 ] .data PROGBITS 00000000 000194 000000 00 WA 0 0 1 [ 5 ] .bss NOBITS 00000000 000194 000000 00 WA 0 0 1 [ 6 ] .rodata PROGBITS 00000000 000194 000068 00 A 0 0 4 [ 7 ] .rel.rodata REL 00000000 000648 0000 d0 08 I 15 6 4
“.rel.rodata ”的偏移为“000648”,
现在可以用 hexedit 进行修改了,主要关注偏移为“000648”的地方,目的是交换’.rel.rodata’的信息,以改变重定位值,进而改变输出值:
1 2 3 4 5 00000640 4F 01 00 00 02 2 A 00 00 00 00 00 00 09 0 A 00 00 O....*..........00000650 04 00 00 00 09 0B 00 00 08 00 00 00 09 0 C 00 00 ................00000660 0 C 00 00 00 09 0 D 00 00 10 00 00 00 09 0 E 00 00 ................00000670 14 00 00 00 09 0F 00 00 18 00 00 00 09 10 00 00 ................00000680 1 C 00 00 00 09 11 00 00 20 00 00 00 09 12 00 00 ........ .......
cookie:BGOMEIUFQJ
对应符号名称:L6 L11 L19 L17 L9 L13 L25 L10 L21 L14
原本的输出:wl0_TZb3vJ
假设我们想输出:0123456789
对应符号名称:L19 L29 L20 L10 L12 L22 L8 L30 L18 L24
然后用 hexedit 做出调换:L6->L19,L11->L29,L19->L20 ……….
1 2 3 4 5 6 7 8 9 10 11 12 13 14 00000640 4F 01 00 00 02 2 A 00 00 00 00 00 00 09 0 A 00 00 O....*..........00000650 04 00 00 00 09 18 00 00 08 00 00 00 09 0 C 00 00 ................00000660 0 C 00 00 00 09 0 D 00 00 10 00 00 00 09 11 00 00 ................00000670 14 00 00 00 09 23 00 00 18 00 00 00 09 22 00 00 .....#.......".. 00000680 1C 00 00 00 09 11 00 00 20 00 00 00 09 1B 00 00 ........ ....... 00000690 24 00 00 00 09 1D 00 00 28 00 00 00 09 14 00 00 $.......(....... 000006A0 2C 00 00 00 09 15 00 00 30 00 00 00 09 23 00 00 ,.......0....#.. 000006B0 34 00 00 00 09 17 00 00 38 00 00 00 09 19 00 00 4.......8....... 000006C0 3C 00 00 00 09 19 00 00 40 00 00 00 09 17 00 00 <.......@....... 000006D0 44 00 00 00 09 1B 00 00 48 00 00 00 09 1C 00 00 D.......H....... 000006E0 4C 00 00 00 09 1D 00 00 50 00 00 00 09 0D 00 00 L.......P....... 000006F0 54 00 00 00 09 1F 00 00 58 00 00 00 09 20 00 00 T.......X.... .. 00000700 5C 00 00 00 09 21 00 00 60 00 00 00 09 22 00 00 \....!..`...." ..00000710 64 00 00 00 09 23 00 00 00 00 00 00 01 26 00 00 d....#.......&..
1 2 3 ➜ [/home/ywhkkx/ex1.linklab/l4] gcc -m32 -o linkbomb4 main.o phase4.o ➜ [/home/ywhkkx/ex1.linklab/l4] ./linkbomb4 0127456789
实验五 修改二进制可重定位目标文件“phase5.o”的重定位节中的数据内容(不允许修改.text节的内容),补充完成其中被清零的一些重定位记录(分别对应于本模块中需要重定位的符号引用),使其与 main.o 链接后能够正确输出(且仅输出)自己学号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 const int TRAN_ARRAY[] = {… …};const char FDICT[] = FDICTDAT;char BUF[] = MYID; char CODE = PHASE5_COOKIE;int transform_code ( int code, int mode ) { switch ( TRAN_ARRAY [mode] & 0x00000007 ) { case 0 : code = code & (~ TRAN_ARRAY[mode]); break ; case 1 : code = code ^ TRAN_ARRAY[mode]; break ; … … } return code; } void generate_code ( int cookie ) { int i; CODE = cookie; for ( i=0 ; i<sizeof (TRAN_ARRAY)/sizeof (int ); i++ ) CODE = transform_code( CODE, i ); } int encode ( char * str ) { int i, n = strlen (str); for ( i=0 ; i<n; i++ ) { str[i] = (FDICT[str[i]] ^ CODE) & 0x7F ; if ( str[i]<0x20 || str[i]>0x7E ) str[i] = ' ' ; } return n; } void do_phase () { generate_code(PHASE5_COOKIE); encode(BUF); printf ("%s\n" , BUF); }
对照 phase5.o 的反汇编程序及已有重定位记录,定位每一空重定位记录可能对应的符号引用
对每一待处理的符号引用,按照下列重定位记录结构,构造其二进制表示(8字节块)
使用 hexedit 或编程将生成的重定位记录写入到相应被清空的记录位置中
直接运行程序:(报错了)
1 2 3 ➜ [/home/ywhkkx/ex1.linklab/l5] gcc -m32 -o linkbomb5 main.o phase5.o ➜ [/home/ywhkkx/ex1.linklab/l5] ./linkbomb5 [1 ] 4179 illegal hardware instruction (core dumped) ./linkbomb5
可能 实验五 就是为了让我们修复程序,一般段错误有以下原因:
未对相关引用进行必要的重定位(实验PTT给出了这个)
用GDB单步排查:
1 Invalid instructions at 0x56556399
“do_phase”出问题了,但不知道是什么问题(其实大概率是重定位的问题,实验给了提示)
看一下重定位表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ➜ [/home/ywhkkx/ex1.linklab/l5] readelf -r phase5.o 重定位节 '.rel.text' at offset 0x6e8 contains 27 entries: 偏移量 信息 类型 符号值 符号名称 00000000 00000000 R_386_NONE 00000009 00001b 0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_00000013 00001509 R_386_GOTOFF 00000000 CmhNnM00000000 00000000 R_386_NONE 00000000 00000000 R_386_NONE 0000004 c 00001509 R_386_GOTOFF 00000000 CmhNnM0000005 d 00001509 R_386_GOTOFF 00000000 CmhNnM00000000 00000000 R_386_NONE 0000007 e 00001509 R_386_GOTOFF 00000000 CmhNnM00000000 00000000 R_386_NONE 0000009 e 00001b 0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_000000 a7 00001809 R_386_GOTOFF 0000000b CODE00000000 00000000 R_386_NONE 00000000 00000000 R_386_NONE 000000 cc 00001809 R_386_GOTOFF 0000000b CODE000000 ea 00001 d02 R_386_PC32 00000000 __x86.get_pc_thunk.bx00000000 00000000 R_386_NONE 000000f b 00001f 04 R_386_PLT32 00000000 strlen 00000120 00001609 R_386_GOTOFF 00000040 cRvFVR00000127 00001809 R_386_GOTOFF 0000000b CODE00000000 00000000 R_386_NONE 00000189 00001b 0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_00000193 00001 c02 R_386_PC32 00000090 generate_code0000019f 00001709 R_386_GOTOFF 00000000 BUF000001 a5 00001e02 R_386_PC32 000000e2 encode000001b 1 00001709 R_386_GOTOFF 00000000 BUF000001b 7 00002104 R_386_PLT32 00000000 puts 重定位节 '.rel.rodata' at offset 0x7c0 contains 8 entries: 偏移量 信息 类型 符号值 符号名称 000000 c0 00000 c09 R_386_GOTOFF 0000002 d .L3000000 c4 00000 d09 R_386_GOTOFF 00000032 .L5000000 c8 00000 a09 R_386_GOTOFF 00000087 .L2000000 cc 00000e09 R_386_GOTOFF 00000046 .L6000000 d0 00000f 09 R_386_GOTOFF 00000057 .L7000000 d4 00001009 R_386_GOTOFF 00000069 .L8000000 d8 00000 a09 R_386_GOTOFF 00000087 .L2000000 dc 00001109 R_386_GOTOFF 00000078 .L9重定位节 '.rel.data.rel.local' at offset 0x800 contains 1 entry: 偏移量 信息 类型 符号值 符号名称 00000000 00002001 R_386_32 0000017b do_phase重定位节 '.rel.eh_frame' at offset 0x808 contains 6 entries: 偏移量 信息 类型 符号值 符号名称 00000020 00000202 R_386_PC32 00000000 .text00000040 00000202 R_386_PC32 00000000 .text00000064 00000202 R_386_PC32 00000000 .text00000088 00000202 R_386_PC32 00000000 .text000000 ac 00000702 R_386_PC32 00000000 .text.__x86.get_pc_thu000000 c0 00000802 R_386_PC32 00000000 .text.__x86.get_pc_thu
发现很多条目空着的,需要补全
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ➜ [/home/ywhkkx/ex1.linklab/l5] readelf -S phase5.o There are 20 section headers, starting at offset 0x8f0 : 节头: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0 ] NULL 00000000 000000 000000 00 0 0 0 [ 1 ] .group GROUP 00000000 000034 000008 04 17 26 4 [ 2 ] .group GROUP 00000000 00003 c 000008 04 17 29 4 [ 3 ] .text PROGBITS 00000000 000044 0001 c4 00 AX 0 0 1 [ 4 ] .rel.text REL 00000000 0006e8 0000 d8 08 I 17 3 4 [ 5 ] .data PROGBITS 00000000 000208 00000 c 00 WA 0 0 4 [ 6 ] .bss NOBITS 00000000 000214 000000 00 WA 0 0 1 [ 7 ] .rodata PROGBITS 00000000 000220 0000e0 00 A 0 0 32 [ 8 ] .rel.rodata REL 00000000 0007 c0 000040 08 I 17 7 4
“.rel.rodata”偏移为“0x7c0”,“.rel.text”偏移为“0x6e8”
在 hexedit 中看看:
1 2 3 4 5 6 000006 D0 64 65 00 73 74 72 6 C 65 6 E 00 64 6F 5F 70 68 61 de.strlen .do_pha000006E0 73 65 00 70 75 74 73 00 00 00 00 00 00 00 00 00 se.puts .........000006F 0 09 00 00 00 0 A 1B 00 00 13 00 00 00 09 15 00 00 ................00000700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................00000710 4 C 00 00 00 09 15 00 00 5 D 00 00 00 09 15 00 00 L.......].......00000720 00 00 00 00 00 00 00 00 7 E 00 00 00 09 15 00 00 ........~.......
可以发现一个规律,对应 ‘.rel.text’ 表中:
第一个4字节空间是偏移量
第二个4字节空间是信息(注意小端字节序)
在“0x6e8”和“0x6e8+0x4”的位置是空的,’.rel.text’ 表中空着的地方都没有数据,通过前面几个实验的观察,’.rel.text’ 表是不应该存在空数据的,所以实验五的核心就是为了把 ‘.rel.text’ 表补全
那么填入什么数据呢,需要在汇编中查看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 ➜ [/home/ywhkkx/ex1.linklab/l5] objdump -d phase5.o phase5.o: 文件格式 elf32-i386 Disassembly of section .text: 00000000 <transform_code>: 0 : 55 push %ebp 1 : 89 e5 mov %esp,%ebp 3 : e8 fc ff ff ff call 4 <transform_code+0x4 > 8 : 05 01 00 00 00 add $0x1 ,%eax d: 8b 55 0 c mov 0xc (%ebp),%edx 10 : 8b 94 90 00 00 00 00 mov 0x0 (%eax,%edx,4 ),%edx 17 : 83 e2 07 and $0x7 ,%edx 1 a: 83 fa 07 cmp $0x7 ,%edx 1 d: 77 68 ja 87 <.L2> 1f : c1 e2 02 shl $0x2 ,%edx 22 : 8b 94 02 c0 00 00 00 mov 0xc0 (%edx,%eax,1 ),%edx 29 : 01 c2 add %eax,%edx 2b : ff e2 jmp *%edx 0000002 d <.L3>: 2 d: f7 55 08 notl 0x8 (%ebp) 30 : eb 59 jmp 8b <.L2+0x4 > 00000032 <.L5>: 32 : 8b 55 0 c mov 0xc (%ebp),%edx 35 : 8b 84 90 00 00 00 00 mov 0x0 (%eax,%edx,4 ),%eax 3 c: 83 e0 03 and $0x3 ,%eax 3f : 89 c1 mov %eax,%ecx 41 : d3 7 d 08 sarl %cl,0x8 (%ebp) 44 : eb 45 jmp 8b <.L2+0x4 > 00000046 <.L6>: 46 : 8b 55 0 c mov 0xc (%ebp),%edx 49 : 8b 84 90 00 00 00 00 mov 0x0 (%eax,%edx,4 ),%eax 50 : f7 d0 not %eax 52 : 21 45 08 and %eax,0x8 (%ebp) 55 : eb 34 jmp 8b <.L2+0x4 > 00000057 <.L7>: 57 : 8b 55 0 c mov 0xc (%ebp),%edx 5 a: 8b 84 90 00 00 00 00 mov 0x0 (%eax,%edx,4 ),%eax 61 : c1 e0 08 shl $0x8 ,%eax 64 : 09 45 08 or %eax,0x8 (%ebp) 67 : eb 22 jmp 8b <.L2+0x4 > 00000069 <.L8>: 69 : 8b 55 0 c mov 0xc (%ebp),%edx 6 c: 8b 84 90 00 00 00 00 mov 0x0 (%eax,%edx,4 ),%eax 73 : 31 45 08 xor %eax,0x8 (%ebp) 76 : eb 13 jmp 8b <.L2+0x4 > 00000078 <.L9>: 78 : 8b 55 0 c mov 0xc (%ebp),%edx 7b : 8b 84 90 00 00 00 00 mov 0x0 (%eax,%edx,4 ),%eax 82 : 89 45 08 mov %eax,0x8 (%ebp) 85 : eb 04 jmp 8b <.L2+0x4 > 00000087 <.L2>: 87 : f7 5 d 08 negl 0x8 (%ebp) 8 a: 90 nop 8b : 8b 45 08 mov 0x8 (%ebp),%eax 8 e: 5 d pop %ebp 8f : c3 ret 00000090 <generate_code>: 90 : 55 push %ebp 91 : 89 e5 mov %esp,%ebp 93 : 53 push %ebx 94 : 83 ec 10 sub $0x10 ,%esp 97 : e8 fc ff ff ff call 98 <generate_code+0x8 > 9 c: 81 c3 02 00 00 00 add $0x2 ,%ebx a2: 8b 45 08 mov 0x8 (%ebp),%eax a5: 88 83 00 00 00 00 mov %al,0x0 (%ebx) ab: c7 45 f8 00 00 00 00 movl $0x0 ,-0x8 (%ebp) b2: eb 20 jmp d4 <generate_code+0x44 > b4: 0f b6 83 00 00 00 00 movzbl 0x0 (%ebx),%eax bb: 0f be c0 movsbl %al,%eax be: ff 75 f8 pushl -0x8 (%ebp) c1: 50 push %eax c2: e8 fc ff ff ff call c3 <generate_code+0x33 > c7: 83 c4 08 add $0x8 ,%esp ca: 88 83 00 00 00 00 mov %al,0x0 (%ebx) d0: 83 45 f8 01 addl $0x1 ,-0x8 (%ebp) d4: 8b 45 f8 mov -0x8 (%ebp),%eax d7: 83 f8 08 cmp $0x8 ,%eax da: 76 d8 jbe b4 <generate_code+0x24 > dc: 90 nop dd: 8b 5 d fc mov -0x4 (%ebp),%ebx e0: c9 leave e1: c3 ret 000000e2 <encode>: e2: 55 push %ebp e3: 89 e5 mov %esp,%ebp e5: 53 push %ebx e6: 83 ec 14 sub $0x14 ,%esp e9: e8 fc ff ff ff call ea <encode+0x8 > ee: 81 c3 02 00 00 00 add $0x2 ,%ebx f4: 83 ec 0 c sub $0xc ,%esp f7: ff 75 08 pushl 0x8 (%ebp) fa: e8 fc ff ff ff call fb <encode+0x19 > ff: 83 c4 10 add $0x10 ,%esp 102 : 89 45 f4 mov %eax,-0xc (%ebp) 105 : c7 45 f0 00 00 00 00 movl $0x0 ,-0x10 (%ebp) 10 c: eb 5 d jmp 16b <encode+0x89 > 10 e: 8b 55 f0 mov -0x10 (%ebp),%edx 111 : 8b 45 08 mov 0x8 (%ebp),%eax 114 : 01 d0 add %edx,%eax 116 : 0f b6 00 movzbl (%eax),%eax 119 : 0f be c0 movsbl %al,%eax 11 c: 0f b6 94 03 00 00 00 movzbl 0x0 (%ebx,%eax,1 ),%edx 123 : 00 124 : 0f b6 83 00 00 00 00 movzbl 0x0 (%ebx),%eax 12b : 89 d1 mov %edx,%ecx 12 d: 31 c1 xor %eax,%ecx 12f : 8b 55 f0 mov -0x10 (%ebp),%edx 132 : 8b 45 08 mov 0x8 (%ebp),%eax 135 : 01 d0 add %edx,%eax 137 : 83 e1 7f and $0x7f ,%ecx 13 a: 89 ca mov %ecx,%edx 13 c: 88 10 mov %dl,(%eax) 13 e: 8b 55 f0 mov -0x10 (%ebp),%edx 141 : 8b 45 08 mov 0x8 (%ebp),%eax 144 : 01 d0 add %edx,%eax 146 : 0f b6 00 movzbl (%eax),%eax 149 : 3 c 1f cmp $0x1f ,%al 14b : 7 e 0f jle 15 c <encode+0x7a > 14 d: 8b 55 f0 mov -0x10 (%ebp),%edx 150 : 8b 45 08 mov 0x8 (%ebp),%eax 153 : 01 d0 add %edx,%eax 155 : 0f b6 00 movzbl (%eax),%eax 158 : 3 c 7f cmp $0x7f ,%al 15 a: 75 0b jne 167 <encode+0x85 > 15 c: 8b 55 f0 mov -0x10 (%ebp),%edx 15f : 8b 45 08 mov 0x8 (%ebp),%eax 162 : 01 d0 add %edx,%eax 164 : c6 00 20 movb $0x20 ,(%eax) 167 : 83 45 f0 01 addl $0x1 ,-0x10 (%ebp) 16b : 8b 45 f0 mov -0x10 (%ebp),%eax 16 e: 3b 45 f4 cmp -0xc (%ebp),%eax 171 : 7 c 9b jl 10 e <encode+0x2c > 173 : 8b 45 f4 mov -0xc (%ebp),%eax 176 : 8b 5 d fc mov -0x4 (%ebp),%ebx 179 : c9 leave 17 a: c3 ret 0000017b <do_phase>: 17b : 55 push %ebp 17 c: 89 e5 mov %esp,%ebp 17 e: 53 push %ebx 17f : 83 ec 04 sub $0x4 ,%esp 182 : e8 fc ff ff ff call 183 <do_phase+0x8 > 187 : 81 c3 02 00 00 00 add $0x2 ,%ebx 18 d: 68 87 00 00 00 push $0x87 192 : e8 fc ff ff ff call 193 <do_phase+0x18 > 197 : 83 c4 04 add $0x4 ,%esp 19 a: 83 ec 0 c sub $0xc ,%esp 19 d: 8 d 83 00 00 00 00 lea 0x0 (%ebx),%eax 1 a3: 50 push %eax 1 a4: e8 fc ff ff ff call 1 a5 <do_phase+0x2a > 1 a9: 83 c4 10 add $0x10 ,%esp 1 ac: 83 ec 0 c sub $0xc ,%esp 1 af: 8 d 83 00 00 00 00 lea 0x0 (%ebx),%eax 1b 5: 50 push %eax 1b 6: e8 fc ff ff ff call 1b 7 <do_phase+0x3c > 1b b: 83 c4 10 add $0x10 ,%esp 1b e: 90 nop 1b f: 8b 5 d fc mov -0x4 (%ebp),%ebx 1 c2: c9 leave 1 c3: c3 ret Disassembly of section .text.__x86.get_pc_thunk.ax: 00000000 <__x86.get_pc_thunk.ax>: 0 : 8b 04 24 mov (%esp),%eax 3 : c3 ret Disassembly of section .text.__x86.get_pc_thunk.bx: 00000000 <__x86.get_pc_thunk.bx>: 0 : 8b 1 c 24 mov (%esp),%ebx 3 : c3 ret
主要看 “00 00 00” 和 “ff ff ff” 有没有在 ‘.rel.text’ 表中出现,把出现的标记,没有的可能就是需要修补的,最后进行修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ➜ [/home/ywhkkx/ex1.linklab/l5] readelf -r phase5.o 重定位节 '.rel.text' at offset 0x6e8 contains 27 entries: 偏移量 信息 类型 符号值 符号名称 00000004 00001 d02 R_386_PC32 00000000 __x86.get_pc_thunk.bx00000009 00001b 0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_00000013 00001 d02 R_386_PC32 00000000 __x86.get_pc_thunk.bx00000025 00001b 0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_00000038 00001509 R_386_GOTOFF 00000000 CmhNnM0000004 c 00001509 R_386_GOTOFF 00000000 CmhNnM0000005 d 00001509 R_386_GOTOFF 00000000 CmhNnM0000006f 00001509 R_386_GOTOFF 00000000 CmhNnM0000007 e 00001509 R_386_GOTOFF 00000000 CmhNnM00000098 00001 d02 R_386_PC32 00000000 __x86.get_pc_thunk.bx0000009 e 00001b 0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_000000 a7 00001809 R_386_GOTOFF 0000000b CODE000000 ae 00001809 R_386_GOTOFF 0000000b CODE000000b 7 00001809 R_386_GOTOFF 0000000b CODE000000 cc 00001809 R_386_GOTOFF 0000000b CODE000000 ea 00001 d02 R_386_PC32 00000000 __x86.get_pc_thunk.bx000000f 0 00001b 0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_000000f b 00001f 04 R_386_PLT32 00000000 strlen 00000120 00001609 R_386_GOTOFF 00000040 cRvFVR00000127 00001809 R_386_GOTOFF 0000000b CODE00000183 00001 d02 R_386_PC32 00000000 __x86.get_pc_thunk.bx00000189 00001b 0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_00000193 00001 c02 R_386_PC32 00000090 generate_code0000019f 00001709 R_386_GOTOFF 00000000 BUF000001 a5 00001e02 R_386_PC32 000000e2 encode000001b 1 00001709 R_386_GOTOFF 00000000 BUF000001b 7 00002104 R_386_PLT32 00000000 puts
“偏移量”很好处理,就是“信息”不好选择,我是根据“汇编代码的相似性”进行选择的,最后总算可以输出了(想要完美完成这个实验,必须掌握汇编)
1 2 ➜ [/home/ywhkkx/ex1.linklab/l5] ./linkbomb5 PP$;`;;``;
没有段错误了,但是输出很奇怪(有些地方没有改好)
收获
以前就对 link 有困惑,做了这个实验感受了一下 link 的过程后,发现自己对 link 的理解更清晰了
学习到了 objdump,readelf,hexedit 等工具的用法
看到了各个节在二进制文件的分布,学会了用“节偏移”和“节内偏移”来寻找需要的数据