关闭

系统栈与函数调用

标签: 系统栈逆向函数调用
258人阅读 评论(0) 收藏 举报
分类:

0x00 系统栈的工作原理

1) 进程使用的内存

  • 代码区:二进制机器代码
  • 数据区:全局变量等
  • 堆区:进程动态请求内存,用完归还。如动态分配和回收
  • 栈区:用于动态存储函数间调用关系,也叫系统栈、调用栈,由系统自动维护

2) 系统栈

int func_B(int arg_B1, int arg_B2)
{
    int var_B1, var_B2;
    var_B1=arg_B1+arg_B2;
    var_B2=arg_B1-arg_B2;
    return var_B1*var_B2;
}

int func_A(int arg_A1, int arg_A2)
{
    int var_A;
    var_A = func_B(arg_A1,arg_A2) + arg_A1 ;
    return var_A;
}

int main(int argc, char **argv, char **envp)
{
    int var_main;
    var_main=func_A(4,3);
    return var_main;
}
  • 程序中使用的缓冲区可以是堆区、栈区、存静态变量的数据区
  • 同一文件不同函数的代码在内存代码区的分布是散乱无关的
  • 程序执行中函数调用与系统栈的变化
    这里写图片描述
    这里写图片描述

3) 寄存器与函数栈帧

  • 当前运行函数的栈帧总在系统栈顶端
  • 当前栈帧(系统栈顶端)由ESP和EBP标识
    ESP:栈指针寄存器,存放着指向顶端栈帧的栈顶的指针
    EBP:基址指针寄存器,存放着指向顶端栈帧的底部的指针
    这里写图片描述
  • 函数栈帧包含
    局部变量:保存局部变量
    栈帧状态值:保存当前栈帧的顶部和底部
    函数返回地址:函数结束后返回到之前的代码区继续执行
  • 函数栈帧的大小不固定,与函数局部变量多少有关。函数运行过程中栈帧的大小也在变
  • EIP:指令寄存器,存着指向下一条等待执行指令的指针。

0x01 函数调用

1) 函数调用约定与相关指令

  • 函数调用约定:描述了函数参数传递方式和栈协同工作的技术细节。包括:
    a) 参数传递方式是寄存器还是压栈
    b) 栈传递时,参数压栈顺序
    c) 清栈由调用方还是被调方进行
  • 不同OS、语言、编译器的函数调用约定有差别
    这里写图片描述
    Visual C++6.0可支持3种函数约定,默认使用_cdecl调用方式
    这里写图片描述
    _fastcall方式在参数较少时通过寄存器传参:参数多时,前两个用寄存器传参,其余用压栈的方式传递
    这里写图片描述

2) 函数调用步骤

  • 参数入栈:参数从右向左依次压入栈中
  • 返回地址入栈:当前代码区调用指令的下一条指令地址压入栈,供函数返回是继续执行
  • 代码区跳转:CPU从当前代码区跳转到被调用函数的入口
  • 栈帧调整
    a) EBP入栈:保存当前栈帧状态值,以备后面恢复本栈帧时使用
    b) ESP—>EBP:更新栈帧底部,切换到新栈帧
    c) ESP – 新栈帧大小:抬高栈顶,给新栈帧分配空间
    这里写图片描述
  • OllyDbg中栈帧是按前栈帧EBP值划分的,返回地址成了栈帧顶部数据
    这里写图片描述
    这里写图片描述

3) 函数返回步骤

  • 保存返回值:函数返回值保存在EAX寄存器
  • 弹出当前栈帧,恢复上一个栈帧
    a) ESP + 当前栈帧大小:堆栈平衡基础上,降低栈顶,回收当前栈帧空间
    b) POP EBP:前栈帧EBP弹给EBP,恢复上一个栈帧
    c) POP EIP:函数返回地址弹给EIP
    这里写图片描述
    这里写图片描述
  • 跳转:按EIP的值返回母函数继续执行

4) 函数调用实现

  • 这里写图片描述

——《0day安全》学习笔记

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:25788次
    • 积分:406
    • 等级:
    • 排名:千里之外
    • 原创:17篇
    • 转载:2篇
    • 译文:0篇
    • 评论:8条