It doesn't make any sense. Oh, Idaho. Nice. Cool. All right, let's get started. OK, first thing, I'll recap a little bit the CTF. So I was super happy with everyone during the CTF time. And I especially appreciate everyone's patience with some of the challenges that weren't working or when the website itself wasn't working. So yeah, that was great. It was really cool to see everyone continue playing after the CTF was over. So we have, yeah, if we look here, you can see that I have the settings, I believe. Will I show you anything important here? Yeah, that's fine. So you can see kind of the settings here of all of the solve counts. So very good that all the teams solved strings. That was great. Then we can see kind of a nice distribution here of solves. So that was pretty good. Ooh, yeah. So no, there's no extra credit for this. Yeah, there may have been some extra challenges waiting, but we didn't get to all of them. So that's how it goes. Cool, which then leads me to, all right. OK, so I'm thinking about the final exam a lot. And I'm sure everyone else has been thinking about it as well. To be perfectly honest, if you think philosophically, the main reason why we have a final exam is essentially to force you to study the material that we've talked about since the midterm. Particularly the stuff we're talking about here about application security is really important, understanding x86 code, and especially these different types of vulnerabilities that we talk about here. So really, that's kind of my goal with a final exam, is it acts as a forcing function to essentially make students study some of this material at least a little bit. So and with that said, I know, let's say, probably, I think, I haven't thought of a good way to do a final exam that would translate nicely into online. And I know there's a lot of problems with online final exams. So here's what we're going to do instead. We're going to do essentially, so we're going to have next week, so a week, two weeks from now. What's that? I don't want to bring up my calendar. But the next CTF, oh no, it'll be in a week. So it's in a week, the 28th. So it'll be just like the previous one in class CTF. And what we'll also do is basically the same style report right up April 28th, April 29th, so the next day. And you would think, Steven, but that's actually not true at all. So what we're going to do is in lieu of a final exam, we're going to what I'm going to basically ask all the CTF teams to do is to create video walkthroughs of video. This will be due when's the exam of the final? What was it? It was the second? Is that right? I feel like this timing is wrong. Let me check on my phone so you can't see all the time. Yeah, the fifth. OK, great. Yeah, thanks. OK, and this will be due May 5th of this. Oh, do you spell that word? There we go. There's some combination. Yeah, so you'll do video walkthroughs as a team of N CTF challenges. We're going to decide basically after the CTF, depending on how the CTF goes. And so the idea is you'll make a video walkthrough describing what the challenge is, how to approach it, what tools to have, and then actually demonstrate solving it. So the idea here is I want you to put the effort that you would spend in this final exam studying the material into studying these challenges and being able to demonstrate and your network analysis skills, your reverse engineering skills, your pining skills, all of this stuff. And you'll be able to do this as a team in lieu instead of a final exam. So this gives you an opportunity to learn from your other team members. And I think we'll be much better than having a remote exam over Zoom or one of these other terrible proctoring software. Now it'll be N videos per team. So all right, it can be the number of videos doesn't really matter. Okay, let's take these questions one by one. So the number of videos doesn't really matter. It's the number of challenges. So you could film a video per challenge. That's fine. You can film one long video that's the challenges. If you don't solve any challenges, then that's a problem. So just like homework five, you have to actually solve the challenges. So what this relieves is, so if you'll notice, the CTF points are decoupled from the video walkthroughs. So the CTF will operate just as normally. You'll write a report describing the challenges that you solved and which ones you attempted to solve. Then after the fact, then we will tell you what were the end challenges to solve. Either tell you, we're not exactly sure. We'll communicate it'll be very clear which challenges to create video walkthroughs from. So maybe N, let's say N is a set. So it's a, there may be a choice from different ones. So the TAs already, Mars Day already went through in virtual recitation, one of the previous ones. But yeah, you can, and then you can, so let's see. Yeah, we'll specify the due date. It'll be on the fifth sometime. I don't want it to go to, yeah, what if the challenge is like the last one where we shouldn't finish all of them and will not be all of them. So that's fine. How do you balance people not participating? You're feel free to narc on them, put it in your read me, say that this person didn't do anything. You know, I'm happy to dock people points for that if the captain says so. Well, N be the empty set. I think you can guarantee no. Yeah, let's say, so maybe, I haven't actually, I think the undergrad TAs were on the call now. This is the first they're hearing about this. So, yeah, I can maybe ask the undergrad TAs to do another kind of like CTF prep class. I think that would be very helpful. We'll do. I'm looking forward to it. Cool. Sounds good. Yeah, so you can continue. Yeah, so the like, so this is why we're separating it, right? So the CTF write up time is in a day. So it's just about what you did during the CTF. And by the way, if you ask me private questions, it shows up in the chat for everyone. So don't think your questions are actually private. The other question. Okay, so, yeah, so the CTF, this is just for your CTF points. That's for the 2.5% of your CTF grade. And then the video walkthroughs will be in lieu of a final.  No, you can't see it on Zoom, but you can see it on the recording. Yeah, it shows up on the recording. Yeah, that's right. Okay, cool. Yeah, so no, I'm not gonna say anything about the challenges or categories or number.  So as a walkthrough, you either decide to make one group as a team or one individually, it doesn't really matter. Yeah, you can submit a Zoom recording, whatever. I think that's great, but make it beyond YouTube so I can see it. I don't wanna get just like 200 megs of video from all of you. Any other questions about this? And I'll try to post more clarifying details on the website. That's true. But you're an undergrad TA, you're not in the class. I don't have to worry about your recordings, Riley. That's fine. Yeah, you don't have to post it publicly on YouTube. You can post it on YouTube as an unlisted link and then just send us the link to that as long as we can view it. That's fine. Cool, all right. Then let's move on to now we gotta cover content. So to make sure you can solve those CTF challenges. So, okay. So now we've looked at so far, command injection vulnerabilities, file, path permission style vulnerabilities. And so now what we're going to look at is one of the most classic style of vulnerabilities that really traces all the way back to when kind of languages like C specifically were first created in, I believe, the 70s, if not earlier. That essentially, one of the key problems is, let's say we have some C code into main. And I need to store some characters, some buff 200, I need a buffer to store 300 characters. And I am going to say, so I can do kind of anything to this. The thing to think about, and you've all written C, C++ programs before, does anything stop me from doing a buff 400 equals C? Does anything stop me from doing this? Yeah, only yourself, right? So you have to actually keep track of how much memory you've allocated because there's no way for functions to know. So when you do things like, but this seems a little counterintuitive, because I can say what's the string length of buff and how does this function operate? So let's say I set, yeah. So let's say I did SCR, CPY, I believe it's destination source, buff, right? So this string length buff, how does this know the length of that? Yeah, it just reads this string and it says, okay, it keeps incrementing it until it gets to a null byte, a zero. So H-E-L-L-O-N null byte. And then it prints that out. So it fundamentally, in C, there's no way to know this buffer has 200 characters in it. We actually have to pass this length along with the buffer all over the place. And this makes things essentially kind of insane. And this causes these major problems right here. And if we think it again, and it always comes back to these types, all these vulnerabilities is what did the developer intend? They intended to create a buffer to store at most 200 characters. No, in C, they're pointers. So this is actually a character pointer. They're not really arrays. I think the major difference here is the compiler knows the size of this buffer, but at runtime it gets compiled into pointers. But cool. And then so, yeah, so there's nothing to stop us from doing this. And in fact, and so what we'll see is while the developer intended for this buffer to only be 200 bytes, there's nothing that enforces that we can't write past or before those 200 bytes. And this gets to actually the heart of, essentially all of the vulnerabilities. And one of the major ones in C and C++ is this concept of overflows or overwrites. So the problem is that there's no boundary checking on these arrays or these buffers. And so if we as an attacker can control what data is overwritten, we may be able to take over the program completely and make it do whatever we wanna do. So we can, and as we'll see, we can use this to modify data of the application. So we may be able to change variables in the application or alter the control flow, right? So we may be able to make the program go and do things that it wasn't designed to do. Really cool stuff. And this is part of actually the work we do in our lab is how to make exploiting these overflows basically completely automatic. So being able to analyze a program, generate inputs that crashes it, and then turn that input into something that is completely exploitable. And the other important thing that we'll discuss here a little bit, because we're not gonna get into it in detail, but basically there's been a lot of progress in designing different types of protection techniques. And there's a lot of different mitigations here, but still even with a lot of these mitigations in place, this is still one of the most popular vulnerability types. And it all comes down to, in order to understand actually what's going on, we need to talk about the stack. So here I'm gonna switch to kind of the view here. So we hopefully, and this should be more of a refresher about what is a stack in terms of a data structure, right?  And our programs as they run actually need this concept of a stack. And the way to think about it, and we won't get into all the things, but essentially you need scratch memory for a function, right? So you need, where does this main function store these bytes? Well, it turns out it's gonna store it on the stack. And as we'll see, the stack is actually used in order to do function call. So you can have one function call, another function call, another function. And so the CPU knows where to go back, which is a super interesting thing. But we can think of it and this is used, and almost all architectures have this notion of a stack. And the way we're going to always draw the stack in this class and all the rest of the slides, it's gonna start at high memory addresses and grows down. So it's gonna start at, let's say, FFFFFF and it's gonna grow down. And functions can basically store data on the stack as long as they essentially clean up after themselves. So as long as the stack is exactly where it needs to be when the function returns, then that's totally fine. So x86 natively supports this notion of a stack. So there's a register called ESP. This register holds the address of the top of the stack. And then there are x86 instructions. So push a register says, decrement the stack pointer. So move the stack pointer down and store whatever's inside the register eax onto the stack. And pop eax does exactly the opposite. It says essentially dereference ESP. So dereference ESP, grab whatever that's pointed to up on the stack and copy it into eax and then increment the stack pointer. So we're going up. So what this looks like, so we can use our example here. So here again, we have high memory at the top, low memory at the bottom. And let's say we have our stack pointer is pointing here and that memory address happens to be 10,000 hex. And what this means is, so remember the stack in our example grows down. So this means that everything above our pointer, our stack pointer is part of the stack, but everything that's below it is garbage. So to get rid of something, we just move the stack pointer above it and now it's garbage and can be reused. And if we need more memory, we move the stack pointer down. So we'll just walk through a very simple example of, so the heap is very, very far underneath the stack so far that we're not going to worry about it right now. So what we're going to do, so we're going to look at a very simple function, push eax, pop ebx. And so semantically, what should the, what should these two operations do? After we execute these two instructions, what should happen to the registers eax and ebx? Yeah, so it's essentially a copy, right? So it's copying what's inside eax to ebx using the stack and so we'll see exactly how it does that. So here we have our registers, we have eax, let's say it has the value hex A or 10, we have ebx, hex zero and ESP. So what's the value that's going to be an ESP based on this diagram? Yeah, hex 10,000 remember, right? So it's important that we get our essentially units correct, right? But here we have 10,000 hex and we know this because we're saying that pointer points to there, right? This arrow, this blue arrow, if I said this is the stack pointer and this is that address 10,000 hex, the only way that makes sense to the system is if the value 10,000 is in ESP, right? They're inextricably linked. If I said the stack was at any other value, that means was at any other memory address, that means this ESP register must be whatever that address is, does that make sense? Cool, okay. So now we're going to walk through this kind of step by step. So at the first one, so this is the kind of the state of the computer and we're not getting into it yet, but you can think that there's another register that we're not showing called EIP, the instruction pointer, and it will point to this memory region and that's how the CPU knows what instruction to execute. So we look here, then it's going to execute a push EAX, so our instruction pointer will increment and we'll go through the exact semantics of push EAX. So what were those? So first things first, how did EAX get 0XA in it? Because I said so, right? So I'm saying that EAX has A in it at this point, EBX has zero and ESP has 10,000 hex. So it's like pretend like I'm setting up the system like this and these are the next instructions we're going to execute. So first things first, I'm going to decrement because I'm pushing something onto the stack, so the stack is growing down, so I'm going to decrement it by four. So now the stack pointer is going to be FFFC. Why four? Why did it decrement it by four? Yeah, it's the size of the register. Wow, there's a, no, a byte is eight bits. Registers are four bytes, 32 bits, yeah. So it has to move down by four bytes so that it can store a 32 bit value there. Cool. So FFFC. And there we go, okay. So then, and then the last thing that happens with the push is whatever's inside EAX gets copied to that memory location. So essentially in our diagram, at memory address FFFC is a four byte value that will be in little endian but will translate to the integer zero XA. So that's one instruction. So all those things happen when the CPU executes our one push instruction. Now, when we execute the next instruction it's gonna be a pop. So a pop is gonna be exactly the opposite steps. So a pop is gonna say dereference ESP. So copy whatever ESP is pointing to, in this case it's A. It's actually memory address FFFC. What's there is the 32 bit value A. Copy that into EBP so we can see, sorry, EVX. We can see EVX changes to A and then increment the stack pointer by four. And again, the four is because of the size there. So everyone get kind of the simple stack operations, push and pop. So now we need to see and we're gonna go deeper to understand how the stack is involved in function frames. So in this case, no, EAX's value does not get changed by a push. So a push says store the value that's in this register on the stack and don't touch this register. Cool. So this is actually the interesting thing. Yeah, so if we look at this, right? So this is a good question. So pop doesn't actually modify the memory at all. The only thing that it modifies is the stack pointer. So remember, like we said, anything below the stack pointer is garbage. What's at FFFC, this zero X A value, that's essentially we consider that garbage even though it's technically still there in memory. So this pop is moving this into EBX. Yes, it's as if the programmer has deallocated it and we'll see how that happens with functions. So this is why we'll see when you have a function, your local variables are stored on the stack. So if you ever return from a function or reference to a local variable and then the stack that function goes away, that variable can change in very weird ways. Yeah, so destructors are about, essentially the heap operates in the same way. We'll see that essentially you can think of the stack is and local like function storage is kind of more automatic. The programmer doesn't have to explicitly deallocate that memory because it happens when the function returns. Whereas the heap, you have to do more manual memory operations and explicitly alloc and deallocate things. Cool. Cool. So we need functions need to allocate space for their local variables, right? We need to be able to reference inside of a function, local variables. And so one of the things to think about is, can we use the stack pointer for this? So can we say, okay, at different offsets of the stack pointer are different local variables? Yes, but the problem is as our function executes, our stack pointer could change. And so that makes things a little bit more complicated. So there's actually another register that's used that we'll see is called the frame pointer because it points to the start of the function's frame on the stack. So this'll make a lot more sense when we look at example. And essentially the compiler, when it compiles a function, it says, okay, all of these local variables are gonna be at different offsets of the frame pointer. And so every time I reference variable A, I'm gonna reference it at a certain offset of the frame pointer. So let's see what that looks like. The important note is on x86, the frame pointer is called the base pointer and it's stored in EBP. Yeah, so we'll see every function needs to have its own frame pointer. And the reason why is very important, let's see. So, anybody ever written a recursive function before? Unfortunately, come on. Let's see, if num is greater than zero, then, oh, I didn't give it a name foo. Yeah, okay, cool. So, I guess I can actually make this a little bit better in, let's call this local. I don't know, whatever. And then after this executes, we'll print out local. Okay, so little function, right? So we know kind of by reasoning through this function, foo, right? So main is gonna call foo. So if we look at the call stack of this, we have main and then we have, we'll draw something like this and then we have foo 10 and then we have that will eventually call foo nine and that will eventually call so on and so forth. The important thing to remember, right, is so each of these different invocations of funk foo have a local variable called local, right? A variable that's only accessible inside that function, each with a different value. So this is why every invocation of a function needs to have its own frame pointer because as we'll see here, that's how different invocations can know which one is their local. So that goes back to the question about, yeah, each function will have a different frame pointer and we'll actually see there's very cool mechanisms of making it so that you can call a function and it sets up the frame pointer correctly and then the next, the function that called you but when you return, you set up its frame pointer correctly but let's walk through this with a little example. Careful that's a function, Skylar, you may get a stack overflow. Okay, cool. So here we have a very simple function, int main. We have variables A, B and float C, right? So just three different local variables and it's a very simple function. A is equal to 10. We will get into, trust me, we're gonna get into exactly what everything does, all those instructions, yeah. So we're gonna set A to be 10, B to be 100, C to be 10.45. We're gonna set A is equal to A plus B and we're gonna return zero. So incredibly simple function. And so essentially what you can think the compiler does is it goes through all of your local variables, A, B and C here and it's gonna just create offsets for them from the base pointer. So internally it says, aha, I am going to have, I'm gonna say that A is at E, B, P plus some offset A and B is at some offset of E, B, P plus B. Same with C and then these memory operations are incredibly straightforward. So this A is equal to 10 is essentially set the memory address at E, B, P plus A to 10, set the memory address at E, B, P plus B to 100, set the memory of E, B, P plus C to 10.45 and then set them and finally this is the A is equal to A plus B and then the return. And so what the compiler does is then figures out what these offsets are. So for reasons that we'll see in a second, all of these offsets will actually be negative. So A, and this is actually from a version that I compiled. So it says A is at E, B, P minus C, B is at E, B, P minus eight and C is at E, B, P minus four and this is just how the compiler did it. So then there's some setup here for the function that we'll get into in a second but then what we can see is this A equals 10 gets directly translated to the assembly instruction move hex A into E, B, P minus C, right? So this is what it was important to understand the displacement syntax here. So here we have E, B, P minus C. The next instruction is just B is equal to 100, move hex 64 is decimal 100 into E, B, P minus eight which we know is B and then move hex 41273333 into EAX. What's this hex value? Yeah, it's the floating point representation of 10.45. Yeah, that's great. So you can look up IEEE floating point format to figure out exactly what that means but then it moves it from EAX into E, B, P minus four and then finally the return zero or no, it has to add them together, that's right. So first move EAX into, no, no, sorry, I'm getting it backwards. Okay, yeah, E, B, P minus eight. So this is move B into EAX and then add what's in EAX to E, B, P minus C which is A and store the result in A. Some interesting things in case you're wondering why does it take two operations to move this floating point value into C into E, B, P minus four? Any thoughts? Yeah, so this value right is 32 bits. This move instruction, well these move instructions are smaller values, there's a move instruction to move those into a memory address but for a value this large, you can only move it into a register. So yeah, it takes two operations to do that. Anyways, the other answer that's always appropriate when you say why did the compiler create this output is because the compiler decided to do that. There's actually many, many different ways to do different types of things. So depending on what compiler, what version, you may get different output but it usually, it should be semantically the same. Cool, so then let's look at what this actually looks like and what our function frame looks like. So we'll walk through this. So we have high memory, low memory and we'll start with our stack at 10,000 hex and we'll start at this instruction. So I haven't covered these two instructions right now. Because we're gonna go into it more in depth but essentially what this is is the start of every function has to set up its base pointer. So what we're doing, so right now when we get called, the only thing we let's say know is the stack value ESP but we don't know what's in the base pointer because somebody else called it and we don't know what's in the EAX or maybe any of the other registers. So what we're first gonna do is set things up. So the first thing we do is move the stack pointer into the base pointer. So now the base pointer points at hex 10,000 hex and now essentially you can think of it, we need to allocate memory for our function frame. So we do that by moving the stack pointer down and that's exactly what this next instruction is, is essentially move the stack pointer down by hex 10 or decimal 16. So move the stack pointer down and now the stack pointer points here and the base pointer points still up to 10,000 hex. So all that did was essentially and now we can maybe see why. So the base pointer is at the top and so negative offsets from the base pointer will always be in allocated memory because the stack pointer was moved down, cool. So now we're just gonna walk through this. So we first move a hex A. Yeah, so what are the extra four bytes for? Great question. The short answer is because the compiler decided on it and the longer answer is the compiler decided on it because on some architectures you need your stack pointers to be aligned at a certain memory alignment. So even though we only use three 32 bit values in our memory because we have A, B and C, those are our three values, the stack pointer decides to align or the compiler decides to align the stack pointer at this value. Yeah, and usually there's options you can set and change things like that, but that's what it does by default. This was a version of GCC a while back. And so we can actually see each of those different memory locations here. So this is the address. And so now what we're gonna do is move hex A into EBP minus C. So look at EBP minus four, minus eight, minus C. So it should copy A into that value in memory. There we go. Move on to the next instruction, 64 into EBP minus eight, 64. And then finally that two-step process to move 10.45 and floating point to A. So first into, sorry, into what was our variable C and is now in EAX and then move that onto the stack. And so now actually we can see the layout of these variables in memory. And this may be, I mentioned it briefly a while back and hopefully you've kind of seen some of this as you've looked at the reverse engineering challenges. This is why it's so difficult to kind of understand a program just from the assembly, right? Because when we looked at that C program, it was very clear we had these different variables named A, B and C, but once they get compiled down, all of that semantic information about their variable names, everything goes away. And all we have are offsets of the base pointer to see that these are different variables. And so one of the important things when you're trying to understand a function and look at it is anything, any reference to a base pointer minus some value is gonna be a local variable. So then we look here and we see, okay, what's the next step that happens? Move EBP minus eight. So EBP minus eight is B. Move B into EAX. So EAX now has the value hex 64. And now add, and remember, add is kind of an interesting operation. It's add the first one with the second one and store it in the second one. So this is add hex 64 into EBP minus C. So this is doing A is equal to A plus B. So we're taking B, we're gonna add it to A and store it in A. So we do that, it becomes 6E and then we're done. Questions on this example? Cool. Okay, so as we saw, we can allocate memory for the function's local variables, but we also have this other question, right? Of other types of things, even we can see in this foo example, right? Every different copy of foo has a different argument. It's num argument. So how does that work? And so we need to think about there's, so we can, we saw how it allows us to allocate memory for the function's local variables, but there are other things we need when we're calling a function. We, for instance, where do we put the return value, right? How do we pass a value back from a function to the function that called it? How does, when I call a function, how do I actually specify the parameters to that function? And this is the kind of really kind of cool thing. If we think about the CPU, if we think about the CPU, right?  These are registers that control, so ESP is the stack pointer, whatever that's pointed to is a stack, EBP is the current frame pointer, and EIP is the instruction pointer, right? CPUs are very dumb, right? So once I change, if I jump somewhere, like if I jump from, if I jump from, when I call from main, when I call foo, and then when foo calls itself, essentially the, how this has to happen is the EIP, the instruction pointer gets changed to foo, but we need some more information. We need to know how do I go back and where do I go back to? Who called me, right? So we need information about where do I start executing from? And so we'll see that all of this information in order for this to actually happen, we need a calling convention. So we need a way of how does one function call another? So we need to essentially store information on the stack in order to call functions. And again, it's really essentially arbitrary. There's, I guess, different trade-offs that you can kind of go into if you want about different ways of doing this. Different architectures, as we'll see, different OSs have different ways of doing this. But basically, we need to look at who calls what. So does the caller call store information? Does the call E? And so we need an exact, precise convention about who stores what in order to even call a function. And it varies based on the architecture, the operating system, the compiler, or sometimes even the type of call. So what we're gonna look at now is, let me move this on the way, there we go. What we're gonna look at now is the Linux, so it's x86 Linux calling convention, Cdecal is what it's called. And these are precisely defined, you can go look this up, and it really helps in understanding what's going on. And in particular, and what we're trying to get to is what happens when you're able to corrupt memory on the stack? And how could that allow an attacker awesome and interesting capabilities? So the caller first does, in this order, pushes arguments onto the stack in a right to left order. So arguments are pushed onto the stack first from right to left, then they need to push the address of the instruction after the call. Right, and this is because when we call that function, we're gonna now start executing some code. When we're done with that function, the CPU has no way of knowing where do I go now, right? It's very dumb, it just goes and executes whatever you tell it to. So we need some way to say, hey, after you're done, execute this next instruction in the function that called you. Then when a function is called, so the call E, will first push the previous frame pointer onto the stack because it needs to set up its own frame pointer. It then creates space on the stack for local variables as we saw, and then ensures that the stack is exactly consistent on return and then places the return value in the EAX register. So let's look at this in action. So here we have C code, we have our int main, int A, we're gonna call some function, pass it the values 10 and 40, set that to be A and then return A for main, and the function that we call has two integers and we're just gonna return A plus B plus one, right? So pretty simple function. And so now we're gonna look at the exact code and how that looks. So when we look at this, main and main is not special. So main is just like any other function, it can be called. So a main, the first thing we need to do is buy that calling convention. We need to first store the caller's frame pointer, right? So we don't know what it is, but we save it onto the stack, we do push EPP. And then we use that trick that I mentioned earlier, we're gonna set our base pointer, our frame pointer to be wherever the stack currently is. And then we are going to move 18 hex down from the stack to allocate memory on the stack for us. And then we're gonna, as we'll see, we're gonna push the arguments onto the stack. So we're gonna push, this is 28 is 40. So we're gonna first copy 40 onto the stack and then 10 and then call the function call E. So we'll go over exactly the semantics of this call instruction in a second. And so this is the nice thing just like in programming, we call some function, it does whatever, and then we get something back and that something back is in the EAX register. So this means take whatever was returned from EAX, copy it into EBP minus four, then move what's in EBP minus four to EAX, leave and return, which as we'll see, leave essentially does the opposite of the prolog. I guess we can do that here. Leave does the opposite of these steps here and return returns to whoever called us. So we'll look exactly at all these semantics. But one thing I wanna call out first is why this, what's that EBP minus four in our function main? What does that value translate to in our C code? Yeah, it's the variable A. And why does it do these two instructions? Do you actually need these two instructions? Yeah, so the, it's super interesting, right? So we're doing this return A. So when a function, by our calling convention, a function puts its return value into EAX. So this last move, EBP minus four into EAX is doing that. But the funny thing is, and this is, this is the different optimization levels of your compiler. I believe these were compiled with no optimization. So in this case, this A is equal to call E1040 is these lines essentially. So this is saying, okay, I need to set A to be whatever's in EAX. So A is that EBP minus four. So I need to move whatever's in EAX into EBP minus four. What's the next instruction? Oh, return A. So I first need to move what's that EBP minus four into EAX. So different optimization levels can be done so that the compiler can look at this and go, oh, actually these two instructions do nothing, right? Because I'm moving a value from a register into memory and then back into that same register. I can just get rid of this. But you can see it's like a one to one straightforward translation of that C code. So let's look at that. So the important thing is to most functions as we'll see we'll have a prologue and an epilogue that will, so that are not kind of the meat of the program, right? So the prologue does all of those steps that we saw for C-deckle. It saves the caller's base pointer. It sets up a new stack frame for itself and it allocates memory and the epilogue cleans all of that up. So there's a question about, oh, how does leave no much to add? We'll look at leave. It's very clever and pretty simple but it basically just does this in reverse. Okay, so we look at callee and the really cool thing is because of the way the frame pointer is set up as we'll see arguments A and B to access them are going to be positive offsets of our base pointer whereas local variables were negative offsets. Yeah, great question. So how does, how do we, so the nice thing is we don't have to know the compiler knows. So if we look at main, what does main need? Main needs four bytes for A and then the question is you can see that main actually there was some optimization here rather than pushing values onto the stack. So pushing 28 and then pushing A it actually pre-moved the stack down more so that it would have places to put those on the stack. So the short answer is I have no idea the compiler just decided that it would be 18 hex on the stack, cool. Okay, so then the callee, this function stores. So again, the same prologue needs to store the base pointer, it moves the stack pointer into the base pointer and then it moves EBP plus C. So this is an offset. We'll see exactly what variable this is. I believe it's B. Yeah, and EBP minus eight into EDX. This is a way it's of adding. So it's load effective address Eax plus EDx move it into Eax. So add the Eax to EDx into Eax. Again, like I mentioned why it chooses to do this this way, I have no idea, probably performance reasons. And then add one to Eax. And now our return values in the Eax, we pop EBP and return. So what's one of the difference between the prologues and Apple, what's the main difference between the prologues in these functions? Yeah, that's the popping is the difference in the epilogue. But what about the prologue? Yeah, no subtraction. Why is that? No, exactly no local variables, right? So the compiler looks at this callee function and it says, oh, there's no local variables. I don't need to decrement the stack at all because I don't need to store anything locally on the stack. So that's why you don't have that subtraction. And as we'll see, this is why it can be slightly more efficient and it doesn't need this leave instruction. It can just do pop EBP. But let's walk through this and see exactly what this looks like. Okay, so we have our callee function. These are exactly the assembly instructions we looked at. We have our main and now there's a big difference. So why, so this one I looked at, it said call callee. But now when I'm looking at it, it says call8048394, why is that? Yeah, it's the address of callee, right? So now we're gonna execute this. We're not looking at it statically. So it's gonna actually be laid out in memory. So this is actually, I took, when I compiled this, I took the actual memory address locations of each of these things, right? So we can see when we call 8048394, as we'll see that essentially means go to 8048394. Okay, so we have positive memory, low memory. We have our stack. And surprisingly, what's kind of interesting is the only registers we actually have to deal with are EAX, EDX, ESP, EBP, EIP, and that's it. So from one run when I did this, the stack was at FD2D4. Ah, yes, so this gets into why are different instructions different sizes? So this is a very old architecture debate about risk versus sysc, like reduce instruction sets versus complicated instruction sets, I think. And essentially it's because of the way x86 is. So yeah, this is x86 instructions. So each of them are different sizes and that's what you can see here. So the delta between these tells you the size of that instruction. So a push EBP is one byte, whereas you can see different instructions are different sizes, which is cool. Okay, so I said the stack pointer is at FD2D4. And so the stack pointer is at FD2D4. And if the instruction pointer is here at the first line of main, that means that what's inside EIP must be 804, 83, A5, right? So, and one thing to think about is there's something in EBP? We actually have no idea what it is. We'll just say it's this value, but we don't really care what it is. It's just something called us. We don't know what's in EBP. Okay, so this is kind of the state of the world at the current point. Like what I literally did, I think was compile this at a breakpoint right at main and be able to see what's going on here and did it step by step. So, so we're gonna first do a push EBP. So this is the first part. Remember the, as part of the calling convention, the callee has to store the caller's base pointer. So we're gonna do that. So we're gonna push EBP so that decrements the stack and we're gonna store whoever called main's base pointer on the stack. We're then gonna move the current stack pointer into the base pointer. So whatever it was, it's currently pointing right here at FD2D0. Then we're gonna subtract 18 from ESP. So now the stack pointer moves down, but the base pointer stays at FD2D0. Then we're going to move hex 28, which was 40 into ESP plus four. So here's ESP is at FD2B8 plus four is gonna be here. So it will show up here. So we should have 28 there and then we'll move 10, which is hex A onto the stack pointer. So now if we think back to our calling convention, right, what I, as somebody who had to call a function had to do was to first pass, push arguments onto the stack from right to left, right? So if we recall, our function was call E, parentheses 10, 40. So what do we do? Look at the stack. We pushed from right to left, 40, 10. And now we're about to call this function. Every good question is up to here. Cool. Now what do I need to do, right? So the last part of the calling convention was that I need to store the address. I need to store on the stack the address that the program should go to, that the function should go to after we're done executing. So this is done in x86 with this call instruction. So called is very simple. It does two things. It's a push, so push, so question. After call E is done executing, where does main want execution to continue from? What memory address? Yeah, the next instruction, right? The next instruction is 80483BF, right? If it was 80483BA, it would just continue going in loops, right? But BF is the next instruction. So what we want to have happen is call E executes and then boop, it goes here. And the only thing that should change from main's perspective is the EAX register, right? So EAX should then have the return value of call E in it, but that's the only thing that should change from main's perspective. And so the way this happens is the call instruction does two things. It has an argument here and that's pretty clear. It's gonna set EIP to be whatever this value is, 8048394. So it says go to the top here and start executing from call E. But it also does a push the next instruction onto the address of the next instruction onto the stack. So what this looks like is it pushes onto the stack 80483BF and then changes the EIP to be 8048394. And now it's exactly as we were at the start of main. We're suddenly in a new function call E. And so we don't know who called us, but we know what we have to do is first store their base pointer, create space in the local stack if we need it, do our computation and put our return value in EAX. Okay. Yeah, so x86, to be perfectly honest, I don't know. There's some, you can look at the C. Dechle calling convention. There's all kinds of stuff about how to deal with values that don't fit in registers. There definitely is a way to do it. I don't know exactly what it is. It may be put it on the stack. It may be put it in different registers. Yeah. Yes, exactly. We're still in call E right now, right? And we still have all of the stack from before, exactly. And if we can look, what do we have currently right now on the stack? Well, we have what's on the top of the stack is the return address. We're gonna call this the return address, right? This is where we start executing after we're done. Above that, we have our first argument and then our second argument. And depending on how many arguments in call E will continue to have that. So I wanna talk a little bit more about this saved return address. It's kind of like, and this may be a little silly, but for the non-Americans, maybe this doesn't make too much sense, but hopefully you've maybe heard of the story of Hansel and Gretel, right? The abridged version. It's like two little kids that go out into the woods and that's like super scary woods. So they wanna be able to find their way home so they leave a trail of breadcrumbs when they go. And that way, when they wanna go home, they just follow those trail of breadcrumbs back. That's exactly the way you should think about these return values, right? So these return values, these return values on the stack are gonna be used as a breadcrumb for the CPU to be able to go back to the function that called it. So let's walk through and see exactly how that happens. So Kali executes. It first does a push EBP. So it has to store whoever called its base pointer. Why? Because it's gonna overwrite that base pointer register with what it's base pointer. So it overwrites that. It then moves ESP into the base pointer, setting up its base pointer, and then finally it starts executing. So now when we look at these and we see what's that EBP might plus C, right? EBP. So when Kali is executing, what's at EBP is the saved base pointer. And what's at EBP plus four is the saved instruction pointer. And what's at EBP plus eight is the first argument, and then 16 is the second argument, and so on up the stack. So this is how every function can be compiled to access its arguments, knowing exactly where it will be, right? It knows the first argument will always be at EBP plus eight. Cool. Okay, so walking through this, we copy EBP plus C, so 28 into EAX. And actually, before we do that, we can look and see that, okay, if we think about it kind of this stack location, so we think about the frame, right? This actually belongs to main and the next one belongs to Kali. And so that'll kind of help us when we're looking at these things, right? So, but let's go on from here. So we move, yeah, so we move 28 into EAX. Then we move EBP plus eight into EDX. So we move a hex A into EDX. We then add them together into EAX, hex 32. Add one to get 33. Now we're all done. So remember that Kali function was incredibly simple. It was return A plus B plus one, right? And where do we put that return value in the EAX register? We put it in the EAX register and then we, now we need to clean up. So we need to put the stack exactly where it was when we left off. So right now, and this is different because we didn't subtract the stack. We'll see how that happens in main. But what are we gonna do? We need to restore the base pointer. This is why we saved it on the stack because we know that nothing is gonna touch it. And so now what we do is we pop EBP. So now we're gonna take, so this pop EBP says wherever the stack pointer is currently pointing, copy that value into the base pointer. So essentially take the saved base pointer on the stack which was whoever called us and put it into EBP. So we walk through this. It will increment the stack pointer and copy that into the base pointer. And then now our base pointer points back up top to main. And now the only thing left to do is return. So the way to think about return, a return instruction is essentially a pop EIP. So what does that mean? It means take whatever the stack pointer is pointing to and start executing from there. And that's how we get our Hansel and Gretel breadcrumbs and being able to go backwards and find that next breadcrumb. So we look and we say, okay, where's the stack pointer currently pointing to? Copy that 80483BF into EIP. So it changes the stack, right? It's a pop. And now we get back to 80483BF. And now we look like, so the stack, remember where the stack pointer currently is, everything below it is garbage, right? So we don't care that there's all these values here. We just know that the stack pointer is exactly as it was when we called call E and we have our A plus B plus one into EAX. And then we just go on and start executing. So we move EAX into EBP minus four and then move that back into EAX. Now, I think technically with x86, you can't directly alter EIP like that. You can't do a pop EIP. You, yeah, I think you can only modify the EIP register through things like jump and return. Cool, okay. So leave does two things. And it needs to, the way that I think about it is it basically is one instruction that gets rid of these three instructions and does the opposite, right? So we had a push EBP, a move ESP into EBP and then a subtract 18 from EBP. So what a leave does is it says, okay, move the base pointer into the stack pointer. Essentially bring the stack pointer up where the base pointer currently is right here, which gets rid of this entire subtraction. It doesn't matter how much memory you've allocated. We're now, boom, moving the stack pointer back to the base pointer. And then as part of leave, then do a pop EBP. So then copy that value into there into EBP. So the leave will move. So first, yeah, we'll first change the stack pointer and base pointer to be the same value here. So they're pointing at the same place and then do a pop EBP. So then change EBP and increase the stack. And so what's at this memory address FD2D4? What's up there and why that I didn't draw it here in the diagram, but what is that? Yeah, so exactly, not exactly. Okay, so it's part of the calling function stack. Yeah, so it's the address of the next instruction, right? Because I'm gonna go return, so whoever called main, right? When they called main, they had to do a call instruction. There should be an address of wherever the CPU should go execute after that. And that's where we're gonna execute after this return instruction happens. Cool, so how are you feeling about that? Questions? Yeah, so I didn't draw it on this location because I, let's say I didn't know it or whatever, right? But at this return, main is gonna go somewhere else. And where that someone else is will be at memory address FD2D4. Just like at FD2B4 right here was where we stored where we should go after call E. So somebody called main and we can get, yeah. So leave is, let's see, we'll take this one at a time. So leave says it gets rid of it by saying, okay, I know where the base pointer was. The stack pointer may have moved a ton. I don't really care. Just copy the base pointer into the stack pointer. So bring the stack pointer up to where the base pointer is. First do that, and then do a pop EVP. So then move whatever was there into the base pointer. And now in two steps, we've been able to undo these three instructions in the prologue. Does that make sense, Ethan? Yeah, and the other important thing is like the wiping away, it's, again, it's more of a conceptual thing, right? As we can see, and this is why on this diagram, I didn't change the memory here because the memory doesn't get wiped or get changed. The only thing that happens is the stack pointer moves. And so now if you think if we called another function or whoever called main calls another function, it may use the stack, but it's free to do so. Yes, so the stack frames will be kind of on top of each other like this. Okay, there was Andrew. So pop EVP assigns EVP to it. Yes, it's part of leave. Yeah, exactly. So part of leave, and so we can maybe compare callee and leave the prologue, right? Callee just did pop EVP return because it knew, the compiler knew because it didn't subtract the stack that EVP and ESP were exactly the same value. So instead of a leave, for efficiency reasons, decided to do a pop EVP and then a return. Yes, exactly. So yeah, Eduardo, that's a good point. So yeah, this is us, part of this leave, just like callee did. We said right when we started main, the very first thing we did was store whoever called us base pointer. So we first store their base pointer. And then this means when we leave, we need to set their base pointer back up. And that way they can start executing just like, and the nice thing is it's all, I don't know if it's, you wanna call it nice because it's like recursion or whatever, but the nice thing is these ideas don't change. Like every function invocation is essentially exactly just like this, right? So here, callee had its own base pointer here, right? Its base pointer was at 2DFD2B0, but it's returning. So it says, okay, whoever called me and to set up their frame pointer. I don't know who it was. I don't know if it was main. I actually don't care who it was. What I do is whatever value I originally pushed here, I'm gonna pop it and set it back up. And then that way, when we get back to main, the everything, all of the registers, all of the stack, the stack pointer and the base pointer are exactly where they were right before we called that function. Cool. And so we need to do the same with main. So what we're going to get into on Thursday is to see how data being copied without checking bounds, essentially the idea is if we're able to alter data on the stack, what happens if we corrupt one of these breadcrumbs on the stack and are able to change it to be whatever we want? And how could we do that in order to execute kind of code of our choosing? And we can basically make the program go to any instruction that we want. But we'll write a good stopping point right here. When we come back, we will get into stack overflows here. Cool. All right, thanks everyone. And yeah, get ready for the upcoming CTF. I think it'll be very fun. See ya. No, no, CTF's on Tuesday. Lecture on Thursday.


