Ghidra 是否误解了函数调用?
Is Ghidra misinterpreting a function call?
在分析 Ghidra 中的汇编列表时,我偶然发现了这条指令:
CALL dword ptr [EBX*0x4 + 0x402ac0]=>DAT_00402abc
我假设程序正在调用一个地址在 DAT_00402abc
内的函数,我最初认为它是一个双字变量。事实上,当试图在 DAT_00402abc
所在的位置创建一个函数时,Ghidra 不让我这样做。
反编译器向我展示了翻译该指令的这行代码:
(*(code *)(&int2)[iVar2])();
所以我想知道,这是什么意思,程序应该如何处理这个调用? Ghidra 有没有可能完全搞砸了?如果是这样,我应该如何解释该指令?
我对 Ghidra 一点都不熟悉,但我可以告诉你如何解释机器指令...
CALL dword ptr [EBX*0x4 + 0x402ac0]
0x402ac0
处有table个函数地址;正在调用 table 中的第 EBX 个条目。我不知道 DAT_00402abc
是什么意思,但是如果您检查地址 0x0402ac0
处双字大小的内存块,您应该会找到合理的函数地址。 [编辑:0x0040_2abc = 0x0040_2ac0 - 4. 我怀疑这意味着 Ghidra 认为当控制达到这一点时 EBX 的值为 -1。可能是错误的,也可能是程序有bug。当控制达到这一点时,人们会期望 EBX 具有 非负 值。]
这条指令对应的自然C源代码应该是这样的
extern void do_thing_zero(void);
extern void do_thing_one(void);
extern void do_thing_two(void);
extern void do_thing_three(void);
typedef void (*do_thing_ptr)(void);
const do_thing_ptr do_thing_table[4] = {
do_thing_zero, do_thing_one, do_thing_two, do_thing_three
};
// ...
void do_thing_n(unsigned int n)
{
if (n >= 4) abort();
do_thing_table[n]();
}
如果 table 中的函数接受参数或 return 值,您将在引用的 CALL 指令前后看到参数处理代码,但 CALL 指令本身不会改变.
如果函数不都采用相同的参数集,您会看到一些不同且复杂得多的东西。
在分析 Ghidra 中的汇编列表时,我偶然发现了这条指令:
CALL dword ptr [EBX*0x4 + 0x402ac0]=>DAT_00402abc
我假设程序正在调用一个地址在 DAT_00402abc
内的函数,我最初认为它是一个双字变量。事实上,当试图在 DAT_00402abc
所在的位置创建一个函数时,Ghidra 不让我这样做。
反编译器向我展示了翻译该指令的这行代码:
(*(code *)(&int2)[iVar2])();
所以我想知道,这是什么意思,程序应该如何处理这个调用? Ghidra 有没有可能完全搞砸了?如果是这样,我应该如何解释该指令?
我对 Ghidra 一点都不熟悉,但我可以告诉你如何解释机器指令...
CALL dword ptr [EBX*0x4 + 0x402ac0]
0x402ac0
处有table个函数地址;正在调用 table 中的第 EBX 个条目。我不知道 DAT_00402abc
是什么意思,但是如果您检查地址 0x0402ac0
处双字大小的内存块,您应该会找到合理的函数地址。 [编辑:0x0040_2abc = 0x0040_2ac0 - 4. 我怀疑这意味着 Ghidra 认为当控制达到这一点时 EBX 的值为 -1。可能是错误的,也可能是程序有bug。当控制达到这一点时,人们会期望 EBX 具有 非负 值。]
这条指令对应的自然C源代码应该是这样的
extern void do_thing_zero(void);
extern void do_thing_one(void);
extern void do_thing_two(void);
extern void do_thing_three(void);
typedef void (*do_thing_ptr)(void);
const do_thing_ptr do_thing_table[4] = {
do_thing_zero, do_thing_one, do_thing_two, do_thing_three
};
// ...
void do_thing_n(unsigned int n)
{
if (n >= 4) abort();
do_thing_table[n]();
}
如果 table 中的函数接受参数或 return 值,您将在引用的 CALL 指令前后看到参数处理代码,但 CALL 指令本身不会改变.
如果函数不都采用相同的参数集,您会看到一些不同且复杂得多的东西。