Ошибка: мусор `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 в локацию. Обратитесь к полному синтаксису здесь.

https://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax

Другие вопросы по тегам