在此堆栈中:
0019FF58 $-8 0019FF58 00000002 LOCAL 2
0019FF5C $-4 0019FF5C 00000001 LOCAL 1
0019FF60 $ ==> 0019FF60 0019FF80 OLD EBP
0019FF64 $+4 0019FF64 | 00401025 return to layout.00401025 from layout.sub_40102C
0019FF68 $+8 0019FF68 | 00000041 PARAM 3
0019FF6C $+C 0019FF6C | 0000BABE PARAM 2
0019FF70 $+10 0019FF70 | 0000CAFE PARAM 1
Ghidra获取:
undefined4 Stack[0x4]:4 param_1 XREF[1]: 00401040 (R)
undefined4 Stack[0x8]:4 param_2 XREF[1]: 00401043 (R)
undefined4 Stack[0xc]:4 param_3 XREF[1]: 00401046 (R)
undefined4 Stack[-0x8]:4 local_8 XREF[1]: 00401032 (W)
undefined4 Stack[-0xc]:4 local_c XREF[1]: 00401039 (W)
00401032 C745FC01000000 MOV dword ptr [EBP + local_8 ],0x1
00401039 C745F802000000 MOV dword ptr [EBP + local_c ],0x2
00401040 8B5D08 MOV EBX ,dword ptr [EBP + param_1 ]
00401043 8B4D0C MOV ECX ,dword ptr [EBP + param_2 ]
00401046 FF7510 PUSH dword ptr [EBP + param_3 ]
而IDA正确获取:
.text:0040102C var_8 = dword ptr -8
.text:0040102C var_4 = dword ptr -4
.text:0040102C arg_0 = dword ptr 8
.text:0040102C arg_4 = dword ptr 0Ch
.text:0040102C arg_8 = dword ptr 10h
.text:00401032 mov [ebp+var_4], 1
.text:00401039 mov [ebp+var_8], 2
.text:00401040 mov ebx, [ebp+arg_0]
.text:00401043 mov ecx, [ebp+arg_4]
#1 楼
TL; DR:这不是Ghidra的错误。这些值只是命名约定,真正的指令已正确反汇编。
Ghidra会根据函数入口点分配变量名称,并根据此值显示偏移量。
Ghidra的行为似乎类似于具有独立于编译器的通用分配名称的方法。
如R4444所指出的,Ghidra显示相对于
entry stack-pointer
的变量偏移量,而不是frame-based
偏移量。这里,Ghidra在输入函数时基于
ESP
(或相应的堆栈指针)分配变量名称,而无需考虑即将到来的PUSH EBP
,基本上遵循以下步骤:0019FF58 $-C 0019FF58 00000002 LOCAL 2
0019FF5C $-8 0019FF5C 00000001 LOCAL 1
0019FF60 $-4 0019FF60 0019FF80 will store the OLD EBP
0019FF64 $ ==> 0019FF64 | 00401025 return to layout.00401025 from layout.sub_40102C
0019FF68 $+4 0019FF68 | 00000041 PARAM 1
0019FF6C $+8 0019FF6C | 0000BABE PARAM 2
0019FF70 $+C 0019FF70 | 0000CAFE PARAM 3
这就是Ghidra如何获取值的方式:
Stack[0x4] -> param_1
Stack[0x8] -> param_2
Stack[0xc] -> param_3
Stack[-0x8] -> local_8
Stack[-0xc] -> local_c
必须将其视为变量命名,实际的指令是以正确的偏移量寻址数据。如果我们导航到其中一个令人反感的指令,则可以看到Ghidra在右下角提供了正确的指令,在这种情况下,对于命名变量
EBP-4
(local_8
),为[-0x8]
:可以通过以下命令永久修改默认的Ghidra行为:
Edit > Tool Options > Listing Fields > Operands Field > Markup Stack Variable References
,然后Ghidra将显示: undefined4 Stack[0x4]:4 param_1 XREF[1]: 00401040 (R)
undefined4 Stack[0x8]:4 param_2 XREF[1]: 00401043 (R)
undefined4 Stack[0xc]:4 param_3 XREF[1]: 00401046 (R)
undefined4 Stack[-0x8]:4 local_8 XREF[1]: 00401032 (W)
undefined4 Stack[-0xc]:4 local_c XREF[1]: 00401039 (W)
00401032 C745FC01000000 MOV dword ptr [EBP + -0x4 ]=> local_8 ,0x1
00401039 C745F802000000 MOV dword ptr [EBP + -0x8 ]=> local_c ,0x2
00401040 8B5D08 MOV EBX ,dword ptr [EBP + 0x8 ]=> param_1
00401043 8B4D0C MOV ECX ,dword ptr [EBP + 0xc ]=> param_2
00401046 FF7510 PUSH dword ptr [EBP + 0x10 ]=> param_3
这是值不匹配和如何获得这些值,但是为什么Ghidra会根据函数条目来命名变量? @emteere解释说:
基于帧变量的堆栈变量偏移量与基于堆栈指针的堆栈变量偏移量的选择可能会引起混淆。它所允许的是忽略堆栈框架变量,而仅在它们发生的地方创建对堆栈的引用。有很多将堆栈指针加载到不带框架的备用寄存器中的示例,因此在两个不同功能中都存在和没有帧指针的情况下,在入口处使用通用栈基似乎是一个不错的选择,并且不会造成混淆。加载调试信息后,需要在入口处完成到SP的转换。另外,许多编译器都不再使用堆栈帧寄存器。
所以,我想我的解释是通常希望具有基于帧的变量至少在某些扩展性最强的体系结构/编译器中,就像在IDA中看到的那样命名。但是,Ghidra用通用策略命名变量,他们决定通过在输入函数时基于堆栈指针偏移变量来协调不同体系结构/编译器的行为。
来源:
ARM中怀疑不正确的FP堆栈变量
Ghidra帮助:“函数签名,属性和变量”
评论
您的示例中使用的呼叫约定是Ghidra和IDA默认值,Ghidra报告“ __stdcall”,我也认为IDA。在任何情况下,调用都是相当标准的,可以由工具识别,并带有RET 0xC
看到这个问题-github.com/NationalSecurityAgency/ghidra/issues/998