So i need to recursievly delete files in a directory using x86_64 assembly.
here is my code and i know it is bad. My problem is that every syscall works individualy(i can individualy delete directories or documents) , But as soon as i merge them together like this, it doesn't work . #edit: as pointed by #fuz, the question was not descriptive enough. so i want it do open directory that contains file called "test.txt", delete that file, and then to delete the directory that contained the file. But it just exits the program when i compile it with nasm. I am using Linux mint
global _start
section .text
_start:
;open directory
mov rax, 2 ;sys_open
mov rdi, dir ;pointer to the directory
mov rsi, 0 ;read only
syscall
;delete document
mov rax, 87 ;sys_unlink
mov rdi, doc ;points to the document
syscall
;delete directory
mov rax, 84 ;sys_rmdir
mov rdi, dir
syscall
_exit:
mov rax, 60
mov rdi, 80
syscall
section .data
dir: db 'test',0
doc: db 'test.txt',0
Your problem is not with assembly, it's with understanding basic POSIX / Unix file manipulation system calls. open("dir") does not make later unlink / rmdir system calls relative to that directory, they're still relative to your current working directory. You can change that with chdir().
(And that's easier to do with C than with asm. For most system calls, the glibc wrapper is trivial and passes on all the args unchanged to the kernel. When that's not the case, the NOTES section of the Linux man page documents that.)
There are system calls that do things relative to an open directory file descriptor (instead of the CWD), whose names add an ...at suffix to the traditional system-call names. The documentation uses C syntax to describe the system calls, but given the ABI this tells you how to call them in asm.
unlinkat(int dirfd, const char *pathname, int flags)
fd-relative rmdir is actually done with unlinkat(fd, path, AT_REMOVEDIR). (Otherwise, with flags=0, unlinkat behaves like regular unlink).
linkat, symlinkat, readlinkat, statat, mkdirat, execveat, ...
various others, including renameat, and a fun renameat2 that takes flags allowing you to atomically swap two pathnames on the same filesystem.
The notes section of the openat man page explains why these at system calls exist in the first place, under Rationale for openat() - avoids race conditions between readdir and open if someone else renames a directory component of the path. And since chdir() is per-process, not per-thread, allows different threads to do relative stuff in different directories at the same time.
Like Jester said, use strace find test -name 'test.txt' -delete or something like that to see how to actually recurse through directories with open(O_DIRECTORY), getdents, and unlinkat.
getdents is the raw system call that the POSIX readdir interface is built on top of, on Linux. The man pages document this. In asm, you can either use libc function calls to readdir, or you'd have to use getdents yourself.
Or since you aren't actually recursing, just hard-coding some relative paths, you could just make unlink("test/test.txt") and rmdir("test") system calls.
Related
I'm getting a weird error message when trying to assemble and run a .s file using AT&T Intel Syntax. Not sure if I'm even using the correct architecture to begin with, or if I'm having syntax errors, if I'm not using the correct commands to assemble and link, etc. Completely lost and I do not know where to begin.
So basically, I have a file called yea.s , which contains some simple assembler instructions. I then try to compile it using the command as yea.s -o yea.o and then link is using ld yea.o -o yea. When running ld, I get this weird message:ld: warning: cannot find entry symbol _start; defaulting to 000000440000.
This is the program im trying to run, very simple and doesn't really do anything.
resMsg: .asciz "xxxxxxxx"
.text
.global main
main:
pushq $0
ret
I just cannot figure out what's going on. Obviously, this is for school homework. I'm not looking for the answer to the homework, obviously, but this is the starting point to where I can actually start the coding. And I just cant figure out how to simple run the program, which it doesn't say in the assignment. Anyway, thanks in advance guys!
Linux executables require an entry point to be specified. The entry point is the address of the first instruction to be executed in your program. If not specified otherwise, the link editor looks for a symbol named _start to use as an entry point. Your program does not contain such a symbol, thus the linker complains and picks the beginning of the .text section as the entry point. To fix this problem, rename main to _start.
Note further that unlike on DOS, there is nothing to return to from _start. So your attempt to return is going to cause a crash. Instead, call the system call sys_exit to exit the program:
mov $0, %edi # exit status
mov $60, %eax # system call number
syscall # perform exit call
Alternatively, if you want to use the C runtime environment and call functions from the C library, leave your program as is and instead assemble and link using the C compiler driver cc:
cc -o yea yea.s
If you do so, the C runtime environment provides the entry point for you and eventually tries to call a function main which is where your code comes in. This approach is required if you want to call functions from the C library. If you do it this way, make sure that main follows the SysV ABI (calling convention).
Note that even then your code is incorrect. The return value of a function is given in the eax (resp. rax) register and not pushed on the stack. To return zero from main, write
mov $0, %eax # exit status
ret # return from function
In all currently supported versions of Ubuntu open the terminal and type:
sudo apt install as31 nasm
as31: Intel 8031/8051 assembler
This is a fast, simple, easy to use Intel 8031/8051 assembler.
nasm: General-purpose x86 assembler
Netwide Assembler. NASM will currently output flat-form binary files, a.out, COFF and ELF Unix object files, and Microsoft 16-bit DOS and Win32 object files.
If you are using NASM in Ubuntu 18.04, the commands to compile and run an .asm file named example.asm are:
nasm -f elf64 example.asm # assemble the program
ld -s -o example example.o # link the object file nasm produced into an executable file
./example # example is an executable file
I am trying to read the contents of a file using x86 assembly on Linux. The question is, what we should put into edx - the "permissions" register for sys_open.
I've used open() of C before; but there wasn't any "permissions" field. I am trying to read a file belongs to the same owner of the executable. The file's permissions are set to 0400 (-r--------). I've tried opening the file with edx: empty (0), 0666 and 0400. All of them returns "-13" to eax which seems to be EACCES.
Sample code:
mov eax, 0x5; //sys_open
push 0x6362612f //file name in hex, let's say "/abc"
mov ebx, esp; //filename to ebx
xor ecx, ecx; //O_RDONLY
mov edx, 0666o; //permissions in octal for nasm
int 0x80; //call it
What should edx to be to open a file, in general (or in this read-only case)? File's current permissions, an empty, an arbitrary?
Thanks!
man 2 open:
if neither O_CREAT nor O_TMPFILE is specified, then mode is ignored.
As such it doesn't matter what you put in edx if you are opening an existing file for reading. The cause of your problems is something else.
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().
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm trying to write an assembly program for Linux assembly x86 that erases a file from a directory. Any tips?
maybe something like this:
.section .data
fpath:
.asciz "/home/user/filename" # path to file to delete
.section .text
.globl _start
_start:
movl $10, %eax # unlink syscall
movl $fpath, %ebx # path to file to delete
int $0x80
movl %eax, %ebx # put syscall ret value in ebx
movl $1, %eax # exit syscall
int $0x80
then check the return value at the command line, 0 being success.
$>echo $?
I tried this code and it would not unlink a file if invoked from the same
directory as the file to delete, it would unlink files from other dirs.
This is 32 bit code so on a 64 bit os if your source file was un-link.s,
you would need to create the executable with:
$> as --32 -gdwarf2 un-link.s -o un-link.o
leave out the -gdwarf2 if you don't need to run it with gdb debugger,
then link with:
$> ld -m elf_i386 un-link.o -o un-link
hope it works for you
I see alot of people using int 0x80 for this, this is deprecated and for most things, you should not use it because it is extremely slow and is subject to possible removal at any point in future. The only cases where you should use int 0x80 would be in a case where space saving is much more important than speed or where sysenter is not supported on the target platform (pre-Pentium 4 CPUs).
In x86 Linux syscalls work by having the syscall code in eax and any arguments for it in the successive registers, ebx, ecx etc. The return value of the syscall will be placed in eax.
mov eax, 0xa ;0xa is the 'unlink' syscall, which removes a file
mov ebx, <location in memory of a null terminated string containing a path>
push <LABEL TO JUMP TO AFTER SYSENTER IS COMPLETE>
push ecx
push edx
push ebp
mov ebp, esp
sysenter
If you don't care about your registers being filled with garbage after the syscall finishes (such as in cases where you'll be overwriting the contents of those registers immediately anyway) you can use this trick to save some space and speed things up a little:
mov eax, 0xa ;0xa is the 'unlink' syscall, which removes a file
mov ebx, <location in memory of a null terminated string containing a path>
push <LABEL TO JUMP TO AFTER SYSENTER IS COMPLETE>
lea ebp, [esp-12]
sysenter
If you want to write assembly code that erases a file from a directory, you can use multiple methods, but one of the best ways is to use the linux systemcall 'unlink'. In order to have to use the proper system call, you have to figure out if you have an x86 system, or an x86-64 system, or any other kind of system. I will specify how to do this using only x86/x86-64.
So system calls work as following in linux:
1.
You put a number into return register (eax or rax depending on system) that corresponds to a system call's number, like $1 is sys_exit on x86 and $29 is sys_pause, you have to make sure you get the right number in %eax or it won't work. (I feel the need to emphasize this, this number is SYSTEM DEPENDENT, so an x86 syscall number in %eax will not do the same thing in an x86-64 system). Also, OS's may tamper with this as well, I will only talk about linux, I can't speak for any other OS.
2.
Then you move the arguments into the proper registers that is specified BY THE SYSTEM, again, find a reference for your specific system, and you will know which registers to put your arguments for the function into (some syscalls don't need arguments, so this step is unnecessary, why would you need an argument for sys_exit, idk).
3.
Then finally you use syscall for your system to let the system know to run a specific function (the one you specified by putting a number into %eax/%rax).
Let's look at an example of some assembly code that deletes a file in two different systems, x86, and x86-64 (windows has its own method, but I will not talk about that one, although it does exist). If I wanted to delete/unlink the file stored at address 0x7fff50 (let's say you don't want to specify fpath and you know the address)
In x86:
movl $10, %eax # defines which systemcall we are using (10th)
movl $0x7fff50, %ebx # moves the address of file we want to delete into %ebx (this is where the argument of sys_unlink(x86) is stored)
int $0x80 # equivalent of syscall that starts the appropriate function
In x86-64:
movq $87, %rax # defines which systemcall we are using (87th)
movq $0x7fff50, %rdi # moves the address of file we want to delete into %rdi (this is where the argument of sys_unlink(x86-64) is stored)
syscall # starts the appropriate function
If you are more of a normal person and don't know the absolute address of the file you are trying to delete, we have an easy way to write relative addresses of the file itself, like so (as copied from the other answer)
.section .data
fpath:
.asciz "/home/user/filename" # path to file to delete
then the system itself will figure out where the absolute path (something like 7fff34fb) to the file is, and move that into the register when you compile the assembly. Might look like this
In x86-64:
.section .data
fpath:
.asciz "/home/user/filename" # path to file to delete
.section .text
.globl _start
_start:
movq $87, %rax # defines which systemcall we are using (87th)
movq $fpath, %rdi # moves the address of file we want to delete into %rdi
# (this is where the argument of sys_unlink(x86-64) is stored)
syscall # starts the appropriate function
You can access the output of the function (usually 0 for success or 1 for fail status) by looking at the %eax register. After each syscall, an integer is returned in %eax
You can put this text into a text file 'program.s' (I would suggest using notepad/notepad++, '.s' stands for assembly code) and compile it using gcc with $ gcc -c program.s to get the object code, and you can print and look at the object code and the hex keys involved with each command using $ objdump -d program.o
For more information about how to look up which syscall is which number and which register to put the arguements in, go here:
For x86-64: https://filippo.io/linux-syscall-table/
section .text
global _start
_start:
nop
main:
mov eax, 1
mov ebx, 2
xor eax, eax
ret
I compile with these commands:
nasm -f elf main.asm
ld -melf_i386 -o main main.o
When I run the code, Linux throw a segmentation fault error
(I am using Linux Mint Nadia 64 bits). Why this error is produced?
Because ret is NOT the proper way to exit a program in Linux, Windows, or Mac!!!!
_start is not a function, there is no return address on the stack because there is no user-space caller to return to. Execution in user-space started here (in a static executable), at the process entry point. (Or with dynamic linking, it jumped here after the dynamic linker finished, but same result).
On Linux / OS X, the stack pointer is pointing at argc on entry to _start (see the i386 or x86-64 System V ABI doc for more details on the process startup environment); the kernel puts command line args into user-space stack memory before starting user-space. (So if you do try to ret, EIP/RIP = argc = a small integer, not a valid address. If your debugger shows a fault at address 0x00000001 or something, that's why.)
For Windows it is ExitProcess and Linux is is system call -
int 80H using sys_exit, for x86 or using syscall using 60 for 64-bit or a call to exit from the C Library if you are linking to it.
32-bit Linux (i386)
%define SYS_exit 1 ; call number __NR_exit from <asm/unistd_32.h>
mov eax, SYS_exit ; use the NASM macro we defined earlier
xor ebx, ebx ; ebx = 0 exit status
int 80H ; _exit(0)
64-bit Linux (amd64)
mov rax, 60 ; SYS_exit aka __NR_exit from asm/unistd_64.h
xor rdi, rdi ; edi = 0 first arg to 64-bit system calls
syscall ; _exit(0)
(In GAS you can actually #include <sys/syscall.h> or <asm/unistd.h> to get the right numbers for the mode you're assembling a .S for, but NASM can't easily use the C preprocessor.
See Polygot include file for nasm/yasm and C for hints.)
32-bit Windows (x86)
push 0
call ExitProcess
Or Windows/Linux linking against the C Library
; pass an int exit_status as appropriate for the calling convention
; push 0 / xor edi,edi / xor ecx,ecx
call exit
(Or for 32-bit x86 Windows, call _exit, because C names get prepended with an underscore, unlike in x86-64 Windows. The POSIX _exit function would be call __exit, if Windows had one.)
Windows x64's calling convention includes shadow space which the caller has to reserve, but exit isn't going to return so it's ok to let it step on that space above its return address. Also, 16-byte stack alignment is required by the calling convention before call exit except for 32-bit Windows, but often won't actually crash for a simple function like exit().
call exit (unlike a raw exit system call or libc _exit) will flush stdio buffers first. If you used printf from _start, use exit to make sure all output is printed before you exit, even if stdout is redirected to a file (making stdout full-buffered, not line-buffered).
It's generally recommended that if you use libc functions, you write a main function and link with gcc so it's called by the normal CRT start functions which you can ret to.
See also
Syscall implementation of exit()
How come _exit(0) (exiting by syscall) prevents me from receiving any stdout content?
Defining main as something that _start falls through into doesn't make it special, it's just confusing to use a main label if it's not like a C main function called by a _start that's prepared to exit after main returns.