Начиная с из моего ответа о "реальной" точке входа исполняемого файла ELF в Linux и "сырых" системных вызовах, мы можем сократить ее до
bits 64
global _start
_start:
mov di,42 ; only the low byte of the exit code is kept,
; so we can use di instead of the full edi/rdi
xor eax,eax
mov al,60 ; shorter than mov eax,60
syscall ; perform the syscall
Я не думаю, что вы можете сделать его немного меньше, не выходя из спецификаций - в частности, psABI ничего не гарантирует о состоянии eax
. Он собирается точно до 10 байтов (в отличие от 7 байтов 32-битной полезной нагрузки):
66 bf 2a 00 31 c0 b0 3c 0f 05
Простой способ (собрать с nasm
, ссылка с ld
) дает мне исполняемый файл размером 352 байта.
Первое «настоящее» преобразование, которое он делает, - это построение ELF «вручную»; делать это (с некоторыми изменениями, так как заголовок ELF для x86_64 немного больше)
bits 64
org 0x08048000
ehdr: ; Elf64_Ehdr
db 0x7F, "ELF", 2, 1, 1, 0 ; e_ident
times 8 db 0
dw 2 ; e_type
dw 62 ; e_machine
dd 1 ; e_version
dq _start ; e_entry
dq phdr - $$ ; e_phoff
dq 0 ; e_shoff
dd 0 ; e_flags
dw ehdrsize ; e_ehsize
dw phdrsize ; e_phentsize
dw 1 ; e_phnum
dw 0 ; e_shentsize
dw 0 ; e_shnum
dw 0 ; e_shstrndx
ehdrsize equ $ - ehdr
phdr: ; Elf64_Phdr
dd 1 ; p_type
dd 5 ; p_flags
dq 0 ; p_offset
dq $$ ; p_vaddr
dq $$ ; p_paddr
dq filesize ; p_filesz
dq filesize ; p_memsz
dq 0x1000 ; p_align
phdrsize equ $ - phdr
_start:
mov di,42 ; only the low byte of the exit code is kept,
; so we can use di instead of the full edi/rdi
xor eax,eax
mov al,60 ; shorter than mov eax,60
syscall ; perform the syscall
filesize equ $ - $$
мы получаем 130 байтов. Это немного больше, чем исполняемый файл на 91 байт, но это происходит из-за того, что несколько полей становятся 64 битами вместо 32.
Затем мы можем применить некоторые трюки, похожие на его; частичное перекрытие phdr
и ehdr
может быть выполнено, хотя порядок полей в phdr
отличается, и мы должны перекрывать p_flags
с e_shnum
(что, однако, следует игнорировать из-за e_shentsize
будучи 0).
Переместить код внутри заголовка немного сложнее, так как он на 3 байта больше, но эта часть заголовка такая же большая, как и в 32-битном случае. Мы преодолеваем это, начав на 2 байта раньше, перезаписывая байт заполнения (хорошо) и поле версии ABI (не хорошо, но все еще работает).
Итак, мы достигаем:
bits 64
org 0x08048000
ehdr: ; Elf64_Ehdr
db 0x7F, "ELF", 2, 1, ; e_ident
_start:
mov di,42 ; only the low byte of the exit code is kept,
; so we can use di instead of the full edi/rdi
xor eax,eax
mov al,60 ; shorter than mov eax,60
syscall ; perform the syscall
dw 2 ; e_type
dw 62 ; e_machine
dd 1 ; e_version
dq _start ; e_entry
dq phdr - $$ ; e_phoff
dq 0 ; e_shoff
dd 0 ; e_flags
dw ehdrsize ; e_ehsize
dw phdrsize ; e_phentsize
phdr: ; Elf64_Phdr
dw 1 ; e_phnum p_type
dw 0 ; e_shentsize
dw 5 ; e_shnum p_flags
dw 0 ; e_shstrndx
ehdrsize equ $ - ehdr
dq 0 ; p_offset
dq $$ ; p_vaddr
dq $$ ; p_paddr
dq filesize ; p_filesz
dq filesize ; p_memsz
dq 0x1000 ; p_align
phdrsize equ $ - phdr
filesize equ $ - $$
длиной 112 байт.
Здесь я остановлюсь на данный момент, так как сейчас у меня не так много времени для этого. Теперь у вас есть базовый макет с соответствующими модификациями для 64-битной системы, поэтому вам просто нужно поэкспериментировать с более смелыми перекрытиями