Ошибка: мусор `0x7f'после выражения при сборке с использованием Gas
Я пытаюсь написать 64-битный шелл-код для чтения файла с именем /proc/flag. Тем не менее, я получаю некоторые случайные ошибки при сборке сборки и не знаю, почему это происходит.
Это мой сборочный файл readflag.S
:
.intel_syntax noprefix
.global _start
.type _start, @function
_start:
mov dword [rsp], '/pro' /* build filename on stack */
mov dword [rsp+4], 'c/fl'
push 'ag'
pop rcx
mov [rsp+8], ecx
lea rdi, [rsp] /* rdi now points to filename '/proc/flag' */
xor rsi, rsi /* rsi contains O_RDONLY, the mode with which we'll open the file */
xor rax, rax
inc rax
inc rax /* syscall open = 2 */
syscall
mov rbx, rax /* filehandle of opened file */
lea rsi, [rsp] /* rsi is the buffer to which we'll read the file */
mov rdi, rbx /* rbx was the filehandle */
push byte 0x7f /* read 127 bytes. if we stay below this value, the generated opcode will not contain null bytes */
pop rdx
xor rax, rax /* syscall read = 0 */
syscall
lea rsi, [rsp] /* the contents of the file were on the stack */
xor rdi, rdi
inc rdi /* filehandle; stdout! */
mov rdx, rax /* sys_read() returns number of bytes read in rax, so we move it to rdx */
xor rax, rax
inc rax
syscall /* syscall write = 1 */
push byte 60 /* some bytes left... */
pop rax /* exit cleanly */
syscall
Вот ошибки, которые я получаю, когда собираю сборку:
readflag.S: Assembler messages:
readflag.S:7: Error: junk `pro10mov dword [rsp+4]' after expression
readflag.S:21: Error: junk `0x7f' after expression
readflag.S:33: Error: junk `60' after expression
objcopy: 'readflag.o': No such file
я думал push byte 60
считался действительной инструкцией в синтаксисе Intel. Я не уверен, откуда происходят ошибки. Буду признателен за любую помощь.
1 ответ
Когда вы указываете .intel_syntax noprefix
опцию, вы указываете ассемблеру Gnu, что вы будете использовать синтаксис MASM. То, что вы написали, на самом деле является синтаксисом NASM, который во многом похож на синтаксис MASM, но слегка отличается в других.
Для полного обсуждения различий см. Этот раздел руководства NASM.
Краткий обзор синтаксиса NASM и MASM приведен в этом документе.
(Этот второй документ раньше размещался в Интернете, в более удобочитаемом формате HTML, здесь, но ссылка вышла из строя, и я, к сожалению, не могу найти копию в Wayback Machine.)
Главное, что нужно изменить в вашем коде, это то, что вам нужно включить PTR
Директива после каждого спецификатора размера. Так, например, вместо:
mov dword [rsp], '/pro'
mov dword [rsp+4], 'c/fl'
вам нужно написать:
mov dword ptr [rsp], '/pro'
mov dword ptr [rsp+4], 'c/fl'
Кроме того, в то время как синтаксис MASM обычно записывает шестнадцатеричные константы с завершающим h
вместо ведущих 0x
Режим Gas MASM не поддерживает это, и вам нужно использовать стиль C 0x
нотации, даже при использовании синтаксиса Intel.
я думал
push byte 60
считался действительной инструкцией в синтаксисе Intel.
Нет, не совсем. Единственные значения размера, которые вы можете PUSH
а также POP
из стека - собственная ширина регистра процессора. Таким образом, в 32-разрядных двоичных файлах вы должны помещать и извлекать 32-разрядные значения, тогда как в 64-разрядных двоичных файлах необходимо вставлять и извлекать 64-разрядные значения. * Это означает, что эти строки кода технически неверны:
push 'ag'
push byte ptr 0x7f
push byte ptr 60
MASM выдаст вам предупреждение о недопустимом размере операнда для последних двух инструкций, для которых явно указан размер, но он неявно расширит эти константы до 64-битных значений и все же успешно соберется. Я предполагаю, что ассемблер Gnu может сделать это автоматическое расширение значения, так что вы должны просто удалить директиву size:
push 'ag'
push 0x7f
push 60
__
* Технически, вы можете использовать префикс переопределения размера операнда, чтобы вы могли сразу поместить 16-битный в стек как в 32-битном, так и в 64-битном режиме. Но вам действительно никогда не следует этого делать, потому что это приводит к смещению стека, что создает проблемы с производительностью (и, если вы взаимодействуете с кодом, скомпилированным на других языках, нарушает ABI). Вставляйте 16-битные значения в стек только при записи 16-битного кода. Если вы хотите выдвинуть 16-битное значение в 32-битном или 64-битном режиме, просто позвольте ассемблеру расширить его до 32-битного или 64-битного, соответственно.
Это неправильный синтаксис для ГАЗА. Вы должны использовать movl '/pro', [rsp] ALso, используйте **$**xx для перемещения фактического значения xx в локацию. Обратитесь к полному синтаксису здесь.