assembly - 如何在没有 0x00 或 0xFF 字节的情况下获取 x86_64 中的指令指针?

标签 assembly x86-64 shellcode program-counter

有没有一种方法可以在不使用 call 后跟 pop 的情况下访问指令指针 (RIP) 中的值?或者是否有可以做到这一点的机器代码操作码?

我一直在谷歌搜索,没有明确的结果。

我的问题是机器代码中不能有任何零,否则我会收到 SIGSEGV 错误。这是由于服务器加载代码并从字节串执行它的方式。近调用在到子例程的距离中为零,因此使用调用不是一种选择。

我在 64 位 linux 上,有 nasm 和 yasm。

最佳答案

在 x86_64 中,标准方法是使用 RIP 相对寻址,而不是像在 x86 中那样使用 CALL。即使这样,call/pop 也不是推荐的方式1

通常你会使用 lea rax, [rip] 将 RIP 转化为 RAX(实际上编码为 lea rax, [rip + 0] 有四个字节对于最后的立即数)。然而,由于 LEA 不取消引用内存地址,您可以将任何常量位移添加到 RIP 并在以后减去它

0:  48 8d 05 04 03 02 01    lea    rax,[rip+0x1020304]
7:  48 2d 04 03 02 01       sub    rax,0x1020304

您可以选择任何没有零或 0xFF 字节的立即值。如果您想要 lea 之后的指令地址(7 个字节长),您可以使用 sub rax, 0x01020304 - 7

进行相应修复

1 The recommended way

GetCurrentAddress:
    mov eax, [esp]
    ret
...
    call GetCurrentAddress
    mov [currentInstruction], eax

为了避免调用栈和返回栈缓冲区(RSB)不匹配。但在 shellcode 中可能并不重要

关于assembly - 如何在没有 0x00 或 0xFF 字节的情况下获取 x86_64 中的指令指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52049481/

相关文章:

assembly - 将ffmpeg中的x86 asm和inline-asm编译成WebAssembly的问题

linux - "Segmentation fault",x86_64 程序集,AT&T 语法

x86 - 什么特别地将 x86 缓存行标记为脏 - 任何写入,还是需要显式更改?

c - 执行 shell 的 Shellcode 导致段错误

计算 C 中两个标签之间的代码大小(操作码字节数)

c# - WinAPI CreateThread 杀进程

c++ - 查找大于或等于给定值的最小幂的算法

Linux 使用堆栈上的字符串写入系统调用

程序集文件扩展名、.s79、.s82、s90、.asm、.s 等...它们有什么区别?

linux-kernel - 为什么 x86-64 Linux 内核源代码中的系统调用编号在 334 和 424 之间存在差距?