So I was reading Slashdot yesterday when I came across a link to this article which is basically a crash course in writing super small programs using assembly language (nasm in Linux). I was completely in awe of their acquired 45 byte executable and took it upon myself to learn the basics of assembly.

My first attempt was to write a hello world (the article writes a 45 byte executable that just returns the number 42). That worked super well and was as easy as I thought, so I decided to play around with a couple of more system calls and write a program that sends hello world to a file in /tmp/. There were a few errors that I came across, so I got some help from the friendly guys in #asm on freenode IRC and figured out the last part. Here is the code, and after it is an explanation of the two parts the screwed me up.

; tiny.asm
		org		0x08048000

	ehdr:                                       ; Elf32_Ehdr
		db			0x7F, "ELF", 1, 1, 1, 0         ;   e_ident
		times		8 db      0
		dw			2                               ;   e_type
		dw			3                               ;   e_machine
		dd			1                               ;   e_version
		dd			_start                          ;   e_entry
		dd			phdr - $$                       ;   e_phoff
		dd			0                               ;   e_shoff
		dd			0                               ;   e_flags
		dw			ehdrsize                        ;   e_ehsize
		dw			phdrsize                        ;   e_phentsize
		dw			1                               ;   e_phnum
		dw			0                               ;   e_shentsize
		dw			0                               ;   e_shnum
		dw			0                               ;   e_shstrndx
	ehdrsize		equ		$ - ehdr
	phdr:                                       ; Elf32_Phdr
		dd			1                               ;   p_type
		dd			0                               ;   p_offset
		dd			$$                              ;   p_vaddr
		dd			$$                              ;   p_paddr
		dd			filesize                        ;   p_filesz
		dd			filesize                        ;   p_memsz
		dd			5                               ;   p_flags
		dd			0x1000                          ;   p_align
	phdrsize		equ	$ - phdr

		msg		db		"Hello, World!", 0xa
		len		equ   $ - msg
		file		db		"/tmp/test.out", 0x0

		; create the file /tmp/test.out
		mov		eax, 5
		mov		ebx, file
		mov		ecx, 66
		int		0x80

		; save the file descriptor
		mov		ebx, eax

		; set read/write permissions on the file
		mov		eax, 94
		mov		ecx, 0x1ff
		int		0x80

		; write the string to the file
		mov		eax, 4
;		mov		ebx, 1			; uncomment this to print to stdout instead
		mov		ecx, msg
		mov		edx, len
		int		0x80

		; close the file
		mov		eax, 6
		int		0x80

		; exit
		mov		eax, 1
		mov		ebx, 0
		int		0x80

filesize			equ	$ - $$

You can build and execute this yourself straight from Linux command line if you have nasm installed by saving it as tiny.asm and executing “nasm -f bin -o a tiny.asm && chmod +x a”. I have the ELF headers embedded directly into the assembly and we use ZERO external libraries so there is no linking needed. In fact, since pretty much everything executed is system calls, you can then run strace on the resultant executable (named “a”) and it will give you a pretty nice dump of exactly what it does.

The first thing that kind of tripped me up was when I created the file, it creates by default with no permission flags set at all. To fix this, I added an fchmod call right after I opened the file. The hex value I pass to as the second parameter (ecx) is just the hex value for 777 permissions. That set the permissions right but originally when I went to write to the file it still wouldn’t write. Thanks to the IRC help I figured out that when I was opening the file, I was opening with O_CREATE (62) when what I really wanted to do was open it with O_CREATE | O_RDWR so that I could write to it as well, so I changed the mode parameter of the call to open to 64 instead of 62 et voila, it works!

Hope you enjoy and maybe it’ll help somebody else out who is trying to write to a file with assembly in Linux.