Last time we talked about system calls. This time we are going to write a program in assembly language that directly invokes two Linux system calls. The write() system call and the exit() system call. To follow along with this entry you’re going to need to install nasm or a similar functioning assembler on your machine.
The System Calls
Each system call in Linux has a number associated with it. Here is a nice reference table that has the system call numbers and some information about the calls in assembly. The information is for the Linux 2.2 kernel but it matches the information in HTAE.
From the man pages we have that the write() function has the following definition.
ssize_t write( int fd, const void *buf, size_t count);
Then we have for the exit() system call.
void _exit(int status);
We are going to translate these templates into assembly code and execute the program on our machine.
The Assembly Program
section .data ; Data segment msg db "Hello, World!", 0x0a ; The string and newline Char section .text ; Text segment global _start ; Default entry point for ELF linking _start: ; SYSCALL: write(1, msg, 14) mov eax, 4 ; Put 4 into eax, since write is syscall 4 mov ebx, 1 ; Put 1 into ebx, since 1 is stdout mov ecx, msg ; Put the address of msg into ecx mov edx, 14 ; Put 14 into edx since the string is 14 bytes. int 0x80 ; Call the kernel to make the system call happen ; SYSCALL: exit(0) mov eax, 1 ; Put 1 into eax since exit is syscall 1 mov ebx, 0 ; Exit with success int 0x80 ; Execut the syscall.
Here we put the system call identifiers into eax for each system call. Then we start filling in the arguments for the system call into the next register. It actually doesn’t matter much which order you assign the registers in each code segment. It does matter which value you store in which register. If you change the values around you won’t get any output from your compiled program.
$ nasm -f elf helloworld.asm $ ld helloworld.o $ ./a.out Hello, World!
We compile the assembly program as an ELF file, which we discussed briefly in the hexdump post. Then we link the helloworld.o file and execute.
This is a nice introduction to actually writing an assembly program. We also see how the system calls are implemented at the assembly level. As Jon Erickson states in HTAE a program like this wouldn’t be useful as an exploit payload because we still have to compile and link the program to get it to execute. So we have some more to do before we are writing our own custom shellcode. In the next few posts we are going to play around with helloworld.asm and examine how the program interacts with our machine.