root@mr-resetti:~$

Architecture 1001: x86-64 Assembly Notes

This is just a page of notes and important things to me to remember while learning Assembly

Constants, Registers, Memory

“12” means decimal 12; “0xF0” is hex. “some_function” is the address of the first instruction of the function. Memory access (use register as pointer): “[rax]”. Same as C “*rax”. Memory access with offset (use register + offset as pointer): “[rax+4]”. Same as C “*(rax+4)”. Memory access with scaled index (register + another register * scale): “[rax+rbx*4]”. Same as C “*(rax+rbx*4)”.

Endianness

Little Endian Example: 0x12345678 = 0x78, 0x56, 0x34, 0x12

Big Endian Example: 0x12345678 = 0x12, 0x34, 0x56, 0x78

Screenshot_12

Network traffic is sent in Big Endian

Memory Hierarchy

Top of Hierarchy is small storange, quick access, volatile.

Lower part of Hierarchy is large, slow, non volatile storage.

Architecture Registers

Register Evolution: AL, AH, AX, EAX, RAX.

Screenshot_11

Register Conventions

These all start with E instead of R in x32 programs

Segment Registers

Registers are also called general purpose registers and their capacity is 32 bits: 4 bytes (4 sets of 8 bits).

The Program Status and Control Register is EFLAGS, which is a collection of 1-bit flags.

The Flags aint important, apart from the Trap Flag which basically allows debuggers to single-step through instructions.

My First Instruction: NOP

The Stack

What can be found on the stack?

Screenshot_13

Push & Pop Instructions

PUSH

r/mX

r/mX can take 4 forms:

  1. Register -> rbx
  2. Memory, base-only -> [rbx]
  3. Memory, base + index * scale -> [rbx+rcx*X]
    • For X = 1, 2, 4 or 8
  4. Memory, base + index * scale + displacement -> [rbx+rcx*X+Y]
    • For Y of 1 byte (0-2^8) or 4 bytes (0-2^32)

Basically a complicated way of addressing memory locations

r/mX could be a single register like rbx or it could be a complicated memory address calculation like [rbx+rcx*X+Y]

r/mX Examples:

Screenshot_17

A scenario: push RAX

Screenshot_15

What happened?

  1. RSP value decremented by 8 because the stack pointer (RSP) is automatically decremented by 8 after being pushed onto the stack
  2. RSP WAS at memory address 0x014FE08. AFTERWARDS it is at 0x014FE00. Again because the stack pointer is automatically decremented by 8 after being pushed.
  3. Also, the value of memory address 0x014FE00 is now 3, because the RAX value was 3. Previously, it was undefined
  4. In the end, 0x014FE00 is the new stack pointer, and its value is still 3. (it was always going to be 3 anyways, because we are pushing a value onto the stack from the predefined register RAX)

POP

Opposite scenario: pop RAX

Screenshot_16

What happened?

  1. RAX had some random value before the POP, in this case it is 5007
  2. RSP was pointing at our previous memory address: 0x014FE00 with the value still being 3
  3. After execution, the 3 value from the stack is popped off of the stack and into the RAX register, overwriting the 5007
  4. RSP register is incremented by 8 as a side effect automatically after being popped off of the stack
  5. Memory address 0x014FE00 is now known as undefined
  6. RSP is now at memory address 0x014FE08 with a memory address value of 2
  7. The value 3 is now stored in the RAX register
  8. Data does still exist past the end of the stack.

32-bit Information

CALL

RET - Return from Procedure

How to read two-operand instructions: Intel vs AT&T Syntax

Screenshot_18

MOV (aka Move)

Can move:

See examples below:

Screenshot_19

ADD and SUB

Examples:

add rsp, 8 -> (rsp = rsp + 8)

sub rax, [rbx*2] -> (rax = rax - memorypointedtoby(rbx * 2))

Writing in Visual Studio

Writing some simple subroutine call code:

int func() {
    return 0xbeef;
}
int main() {
    func();
    return 0xf00d;
}

Debugging the code results in the RSP register being changed after hitting the main() breakpoint and stepping into the function:

Before

Screenshot_20

After

Screenshot_21