2

我正在尝试编写一个 64 位 shellcode 来读取一个名为“/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被认为是英特尔语法中的有效指令。我不确定错误来自哪里。将不胜感激任何帮助。

4

2 回答 2

4

当您指定该.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被认为是英特尔语法中的有效指令。

不,不是。您可以从堆栈中获取的唯一大小值是处理器的本机寄存器宽度PUSHPOP因此,在 32 位二进制文​​件中,您必须推送和弹出 32 位值,而在 64 位二进制文​​件中,您必须推送和弹出 64 位值。*这意味着这些代码行在技术上是错误的:

push    'ag'
push    byte ptr 0x7f
push    byte ptr 60

MASM 会给你一个关于后两条指令的无效操作数大小的警告,这些指令有一个明确指定的大小,但它会隐式地将这些常量扩展为 64 位值并且仍然可以成功汇编。我假设 Gnu 汇编器也可以执行此自动值扩展,因此您应该删除 size 指令:

push    'ag'
push    0x7f
push    60

__
*从技术上讲,您可以使用操作数大小覆盖前缀来允许您在 32 位和 64 位模式下将 16 位立即数压入堆栈。但是你真的不应该这样做,因为它会使堆栈错位,产生性能问题(并且,如果你正在与用其他语言编译的代码进行互操作,则会破坏 ABI)。编写 16 位代码时,仅将 16 位值压入堆栈。如果您想在 32 位或 64 位模式下推送 16 位值,只需让汇编程序将其相应地扩展为 32 位或 64 位。

于 2017-06-22T07:09:41.083 回答
-1

这是 GAS 的错误语法。您必须使用 movl '/pro', [rsp] ALso,使用 **$**xx 将实际值 xx 移动到一个位置。请参阅此处的完整语法。

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

于 2019-02-12T00:42:55.513 回答