IDA Pro 函数堆栈框架视图

逆向工程 拆卸 静态分析 艾达 调用约定
2021-06-15 10:00:35

IDA Pro 在堆栈帧视图中在局部变量上方(在较低地址处)显示某些缓冲区或填充。例如:

示例 1.
以下堆栈帧视图的屏幕截图显示了 12 字节(包含在红色框中)缓冲区:

在此处输入图片说明

示例 2。
以下不同堆栈帧视图的屏幕截图再次显示了 12 字节缓冲区:

在此处输入图片说明

我知道 IDA 将其标记为db ?; undefined因为它无法弄清楚它是如何使用的。我还意识到 IDA 通过监视 ESP 自动计算堆栈帧的大小。我认为它可能与非易失性寄存器保存区域有关。然而,在示例 1 中它清楚地显示Saved regs: 0,在示例 2 中它显示了Saved regs: 4我很困惑,这里是我的问题:

为什么 IDA Pro 在堆栈帧视图中在局部变量上方(较低地址)显示某些缓冲区或填充?两个视图都显示正好12 字节的缓冲区是巧合吗?它是某些调用约定或编译器所特有的吗?

3个回答

在整个函数的静态分析过程中,IDA 会跟踪堆栈指针 (ESP) 的值。ESP 的最大负值(相对于函数的开头)用于确定堆栈帧的大小。

至于为什么您发布的堆栈帧顶部有“未定义”字节,这是因为 IDA 无法自动确定是否或如何使用这些堆栈偏移量。

非常感谢大家的回答和评论。在阅读您的评论并准备更新我的问题时,我找到了答案。

我必须感谢 Igor Skochinsky,他让我提供函数的序言指令。这两个函数都使用cdecl 调用约定但是,调用约定与此缓冲区无关。这是序言的样子:

push    ebp
mov     ebp, esp
sub     esp, <size of local vars>
push    ebx
push    esi
push    edi

该缓冲区反映了寄存器 EBX、ESI、EDI 的三个推送指令这些寄存器被归类为被调用者保存的寄存器,这个“缓冲区”被称为非易失性寄存器保存区

按照x86约定(x64也适用),寄存器分为Caller Saved RegistersCallee Saved Registers

调用者保存的寄存器也称为易失性寄存器。这些是核心 CPU 寄存器,例如 EAX、EDX 和 ECX。调用函数(Caller)负责在调用之前将易失性寄存器保存到通常的运行时堆栈中。

被调用方保存的寄存器称为非易失性寄存器。这些是核心 CPU 寄存器,例如 EBX、ESI、EDI、ESP 和 EBP。按照惯例假设,这些寄存器中的值将由被调用函数保存。如果要在被调用方中使用任何非易失性寄存器,则被调用方负责将寄存器保存到运行时堆栈中。此外,被调用者负责在返回调用者函数之前恢复这些寄存器。

使用易失性和非易失性寄存器的方式是由编译器驱动的。下面的论文x86 Assembly Guide更详细地描述了 Caller 和 Callee 规则。

屏幕截图显示您正在检查 IDA 的详细堆栈视图。

IDA 为函数中直接访问的每个字节命名,任何其他字节保持未定义。

调用约定?给我们这个子程序的序言和结尾,这样我们就可以看到堆栈是如何分配和清理的。

因此,如果这是用高级语言(不是恶意软件也不是手工编写的)编写的普通应用程序的堆栈框架,并且不是特定于调用约定的,那么我认为我们可以同意编译器分配的堆栈空间比该函数需要的更多原因。

我不认为知道编译器为什么这样做是“必须的”,但那是您的选择。