打印堆栈中的东西(组装)

Printing something in stack (assembly)

在linux中你可以使用系统调用号4打印一些东西:

mov eax,4       ;system call number
mov ebx,0       ;file descriptor
mov ecx,msg     ;adress of message in data segment
mov edx,length  ;length of message

但是,你如何从堆栈段打印一些东西?

我试过这个:

push 'H'
push 'e'
push 'l'
push 'l'
push 'o'
push ' '
push 'w'
push 'o'
push 'r'
push 'l'
push 'd'
mov eax,4       ;system call number
mov ebx,0       ;file descriptor
mov ecx,ebp     ;adress of message
mov edx,11      ;length of message

但不打印任何东西。

编辑: 我对我的代码做了一些修改,现在是这样:

section .data
msg: db "Hola mundo",0Ah
ok: db "OK",0Ah

section .text
global _start
_start:
push 'leH'
push 'w ol'
push 'dlro'
mov eax,4       ;system call number
mov ebx,1       ;file descriptor
mov ecx,esp     ;adress of message in data segment
mov edx,11      ;length of message
mov eax,1
xor ebx,ebx     ;same as move ebx,0 but better
int 0x80

编辑 2(仍然无效)

section .data
msg: db "Hello world",0Ah

section .text
global _start
_start:
push 'leH'
push 'w ol'
push 'dlro'
mov eax,4       ;system call number
mov ebx,1       ;file descriptor
mov ecx,esp     ;adress of message in data segment
mov edx,11      ;length of message
int 0x80
mov eax,1
xor ebx,ebx     ;same as move ebx,0 but better
int 0x80

回应评论,我assemble并编译:

nasm -f elf64 hello.asm && ld hello.o && ./a.out

我正在使用 Ubuntu 64 位 Linux。

这个问题本来就是缺少一个关键信息。您 assemble 和 link 与:

nasm -f elf64 hello.asm && ld hello.o && ./a.out

这将生成一个 64 位可执行文件。 int 0x80 不应在 64 位可执行文件中使用。在 64 位程序中,堆栈指针不能仅在 32 位 ESP 寄存器中表示。使用 64 位指针的唯一方法是使用 syscall 指令。 Ryan Chapman's blog 有关于通过 syscall 指令使用 64 位系统调用接口的很好的信息。

如果您修改代码以符合该接口,它可能类似于:

section .text
global _start
_start:
    mov dword [rsp-4], `rld\n`
                    ; Use back ticks instead of single quotes
                    ; To parse the string like C. We can write safely
                    ; in the 128 bytes below RSP because of the
                    ; Linux red zone.
    mov dword [rsp-8], 'o Wo'
    mov dword [rsp-12],'Hell'
    mov eax,1       ;Write system call number
    mov edi,eax     ;file descriptor (1 = stdout)
    lea rsi,[rsp-12];address of message on the stack
    mov edx,12      ;length of message
    syscall
    mov eax,60      ;Exit system call
    xor edi,edi     ;RDI=0
    syscall

此代码将常量写入 32 位寄存器,因为它们被零扩展到整个 64 位寄存器。我们不能压入 64 位立即值,但我们可以将字符串作为 32 位 DWORD 值直接写入堆栈。我们不需要调整 RSP 因为 Linux 有一个 128 字节的 red zone 可以防止被异步事件和信号破坏。

如果您想使用 C 样式的字符串,其中包含 C 转义字符,NASM 而不是单引号来区分。这允许您使用类似 \n 的字符作为表示换行符的字符。我提到这一点是因为您似乎想在已删除的问题中发布的一些代码中放置一个换行符。