失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > C和汇编混合编程--------函数调用后ebp esp值问题

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

时间:2023-08-03 11:05:27

相关推荐

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的内容,为什么是这个数据,看这篇文章(/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,4mov ebp,0x19ff30}printf("end\n");return 0;}

执行,完美解决问题

总结:

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

esp和ebp的值最后要相同

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

如果觉得《C和汇编混合编程--------函数调用后ebp esp值问题》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。