csapp炸弹实验_bomb_lab详解

个人博客:sekyoro.top
之前图床挂了(没错是gitee),现在更新一下

开始的准备

CS:APP3e, Bryant and O’Hallaron (cmu.edu)

实验网址,有好几个lab.选择Bomb lab的self-study就行了.最新版2016年的.

原来做的时候老师没有发文档,现在有个bomblab文档,很有用.

我还找到了这篇pdf的机翻,不过建议一起看.《深入理解计算机系统》实验二Bomb Lab下载和官方文档机翻_达的程序员日记-CSDN博客

说实话,到现在我还是有点不懂

需要一点对于二进制文件和汇编基础.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MWwhnw05-1653359308633)(http://cdn.sekyoro.top/imgs/093711.png)]

  • ELF文件头:存储文件类型和大小的有关信息,以及文件加载后程序执行的入口信息
  • 程序头表:可执行文件的数据在虚拟地址空间中的组织方式,以及段的数目,位置以及用途
  • 节:将文件分成一个个节区,每个节区都有其对应的功能,如符号表,哈希表等
  • 段:就是将文件分成一段一段映射到内存中。段中通常包括一个或多个节区
  • 节头表:存储段的附加信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jBC33qd4-1653359308635)(http://cdn.sekyoro.top/imgs/093713.png)]

大端模式与小端模式

**大端:多字节值的大端存储在该值的起始位置;(老大站排头为大) **

小端:多字节值的小端存储在该值的起始位置

我这里是小端

64位cpu

objdump与gdb常用命令

(其实我觉得命令太多了记不完的,记住重要的需要时再查就行了)

objdump

-f 文件头信息

-h 节头表信息 输出目标文件中节表(Section Table)中所包含的所有节头(Section Header)的信息

-x 所有的头信息 包括文件头,程序头和节头还包括符号表信息

-d 反汇编 可执行节(段)信息

-D 反汇编所有节(段)信息

-S 源代码与汇编混合 编译时需要-g

-s 所有节以及二进制

-t 显示符号表

-T 动态符号表

文件头

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ke6K1Cqi-1653359308636)(http://cdn.sekyoro.top/imgs/065645.png)]

节(段)头信息

段头表

反汇编结果

反汇编

符号表

符号表

Linux objdump 命令用法详解-Linux命令大全(手册) (ipcmen.com)

节(段)介绍(注意.bss与.data .rodata)

  • .text:已编译程序的机器代码。
  • .rodata:只读数据,比如printf语句中的格式串和开关(switch)语句的跳转表。
  • .data:已初始化的全局C变量。局部C变量在运行时被保存在栈中,既不出现在.data中,也不出现在.bss节中。
  • .bss:未初始化的全局C变量。在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。目标文件格式区分初始化和未初始化变量是为了空间效率在:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。
  • .symtab:一个符号表(symbol table),它存放在程序中被定义和引用的函数和全局变量的信息。一些程序员错误地认为必须通过-g选项来编译一个程序,得到符号表信息。实际上,每个可重定位目标文件在.symtab中都有一张符号表。然而,和编译器中的符号表不同,.symtab符号表不包含局部变量的表目。
  • .rel.text:当链接噐把这个目标文件和其他文件结合时,.text节中的许多位置都需要修改。一般而言,任何调用外部函数或者引用全局变量的指令都需要修改。另一方面调用本地函数的指令则不需要修改。注意,可执行目标文件中并不需要重定位信息,因此通常省略,除非使用者显式地指示链接器包含这些信息。
  • .rel.data:被模块定义或引用的任何全局变量的信息。一般而言,任何已初始化全局变量的初始值是全局变量或者外部定义函数的地址都需要被修改。
  • .debug:一个调试符号表,其有些表目是程序中定义的局部变量和类型定义,有些表目是程序中定义和引用的全局变量,有些是原始的C源文件。只有以-g选项调用编译驱动程序时,才会得到这张表。
  • .line:原始C源程序中的行号和.text节中机器指令之间的映射。只有以-g选项调用编译驱动程序时,才会得到这张表。
  • .strtab:一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。字符串表就是以null结尾的字符串序列。
gdb

gdb 运行二进制文件

run 简介r 运行 直到执行整个程序或断点处

break 简写b 打断点

注意打断点可以在 行号 函数 内存地址处

delete 简写d 删除断点

x/nfu addr 按照指定的格式而非程序的数据类型考察内存数据(这个指令很有意思)

continue 简写c 继续执行被调试程序 直到下一个断点或结束

step 简写s 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数

next 简写n 执行一行源程序代码,此行代码中的函数调用也一并执行

注意对于汇编我们需要使用si,ni代替

print 简写p 显示变量值

display 设置程序中断后欲显示的数据及其格式 /i 表示以十六进行显示

undispaly,取消先前的display设置,编号从1开始递增

quit 简写q 退出

值得一提的是gdb tui模式,

gdb -tui #进入
#或者gdb进入后
focous #进入tui
ctrl+x a #退出tui
layout  asm|reg|split|src #展示相关信息
ctrl+p ctrl+n #gdb上一条 下一条命令
Ctrl + L #刷新窗口
Ctrl + x #再按1:单窗口模式,显示一个窗口
Ctrl + x #再按2:双窗口模式,显示两个窗口

先知道这么多吧.

Linux 调试器gdb命令及TUI模式

Enscript Output (cmu.edu)

注意汇编指令也有格式 可以看出这里是AT&T格式

Intel格式和AT&T格式汇编区别

同时注意汇编指令 call ret leave

call addr:
push rip
mov addr rip
#call指令 调用函数
ret :
pop rip
#ret指令  返回
leave :
mov rbp rsp
pop rbp
#leave指令 关闭栈帧

汇编语言CALL和RET指令:调用一个过程 (biancheng.net)

还有vim查看16进制,因为需要修改二进制可执行文件

#打开file文件
vim file
#在命令模式下输入.. 以16进制显示
:%!xxd
#在命令模式下输入.. 切换回默认显示
:%!xxd -r
readelf

-h ELF文件开始的文件头信息

-l 程序头 节到段的映射

-S 显示节头信息

-s 符号表信息

-r 显示可重定位段的信息

-d 显示动态段的信息

正式开始

initial_bomb

首先先看源文件,不得不说这个作者真的很humorous.

注意如果运行时无参数就读取输入,否则读取文件.

根据参数确定输入

然后进入了initialize_bomb函数,我们尝试看一看.

objdump -d bomb

这样可以查看.text段里的信息.

查看initialize_bomb这个函数

00000000004013a2 <initialize_bomb>:
  4013a2:       48 83 ec 08             sub    $0x8,%rsp
  4013a6:       be a0 12 40 00          mov    $0x4012a0,%esi
  4013ab:       bf 02 00 00 00          mov    $0x2,%edi
  4013b0:       e8 db f7 ff ff          callq  400b90 <signal@plt>
  4013b5:       48 83 c4 08             add    $0x8,%rsp
  4013b9:       c3   

首先开栈,注意这是x86_64架构的,mov指令是mov src->dst,这跟intel指令不一样.

AT&T 格式Intel 格式
movl -4(%ebp), %eaxmov eax, [ebp - 4]
movl array(, %eax, 4), %eaxmov eax, [eax*4 + array]
movw array(%ebx, %eax, 4), %cxmov cx, [ebx + 4*eax + array]
movb $4, %fs:(%eax)mov fs:eax, 4
寄存器描述
rdi传递第一个参数
rsi传递第二个参数

寄存器介绍这个可以看一看

这里有一篇很好的文章x86-64 规定只有6个寄存器来存参数,那 C 函数为什么还能超过6个参数呢? (mengkang.net)

当了解了汇编基础知识(其实可以面向搜索引擎学习,遇到不懂的指令去搜索就可以了)后,我们知道esi值第二个参数,edi是第一个参数.然后callq 400b90转去执行这个函数.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZvD6Ae3i-1653359308638)(http://cdn.sekyoro.top/imgs/093729.png)]

注意jmpq *0x2024c2(%rip)表示跳转到 %rip+0x2024c2地址所存储的值,即0x603058地址存储的值(是一个地址)

这个函数叫signal@plt,我也不懂,我在网上搜索后.这跟链接,重定位相关重定位和链接

Linux动态链接之GOT与PLT

Linux Debugging(七): 使用反汇编理解动态库函数调用方式GOT/PLT_anzhsoft的技术专栏-CSDN博客_动态库反汇编

assembly - What does @plt mean here? - Stack Overflow

在实际的可执行程序或者共享目标文件中,GOT表在名称为.got.plt的section中,PLT表在名称为.plt的section中

GOT是Global Offset Table,是保存库函数地址的区域。程序运行时,库函数的地址会设置到GOT中。由于动态库的函数是在使用时才被加载,因此刚开始GOT表是空的。地址的设置就涉及到了PLT,Procedure Linkage Table,它包含了一些代码以调用库函数,它可以被理解成一系列的小函数,这些小函数的数量其实就是库函数的被使用到的函数的数量。

简单来说,PLT就是跳转到GOT中所设置的地址而已。如果这个地址是空,那么PLT的跳转会巧妙的调用_dl_runtime_resolve去获取最终地址并设置到GOT中去。由于库函数的地址在运行时不会变,因此GOT一旦设置以后PLT就可以直接跳转到库函数的真实地址了。

stack overflow中的解答,类似的

printf@plt is actually a small stub which (eventually) calls the real printf function, modifying things on the way to make subsequent calls faster.

The real printf function may be mapped into any location in a given process (virtual address space) as may the code that is trying to call it.

So, in order to allow proper code sharing of calling code (left side below) and called code (right side below), you don’t want to apply any fixups to the calling code directly since that will restrict where it can be located in other processes.

让我们也试试看吧.

首先signal@plt跳转到一个地址(*0x603058),这里需要gdb看一看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rYvVps2S-1653359308639)(http://cdn.sekyoro.top/imgs/065647.png)]

所以jmp到了0x00400b96,这个这份地址又是什么呢,有点眼熟?注意signal@plt中的汇编代码,貌似我们又跳回来了.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iGCc1a3a-1653359308639)(http://cdn.sekyoro.top/imgs/065648.png)]

使用gdb的x指令查看内存的数据,指定x /5i 表示往后五个单位的指令(i表示指令),可以看出先把0x0b压栈,又跳转一个地址0x400ad0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6OfF7eS7-1653359308640)(http://cdn.sekyoro.top/imgs/093732.png)]

使用gdb执行到0x400ad0处

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hsxn7V27-1653359308640)(http://cdn.sekyoro.top/imgs/065650.png)]

我在这卡了很久,因为我以为跳转的就是这个地址,实际上这是32位的值,是原本64位地址的低地址.jmpq跳转到64位地址.这也跟我gdb使用不熟练有关

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ntM50ZqV-1653359308641)(http://cdn.sekyoro.top/imgs/065651.png)]

然后执行函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2QUB3Ai0-1653359308641)(http://cdn.sekyoro.top/imgs/093736.png)]

这中间又跳转执行了很多函数。

最后又跳了回来.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3rTKuH9z-1653359308642)(http://cdn.sekyoro.top/imgs/093738.png)]

GOT表和PLT表知识详解_qq_18661257的专栏-CSDN博客_got表

再来看看传入的参数0x4012a0,可以看到这是函数的地址[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B0u9uQ5t-1653359308642)(http://cdn.sekyoro.top/imgs/065652.png)]

可以知道在initial_bomb中使用了signal函数,传入信号量2,调用写的sig_handler函数.

sig_handler中进行了一些设置,主要捕获中断信号,针对ctrl+c.

C 库函数 – signal() | 菜鸟教程 (runoob.com)

好了,initial_bomb就解析到这吧.

phase_1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oCsvrJZI-1653359308642)(http://cdn.sekyoro.top/imgs/065654.png)]

还是很好理解的,读取输入并传输函数.

第一行就不说明了,使用gdb调试第二行.

b phase_1 #打断点
r #运行

随便进行输入,然后进入函数.接下来就是艰难的读汇编代码阶段.

0x400ee0 <phase_1>      sub    $0x8,%rsp                                                                                          
  0x400ee4 <phase_1+4>    mov    $0x402400,%esi                                                                                     
  0x400ee9 <phase_1+9>    callq  0x401338 <strings_not_equal>                                                                        
  0x400eee <phase_1+14>   test   %eax,%eax                                                                                           
  0x400ef0 <phase_1+16>   je     0x400ef7 <phase_1+23>                                                                               
  0x400ef2 <phase_1+18>   callq  0x40143a <explode_bomb>                                                                             
  0x400ef7 <phase_1+23>   add    $0x8,%rsp                                                                                           
  0x400efb <phase_1+27>   retq  

可以看到首先是开栈,栈顶移动8个字节,然后将$0x402400赋值给函数第二个调用参数,然后调用函数,通过名字就可以知道是判断字符串是否相等.然后测试结果根据结果进行跳转.je 表示相等就跳转否则调用炸弹爆炸.

我们到stings_not_equal中看看,其实不用细看,我们主要想知道进行比较的是什么字符串,它们的地址是什么.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-98ld2mta-1653359308648)(http://cdn.sekyoro.top/imgs/093741.png)]

首先需要肯定的是,调用字符串比较函数需要参数,%esi是第二个参数.我们看看这个寄存器的值

x /s显示地址上的值,以字符串形式.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WGSKBhFk-1653359308649)(http://cdn.sekyoro.top/imgs/093745.png)]

使用info r查看寄存器%rdi值[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YtemRG2X-1653359308649)(http://cdn.sekyoro.top/imgs/065657.png)]

看到了之前随意输入的参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D413bq5Q-1653359308650)(http://cdn.sekyoro.top/imgs/093748.png)]

所以字符串修改为0x402400上的字符串即可.

参数可以为文件,每行一个题答案.

./bomb myanswers.txt

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LNeFlNhZ-1653359308650)(http://cdn.sekyoro.top/imgs/093803.png)]

phase_defused函数,我们也可以看看.估计就是输出一些语句就行了.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IFFjNY3Z-1653359308651)(http://cdn.sekyoro.top/imgs/093808.png)]

phase_2

/* The second phase is harder.  No one will ever figure out
     * how to defuse this... */
    input = read_line();
    phase_2(input);
    phase_defused();
    printf("That's number 2.  Keep going!\n");

可以在gdb使用set args设置参数为答案文本.

然后继续打断点,打在phase_2即可

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cxC69Kpq-1653359308651)(http://cdn.sekyoro.top/imgs/093811.png)]

可以看到先读取了调用函数6个数字,在这之前将栈顶地址移到$rsi中,可以看看这个函数

0x40145c <read_six_numbers>     sub    $0x18,%rsp                                                                                  │
│   0x401460 <read_six_numbers+4>   mov    %rsi,%rdx                                                                                   │
│   0x401463 <read_six_numbers+7>   lea    0x4(%rsi),%rcx                                                                              │
│   0x401467 <read_six_numbers+11>  lea    0x14(%rsi),%rax                                                                             │
│   0x40146b <read_six_numbers+15>  mov    %rax,0x8(%rsp)                                                                              │
│   0x401470 <read_six_numbers+20>  lea    0x10(%rsi),%rax                                                                             │
│   0x401474 <read_six_numbers+24>  mov    %rax,(%rsp)                                                                                 │
│   0x401478 <read_six_numbers+28>  lea    0xc(%rsi),%r9                                                                               │
│   0x40147c <read_six_numbers+32>  lea    0x8(%rsi),%r8                                                                               │
│   0x401480 <read_six_numbers+36>  mov    $0x4025c3,%esi                                                                              │
│   0x401485 <read_six_numbers+41>  mov    $0x0,%eax                                                                                   │
│   0x40148a <read_six_numbers+46>  callq  0x400bf0 <__isoc99_sscanf@plt>                                                              │
│   0x40148f <read_six_numbers+51>  cmp    $0x5,%eax                                                                                   │
│   0x401492 <read_six_numbers+54>  jg     0x401499 <read_six_numbers+61>                                                              │
│   0x401494 <read_six_numbers+56>  callq  0x40143a <explode_bomb>                                                                     │
│   0x401499 <read_six_numbers+61>  add    $0x18,%rsp                                                                                  │
│   0x40149d <read_six_numbers+65>  retq

可以看到调用了sscanf@plt也就是后面会执行sanf函数,需要两参数,一个格式字符串.看到mov $0x4025c3 %esi,看一下是什么

(gdb) x 0x4025c3
0x4025c3:       "%d %d %d %d %d %d"

也就是六个整数.这一有一个知识点,传函数参数时,如果数量比较多那么就会使用栈.也就是使用%rbp或%rsp指示,同时函数参数是从右往左开始的,也就是最后一个输入的参数会先被传入寄存器或栈中.

再看看%edi

(gdb) x /s $edi
0x6037d0 <input_strings+80>:    "1 12 23 34 13 100"

即传入了这个字符串到read_six_numbers函数.

注意到后面有jg即大于跳转,也就是输入的正确参数要大于5,即6个(跟函数名称一样就行了).然后跳出这个函数.继续执行

   0x400f05 <phase_2+9>    callq  0x40145c <read_six_numbers>                                                                         
  0x400f0a <phase_2+14>   cmpl   $0x1,(%rsp)                                                                                         
   0x400f0e <phase_2+18>   je     0x400f30 <phase_2+52> 

后面又继续跳转到0x400f30(当然这里有条件寄存器rsp值等于1,后面会说)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aRDtsZrc-1653359308652)(http://cdn.sekyoro.top/imgs/093813.png)]

这里进行了赋值后又继续跳转到0x400f17

 0x400f17 <phase_2+27>   mov    -0x4(%rbx),%eax                                                                                     
   0x400f1a <phase_2+30>   add    %eax,%eax                                                                                          
  0x400f1c <phase_2+32>   cmp    %eax,(%rbx)                                                                                         
   0x400f1e <phase_2+34>   je     0x400f25 <phase_2+41>                                                                               
  0x400f20 <phase_2+36>   callq  0x40143a <explode_bomb> 

可以看出又会进行比较值相等才能避免爆炸,相等的话又会跳转到一个地址0x400f25.

0x400f25

0x400f25 <phase_2+41>   add    $0x4,%rbx                                                                                           │
│   0x400f29 <phase_2+45>   cmp    %rbp,%rbx                                                                                           │
│   0x400f2c <phase_2+48>   jne    0x400f17 <phase_2+27>                                                                               │
│   0x400f2e <phase_2+50>   jmp    0x400f3c <phase_2+64>                                                                               │
│   0x400f30 <phase_2+52>   lea    0x4(%rsp),%rbx                                                                                      │
│   0x400f35 <phase_2+57>   lea    0x18(%rsp),%rbp                                                                                     │
│   0x400f3a <phase_2+62>   jmp    0x400f17 <phase_2+27>                                                                               │
│   0x400f3c <phase_2+64>   add    $0x28,%rsp                                                                                          │
│   0x400f40 <phase_2+68>   pop    %rbx                                                                                                │
│   0x400f41 <phase_2+69>   pop    %rbp                                                                                                │
│   0x400f42 <phase_2+70>   retq           

可以看到这里又会进行比较如果不等又会跳回去,相等才能脱离苦海.如果你想锻炼你的汇编代码阅读能力可以直接硬读,我这直接设置6个特别的数值然后看看寄存器存储的什么值.

跳出读取6个值的函数后,跳回0x400f0a,这里对寄存器$rsp值进行了比较(如果你设置特殊值进行多次测试就知道这个值等于什么了)

这里我们回去关注一下%rsp的值(关于寄存器符号我这里%与$混合使用)

所以我们需要好好探讨一下read_six_numbers中传给scanf的参数.

关于函数传参寄存器中存储的值.

C语言参数传递所使用的寄存器_天马行空-CSDN博客_参数寄存器

由于%edi是phase_2传入read_six_numbers的参数,所以read_six_numbers向scanf传参是从%esi开始,需要七个参数(6个数字与一个格式化参数).rdx,rcx,r8,r9也是传参的寄存器,算上%esi就有五个,还有两个就需要用栈了.

可以看到在read_six_numbers中将%rsi传给了%rdx,这是第一个参,然后将0x4(%rsi)存储的值赋给%rcx,就是第二个参数.(一个值4字节,但一个寄存器大小是8字节).也就是说%rcx存储的是第二个参数的地址.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MhJYg4rY-1653359308652)(http://cdn.sekyoro.top/imgs/093815.png)]

还是画图好理解.开始的4个用寄存器存,后面的寄存器不够雷人用栈存.当scanf执行完后,%rsp = %rsp’.所以(%rsp)就是输入的第一个值.返回值%eax就是6(正确读取了6个值)

所以第一个值为1.至于为什么是第一个而不是最后一个,因为要存储最后两个值寄存器不够所以入栈了,它们值存储在距离phase_2栈帧的栈顶最远的地方.

0x400f30 <phase_2+52>   lea    0x4(%rsp),%rbx                                                                                      
   0x400f35 <phase_2+57>   lea    0x18(%rsp),%rbp                                                                                    
   0x400f3a <phase_2+62>   jmp    0x400f17 <phase_2+27>  

然后便是将%rbx赋值为第二个值的地址,栈底赋值为%rsp+24.24个字节是6个int大小.

0x400f17 <phase_2+27>   mov    -0x4(%rbx),%eax                                                                                     
   0x400f1a <phase_2+30>   add    %eax,%eax                                                                                           
   0x400f1c <phase_2+32>   cmp    %eax,(%rbx)

然后将上一个值赋给%eax,再加倍.判断与当前值的大小.相等才能避免爆炸

0x400f25 <phase_2+41>   add    $0x4,%rbx                                                                                           
0x400f29 <phase_2+45>   cmp    %rbp,%rbx

再将当前值指向下一个(4字节是一个int大小),然后将地址与%rbp比较.因为%rbp = 0x18(%rsp).经历五次循环后就结束了.而每循环都需要将当前值设置为前一个值的二倍.

所以结果就是1 2 4 8 16 32

phase_3

有空了,开冲.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1GcPpIrb-1653359308653)(http://cdn.sekyoro.top/imgs/093817.png)]

代码类似.在这之前

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OQk9KG77-1653359308653)(http://cdn.sekyoro.top/imgs/065659.png)]

将输入值传入phase_3参数.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mOxKw5hQ-1653359308654)(http://cdn.sekyoro.top/imgs/093818.png)]

进入phase_3函数查看0x4025cf的值

(gdb) x 0x4025cf
0x4025cf:       "%d %d"

后面调用scanf函数,第一个参数就在%esi中,"%d %d"表示传入两个整数,第一个在%rdx,第二个在%rcx.

cmp $0x1,%eax表示比较,必须大于一个才能跳转.

后面比较第二个参数,ja表示无符号比较.汇编语言—跳转指令ja、jb、jl_poptar的博客-CSDN博客_汇编语言ja

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DAvTpF3b-1653359308654)(http://cdn.sekyoro.top/imgs/093821.png)]

0x400fad跳转到一个调用引爆炸弹的地方,所以第一个参数要小于等于7.

>0x400fad <phase_3+106>  callq  0x40143a <explode_bomb> 

后面jmp到一个地址,*(0x402470)(,%rax,8) 8表示8个字节,即(0x402470)(,%rax,8)表示0x402470+%rax*8.

寻址方式

地址或偏移(%基址或偏移量寄存器, %索引寄存器, 比例因子)

地址的计算公式是:

最终地址 = 地址或偏移 + %基址或偏移量寄存器 + %索引寄存器  * 比例因子

这里第一个参数假设为6,地址是400f9f x/10gx 表示查看后面10个giant(8字节)以16进制形式的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fbMA9UyQ-1653359308654)(http://cdn.sekyoro.top/imgs/093822.png)]

0x2aa移到%eax值然后与第二个参数进行比较,需要等于才能避免爆炸.

所以这就是一个答案,一共应该有0-6七组答案,这里我就不写了.

phase_4

进入phase_4函数,查看x $edi表明是将输入的参数传入函数phase_4.

在函数中后面又继续传入参数,x 0x4025cf

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qcRZ5u3Q-1653359308655)(http://cdn.sekyoro.top/imgs/093824.png)]

(gdb) x 0x4025cf
0x4025cf:       "%d %d"

表明需要输入两个整数.0xc(%rsp)是第二个参数,0x8(%rsp)是第一个参数.

 >0x40102c <phase_4+32>   jne    0x401035 <phase_4+41>                                                                               
   0x40102e <phase_4+34>   cmpl   $0xe,0x8(%rsp)                                                                                      
   0x401033 <phase_4+39>   jbe    0x40103a <phase_4+46>                                                                               
   0x401035 <phase_4+41>   callq  0x40143a <explode_bomb> 

如果不是输入了两个整数jne跳向炸弹爆炸.接着进行比较第一个整数,与0xe(14)比较.jbe表示小于等于.也就是第一个参数如果小于等于14则跳转否则不跳转爆炸.

这里我们输入14,后面跳转到0x40103a,将14赋值给%edx. %esi赋值为0.第一个参数赋值给%edi.调用func4.

也就是func4(第一个参数(这里我们是14),0,14).

查看func4函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9VvwTiNj-1653359308655)(http://cdn.sekyoro.top/imgs/093826.png)]

SHR(右移)指令使目的操作数逻辑右移若干位,最高位用 0 填充。最低位复制到进位标志位,而进位标志位中原来的数值被丢弃.因为%ecx值是0xe,最低位是0.CF=0.

sar与shr差别 两者的区别在于SAR右移时保留操作数的符号,即用符号位来补足,而SHR右移时总是用0来补足

sar %eax表示将%eax存储的值右移一位,最高位由符号位补齐.14右移一位得到7.

│   0x400fdf <func4+17>     lea    (%rax,%rsi,1),%ecx                                                                                  │
│  >0x400fe2 <func4+20>     cmp    %edi,%ecx                                                                                           │
│   0x400fe4 <func4+22>     jle    0x400ff2 <func4+36>                                                                                 │
│   0x400fe6 <func4+24>     lea    -0x1(%rcx),%edx                                                                                     │
│   0x400fe9 <func4+27>     callq  0x400fce <func4>                                                                                    │
│   0x400fee <func4+32>     add    %eax,%eax                                                                                           │
    0x400ff0 <func4+34>     jmp    0x401007 <func4+57> 

我们可以先看看函数外的判断

  40104d:       85 c0                   test   %eax,%eax
  40104f:       75 07                   jne    401058 <phase_4+0x4c>
  401051:       83 7c 24 0c 00          cmpl   $0x0,0xc(%rsp)
  401056:       74 05                   je     40105d <phase_4+0x51

test和je指令的组合用法_counsellor的专栏-CSDN博客_je指令

所以我们需要函数结果为0,同时第二个参数也为0.

比较简单的处理就是第一个参数等于%ecx,也就是等于7.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wz826zrS-1653359308656)(http://cdn.sekyoro.top/imgs/093827.png)]

phase_5

  40107a:       e8 9c 02 00 00          callq  40131b <string_length>
  40107f:       83 f8 06                cmp    $0x6,%eax

输入参数,字符串长度等于6.所以需要输入含有6个字符的字符串.

进入phase_5函数.

注意后面的代码

  4010b3:       be 5e 24 40 00          mov    $0x40245e,%esi
  4010b8:       48 8d 7c 24 10          lea    0x10(%rsp),%rdi
  4010bd:       e8 76 02 00 00          callq  401338 <strings_not_equal>
  4010c2:       85 c0                   test   %eax,%eax
  4010c4:       74 13                   je     4010d9 <phase_5+0x77>

可以看到将0x40245e赋值给%esi

看一下是什么

(gdb) x /s 0x40245e
0x40245e:       "flyers"

表明我们的%rdi的需要等于这个字符串.

  40108b:       0f b6 0c 03             movzbl (%rbx,%rax,1),%ecx
  40108f:       88 0c 24                mov    %cl,(%rsp)
  401092:       48 8b 14 24             mov    (%rsp),%rdx
  401096:       83 e2 0f                and    $0xf,%edx
  401099:       0f b6 92 b0 24 40 00    movzbl 0x4024b0(%rdx),%edx
  4010a0:       88 54 04 10             mov    %dl,0x10(%rsp,%rax,1)
  4010a4:       48 83 c0 01             add    $0x1,%rax
  4010a8:       48 83 f8 06             cmp    $0x6,%rax
  4010ac:       75 dd                   jne    40108b <phase_5+0x29>
  4010ae:       c6 44 24 16 00          movb   $0x0,0x16(%rsp)

注意到将0x4024b0后面的字节移动到%edi.而之前的%rdx是由我们输入的字符的ascii码与0xf相与得到的.

(gdb) x 0x4024b0
0x4024b0 <array.3449>:  "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"

所以需要首先得到flyers每个字母在上面字符串中的位置,分别是(从0开始)9 15 14 5 6.

我们输入的6个字符的ascii码与0xf相与后必须是以上的值.所以答案有很多.

比如0x69 0x6f 0x6e 0x65 0x66.即ionefg

phase_6

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s8mxyWId-1653359308656)(http://cdn.sekyoro.top/imgs/093829.png)]

一开始进行比较

 0x401145 <phase_6+81>   add    $0x1,%ebx                                                                                           │
│  >0x401148 <phase_6+84>   cmp    $0x5,%ebx                                                                                           │
│   0x40114b <phase_6+87>   jle    0x401135 <phase_6+65>                                                                               │
│   0x40114d <phase_6+89>   add    $0x4,%r13                                                                                           │
│   0x401151 <phase_6+93>   jmp    0x401114 <phase_6+32>                                                                               │
│   0x401153 <phase_6+95>   lea    0x18(%rsp),%rsi  

6个数均小于等于6且不能相等.

后面跳转到0x0000000000401153,用7去减去每一个数

0x40116f 0x40116f 0x401188

0x4011ab这里的代码将链表反向串联,便于比较.

x /24wx 0x6032d0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cxtu2rje-1653359308656)(http://cdn.sekyoro.top/imgs/093831.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yVnCkQxA-1653359308657)(http://cdn.sekyoro.top/imgs/093832.png)]

执行完后

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u8Aj6v2B-1653359308657)(http://cdn.sekyoro.top/imgs/093836.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d7ql06Ef-1653359308658)(http://cdn.sekyoro.top/imgs/065701.png)]

关键代码

  0x4011d0 <phase_6+220>  jmp    0x4011bd <phase_6+201>                                                                              │
│   0x4011d2 <phase_6+222>  movq   $0x0,0x8(%rdx)                                                                                      │
│   0x4011da <phase_6+230>  mov    $0x5,%ebp                                                                                           │
│   0x4011df <phase_6+235>  mov    0x8(%rbx),%rax                                                                                      │
│   0x4011e3 <phase_6+239>  mov    (%rax),%eax                                                                                         │
│  >0x4011e5 <phase_6+241>  cmp    %eax,(%rbx)                                                                                         │
│   0x4011e7 <phase_6+243>  jge    0x4011ee <phase_6+250>                                                                              │
│   0x4011e9 <phase_6+245>  callq  0x40143a <explode_bomb> 

000032d0是node1的地址,这里需要修改二进制文件.

将节点值从头到尾依次增大(假设输入 1 2 3 4 5 6).

0x4011e5 <phase_6+241>  cmp    %eax,(%rbx)                                                                                         │
│   0x4011e7 <phase_6+243>  jge    0x4011ee <phase_6+250>                                                                              │
│   0x4011e9 <phase_6+245>  callq  0x40143a <explode_bomb>                                                                             │
│   0x4011ee <phase_6+250>  mov    0x8(%rbx),%rbx                                                                                      │
│   0x4011f2 <phase_6+254>  sub    $0x1,%ebp                                                                                           │
│   0x4011f5 <phase_6+257>  jne    0x4011df <phase_6+235>                                                                              │
│   0x4011f7 <phase_6+259>  add    $0x50,%rsp                                                                                          │
│  >0x4011fb <phase_6+263>  pop    %rbx                                                                                                │
│   0x4011fc <phase_6+264>  pop    %rbp                                                                                                │
│   0x4011fd <phase_6+265>  pop    %r12 

secret_phase

strings bomb发现有一个secret_phase很可疑.

查看反汇编文件发现与phase_defused有关

00000000004015c4 <phase_defused>:
  4015c4:       48 83 ec 78             sub    $0x78,%rsp
  4015c8:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  4015cf:       00 00 
  4015d1:       48 89 44 24 68          mov    %rax,0x68(%rsp)
  4015d6:       31 c0                   xor    %eax,%eax
  4015d8:       83 3d 81 21 20 00 06    cmpl   $0x6,0x202181(%rip)        # 603760 <num_input_strings>
  4015df:       75 5e                   jne    40163f <phase_defused+0x7b>
  4015e1:       4c 8d 44 24 10          lea    0x10(%rsp),%r8
  4015e6:       48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
  4015eb:       48 8d 54 24 08          lea    0x8(%rsp),%rdx
  4015f0:       be 19 26 40 00          mov    $0x402619,%esi
  4015f5:       bf 70 38 60 00          mov    $0x603870,%edi
  4015fa:       e8 f1 f5 ff ff          callq  400bf0 <__isoc99_sscanf@plt>
  4015ff:       83 f8 03                cmp    $0x3,%eax
  401602:       75 31                   jne    401635 <phase_defused+0x71>
  401604:       be 22 26 40 00          mov    $0x402622,%esi
  401609:       48 8d 7c 24 10          lea    0x10(%rsp),%rdi
  40160e:       e8 25 fd ff ff          callq  401338 <strings_not_equal>
  401613:       85 c0                   test   %eax,%eax
  401615:       75 1e                   jne    401635 <phase_defused+0x71>
  401617:       bf f8 24 40 00          mov    $0x4024f8,%edi
  40161c:       e8 ef f4 ff ff          callq  400b10 <puts@plt>
  401621:       bf 20 25 40 00          mov    $0x402520,%edi
  401626:       e8 e5 f4 ff ff          callq  400b10 <puts@plt>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3mEtFigp-1653359308658)(http://cdn.sekyoro.top/imgs/093840.png)]

需要在第四题答案后加上这个字符串.

(gdb) x /s 0x603870
0x603870 <input_strings+240>:   "7 0"
(gdb) x /s 0x402619
0x402619:       "%d %d %s"

比较输入过的答案数量,等于6则进行特殊的测试.

0x4015d8 <phase_defused+20>     cmpl   $0x6,0x202181(%rip)        # 0x603760 <num_input_strings>                                   │
│  >0x4015df <phase_defused+27>     jne    0x40163f <phase_defused+123>                                                                │
│   0x4015e1 <phase_defused+29>     lea    0x10(%rsp),%r8                                                                              │
│   0x4015e6 <phase_defused+34>     lea    0xc(%rsp),%rcx                                                                              │
│   0x4015eb <phase_defused+39>     lea    0x8(%rsp),%rdx                                                                              │
│   0x4015f0 <phase_defused+44>     mov    $0x402619,%esi                                                                              │
│   0x4015f5 <phase_defused+49>     mov    $0x603870,%edi     

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ILAuiDLP-1653359308659)(http://cdn.sekyoro.top/imgs/093844.png)]

最后结果需要等于2

0000000000401204 <fun7>:
  401204:       48 83 ec 08             sub    $0x8,%rsp
  401208:       48 85 ff                test   %rdi,%rdi
  40120b:       74 2b                   je     401238 <fun7+0x34>
  40120d:       8b 17                   mov    (%rdi),%edx
  40120f:       39 f2                   cmp    %esi,%edx
  401211:       7e 0d                   jle    401220 <fun7+0x1c>
  401213:       48 8b 7f 08             mov    0x8(%rdi),%rdi
  401217:       e8 e8 ff ff ff          callq  401204 <fun7>
  40121c:       01 c0                   add    %eax,%eax
  40121e:       eb 1d                   jmp    40123d <fun7+0x39>
  401220:       b8 00 00 00 00          mov    $0x0,%eax
  401225:       39 f2                   cmp    %esi,%edx
  401227:       74 14                   je     40123d <fun7+0x39>
  401229:       48 8b 7f 10             mov    0x10(%rdi),%rdi
  40122d:       e8 d2 ff ff ff          callq  401204 <fun7>
  401232:       8d 44 00 01             lea    0x1(%rax,%rax,1),%eax
  401236:       eb 05                   jmp    40123d <fun7+0x39>
  401238:       b8 ff ff ff ff          mov    $0xffffffff,%eax
  40123d:       48 83 c4 08             add    $0x8,%rsp
  401241:       c3                      retq

需要等于一个类似二叉树中节点的值才能跳出来.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lDLmesAM-1653359308659)(http://cdn.sekyoro.top/imgs/093846.png)]

同时不能随便等于一个节点值,2 = 1+1,需要等与第二个节点值.如果给的参数值大于等于节点值才能进行进一步等于的比较

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HFOq0LKo-1653359308660)(http://cdn.sekyoro.top/imgs/093854.png)]

gdb设置汇编代码风格,Linux下是AT&T.

Linux下gdb显示intel和at&t汇编_freezing111的博客-CSDN博客

使用vim编辑可执行文件–16进制模式_astrotycoon-CSDN博客

结束语

网上搜到的资料

CSAPP: Bomb Lab 实验解析 - 简书 (jianshu.com)

IDA反汇编工具

做到后面不想写了…核心还是函数的一些知识和循环分支语句的汇编代码,传参用的寄存器.

注意第六题其实并不需要改变可执行文件,需要按顺序排列1-6,这里我直接改变的可执行文件…

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

procoder338

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值