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

如上图,在本帧中具体顺序是:被保存的寄存器 局部变量 参数构造区(也就是放过多参数的地方)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,都是取地址后访存

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。