欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-03 15:51:17
...

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

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

C和汇编混合编程--------函数调用后ebp、esp值问题
我们可以看到fun1里填的0x401191不是0x40118e,这是1和0x401191和所占的字节不同导致的

继续报错,提示堆栈没有平衡,继续分析
我们分析一下,当调用fun1函数前,esp的值如图
C和汇编混合编程--------函数调用后ebp、esp值问题
fun2执行完,执行完下图的add esp,8时,esp的值为

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

C和汇编混合编程--------函数调用后ebp、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;
}

C和汇编混合编程--------函数调用后ebp、esp值问题
栈都平衡了,为什么还会报错呢,这就和检查有没有平衡栈的机制有关了

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;
}

执行,完美解决问题
C和汇编混合编程--------函数调用后ebp、esp值问题
总结:

  • 检查栈有没有平衡,是根据ebp和esp的值,有一个修改都要还原
  • ebp存放的是调用函数前的esp,函数调用最后需要平衡栈数据,也就是将esp还原成调用函数前的esp,如果比较ebp和esp相等就不报错,就是下图这两条语句检查的
    C和汇编混合编程--------函数调用后ebp、esp值问题
  • esp和ebp的值最后要相同

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

相关标签: win32汇编