C和汇编混合编程--------函数调用后ebp、esp值问题

今天老师又给了一个程序,让我们分析,记录一下分析过程
程序:

#include "stdio.h"
#include "string.h"


char *shellcode="\x64\x65\x66\x67\x68\x69\x70\x71\x05\x10\x40\x00";
void fun1(int a, int b)
{
   printf("fun1 run!para a=%d,b=%d\n",a,b);
    char aa[4]={0};
strcpy(aa,shellcode);	
}
void fun2(int a)
{
   printf("fun2 run! para a=%d\n",a);
   
}
void fun3(int a,int b,int c)
{
  printf("fun3 run! para a=%d,b=%d,c=%d\n",a,b,c);
}
int main(int argc, char* argv[])
{
	printf("begin\n");
	fun1(1,2);
	
	printf("end\n");
	return 0;
}

结果:

fun2函数执行了,没有输出来end
在这里插入图片描述
首先我们来看看为什么fun2执行了,将程序反汇编
当执行完char aa[4]={0},我们发现0x0019fed0这个地址存放这个数据,此时我们看一下0x0019fed4和0x0019fed8内的数据
在这里插入图片描述
当执行完strcpy时,0x0019fed0到0x0019fed8存放的内容是shellcode的内容,为什么是这个数据,看这篇文章(https://blog.csdn.net/qq_41683305/article/details/104282462),继续往下执行
在这里插入图片描述
当执行到ret命令时,我们观察esp的值,发现存放的内容是00401005,这个是什么?我们找到fun2的地址
在这里插入图片描述
发现和fun2的地址一样,这就是为什么会执行fun2
在这里插入图片描述
为什么不会输出end呢?
下面继续分析,按照上面的继续执行,当执行到ret时,此时esp存放的数据是00000001,我们会到这个地址执行
在这里插入图片描述
00000001啥都不是,所以不会执行end
在这里插入图片描述
下面来解决问题
现在我们来理一理思路,程序先执行fun1,然后去执行fun2,然后到00000001执行,没有返回来,我们要注意,00000001是我们程序fun1(1,2)中的1,所以我们将1改成我们要fun2执行完跳转的地址,就可以继续执行了,这个地址就是下图中的地址,跳转到这里继续执行
在这里插入图片描述
我们来改一下,程序:

#include "stdio.h"
#include "string.h"


char *shellcode="\x64\x65\x66\x67\x68\x69\x70\x71\x05\x10\x40\x00";
void fun1(int a, int b)
{
   printf("fun1 run!para a=%d,b=%d\n",a,b);
    char aa[4]={0};
strcpy(aa,shellcode);	
}
void fun2(int a)
{
   printf("fun2 run! para a=%d\n",a);
   
}
void fun3(int a,int b,int c)
{
  printf("fun3 run! para a=%d,b=%d,c=%d\n",a,b,c);
}
int main(int argc, char* argv[])
{
	printf("begin\n");
	fun1(0x401191,2);
	printf("end\n");
	return 0;
}

在这里插入图片描述
我们可以看到fun1里填的0x401191不是0x40118e,这是1和0x401191和所占的字节不同导致的

继续报错,提示堆栈没有平衡,继续分析
我们分析一下,当调用fun1函数前,esp的值如图
在这里插入图片描述
fun2执行完,执行完下图的add esp,8时,esp的值为

在这里插入图片描述

在这里插入图片描述
本应该执行完add esp,8,esp的值应该是调用fun1函数前的值,结果差了4,找到原因了,补上:

#include "stdio.h"
#include "string.h"


char *shellcode="\x64\x65\x66\x67\x68\x69\x70\x71\x05\x10\x40\x00";
void fun1(int a, int b)
{
   printf("fun1 run!para a=%d,b=%d\n",a,b);
    char aa[4]={0};
strcpy(aa,shellcode);	
}
void fun2(int a)
{
   printf("fun2 run! para a=%d\n",a);
   
}
void fun3(int a,int b,int c)
{
  printf("fun3 run! para a=%d,b=%d,c=%d\n",a,b,c);
}
int main(int argc, char* argv[])
{
	printf("begin\n");
	fun1(0x401191,2);
	
	__asm{
		sub esp,4
	}
	
	printf("end\n");
	return 0;
}

在这里插入图片描述
栈都平衡了,为什么还会报错呢,这就和检查有没有平衡栈的机制有关了

ebp存放的是调用函数前的esp,函数调用最后需要平衡栈数据,也就是将esp还原成调用函数前的esp,如果比较ebp和esp相等就不报错

没错还和ebp有关,在执行strcpy时,把原来的ebp内容修改了,所以会报错,继续改,还原原来的ebp

#include "stdio.h"
#include "string.h"


char *shellcode="\x64\x65\x66\x67\x68\x69\x70\x71\x05\x10\x40\x00";
void fun1(int a, int b)
{
   printf("fun1 run!para a=%d,b=%d\n",a,b);
    char aa[4]={0};
strcpy(aa,shellcode);	
}
void fun2(int a)
{
   printf("fun2 run! para a=%d\n",a);
   
}
void fun3(int a,int b,int c)
{
  printf("fun3 run! para a=%d,b=%d,c=%d\n",a,b,c);
}
int main(int argc, char* argv[])
{
	printf("begin\n");
	fun1(0x401191,2);
	
	__asm{
		sub esp,4
		mov ebp,0x19ff30
	}
	
	printf("end\n");
	return 0;
}

执行,完美解决问题
在这里插入图片描述
总结:

  • 检查栈有没有平衡,是根据ebp和esp的值,有一个修改都要还原
  • ebp存放的是调用函数前的esp,函数调用最后需要平衡栈数据,也就是将esp还原成调用函数前的esp,如果比较ebp和esp相等就不报错,就是下图这两条语句检查的
    在这里插入图片描述
  • esp和ebp的值最后要相同

中间涉及esp和ebp的值变换,没有写了,反汇编调试注意一下

发布了168 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41683305/article/details/104299319
今日推荐