pwn入门笔记(2)——什么是Canary保护

有无Canary保护的区别

无canary保护
在这里插入图片描述
有canary保护
在这里插入图片描述

子函数在执行完了之后会去对比之前开始压入的有没有变化,如果不一样,就说明被改了

实例

#include<stdio.h>
int main()
{
    char *name = "Roger";
    printf("My name is %s"); 
    return 0;
}

源码已给,之后参考笔记(0)去编写

接下来输入

gcc -no-pie -fno-stack-protector -m32 -o printf1 printf1.c//关闭堆栈保护

具体解释参考之前的笔记
在这里插入图片描述
之后进行提权chmod 777 printf1.c
之后再用gdb进行调试
借大佬图:
pwmdbg下 disass main
查看一下main函数
在这里插入图片描述
我们可以看到除了前面三行,其他的都很正常
我们可以先下一个断点

pwndbg>b main

之后 run,跑起来
在这里插入图片描述
emmmmm…断点的位置不太对,对于main的起始位置跳过了15行
所以,我们还是在这里断
在这里插入图片描述
(<+0>那里)
直接用前面的代码去下

所以咱们得删除之前那个错误的断点,建立新的断点
输入
pwndbg>i b
在这里插入图片描述
查看我们有那些断点
之后用
pwndbg>d 1
d——>delete
1——>上面那个图前面的序号
就可以直接删掉了

之后咱们下个断点

pwndbg> b *0x080048426

之后让程序跑起来
在这里插入图片描述
这个时候就对了
在这里插入图片描述

什么是堆栈内存对齐

AND ESP 0XFFFFFFF0

主流编译器的编译规则规定 “ 程序访问的地址必须向16字节对齐(被16整除)” 内存对齐之后可以提高访问效率。
类似于C语言里面的结构体(对齐)

这里解释一下
在这里插入图片描述

这里有2个变量,一个是char定义的a(一行),一个是int定义的b(四行)
但是程序读取的时候一次读四行,所以第一次的时候程序读完之后,发现不对劲,后面三和前面那个不一样。
就把第一个读一遍,然后再读后面四个。
所以一共读了三遍

内存对齐,则是把上面补齐
把前面重新补成四个字节
这样就只用读两次就可以了
也就是add操作
在这里插入图片描述在这里插入图片描述
也就是内存对齐之后,压栈那些就会快上很多,访问栈里面的数据也会快很多
对之后的操作是不影响的
在这里插入图片描述
在这里插入图片描述

数值并没有变化,只是优化了栈的结构,这样压栈入栈,访问数据操作就会快很多

有Canary保护的情况下

之后我们输入

gcc -no-pie -fstack-protector-all -m32 -o printf1 printf1.c//启用堆栈保护,为所有函数插入保护代码

我们可以看到后面带all,就是所有函数都带上这个保护
如果是下面这个的话

-fstack-protector//启用堆栈保护,不过只为局部变量中含有 char 数组的函数插入保护代码

其实也就少个all
之后就直接覆盖了
然后提权
之后进gdb分析disass main
在这里插入图片描述

在这里插入图片描述
入栈操作的时候我们可以看到ecx把原来的数据存入了【ebp-0xc】里面
主函数执行完了之后
在这里插入图片描述
又把数据送了回去

之后咱们重新下一个断点,下到保护这里
在这里插入图片描述
放到了ecx里面
在这里插入图片描述

在这里插入图片描述
然后我们可以看到把ecx放到【ebp-0xc】里面去了

GDB基础调试命令总结
 
s step,si步入
 
n 执行下一条指令 ni步入
 
b 在某处下断点,可以用
 
b * adrress
 
b function_name
 
info b 查看断点信息
 
delete 删除所有断点
 
c 继续
 
r 执行
 
finish 执行完当前函数返回到调用它的函数。运行程序,直到当前函数运行完毕返回再停止。例如进入的单步执行如果已经进入了某函数,而想退出该函数返回到它的调用函数中,可使用命令finish.  (ctrl+F12)
 
(gdb) until 或(gdb) u  指定程序直到退出当前循环体这里,发现需要把光标停止在循环的头部,然后输入u这样就自动执行全部的循环了。
 
(gdb) jump 5 跳转执行程序到第5行:这里,可以简写为"j 5"需要注意的是,跳转到第5行执行完毕之后,如果后面没有断点则继续执行,而并不是停在那里了。
 
另外,跳转不会改变当前的堆栈内容,所以跳到别的函数中就会有奇怪的现象,因此最好跳转在一个函数内部进行,跳转的参数也可以是程序代码行的地址,函数名等等类似list。
 
(gdb) return 强制返回当前函数: 这样,将会忽略当前函数还没有执行完毕的语句,强制返回。return后面可以接一个表达式,表达式的返回值就是函数的返回值。
 
disas addr 查看addr处前后的反汇编代码
 
disas functions 参看fucntion函数的反汇编代码
 
p 系列
 
p system/main 显示某个函数地址
 
p $esp 显示寄存器
 
p/x p/a p/b p/s。。。
 
p 0xff - 0xea 计算器
 
print &VarName 查看变量地址
 
p * 0xffffebac 查看某个地址处的值

比如我们要查看ecx的值
输入p $ecx
然后就能显示出来,不过是十进制
但是我们只要稍稍改动一下

p/x $ecx

就会输出0x这样格式的16进制的了

如果是看内容的话,我们在前面打个*

p/x *($ebp-0xc)

注意【】换成了(),用来查看内容
如果是看数值的话

p $ebp-0xc

之后,除了p系列,我们还有x系列

x系列
 
命令格式:x/<n/f/u> <addr>
 
n是一个正整数,表示需要显示的内存单元的个数
 
f 表示显示的格式(可取如下值: x 按十六进制格式显示变量。d 按十进制格式显示变量。u 按十进制格式显示无符号整型。o 按八进制格式显示变量。t 按二进制格式显示变量。a 按十六进制格式显示变量。i 指令地址格式c 按字符格式显示变量。f 按浮点数格式显示变量。)
 
u 表示从当前地址往后请求的字节数 默认4byte,u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节
 
<addr>表示一个内存地址
 
x/xw addr 显示某个地址处开始的16进制内容,如果有符号表会加载符号表
 
x/x $esp 查看esp寄存器中的值
 
x/s addr 查看addr处的字符串
 
x/b addr 查看addr处的字符
 
x/i addr 查看addr处的反汇编结果

差不多
之后一直n慢慢分析
在这里插入图片描述
我们可以看到他把数据从ebp-0xc取出来了放到ecx里面了
之后我们可以试试输入

i r

在这里插入图片描述
我们可以看到flag
0x282=0010 1000 0010
接下来我们是je跳转
在这里插入图片描述
关注zf标志位,接下来对照表格
在这里插入图片描述
我们可以看SF在第七个
0010 1000 0010
从右往左数
------- 7654 3210

我们可以看到第七个是1
SF=1
不过我们接下来执行了之后这个标志位是会改变的
在这里插入图片描述
ZF=1了
对照表格很明显
我们接下来看看0x246=0010 0100 0110
--------------------------------------- 654 3210
ZF=1

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值