Hello, everyone.
So this session will be divided into multiple, I would say, videos, because it's a long one and that
way it will be probably easier to go through each one of them separately, understand it, and then
jump to the other one.
So I will divide them into maybe two or three, depending on how much time it will take me to the finish.
Each section of this session and again, it's going to be easier for you that way to go over each one
of them.
So in this session today, we will start talking about memory.
Now, this this presentation was prepared by me and my my friend, uh, shot in life.
So, uh, thanks to him, we did them a long time ago, but they are still very useful.
And I would say they explain what we want when we talk about exploitation.
So welcome to America.
And again, let's start this is an outline what's going to be covered, the topics here that we will
be going over them, some of them, I will move much faster than the others.
But the reason that they were covered in previous sessions, so don't expect me to dive deeper into
them.
But you can go back and check the other videos or our other sessions for further understanding, or
you can just check online references for doing that.
So software exploitation introduction, let's start here.
So at the end, a program is just a set of rules that they follow a certain execution flaw which tells
the computer what to do.
And those, let's say those those rules were defined by the developer of the of the program.
So the developer said, let's say he defined or he set these certain execution flaw that he wants to
do this.
It goes there, it comes here, etc. And then when you're on the program, that's what's going to happen.
But for us, our goal is to exploit the program or exploit the software.
So we want to get the computer to do what we want.
Even if the program was designed to prevent that action.
So this is also part of the definition from the art of exploitation.
Now, I know the art of exploitation is probably an old book and talking about when we compare where
we are today.
But still, it has the basics, the basics.
And it has, I would say, more than the basics.
Actually, it has the core for software exploitation.
And this definition is really what exploiting the program is about.
So, again, the developer created the program.
The idea was to have that program do something.
But we want we as let's say, software.
We want to do some exploitation that software or we want to exploit it or maybe even a threat actor
wants to exploit the software.
So the idea or the goal is to get the program to do what we want, even if that program was not designed
to do that or they want to prevent us from doing that.
This is not, by the way, something new.
Again, if anyone is interested in history.
This was documented back in 1972 by the US Air Force, so or by study in the US Air Force.
So it's not something new.
So it's seven, 1972.
That's a long time ago.
And still, with the new mitigation techniques that are being developed by, let's say, the which are
we will also talk about them even with those new mitigation techniques which are are being applied,
whether by the operating system or whether they are applied by your hardware or even the compiler itself.
Software, unfortunately, still today exploitable or we can still exploit that, exploit the software
or programs.
So welcome again to the memory lane.
Now, what's needed to understand exploitation?
Definitely.
You need some background with computer languages.
It's good to have at least the basics.
You probably need to be a professional professional in them.
It's good if you are, but if you don't at least understand them, operating systems is very important.
I keep mentioning that and I will continue doing that.
And architectures like understanding which computer are we targeting and let's say what what program
we are targeting and what hardware is it running on.
So those are the basics I would say, that you need in order to understand exploitation.
What will be covered in this section a little bit about C.P.U registers, because, again, we cover
those in a different session, how functions work, we will focus on this is very important memory management,
especially for the Intel three 32 bit architecture or Intel 86.
We won't be doing anything related to 64 bit of time if we have enough time out that at the end of our,
uh, our classes.
But for now, we'll focus on Intel, 32 bit architecture.
Also, we'll need a little bit about, let's say, assembly.
I assume by now you have a little bit of background with assembly and see at least understanding the
code.
You don't need to be, at least for now, proficient with C or assembly, but at least you are able
to read the code, understand it and understand what's going on.
Why do I need those?
Because at the end, security has come.
Most of them, I would say most of them come from from memory corruption.
So that's why it's very important if you have good background in what we just mentioned.
Now, CPR instructions and register registers, so the CPR at the end contains a couple or let's say
a number of registers depending on its modern architecture.
So whether the number of registers on a 32 bit system is on an exit 56, I mean, system is different
than when we talk about a system, 64 bit system.
So keep that in mind.
The number of registers will be different in this session.
We will be focusing on three main registers, which is the EBP, ESPN, the IP, which is the instruction
pointer.
And we'll talk about all of these.
So these are the main focus in this session.
Not that other registers are not important, but these are the main ones because we want to focus on
exploitation and how things are working, especially when dealing with the stack, something which we
will be seeing in a couple of minutes now at the end of the instruction is the lowest execution turn
for the CPU.
So we will be executing instructions while a statement is the higher high level term that is compiled
and loaded as one of many instructions.
So you can think of instruction as the assembly code and you can think which is being, let's say,
executed by the CPU.
And you can think of the statement, which is the program that it's written in C, but that that code,
which is written in C, it could be more than one single instruction.
OK, so a statement could be multiple instructions and instruction is just one single set of, let's
say, one one instruction.
It will be a one set of things to do.
Let's say let's go to let's call it that way.
Probably so assembly language is a human friendly representation of the instructions or the machine
code.
So assemblies, let's say, even though some people might say assembly is not easy, it is not easy.
I would say maybe it depends also on it depends on practice, really, I would say.
But it's the human friendly version of the instructions which the machine will be executing at the end.
The machine will be actually executing what is called machine code or bytecode.
We will also see those later in in this in this course.
Uh, adjusters, just a quick overview, as you can see, we have the 16 bits, 32 bits and 64 bits,
and we can see that each one of them, like when we talk about the AICS, which is the accumulator.
That's what it's called.
But it could be used for something else.
Backspace index, SCIEX counter the data, BP or SBP, which we are going to focus on 32 bit.
So let's talk about that, which is the extended base pointer.
OK, E.S.P, which is the extended stack pointer.
These are all 32 bit registers, IP, which is the extended instruction pointer.
And then we have ESR, an idea which are two pointers for when we deal with with strings or with data.
Now.
I just thought the system can also access, let's say we can access, let's say, lower and higher ends
of these registers.
So let's say we have the 16 bit, let's say the AICS, the 16 bit, which is a 16.
But we can access the lower worth of the apex register by accessing the A-L of that register, which
is called A-L.
So that way we are accessing the lower world of that.
If we want to access the higher world, then we will just go H and the same applies for X and the X..
OK, now these are again not the complete list of registers.
Again, like 64, which has more than more than this.
But these are just an example.
Now functions a high level view, we want to look at the functions, a high level view and see what
what makes a function or what is a function, what does the function consist of?
So here in this program, we have three different functions if we go to the the bottom, because that's
where, let's say, the program will first start, I would say at least for the session.
So integer, main integer, arctica stargaze and then those brackets, etc..
So this is the main function, which is the integer integer.
I mean, this is the main function.
And inside it we have some.
If statement, which is going to be checking if the argument is more than one, so we have a decision
to be made here based on the value which is passed on the value which is in our is the argument counter
and the argument counter is more than one.
Then we will be calling a function called My Fun One, and we will be passing the second argument to
that function.
Now, if we go to my function one or my phone one, then we see it's taking a pointer to a string.
Inside there is a character buffer of 16 bytes or we are creating a buffer of 16 bytes means our buffer
is 16 bytes long.
And then we are calling the CPI, which is to copy the value which is going to be passed into a store,
into our buffer.
So whatever value the user will be entering, it's going to be copied to the buffer.
And then that power is going to be passed to my phone, too, if we go to my funk to go up now again
we can see we get up.
It's a pointer to a value so we can see then print you and third percentages and and then X.
So what's happening here is, let's say when you enter when you were on the program and then you let's
say you send the argument like hello, what will happen is the program will take the value.
Hello or the string.
Hello.
It will copy it into the buffer and then it will take that value which is now in the buffer.
And it will send it to my phone too, and my phone will just print on the screen.
You entered.
Hello.
So that's basically how the execution will happen.
We will be running this code and exploiting it, but that's going to be in a later video.
For now.
I just want you to understand the code, which is which is over here.
So there's a high level view of of our functions now.
These are the function names, so as you can see, these are the function names and that's why we have
this color for we so we can highlight them.
Now, these are the parameters or arguments which are going to be passed to this function.
OK, these are the parameters, arguments to this function.
And as you can see, the slides were prepared in a way that you can you can, like, navigate them with
kind of animation or kind of, let's say, help you understand which one we are focusing on in the slide.
Now, this is the body of the function.
So each one of these, whether mean Myfanwy one might want to each one of them has a body that's the
body of those functions.
And then at the end, this is the local variable definition.
So as you can see here, only Myfanwy one in this example has some local variable definitions.
OK, and then these are the return values.
So when the function finishes its work, it's going to have to return something back so we can see means
is going to be returning back an integer.
My fourth one is going to be returning back nothing.
So this is the return type value.
OK, that's going to be returned by this function.
And now let's look at how.
The system will actually track the execution of this function, so let's say you.
Compiled this program, and now you are about to execute it.
We are not going to look now at the code from an assembly point of view, which is the lowest instruction
which we will be seeing, which the copy will be, let's say, executing.
But here we want to keep focusing on the functions.
A high level view of what see what will happen and how the execution law is going to be is going to
be done, how it's going to work.
But we want to introduce the concept of the stack.
So the stack is actually the best structure which the system could use to trace the program's execution.
And you are going to see why the stack is last in, first in, last out.
So when you put something into the stack and you add something on top of it, the first thing you put
there is going to be the last one to, like, take out.
You can think of it like the usually it's c some people might refer to it similar to the example of
some dishes.
So you have our plates, you have a plate and we put the first plate in the sink.
And then when you put the second plate is going to be on top, the third on top, top, top, etc. then
if you want to take the first plate out, you'll need to take all of the first plates which are on the
top in order to reach the bottom of them.
So again, it's first in, last out.
So that's what the stack is about.
And you will understand in when we go over the when we go over this why the stack is used for program
execution.
It's really good one.
So if the if the current statement is going to be executed, you'll see it in this blue color.
So let's start, let's say, executing our code.
So what will happen is first thing is the programming will start and it's going to be checking whether
the arguments counter is more than one or less or one maybe.
So if it's more than one, then now the execution is going to go to my fun one.
And we are going to pass the second argument to my first one.
Why is the second?
Because the first one, the zero is actually the name of the program.
So are one is actually the first parameter to be passed.
And don't forget that arrays start always with zero.
So the first member in the array is actually RGV zero, which is again the name of the program, and
then RGV one is a second, which is actually the first argument to be passed.
So again, let's say we pass the value.
Hello now.
Hello will be sent to my first one.
So what will happen is my phone one now gets pushed the let's say the position of my phone, one gets
pushed over onto the stack.
So now we are saving the position of my phone once we go to my first one.
Now, this is where the execution is going to happen.
Now we are going to create a buffer for the character buffer with 16 bytes executions continuing.
Now, I still copy.
Now, this one is also a function.
So we should be storing actually also the location, the position of SDR copy here onto the stack.
But for, let's say, making things simpler, we are just going to like jump over it and focus on the
functions which we have in our code, not the functions which are provided to us by the library, which
is which is as are copy is a function that you can use by the by by a library that you import and you
include you start to use.
So we are if we were to trace this one step at a time, then we will be adding the position of a star
copy to the stack and then continuing from there.
But again, for making things simpler, we are just going to skip this and assume it was done.
Now we are going to go to my phone to we are going to pass the buffer.
So the executions here.
My friend, to the position of that, we need to also push it were onto the stack, so we need to save
the position of my fund to OK before we go and start executing it now since we saved the position.
Now let's go and start executing so we get there.
Now we print the statement.
So this statement will print the hello message, which we allow word that we entered.
OK, now the execution has ended for my fund to where are we going to go back now?
The stock will be used to understand where was I and how can I continue from, where did I, where I
left from.
So we are going to pop out the value of the position which is now on the stock.
And as you can see, the the the the top value on the stock was the previous function we were executing.
So that's why the stock is very useful for program execution.
Again, what we need to do now is after we finished my fund to we need to know how we can go back to
where were we before we entered my fund to we were in my fund one.
So we need to understand, how can we go back to that again?
We are we are going to pop the position which is currently on the stock and then go go there.
So we pop there.
As you can see, there is really nothing left in my fund.
One, if there was, it will be executed, but there is nothing here.
So now what will happen?
We need to now understand where were we before we came to my fund one like what was the previous execution
thought that we were working on or we were executing or the system was executing before we started executing.
My plan once again will go back to the stack.
The stack will pop out the position of my fund.
One, it will tell me that the system that, hey, if you want to go back to the previous function,
the position for that is over here.
So it's going to pop that value out.
Then we are going to come here, finish the execution and then end of execution.
So that's how the program will start and the execution will end.
So we saw by looking at the high level view how the function will work, how the stack representation,
which is actually doesn't really exist in memory.
This is something virtual, OK, but it's used to it's used to for program execution.
And now we can understand how the program was executed and how the stack was used, actually, to make
sure once I go to another function, I know how I can go back to where I was before I went there.
And the same thing.
When I go to that function, I know how I can go back to the previous function and so on and so forth
until the program ends its execution, like you can see here.
End of execution.
So stuck in flames, there is no physical stuck inside the sepia again, it's something virtual instead
of the CPU uses the mean memory to represent a logical structure of the stack.
Again, this is there is nothing really in memory that is a stack.
It's just like it's not a physical part in the CPU or in memory that is being used to represent the
stack.
It's just a logical representation in in which is used to represent the stack.
Now the operating system reserves a contiguous role, memory space for the stack.
And that happens at the at the immediate start up when you start the application that the OS will reserve
that value for you.
OK.
And the stock is logically divided into many, many stock frames.
The stock is also logically divided into many stock frames.
Each frame will be created when we create what we call a new function.
We will come to this in a little bit.
Now, the stock and all the stock frames are represented in memory upside down.
OK, keep that in mind.
The stock and all frames are represented in memory upside down.
You will see in a in a minute.
What does that mean?
But for now, just think of it like that.
So that frames the frame is represented by two pointers, so we need in order to be able to trace the
dark frame and what's happening in the stack frame, we need to have two pointers.
One will be pointing at the base, which is the base pointer, and that's SBP, that's the register
SBP.
So that I just repeat, will always be pointing at the base of the other frame.
OK.
The memory address that is equal to SBP minus one is the first memory location of the stark frame.
Keep that in mind, EBP minus one.
This is just an example to which will always be pointing to the memory location of the is the first
memory location of the frame.
OK, now the stack pointer, which is a used by, let's say, the E.S.P, which is the registered E.S.P,
which is a stack pointer that will be pointing always to the top of the stack.
So the memory address that is equal to E.S.P is the top memory location of the stack frame.
Again, E.S.P will always be pointing to the top of the stack.
And again, since we our stack is divided into frame, you will see all of that in a minute.
So even if you can currently imagine how this is working, we will see it in some visual.
E.S.P will always be pointing to the top of that frame in the stack.
OK, when you push or Papa Value E.S.P register is going to be changing.
So when you push a value, E.S.P will change.
When you pop a value, E.S.P will also be changed.
So the register, which will be changing depending on when you add a value or when you push a value
to the stack, or when you remove a value from the stack by pop is actually the E.S.P pointer.
OK, the base pointer, which is SBP never changes unless the current stack frame is changed.
Keep that in mind again.
The base pointer will never change unless the current static frame is changed.
So if the current frame, which is active change, I guess change, that's when SBP will happen again.
All of this I maybe will say, what is this guy talking about?
That's probably true.
You'll understand all of this in in a in a couple of minutes when we go to some visuals and have an
idea about what's happening, that the static frame is empty when SBP value equals to ESPs value.
So that's when we consider that the static frame is empty.
Now let's go and look at this and see what what's going on.
Again, we like we said, we have the the stack.
It's upside down.
So that's why you can see the top of the stack is always going to grow towards the lower end of the
memory.
And the start of the stack are the base of the stack is always going to be on the higher end of the
memory.
OK, so when we push a value, when we add a value to the stack, it's it's growing towards the lower
end of the memory.
So what that means is the memory addresses will be decreased.
OK, keep that in mind.
And when we remove a value from the stack, it's actually the memory addresses will be increased.
Now, here you can see the the memories because I just put this one from 002, FMF, etc..
Now, this memory is always will be divided into two.
Let's say space's one is kernel space and one is userspace.
Sometimes this is for Linux will.
Let's say you use one gigabyte for for kernel space while the userspace will have three gigabytes.
Now all of that.
So this means we have four gigabytes for 32 bit application.
But keep that in mind.
This is all virtual.
But for every single application, you'll have a virtual address base of.
Four gigabytes.
OK, this could be changed, but again, this is the default, which for now we just want to explain
the idea.
So, again, you have the stack.
You can see here this there is a pointer pointing to the start of the stack.
There's a pointing pointing to this to the top of the stack again.
Remember when we add a value to the stack.
So when we push a value, the memory address is going to be decreasing.
When we remove the value, the memory addresses address is going to be increasing.
Why?
Because when we add we are moving towards the lower end, when we are removing, we are moving towards
the higher end of the memory that's continual.
You'll you'll understand more about this as we continue.
So stack and stack frames inside the main memory.
Again, this is the lower end at the top, you can see.
Not sure if you can see my my mouse.
This is where the lower end of the memory.
This is the higher end of the memory.
And we can see this is the top of the stack.
You can see this is the bottom of the stack.
So we can see here the stack has multiple frames.
So all the stack frames that frame newest frame.
So one note to keep in mind is the stack frame, which is frame index number zero.
Will be the one that is actually active and the oldest acronym is indexed as stock count minus one.
So again, the one that's going to be active will be the stock from zero, the one before it will be
like number one and so on and so forth.
So the new newest stock frame is indexed as stock from zero.
The older one stock for him one.
And the oldest stock for him is index stock frame count minus one and so on and so forth.
OK, so keep that in mind.
Uh.
Yes, so here we have one, two, three stack flames.
So managing stat frames, uh.
Let's see, yeah, let's let's probably stop here and then continue, yeah, we already have reached
one slides, so let's stop here and continue in another video.
So we'll start in managing stock frames and our next video.
Thank you for watching this one.