【发布时间】:2011-05-03 00:31:03
【问题描述】:
我想用汇编语言获取 EIP 寄存器的当前值。这可能吗?
【问题讨论】:
我想用汇编语言获取 EIP 寄存器的当前值。这可能吗?
【问题讨论】:
在 x86-64(相对于 32 位 x86)上,有 RIP-相对寻址(RIP 是 EIP 的 64 位类似物)。所以在 64 位代码中,你可以这样做
lea rax, [rip]
将RIP 的当前内容移动到RAX(您可以使用lea,但不能使用mov)。
【讨论】:
__asm{} 块中不起作用。 :( 获取error C2415: improper operand type 错误。
假设 32 位 x86,使用以下函数:
get_eip: mov eax, [esp]
ret
那么,要获取 EAX 中 EIP 的值,只需:
call get_eip
【讨论】:
call $+0 / ret / mov eax, [esp-4]
call $+0 是一个无限循环。 (直到您在尝试推送另一个返回地址时填满堆栈和段错误)。即使call $+5 / ret 也行不通;第一个ret 将返回到它自己,然后它会再次运行并将堆栈中的下一个东西弹出到EIP 中。此外,从 ESP 下方阅读也不安全;它可能已被信号处理程序或调试器异步破坏。 (或者在内核堆栈上,通过中断。)
call $+5 / pop eax 毫无疑问是最好的序列。但是 $+5 不能保证正确,它假定E9 CD 其中 CD 是 rel32 或 32 位位移。在 16 位模式下,它将是 E9 CW,其中 CW 是 rel16 或 16 位位移。但是,您错误地认为在堆栈指针下方读取是不安全的。我们谈论的是硬件,而不是操作系统的恶作剧。是的,实际上操作系统在进行任务切换时不会保留它,尽管可能有一些技巧可以保证它会。
call foo
foo:
pop eax ; address of foo
【讨论】:
call foo / foo: pop eax / add eax, bar-foo / push eax / ret / bar:
call next_insn 是特殊情况下不 破坏大多数 CPU 上的返回地址预测器堆栈:blog.stuffedcow.net/2018/04/ras-microbenchmarks/#call0 - 这只是硬壳旧的问题PPro(大概到 PIII)。所以这个答案很好。 Reading program counter directly