Navigation

User login

Browse archives

« January 2008 »
Su Mo Tu We Th Fr Sa
    1 3 4 5
6 7 8 9 10
13 14 15 16 17
20 21 22 23 24 25 26
27 28 29 31    

Who's online

There are currently 0 users and 2 guests online.

archives

Introduction to Intel Assembly

This semester I am taking a class on Intel assembly, because I want more of an insight into how the computer works, and it will allow me to better reverse engineer new viruses and spyware. The class is also required if one is a Software Engineering major, so that means I have to take it.

The professor who teaches it absolutely sucks at teaching. He gets up in front of the class and mumbles through some powerpoint slides, which provide no real information, and then goes on and on about his days at Motorolla. It really sucks. Oh, best part is this quote:

"I think that is how Intel processors do it. I don't know I have not read up on it yet"

Well, we had our first assignment. Sum two numbers and then output them to the screen. We were supposed to write inline assembly using Visual Studio C++, but if we are to do an assembly class, then we should learn how to do write assembly, not have some parts assembly and other parts the compiler. Sure it makes it easy as you will get immediate access to the standard C library, but if you want that, you can just link against it.

The following code examples were written on Mac OS X, and will work on FreeBSD. Linux uses a different calling convention for it's syscalls, and as such this code will not run on Linux, unless it is modified. Do note, you need an Intel Mac for this to work. This is Intel assembly.

Compile the code with (Mac OS X):

nasm -f macho addnumbers.asm
ld -o addnumbers addnumbers.o

or (FreeBSD)

nasm -f elf addnumbers.asm
ld -o addnumbers addnumbers.o

Then you can run it with:

./addnumbers 1 5

As you can see in the comments of the source code, there are still some limitations, but the rest of the source code should be made readable by the comments that are provided.

Porting to Linux: Please double check that all the syscall numbers are the same. There are some differences between Linux and FreeBSD/Mac OS X in that regard.

; File: addnumbers.asm
; Bert JW Regeer
; 
; 2008-01-27
; 
; Function:
;	Add numbers together that are provided as arguments to the program in argv[1] and argv[2].
;
; Known limitations:
;	As of right now, the numbers that are provided may not add up to anything more than 9.
;	This will hopefully be fixed in the next revision. Floating point numbers will not work.
;
; Todo:
;	Write conversion routine, to convert a string of numbers into a real integer on which
;	math may be performed.
 


section .data

	; Define some strings that are going to be used throughout the program

	; This string is to let the user know they failed to provide the proper amount of arguments.
args	db	"You failed to provide the proper amount of arguments", 0xa
largs	equ	$ - args

	; This string contains part of the output that we are going to send to the terminal. The last two
	; bytes will be filled automatically by the program, before it is output to stdout.
msg	db	'Answer: ',	0,	0
lmsg	equ	$ - msg

section .text
global start				; Linker defined entry point. Mac OS X this is start. FreeBSD and others _start.
global _start

_start:
start:

; Start the program here.

	add	esp, byte 8		; We don't care about argc or argv[0]
	
	pop 	ecx			; Get the first argument or argv[1]
	jecxz	exit			; If there was no argument. Exit. Let the user know why

	; Change the number from a character to an actual dword
	mov	eax, dword [ecx]	; Move the character into eax so we can manipulate it
	sub	eax, 0x30		; Remove 0x30 from the character. To make it an actual number, not an ASCII number.

	pop	ecx			; get the second argument or argv[2]
	jecxz	exit			; If there was no second argument. Exit. Let the user know why

	mov	ebx, dword [ecx]	; Move the character into ebx so we can manipulate it
	sub	ebx, 0x30		; Remove 0x30 from the character. To make it an actual number, not an ASCII number.

	add	eax, ebx		; Add the two numbers together
	add	eax, 0x30		; Make it an ASCII number again

	mov	[msg+lmsg-2], eax	; Replace the null character in the msg with the answer
	mov	[msg+lmsg-1], dword 0xa	; Add an newline character so that when it spits it out it is neatly formatted
					
					; Call sys_write
	push	dword lmsg		; Push the length of the string
	push	msg			; Push the location of the string in memory
	push	dword 0x1		; Push the file descriptor to write to
	mov	eax,4			; Move the syscall number into eax
	push	eax			; Push the syscall onto the stack
	int	0x80			; Interrupt 80, go to kernel
	add	esp, byte 16		; Advance the stack pointer
 
	jmp	done			; Program is done. Jump to done

exit:
					; Call sys_write
	push	dword largs		; Push the length of the string
	push	dword args		; Push the location of the string in memory
	push	dword 0x1		; Push the file descriptor to write to
	mov	eax,4			; Move the syscall number into eax
	push	eax			; Push the syscall onto the stack
	int	0x80			; Interrupt 80, go to kernel
	add	esp, byte 16		; Advance esp past the part we were just at

done:
					; sys_exit
	push	dword 0x1		; Push the value to return to the operating system
	mov	eax,1			; Move the syscall number into eax
	push	eax			; Push the syscall onto the stack
	int	0x80			; Interrupt 80, go to kernel

	; We never return to this function, so no need to clean the stack.