2017-10-14 148 views
2

在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 

EDIT 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 

迴應的評論,我組裝和編譯:

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

我正在使用Ubuntu 64位Linux。

+0

'ebp'不是堆棧指針,'esp'是。此外,'push'將使用每個字符4個字節,這樣就不會起作用。 – Jester

+0

更不用說使用'push'會反轉你的字符串。 – Jester

+0

@Jester字符串的反轉是我想測試的東西 –

回答

2

這個問題最初缺少關鍵信息。您組裝和鏈接:

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

這會生成一個64位可執行文件。不應該在64位可執行文件中使用int 0x80。在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,它可以防止被異步事件和信號破壞。

如果你想在它使用ç風格的字符串與Ç轉義字符,NASMsupports backtick,而不是單引號做出區分。這使您可以使用類似\n的字符作爲表示新行字符的字符。我提到這一點,因爲看起來你想在你的問題中發佈的一些代碼中放置一個換行符,這些代碼已經被刪除。

+1

對於代碼密度,你可以實際上混合'push'和'mov',例如'推'地獄'/'mov dword [rsp + 4],'o Wo''。作爲獎勵,你最終將rsp指向你的字符串的前面,所以你只需要一個'mov'而不是'lea'。也是一種簡單的方法,在機器代碼中沒有字面0字節的情況下爲'execve'獲取以null結尾的字符串。但是,對於非常容易理解的非'push'示例,請+1! –