调试PE

时间:2018-11-08 09:49:00

标签: windows debugging assembly x86

我目前正在Windows平台上以汇编形式编写一个小型调试器。

我按如下所示打开调试进程:

invoke    CreateProcess, addr buffer, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+DEBUG_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi

效果很好,我可以通过查看调试对象的上下文来获取EIP,这样我就可以获取将要执行的指令的第一个字节。

但是,我需要获取上一条指令中已执行的字节数。

指令与大小无关。有时一条指令只有1个字节,而另一些时候则是6个字节或更多。

我试图用当前的EIP减去先前的EIP,以获取已执行的字节数。但是,如果有一个jmp或一个呼叫,它将不起作用,因为地址空间不再相同。

我计划获取所有操作码的映射并进行一些cmp,但这似乎是一项艰巨的工作。

如果您有任何想法要获取已执行的上一条指令的字节数(可能正在查找缓存或类似内容),请告诉我。

最诚挚的问候

1 个答案:

答案 0 :(得分:2)

TL; DR

保持简单:单步执行,仅解码分支指令,并使用EIP - last EIP,除非最后一条指令是分支(在这种情况下,使用解码来查找长度)。
如果找到未知指令,请退后,不要提供其大小。


由于考虑到mov eax, 90909090h或类似的因素,x86编码不是对称的(地址增长),因此无法向后解码x86指令流。

因此,您在单步执行程序时就需要反汇编每条指令(无论如何调试器都需要这样做)并记录其大小。
控制传递指令明显少于指令总数,因此您可以仅解码该指令并使用EIP - EIP'(其中EIP'是最后一条指令的EIP)技巧,否则。

Intel处理器支持Last Branch Recording,但是它需要操作系统支持,并且无论如何您都需要对数据进行后处理,这似乎太麻烦了。
可以对英特尔处理器跟踪技术做出类似的论点。

我想不出任何性能计数器的事件(可以使用它们),这会导致指令的字节数。
实际上,在后端,“指令”的概念已简化为一系列uOP(可能有点说一个操作码是指令中的最后一个),并且前端大多与的架构价值脱钩。 eip(几乎总是以eip的推测值工作),因此它可能比后端要多条指令。
我相信每个uOP可能都有一个字段来记录如何在退休时更新eip,但没有一条指令的字节大小。
类似地,仅在预解码阶段,在前端中才记录一条指令长度(以字节为单位),此后我认为它已被丢弃(我想不起来有什么用)。

L1指令缓存中的指令尚未解码,因此,即使有一种方法可以检查其内容和元数据,也不会有任何内容。

完成此操作的通常方法是进行跟踪:单步执行程序,在eip处分解指令(见下文),记录其大小,恢复程序,重复直到停止。 br /> 这为您提供了地址和指令大小的列表。
如果您发现一条指令,则无法解码,或者不记录它的大小,或者尝试用某种试探法对其进行估算(其长度必须小于16B,并且理论上您可以将数据与来自PMC的计数进行整合,例如{ {1}})。

It's possible to detect the size of an instruction at runtime but that's totally not feasible in this context