x64 ASM Fundamentals 0x02 – MOVing on to the basics of ASM.


This post will be a short primer on some of the basic building blocks of the x64 assembly language (and also x32, because they share a lot of the same building blocks)

The instructions covered in this post will genuinely cover 80-90% of the code which you’ll see in the vast majority of applications which you reverse engineer / write. After reading this post, you should go away and have a play with reverse engineering a few programs yourself and you’ll see what I mean by the above statement!

Final point in this rambling introduction before I shut up and start writing more interesting things. It is MY personal opinion that the very best way of learning assembly is to write some basic programs using C, compile them with GCC and then open them up in GDB. This means that you can compare the disassembled ASM instructions side by side with the code that you’ve written and really get a sense of what’s happening.

Just my two cents on the matter. Also yes, the title of this post is a rubbish pun because….

The MOV Instruction

The MOV instruction, short for “move”. Move is actually a bit of a misnomer, because it actually copies data from source to destination.

Syntax – 

MOV (destination) (source)

Where destination is typically always a register, and source can be –

  • A hard coded hexadecimal integer
  • A register
  • A expression (typically something like [RBP-0x53], for example)

The MOV instruction is absolutely fundamental in ASM programming. It’s literally analogous to variable assignment in high level languages and you’re going to see it in every single program you can possible imagine.

Code example – 

// High Level Language
int myInt = 53;
int myInt2 = 65;
myInt = myInt2;


; 64 bit assembly version
mov RAX, 0x35 ; put 53 into the RAX register
mov RBX, 0x41 ; put 65 into the RBX register
mov RAX, RBX  ; replace the contents of RAX with the contents of RBX

At the end of the last instruction above, RBX and RAX both contain 0x41. The value was copied using the mov instruction.

Bonus tid-bit, where “//” is the comment character in most high level languages, “;” is the comment character in ASM.

Note that in the assembly version, we didn’t explicity define – 

  • A variable type
  • A variable name
  • A variable scope

This is because in assembly, a “variable” doesn’t really exist as a concept.. A piece of dynamic data placed in a register acts as a variable, but as soon as a register’s value is changed then that “variable” is gone.

You don’t need to supply a type because your data is always defined in bytes, whether that data is a string, a single character or an integer.

A “variable”‘s scope in ASM is global by default, because any function can access all of the registers, and if the register holds a variable then it’s accessible to any function.

An Example

Believe it or not, you now know enough to write your first Assembly program. Let’s write an application in ASM and then reverse engineer it like hax0rs.

Pop the following into a file named “test.s” and assemble it with “nasm test.s -felf64 -o test.o” –

section .text
global _start

mov RAX, 0x35 ; put 53 into the RAX register
mov RBX, 0x41 ; put 65 into the RBX register
mov RAX, RBX  ; replace the contents of RAX with the contents of RBX

Three lines above are probably confusing you a little bit. They are all standard boilerplate when handwriting assembly code.

“section .text” means that our code lives in the “.text” section of the application.  Don’t stress over this for now, essentially ELF applications are divided up into sections and the .text section is where code lives.

“global _start” simply defines the entry point for the application. Again, this is boilerplate and analogous to “int main()” in C programs.

“_start:” defines the start of the “_start” function. In ASM any line which ends with a colon is a “label”. This supplies the linker with a named entry point for the application.

Now that we’ve got our test.o file, we can link it into an executable with “ld test.o -o test”. This will generate an executable named “test”. Load the newly created binary into GDB with “gdb ./test”.

After a few lines of output, you’ll be presented with a prompt. Enter “disassemble _start” (aka, disassemble the function named _start which we wrote above). Lo’ and behold, you see the code which we wrote earlier!

Now, we have one last little snag to solve before we can wrap this section up. If you type “run”, the application will crash.. If you try and run the application outside of GDB with “./test” it’ll crash too.

This is because we’ve not adequately defined how the application should quit. Add the following three lines to the end of test.s and assemble / link it again with the commands above – 

mov rax, 60     ; system call for exit
mov rdi, 0x41   ; exit code 0x41

To explain the above few commands. We’re moving 60 into the RAX register, we’re setting RDI to 0x41 (which will be the return code!) and performing a syscall. We’ll cover syscalls in more detail soon, but for now just acknowledge that we’re calling syscall number sixty, which corresponds with exit on 64 bit Linux.

For a bit more information about syscalls, and where the number 60 came from, take a look here

Attempting to run the application now works flawlessly. Running “echo $?” (Linux command to print the return code of the last program) will print 65 to the screen, 65 being the decimal value for 0x41.


So in this post, you’ve learned arguably the most fundamental building block of the Assembly programming language – you’ve learned how to copy data around between different registers.

This one little building block has enabled you to write an actual ASM application which works correctly.

In the next post we’ll cover the other most fundamental concept in the assembly language – The Stack.

Thanks for reading 😊


Add a Comment

Your email address will not be published. Required fields are marked *

I accept that my given data and my IP address is sent to a server in the USA only for the purpose of spam prevention through the Akismet program.More information on Akismet and GDPR.