链接这一块呢,先看了李春凤老师的慕课,然后看一遍课本,然后来做实验,感觉真的懂了一样
把火炬传下去!
实验报告
实 验(四
题 目 LinkLab
链接
专 业 xxxx
学 号 xxxx
班 级 xxxx
学 生 xxxx
指 导 教 师 xxxx
实 验 地 点 xxxx
实 验 日 期 xxxx
计算机科学与技术学院
目 录
第1章 实验基本信息............................................................................................. - 3 -
1.1 实验目的......................................................................................................... - 3 -
1.2 实验环境与工具............................................................................................. - 3 -
1.2.1 硬件环境................................................................................................. - 3 -
1.2.2 软件环境................................................................................................. - 3 -
1.2.3 开发工具................................................................................................. - 3 -
1.3 实验预习......................................................................................................... - 3 -
第2章 实验预习..................................................................................................... - 4 -
2.1 请按顺序写出ELF格式的可执行目标文件的各类信息(5分)............ - 4 -
2.2请按照内存地址从低到高的顺序,写出Linux下X64内存映像。(5分) - 4 -
2.3请运行“LinkAddress -u 学号 姓名” 按地址循序写出各符号的地址、空间。并按照Linux下X64内存映像标出其所属各区。.................................. - 4 -
(5分)................................................................................................................ - 4 -
2.4请按顺序写出LinkAddress从开始执行到main前/后执行的子程序的名字。(gcc与objdump/GDB/EDB)(5分)........................................................ - 4 -
第3章 各阶段的原理与方法................................................................................. - 5 -
3.1 阶段1的分析................................................................................................. - 5 -
3.2 阶段2的分析............................................................................................... - 5 -
3.3 阶段3的分析............................................................................................... - 5 -
3.4 阶段4的分析............................................................................................... - 5 -
3.5 阶段5的分析............................................................................................... - 5 -
第4章 总结............................................................................................................. - 6 -
4.1 请总结本次实验的收获................................................................................. - 6 -
4.2 请给出对本次实验内容的建议..................................................................... - 6 -
参考文献................................................................................................................... - 7 -
理解链接的作用与工作步骤
掌握ELF结构与符号解析与重定位的工作过程
熟练使用Linux工具完成ELF分析与修改
X64 CPU;2GHz;2G RAM;256GHD Disk 以上
Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟 64位;
ELF头
段头部表:将连续的文件映射到运行时的内存段
. init : 定义了_init函数,程序初始化代码会调用它
. text : 已编译程序的机器代码
. rodata : 只读数据,比如printf语句中的格式串和开关语句的跳转表
. data : 已初始化的全局和静态C变量
. bss : 未初始化的全局和静态C变量
. symtab :一个符号表,它存放在程序中定义和引用的函数和全局变量的信息
. debug : 一个调试符号表,其条目时程序中定义的全局变量和类型定义,程序中定义和引用的全局变量,以及原始的C源文件。
. line : 原始C源程序的行号和.text节中机器指令之间的映射
. strtab : 一个字符串表,其内容包括 .symtab 和 .debug节中的符号表,以及节头部中的节名字。
节头部表:描述目标文件的节。
所属区 |
各符号的地址、空间(地址从小到大) |
只读代码段(.init , .text , .rodata) |
.rodata pstr 0x400ea 84198056 gc 0x400f44 4198212 cc 0x400ee0 4198112 .txt: show_pointer 0x400712 4196114 useless 0x400707 4196103 main 0x400737 4196151
exit 0x7f40bccf1120 139916022321440 printf 0x7f40bcd12e80 139916022460032 malloc 0x7f40bcd45070 139916022665328 free 0x7f40bcd45950 139916022667600 strcpy 0x7f40bcd64540 139916022793536
|
读写段(.data,.bss) |
.data: global 0x6020f0 6299888 glong 0x6020e8 6299880 cstr 0x602080 6299776 local static int 1 0x602060 6299744 .bss: big array 0x40602120 1080041760 huge array 0x602120 6299936 gint0 0x60210c 6299916 local static int 0 0x602110 6299920
|
运行时堆(由malloc创建) |
p1 0x7f40accad010 139915753607184 p2 0x4291e670 1116857968 p3 0x7f40bd28a010 139916028190736 p4 0x7f406ccac010 139914679861264 p5 (nil) 0 |
用户栈(运行时创建) |
argc 0x7fffeca45b3c 140737163582268 argv 0x7fffeca46058 140737163583576 argv[0] 7fffeca47329 argv[1] 7fffeca47334 argv[2] 7fffeca47337 argv[3] 7fffeca47342 argv[0] 0x7fffeca47329 140737163588393 ./linkaddr argv[1] 0x7fffeca47334 140737163588404 -u argv[2] 0x7fffeca47337 140737163588407 1180800811 argv[3] 0x7fffeca47342 140737163588418 张瑞豪 env 0x7fffeca46080 140737163583616 env[0] *env 0x7fffeca4734c 140737163588428 env[1] *env 0x7fffeca47362 140737163588450 env[2] *env 0x7fffeca4794e 140737163589966 LESSCLOSE=/usr/bin/lesspipe %s %s env[3] *env 0x7fffeca47970 140737163590000 XDG_MENU_PREFIX=gnome- env[4] *env 0x7fffeca47987 140737163590023 LANG=en_US.UTF-8 env[5] *env 0x7fffeca47998 140737163590040 MANAGERPID=1621 env[6] *env 0x7fffeca479a8 140737163590056 DISPLAY=:0 env[7] *env 0x7fffeca479b3 140737163590067 INVOCATION_ID=212316a40a94413780441c9dc64b059b env[8] *env 0x7fffeca479e2 140737163590114 GNOME_SHELL_SESSION_MODE=ubuntu env[9] *env 0x7fffeca47a02 140737163590146 COLORTERM=truecolor env[10] *env 0x7fffeca47a16 140737163590166 USERNAME=zrh1180800811 env[11] *env 0x7fffeca47a2d 140737163590189 XDG_VTNR=2 env[12] *env 0x7fffeca47a38 140737163590200 SSH_AUTH_SOCK=/run/user/1000/keyring/ssh env[13] *env 0x7fffeca47a61 140737163590241 XDG_SESSION_ID=2 env[14] *env 0x7fffeca47a72 140737163590258 USER=zrh1180800811 env[15] *env 0x7fffeca47a85 140737163590277 DESKTOP_SESSION=ubuntu env[16] *env 0x7fffeca47a9c 140737163590300 QT4_IM_MODULE=fcitx env[17] *env 0x7fffeca47ab0 140737163590320 TEXTDOMAINDIR=/usr/share/locale/ env[18] *env 0x7fffeca47ad1 140737163590353 GNOME_TERMINAL_SCREEN=/org/gnome/Terminal/screen/6baa25d2_824f_4d29_8dd3_f1361be4c409 env[19] *env 0x7fffeca47b27 140737163590439 PWD=/home/zrh1180800811/shiyan44 env[20] *env 0x7fffeca47b48 140737163590472 HOME=/home/zrh1180800811 env[21] *env 0x7fffeca47b61 140737163590497 JOURNAL_STREAM=9:51422 env[22] *env 0x7fffeca47b78 140737163590520 TEXTDOMAIN=im-config env[23] *env 0x7fffeca47b8d 140737163590541 SSH_AGENT_PID=1741 env[24] *env 0x7fffeca47ba0 140737163590560 QT_ACCESSIBILITY=1 env[25] *env 0x7fffeca47bb3 140737163590579 XDG_SESSION_TYPE=x11 env[26] *env 0x7fffeca47bc8 140737163590600 XDG_DATA_DIRS=/usr/share/ubuntu:/usr/local/share:/usr/share:/var/lib/snapd/desktop env[27] *env 0x7fffeca47c1b 140737163590683 XDG_SESSION_DESKTOP=ubuntu env[28] *env 0x7fffeca47c36 140737163590710 DBUS_STARTER_ADDRESS=unix:path=/run/user/1000/bus,guid=27b23190b25028168780b6775de2584d env[29] *env 0x7fffeca47c8e 140737163590798 GTK_MODULES=gail:atk-bridge env[30] *env 0x7fffeca47caa 140737163590826 WINDOWPATH=2 env[31] *env 0x7fffeca47cb7 140737163590839 TERM=xterm-256color env[32] *env 0x7fffeca47ccb 140737163590859 SHELL=/bin/bash env[33] *env 0x7fffeca47cdb 140737163590875 VTE_VERSION=5202 env[34] *env 0x7fffeca47cec 140737163590892 QT_IM_MODULE=fcitx env[35] *env 0x7fffeca47cff 140737163590911 XMODIFIERS=@im=fcitx env[36] *env 0x7fffeca47d14 140737163590932 IM_CONFIG_PHASE=2 env[37] *env 0x7fffeca47d26 140737163590950 DBUS_STARTER_BUS_TYPE=session env[38] *env 0x7fffeca47d44 140737163590980 XDG_CURRENT_DESKTOP=ubuntu:GNOME env[39] *env 0x7fffeca47d65 140737163591013 GPG_AGENT_INFO=/run/user/1000/gnupg/S.gpg-agent:0:1 env[40] *env 0x7fffeca47d99 140737163591065 GNOME_TERMINAL_SERVICE=:1.69 env[41] *env 0x7fffeca47db6 140737163591094 XDG_SEAT=seat0 env[42] *env 0x7fffeca47dc5 140737163591109 SHLVL=1 env[43] *env 0x7fffeca47dcd 140737163591117 GDMSESSION=ubuntu env[44] *env 0x7fffeca47ddf 140737163591135 GNOME_DESKTOP_SESSION_ID=this-is-deprecated env[45] *env 0x7fffeca47e0b 140737163591179 LOGNAME=zrh1180800811 env[46] *env 0x7fffeca47e21 140737163591201 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus,guid=27b23190b25028168780b6775de2584d env[47] *env 0x7fffeca47e7d 140737163591293 XDG_RUNTIME_DIR=/run/user/1000 env[48] *env 0x7fffeca47e9c 140737163591324 XAUTHORITY=/run/user/1000/gdm/Xauthority env[49] *env 0x7fffeca47ec5 140737163591365 XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdg env[50] *env 0x7fffeca47ef2 140737163591410 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin env[51] *env 0x7fffeca47f5a 140737163591514 SESSION_MANAGER=local/ubuntu:@/tmp/.ICE-unix/1651,unix/ubuntu:/tmp/.ICE-unix/1651 env[52] *env 0x7fffeca47fac 140737163591596 LESSOPEN=| /usr/bin/lesspipe %s env[53] *env 0x7fffeca47fcc 140737163591628 GTK_IM_MODULE=fcitx env[54] *env 0x7fffeca47fe0 140737163591648
|
Breakpoint 1 at 0x400598
Breakpoint 2 at 0x4005d0
Breakpoint 3 at 0x4005e0
Breakpoint 4 at 0x4005f0
Breakpoint 5 at 0x400600
Breakpoint 6 at 0x400610
Breakpoint 7 at 0x400620
Breakpoint 8 at 0x400630
Breakpoint 9 at 0x400650
Breakpoint 10 at 0x400680
Breakpoint 11 at 0x4006c0
Breakpoint 12 at 0x400700
Breakpoint 13 at 0x400720
Breakpoint 14 at 0x40074a
Breakpoint 15 at 0x40077b
Breakpoint 16 at 0x400786
Breakpoint 17 at 0x400b10
Breakpoint 18 at 0x400b80
Breakpoint 19 at 0x400b84
每阶段40分,phasex.o 20分,分析20分,总分不超过80分
3.1 阶段1的分析
程序运行结果截图:
分析与设计的过程:
首先
直接将main.o进行编译,得到linkbomb,运行之后显示如下截图
通过查看main的反汇编可以得出main函数的主要逻辑:判断phase是否为空,如果为空则打印上述输出字串,如果不为空则调用phase函数。
尝试将main.o与phase1.o进行链接,运行linkbomb后屏幕输出为:
可以看到这是一串没有什么特殊意义字符串。我们的目标就是将该字符串的前部替换为我们的学号,最终使屏幕输出我们的学号。
程序运行结果截图
分析与设计的过程:
首先将文件链接,gcc -m32 -o linkbomb2 main.o phase.o ,然后使用gdb对uorUhNQV函数进行调试。
do_phase函数结构如下:
分析strcmp函数,根据ppt给的提示,执行strcmp之前向栈中压入了两个参数,一个是MYID,另一个则是函数传入的参数。因此,整道题的逻辑就是,在do_phase函数的nop部栈,并且跳转到qmNFFwCm函数。
根据查询, call 0x804848f <__x86.get_pc_thunk.ax> 和add $0x1b24,%eax指令,实现了%eax指向_GLOBAL_OFFSET_TABLE,同样的 call 0x8048370 <__x86.get_pc_thunk.bx> 和add $0x1b61,%ebx 指令,实现了%ebx指向_GLOBAL_OFFSET_TABLE。
又因为%ebx之后还执行了lea -0x19fc(%ebx),%eax ,目的是重定位之后使%eax指向 .rodata ,因此在nop处填写的汇编代码中,需要同样的操作,使do_phase中%eax也指向 .rodata ,操作为lea -0x19fc(%eax),%eax 。
最后,我们需要使用相对寻址的方式,使do_phase 函数跳转到qmNFFwCm函数
对ELF文件的Section部分进行解析
objdump –s –d phase2.o > phase2.txt
查看phase2.txt的内容:
可知根据uorUhNQV的函数地址为0x5b5,而我们do_phase函数插入我们写的汇编代码后,执行lea -0x18b0(%eax),%eax时%eax的值为0x60c,分局二者的差值得0xffffffa6.因此可以写出汇编代码保存在getcode.s。
gcc -m32 -c getcode.s
objdump -d getcode.o > getcode.txt
得到
最后将得到的反汇编代码使用hexedit插入第一个nop处即可
再main.o与phase1.o进行链接,运行linkbomb1后屏幕输出为:
程序运行结果截图
分析与设计的过程:
获得数组名称
使用readelf确定PPT中所谓的PHASE3_CODEBOOK数组对应的名称。
readelf -a phase3.o > phase3.txt
得到:
可见,PHASE3_CODEBOOK的实际名称是QDwnxQFyLh。
这是因为QDwnxQFyLh已经在phase3.o中有了全局弱定义,所以必然存在于符号表.symtab中
分析do_phase结构
可见最终输出的字符存储在JmlRaMGuqe数组中,最终输出是使用cookie这个字符数组来进行寻址,cookie是已知不变的,所以我们的工作是:得到cookie数组,根据cookie数组构造JmlRaMGuqe数组,要求按照cookie的索引顺序在JmlRaMGuqe中依次填入自己的学号。
获得cookie数组
gcc -o linkbomb3 main.o phase3.o
得到linkbomb3,使用edb运行linkbomb3,点击运行,运行到main函数,然后单步运行到do_phase中的循环位置,如下:
得到我的cookie数组是moerdxakuc。
对应的ascall码为:109 111 101 114 100 120 97 107 117 99
因此我们只需要在字符数组cookie的字符所指向的JmlRaMGuqe数组的指定位置处 按顺序 填上自己的学号即可。
解释一下:比如我的cookie数组是moerdxakuc,正好10个对应我的10位学号,比如我要填第一个,‘m’对应ASCII码的109,所以我要使JmlRaMGuqe[109]=’1’。剩下的类似。其他地方随便填,我就用x填上了。
剩下的工作:在a.c中定义JmlRaMGuqe数组,
然后:
gcc -m32 -c a.c
gcc -m32 -o linkbomb3 main.o phase3.o a.o
程序运行结果截图:
分析与设计的过程:
程序运行结果截图:
分析与设计的过程:
通过这次实验,清楚地了解了链接这一章的知识。
学会使用readelf工具查看elf可重定位目标文件;
学会使用hexedit对 .o文件进行修改
掌握了链接过程中的符号解析和重定位的过程
掌握了可冲定位文件邻接成可执行目标文件的方法
建议老师讲的详细一点
注:本章为酌情加分项。
为完成本次实验你翻阅的书籍与网站等
[1] 林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42.
[2] 辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999.
[3] 赵耀东. 新时代的工业工程师[M/OL]. 台北:天下文化出版社,1998 [1998-09-26]. http://www.ie.nthu.edu.tw/info/ie.newie.htm(Big5).
[4] 谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.
[5] KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.
[6] CHRISTINE M. Plant Physiology: Plant Biology in the Genome Era[J/OL]. Science,1998,281:331-332[1998-09-23]. http://www.sciencemag.org/cgi/ collection/anatmorp.