Assembly execve failure -14 - linux
Program writes executable placed in it's second segment on disk, decrypts it(into /tmp/decbd), and executes(as it was planned)
file decbd appears on disk, and can be executed via shell, last execve call return eax=-14, and after end of the program, execution flows on data and gets segfault.
http://pastebin.com/KywXTB0X
In second segment after compilation using hexdump and dd I manually placed echo binary encrypted via openssl, and when I stopped execution right before last int 0x80 command, I've already been able to run my "echo" in decbd, using another terminal.
You should have narrowed it down to a minimal example. See MCVE.
You should comment your code if you want other people to help.
You should learn to use the debugger and/or other tools.
For point #1, you could have gone down to:
section .text
global _start ;must be declared for linker (ld)
_start:
mov eax,11 ; execve syscall
mov ebx,program ; name of program
mov ecx,[esp+4] ; pointer to argument array
mov ebp,[esp] ; number of arguments
lea edx,[esp+4*ebp+2] ; pointer to environ array
int 0x80
section .data
program db '/bin/echo',0
For point #3, using the debugger you could have seen that:
ebx is okay
ebp is okay
ecx is wrong
edx is wrong
It's an easy fix. ecx should be loaded with the address, not the value and edx should be skipping 2 pointers which are 4 bytes each, so the offset should be 8 not 2. The fixed code could look like this:
section .text
global _start ;must be declared for linker (ld)
_start:
mov eax,11 ; execve syscall
mov ebx,program ; name of program
lea ecx,[esp+4] ; pointer to argument array
mov ebp,[esp] ; number of arguments
lea edx,[esp+4*ebp+8] ; pointer to environ array (skip argc and NULL)
int 0x80
section .data
program db '/bin/echo',0
man execve says this in the "ERRORS" section with regard to return code -14 (-EFAULT):
EFAULT filename points outside your accessible address space.
You passed a bad pointer to execve().
Related
NASM elf file size difference with uppercase and lowercase letters in section
I wrote a simple "Hello world" in assembly under debian linux: ; Define variables in the data section SECTION .data hello: db 'Hello world!',10 helloLen: equ $-hello ; Code goes in the text section SECTION .text GLOBAL _start _start: mov eax,4 ; 'write' system call = 4 mov ebx,1 ; file descriptor 1 = STDOUT mov ecx,hello ; string to write mov edx,helloLen ; length of string to write int 80h ; call the kernel ; Terminate program mov eax,1 ; 'exit' system call mov ebx,0 ; exit with error code 0 int 80h ; call the kernel After assembling nasm -f elf64 hello.asm -o hello.o ld -o hello hello.o. I got a 9048 byte binary. Then I changed two lines in the code: from .data to .DATA and .text to .TEXT: SECTION .DATA SECTION .TEXT and got a 4856 byte binary. Changing them to SECTION .dAtA SECTION .TeXt produced a 4856 byte binary too. NASM is declared to be a case-insensitive compiler. What is the difference then?
You're free to use whatever names you like for ELF sections, but if you don't use standard names, it becomes your responsibility to specify the section flags. (If you use standard names, you get to take advantage of default flag settings for those names.) Section names are case-sensitive, and .data and .text are known to NASM. .DATA, .dAta, etc. are not, and there is nothing which distinguishes these sections from each other, allowing ld to combine them into a single segment. That automatically makes your executable smaller. With the standard flags for .text and .data, one of those is read-only and the other is read-write, which means that they cannot be placed into the same memory page. In your example program, both sections are quite small, so they could fit in a single memory page. Thus, using non-standard names makes your executable one page smaller, but one of the sections will have incorrect writability.
NASM: Two subsequent file writes not working
Trying to run this code so I could create bmp file - I write headline, then I want to write content to file - everything works separately but not together. I'm using hexedit for checking file if it matters. If I run the code with headline writing part it works. If I run the code with content writing part it works. When I run both of them it doesn't. Any ideas? Here's the code: section .text global _start _start: ;####################################################################### ;### main ############################################################## ;####################################################################### ; open file mov eax,8 ;system call number - open/create file mov ebx,msg ;file name mov ecx,111111111b ;file mode int 0x80 ;call kernel ; save file descriptor to r8d mov r8d, eax ; write headline to file mov eax, 4 ;write 54 bytes to file mov ebx, r8d ;load file desc mov ecx, bmpheadline ;load adress of memory to write mov edx, 54 ;load number of bytes int 0x80 ;call kernel ; write content to file mov eax, 4 ;number of syscall - write mov ebx, r8d ;load file desc ;add ebx, 54 ;add 54 bytes to location of file location mov ecx, empty_space ;load adress of buffer mov edx, 40054 ;load number of bytes int 0x80 ;call kernel ; close file mov eax, 6 ;load syscall number - close mov ebx, r8d ;load file desc int 0x80 ;call kernel ; exit program mov eax,1 ;syscall number - exit int 0x80 ;call kernel section .data msg db 'filename.bmp',0x00 ;name of out file, 0x00 = end of string bmpheadline db 0x42,0x4D,0xB6,0xDA,0x01,0x00,0x00,0x00,0x00,0x00,0x7A,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0xC9,0x00,0x00,0x00,0xC9,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x3C,0xDA,0x01,0x00,0x13,0x0B,0x00,0x00,0x13,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x47,0x52,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 section .bss empty_space: resb 40054
There are 2 significant problems with your code. R8D (R8) is not preserved across int 0x80. Secondly, the add ebx, 54 in your original question is incorrect. You don't need to change the file descriptor. SYSCALL preferred for 64-bit code int 0x80 is an IA32 compatibility feature in the Linux kernel. This feature is generally turned on in most 64-bit Linux kernels but it can be turned off. You can't use 64-bit pointers with int 0x80. This prevents using stack based addresses as parameters to int 0x80. For these reasons it is preferred that you use SYSCALL for 64-bit programs rather than int 0x80. More on using SYSCALL in Linux can be found in Ryan Chapman's Blog . Note that the system call numbers used with SYSCALL are different from int 0x80. The registers used to pass parameters are different, and the only registers not preserved across a SYSCALL are RCX, R11, and RAX (RAX being the return value). The system calling convention is thoroughly described in the current 64-bit Linux System V ABI. In particular: User-level applications use as integer registers for passing the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9. The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9. A system-call is done via the syscall instruction. The kernel destroys registers %rcx and %r11. The number of the syscall has to be passed in register %rax. System-calls are limited to six arguments, no argument is passed directly on the stack. Returning from the syscall, register %rax contains the result of the system-call. A value in the range between -4095 and -1 indicates an error, it is -errno. Only values of class INTEGER or class MEMORY are passed to the kernel If you want your 64-bit code to work with INT 0x80 INT 0x80 has some quirks in 64-bit code. It adheres to the 32-bit calling convention of preserving RBX, RCX, RDX, RSI, RDI, and RBP. For the other 64-bit registers the 64-bit C calling convention applies. From the ABI: A.2.1 Calling Conventions ... applications that like to call system calls should use the functions from the C library. The interface between the C library and the Linux kernel is the same as for the user-level applications See Figure 3.4: Register Usage in the 64-bit Linux ABI linked to above. R12, R13, R14, and R15 will also be preserved. This means that RAX, R8, R9, R10, and R11 will not be preserved. Change your code from using R8D to one of the registers that are saved. R12D for example. Why does your code fail? Since R8D is not preserved across int 0x80 it is being potentially overwritten by the SYS_WRITE system calls. The first write works, the second one doesn't because R8D was likely trashed by the first SYS_WRITE, and R8D likely became an invalid file descriptor. Using one of the registers that will be preserved should solve this issue. If you run out of registers you can always allocate space on the stack for temporary storage.
You add 54 to the file descriptor without explanation; I have absolutely no clue why you are doing that. I suspect that you misunderstand file descriptors and believe that you need to add the total amount of data written so far to the descriptor. This is not so. The descriptor does not change from the time you open/create to the time that you close the file handle. It's a really good idea to verify that your comments are synced with your code. When you are writing detailed comments, lines with no comments become immediately suspect (the add instruction, for instance.) You appear to have some issues from the very beginning. For example, your comments say "open file" and "sys_write" but your code doesn't match. What your code currently does is attempt to call sys_creat. What you are calling the file descriptor is actually the permissions mode. ebx should contain the address of the string representing the path... The comments seem to indicate it should be stdout, but it's clearly not. :) You also don't state whether this is for 64 bit or 32 bit Linux. Your code seems to mix the two, using r8d and using int 0x80.
(Posted solution on behalf of the OP). Here is the source code of solution, 64 bit version: section .text global _start ;must be declared for linker (ld) _start: ;tell linker entry point ;####################################################################### ;### This program creates empty bmp file - 64 bit version ############## ;####################################################################### ;### main ############################################################## ;####################################################################### ; open file mov rax,85 ;system call number - open/create file mov rdi,msg ;file name ;flags mov rsi,111111111b ;mode syscall ;call kernel ; save file descriptor mov r8, rax ; write headline to file mov rax, 1 ;write to file mov rdi, r8 ;load file desc mov rsi, bmpheadline ;load adress of memory to write mov rdx, 54 ;load number of bytes syscall ;call kernel ; write content to file mov rax, 1 ;write to file mov rdi, r8 ;load file desc mov rsi, empty_space ;load adress of memory to write mov rdx, 40000 ;load number of bytes syscall ;call kernel ; close file mov rax, 3 ;load syscall number - close mov rdi, r8 ;load file desc syscall ;call kernel ; exit program mov rax,60 ;system call number (sys_exit) syscall ;call kernel section .data msg db 'filename.bmp',0x00 ;name of out file, 0x00 = end of string len equ $ - msg ;length of our dear string bmpheadline db 0x42,0x4D,0xB6,0xDA,0x01,0x00,0x00,0x00,0x00,0x00,0x7A,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0xC9,0x00,0x00,0x00,0xC9,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x3C,0xDA,0x01,0x00,0x13,0x0B,0x00,0x00,0x13,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x47,0x52,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 section .bss empty_space: resb 40000 Makefile: all: a.out a.out: main.o ld main.o main.o: main64.asm nasm -f elf64 main64.asm -o main.o
Code works when run from section .data, but segmentation faults in section .text
Why doesn't the following code give a segmentation fault? global _start section .data _start: mov ecx, 3 xor byte[_start+1], 0x02 mov eax, 1 mov ebx, 2 int 80h I expected it to segfault at the same place (line marked with a comment) as when the same code is run in the .text section: global _start section .text ; changed from data to text _start: mov ecx, 3 xor byte[_start+1], 0x02 ; ******get segmentation fault here mov eax, 1 mov ebx, 2 int 80h Now, I know that section .data is for read-write, and section .text is for read only. But why would it matter when I try to access illegal memory address? For the example here, I expected to get segmentation fault also at section .data, in the same place that I got it in section .text.
[_start+1] is clearly not an illegal address. It's part of the 5 bytes encoding mov ecx, 3. (look at objdump -Mintel -drw a.out to see disassembly with the hex machine code). IDK why you think there would be a problem writing to an address in .data where you've defined the contents. It's more common to use pseudo-instructions like db to assemble bytes into the data section, but assemblers will happily assemble instructions or db into bytes anywhere you put them. The crash you'd expect from the .data version is from _start being mapped without execute permission but thanks to surprising defaults in the toolchain, programs with asm source files often end up with read-implies-exec (like gcc -zexecstack) unless you take precautions to avoid that: Why data and stack segments are executable? Unexpected exec permission from mmap when assembly files included in the project If you applied that section .note.GNU-stack noalloc noexec nowrite progbits change, code fetch from RIP=_start would fault. The version that tries to write to the .text section of course segfaults because it's mapped read-only.
Linux Assembly x86_64 create a file using command line parameters
I'm trying to teach myself assembly. I've found a good website; however, everything is written for x86 and I use a 64-bit machine. I know what the problem is, but I don't know how to fix it. If I run the program with strace, then here is the results: execve("./file", ["./file", "hello"], [/* 94 vars */]) = 0 creat(NULL, 0) = -1 EINVAL (Invalid argument) write(0, NULL, 0 <unfinished ...> +++ exited with 234 +++ So, I know that when I call creat, that the file name "hello" is not being passed and as a result I don't have a file descriptor. Here is the code in question: section .text global _start _start: pop rbx ; argc pop rbx ; prog name pop rbx ; the file name mov eax,85 ; syscall number for creat() mov ecx,00644Q ; rw,r,r int 80h ; call the kernel I know that I can use the syscall command; however, I want to use interrupt. Any ideas or suggestions would be helpful. Also, I'm using nasm an assembler.
You attempted to use the 32 bit mechanism. If you have a 32 bit tutorial, you can of course create 32 bit programs and those will work as-is in compatibility mode. If you want to write 64 bit code however, you will need to use the 64 bit conventions and interfaces. Here, that means the syscall instruction with the appropriate registers: global _start _start: mov eax,85 ; syscall number for creat() mov rdi,[rsp+16] ; argv[1], the file name mov esi,00644Q ; rw,r,r syscall ; call the kernel xor edi, edi ; exit code 0 mov eax, 60 ; syscall number for exit() syscall See also the x86-64 sysv abi on wikipedia or the abi pdf for more details.
How to create a file in Linux assembly
I have the following code: section .text global _start ;must be declared for using gcc _start: ;tell linker entry point mov ecx, 2 ;read-write perms mov ebx, name ;name of file mov eax, 8 ;system call number (sys_creat) int 0x80 ;call kernel mov eax, 1 ;system call number (sys_exit) int 0x80 ;call kernel section .data name db 'C:\\test.txt',0xa It is meant to create a file (test.txt) in the C drive however doesn't work, what is the correct way to do this?
First, syscall=8 is sys_creat, not write. But the easiest way to find out what is happening is looking at the strace output of the program. There you can see if the syscall succeeded, and if not, what is the error value. (errno) Afaik creat(2) is not used anymore, and Open(2) with O_CREAT in the second argument is used nowadays.