使用CALL避免shellcode中的0xFF字节读取RIP?

问题描述 投票:1回答:1

我正在尝试编写一个解码器存根,而我正在对0xFF作为一个坏角色进行限制。我正在使用jmp-call-pop方法将我编码的shellcode的地址放入寄存器中。这是相关的片段:

401012: e8 eb ff ff ff          call   0x401002

似乎call将始终在其字节中使用0xFF。是否有另一条指令在执行时会将rip推入堆栈并跳转到另一部分代码?我尝试过手动将地址压入堆栈,但这导致空字节,因为我的地址长3个字节,需要填充。


我的机器代码中不允许的字节是:

  • 00
  • FF
assembly x86-64 shellcode machine-code
1个回答
4
投票

call rel32是唯一的相对编码(间接或远jmp很少有用),所以当然高字节总是00或FF,除非你跳得很远,因为这是2的补码是如何工作的。

自修改代码将是一个选项(但是你有一个鸡/蛋问题,获得指向你的代码的指针)。根据漏洞利用机制,您可能在RSP中有一个指向(接近)代码的指针。所以你可能只是lea rax, [rsp+44] / push rax / jmp ...

但是x86-64不需要jmp / call / pop习惯用法。通常你可以只对你的数据进行jmp,然后使用带有负rel32的RIP相对LEA,但那当然也会有0xFF字节。


您可以使用RIP相对LEA和安全rel32然后更正它:

    lea    rsi, [rel anchor + 0x66666666]      ; or  [RIP + 0x66666666]
    sub    rsi, 0x66666666
    ;...
    xor    eax,eax
    mov    al,1        ; __NR_write = 1  x86-64 Linux
    mov    edi, eax
    lea    edx, [rax-1 + msglen]
    syscall            ; write(1, msg, msglen)

    lea    eax, [rdi-1 + 60]       ; __NR_exit
    syscall            ; sys_exit(1)

anchor:
    msg: db     "Hello World", 0xa
    msglen equ $-msg

与NASM组装并与objdump -drwC -Mintel拆解的机器代码:

$ asm-link -dn rel.asm                   # a helper script to assmble+link and disassemble
+ nasm -felf64 -Worphan-labels rel.asm
+ ld -o rel rel.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000

rel:     file format elf64-x86-64


Disassembly of section .text:

0000000000401000 <anchor-0x1e>:
  401000:       48 8d 35 7d 66 66 66    lea    rsi,[rip+0x6666667d]        # 66a67684 <__bss_start+0x66665684>
  401007:       48 81 ee 66 66 66 66    sub    rsi,0x66666666
  40100e:       31 c0                   xor    eax,eax
  401010:       b0 01                   mov    al,0x1
  401012:       89 c7                   mov    edi,eax
  401014:       8d 50 0b                lea    edx,[rax+0xb]
  401017:       0f 05                   syscall 
  401019:       8d 47 3b                lea    eax,[rdi+0x3b]
  40101c:       0f 05                   syscall 

000000000040101e <anchor>:
  40101e:       48                      rex.W
   ... ASCII data that isn't real machine code
  401029:       0a                      .byte 0xa

peter@volta:/tmp$ ./rel 
Hello World

$ strace ./rel 
execve("./rel", ["./rel"], 0x7ffd09467720 /* 55 vars */) = 0
write(1, "Hello World\n", 12Hello World
)           = 12
exit(1)                                 = ?
+++ exited with 1 +++

有趣的是,0x66是字母'f'的ASCII码。我试图避免使用'f'时没有故意选择0xFF:P但是无论如何,选择你喜欢的任何4字节字符串。

rel32的低字节将取决于它必须达到多远,因此明智地选择。


Actually doing a call to somewhere nearby:

您可以使用上述RIP相对LEA + fixup技巧来创建自修改代码,例如inc byte [rax]0xFE变成0xFF。或者与sub或某事的dword 0x11111111-immediate可能对修复rel32有用

call r/m64jmp r/m64都无法直接使用,因为操作码本身就是FF /2FF /4

如果你想返回,最简单的方法是修复call rel32call rax。但是也可以使用RIP相对LEA来计算寄存器中的返回地址并将其推送,然后使用jmp rel8jmp rax等等。

© www.soinside.com 2019 - 2024. All rights reserved.