核心gdb-动态调试
进入程序的gdb调试 gdb-程序名
run命令
run:启动命令,就是把程序完全跑一遍
start
start运行到程序的入库点
查看程序运行的位置i r
虽然他知道程序运行到那里了,但是我们不知道,如何查看呢?首先查看寄存器
前16个是一摸一样的,最重要的是rip.
在代码中,我们可以int1知道int100,但是在cpu中能用到只有前15个,并且还有占用,cpu能直接操作的数字都是这些寄存器
查看汇编语言-disassembel
查看main函数的汇编语言
rip较为重要,上面图中就可以查看rip在什么位置 。。。。。275,最上面的一行显示了rip在main函数当中,我的格式没有变,这里就不改变/.gdbinit的内容了
了解汇编指令-mov
一般一个指令后面加一个数或者两个数,一个的就是一个操作指令一个操作数,两个的就是一个操作指令,一个目的操作数,一个是源操作数
mov rbp,rsp :mov就是赋值,就是将rsp的数值赋值给rbp,我们可以走到这个地方,
设置一个断点-b *
查看断点 -i b
如何查看这个断点呢?i b
执行到断点为止-c
再次查看,就可以得知执行到了这个位置
对比赋值前后的结果
i r 查看rsp和rbp的数值,此时是还没有赋值的结果
使用ni命令步入,赋值后的结果就是
此时已经赋值成功。
add是加 sub是减 xor是异或 call是调函数 lea:load effective address :取有效地址,现在大部分的lea是用来计算的
这里的意思就是rbp-0x18=rax
lea命令的执行效果
先设置一个断点
查看断点
执行到断点为止-c
i r 查看赋值之前的效果
执行命令ni
执行过后
lea对比sub
为什么不用sub rbp,0x18而后mov rax,rbp,这是因为lea短,
很明显中间只使用了4行,而一个sub就需要4行
后面再用一个mov指令,可想而知其中的长度。这个指令第一个不用改变rbp的数值,第2,这个指令很短。
xor eax,eax就是eax=0,之所以不写成mov ebx,0是因为前面的比较短,占据内存小
带mov的都是赋值,只不过是赋值形式不同
jcc系列
满足条件跳转,满足什么,需要具体分析。
cmp指令
strcmp也是类似的
约等于sub
cmp al,0x61 :: al-0x61
sub al,0x61::al=al-0x61
两者的区别在于:cmp减完以后不赋值,sub减完以后赋值给al,cmp不存储,是用来和下面的jne进行对比的
jne:结果不为0的时候就跳转
al-0x61不等于0的话就跳转,跳到mov,等于0的时候就不跳转
等于0的时候,就执行func的函数。
步入步过的指令
gdb断点失效--disable b id
可以看到此时已经变成了n而不是y
再打开-enable b 3
可以看到id为3的断点现在又打开了。pwn是不会频繁设置断点的。
ni和si的区别
看效果
先在cal的位置上设置一个断点
查看一下断点
重新启动一下
执行到断点
再查看一下,已经执行到了断点
使用ni是让输入,
而使用si就是进入到put的实现功能当中。
看效果,再次重新启动一下
开始执行
输入si,可以看到进入到了put函数中,再次disassemble $rip,可以查看到的内容是put函数中的
可以使用finish来步出
看到是已经执行完了,步出程序到下一行