CSAPP Bomb Lab

image

from pixiv

参考博客

知识点

gdb

  • jump 函数名 / * 地址名

    jump 能够很灵活地在gdb调试汇编代码时跳转

    当一不小心错过了关键信息时,我们便可以使用jump


  • run(简写为r) 参数1 参数2 ...

    当我们在调试gdb想要携带参数时,通过gdb bomb input.txt是不可以行的

    应该在run后加上参数


  • layout src显示源码

    layout asm显示汇编代码

    layout split源码和汇编代码都显示

    ctrl+x+a 快捷退出layout


  • x/[count][format] [address]

    打印内存值,从所给地址(address)处开始,以指定格式(format)显示 count 个值

    比较强大的用法是x/s address 可以打印出字符串出来

    x/100i address 可以从address开始打印出100条指令出来


  • info register (指定寄存器名,如rax)

    打印寄存器的值

    info register rax 指定打印rax的值

    i r rax 可以这样简写

炸弹2:Phase_2 栈中探险

这个主打的就是一个静下心来分析栈中的内容

比如在excel上打打草稿

解决这个问题的关键我总结为3个:

知识点

在函数a中调用函数b,我们函数a中要将参数放到指定的6个寄存器上。

(有个有趣的点是:调用者保存寄存器都是用来保存参数的寄存器)

当参数超过6个,函数a就要在自己的栈帧上分配空间用来放参数,且参数越在后面,越先入栈

这点是符合直觉的,因为参数越在后面可能越后别用到。P169

如上图,在本帧中具体顺序是(从上往下):

  • 被保存的寄存器

    即保存用到的 被调用者保存寄存器

  • 局部变量

    即在函数内部定义的一些变量有事会用栈来保存

  • 参数构造区

    也就是在函数中调用其他函数,在传递参数时,寄存器不够用了,将过多的参数放到栈中

  • 返回地址

    使用call指令时,将本函数中下一条要执行的指令地址(在%rip中)压栈

    我们还需要注意:call ret 这些指令在执行的时候 携带了push %rippop %rip操作的

P164


在通过栈存放参数时,所有数据都是向8的倍数对齐 P169

但是我们通过栈存放局部变量,大多数情况并不是这样 P170(栈上的局部存储)P196(数组存放到栈中)P190(数据对齐)

在x86-64中,我们的处理器一次能够处理64个位,一次也能够取到64位

我们的内存(注意,栈也在内存中),是以1字节(8位)作为单位编号,所以 64位/8位=8

所以我们经常能够看到如下栈表示(内存表示):

但是我觉得实际分析起来还是如下更好分析:


还有一件关于寄存器的事,下面以%rax举例

movl 0x40000000 %eax, 这个时候%rax的高32为都会被置0 P124

Phase_5 内存寻值

这里主要有几个知识点:

  • test %eax,%eax

    这条指令的作用等价于 And %eax,%eax,同时当%eax结果为0,置ZF=0

    所以我们还经常能够在这条语句的下面看到 je,jne等,因为我们知道函数常常将结果放到%rax,判断是否相同的函数也是这样
    当相同时,函数返回0,放到%rax中(或者1)

  • movq %fs:40,%rax

    看到这个指令开始还觉得奇怪,其实他是'金丝雀值' P199
    是一种栈保护机制

  • p 0x14

    快速打印出十六进制0x14的十进制

  • x/s $rax

    在gdb中要取寄存器中的值用$,而不是%;(也可以直接rax)

    x/s , x/x 等相当于c中的printf,都是取地址后访存

phase_6 层层访址

这个炸弹让我知道了:

如果硬刚汇编代码一条一条看下来,即使做出来了,自己也脱了一层皮吧(悲)

所以我转换思路了,我将断点设置到跳出循环处,然后观察内存和栈的变化,能够很容易知道汇编代码在做什么

b * 地址 layout asm layout reg continue(或者简写为c)

这道题目的关键在于:

当我输入1 2 3 4 5 6时,发现保存在栈中(从高地址到低地址)的值为:

0x603320
0x603310
0x603300
0x6032f0
0x6032e0
0x6032d0

设置关键断点(慢慢分析就知道关键断点是什么了,一般是循环退出时),continue,发现得到如下结果:

我将在栈中保存的值设为argn,其中n越小表示越在栈底
那么循环做的事(我就只看了一点循环中的代码,根据结果),我猜到应该是:

*(arg(n-1)+0x8) = arg(n)

最后的判断是要求*arg(n-1)<=arg(n)!

暗雷

汇编代码在phase_6往下翻翻就能看到,这已经是明示了,secret_phase都写出来了

Code

Here

posted @ 2024-03-12 21:48  次林梦叶  阅读(50)  评论(0)    收藏  举报