Hi, my name is Tracy Tucajones-Pinoza and I want to welcome you to our new course, Effective Online Teaching Planning for Differentiation. In this course we have four modules and the first we're looking at the concept of bundles or many libraries or ways to create a stock of resources for a classroom as opposed to just a single textbook. We'll be looking at some of the traditional types of resources you might already use, worksheets, readings, videos, but we're also going to talk about some new digital resources that you might not be as familiar with, including different types of platforms, apps, and gamification. In module two we'll be looking at this variety of tools and talking about their pros and cons. You know, what are the benefits of using some of these in the drawbacks that might also exist and how you can go about choosing the right balance of these different tools for your particular class. In module three we'll be considering this wide range of students that you all have in your classrooms and to talk about differentiation and how we actually meet those needs either through differentiated instruction or through differentiated evaluation. So we're going to talk a lot about how you can differentiate homework, which is a less known concept, by leveraging the information that you put into your bundles. And in the fourth module we'll be looking at the different resources and how to find them online yourselves. We'll be giving you a list of more than 600 different apps and games and resources and platforms that are possible, but we'd like to, you know, sort of teach a man to fish. The idea here is that you learn those basic skills yourself. So in the future if you need to modify or tweak your bundles you can certainly do that on your own. I am really looking forward to working with you in this course. If you have any questions before we begin please go ahead and send me an email. Looking forward to seeing you soon.


