CPU Registers Explained: What They Are and Why They Matter in Reverse Engineering

:high_voltage: OllyDbg Reverse Engineering Series - Part 4 of 60

CPU registers are fundamental to understanding how programs execute in memory.

# Title Link
Part 1 What is Reverse Engineering? Why OllyDbg? What is Reverse Engineering? And Why Am I Using OllyDbg?
Part 2 OllyDbg Interface Tour – Every Window Explained How to Read Disassembly in OllyDbg: A Beginner’s Guide
Part 3 Number Systems – Hex, Decimal, Binary with Real Examples Hex vs Binary vs Decimal: Explained for Programmers and Reverse Engineers
Part 4 - You are here CPU Registers – What They Are and Why They Matter CPU Registers Explained: What They Are and Why They Matter in Reverse Engineering
Part 5 Your First Look at Assembly – Reading Code Like a Reverser How to Read Assembly Code for Reverse Engineering

Since Part 2, I kept seeing these names EAX, EBX, EIP, ESP, EBP. They were everywhere. In the Registers window, in assembly instructions, in every tutorial I read. I just accepted them without really understanding what they were.

At some point I realized I’m reading assembly instructions that say MOV EAX, 0xFF and I don’t even properly know what EAX is. I know it’s a register. But what does that actually mean? What does it do? Why does EIP matter more than the others?

This part answers all of that. We go through every register you’ll see in OllyDbg — what it is, what it does, and why you care. And I’ll be honest about the parts that confused me, because they’ll probably confuse you too.

Quick note we still haven’t opened OllyDbg yet. We’re building the mental model first. When we do start using the tool, everything here will click naturally in context.


What Even Is a Register?

You already know from Part 3 that the CPU is constantly working adding numbers, comparing values, moving data around. It needs somewhere to keep the values it’s actively working on.

It can’t use RAM for this. RAM is relatively slow. Every time the CPU needs a value from RAM, it has to travel across the bus to fetch it. For a processor running at gigahertz speeds, that delay adds up fast.

So the CPU has its own tiny built-in storage slots sitting right inside the processor itself. These are registers. Accessing a register is thousands of times faster than accessing RAM.

Think of it like a carpenter. RAM is the storage room down the hall all the wood, nails, tools are stored there. But when the carpenter is actively working, he keeps the tools he’s using right on his workbench immediately within reach. That workbench is the registers.

A 32-bit register holds 32 bits 4 bytes one 8-digit hex value like 00401000.

So: **RAM stores a lot of data at specific addresses. Registers store only the data the CPU is actively using right now so it can access it immediately without going to RAM. **


The General-Purpose Registers EAX, EBX, ECX, EDX

These four are the main working registers. The CPU uses them to hold values it’s computing with.

EAX -  Accumulator
EBX -  Base  
ECX -  Counter
EDX -  Data

Their full names honestly don’t matter that much day to day. What matters is how they’re commonly used:

EAX is the most used one. When a function finishes and returns a result that result comes back in EAX. So, if you call a function that checks if a password is correct, the yes/no answer will be sitting in EAX when it returns.

ECX is often used as a loop counter. “Do this 10 times” ECX starts at 10 and counts down to 0. Every loop iteration, ECX decreases by 1.

EBX and EDX are general helpers holding values the program is working with at any given moment.

But here’s something important I want you to understand these are called general purpose for a reason. The CPU can use any of them for anything. The uses I described above are conventions common patterns not strict rules. You’ll see EAX used as a counter sometimes. You’ll see ECX used for something completely different other times.

This is why when you’re actually reversing, you can’t just assume “oh, ECX must be a counter here.” You have to read the assembly and figure out what it’s actually being used for in that specific code. That’s the mindset of a doesn’t assume. Read the code.


ESP and EBP - The Stack Registers

You know what the stack is from Part 2 it tracks return addresses, function calls, local variables. Two registers are dedicated to managing it.

ESP - Stack Pointer

ESP always points to the top of the stack right now.

Think of the stack like a stack of plates. ESP is your finger always pointing at the topmost plate. You add a plate your finger moves up. You remove a plate your finger moves down. ESP works exactly like that.

Stack:
[ value 4 ]  ← ESP points here (top)
[ value 3 ]
[ value 2 ]
[ value 1 ]  (bottom)

Remove value 4 - ESP moves down to value 3. Push a new value ESP moves up to it. ESP is constantly moving as code runs.

EBP - Base Pointer

This one confused me for a while. Let me explain it the way it finally clicked for me.

When a function is called, the CPU sets aside a chunk of stack space just for that function. Local variables, temporary values all go in that chunk. That chunk is called a stack frame.

EBP gets planted at the start of that chunk and stays there the whole time you’re inside the function. It’s an anchor.

Why do you need an anchor? Because local variables are accessed relative to EBP:

EBP - 4   →  local variable 1
EBP - 8   →  local variable 2

ESP is constantly moving as values get pushed and popped. If you tried to find local variables relative to ESP, their address would keep changing every time something gets pushed or popped. EBP stays still so you always know exactly where your variables are.

Think of it like working at a desk:

  • EBP is the desk itself fixed, doesn’t move while you’re working
  • ESP is your hand moving around the desk, picking things up, putting things down

So, when you see EBP in assembly the function is accessing its own local variables. When you see ESP, the function is pushing or popping things from the stack.

The moment a function ends, EBP gets restored to whatever it was before ready for the next function.


EIP The Most Important Register of All

EIP stands for Extended Instruction Pointer. One job, one job only:

**It holds the address of the next instruction the CPU will execute. **

