前言
因为CSAPP中第二章讲数据的存储,最近在学校时间有点紧,所以我匆匆浏览一下发现之前做的笔记更通俗一点,但是可能有盲点,以后二刷再精读一下
一、程序机器级代码
编写一个程序
#include<stdio.h>
long mult2(long a, long b)
{
long s = a*b;
return s;
}
void multstore(long x,long y, long* dest)
{
long t = mult2(x,y);
*dest = t;
}
int main()
{
long d;
multstore(2,3,&d);
printf("2 * 3 --> %ld\n",d);
return 0;
}
在ubuntu18上利用命令编译gcc -Og -S test.c
,可以得到一个test.s的文件,打开一看就是我们的汇编代码,而前面那些,以“.”开头的就是汇编器与链接器的伪指令,通常可以忽略
如果我们用命令gcc -Og -c test.c
得到的是一个test.o的文件,无法打开。。。但是书上说是一堆二进制格式的
打开gdb我们看到利用gcc命令gcc -Og -c test.c
编译出test.o后,利用gdb打开,然后输入x/14xb multstore
查看反汇编
这里运用的是examine命令,x的命令语法如下
x/<n/f/u> n 是一个正整数,表示需要显示的内存单元的个数,也就是说当前地址后显示几个内存单元的内容,一个内存单元的大小由后面的u定义。u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。表示一个内存地址
所以上面就是,查看multstore函数处的反汇编,展示14个以byte为格式的内存,以x的形式就是16进制的形式展现
而我们要查看整个程序的反汇编可以输入命令objdump -d test.o
来查看反汇编
二、使用gdb调试器
开始和停止
命令 | 效果 |
---|---|
quit | 退出gdb |
run | 运行程序 |
kill | 停止程序 |
断点
命令 | 效果 |
---|---|
break 函数名 | 函数入口处下断点 |
break *地址 | 地址处下断点 |
delete 1 | 删除断点1 |
delete | 删除断点 |
执行
命令 | 效果 |
---|---|
stepi | 执行一条语句 |
stepi n | 执行n条语句 |
next i | 执行下一个函数调用 |
continue | 继续执行 |
finish | 执行到当前函数返回 |
检查代码
命令 | 效果 |
---|---|
disassemble | 查看当前函数的反汇编 |
disassemble 函数名字 | 查看这个函数的反汇编 |
disassemble 地址 | 地址附近函数的反汇编 |
disassemble 地址1,地址2 | 查看地址1到地址2范围内的反汇编 |
print /x $rip | 十六进制数输出程序的计数器 |
或者下断点用vmmap查看
三、深入理解缓冲区溢出
看下gets函数的原型
char* gets()
{
int c;
char* dest =s; //定义了dest就是这个参数的地址
while((c = getchar())!='\n' && c != EOF)//从getchar获取到\n和EOF结束
{
*dest++ = c;//这个地址每输入一次向后移动一位
}
if (c == EOF && dest == s)//如果一开始就输入了EOF或者没有输入,那就直接返回空
{
return NULL;
}
*dest++ = '\0'; //令最后一个为0
return s;
}
所以将字符串复制到s指明的位置
void echo()
{
char buf[8];
gets(buf);
puts(buf);
}
这里故意设置缓冲区很小,那我们就可以越界了。参考之前的pwn,各种栈的题目