Reading Memory

Bits and Hex

Memory is stored in bits, which can be either 0 or 1 (Binary)

Hex is a number system based on 16, so values can be 0-9, or A-F (10-15).

Why use hex? It's easier to parse and it's simple to convert it to binary, unlike decimal.

Converting Hex to Binary

In binary, the number 15 is represented as 1111

1 1 1 1
8 + 4 + 2 + 1 = 15

In hex, the number 15 if represented by F

F

By splitting up binary into groups of 4 bits, you can convert that group into hex by adding the values of the bits ...

1 1 1 1
8 + 4 + 2 + 1
= 15
0 1 1 1
0 + 4 + 2 + 1
= 7
0 0 1 0
0 + 0 + 2 + 0
= 2
1 0 1 0
8 + 0 + 2 + 0
= 10

... and then joining them back together.

F 7 2 A
15   7    2   10

Pointers

A pointer is a piece of memory that holds the address of a value, and not the value itself.

07 1C 00 00
Value of pointer:
071C0000
00 00 00 A0
Value at 071C0000:
A0

This can be useful when a program is not sure what the actual address of a value will be until runtime.

Sometimes pointers hold the addresses of other pointers. These are called pointer chains.

07 1C 00 00
Value of pointer:
071C0000
14 55 F0 08
Value of pointer:
1455F008
00 00 10 FF
Value at 1455F008:
10FF

Registers

In assembly code you can't save values to variables, so arguments to functions are stored and passed around in registers.

What's a register? It's a special piece of memory that's only big enough to store 4 bytes of data, but the processor can access it really quickly.

In x86 architecture, there are 8 usable registers.

  • EAX
  • EBX
  • ECX
  • EDX
  • EDI
  • ESI
  • ESP
  • EBP

... but most instructions will only involve these four.

Most registers have a special function, so you'll see them used in consistent ways across different programs.

For example, EAX is optimized for calculations, while ESP is used to reference the top of the stack.

Assembly

Assembly Code Essentials

Assembly code is a list of instructions that tell the computer exactly what it needs to do to complete a program.

Each instruction is very specific, and only has a few operands.

Taken one step at a time, it's possible to follow the code exactly as the computer would execute it.

So, how do bytes in memory become code?

Each instruction is a direct translation of bits in memory

1 0 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0

These bits indicate this an add instruction, adding a constant to a register.

These bits indicate which register is being added to.

And these bits are the value being added.

Based on the bits, the computer will translate them into an instruction.

add ESP, 08

There are 4 ways to provide arguments to assembly instructions:

  • add EAX,1

    constants - these can be addresses or values of any type.

  • add EAX,EBX

    registers - the value currently in register EBX is used.

  • add EAX,[EBX]

    addressing - the value in memory at the address in register EBX is used.

  • add EAX,[EBX+C]

    address displacement - add C to the address in register EBX and use what is stored in memory there.

Need to Know Instructions

Arithmetic

INC operandoperand += 1
DEC operandoperand -= 1
NOT operandnegates each bit in operand
ADD destination, sourcedestination += source
SUB destination, sourcedestination -= source
AND destination, sourcedestination &= source
OR destination, sourcedestination |= source

Memory Management

MOV destination, operandcopies operand value to destination
CMP value1, value2

compares value1 to value2 (<, =, >) without modifying either

PUSH operand

places operand value on top of stack

POP destination

removes value on top of stack and copies it to destination

CALL operandcalls a subroutine at address or label

Jumps

JMP destinationjumps execution to address or label
JE destinationjumps if previous CMP was equal
JNE destination

jumps if previous CMP was not equal

JG destination

jumps if previous CMP determined value1 > value2

JL destination

jumps if previous CMP determined value1 < value2

References