示例程序 链接: http://pan.baidu.com/s/1mi2kce0 密码: v3fh

调试逆向基础知识四之函数调用约定&栈帧处理

目录:
1.利用实例理解栈帧
2.了解函数调用约定

环境配置和调试逆向基础知识一相同

一:利用实例理解栈帧

概念:
栈帧:栈帧在函数中用于声明局部变量,保存函数参数,保存函数返回地址等。
EBP 寄存器又叫栈帧寄存器(作用通过EBP寄存器访问保存在栈中的局部变量,函数参数,函数返回地址等)

栈帧对应的汇编代码如下:

push ebp
mov  ebp,esp
...
mov esp,ebp
pop ebp
RETN
原理:
首先将EBP寄存器中的值进栈
将ESP的值赋值给EBP
接下来无论是访问局部变量,还是调用函数都是以EBP 寄存器为基准,这样无论ESP怎么变化都不会影响访问局部变量,函数返回地址,函数等。
最后:
将ebp的值赋值给esp 寄存器,pop 一个数据赋值到ebp寄存器(其实此时pop的就是最初push ebp的值) 
即最后一步骤的操作就是为拉恢复寄存器中为调用函数前的状态

下面实例分析StackFrame.exe:

源码:
#include "stdio.h"
long add(long a, long b)
{
    long x = a, y = b;
    return (x + y);
}
int main(int argc, char* argv[])
{
    long a = 1, b = 2;
    printf("%d\n", add(a, b));
    return 0;
}

首先用 OD打开StackFrame.exe如图1所示:

如图一已经标出啦此次试验需要重点关注的窗口
我们直接找到主函数的call(方法在第一篇中已经介绍)来到如图2所示:

此时我们直接在地址00401248处F7快捷键进入此call,(此时我们还需要记着00401248处的下一条指令的地址是0041250(very import))
我们来到来到图三所示情形:

图中关键信息已经标注啦出来。。
首先介绍几个关于 od的快捷键

*  表示光标返回到正在调试的EIP的地址处
 -  表示返回到当前光标的上一次行为处
 Enter 可以进入call 
以上三个快捷键在调试时候对于查看程序的上下文非常有用,请熟练运用

在图三中我们观察到esp的值为 0012FF7C 观察堆栈窗口时,只能看到主函数执行完以后的返回地址。
此时我们按快捷键F8使程序运行到0040102D如图四所示:

如图四中重要信息已经标注出,我们可以看到此时堆栈窗口中申请啦12字节内存已经,此时我们可以猜测堆栈窗口地址0012FF70处存储的值为 2,(一会我们可以验证)
接下来我们执行程序到CPU窗口中到地址0040103C处如图五所示:

图五中重点在与add()函数两个参数的进栈顺序以及在栈中的排列顺序这个要理解清楚。
然后我们快捷键进call如图6所示:

在堆栈窗口我们可以选择地址的显示方式,方法是 右键-》地址-》有三个选项可以自己进行选择此处我们选择是相对ebp 如图六 显示
当程序执行到地址00401015处的时候我们可以观看如图七所示:

如图七所示重点部分已经标注出来。当我们执行到地址004011B处的时候堆栈窗口如图八所示:

图八重点部分已经标注出
接下来继续执行程序来找主函数,当主函数执行到地址00401057处时候如图九所示:

如图九所示 栈帧已经被销毁

总结:
1.栈帧的生成销毁已经啦,
2.请熟记栈帧的生成及销毁的汇编代码
3.多次调试程序知道理解为止

二:函数调用约定

概念:
函数约定是对函数调用时如何传递参数的一种约定
函数调用约定常见形式有:
cdecl (主要用在c 语言中)由调用者处理栈
stdcall 主要用在win32 api编程中  由被调用者负责处理栈
fastcall  通常由寄存器传递参数

cdecl实例

源码:
#include "stdio.h"
int add(int a, int b)
{
    return (a + b);
}
int main(int argc, char* argv[])
{
    return add(1, 2);
}

用od打开cdecl.exe如图10所示:

stdcall

源码:
#include "stdio.h"
int _stdcall add(int a, int b) //用_stdcall 模式进行处理
{
    return (a + b);
}
int main(int argc, char* argv[])
{
    return add(1, 2);
}

用od打开cdecl.exe如图11所示:

如图11所示即可看出

小结:
1.掌握常用的函数调用约定方式。fastcall 不经常遇到。
2.多加调试练习
打赏