我已经在C代码中实现了内存读取访问硬件断点。
它可以完美工作并在读取内存后为我提供下一条指令。

我正在使用BeaEngine在EIP上反汇编指令。

我需要找出前一条已执行的指令,该指令实际上是访问有问题的内存的指令(例如,像作弊引擎一样)。

如何我做到了吗?

#1 楼

这是一个棘手的问题。

在x86平台上,一条指令的最大长度为15个字节。

您可以从当前EIP向后读取15个字节,并将其传递给BeaEngine的Disasm函数。这将返回反汇编指令的长度。如果等于15,您已经找到上一条指令。如果小于15,则少传递1个字节(即14个字节),依此类推,直到传递给BeaEngine的缓冲区的长度等于反汇编指令的长度。

可以表示为伪代码

eip = 0xDEADCODE

length = 15
while(length > 0)
{
    buffer = ReadProcessMemory(start=eip-length, length)
    lenDisasm = Disasm(buffer)

    if (lenDisasm == length) 
    {
        prevIns = eip-length
        break;
    }
    else length--;
}


请注意,上述算法本质上不是通用的,即,在给定当前eip的情况下,您不能使用它来查找先前执行的指令。仅当执行序列是线性的且之间没有任何跳跃时,这才起作用。如果在访问时发生硬件断点,则执行顺序保证是线性的,并且上述算法适用。

编辑:序列在以下情况下可能不是线性的

format PE

entry start

section '.text' code readable executable

start:
    nop
    nop
    jmp dword [here]
    mov eax, 1
    push eax
    pop eax

address:
    xor eax, eax
    ret     

section '.data' readable writable

here:   ; <<<<<<<< HWBP on read
 dd address


here设置了读取时的硬件断点。在这种情况下,当EIP位于address时,hwbp将达到。如果使用上述算法,则先前执行的指令将变成pop eax,这是不正确的。
在这种情况下,可以使用指令跟踪或内存断点(1、2、3)。

评论


很有道理,非常感谢您的解释!

– fred26
16 Mar 26 '16 at 12:09

即使执行顺序是线性的,您也可能找不到期望的结果。考虑32位反汇编8B 8B 05 78 56 3412。然后考虑8B 05 78 56 34 12.根据寄存器值,它们中的任何一个都是正确的。消除歧义实际上是不可能的。

–彼得·弗里
16 Mar 28 '16 at 16:08