避免使用CALL读取RIP的shellcode中的0xFF字节? [英] Avoiding 0xFF bytes in shellcode using CALL to read RIP?

查看:104
本文介绍了避免使用CALL读取RIP的shellcode中的0xFF字节?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个解码器存根,并且遇到了对0xFF的限制,因为该字符是错误字符.我正在使用jmp-call-pop方法将编码的shellcode的地址保存到寄存器中.这是相关的代码段:

I'm trying to write a decoder stub and I'm running into a restriction on 0xFF as a bad character. I'm using the jmp-call-pop method to get the address of my encoded shellcode into a register. Here's the relevant snippet:

401012: e8 eb ff ff ff          call   0x401002

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

It seems like call will always use 0xFF in its bytes. Is there another instruction that, when executed, will push rip onto the stack and jump to another section of code? I've tried just pushing the address onto the stack manually, but that results in a null byte because my addresses are 3 bytes long and need to be padded.

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

Disallowed bytes in my machine code are:

  • 00
  • FF

推荐答案

call rel32是唯一的相对编码(间接或远距离jmp很少有用),因此,高字节当然总是00或FF,除非您将非常跳得很远,因为那是2的补码的工作原理.

call rel32 is the only relative encoding (and indirect or far jmp are rarely useful), so yes of course the high byte(s) will always be 00 or FF unless you're jumping very far away, because that's how 2's complement works.

自修改代码将是一种选择(但是,那么就遇到了获取代码指针的鸡肋/鸡蛋问题). 根据漏洞利用机制,您可能在RSP中有一个指向(接近)代码的指针.因此,您可能只是lea rax, [rsp+44]/push rax/jmp ...

Self-modifying code would be one option (but then you have a chicken/egg problem of getting a pointer to your code). Depending on the exploit mechanism, you might have a pointer to (near) your code in RSP. So you could maybe just lea rax, [rsp+44] / push rax / jmp ...

但是x86-64不需要jmp/call/pop惯用语.通常,您只需要对数据进行jmp,然后使用带有负rel32的RIP相对LEA,但是当然也将具有0xFF字节.

But x86-64 has no need for the jmp/call/pop idiom. Normally you can just jmp over your data and then use RIP-relative LEA with a negative rel32, but that will of course also have 0xFF bytes.

您可以将相对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进行反汇编的机器代码:

machine code from assembling with NASM and disassembling with 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码.尝试避免0xFF时,我不是故意选择'f':P但是无论如何,请选择您喜欢的4字节字符串.

Amusingly, 0x66 is the ASCII code for the letter 'f'. I didn't intentionally pick 'f' when trying to avoid 0xFF :P But anyway, choose whatever 4-byte string you like.

rel32的低字节会更高,具体取决于它必须达到的距离,因此请明智地选择.

The low byte of the rel32 will be higher depending on how far it has to reach, so choose wisely.

您可以使用以上相对于RIP的LEA + fixup技巧来创建自修改代码,例如inc byte [rax]0xFE转换为0xFF.或用0x11111111直接加上sub的双字或其他一些有用的方法来修复rel32

You can use the above RIP-relative LEA + fixup trick to create self-modifying code, e.g. inc byte [rax] to turn 0xFE into 0xFF. Or a dword sub-immediate with 0x11111111 or something could be useful to fixup a rel32

call r/m64

call r/m64 and jmp r/m64 are both unusable directly, because the opcodes themselves are FF /2 and FF /4

如果要返回,可能最容易修复call rel32call rax.但是也可以使用相对RIP的LEA来计算寄存器中的返回地址,然后将其推入,然后按jmp rel8jmp rax等.

If you want to return, it's probably easiest to fixup a call rel32 or call rax. But it would be possible to also use RIP-relative LEA to calculate a return address in a register and push it, then jmp rel8 or jmp rax or whatever.

这篇关于避免使用CALL读取RIP的shellcode中的0xFF字节?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