asm_execve.s:
.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
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?
System calls enable users to request a service from the operating system (OS). To execute a system call , the execution of the process is halted, and the execution of the system call starts in kernel mode. This switch from user mode to kernel mode may incur a short delay.
The specific system call being invoked is stored in the EAX register, abd its arguments are held in the other processor registers.
Execve() function is used for the execution of the program that is referred to by pathname. The exec family is used mainly in the C programming language and has many functions. These functions execute a system command in a separate process from the main program and print the output.
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:
.ascii
does not 0-terminate the string. (You might get lucky, as there is nothing following it in your .data
section in this example, but that's not guaranteed...) Add a 0, or use .asciz
(or .string
) instead.
movl file_to_run, %edi
moves the value pointed to by the file_to_run
symbol 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 say movl $file_to_run, %ebx
a 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 the leal
instruction should be leal -8(%ebp), %ecx
.
Fixed code:
.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
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 $0x80
leave
ret
This will essentially open a shell terminal after invoking the system call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With