我想使用“函数”选项卡中的“参数”值在 IDA Pro 中高效地查找特定函数。但是,对于以下从 IDA 反编译中获得的代码示例:
__int64 __fastcall sub_49FB60(__int64 a1)
{
sub_484690(a1 + 208, 0LL);
sub_484690(a1 + 112, 0LL);
return sub_484690(a1 + 16, 0LL);
}
_QWORD *__fastcall sub_4A0050(_QWORD *a1, __int64 a2)
{
sub_4A3CB0(a1);
*a1 = off_979AD8;
a1[13] = a2;
return a1;
}
__int64 __fastcall sub_4D3D20(__int64 a1, __int64 a2, unsigned __int8 a3)
{
__int64 v5; // rcx
*(_QWORD *)a1 = a2;
v5 = *(_QWORD *)(*(int *)(*(_QWORD *)a2 + 4LL) + a2 + 72);
if ( v5 )
(*(void (__fastcall **)(__int64))(*(_QWORD *)v5 + 8LL))(v5);
*(_BYTE *)(a1 + 8) = sub_4D3BC0(*(_QWORD *)a1, a3);
return a1;
}
所有这些函数的“参数”值都是 00000010。最初,我认为它可能表示参数大小的总和,但计算结果不匹配。“参数”字段实际上代表什么?
此外,所提供的代码示例中的“参数”值代表什么?
__int64 __fastcall sub_52AFD0(unsigned int **a1, unsinged int a2, __int64 a3)
{
unsinged int v3;
unsinged int v4;
unsinged int v6;
unsinged __int i;
v6 =-1;
for ( i = a2 / 8ui64; i; --i)
{
v3 = **a1 ^ v6;
++*a1;
v4 = **a1;
v6 = *(_DWORD *)(a3 + 4i64 * (v4 >> 24)));
}
return v6;
}
“参数”列中的值似乎表示在函数堆栈框架(较高的堆栈地址)之前为函数参数保留的空间。因此,它并不表示所有函数参数的总大小,而只是表示通过堆栈传递的参数。感谢Andrey Turkin在下面的评论中指出了这一点。
例如,
/bin/awk
在我的 x86-64 Linux 系统上使用 IDA Free 8.4 反汇编时,我看到以下函数:它的“参数”列显示
00000004
。如果我查看反汇编,我可以看到以下内容:请注意,在堆栈指针之后分配的唯一变量(具有正偏移量
8
)是arg_0
。这对应于a7
函数签名中的参数。在这种情况下,前 6 个参数通过寄存器 RDI、RSI、RDX、RCX、R8 和 R9 传递。第 7 个参数在堆栈上传递。事实上,如果我看一下 xref(按下X函数名称),我可以看到这个调用:
如您所见,第 7 个参数通过 传递
push 9
。尽管该指令push 9
将 8 字节值推送到堆栈,但该函数似乎只能使用 4 字节(dword
)取消引用操作来访问该值(或在任何情况下将其视为 4 字节值)。这似乎就是“参数”列显示 的原因00000004
。同样,对于另一个函数:
我可以看到“参数”列显示
00000011
(17),因为__int64 a7
,__int64 a8
和char a9
通过堆栈传递:查看 IDA 文档
IDA 有一个非常不错的内置文档。如果您将光标放在函数窗口中,然后按下键F1,文档将在一个新窗口中弹出。以下是它在我 IDA Free 8.4 上的样子。
查看文档中的“功能窗口”页面,这些字段包括:
相同的文档页面也可在此处在线获取。
从文档来看,“参数”列似乎应该表示“传递给函数的参数的大小”。 Hex-Rays YouTube 频道也有一个关于函数窗口的视频来解释这些内容,它还说“参数”列应该表示“传递给函数的参数的大小”。
这些描述似乎太笼统,无法准确描述列的含义。似乎应该更新文档页面,提供更清晰的描述。
同样的道理也适用于第二列和第三列(段和起始): “起始”列绝对不代表“段”列中显示的 ELF 段内的偏移量(即使它显示了
.text
哪个是节),而是绝对虚拟地址。这可能是因为正如Ben Voigt在下面所建议的那样,“段”列的文档中的“段”一词指的是二进制(例如 ELF)段/节,但对于“起始”列,当 CPU 使用分段内存模型(例如分段 16 位 x86 实模式)时,它可能指的是体系结构定义的段。令人困惑。