2012-02-18 100 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