ELF-使用x86零扩展地址修补入口点

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

我已经设法修补了ELF文件的入口点,并使其指向其他位置,并在返回原始入口点之前执行了一段代码。以下是我尝试跳回到OEP的方式:

mov rax, 0x4141414141414141  ( 48 b8 41 41 41 41 41 41 41 41 )
jmp rax                      (ff e0)

我有一个包含这些操作码的数组,我在解析ELF标头以获取入口点后立即对其进行修补:

uint64_t oep = ehdr->e_entry;
memcpy(&opcode[23], &oep, 8);

但是入口点总是类似于:0x47fe8d,这使数组的其余部分无效,因为操作码期望的是8个字节的地址而没有零。我尝试通过符号扩展地址来代替它,例如:0xffffffff47fe8d,但是它不起作用。由于x86地址为zero-extended,因此这似乎是正常现象。

EDIT:shellcode数组看起来像这样:

 _start:
       xor rax, rax
       xor rax, rax
       xor rsi, rsi
       jmp get_str
 shellcode:
       pop rsi
       mov al, 1
       mov dil, 1
       mov dl, 9
       syscall ; writes a string

       mov rax, 0x4141414141414141 ; patched with the EP
       jmp rax
   get_str:
         call shellcode
         db "strings!", 0xa

 // write syscall + jmp OEP (mov rax, addr, jmp rax). patch at 23
unsigned char shellcode[] = "\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\xeb"
                  "\x16\x5e\xb0\x01\x40\xb7\x01\xb2\x09\x0f"
                  "\x05\x48\xb8\x41\x41\x41\x41\x41\x41\x41"
                  "\xff\xe0\xe8\xe5\xff\xff\xff\x68\x69\x6a"
                  "\x61\x63\x6b\x65\x64\x0a";

我制作了一个函数,该函数在修补该阵列之前将其打印出来。外观如下:

\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\xeb\x16\x5e\xb0\x01\x40\xb7\x01\xb2\x09\x0f\x05\x48\xb8\x41\x41\x41\x41\x41\x41\x41\xff\xe0\xe8\xe5\xff\xff\xff\x68\x69\x6a\x61\x63\x6b\x65\x64\x0a

但是用0x47fe8d修补jmp指令后,地址的高字节变为零:

\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\xeb\x16\x5e\xb0\x01\x40\xb7\x01\xb2\x09\x0f\x05\x48\xb8\x20\x1b\x40

并且由于某种原因导致分割错误。我使用IDA搜索修补文件的入口点,这就是我发现的内容:

LOAD:000000000047FE8D start:                                  ; DATA XREF: LOAD:0000000000400018↑o
LOAD:000000000047FE8D                 xor     rax, rax
LOAD:000000000047FE90                 xor     rdi, rdi
LOAD:000000000047FE93                 xor     rsi, rsi
LOAD:000000000047FE96
LOAD:000000000047FE96 loc_47FE96:                             ; CODE XREF: LOAD:000000000047FEAC↓j
LOAD:000000000047FE96                 jmp     short loc_47FEAE
LOAD:000000000047FE98 ; ---------------------------------------------------------------------------
LOAD:000000000047FE98                 pop     rsi
LOAD:000000000047FE99                 mov     al, 1
LOAD:000000000047FE9B                 mov     dil, 1
LOAD:000000000047FE9E                 mov     dl, 9
LOAD:000000000047FEA0                 syscall                 ; $!
LOAD:000000000047FEA2                 mov     rax, offset _start
LOAD:000000000047FEAC                 loopne  loc_47FE96
LOAD:000000000047FEAE
LOAD:000000000047FEAE loc_47FEAE:                             ; CODE XREF: LOAD:loc_47FE96↑j
LOAD:000000000047FEAE                 in      eax, 0FFh       ; $!
LOAD:000000000047FEAE ; ---------------------------------------------------------------------------
LOAD:000000000047FEB0                 dq 6B63616A6968FFFFh
LOAD:000000000047FEB8                 db 65h, 64h, 0Ah
LOAD:000000000047FEB8 LOAD            ends

因此,尽管IDA在000000000047FEAC]处错误地编码了指令,但似乎文件已被成功修补,_start符号仍会导致以下路径:

public _start
_start proc near
endbr64
xor     ebp, ebp
mov     r9, rdx         ; rtld_fini
pop     rsi             ; argc
mov     rdx, rsp        ; ubp_av
and     rsp, 0FFFFFFFFFFFFFFF0h
push    rax
push    rsp             ; stack_end
mov     r8, offset __libc_csu_fini ; fini
mov     rcx, offset __libc_csu_init ; init
mov     rdi, offset main ; main
db      67h
call    __libc_start_main
hlt
_start endp

这最终调用了原始的main函数,似乎一切正常。

进一步检查后,我发现000000000047FEAE]处的指令是罪魁祸首,尽管我不太清楚为什么。这是我用来将字符串的地址压入堆栈的call

指令。

为什么会出现细分错误?

我已经设法修补了ELF文件的入口点,并使其指向其他位置,并在返回原始入口点之前执行了一段代码。以下是我尝试跳的方式...

x86-64 elf shellcode
1个回答
0
投票

IDA没解码错,您的机器代码的十六进制字符串版本是错误的

;一个\x41字节短,因此mov r64, imm64消耗下一个FF字节作为其立即数的一部分,而不是jmp的操作码。这就是为什么它在0e e8 loopne`处解码。
© www.soinside.com 2019 - 2024. All rights reserved.