Welcome back everyone. Today we're going to give an introduction into computer hardware. So this is a CPU. CPUs are really complicated actually. And they're super interesting, but we're not going to get too much into them. Basically, CPUs have extremely tiny capacitors inside. And the more capacitors you can fit inside a CPU, the faster or the basically the better it works, the faster it works. A CPU, its whole job is to process. It's basically a very simple calculator. You can think of it like a calculator. So all of the data in the computer needs calculations to know what that data, what we should do with that data. So for example, to even show the mouse on my screen or even to show this screen, the processing unit is processing data and then outputting basically the command to the video card to show this on my screen. So the central processing unit is kind of like a calculator that does all of the calculations and says, okay, this is the output that you need to put onto the screen. And then it sends that through a bus. The graphics card processes that output or interprets that output and outputs that to your screen. Or if I move my mouse, then the processor says, hey, the mouse is moving, I need to move the mouse on the screen as well. So the processor basically computes and commands everything in the computer, what it should do and how it should work. These sticks are sticks of random access memory. Random access memory is you can think of it like almost like a notebook, right? So if you're trying to do math, and you have a really complicated problem, then you can write down the math problem in a notebook. And then you can work on different parts of the problem in your head, and then write the answer to certain parts of the problem, and then maybe write down a number in your notebook and then get another part of the problem work on the other part of the problem, write that down in your notebook and things like that. So you're not working on the entire problem at the same time. And your notebook is kind of like a temporary storage space for the math problem. And in computers, it's exactly the same. So RAM acts as a very fast temporary storage, fast temporary storage. So we load data into RAM, and then the processor takes parts of the data and does calculations with it, and basically sends the data back and forth between memory while it's working on it. So RAM is a temporary working space to hold programs or program data for the processor to work on. Now, what kinds of things are loaded into memory? Well, any application that you're running in your computer, the data has to be loaded into memory, that way the processor can work on it. So if you load KakaoTalk or you load Microsoft PowerPoint or something like that, that program's data is loaded into RAM, and then the processor can work with that data and configure it to how it should work. Yeah, so RAM is just like a temporary working space that can hold certain amounts of data for the processor to work on. Other things that are inside RAM are like passwords. So anything you type into your keyboard also goes into memory. So a lot of criminals steal data, like credit cards or passwords or things like that, by looking at your memory and trying to collect memory that has maybe sensitive or secret information. If you open up a picture on your computer, then that picture's data is loaded into RAM, that way the processor can use it. So basically everything that we run on our computer is loaded into RAM. Now, where is the data coming from? Well, the data is coming from hard drives. We store data on hard drives, and that if we shut our computers off, hard drives can keep the data for a very long time. If we shut the computer off, RAM is cleared out. RAM only works whenever the computer is on and has power. Hard drives store the data for a very long time, even if there is no power. Now, this type of hard drive is called a hard disk drive. So if you look into your computer, you'll probably see this kind of big square-ish box, okay? And inside this big square, well, first off, this box is the hard drive itself. There's kind of a protective container on the outside. You do not open up these hard drives. This is a SATA connector that would connect directly to the keyboard, and then these are jumpers that tell the hard drive a little bit about how it should be configured. But basically, we just plug in a SATA connector, and that's it. Yeah, SATA connector to the motherboard, and then the motherboard would be able to see the hard drive. Now, if we did open up this case, then inside we would see a bunch of disks. They kind of look like CDs, but they're just made of metal. So in a hard disk drive, we store data magnetically. So you can see this arm, and this arm has a head. And basically, this arm and head can change the magnetic fields on this metal disk. And by changing the magnetic fields, we can store ones and zeros or data. So your hard drive is storing, most likely, on desktop computers, your hard drive is a hard disk drive. They're relatively cheap to store a large amount of data, but these are very slow. So RAM, for example, is very fast storage, but it's very expensive. Hard drives are very slow storage, but they're very cheap. So we use a combination. We use hard drives to save the data, and then whenever we need the data, we pull the data from the hard drive and load it into memory. And basically, we just read magnetic signals off of these platters or these disks. Another type of hard drive that's newer and faster but also more expensive are solid state disks. And inside its case, it looks something like this. This is also a SATA connector or E-SATA connector to the motherboard, or SATA connector, sorry, the SATA connector to the motherboard. This is inside a case. If we open that up, then it just looks like chips. There's no moving parts where if we go back, these disks spin. And because they spin, there's a lot of moving parts, like this arm will actually move back and forth, and these disks will spin. On solid state disks, nothing moves. It's just chips. But it's also more expensive to use. It's also more expensive to store data inside these chips. Now, both of them work pretty well. Hard disk drives will store data a little bit longer, but it's possible that some of these motors break relatively quickly. On solid state disks, sometimes the chips, if you keep using the chip over and over and over again a lot of times, then the chips will start to go bad. So if you have a hard drive where you have to write a lot of data over and over again, hard disk drives are probably a little bit better, but they're slower. Solid state drives are really good if you're writing data really quickly and you don't change the data very often. But they're both pretty commonly used now, and most people keep their computers for maybe two to five years. So it's unlikely that a solid state drive is going to go bad that quickly. Next is a video card. This is a newer type of video card, and it basically is almost another computer inside your computer that focuses only on video. So whenever we go back, I'm going to go back a little bit, the processor that we have in our computer normally is what we call a general processor. It's used for general processing. That means that it can handle a bunch of different problems, but it's not really good at solving any of the problems. Now, processors are quick, but it's used for general purpose processing. That means that any problem that it gets, it should be able to handle. Now, if we go back to video processors, these video cards that we put inside an expansion slot, these video cards have their own processor inside. So this is a video card with a case, this is without the case, and you see this processor in the middle here. This processor is specifically designed to do math for video. So it is really, really good at doing extremely fast math calculations, but it would be really bad at running KakaoTalk, right? Because KakaoTalk is not video intensive. So its processor would be really bad at running something like KakaoTalk, but it would be really good at running extremely realistic graphics or rainfall or something like that. So there's a processor, and this processor is specifically designed to render video. So we can use this for a lot of different things. Basically, it's extremely fast at math calculations. Now, if we look at the back of it, there's a couple of different connectors. These are, it looks like a 2DMI connectors and then an HDMI connector, and then I'm not sure what this one is, but there's at least three monitors that I can plug into this video card. So you would plug this video card into your motherboard. The motherboard would detect that a new video card is available, and it would try to figure out what features this video card has, and then we could connect three monitors or more to this video card. Now, video card's basically just almost like a separate computer because it has its own processor, it has its own even RAM, but it's not good for general purpose processing. Now, what you'll notice from all of this is if I look at the motherboard, I can change the processor, I can change RAM, I can change hard drives, I can change video cards. So if you buy a computer, you can upgrade all of these components, and that was the original idea, actually. Most people don't upgrade their computers, they just buy a new computer whenever their old one gets old, but if you take your desktop computer apart, you can put a new processor in that's faster. You can put in more RAM, you can put in a new graphics card, you can put in new hard drives or more hard drives. So the idea of computers originally was to upgrade them, not throw everything away, because computers used to be really really expensive. Now, especially with consumer computers, people don't tend to upgrade their computers very often, but you can, and it's usually sometimes a little bit cheaper to upgrade it. So for example, more RAM might help your computer run much faster, and then you don't, you can spend maybe a hundred dollars instead of spending, you know, a thousand dollars for a new computer. Okay, so computers were made to be upgraded, and all of these components can be taken out of the motherboard, and you can add better ones in. Okay, now that's for desktop computers. For laptops, it's a little bit different. Most laptops, you can upgrade them at least a little bit, but laptops are more compact, much smaller. So for example, this is one of HP's extremely thin laptops, and it would be very difficult to upgrade this laptop without HP's own parts, basically. Now, if you notice, on a laptop, we have all of the same things as a desktop. So on the side here, we have speakers, we have a keyboard, we have a mouse pad, we have a monitor, and then on this, we also have microphone and camera. So microphone and camera, microphone and camera, input, keyboard input, mouse pad input, speakers output, display output, okay, but the computer itself has all of the same components. So let's look inside a laptop. So inside this laptop, and basically the monitor would, or the display would be about which side? Actually, I think the display is, it's probably closed and it's on top of it. So the display, this is the bottom of the laptop. This is where the battery would be. This is actually a relatively high-end gaming laptop. So this is for air circulation. Remember, the computer gets really, really hot, and this is a very high-end fan to make sure that the computer doesn't get very hot. This card right here is probably the GPU. Now, think about the GPU we just saw. This GPU is really, really big, right? But it fits inside a big computer case. This GPU is much smaller and maybe a little bit less powerful, but still quite powerful GPU. Here, what do we have over here? The processor is probably underneath here, I'm guessing, and then the RAM is here. Now, the RAM for a laptop is about half the size, maybe a little bit less than for a big computer, but it's about the same speed, okay? Processor is about the same size, maybe a little bit less, and then I'm not sure what exactly this chip is. I can't really see it too well, okay? So we have the GPU, we have RAM, we have the processor, we have a fan and heat sink, and then here is a hard drive, and this is a, it looks like a hard disk drive. So the hard disk drive that we saw for the computer is actually quite big, but the hard disk drive that we put inside a laptop is actually very, very small. So that's why laptops tend to have smaller size, capacity hard drives than computers or big computers, because the space or the size of the disk must be much smaller. So we have storage, we have RAM, we have processor, we have GPU, we have fan, okay? And then we have power, but the power is not in there right now. So all of it exactly the same components as a desktop computer, except in much smaller size. So with a laptop, it's a little bit harder to change components. You can change RAM pretty easily, you can change hard drive pretty easily, but changing the processor, changing the GPU, it's a little bit more complicated. Okay, and this brings us to phones. So are smartphones, computers? Yep, definitely, okay? So this is an iPhone, yeah, just a newer iPhone and newer Samsung. I don't know what this is. Maybe a s, I don't know, six, three, six, five, something like that. I don't know. So a Samsung phone and an iPhone. And let's take a look on the inside. So this is an iPhone from the inside. It has a battery and the battery takes up most of the phone's size and capacity, right? The battery is pretty much everything. If we take the battery out, there's, I don't think there's anything behind the battery. The entire phone, all of the processor, all of the RAM and all of the hard drive is in this chip right here. So this chip on basically above and to the side of the phone, this is one single chip. And that's essentially the entire iPhone is just this chip. And everything that we put inside the desktop computer is inside this compact form. So really, really tiny. That's why, well, that's one reason why phones are so expensive is because if we make chips really big, then they're easier to work with. We don't have to use really complicated, well, as complicated manufacturing methods. But if chips are really, really small, then we have to use more complicated methods to create these chips. So part of the expense of a phone is making these chips so small. Now that being said, you can probably produce a phone. If you were just building this phone, if you could just get the raw parts, it probably costs maybe, I don't know, $100, maybe less than that to make a phone. And then there's all of the cost of advertisements and stuff like that. But and research and development, all those things. But the actual cost to make this, especially in the millions of units, is relatively low. Down here is what they use, I believe, for the touch display, kind of a processor for touch display. And then some of this is just where power comes in, power converters and chip. Yeah. So this is the inside of an iPhone. The chip is actually really, really small. If we look closer at the iPhone chip, there's the camera. So this is a controller for the camera. And then all of this is, I don't even know which part is which, but basically all of this is the RAM, hard drive and processing unit. So everything is inside this chip that you would put inside a desktop computer. Now look how tiny these capacitors are. The manufacturing for these is very difficult and it takes a lot of research and a lot to get it working, basically. Now for the Samsung, same thing, you basically have the back end and then the case. And inside the case, there's not a lot of electronics. A lot of this is for, for example, the connectors for the headphones, connectors for power, connectors for, I think, the speaker. So this is a controller unit for the inputs on the bottom of the phone. And then all of the processing unit, processing unit, RAM and hard drive, internal hard drive is all in here. So this is a very, very small unit. And this is the entire computer. It looks very tiny, but it is super, super complicated. And that's why, one reason why it's so expensive. And basically upgrading this and making the circuitry better is why people are always coming out with new phones. So from a big computer to a laptop to a smartphone, all computers have some sort of processing unit, most likely some sort of RAM or temporary storage, and then most likely some sort of hard drive or long term storage. Hard drive and long term storage tends to work without power. And it keeps for a very long time. Temporary storage, like RAM, you have to have power to keep data in RAM. And then the processing unit speaks directly to RAM to be able to work on the data that needs to work with. So that's, I think, pretty much it. Yep, that's it for computer hardware and looking into a computer, a laptop and your smartphones. That's it for today. Thank you very much.