That’s it. Whatever address is in EIP that’s what runs next. CPU executes that instruction, EIP automatically updates to the next one, CPU executes that, EIP updates again. This is how code flows forward one instruction at a time, EIP always pointing to what’s next.

When you eventually open OllyDbg, you’ll see a highlighted line in the Disassembler window. That highlighted line is exactly where EIP is pointing right now.

Think of EIP like a finger reading a book it points to the current word, moves to the next, moves to the next. Except EIP points to instructions instead of words.

Now here’s why EIP is the most important register:

**Whoever controls EIP controls the entire program. **

If you can somehow force EIP to point to your own code the CPU will execute your code. This is the foundation of most real-world exploits. Buffer overflows, shellcode, ROP chains they all come down to controlling EIP. We’ll get deep into this in later parts. For now, just remember EIP is the register that controls what runs next. Everything else is secondary.


The Flags Register - Yes/No Answers That Control Code Flow

This one is different from all the others. EAX, EBX, ESP they hold full values like 000000FF or 00401000.

The Flags register is a collection of single bits. Each bit answers one yes/no question about what just happened.

The main ones you’ll see:

ZF - Zero Flag Did the last operation result in zero? If yes, ZF = 1. If no, ZF = 0.

CF - Carry Flag Did the last operation overflow beyond the register size? CF = 1 if yes.

SF - Sign Flag Was the result negative? SF = 1 if yes.

Now you might be thinking okay, but why do I care if something was zero or not?

Because jumps in assembly depend on flags. This is how if/else logic works at CPU level.

Look at this:

CMP EAX, 5       ← compare EAX with 5
JE  00401050     ← jump to 00401050 IF zero flag is set

CMP subtracts 5 from EAX internally and sets the flags based on the result. If EAX was 5, the result is zero so ZF gets set to 1. Then JE (Jump if Equal) checks ZF if it’s 1, jump to 00401050. If it’s 0, don’t jump, just continue to the next line.

That’s an if statement in assembly. “If EAX equals 5, go here. Otherwise keep going.”

The way I think about it: imagine you have two functions, and which one runs depends on what the previous operation returned. The flag register is what carries that yes/no answer forward to the next decision point. Flags are the yes/no answers that control which path the code takes.

Flags will make much more sense once you’re watching them change live in OllyDbg. For now just know they exist and that jumps depend on them.


EAX, AX, AH, AL - The Same Register in Different Sizes

One last thing that confused me when I first saw it.

You know EAX is 32 bits. But here’s something interesting you can access smaller pieces of EAX directly:

EAX → full 32 bits (the whole thing)
 AX → lower 16 bits of EAX
 AH → upper 8 bits of AX
 AL → lower 8 bits of AX

Let me make it visual. If EAX = 0000004A:

EAX:  [ 00 ][ 00 ][ 00 ][ 4A ]
                   [    AX   ]
                   [ AH ][ AL]

So:

  • AL = 4A (last two hex digits the rightmost byte)
  • AH = 00 (second to last byte)
  • AX = 004A (last four hex digits the last two bytes)
  • EAX = 0000004A (the whole thing)

Simple rule: AL is always the last two hex digits of EAX.

Why does this matter? Because sometimes code works with just one byte of data like a single ASCII character. Instead of using the full 32-bit EAX, it’ll use AL. When you see AL in the Disassembler, you know the code is working with just the bottom byte of EAX.

EBX, ECX, EDX all have the same pattern BX/BH/BL, CX/CH/CL, DX/DH/DL. Same idea across all four general purpose registers.

Since we’re using 32-bit OllyDbg in this series, you’ll mostly see the full E versions. But now when you see AL or CL in an instruction, you’ll know exactly what it is.


What I Found Confusing (And Now Don’t)

“EBP - why can’t ESP do the same job?” Because ESP moves constantly. Every push and pop changes it. If you used ESP to find local variables, their address would keep shifting. EBP stays planted at the function’s base so you always have a stable reference point for the function’s local data.

“Flags - I’ll understand better in practice.” Honest answer: yes. Flags are one of those things that make complete sense the moment you watch ZF flip from 0 to 1 after a CMP instruction in OllyDbg. The theory is simple the practical click comes later.

“EAX vs AX vs AL - which one does the code use?” Depends on how much data the code is working with. Full 32-bit value → EAX. 16-bit value → AX. Single byte → AL. You’ll see which one is being used by reading the instruction.


What We Learned - Glossary

Term What It Means
Register Tiny ultra-fast storage slot built directly inside the CPU
EAX General purpose function return values come back here
EBX General purpose holds values being worked on
ECX General purpose often used as a loop counter
EDX General purpose holds values being worked on
ESP Stack Pointer always points to the top of the stack, moves constantly
EBP Base Pointer anchored to the start of the current function’s stack frame
Stack Frame The chunk of stack space set aside for one function’s local data
EIP Instruction Pointer holds the address of the next instruction to execute
ZF Zero Flag set to 1 if the last operation resulted in zero
CF Carry Flag set to 1 if the last operation overflowed
SF Sign Flag set to 1 if the last result was negative
AX Lower 16 bits of EAX
AH Upper 8 bits of AX
AL Lower 8 bits of AX the last two hex digits of EAX
CMP Assembly instruction that compares two values and sets flags
JE Jump if Equal checks the Zero Flag and jumps if it’s 1

Coming Up Next

In Part 5 we take our first real look at assembly language reading actual instructions, understanding what they do, and starting to think like a reverser when you look at disassembled code.

→ Part 5: Your First Look at Assembly - Reading Code Like a Reverser

← Part 3: Number Systems - Hex, Decimal, Binary with Real Examples