为了学习(和娱乐),我一直在使用IDA Pro分析文本编辑器应用程序。在查看反汇编时,我注意到通过显式调用函数名称进行了许多函数调用。例如,我注意到IDA将大多数函数调用转换为以下两种格式。

call cs:CoCreateInstance




call WinSqmAddToStream


但是有时格式不使用函数名称。下面的示例包括导致该行的代码。第三行代码似乎“缺少”函数名称。 (评论是我自己的。)

mov rcx, [rsp+128h+var_D8]    // reg CX gets the address at stack pointer+128h+var_D8 bytes 
mov r8, [rcx]                 // the address at reg CX is stored to reg r8
call qword ptr [r8 + 18h]     // at address rax+18h, call function defined by qword bytes 


我的问题如下:


如何建立两者之间的联系call qword ptr <address>和反汇编中的函数?
我知道IDA在这里不能使用函数名称,因为它不知道存储在寄存器R8中的值...那是什么原因呢?开发人员是否使用某种语法或约定?换句话说,开发人员是否以与WinSqmAddToStream处不同的方式调用函数[r8+18h]


评论

例如,这些间接调用用于在C ++中实现虚拟功能(通过使用vtable)。

也有像github.com/0xgalz/Virtuailor这样的插件可以自动执行这些任务。

#1 楼

要将间接调用连接到其目标(如果知道),可以执行以下操作:

1)添加自定义交叉引用-使用IDC / Python或“交叉引用”子视图。如果使用脚本,请不要忘记添加XREF_USER标志,以便IDA在重新分析时不会将其删除。

2)使用“ callee”插件(编辑->插件->更改被调用者地址) ,或Alt + F11)。这将自动在调用旁边添加一个交叉引用和注释。

为什么在二进制文件中不存在显式调用,可能有很多解释。您显示的代码片段看起来像一个虚拟函数调用,通常仅以这种方式完成,以解决方法在派生类中被覆盖的可能性。

评论


感谢你的回答。一旦我知道目标函数,这将非常有帮助。我仍然不知道如何确定正在调用的函数。我将编辑问题以表明我对该部分更感兴趣。

–克拉克
13年5月28日在14:22

@clark尝试在指令上放置一个断点,然后运行,然后进入/手动计算与可用寄存器的偏移量?还是必须是静态的?

–马丁
16-10-26在22:41

#2 楼

诀窍是找到对象的构造函数。让我们假设代码看起来像这样:

a = new CFoo();
a->bar();


编译器(我假设是MSVC,32位)可能会产生以下内容:

push 12h ; size_t
call ??2@YXYXY@Z  ; operator new(uint)
mov [ebp+var_8], eax
mov esi, eax
test esi, esi
jz loc_1
  mov ecx, esi
  call ??0CFoo@@AAAA@AA ; CFoo::CFoo(void)
  mov [ebp+var_8], eax
  jmp loc_2
loc_1:
  mov [ebp+var_8], 0
loc_2:
...
...
...
mov eax, [ebp+var_8]
mov ecx, [eax]
mov ebx, ecx
mov ecx, [ebp+var_8]
call dword ptr [ebx+08h]


查看??0CFoo@@AAAA@AA,又称为CFoo::CFoo():

...
mov esi, ecx
mov dword ptr [esi], unk_12345
...


unk_12345CFoo的虚拟表偏移量: />
被称为sub_45678的是unk_12345+08h处的CFoo::bar()(在本例中为第3个条目)。