2012-02-18 142 views
3

asm_execve.s:sys_execve系統調用

 
.section .data 
file_to_run: 
.ascii  "/bin/sh" 

.section .text 
.globl main 

main: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $0x8, %esp   # array of two pointers. array[0] = file_to_run array[1] = 0 

    movl file_to_run, %edi 
    movl %edi, -0x4(%ebp) 
    movl $0, -0x8(%ebp) 

    movl $11, %eax      # sys_execve 
    movl file_to_run, %ebx    # file to execute  
    leal -4(%ebp), %ecx     # command line parameters 
    movl $0, %edx      # environment block 
    int $0x80    

    leave 
    ret 

生成文件:

 
NAME = asm_execve 
$(NAME) : $(NAME).s 
    gcc -o $(NAME) $(NAME).s 

程序被執行,但sys_execve不叫:

 
[email protected]:~/project$ make 
gcc -o asm_execve asm_execve.s 
[email protected]:~/project$ ./asm_execve 
[email protected]:~/project$ 

預期成果是:

 
[email protected]:~/project$ ./asm_execve 
$ exit 
[email protected]:~/project$ 

本屆大會的程序應該像下面的C代碼工作:

 
char *data[2]; 
data[0] = "/bin/sh"; 
data[1] = NULL; 
execve(data[0], data, NULL); 

一些錯誤的系統調用的參數?

+0

使用'strace -e execve'來跟蹤你的程序* exec *調用的execve調用。 – 2017-10-03 22:24:28

回答

8

execve系統調用被調用,但你的確在傳遞它壞的參數。

(您可以通過使用strace運行可執行文件看到這一點。)

有三個問題:

  1. .ascii沒有0結束的字符串。 (您可能會很幸運,因爲在本例中您的.data部分沒有任何內容,但不能保證......)添加0或使用.asciz(或.string)代替。

  2. movl file_to_run, %edi移動指向file_to_run符號到%edi值,即第一個4個字節串(0x6e69622f)的。該字符串的地址只是該符號本身的值,因此您需要使用$前綴的文字值:movl $file_to_run, %edi。同樣,你需要在下面說幾句movl $file_to_run, %ebx。 (這是AT & T語法和Intel語法之間的混淆的常見來源!)

  3. 的參數被放置在錯誤的順序在堆棧上:-0x8(%ebp)-0x4(%ebp)低位地址。所以命令字符串的地址應該寫入-0x8(%ebp),0應該寫入-0x4(%ebp),並且leal指令應該是leal -8(%ebp), %ecx


固定碼:

.section .data 
file_to_run: 
.asciz  "/bin/sh" 

.section .text 
.globl main 

main: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $0x8, %esp   # array of two pointers. array[0] = file_to_run array[1] = 0 

    movl $file_to_run, %edi 
    movl %edi, -0x8(%ebp) 
    movl $0, -0x4(%ebp) 

    movl $11, %eax      # sys_execve 
    movl $file_to_run, %ebx    # file to execute  
    leal -8(%ebp), %ecx     # command line parameters 
    movl $0, %edx      # environment block 
    int $0x80    

    leave 
    ret 
+0

作爲一個不可移植的擴展,Linux允許'argv'或'envp'實際*爲* NULL(就像你爲envp所做的那樣),所以'xor%ecx,%ecx'; 'xor%edx,%edx'。在堆棧上創建'argv []'的簡單方法是'mov $ file_to_run,%ebx'; '推$ 0'(或者一個歸零註冊表); 'push%ebx'; 'mov%esp,%ecx'。 – 2017-10-03 22:23:22

1

你其實並不需要在其他參數加載任何東西。如果你在86做這下面簡單的代碼也將工作:

.global _main 
.section .text 

.data 
file_to_run: 
.asciz "/bin/sh" 

.section .text 
.globl main 

_main: 
pushl %ebp 
movl %esp, %ebp 

movl $11, %eax      # sys_execve 
movl $file_to_run, %ebx    # file to execute  
movl $0, %ecx      # Null value will work too 
movl $0, %edx      # Null will works too 
int $0x80    

leave 
ret 

調用系統調用後,這將從根本上打開一個shell終端。

+0

您應該使用'xor%ecx,%ecx'來零寄存器。你確定通過非零垃圾的作品?除了'0'(或一個有效指針)以外的任何內容都應該使系統調用返回'-EFAULT'。 'argv'和'envp'的NULL指針被特別記錄爲特定於Linux的行爲(http://man7.org/linux/man-pages/man2/execve.2.html),相當於傳遞一個*指針給一個NULL指針。但這並不意味着其他壞指針會「起作用」。這實際上是實現中的一個錯誤,如果它發生並且發出某種東西而不是返回具有非0壞指針的'-EFAULT' – 2017-10-03 22:17:06

+0

是的,你是正確的。我很抱歉。我基本上是說,如果你想打開一個終端,你不需要提供任何具體的參數,如果你給出空值,它仍然可以工作。 – Shank 2017-10-03 23:53:06

+1

你確定你測試過嗎?你需要'$ file_to_run',否則你只是加載字符串的前4個字節並將它作爲指針傳遞。另外,你保存/恢復'ebp',但你的代碼破壞'ebx'。如果當'execve'返回錯誤而不是執行時,你想安全地返回而不是崩潰,你應該'push/pop' ebx /而不是堆棧幀。 (如果你打開ebx,CRT代碼也可以)。可選的改進:你的字符串可以放在'.rodata'中,所以你不需要'.data'部分。你可以使用'.asciiz'來獲得零終止的字符串。 – 2017-10-03 23:58:00