本文主要是介绍HIT CSAPP LAB5,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
LinkLab
链接
目 录
第1章 实验基本信息 - 3 -
1.1 实验目的 - 3 -
1.2 实验环境与工具 - 3 -
1.2.1 硬件环境 - 3 -
1.2.2 软件环境 - 3 -
1.2.3 开发工具 - 3 -
1.3 实验预习 - 3 -
第2章 实验预习 - 5 -
2.1 ELF文件格式解读 - 5 -
2.2程序的内存映像结构 - 5 -
2.3程序中符号的位置分析 - 6 -
2.4程序运行过程分析 - 12 -
第3章 各阶段的原理与方法 - 15 -
3.1 阶段1的分析 - 15 -
3.2 阶段2的分析 - 16 -
3.3 阶段3的分析 - 21 -
3.4 阶段4的分析 - 23 -
3.5 阶段5的分析 - 26 -
第4章 总结 - 36 -
4.1 请总结本次实验的收获 - 36 -
4.2 请给出对本次实验内容的建议 - 36 -
参考文献 - 37 -
第1章 实验基本信息
1.1 实验目的
理解链接的作用与工作步骤
掌握 ELF 结构、符号解析与重定位的工作过程
熟练使用 Linux 工具完成 ELF 分析与修改
1.2 实验环境与工具
1.2.1 硬件环境
X64 CPU;2GHz;2G RAM;256GHD Disk 以上
1.2.2 软件环境
Windows7 64位以上;VirtualBox/Vmware 11以上;Ubuntu 16.04 LTS 64位/优麒麟 64位;
1.2.3 开发工具
Visual Studio 2010 64位以上;GDB/OBJDUMP;DDD/EDB等
1.3 实验预习
上实验课前,必须认真预习实验指导书(PPT或PDF)
了解实验的目的、实验环境与软硬件工具、实验操作步骤,复习与实验有关的理论知识。
请按顺序写出ELF格式的可执行目标文件的各类信息。
请按照内存地址从低到高的顺序,写出Linux下X64内存映像。
请运行“LinkAddress -u 学号 姓名” 按地址顺序写出各符号的地址、空间。并按照Linux下X64内存映像标出其所属各区。
请按顺序写出LinkAddress从开始执行到main前/后执行的子程序的名字。(gcc与objdump/GDB/EDB)
第2章 实验预习
2.1 ELF文件格式解读
请按顺序写出ELF格式的可执行目标文件的各类信息(5分)
ELF头
段头部表:将连续的文件映射到运行时的内存段。
.init:定义了_init函数,程序初始化代码会调用它。
.text:已编译程序的机器代码。
.rodata:只读数据,比如printf语句中的格式串和开关语句的跳转表
.data:已初始化的全局和静态C变量。局部C变量在运行时被保存在栈中,既不出现在.data节中,也不出现在.bss节中。
.bss:未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态变量。
.symtab:一个符号表,它存放在程序中定义和引用的函数和全局变量的信息。
.debug:一个调试符号表,其条目时程序中定义的全局变量和类型定义,程序中定义和引用的全局变量,以及原始的C源文件。
.line:原始C源程序的行号和.text节中机器指令之间的映射
.strtab:一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。
节头部表:描述目标文件的节。
2.2程序的内存映像结构
请按照内存地址从低到高的顺序,写出Linux下X64内存映像(5分)
2.3程序中符号的位置分析
请运行“LinkAddress -u 学号 姓名” 按地址顺序写出各符号的地址、空间。并按照Linux下X64内存映像标出其所属各区(5分)
所属区 | 各符号的地址、空间(地址从小到大) |
---|---|
只读代码段(.init , .text , .rodata) | exit 0x400630 4195888 printf 0x400600 4195840 malloc 0x400620 4195872 free 0x4005d0 4195792 |
读写段(.data .bss) | show_pointer 0x400746 4196166 useless 0x400777 4196215 main 0x400782 4196226 global 0x60206c 6299756 huge array 0x602080 6299776 big array 0x40602080 1080041600 |
运行时堆(由malloc创建) | p1 0x7febf17c9010 140651345514512 p2 0x435a5420 1129993248 p3 0x7fec01d7a010 140651619917840 p4 0x7febb17c8010 140650271768592 p5 (nil) 0 |
用户栈(运行时创建) | argc 0x7ffd01e746dc 140724635387612 local 0x7ffd01e746e0 140724635387616 argv 0x7ffd01e74808 140724635387912 argv[0] 7ffd01e751d2 argv[1] 7ffd01e751e0 argv[2] 7ffd01e751e3 argv[3] 7ffd01e751ee argv[0] 0x7ffd01e751d2 140724635390418 ./linkaddress argv[1] 0x7ffd01e751e0 140724635390432 -u argv[2] 0x7ffd01e751e3 140724635390435 “这里是学号再挣扎一下嘻嘻” argv[3] 0x7ffd01e751ee 140724635390446 “这里是姓名” env 0x7ffd01e74830 140724635387952 env 0x7fff66970c70 140734914563184 env[0] env 0x7fff669721f8 140734914568696 XDG_VTNR=7 env[1] env 0x7fff66972203 140734914568707 LC_PAPER=zh_CN.UTF-8 env[2] env 0x7fff66972218 140734914568728 LC_ADDRESS=zh_CN.UTF-8 env[3] env 0x7fff6697222f 140734914568751 XDG_SESSION_ID=c2 env[4] env 0x7fff66972241 140734914568769 XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/helloworld env[5] env 0x7fff66972277 140734914568823 LC_MONETARY=zh_CN.UTF-8 env[6] env 0x7fff6697228f 140734914568847 CLUTTER_IM_MODULE=xim env[7] env 0x7fff669722a5 140734914568869 SESSION=ubuntu env[8] env 0x7fff669722b4 140734914568884 GPG_AGENT_INFO=/home/helloworld/.gnupg/S.gpg-agent:0:1 env[9] env 0x7fff669722eb 140734914568939 TERM=xterm-256color env[10] env 0x7fff669722ff 140734914568959 VTE_VERSION=4205 env[11] env 0x7fff66972310 140734914568976 XDG_MENU_PREFIX=gnome- env[12] env 0x7fff66972327 140734914568999 SHELL=/bin/bash env[13] env 0x7fff66972337 140734914569015 QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1 env[14] env 0x7fff6697235a 140734914569050 WINDOWID=54525962 env[15] env 0x7fff6697236c 140734914569068 LC_NUMERIC=zh_CN.UTF-8 env[16] env 0x7fff66972383 140734914569091 UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/2061 env[17] env 0x7fff669723c7 140734914569159 GNOME_KEYRING_CONTROL= env[18] env 0x7fff669723de 140734914569182 GTK_MODULES=gail:atk-bridge:unity-gtk-module env[19] env 0x7fff6697240b 140734914569227 USER=helloworld env[20] env 0x7fff6697241b 140734914569243 LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:.tar=01;31:.tgz=01;31:.arc=01;31:.arj=01;31:.taz=01;31:.lha=01;31:.lz4=01;31:.lzh=01;31:.lzma=01;31:.tlz=01;31:.txz=01;31:.tzo=01;31:.t7z=01;31:.zip=01;31:.z=01;31:.Z=01;31:.dz=01;31:.gz=01;31:.lrz=01;31:.lz=01;31:.lzo=01;31:.xz=01;31:.bz2=01;31:.bz=01;31:.tbz=01;31:.tbz2=01;31:.tz=01;31:.deb=01;31:.rpm=01;31:.jar=01;31:.war=01;31:.ear=01;31:.sar=01;31:.rar=01;31:.alz=01;31:.ace=01;31:.zoo=01;31:.cpio=01;31:.7z=01;31:.rz=01;31:.cab=01;31:.jpg=01;35:.jpeg=01;35:.gif=01;35:.bmp=01;35:.pbm=01;35:.pgm=01;35:.ppm=01;35:.tga=01;35:.xbm=01;35:.xpm=01;35:.tif=01;35:.tiff=01;35:.png=01;35:.svg=01;35:.svgz=01;35:.mng=01;35:.pcx=01;35:.mov=01;35:.mpg=01;35:.mpeg=01;35:.m2v=01;35:.mkv=01;35:.webm=01;35:.ogm=01;35:.mp4=01;35:.m4v=01;35:.mp4v=01;35:.vob=01;35:.qt=01;35:.nuv=01;35:.wmv=01;35:.asf=01;35:.rm=01;35:.rmvb=01;35:.flc=01;35:.avi=01;35:.fli=01;35:.flv=01;35:.gl=01;35:.dl=01;35:.xcf=01;35:.xwd=01;35:.yuv=01;35:.cgm=01;35:.emf=01;35:.ogv=01;35:.ogx=01;35:.aac=00;36:.au=00;36:.flac=00;36:.m4a=00;36:.mid=00;36:.midi=00;36:.mka=00;36:.mp3=00;36:.mpc=00;36:.ogg=00;36:.ra=00;36:.wav=00;36:.oga=00;36:.opus=00;36:.spx=00;36:*.xspf=00;36: env[21] *env 0x7fff669729a3 140734914570659 QT_ACCESSIBILITY=1 env[22] *env 0x7fff669729b6 140734914570678 LC_TELEPHONE=zh_CN.UTF-8 env[23] *env 0x7fff669729cf 140734914570703 XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0 env[24] *env 0x7fff66972a09 140734914570761 XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0 env[25] *env 0x7fff66972a3d 140734914570813 SSH_AUTH_SOCK=/run/user/1000/keyring/ssh env[26] *env 0x7fff66972a66 140734914570854 SESSION_MANAGER=local/ubuntu:@/tmp/.ICE-unix/2295,unix/ubuntu:/tmp/.ICE-unix/2295 env[27] *env 0x7fff66972ab8 140734914570936 DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path env[28] *env 0x7fff66972aeb 140734914570987 XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg env[29] *env 0x7fff66972b2f 140734914571055 DESKTOP_SESSION=ubuntu env[30] *env 0x7fff66972b46 140734914571078 PATH=/home/helloworld/bin:/home/helloworld/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin env[31] *env 0x7fff66972bdf 140734914571231 QT_IM_MODULE=fcitx env[32] *env 0x7fff66972bf2 140734914571250 QT_QPA_PLATFORMTHEME=appmenu-qt5 env[33] *env 0x7fff66972c13 140734914571283 LC_IDENTIFICATION=zh_CN.UTF-8 env[34] *env 0x7fff66972c31 140734914571313 XDG_SESSION_TYPE=x11 env[35] *env 0x7fff66972c46 140734914571334 PWD=/home/helloworld/hitics/lab5/32 |
env[36] *env 0x7fff66972c6a 140734914571370 JOB=dbus env[37] *env 0x7fff66972c73 140734914571379 XMODIFIERS=@im=fcitx env[38] *env 0x7fff66972c88 140734914571400 GNOME_KEYRING_PID= env[39] *env 0x7fff66972c9b 140734914571419 LANG=zh_CN.UTF-8 env[40] *env 0x7fff66972cac 140734914571436 GDM_LANG=zh_CN env[41] *env 0x7fff66972cbb 140734914571451 MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path env[42] *env 0x7fff66972cf1 140734914571505 LC_MEASUREMENT=zh_CN.UTF-8 env[43] *env 0x7fff66972d0c 140734914571532 COMPIZ_CONFIG_PROFILE=ubuntu env[44] *env 0x7fff66972d29 140734914571561 IM_CONFIG_PHASE=1 env[45] *env 0x7fff66972d3b 140734914571579 PAPERSIZE=a4 env[46] *env 0x7fff66972d48 140734914571592 GDMSESSION=ubuntu env[47] *env 0x7fff66972d5a 140734914571610 SESSIONTYPE=gnome-session env[48] *env 0x7fff66972d74 140734914571636 GTK2_MODULES=overlay-scrollbar env[49] *env 0x7fff66972d93 140734914571667 SHLVL=1 env[50] *env 0x7fff66972d9b 140734914571675 HOME=/home/helloworld env[51] *env 0x7fff66972db1 140734914571697 XDG_SEAT=seat0 env[52] *env 0x7fff66972dc0 140734914571712 LANGUAGE=zh_CN:en_US:en env[53] *env 0x7fff66972dd8 140734914571736 GNOME_DESKTOP_SESSION_ID=this-is-deprecated env[54] *env 0x7fff66972e04 140734914571780 XDG_SESSION_DESKTOP=ubuntu env[55] *env 0x7fff66972e1f 140734914571807 LOGNAME=helloworld env[56] *env 0x7fff66972e32 140734914571826 DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-QnglPcTmlQ env[57] *env 0x7fff66972e6e 140734914571886 XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop env[58] *env 0x7fff66972ed2 140734914571986 QT4_IM_MODULE=fcitx env[59] *env 0x7fff66972ee6 140734914572006 LESSOPEN= | /usr/bin/lesspipe %s env[60] *env 0x7fff66972f06 140734914572038 INSTANCE= env[61] *env 0x7fff66972f10 140734914572048 XDG_RUNTIME_DIR=/run/user/1000 env[62] *env 0x7fff66972f2f 140734914572079 DISPLAY=:0 env[63] *env 0x7fff66972f3a 140734914572090 XDG_CURRENT_DESKTOP=Unity env[64] *env 0x7fff66972f54 140734914572116 GTK_IM_MODULE=fcitx env[65] *env 0x7fff66972f68 140734914572136 LESSCLOSE=/usr/bin/lesspipe %s %s env[66] *env 0x7fff66972f8a 140734914572170 LC_TIME=zh_CN.UTF-8 env[67] *env 0x7fff66972f9e 140734914572190 LC_NAME=zh_CN.UTF-8 env[68] *env 0x7fff66972fb2 140734914572210 XAUTHORITY=/home/helloworld/.Xauthority env[69] *env 0x7fff66972fda 140734914572250 _=./linkaddress |
linkaddress.c程序如下:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>static void show_pointer(void *p, char *descr) {// printf("Pointer for %s at %p\n", descr, p);printf("%s\t%p\t%lu\n", descr, p, (unsigned long) p);
}char big_array[1L<<24]; /* 16 MB */
char huge_array[1L<<30]; /* 1 GB */
int global = 0;int useless() { return 0; }int main (int argc,char *argv[])
{char **env = __environ; //环境变量__environ void *p1, *p2, *p3, *p4,*p5;int local = 0;if(argc!=4){printf("Usage: LinkAddress P1 P2 P3\n");return 1;}useless(); //打印系统变量信息 show_pointer((void *) env, "env");int i=0;while(*env) { printf("env[%d]\t",i);show_pointer((void *) (*env), "*env");puts(*env); env++; i++;} p1 = malloc(1L << 28);p2 = malloc(1L << 17);p3 = malloc( (1L << 17) +1);p4 = malloc(1L << 30);p5 = malloc(1L << 31);show_pointer((void *) big_array, "big array");show_pointer((void *) huge_array, "huge array");show_pointer((void *) &local, "local");show_pointer((void *) &global, "global");show_pointer((void *) &argc, "argc");show_pointer((void *) argv, "argv");printf("argv[0] %16lx\n",(unsigned long) (*argv));printf("argv[1] %16lx\n",(unsigned long) (*(argv+1))); //argv[1] argv 指针+1 就是argv地址+8printf("argv[2] %16lx\n",(unsigned long) (*(argv+2)));printf("argv[3] %16lx\n",(unsigned long) (*(argv+3)));show_pointer((void *) argv[0], "argv[0]");printf("%s\n",argv[0]);show_pointer((void *) argv[1], "argv[1]");printf("%s\n",argv[1]);show_pointer((void *) argv[2], "argv[2]");printf("%s\n",argv[2]);show_pointer((void *) argv[3], "argv[3]");printf("%s\n",argv[3]);show_pointer((void *) p1, "p1");show_pointer((void *) p2, "p2");show_pointer((void *) p3, "p3");show_pointer((void *) p4, "p4");show_pointer((void *) p5, "p5");show_pointer((void *) show_pointer, "show_pointer");show_pointer((void *) useless, "useless");show_pointer((void *) main, "main");show_pointer((void *) exit, "exit");show_pointer((void *) printf, "printf");show_pointer((void *) malloc, "malloc");show_pointer((void *) free, "free");free(p1); free(p2); free(p3); free(p4); return 0;
}
2.4程序运行过程分析
请按顺序写出LinkAddress从开始执行到main前/后执行的子程序的名字(使用gcc与objdump/GDB/EDB)(5分)
main()执行前:
Breakpoint 9, 0x0000000000400650 in _start ()
Breakpoint 6, 0x0000000000400610 in __libc_start_main@plt ()
Breakpoint 17, 0x0000000000400b10 in __libc_csu_init ()
Breakpoint 1, 0x0000000000400598 in _init ()
Breakpoint 13, 0x0000000000400720 in frame_dummy ()
Breakpoint 11, 0x00000000004006c0 in register_tm_clones ()
main执行时:
Breakpoint 16, 0x0000000000400782 in main ()
main执行后:
Breakpoint 3, 0x00000000004005e0 in puts@plt ()
Breakpoint 7, 0x0000000000400620 in malloc@plt ()
Breakpoint 12, 0x0000000000400700 in __do_global_dtors_aux ()
Breakpoint 10, 0x0000000000400680 in deregister_tm_clones ()
Breakpoint 19, 0x0000000000400b84 in _fini ()
objdump中:
main()前:
Breakpoint 1 at 0x400598
<function, no debug info> _init;
Breakpoint 2 at 0x4005d0
<function, no debug info> free@plt;
Breakpoint 3 at 0x4005e0
<function, no debug info> puts@plt;
Breakpoint 4 at 0x4005f0
<function, no debug info> __stack_chk_fail@plt;
Breakpoint 5 at 0x400600
<function, no debug info> printf@plt;
Breakpoint 6 at 0x400610
<function, no debug info> __libc_start_main@plt;
Breakpoint 7 at 0x400620
<function, no debug info> malloc@plt;
Breakpoint 8 at 0x400630
<function, no debug info> exit@plt;
Breakpoint 9 at 0x400650
<function, no debug info> _start;
Breakpoint 10 at 0x400680
<function, no debug info> deregister_tm_clones;
Breakpoint 11 at 0x4006c0
<function, no debug info> register_tm_clones;
Breakpoint 12 at 0x400700
<function, no debug info> __do_global_dtors_aux;
Breakpoint 13 at 0x400720
<function, no debug info> frame_dummy;
Breakpoint 14 at 0x400746
<function, no debug info> show_pointer;
Breakpoint 15 at 0x400777
<function, no debug info> useless;
main():
Breakpoint 16 at 0x400782
<function, no debug info> main;
main()后:
Breakpoint 17 at 0x400b10
<function, no debug info> __libc_csu_init;
Breakpoint 18 at 0x400b80
<function, no debug info> __libc_csu_fini;
Breakpoint 19 at 0x400b84
<function, no debug info> _fini;
第3章 各阶段的原理与方法
每阶段40分,phasex.o 20分,分析20分,总分不超过80分
3.1 阶段1的分析
程序运行结果截图:
分析与设计的过程:
首先readelf -a phase1.o 查看elf文件内容,根据节头信息可知,字符串输出起始地址在 .data 段中,.data节开始于0x80的位置。
运行linkbomb1程序,查看输出的字符串如下图:
找到 .data节,找到与乱码字符串相同的位置,偏移量为11(10)的地方为待输入字符串所在地址,
使用hexedit修改其ascii码,(学号) 的ascii码为(学号),最后再以00表示字符串结束,于是得到以下的修改结果。再次链接并且运行linkbomb1即可输出(学号)。
3.2 阶段2的分析
程序运行结果截图:
分析与设计的过程:
查看phase2.o的反汇编代码:
反汇编代码如下:
phase2.o: 文件格式 elf32-i386Disassembly of section .text:00000000 <cbLxqPqM>:0: 55 push %ebp1: 89 e5 mov %esp,%ebp3: 53 push %ebx4: 83 ec 04 sub $0x4,%esp7: e8 fc ff ff ff call 8 <cbLxqPqM+0x8>c: 81 c3 02 00 00 00 add $0x2,%ebx12: 83 ec 08 sub $0x8,%esp15: 8d 83 00 00 00 00 lea 0x0(%ebx),%eax1b: 50 push %eax1c: ff 75 08 pushl 0x8(%ebp)1f: e8 fc ff ff ff call 20 <cbLxqPqM+0x20>24: 83 c4 10 add $0x10,%esp27: 85 c0 test %eax,%eax29: 75 10 jne 3b <cbLxqPqM+0x3b>2b: 83 ec 0c sub $0xc,%esp2e: ff 75 08 pushl 0x8(%ebp)31: e8 fc ff ff ff call 32 <cbLxqPqM+0x32>36: 83 c4 10 add $0x10,%esp39: eb 01 jmp 3c <cbLxqPqM+0x3c>3b: 90 nop3c: 8b 5d fc mov -0x4(%ebp),%ebx3f: c9 leave 40: c3 ret 00000041 <do_phase>:41: 55 push %ebp42: 89 e5 mov %esp,%ebp44: e8 fc ff ff ff call 45 <do_phase+0x4>49: 05 01 00 00 00 add $0x1,%eax4e: 90 nop4f: 90 nop50: 90 nop51: 90 nop52: 90 nop53: 90 nop54: 90 nop55: 90 nop56: 90 nop57: 90 nop58: 90 nop59: 90 nop5a: 90 nop5b: 90 nop5c: 90 nop5d: 90 nop5e: 90 nop5f: 90 nop60: 90 nop61: 90 nop62: 90 nop63: 90 nop64: 90 nop65: 90 nop66: 90 nop67: 90 nop68: 90 nop69: 90 nop6a: 90 nop6b: 90 nop6c: 90 nop6d: 90 nop6e: 90 nop6f: 5d pop %ebp70: c3 ret Disassembly of section .text.__x86.get_pc_thunk.ax:00000000 <__x86.get_pc_thunk.ax>:0: 8b 04 24 mov (%esp),%eax3: c3 ret Disassembly of section .text.__x86.get_pc_thunk.bx:00000000 <__x86.get_pc_thunk.bx>:0: 8b 1c 24 mov (%esp),%ebx3: c3 ret
其中含有函数cbLxqPqM,对其进行gdb,使用jump等指令对函数cbLxqPqM相应内容进行查看:
可以得到此时待比较字符串内容为学号(学号)。而执行strcmp之前向栈中压入了两个参数id以及MYID,我们需要在do_phase函数的nop部分,执行压栈,并且跳转到cbLxqPqM函数。
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…” );
}
查看main函数, call 0x804848f <__x86.get_pc_thunk.ax> 和add $0x1bb1, %eax指令,实现了%eax指向_GLOBAL_OFFSET_TABLE。
查看cbLxqPqM函数,同样的 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 函数跳转到cbLxqPqM函数。由于函数此时地址为0x08048493,而do_phase函数执行到lea -0x19fc(%eax),%eax时%eax的值为0x8048604,根据二者的差值,即可跳转至%eax减去0x171处的地址。
故而采用以下汇编代码:
leal -0x19fc(%eax),%eax
leal -0x171(%eax),%ecx
pushl %eax
calll *%ecx
popl %eax
将其插入第一个nop(90)0x44+0x4e=0x92即可:
3.3 阶段3的分析
程序运行结果截图:
分析与设计的过程:
分析do_phase的反汇编指令,获取COOKIE字符串。gcc -m32 -o linkbomb3 main.o phase3.o链接之后,使用gdb进行调试do_phase函数:
其中白色部分为循环部分,如下图。显然这部分循环可以写成如下形式:
char PHASE3_CODEBOOK[256];
void do_phase(){ const char cookie[] = PHASE3_COOKIE; for( int i=0; i<sizeof(cookie)-1; i++ ) printf( "%c", PHASE3_CODEBOOK[ (unsigned char)(cookie[i]) ] );printf( "\n" );
}
反汇编代码如下:
phase3.o: 文件格式 elf32-i386Disassembly of section .text:00000000 <do_phase>:0: 55 push %ebp1: 89 e5 mov %esp,%ebp3: 53 push %ebx4: 83 ec 24 sub $0x24,%esp7: e8 fc ff ff ff call 8 <do_phase+0x8>c: 81 c3 02 00 00 00 add $0x2,%ebx12: 65 a1 14 00 00 00 mov %gs:0x14,%eax18: 89 45 f4 mov %eax,-0xc(%ebp)1b: 31 c0 xor %eax,%eax1d: c7 45 e9 76 69 6a 72 movl $0x726a6976,-0x17(%ebp)24: c7 45 ed 65 62 7a 75 movl $0x757a6265,-0x13(%ebp)2b: 66 c7 45 f1 73 70 movw $0x7073,-0xf(%ebp)31: c6 45 f3 00 movb $0x0,-0xd(%ebp)35: c7 45 e4 00 00 00 00 movl $0x0,-0x1c(%ebp)3c: eb 2b jmp 69 <do_phase+0x69>3e: 8d 55 e9 lea -0x17(%ebp),%edx41: 8b 45 e4 mov -0x1c(%ebp),%eax44: 01 d0 add %edx,%eax46: 0f b6 00 movzbl (%eax),%eax49: 0f b6 c0 movzbl %al,%eax4c: 8b 93 00 00 00 00 mov 0x0(%ebx),%edx52: 0f b6 04 02 movzbl (%edx,%eax,1),%eax56: 0f be c0 movsbl %al,%eax59: 83 ec 0c sub $0xc,%esp5c: 50 push %eax5d: e8 fc ff ff ff call 5e <do_phase+0x5e>62: 83 c4 10 add $0x10,%esp65: 83 45 e4 01 addl $0x1,-0x1c(%ebp)69: 8b 45 e4 mov -0x1c(%ebp),%eax6c: 83 f8 09 cmp $0x9,%eax6f: 76 cd jbe 3e <do_phase+0x3e>71: 83 ec 0c sub $0xc,%esp74: 6a 0a push $0xa76: e8 fc ff ff ff call 77 <do_phase+0x77>7b: 83 c4 10 add $0x10,%esp7e: 90 nop7f: 8b 45 f4 mov -0xc(%ebp),%eax82: 65 33 05 14 00 00 00 xor %gs:0x14,%eax89: 74 05 je 90 <do_phase+0x90>8b: e8 fc ff ff ff call 8c <do_phase+0x8c>90: 8b 5d fc mov -0x4(%ebp),%ebx93: c9 leave 94: c3 ret Disassembly of section .text.__x86.get_pc_thunk.bx:00000000 <__x86.get_pc_thunk.bx>:0: 8b 1c 24 mov (%esp),%ebx3: c3 ret
运行到图示处,再接着查看%ebp-0x17处的cookie内容,存储内容为vijrebzusp。
使用readelf确定PHASE3_CODEBOOK[256]数组对应的名称。readelf -a phase3.o得到:
Num为11处,Ndx为COM,Name为qZwfEQMjKc。故而数组PHASE3_CODEBOOK[256]实际名称为qZwfEQMjKc。这是因为QDwnxQFyLh已经在phase3.o中有了全局弱定义,所以必然存在于符号表.symtab中。
从而只要使相应位置字符为学号即可。cookie中字符串vijrebzusp转换为ascii为(十进制):118 105 106 114 101 98 122 117 115 112,将以上相应位置的字符改为学号(学号)即可。然后将该.c文件预处理编译汇编成.o文件。
char qZwfEQMjKc[256] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0aa3aaa18aaaaa9a01a71aaa0aaaaaaa";
3.4 阶段4的分析
程序运行结果截图:
分析与设计的过程:
查看do_phase处的反汇编代码,可以看出应该是switch开关语句,图片如下。
每次比较之前都将cookie字符-0x41与0x19进行比较,并跳转到%eax所存的地址处,%eax的值为(((%eax-0x41)<<2)+%ebx-0x189c),外括号代表寻址, 这里是将cookie值作为索引映射到switch跳转表,switch跳转表保存在.rodata中。当将main.o和phase4.o链接之后确定跳转表的值。当程序运行时,程序先拿到跳转表的值,跳转表中存放着相对偏移位置,通过 %eax=%ebx+偏移量 获得存储在.text段中共的case代码段地址,之后跳转执行。
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顺序建议不一样 case ‘A’: { c = 48; break; } case ‘B’: { c = 121; break; } … case ‘Z’: { c = 93; break; } } printf("%c", c); }
}
我们可以得到所有的case类在跳转表里面对应的偏移量,我们选择输出指定字母串为学号的case块的跳转表偏移量,按cookie映射顺序与位置填入到.rodata跳转表之中。偏移量依次为7,22,17,21,0,18,11,6,3,5
查看.rel.rodata段获取偏移量值:
由于每次重定位时都会覆盖.rodata段的值,故而选择更改.rel.rodata段的值。根据输出的值4:7aB<MkW~,将.rel.rodata从0x648开始更改,可以知道原来分别对应.L12,.L27,.L22,.L26,.L4,.L23,.L16,.L11,.L8,.L10,根据偏移量将对应位置的对应信息更改,分别改成.L24,L24,.L20,.L28,.L18,.L28,.L28,.L22,.L24,.L29,
如图所示:
3.5 阶段5的分析
程序运行结果截图:
分析与设计的过程:
使用readlef查看phase5.o的信息:
.rel.text从0x6e8起,占的内存为0xd8;.rel.rodata从0x7c0起,占0x40。
查看相应信息,相应信息对应内容如下:
offset | 需要进行重定向的代码在.text或.data节中的偏移位置,4个字节。 |
---|---|
info | 包括symbol和type两部分,其中symbol占前3个字节,type占后1个字节,symbol代表重定位到的目标在.symtab中的偏移量,type代表重定位的类型 |
Type | 重定位到的目标的类型 |
name | 重定位到的目标的名称 |
与第四轮相同,一个重定位信息占8个字节,前4个字节代表offset,后四个字节代表info,其中info的高3个字节代表symbol是该symbol在.symtab中的Num,info的低1个字节代表type。
将.rel.text的已有重定位信息整理如下,重定位的代码中8个缺少的部分,需要根据反汇编代码填写。
其中可能存在的type类型如下:
info.type | 含义 | 已知重定位目标 |
---|---|---|
02 | R_386_PC32 | __X86.get_pc_thunk.bx , transform_code,generate_code,encode,__X86.get_pc_thunk.ax |
0a | R_386_GOTPC | GLOBAL_OFFSET_TABLE |
09 | R_386_GOTOFF | .rodata , CODE,BUF |
04 | R_386_PLT32 | strlen,puts |
查看.rel.rodata节,其中有.L3,.L5,.L2,.L6,.L7,.L8,.L2,.L9,均已填充完毕,无需更改.rel.rodata段
再查看符号表.symtab中的具体信息,.L2,.L3,.L5,.L6,.L7,.L8,.L9在其中。
根据以上OBJECT可推知UJXJSd, mvEQni,CODE,BUF为数组或数组中的内容。根据.symtab同样可以获取偏移量。
查看具体代码:
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);
}
对反汇编代码进行说明和补充。
由.rel.rodata段(图片在上面)可以知道//部分是已经填充好的。
接下来对照代码根据功能填充(前面加了6个~)斜体部分,为了获取偏移量,我们根据反汇编代码将要更改的位置确定偏移量,根据.symtab表获取info的symbol(高3个字节)位,根据类型确定type(低一个字节)位。填充如下:
00000000 <transform_code>:0: 55 push %ebp1: 89 e5 mov %esp,%ebp3: e8 fc ff ff ff call 4 <transform_code+0x4>
~~~~~~//映射__x86.get_pc_thunk.ax 其offset为0x00000004 info为0x00001a028: 05 01 00 00 00 add $0x1,%eax
//映射_GLOBAL_OFFSET_TABLE_ 其offset为0x00000009 info为0x00001b0a d: 8b 55 0c mov 0xc(%ebp),%edx //%edx为mode10: 8b 94 90 00 00 00 00 mov 0x0(%eax,%edx,4),%edx
//映射UJXJSd TRAN_ARRAY 其offset为0x00000013 info为0x00001509 17: 83 e2 07 and $0x7,%edx1a: 83 fa 07 cmp $0x7,%edx1d: 77 68 ja 87 <.L2>1f: c1 e2 02 shl $0x2,%edx22: 8b 94 02 c0 00 00 00 mov 0xc0(%edx,%eax,1),%edx
//映射.rodata段 其offset为0x00000025 info为0x0000050929: 01 c2 add %eax,%edx2b: ff e2 jmp *%edx0000002d <.L3>:2d: f7 55 08 notl 0x8(%ebp)30: eb 59 jmp 8b <.L2+0x4>00000032 <.L5>:32: 8b 55 0c mov 0xc(%ebp),%edx35: 8b 84 90 00 00 00 00 mov 0x0(%eax,%edx,4),%eax
//映射UJXJSd 其offset为0x00000038 其info为0x000015093c: 83 e0 03 and $0x3,%eax3f: 89 c1 mov %eax,%ecx41: d3 7d 08 sarl %cl,0x8(%ebp)44: eb 45 jmp 8b <.L2+0x4>00000046 <.L6>:46: 8b 55 0c mov 0xc(%ebp),%edx49: 8b 84 90 00 00 00 00 mov 0x0(%eax,%edx,4),%eax
~~~~~~//映射UJXJSd 其offset为0x0000004c 其info为0x0000150950: f7 d0 not %eax52: 21 45 08 and %eax,0x8(%ebp)55: eb 34 jmp 8b <.L2+0x4>00000057 <.L7>:57: 8b 55 0c mov 0xc(%ebp),%edx5a: 8b 84 90 00 00 00 00 mov 0x0(%eax,%edx,4),%eax
//映射UJXJSd 其offset为0x0000005d 其info为0x0000150961: c1 e0 08 shl $0x8,%eax64: 09 45 08 or %eax,0x8(%ebp)67: eb 22 jmp 8b <.L2+0x4>00000069 <.L8>:69: 8b 55 0c mov 0xc(%ebp),%edx6c: 8b 84 90 00 00 00 00 mov 0x0(%eax,%edx,4),%eax
~~~~~~//映射UJXJSd 其offset为0x0000006f 其info为0x0000150973: 31 45 08 xor %eax,0x8(%ebp)76: eb 13 jmp 8b <.L2+0x4>00000078 <.L9>:78: 8b 55 0c mov 0xc(%ebp),%edx7b: 8b 84 90 00 00 00 00 mov 0x0(%eax,%edx,4),%eax
//映射UJXJSd 其offset为0x0000007e 其info为0x0000150982: 89 45 08 mov %eax,0x8(%ebp)85: eb 04 jmp 8b <.L2+0x4>00000087 <.L2>:87: f7 5d 08 negl 0x8(%ebp)8a: 90 nop8b: 8b 45 08 mov 0x8(%ebp),%eax8e: 5d pop %ebp8f: c3 ret 00000090 <generate_code>:90: 55 push %ebp91: 89 e5 mov %esp,%ebp93: 53 push %ebx94: 83 ec 10 sub $0x10,%esp97: e8 fc ff ff ff call 98 <generate_code+0x8>
~~~~~~//映射__x86.get_pc_thunk.bx 其offset为0x00000098 其info为0x00001d029c: 81 c3 02 00 00 00 add $0x2,%ebx
//映射_GLOBAL_OFFSET_TABLE_ 其offset为0x0000009e 其info为0x00001b0aa2: 8b 45 08 mov 0x8(%ebp),%eaxa5: 88 83 00 00 00 00 mov %al,0x0(%ebx)
//映射CODE 其offset为0x000000a7 其info为0x00001809ab: 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
~~~~~~//映射CODE 其offset为0x000000b7 其info为0x00001809bb: 0f be c0 movsbl %al,%eaxbe: ff 75 f8 pushl -0x8(%ebp)c1: 50 push %eaxc2: e8 fc ff ff ff call c3 <generate_code+0x33>
//映射transform_code 其offset为0x000000c3 其info为0x00001902c7: 83 c4 08 add $0x8,%espca: 88 83 00 00 00 00 mov %al,0x0(%ebx)
~~~~~~//映射CODE 其offset为0x000000cc 其info为0x00001809 d0: 83 45 f8 01 addl $0x1,-0x8(%ebp)d4: 8b 45 f8 mov -0x8(%ebp),%eaxd7: 83 f8 0a cmp $0xa,%eaxda: 76 d8 jbe b4 <generate_code+0x24>dc: 90 nopdd: 8b 5d fc mov -0x4(%ebp),%ebxe0: c9 leave e1: c3 ret ktkk) q000000e2 <encode>:e2: 55 push %ebpe3: 89 e5 mov %esp,%ebpe5: 53 push %ebxe6: 83 ec 14 sub $0x14,%espe9: e8 fc ff ff ff call ea <encode+0x8>
//映射__x86.get_pc_thunk.bx 其offset为0x000000ea 其info为0x00001d02ee: 81 c3 02 00 00 00 add $0x2,%ebx
~~~~~~//映射_GLOBAL_OFFSET_TABLE_ 其offset为0x000000f0 其info为0x00001b0af4: 83 ec 0c sub $0xc,%espf7: ff 75 08 pushl 0x8(%ebp)fa: e8 fc ff ff ff call fb <encode+0x19>
//映射strlen 其offset为0x000000fb 其info为0x00001f04ff: 83 c4 10 add $0x10,%esp102: 89 45 f4 mov %eax,-0xc(%ebp)105: c7 45 f0 00 00 00 00 movl $0x0,-0x10(%ebp)10c: eb 5d jmp 16b <encode+0x89>10e: 8b 55 f0 mov -0x10(%ebp),%edx111: 8b 45 08 mov 0x8(%ebp),%eax114: 01 d0 add %edx,%eax116: 0f b6 00 movzbl (%eax),%eax119: 0f be c0 movsbl %al,%eax11c: 0f b6 94 03 00 00 00 movzbl 0x0(%ebx,%eax,1),%edx
//映射mvEQni 其offset为0x00000120 其info为0x00001609123: 00 124: 0f b6 83 00 00 00 00 movzbl 0x0(%ebx),%eax
~~~~~~//映射CODE 其offset为0x00000127 其info为0x0000180912b: 89 d1 mov %edx,%ecx12d: 31 c1 xor %eax,%ecx12f: 8b 55 f0 mov -0x10(%ebp),%edx132: 8b 45 08 mov 0x8(%ebp),%eax135: 01 d0 add %edx,%eax137: 83 e1 7f and $0x7f,%ecx13a: 89 ca mov %ecx,%edx13c: 88 10 mov %dl,(%eax)13e: 8b 55 f0 mov -0x10(%ebp),%edx141: 8b 45 08 mov 0x8(%ebp),%eax144: 01 d0 add %edx,%eax146: 0f b6 00 movzbl (%eax),%eax149: 3c 1f cmp $0x1f,%al14b: 7e 0f jle 15c <encode+0x7a>14d: 8b 55 f0 mov -0x10(%ebp),%edx150: 8b 45 08 mov 0x8(%ebp),%eax153: 01 d0 add %edx,%eax155: 0f b6 00 movzbl (%eax),%eax158: 3c 7f cmp $0x7f,%al15a: 75 0b jne 167 <encode+0x85>15c: 8b 55 f0 mov -0x10(%ebp),%edx15f: 8b 45 08 mov 0x8(%ebp),%eax162: 01 d0 add %edx,%eax164: c6 00 20 movb $0x20,(%eax)167: 83 45 f0 01 addl $0x1,-0x10(%ebp)16b: 8b 45 f0 mov -0x10(%ebp),%eax16e: 3b 45 f4 cmp -0xc(%ebp),%eax171: 7c 9b jl 10e <encode+0x2c>173: 8b 45 f4 mov -0xc(%ebp),%eax176: 8b 5d fc mov -0x4(%ebp),%ebx179: c9 leave 17a: c3 ret 0000017b <do_phase>:17b: 55 push %ebp17c: 89 e5 mov %esp,%ebp17e: 53 push %ebx17f: 83 ec 04 sub $0x4,%esp182: e8 fc ff ff ff call 183 <do_phase+0x8>
~~~~~~//映射__x86.get_pc_thunk.bx 其offset为0x00000183 其info为0x00001d02 187: 81 c3 02 00 00 00 add $0x2,%ebx
//映射_GLOBAL_OFFSET_TABLE_ 其offset为0x00000189 其info为0x00001b0a18d: 68 ca 00 00 00 push $0xca192: e8 fc ff ff ff call 193 <do_phase+0x18>
//映射generate_code 其offset为0x00000193 其info为0x00001c02197: 83 c4 04 add $0x4,%esp19a: 83 ec 0c sub $0xc,%esp19d: 8d 83 00 00 00 00 lea 0x0(%ebx),%eax
//映射BUF 其offset为0x0000019f 其info为0x000017091a3: 50 push %eax1a4: e8 fc ff ff ff call 1a5 <do_phase+0x2a>
//映射encode 其offset为0x000001a5 其info为0x00001e021a9: 83 c4 10 add $0x10,%esp1ac: 83 ec 0c sub $0xc,%esp1af: 8d 83 00 00 00 00 lea 0x0(%ebx),%eax
//映射BUF 其offset为0x000001b1 其info为0x000017091b5: 50 push %eax1b6: e8 fc ff ff ff call 1b7 <do_phase+0x3c>
//映射puts 其offset为0x000001b7 其info为0x000021041bb: 83 c4 10 add $0x10,%esp1be: 90 nop1bf: 8b 5d fc mov -0x4(%ebp),%ebx1c2: c9 leave 1c3: c3 ret Disassembly of section .text.__x86.get_pc_thunk.ax:00000000 <__x86.get_pc_thunk.ax>:0: 8b 04 24 mov (%esp),%eax3: c3 ret Disassembly of section .text.__x86.get_pc_thunk.bx:00000000 <__x86.get_pc_thunk.bx>:0: 8b 1c 24 mov (%esp),%ebx3: c3 ret
按照上述规则按小端法填充,未填充时如下:
填充时如下:
这篇关于HIT CSAPP LAB5的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!