在调用x86后,推送到堆栈的地址指向调用指令后的位置。该指令在x86机器上可以是可变长度的。有没有办法检测使用了哪种呼叫?
例如,间接调用*(%eax)是FF 10,但这也可能是直接调用0x10FF10FF的一部分。即。
12: ff 10 call *(%eax)
14: e8 fb 10 ff 10 call 10ff1114 <main+0x10ff1114>
E.g。如果我找到FF 10,那么在E8之前检查是否有3个字节 - 是否足够或没有?我还没有想到其他隐藏的陷阱?
答案 0 :(得分: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
,使其看起来像任何所需的模式。
答案 1 :(得分:2)
基本上,你不能。你也无法区分完成一个调用和在堆栈上推送一些地址然后进行跳转。你可以做出有根据的猜测,但除非你真的在某种模拟器中运行代码来完成一个完整的指令跟踪(记录),否则一些恶意代码总是可能欺骗你。