什么是Canary
有无Canary呢就是在函数压栈的时候,函数刚开始执行的时候,它会多一个参数,也就是在ebp的上面,会压入一个Canary的值,在子函数验证完之后,对比Canary的值,看看是否相等。不相等,代表程序被修改,产生了异常。
本次实验教学代码如下:
实验目的,对比有无Canary保护的程序有何不同
gcc -m32 -no-pie -fno-stack-protector -o canary canary.c
-m32 32位程序
-no-pie 中间没有空格
-fno-stack-protector 关闭canary保护
-o 输出
生成之后图片有锁,输入指令chmod 777 canary 进行提权
下一步我们使用gdb开始调试
补充的知识:
什么是堆栈内存对齐
and esp 0xfffffff0
主流编译器的编译规则规定“程序访问的地址必须向16字节对齐(被16整除)”内存对齐之后可以提高访问效率。
加入保护的gcc指令:
gcc -m32 -no-pie -fstack-protector-all -o canary canary.c
加入保护后如下图:
gdb指令复习
s step,si步入 n 执行下一条指令 ni步入 b 在某处下断点,可以用 b * adrress b function_name info b 查看断点信息 delete 删除所有断点 c 继续 r 执行 finish 执行完当前函数返回到调用它的函数。运行程序,直到当前函数运行完毕返回再停止。例如进入的单步执行如果已经进入了某函数,而想退出该函数返回到它的调用函数中,可使用命令finish. (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 查看某个地址处的值
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处的反汇编结果