3

在 x86 上,调用后压入堆栈的地址指向调用指令之后的位置。该指令在 x86 机器上可以是可变长度的。有没有办法检测使用了哪种呼叫?

例如,间接调用 *(%eax) 是 FF 10,但这也可能是直接调用 0x10FF10FF 的一部分。IE

12: ff 10                   call   *(%eax)
14: e8 fb 10 ff 10          call   10ff1114 <main+0x10ff1114>

例如,如果我找到 FF 10,那么在 E8 之前检查 3 个字节是否足够?还有哪些我没有想到的隐藏陷阱?

4

2 回答 2

3

由于您的信息比平时多一些,因此不太可能。但我会准确地展示即使有额外的信息它仍然是不可能的。

额外的信息来自于知道它跳转到哪里,并且知道返回地址。如果差异与返回地址之前的 dword 不匹配,则它不是直接调用。所以这是你可以相对容易地找到的东西,而不必弄乱反向解码(这通常是不可能的,只有靠运气和启发式方法以及不是专门设计来克服它的代码,即使这样,跳跃也可能来了从任何地方的任何地方进入)。

但是,代码可能是这样的:

  push returnaddr
  mov eax, calladdr
  jmp eax ;or whatever way you like, showing a silly jump through reg for no reason
  ...
  call calladdr
returnaddr:

现在它无论如何都匹配,以一种你不可能检测到的方式。

所以你唯一能发现的是它是否绝对不是直接调用。您无法确定是否使用了任何特定方式 - 显然可以替换call calladdr上面代码段中的 以使其看起来像任何所需的模式。

于 2012-10-12T20:59:30.823 回答
2

基本上,你不能。您也无法区分进行调用和将某个地址压入堆栈然后进行跳转之间的区别。您可以做出有根据的猜测,但除非您实际上在某种仿真器中运行了代码,从而生成了完整的指令跟踪(记录),否则某些恶意代码总是有可能欺骗您。

于 2012-10-12T20:32:33.493 回答