大會的x86(32位),調用NR_creat(8)會損壞文件名存儲大會的x86(32位),調用NR_creat(8)會損壞文件名存儲
一切,我已經把我的頭髮試圖確定如何爲文件名保留的存儲器被文件creat (NR_creat 8)
的調用破壞。彙編程序爲nasm
,代碼爲32位編譯並在x86_64
框中運行。該例程是一段簡單的代碼,它從程序參數argv[1]
獲取文件名,然後使用該名稱創建一個具有0644八進制權限的文件。將文件寫入,然後程序退出。文件操作起作用,問題是我在調用文件creat
時丟失了保存在fnbuf
中的文件名。
保留的存儲名爲fnbuf
的是32字節,在mov [fnbuf], ebx
的簡單操作中填入了argv[1]
。 fnbuf
中的信息正常,直到文件被創建,此後,fnbuf
中的信息被破壞,並且地址被更改。 (所有其他存儲的信息都很好)。爲了保留文件名,我最終將其推入堆棧(在創建文件後工作正常)我不明白爲什麼fnbuf
中的信息已損壞並需要幫助。
相關的代碼如下,以及簡要的gdb輸出(完整代碼在結尾後面)。
section .data
buflen equ 32
section .bss
fd_out resb 1
fd_in resb 1
fnbuf resb buflen
section .text
global _start
_start: ; linker entry point
; get the file_name from stdin (argv[1])
add esp, 8 ; skip over argc and argv[0] on stack (2 ptr = +8)
pop ebx ; pop argv[1] to ebx
test ebx, ebx ; test if null, jump
jz noarg ; (if pop to ecx, use jecxz - no test required)
mov [fnbuf], ebx ; save the filename in fnbuf (FIXME)
push ebx ; save on stack since fnbuf is getting whacked
; output fnbuf to stdout (fnbuf is fine here)
mov edi, [fnbuf] ; load string in edi for length calc & output
call strprn ; calc length and output to stdout
call newln ; output newline to stdout
; create the file (fnbuf is corrupted by this call)
mov eax, 8 ; system call number (sys_creat)
mov ebx, [fnbuf] ; set ebx to filename (fine here)
mov ecx, 0420 ; 644 octal -rw-r--r--
int 0x80 ; call kernel
jc errcf ; if carry flag non-zero, jmp errcf
mov [fd_out], eax ; save file descriptor in fd_out
; write msg to file
mov edi, msg ; msg address to edi for length
call strsz ; calc length of message to write (ret in edx)
mov eax, 4 ; system call number (sys_write)
mov ebx, [fd_out] ; file descriptor
mov ecx, msg ; message to write
int 0x80 ; call kernel
的代碼是建立與以下,並提供使用[fnbuf]
寫file creat
調用之前的文件名stdout
下面的輸出,但後來,必須從棧中彈出的保存argv[1]
輸出文件名以下file creat
。採用[fnbuf]
正常工作,以及:
nasm -f elf -o ./obj/filecwr_32.o filecwr_32.asm -g
ld -m elf_i386 -o ./bin/filecwr_32 ./obj/filecwr_32.o
$ ./bin/filecwr_32 newfile.txt
newfile.txt
File write complete.
newfile.txt
$ cat newfile.txt
To whom it may concern, this information was written to the file
通過與gdb
程序步進顯示了腐敗發生在內核調用爲file creat
:
gdb ./bin/filecwr_32
(gdb) set args newfile.txt
(gdb) break 1
Breakpoint 1 at 0x8048080: file filecwr_32.asm, line 1.
(gdb) run
(gdb) watch fnbuf
Hardware watchpoint 2: fnbuf
(gdb) step
Single stepping until exit from function strsz,
which has no line number information.
0x08048095 in strprn()
(gdb)
Single stepping until exit from function strprn,
which has no line number information.
newfile.txt0x080480f2 in _start()
(gdb) x/s fnbuf
0xffffd2fd: "newfile.txt"
(gdb) step
...
Hardware watchpoint 2: fnbuf
Old value = -11523
New value = -11776
0x08048120 in _start()
(gdb) x/s fnbuf
0xffffd200: "\376\336\377\377\023\337\377\377\036\337\377\377<\337\377\377\227\337\377\377"
...
[Inferior 1 (process 30000) exited normally]
(gdb) quit
看看上面的gdb
輸出,地址報道對於fnbuf
已更改?它最初是在0xffffd2fd
,但後來在0xffffd200
報告 - 大約253個字節。這令人困惑,我陷入困境。這幾乎就像是其中一個段地址在移動,但我希望剩下的信息也會被破壞。我的其他想法是,不知何故fnbuf
不是明確NUL-terminated
。我已將其設置爲NUL,問題和問題仍然存在。除此之外,我無法想象除x86_64問題上的x86執行異常之外的任何事情,但這看起來像是一個延伸。
完整的代碼清單:
section .data
msg db 'To whom it may concern, this information was written to the file', 0xa, 0
msg_done db 'File write complete.', 0xa, 0
msg_noarg db 'No argument available for filename.', 0xa, 0
msg_create_fail db 'File create failed.', 0xa, 0
buflen equ 32
nwln db 0xa
section .bss
fd_out resb 1
fd_in resb 1
flen resb 1
fnbuf resb buflen
section .text
global _start
; szstr computes the length of a string.
; edi - string address
; edx - contains string length (returned)
strsz:
xor ecx, ecx ; zero rcx
not ecx ; set rcx = -1 (uses bitwise id: ~x = -x-1)
xor al,al ; zero the al register (initialize to NUL)
cld ; clear the direction flag
repnz scasb ; get the string length (dec ecx through NUL)
not ecx ; rev all bits of negative -> absolute value
dec ecx ; -1 to skip the null-term, ecx contains length
mov edx, ecx ; size returned in edx, ready to call write
ret
; strprn writes a string to the file descriptor.
; edi - string address
; edx - contains string length
strprn:
push edi ; push string address onto stack
call strsz ; call strsz to get length
pop ecx ; pop string to ecx esi (source index)
mov eax, 0x4 ; write/stdout number in eax (sys_write 4)
mov ebx, 0x1 ; set destination index to ebx (stdout 1)
int 0x80 ; call kernel
ret
; newln writes a newline to the file descriptor.
newln:
mov ecx, nwln ; set string index in ecx
mov ebx, 0x1 ; set destination index to (stdout 1)
mov edx, 0x1 ; set length of string in edx
mov eax, 0x4 ; mov write syscall number (4) to eax
int 0x80 ; call kernel
ret
; error function for no argument
noarg:
mov edi, msg_noarg ; error msg to edi for length calc
call strprn ; calc length and output to stdout
jmp exit
; error on fail to create file
errcf:
mov edi, msg_create_fail ; error msg to edi for length calc
call strprn ; calc length and output to stdout
jmp exit
_start: ; linker entry point
; get the file_name from stdin (argv[1])
add esp, 8 ; skip over argc and argv[0] on stack (2 ptr = +8)
pop ebx ; pop argv[1] to ebx
test ebx, ebx ; test if null, jump
jz noarg ; (if pop to ecx, use jecxz - no test required)
mov [fnbuf], ebx ; save the filename in fnbuf (FIXME)
push ebx ; save on stack since fnbuf is getting whacked
; output fnbuf to stdout (fnbuf is fine here)
mov edi, [fnbuf] ; load string in edi for length calc & output
call strprn ; calc length and output to stdout
call newln ; output newline to stdout
; create the file (fnbuf is corrupted by this call)
mov eax, 8 ; system call number (sys_creat)
mov ebx, [fnbuf] ; set ebx to filename (fine here)
mov ecx, 0420 ; 644 octal -rw-r--r--
int 0x80 ; call kernel
jc errcf ; if carry flag non-zero, jmp errcf
mov [fd_out], eax ; save file descriptor in fd_out
; write msg to file
mov edi, msg ; msg address to edi for length
call strsz ; calc length of message to write (ret in edx)
mov eax, 4 ; system call number (sys_write)
mov ebx, [fd_out] ; file descriptor
mov ecx, msg ; message to write
int 0x80 ; call kernel
; close the file
mov eax, 6 ; set eax sys_close
mov ebx, [fd_out] ; file descriptor in ebx
int 0x80
; print write done to stdout
mov edi, msg_done ; msg_done in ecx
call strprn ; calc length and output to stdout
; print file name to stdout
; mov edi, [fnbuf] ; fnbuf corrupted? Segment smashed?
pop edi ; pop original filename from stack
push edi ; save another copy since fnbuf is messed up
call strprn ; calc length and output to stdout
call newln ; output newline
jmp exit
exit:
xor ebx, ebx ; set exit code to 0
mov eax,1 ; system call number (sys_exit)
int 0x80 ; call kernel
我在茫然,是什麼原因造成的fnbuf
腐敗。此外,單獨影響該地址的其他因素似乎可以按預期工作。任何幫助將不勝感激。
安德烈亞斯,謝謝。因此,爲了在'fnbuf'中存儲'argv [1]',我需要在'si'中使用'rep movsb'和''''中的'argv [1]'和'di'中的'fnbuf'。 – 2014-10-10 14:16:39
本質上是 - 不要忘記正確設置ECX和[方向標誌](http://stackoverflow.com/questions/10380076/direction-flag-in-x86) – 2014-10-10 18:53:14