asm_execve.s:
.section .data file_to_run: .ascii "/bin/sh" .section .text .globl main main: pushl %ebp movl %esp, %ebp subl 0ドルx8, %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 0ドルx80 leave ret
makefile:
NAME = asm_execve $(NAME) : $(NAME).s gcc -o $(NAME) $(NAME).s
Program is executed, but sys_execve is not called:
alex@alex32:~/project$ make gcc -o asm_execve asm_execve.s alex@alex32:~/project$ ./asm_execve alex@alex32:~/project$
Expected output is:
alex@alex32:~/project$ ./asm_execve $ exit alex@alex32:~/project$
This Assembly program is supposed to work like the following C code:
char *data[2]; data[0] = "/bin/sh"; data[1] = NULL; execve(data[0], data, NULL);
Something wrong in system call parameters?
2 Answers 2
The execve system call is being called, but you are indeed passing it bad parameters.
(You can see this by running your executable using strace.)
There are three problems:
.asciidoes not 0-terminate the string. (You might get lucky, as there is nothing following it in your.datasection in this example, but that's not guaranteed...) Add a 0, or use.asciz(or.string) instead.movl file_to_run, %edimoves the value pointed to by thefile_to_runsymbol into%edi, i.e. the first 4 bytes of the string (0x6e69622f). The address of the string is just the value of the symbol itself, so you need to use the$prefix for literal values:movl $file_to_run, %edi. Similarly, you need to saymovl $file_to_run, %ebxa few lines further down. (This is a common source of confusion between AT&T syntax and Intel syntax!)The parameters are placed on the stack in the wrong order:
-0x8(%ebp)is a lower address than-0x4(%ebp). So the address of the command string should be written to-0x8(%ebp), the 0 should be written to-0x4(%ebp), and thelealinstruction should beleal -8(%ebp), %ecx.
Fixed code:
.section .data
file_to_run:
.asciz "/bin/sh"
.section .text
.globl main
main:
pushl %ebp
movl %esp, %ebp
subl 0ドルx8, %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 0ドルx80
leave
ret
3 Comments
argv or envp to actually be NULL (like you're doing for envp), so xor %ecx,%ecx ; xor %edx,%edx. An easier way to create argv[] on the stack would be mov $file_to_run, %ebx; push 0ドル (or a zeroed reg); push %ebx; mov %esp, %ecx.execve(2) man page documenting this is talking about C, where it is non-portable.You actually don't need to load anything in the other arguments. If you are doing this in x86 the following simpler code will also work:
.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 0ドルx80
leave
ret
This will essentially open a shell terminal after invoking the system call.
3 Comments
xor %ecx,%ecx to zero registers. Are you sure that passing non-zero garbage works? Anything other than 0 (or a valid pointer) should make the system call return -EFAULT. NULL pointers for argv and envp are specially documented as Linux-specific behaviour (man7.org/linux/man-pages/man2/execve.2.html), and being equivalent to passing a pointer to a NULL pointer. But that doesn't imply that other bad pointers will "work". That would actually be a bug in the implementation if it went and execed something instead of returning -EFAULT with non-0 bad pointers$file_to_run, otherwise you're just loading the first 4 bytes of the string and passing it as a pointer. Also, you save/restore ebp, but your code clobbers ebx. If you want to return safely instead of crashing when execve returns an error instead of execcing, you should push/pop ebx as well / instead of making a stack frame. (Perhaps the CRT code is ok if you clobber ebx though.) Optional improvements: your string can go in .rodata so you don't need a .data section. You can use .asciiz to get a zero-terminated string.
strace -e execveto trace the execve call your program actually makes.