Hello everyone.
I'm here again and in this lecture we are going to explore two fundamental concepts in x86 64 assembly
programming which is the memory addressing.
And Endianness.
So these are essential for understanding how data is stored, accessed and manipulated at a low level
in your programs.
Now let's start with the memory addressing here, because this is one of the most essential concept
to understand assembly programming.
So imagine your computer's memory as a very long rows of mailboxes here, and each with a number on
it.
Now these numbers are the memory addresses.
Every single byte of data stored in random access memory is placed in one of these mailboxes and its
address tells the CPU.
Where to find it.
So when a program is run, the operating system loads the program's executable file into memory.
Now this is done by mapping the file into specific regions of memory.
So for example, in this part of the memory this is for notes dot txt.
And for example in the other part is for the virus that exa right.
This is basically how memory works in a nutshell.
So we have basically in the memory the code section data and b As S section.
So the code section holds the machine instructions E or IP and so on and so forth.
The data section contains global and static variables that are initialized.
The BSS sections contains uninitialized, global and static variables.
Basically the data but uninitialized.
Now each of these segments starts uh, at a known memory address when the CPU executes instructions
in the code section here, uh, these instructions may reference data stored in the data section by
directing using the memory addressing.
Sometimes the data itself contains more addresses, for example the memory address here, by the way.
Here, for example, this is the part where we store the memory addresses.
So this memory address tells that this data is here.
Or this memory addresses redirects to memory itself.
Right.
So you will understand this in more deeply as we learn more about it.
But uh, yeah.
Uh, a pointer, uh, which is this is basically what pointers does uh, in C, if you know the C,
you will be very familiar with this concept here.
So basically, uh, data itself contains more addresses sometimes.
Now for example uh pointers.
Pointers is simply a value that points to another memory address like this allowing for indirect access
to other data.
Now, this structure is vital when reverse engineering because it helps us understand how a program
is organized in memory and how different parts of it interact through addresses.
Now let's talk about the Indians here, which is how multi-byte data is laid out in memory.
So when you store a four byte value, uh, which we call it a D word in uppercase, it has to be broken
down into four separate bytes and placed into a memory.
But in what order?
So we have to.
One byte.
One byte, one byte.
So this, uh.
Yeah.
But in what?
Order here.
So there are two main, uh, schemes here.
Uh, so Indiana's separate to two main categories into a lead endian or little endian and the big endian.
Yes.
Uh, basically let's start with understanding what the little endian does.
Uh, this uh format is mostly used in X uh 86 processors, uh, and therefore uh, by most windows programs
now in little endian format, the least significant bit least significant is L s b is stored at first.
So let's say you want to store the Dword value like D.
D.
This is a hex, by the way.
Since we are writing the zero x here, we are telling that it is a hexadecimal d cc b b a a in memory
in little endian.
It will be stored like this.
The first is going to be a a in a address of 0000, and the 0X0001, it will be BB0X0003 it will be
cc and in the 0X00 for it at the memory address of 0X004, it will be the, uh Didi.
So if you read uh from the address 000 as a Dword, you get back this hexadecimal value, even though
the bytes are stored in a reverse order, but in the big endian.
Here, what you will see is if you want to store the again bytes up here, it will be basically the
same as well.
But the format is often used in network protocols here.
So and streaming data um, because it's uh, more uh, intuitive when reading a sequence of bytes.
But basically the most endian here uses the more, uh, big endian here uses most significant byte.
So from uh.
Most significant to the least significant byte in the little endian, we are using the LSB, which is
the least significant byte.
Now here's what you see is what you get.
The format is often used in network protocols basically.
But yeah, little endian using x86 processors, which is basically the x86 in the windows.
Now you may ask here why little endian matters in x86.
So the little endian format has some unique advantages.
Now let's consider this memory layout, uh where the 0X001 or let's use the one byte zero one is a a.
So now if you read from this uh zero x uh zero.
Oops.
Not like this.
Uh, it should be one Uh, zero.
And here it will be.
One, two, three.
Sorry for this.
Now, if you read from this 0000, which is, uh, holds the value of AA.
Now, as a byte, if you read this as a byte, what you will get if you read this as a byte you will
get is 0XAA from uh, this here.
Right.
But if you read this as a word, you will get
0X00AA.
But if you read this as a D word, what you will get is
0012350AA.
Now you can notice something different here.
Obviously the value is always interpreted starting from the same address, even when the size of reed
changes.
Now this consistent behavior simplifies memory access logic in many programs.
So in contrast, if we if the same data were stored in a big endian format, reading it in a different
sizes would give different results.
Now this can.
But, uh, here.
Yeah.
In here, uh, you will get, uh, zero same because we just only have two.
But if you get this from here in a big endian format, you will get that 0XAA, uh, zero zero.
So you remember the one is less significant bite and the other is more significant bite.
The same one applies here.
Um, yeah.
In the D word.
We get the same here.
Just changing the A's and it wouldn't change anything here.
But in the D word here again it will change to 0XAA00000.
That is what, uh, the most difference is the least significant byte.
Little endian, uses the least significant byte as a starting point, and the big endian uses most significant
byte.
That's it.
How it, uh, how the indigenous and memory addressing works.
Uh, in computing, uh, doesn't matter if it's an x86, ASM and ASM or any other programming languages
or, um, assembly languages here.
That's basically how the CPU central processing unit or computer processing unit.
Some call that functions and yeah, that's it with our, uh, lecture.
Uh, thank you for watching understanding memory addresses and how data is laid out, uh, in the Indians
is crucial for reverse engineering and low level programming in the x86 world.
Uh, little endian is the standard.
Uh, so, uh, the most you will see, it doesn't matter if it's a Linux or Windows, you you will get
the least significant byte for byte first in the most cases, especially in x86 world.
Uh, but it is also used in some uh, micro processing units, uh, which will be explained later.
But yeah, the the most, the, the most uh, difference is the LSP, which is least significant.
Five starts from the left to right and the most significant right or right to left.
And yeah, now this is, uh, and this also affects how we interpret data from memory and how instructions
interact with it, which is very important here.
So if you, uh, read from the left, it will have a different meaning.
If we don't know this is a big endian or if we on the little endian, if we read it from the right,
it will have a completely different, uh, value or meaning, uh, for the instructions and or the values.
Doesn't matter right now.
Next time you load a program into a debugger or a disassembler, remember, behind every value there's
a memory address that we explained in our previous diagram.
And how you read it depends on the endian format.