当我按下某个函数(sub_xyz)上的X键(列出外部引用)以查看调用哪个函数时,我只看到dd offset sub_xyz两次,没有call sub_xyz指令。

没有其他地方写call sub_xyz

我怎么看哪个函数正在调用sub_xyz
这只是IDA感到困惑吗?

评论

您可以拍摄dd sub_xyz周围区域的屏幕截图,还是可以提供二进制文件?

那不可能。我需要在那里看什么?是反调试吗?

#1 楼

尽管Nirlzr的回答很好地说明了这一点,但以下示例考虑了C ++代码和vtable的存在。代码摘自此处
#include <iostream>
using namespace std;
class Vehicle {
public:
  virtual void ApplyBreaks() { cout << "Vehicle Break" << endl; }
  virtual void ApplyHorns() { cout << "Vehicle Horns" << endl; }
};

int main() {
  Vehicle *v = new Vehicle();
  v->ApplyBreaks(); // Calls vehicle ApplyBreak
  v->ApplyHorns();  // Calls vehicle ApplyHorn
}

使用g ++进行编译并在IDA中打开对ApplyBreaks的引用。

这在C ++应用程序中很常见,在vtables中具有函数引用。此外,在Vehicle中初始化此vtable时,已在对象中对其进行了设置,如您在此处看到的一样。

main中调用此类的成员函数时,地址的访问就像在编译时定义了偏移量的数组一样。

main+48处访问第一个(第0个)成员ApplyBreaks,并在main+71处访问ApplyHorns,该成员位于ApplyBreaks旁边。

评论


是的,VTables是一种很常见的情况,可能会发生。也许我应该更加关注这一点。好答案,+ 1 :)

– NirIzr
18年7月31日在18:08

#2 楼

如果没有其他引用,则表明没有call sub_xyz(至少IDA已标识)。相反,IDA仅标识了对sub_xyz的一个交叉引用,并且该引用是数据变量中的硬编码偏移量。

通常,有一段代码可以访问该数据并间接调用该函数,因此您可以搜索对该数据区域的交叉引用。您应该注意,该引用不必引用sub_xyz偏移它的位置。取而代之的是,sub_xyz的偏移量可以是更大的结构(或数组,或结构的数组)的一部分,可以列举出来。您需要搜索指向该区域周围的参考(这些参考也可以是地址较高的区域的偏移量,然后将其减去)。

让我们举个例子

假设在查找对sub_xyz的交叉引用时,您在下面描述的地址00008540上仅找到一个。

unk_00008538
    00008538    dd offset sub_foo
    0000853c    dd aFuncionFoo      ; "Function Foo"
    00008540    dd offset sub_xyz       <- our sub_xyz reference
    00008544    dd aFunctionXYZ     ; "Function XYZ"
    00008548    dd offset sub_abc
    0000854c    dd aFunctionABC     ; "Function ABC"


您会注意到dd offset sub_xyz上方(位于地址00008540)与另一个子例程sub_foo(位于00008538)有偏移,并且尽管没有对dd offset sub_xyz(在00008540处)的交叉引用,但有对dd offset sub_foo(在00008538处)的交叉引用。 >
您还可以注意到,在00008548处还有另一个子例程偏移量,并且在每个子例程偏移量之后还有另一个偏移量,即恰好在其中包含函数名称的字符串。这显然是一个相对简单的示例,我们可以假定它们实际上是一个结构的三个实例,每个实例都有两个成员,可以这样定义:

typedef struct FunctionDefinition
{
    void* func_addr;
    char* func_name;
} _FunctionDefinition;


我们可以还猜测我们发现了一个由FunctionDefinition结构的三个实例组成的数组,并且一些代码枚举了该数组并遍历所有函数。

更复杂的示例可以包括例如功能数组及其网络消息标识符,其中,例如,根据接收到的消息的类型来调度处理网络命令的功能。如果您正在使用C ++,甚至可能是函数虚拟表,也可以找到任何类的全局对象。选项是无止境的,您需要使用遇到的特定情况以及可以收集的其他信息(例如,引用该较大结构或数组的代码)来弄清楚。

评论


没有调用sub_xyz,我在外部参照中两次看到dd sub_xyz,所以您在sub_xyz区域中告诉seach外部参照,并期待在那里的呼叫?

– Keystone
18年7月30日在19:51

@Keystone我添加了一个示例,希望这可以帮助您更好地理解这一点。

– NirIzr
18年7月30日在20:30