最近看了一点点栈的知识,顺手写下来之前不清楚的点
在调用一个函数的时候,会用栈来存储信息,在这个函数调用结束之后栈上这一部分东西会被清除,通常的汇编代码为 (以32位为例)
push ebp
mov esp, ebp
sub esp, xxx (xxx为这一函数所用的栈的空间大小)
... ...
mov esp, ebp
pop ebp
ret
这一段汇编中 EBP 位置不变,最后回到原点,意思也就是没清除栈上剩余 “ 垃圾 ” 仅是将 ESP 拉回来,再 pop EBP,这样栈上的 “ 垃圾 ” 可能会污染到接下来的函数调用,以下就是我看的文章举得一个小栗子
#include <stdio.h>
void f1()
{
int a=1, b=2, c=3;
};
void f2()
{
int a, b, c;
printf ("%d, %d, %d\n", a, b, c);
};
int main()
{
f1();
f2();
};
这个编译之后得到的结果是
1, 2, 3
为什么产生这个结果,就跟我上面所说的有关,接下来我们进入 gdb 调试一下,不过我将它的代码增加了一点
事先声明,由于我还没搞成功 32 位 C 的编译器,所以用的 64 位的 ??
#include <stdio.h>
void g1()
{
int a=0, b=3, c=5;
return ;
}
void g2()
{
int a,b,c;
printf("%d %d %d\n", a, b, c);
return ;
}
void f1()
{
int x=4, y=5;
g1();
g2();
return ;
}
void f2()
{
int x, y, z;
printf("%d %d %d\n", x, y, z);
return ;
}
int main()
{
f1();
f2();
return 0;
}
先是进行 f1, f1 中用的上述文章中的小栗子,再进行 f2 , 这个得到的结果如下
0 2 3
4 5 21912/21952/... (由于我只 int 两个值,所以 最后一个 z 是从栈上取得,因此是随机的)
我们来看一下这几个函数的 RBP 和 汇编
我先设了四个断点, f1 f2 g1 g2,接下来我们要从汇编层次来验证 F1_RBP == F2_RBP,G1_RBP == G2_RBP
接下来的图分别是, F1,G1,G2,F2,G2 的 print,F2 的 print,F1和G1 的第一箭头是将局部变量存储的位置,G2和F2 的第一个箭头都是 格式化字符串取的值的位置,这四个的第二箭头都是 RBP
通过两个 print 也可以验证,为什么会产生这种结果
参考文章是 reverse-engineering-for-beginners 的翻译