 Test test. Test test. Test test. Better? Can y'all hear me in the back? I'm in the chat now. I'm in first, so you don't get first. Okay. Hey everyone. Glad to see you all again after this long, long weekend away. I hope you missed me. I definitely did not miss you. I was only because I was there on the Discord with you. That's why I didn't miss you. I'm missing you in person, obviously. Yeah, cool. Okay, so as you are probably already aware, hopefully aware, talking web was due Monday. Let's go to the syllabus. Check where we are. Where's that so slow to load? Module one was due on the fourth. Module two is where we're going to put into action everything we're learning now with assembly. Let's do next Friday. So you got extra time on this. Please start early. Good question. Question was if we didn't finish everything. So this is something I announced on Discord. So if you're asking that, maybe you're not on the Discord looking at the announcements. So make sure you sync up to get all the roles there. But this is something that we did not have in the syllabus at the start that we added. So the late submission policies, so you can submit any late submissions will be 50% credit. So continue to solve those even if you're past the past the deadline. Yeah. Yeah, no, no, that's at the end. So yeah, we do grades and everything at the end. So just and we can always like fix that stuff too. So you go into a course here and you go into your grade. That should be all good. If you haven't like we just talked about aren't on the Discord and have your role set up, make sure you go to the setup link on the course page. You want to see five beautiful green checkmarks that will make sure that you have your role in Discord. If you don't have that, do it. I don't have it. I'm not a student in this class. If you look, that's actually the X that I'm missing because I'm not a student in the class. Yeah. Good. Yeah. Those are there for people that want to get started early. We'll cover everything you need to know. I think today we'll get through everything you need on assembly. We'll go over the challenges. I just wanted to release it early so that people who wanted to get started could get started, but you should have plenty of time to do everything. Yeah. For somebody with low experience in assembly, study the slides, make sure you understand things, go step by step. We will be talking about them in class right now and we'll be demoing how to approach these things and give you the tools that you need so that you can build up to these. Ask questions also. Yeah, back. Yes, we are definitely doing that today. Good question. Cool. Let's do 10% late penalty. Yeah, sorry. Lecture slides are all, oh, they're not, I guess they're technically not on the syllabus. Is that true? Maybe I didn't add them there. Okay. If somebody can ping me, I'll put the link to the slides there. Thanks, Twitch, for telling me. They are on the course module on the assembly. This is the internet that's low. How's the stream? Is it the website that's low? Where's Connor? I'm used to him there, so I can't. Okay. So on the assembly crash course. Question. How many assemblies or assembly languages have I done? Ooh, that's a bad error. Ah, did you just fix something? No. Oh, sporadically broken? Great. Great, great, great. Okay, question of how many languages have I done? Oh, god, that's an interesting question. I guess I learned MIPS in school just like you for undergrad and then I did x86 32-bit, normal x86, and then I had to learn x86 64. I've done ARM kind of. I can like look at ARM and understand it. I've also written my own assembly language for a data flow computer for a DEFCON challenge. So this is like where you don't have, you actually don't have any registers. You just say that data like to your operations is relies on previous languages and data like flows through the computer in this crazy way. So you can actually parallel execute as many instructions on the computer as possible as long as data is ready. Yeah, good question, I guess. Okay. Cool. So we went over the basics. Let's do this. Let's do, let's learn about registers because we already talked about this. I think this is just going into slightly more detail. Let's learn about, you can see that. They can see this. Okay, let's learn about registers and then we'll pop over and start attempting to solve the first challenge knowing what we've learned on Wednesday last week and what we just learned here in 10 minutes. Okay, cool. So as we talked about with computer architectures, CPUs need registers, right? They need to actually operate or I guess modern CPUs. I just said there's CPUs that you can have without registers. They usually need to operate on some data. And so where is that data? We talked about different places. What are some of the places that we talked about where data can be on a computer? Disk? Yeah, could be on disk. Where else? Yeah. Cash? Where else? RAM? Network? Right? It could be in many different places, but fundamentally to compute on that data needs to be in registers and registers are like, you can think of physically right next door to the CPU. And so that access is very fast. I don't remember the exact order of magnitude. I think it's what 10, probably 10 or maybe 100x faster to access a register than even RAM, even with very fast RAM and maybe 1000x. I don't know. These stuff is like actually crazy about how much faster that stuff is. And with like disk, it's 1000s times faster. Anyway, it's registers very, very fast. They are on the CPU. So as we talked about here, registers exist here on the CPU. We need to bring data in. Somebody mentioned caching, right? We talked about caching is essentially parts of the chip that will magically prefetch data from the memory or from other places for us, but we shouldn't have to think about that until it breaks. So as computer architectures evolved, there's just different names for these things. So two important things to kind of think about, there's the names of these registers and you can actually see, hear the evolution from, we said the 8085 was what, created in 1970 something, 76, 75? Nobody remembers this one specific detail I mentioned an entire week ago. You've forgotten that over a three day weekend and I forgot too. Okay. Sometime in the 70s because I thought it'd be the 80s. That's what I do remember. And originally they had registers with very simple names. Maybe some of you program like this. I would recommend not doing this though. A, C, D, B, E, H, L. Why shouldn't you use those as your variable names in your programs? Yeah, you forget what they mean. You forget what they mean because they have no semantic information. Although here with these registers, they're kind of, it's just whatever meaning are in these registers is kind of ascribed by you, the assembly programmer, but that kind of changes as we go further down. Yeah. Those are the special registers. So we will talk about that. So the 8086 extended these. So this is the AX, you can see now, instead of just having a single letter names, now we have two letter names, but they all have the same prefix, basically X. And then when, and actually like a, I don't know the exact progression, but as the register sizes got larger, we needed new names to talk about that. And we'll actually talk about why that is in a second. But this is the first systems had these original names. I know, I would guess this is a byte. This is two bytes. So eight bit, 16 bit, 32 bit, and then 64 bit systems. I may be wrong about the early ones. But the idea is when that when x86 was a release, which is a 32 bit CPU, which means it has 32 bit registers, they still wanted to use those same names, but said, ah, we already added something to the end. Let's add it something to the beginning to differentiate these. So you still have those same essentially conceptually registers of A, B, C, D. But now added an E, the E stands for extended, because we extended them before. I think that's true. See, now I just got myself in a trap because I don't know what R stands for. So I'm trying to make up something. I think like really large. Yeah, ridiculously large. That's good. We can go with that. And somebody can raise their hand when they look that up. Then with the move to 64 bits, now we need to talk about a register that's 64 bits. And part of the reason why you want to not use the same names, if you want to add new names is because you want to be backwards compatible. So if you have a very large register that's 64 bits, it can still store the 32 bits of information. So you still can run 32 bit applications. Yeah, good question. I think that's like technically how they are laid out. I don't know if that's specified in a manual somewhere, but good question. So the bolded registers are special purpose registers. So for all of these registers, they're essentially general purpose. So what they mean, again, means absolutely nothing to you, except as an assembly programmer. Four is we'll find out when you're writing C code, that's compiled to what? What was it? Yeah, the machine language, aka the assembly, right? Your C code is compiled down to assembly language. And when you're trying to let's say exploit a C program, you may need to understand what do these registers mean in relationship to this specific program. And we'll talk about those later. But so we need to have important concepts that we'll talk about of the stack. So the stack is a place where memory is allocated. It's just a register. It's special in the fact that on x86, there are specific instructions that will automatically adjust that value and change the value. We'll look at that later. The BP, the base pointer. So SP stack pointer BP base pointer. This is your where your function frame is located. You'll learn more about this in three 40, but we'll also kind of cover what this means. This is actually used by the compiler, basically when you compile a function, it needs to know where on the stack is that frame, but we can ignore that for now. And then arm has completely different things. So rather than using ABCD, whatever has numbers. Why? Who knows, because they just want to do this, like all this stuff is arbitrary, right? The important thing is not necessarily what it's kind of what these things mean and then has registers that mean something in insane numbers like R 13 and R 14. Now the other important thing is what instruction do I execute next, right? This is the fundamental idea of a CPU. You need to know where's the next address that I need to execute? Where must that information be? Can you keep the instructions in a register? How many instructions do your programs usually have more than eight? If you think of a byte is the smallest, you can think of a smallest instruction possibly can be as one byte. So if you're limited to all of your instructions fitting in one register, you would be limited to eight instructions ever, right? So we want to use memory for this. So the register is the instruction pointer. So that's how you can think of the IP, the instruction pointer. So the EIP for 32 bit is a memory address that is where the next instruction will be fetched and executed. People are, and this was extended for 64 bit to RIP. So we're talking a lot about RIP and we'll focus on these registers here. There's a lot of other extensions that you can actually add a ton of different registers, but that's not super important. Cool. So now the size. So this is what we talked about, right? Different sizes of architectures have different sizes of registers. We'll be focusing on 64 bit registers, which have, how much data can you fit into a 64 bit register? 64 bits. Yeah, it's in my question, but I just want to make sure you're slightly alive and responding. So now our programs, like I said, with partially because of backwards compatibility, we can actually reference this whole register in different ways. And this is one of the crazy things about assembly programming. And this, like I talked last week, that assembly is mostly easy. This is one case where it's not easy. So you can have the physical register RAX, which is how many bits? 64 bits. Yes. You can also write assembly code that references just the lower 32 bits of that RAX register. And that would be with EAX. They reuse the same names. Again, like I said, that way the code actually would still work because the code doesn't realize that the registers are bigger because it never had to think that registers were bigger than 32 bits. So you can reference just the lower 32 bits with EAX. This is something that is very important. So for sure, look at this. You can also reference just the lower 16 bits with AX. And then you can even split those and reference AH, the high bits of A. So it's the upper 8 bits or AL, the lower 8 bits. So this partial access also works with copying data out of a register. So if you want to copy just the lower 32 bits, you could say move into, let's say, register RBX comma RAX, or sorry, EAX. So move EAX, the lower 32 bits of RAX into the total size of RBX. We'll talk about more of that later. But so this is actually with, I believe, all of the registers, is that right? I think with almost all of them, except maybe RIP, I don't know if you can actually reference that directly. But for all the registers that you will care about, these are the ways to access the different aspects of there. So yeah, you don't need to memorize this. Like this is not to memorize. It's more important to understand the concept so that when you are either reading assembly code or writing, then you say, Oh, that's weird. It's moving something DL, but nothing was ever moved into DL. You'd be like, Oh, yeah, that's right. I remember. I don't know exactly what that is. But I can refer to this table and then I can figure out, Oh, that's the lower eight bits of the register RDX. That's how you use this table. Yes. Why does yeah, why does RSI not have a high? I have no idea. It could be backwards compatibility. Maybe there wasn't an SI register in when it had 62 or 16 bit architecture. So there was no reason to do that. I don't know the people who made this decided I'm sure they have a great reason. They're very smart people that design CPUs. So I trust in whatever thought process they have. But this is what, uh, what we're working with basically. Cool. Okay. Yeah. Equate shifts are right. So the question is there were instructions that we talked about last week of like shifting bits around so you could move, let's say the bits shift them right. Uh, if you reference in most cases, if you reference a lower 32 bits, it only affects those bits. So you can't affect the upper bits from doing something like that, except in one case, which I'll talk about very shortly. Uh, okay. So how do we get data into this? These are under search. We're talking a lot about them. We actually talked a lot about the different operands move is the operand that moves bytes. So again, remember syntax. We have our operation is move. We have two operands and we're using Intel syntax, which means the destination is what on this first instruction. RAX. Yeah. So we're moving the value a hex 539 into the register RAX. What does that do with the lower 32 bits of RAX, AX, HAL overrides them with what? With this value, right? So whatever this is in binary that's filled in here and all 64 bits change because we modified the RAX register, right? So if we then we're trying to access EAX, we probably get actually that same value because it's not greater than 32 bits. And if we got AX, we've accessed different things, but we clobber this whole thing. Cool. Similar things move 1337 into RBX, right? So now if you were asked a question like, Hey, what's the value in the RAX register? After these instructions execute, you'd be able to tell me because you can look at here. You can even tell me what's the value in the lower 16 bits of the RBX register. You could look at this value and then take the lower 16 bits there. You can just use the calculator app on your computer for wherever you like. So when we do this with these registers, when a data is in an instruction, just for consistency, it's the immediate value. So we will using that. So this is an immediate value. Why? Because it's immediately actually in the instruction. If you look at the binary of the instruction, this instruction says move 1337 and the value 1337 is literally in the binary code there. We can also load data into partial registers like move five into AH. This will only change those eight bytes of the AH register. So everything else remains the same. So if we didn't know what was in it, we still don't know what's in it, right? The only thing we'll know after this instruction of move five into AH is the fact that AH is now has the value five. We don't know anything else about it. We can also move 39 hex into AL. Similar thing, only the lower eight bits would change. Okay. And again, like I said, this is the one caveat that we're all staring at on the screen. If you write to the lower 32 bits with an EAX register, the CPU will zero out the upper 32 bits. This actually can come up when you're coding assembly and cause problems. So definitely keep that in mind. There are performance and also backwards compatibility reasons why this happens, that this way you can actually, I think, comix 32 bit and 64 bit code. So anyways, if you're curious, think about what happens if you're 64 bit code calling into a 32 bit library and you're expecting back a value that the library thinks is 32 bits. So it only sets the 32 bits of the register, but you're expecting a 64 bit value. Anyways, bless you. Okay. So you can, so this example here, move all f's into RAX, right? Hexadecimal, we talked about it. Hex, all f's is all of what binary value? Only two options. All ones, thank you. The other option is all zeros, which is zero. So all ones, and then if we change AX to 539, then the result of RAX will be this value. All f's and then the last 16 bits are zero, hex 539. Now, if we change this around and the last line instead moves 539 into EAX, that will wipe out all of the upper bits. So this is the thing to look out for. Is there a hand? Okay. Cool. Now we know how to put values and registers, right? We're like halfway there. All right, should we try the first level? Yeah. Cool. All right, we'll see if, all right, I'll use the desktop here. Okay, I will need people's help because I forgot to write down the exact commands, but I vaguely remember them. Terminal emulator. Okay. Can you all see that in the back? Yeah? Does that mean raise it higher or that you're good? Okay, cool. Cool. Okay. So what is the first thing we do when we are on a new challenge? Yeah, challenge run. There you go. Look at that. You guys don't even need me anymore, do you? Just set these up and go home. Okay, running the challenge. Welcome to assembly level one. To interact with any challenge, you will send raw bytes over standard into this program. It's okay if you don't know what those mean yet. You can always go look those up, but we will talk about them right now. To efficiently solve these problems, first run it once to see what you need. I guess it means run this challenge once, then craft assemble and pipe your bytes to this program. In this level, you'll be working with registers. Hey, we just learned about registers. You will be asked to modify or read from registers. Let's move this over so we can see this. In this level, I just said that, please set the following RDI to hex value. How do I know this is a hex value? The zero X prefix. Should I keep that in mind as I try to solve this? Is this the same as the decimal number one, three, three, seven? Oh, yeah. Yes. Look it up. It's an old, old hacker thing. I'm not live anymore. Oh, no, there's an error. Oh, that looks bad. It's a network issue. What can I do? Everyone off the internet. Okay. Mostly joking. Zero. Okay. Let's stop. What have we stopped streaming and then start streaming? Oh, there we go. Better. We're trying to get you back. All right. While we're gone, I obviously showed everyone how to solve all the challenges. So that was great. Okay. We're back to green. Thank you for letting me know. Okay. So please give me your assembly and bytes up to a thousand hex bytes. So we know how many bytes total we can send to this. Do we know what our goal is? Does anybody unclear about our goal? Yeah. So we want to write some assembly code that after it is executed, the value of an RDI must be that value that we're given. Okay. And I'm sure you've done this where your computer freezes and your network connection is bad when you try to talk to this dojo. Okay. We're going to kill the VNC. Sorry guys. I think low bandwidth alternative. Okay. Same thing. Why doesn't it say to work with registers use? I think it's just an internal thing and just telling you what, what registers it is in there. But yeah, that's a maybe Connor, you want to mark that down as a thing that we can fix. Okay. So jam on keyboard and then scroll up weirdly. Okay. Warning. It looks like your input might not be assembled binary code. Is this assembled binary code? Oh, this is just junk. I just randomly typed in the computer. It looks like your input may not be that, but actually assembly source. Haha. Jokes on you. It's not even that. It's just random garbage. This challenge needs the raw binary assembled code as input. So this may be what some of you are stuck on. That's what we're going over today. It's still going to try to execute our code. So if we were to look at all of these memory locations, we'd probably see the hex value of these bytes, J, K, L, F, G, G, D, S, J, K, L, semi-colon, blah, blah, blah, blah. I think those would all be in there. So, okay, but now we need to actually do this. So a couple of things we can do. Well, one thing we can do, this is before getting into it. So this is just, so the question would be how to, let's say I wanted to recreate this exactly. So it's reading from standard input. How do I get a program to read from, let's say like a file or something else as standard input? Yeah, I can use redirection. So on the command line. So I can use, there's a couple ways to do this. Let's say challenge run. So redirect the left arrow means whatever file I give after it, set that file as the standard input of the program. So I could actually just feed this into itself. I have no idea what this is going to do. Oh, that's it. Wait, how come that's not one? Oh, because this isn't something interesting. Five demos. Okay. Let's do this because we had an example that worked. So now I tried some things that didn't work. Now what I'm going to do is go back here, get to something that should work. I'm going to echo this into a file. So this is, I'm using redirection. I'm calling the echo command, passing the string, and I'm redirecting. So echo just writes whatever is in the, in the arguments to standard output. And by using the other redirection bracket, I'm saying whatever the standard output is of this program, put it to a file. So let's do temp test. Now we can do challenge run temp test. And hopefully it will give us the exact same output, which we're looking for. Yay. Okay. So it didn't get the flag, but at least figured out how to get input to the program. So if I cat temp test, I can look at that. There's a couple different ways to do this. You can write ultimately, so we're kind of working backwards, right? Like, how do I get my bytes into this program? Right now, I'm just inputting this string that I originally started with. So let's another way to do this. I have the echo command. So another way to do this is with the pipe operation. So on the shell, a pipe says, Hey, the standard output of the thing on the left, set that output as the input to the thing on the right. So this way, so if we do challenge run, now with challenge run is going to do it just again, the beauty of this, if you haven't seen this before, is that this challenge run program doesn't care that it's getting input from another process or that it's getting input from a file. All it knows is it's reading standard in and we're using this handy dandy shell operations to change where that's reading from data. So echo this in the challenge run, and I can get my data in that way. So several ways that we could do this, if I wanted to try like, I would not expect you to know this, so don't worry. The option to echo, if you look at the man page of echo, allows you to write hex characters like this slash X means I want a hex character. And I know 90 is a no op. That's just one of the things you learn doing security stuff. And so I should see three no ops in my code here. Yep. So no op does what do we think? Nothing, no operation. It's great. Literally nothing happens. Still can't get the flag with that though. But I'm feeding it valid assembly code, right at this point. Now, do we want to write our programs in hex like this? You can if you want that I guess would be super fun. You have to like, figure out, look at the Intel manual, figure out the compilation of the various things and then write it a hex by hand. But you're a computer scientist or you're in a computer science class, let's say, so you should not be thinking of doing things by hand. We have programs to do this for us. That's kind of the whole essence of what we're doing. So we don't want to do this ourselves. We want to write a assembly program. Connor, what's the magic stuff I need at the top? So I don't have to open up our DMs. Thank you. Okay. I think it's the syntax. Yeah, so this is all everything that begins with a dot is just the thing to the assembler giving it different commands. The dot means, hey, I want to use Intel syntax. The tool that we use AS, it will use AT&T syntax. But this says, hey, I want to use Intel syntax. The next one is dot global. And this tells it that, hey, I don't want to have to tell you the size of all the registers. You should be able to figure it out based on my operations. Okay. And this just says, hey, underscore start is something important that you should know about. Now this is looking at assembly syntax, a location. So just like you can specify kind of like functions, but it just says, hey, so this says, hey, if anything ask for dot start or underscore start, tell them and underscore start is here. Let's do. So let's do one of these examples from the slides because obviously what you all do is I show you something in class and then you go and try it on your own, right? Thank you. Okay. So we'll move all fs into RAX. And then we'll move this guy into RAX. So this was the example of showing that, hey, this should, what should we expect the value of the RAX register to be after these are executed? Yeah, zero, actually just zero x five, three, nine, right? So it should wipe out all of the ones in that. Okay, write that out. Now, so as is actually, I believe this is what's used by GCC when you act GCC is actually a collection of things and tools underneath. Now we're actually digging in and using those. Yes. So okay, great question. So the question is if the move operation uses different syntax for different register sizes, the answer is no. So you can just go in here and change this to AX, AL, whatever. Now, if I tried to do this to AL, what would I expect that to work? Why too big? Yeah, my argument here, my immediate value is too big. It's zero x five, three, nine. That's way too big. I have only eight bits to work with in AL, but I'm trying to move a value that's at least 16 bits. You may need to know prefix. Okay, we are not there yet. So I okay, back to AS. So this is the assembler. What does an assembler do? Yeah, so it basically just takes in our program. What I call this, ascend dot s. That seems bad. Ah, okay. So it actually didn't throw an error. That's bad, because you wanted to throw an error because this is wrong. And we'll go back. Okay, assemble it. Pretty good, right? Because then did I get an error? I can actually check if there was an error. This is a little bit more stuff, but a dollar sign question mark in the shell gives you the return value of the last process. And on Linux, zero means all is well. Basically, was there an error? So I'm looking at, nope, there was no error. I want to control where this output goes. So I'm going to use dash oh, I'm actually just guessing I could go if I didn't know where this output was, I would do man OS output, or I would look for another thing I would look for. Why is it more? Why is this man page weird? Why is it not less? Okay, great, cool example. Anyways, dash oh is an object file that you specify as output. That's a common thing on a lot of programs. So ASM dot oh, have any of you ever compiled an object file? Yeah, doing one. Yeah, make with GCC. GCC, the dash oh option, if you just give it a C file, will out actually, I think GCC dash C to just compile it will output an object file that is literally just like this. Now, let's do, I think great. This is awesome. I am ready to go. I have solved this challenge. Do I expect this to give me the flag? Yes. Did I do with the assignment s? No, what did I do? Yeah, I'm doing the example from the slides. Okay, so RDI is equal to this is not what I'm doing. Oh, wow, none of my code is here. That seems weird. Okay, why is that? Let's run the file command to see what type of file are we dealing with? Ah, it's an elf 64 bit LSB relocatable. How many instructions was my assembly? Yeah, two lines. Let's LS dash LA. Let's look at the size here. This is 704 bytes. Does it make sense that two instructions equals 704 bytes? No, what's all this extra junk? Yeah, all this help stuff. So this is actually, like I mentioned, this is the exact same object file that you could then use in your C program or link to. So you can actually write a C program that calls your assembly function. We're not going to get into that. But that's how you would do this. So okay, what we need are the raw bytes of this instruction. One thing that we will look at is object dump is a great tool that will look at and disassemble go back from bytes to looking at your program dash capital D means just disassemble everything you see. So this is just a double check. Hey, do I actually have those instructions that I want there? Hey, look at this. It says it's an elf 64 x86 64. Great. We'll talk about elf means in a little bit. You can just think like that's a cute little name x86 64. Great is what we want. And how about our instructions? What's weird about these instructions? Are these instructions we wrote? Yeah, they're AT&T syntax. And we don't like that. I think it's m. Is that right? So we would actually need dash m. Yay, that looks better, right? And what this actually shows us is the raw bytes that correspond to these instructions. So let's do if we again, didn't like tools, but got to this point and thought, I know, I have everything I need, I have the instructions, and I have their bytes right here. So I will do zero x 48. I wish this was shorter seven. Do I need to do the other one too? Yeah, let's do it. Yes. x 39 x 0 x 0. What do I expect to happen when I hit enter? Should it give me the flag? No, good check. But what am I looking for here? Yeah, that at least showed me the same instructions that I started with. It'd be really cool if this worked right off the bat, huh? Hey, look at that. So the code is the same. So you could do this. At this point, you're done. Should you want to do this? There's not a lot of no's. Why? Why should you not want to do this? There's a lot of steps and typing that hex by hand is insane. And you make one mistakes, and everything is messed up. And then you have to re type it in, right? We don't want to do that. So we can, can you give me the object extraction? Object copy. Now, so we want to copy from there from that object file. So I actually saw that in the object down that this was at underscore start are these bytes. So we can use a handy dandy tool to copy from that file. So what's the dash capital capital capital. Oh, that's annoying. This isn't where it's going. This is saying the input the object file. So it's just binary. This is not a path. Got it. Oh, the output format. That's what the dash dash only dash section. Okay, because we want the text section here disassembly of section text. So we just want these bytes specifically dot text dot text is what we want because that's actually what it says right here. Yeah, so the input path is asm.o. And we'll do asm.bin for binary. We can use a handy tool called hexadump that will show an output of a file as bytes. We can see some of our favorite bytes right here. The orders are reversed, which is really weird. And I don't like that that's like that. But let's see. So I can do again, like I said, there are several different ways to do this. So this is making the standard input of challenge run to be the file assembly dot bin. Now we see move hex into our x move 539 into EAX, which was which was the code we wanted, right, still did not get us the flag. That's okay. So we can use up so we can one thing we can do is use AS to assemble the into an object file. And then we can use object copy to copy out the bytes of the text section. Um, but what was I what was the point of me showing you this example? He knows why is he doing these things? They think I'm all sitting there. Yeah. Yeah, but what was the point of this code snippet? That's where I'm going. Yeah. Yeah, because we want to actually see the values in RAX. Right. Okay, so I'm going to show you the better way of doing this first. And then I'll show you the actually, I guess, do you even like better ways? Okay, let's do is it in XCC? Is that the in three? Okay. So the way specifically this level is set up. And this system is set up that int is an interrupt. So it's an operand that causes an interrupt. We'll go over exactly what those are, but essentially it's a signal from your program to the operating system, says, Hey, I want you to do something. And the, what I want you to do here is three. And what that means depends on the operating system. For now, I'm just telling you to use this. And what the program will do is it will then, uh, what the chap, these specific series of challenge will do is print out the state of the registers. So let's start with a handy dandy into three, right? Quit. Okay. And then I wanted to AS so assemble it. No errors. That's great. Obj copy. And then so run it. And hopefully everything will just work. So this is the kind of the, so now we can see our code first and in three, then these two operations and then three. So this is just a little bit of debugging information that it's giving you. Again, this is by the program itself as it's executing. So this can help you debug errors. It will not help you debug all the errors that you could occur because you don't control over what you see, but we can see all the registers. We can see all the values. We can see RSP has this value. We can see some part of the stack. We haven't used the stack. So it's not here. We can show some parts of memory locations. So this is the first output before we ran anything, which we did nothing. And then we moved that value into RAX and then move that other value into EAX. Everyone remember? And so now when I scroll down, what am I looking for to see if this test was successful? What register? Yeah, RAX should have the value of five, three, nine. Boom. RAX five, three, nine. So if this challenge was set the value of RAX to five, three, nine, I should get the flag now. But oftentimes, like I said, this can actually be a lot of output. It can be very actually annoying to do. So one thing we can do is actually make this into a real probe, a real executable that we can execute. And I, is it just LD Connor? So LD is the linker. So after you assemble it, we need to link it. So LD and is it asm.o and then dash o. So link this object file. You can put as many object files as you want on there and then output it as exam.exe. This is Linux, as you know, and you're playing with it. File extensions don't mean anything. I'm just adding this.exe to say this is executable. So let's actually look at the difference between, so I have this bin, which was just the 14 bytes. Now my 700 byte object file grew into this insane 4000 bytes, 640 byte, which has only 14 actually useful instructions. But now that it's an executable file, I can execute this. And that in three, as we see as a trap instruction, which means I can't actually run this. But what I can do is use my handy dandy GDB to debug this tip for this course. If you have not gotten good at GDB yet, you will. And debugging is super important to get good at. I should not use my fancy thing first. Okay. And okay, so I can do that. I'm in GDB, nothing's happening. It's not running. I can say start. I can't say start. Okay, but I can see that we received a sig trap. So that's the signal that in three that we saw. I'm at this program location. One of the things there's actually, I think a GDB module will go through at some point. But for now, I can examine 20 instructions. So examine slash 20. I've been doing this a long time. This takes a long time to do this. So don't be freaked out. Dollar sign, our IP. So show me the next 20 instructions from the instruction pointer. And I see the next instruction is how the thing is in AT&T syntax. But move this value into rax, move that into eax. And I can do si for single instruction to go one instruction at a time. I can see it tells me I'm now at eight, which means I'm here. Now what should the value be in the, if I print as hex, the rax register, what should the value of the rax register be right now? Was it 539 yet? Where we we've just executed this instruction, we haven't executed anything else. A bunch of ones, or all f's. Okay, single step again. Now we're at this instruction. So we've executed these two instructions before it. Now what should the value be? 539? Excellent. So now we've verified it two ways using the debugging in there. We're using the debugging in here, in GDB. Okay, cool. So should we solve the challenge now? Does anybody remember what the challenge actually wanted? I remember the value of the register. I think it's RDI. Okay, RDI boom. And what are we going to do instead of remembering this, we're going to copy it and paste it for later. So we don't have to worry about mistyping it. Okay. Okay, let's not do this. Okay, so you tell me what to type. You can say it in operations, you have to do a letter by letter. Move. So how do you do a comment? Is it pound? I heard that from the audience. Okay, assemble it using asas the dash f file dash O object copy. This whole guy. And I'll do it a different way even will cat assembly dot bin pipe that to challenge run. So now do I expect this to give me the flag? What if it doesn't give me the flag? What do I do? Yeah, I go back, I rerun the program. I see what it's asking for. I double check my things. I add in in threes to get more debugging information about what is in the registers to see if it's incorrect. If that doesn't work, I maybe try GDB debug it that way. If that doesn't work, then ask them to just work. It's kind of suspenseful, right? I kind of like that it takes. Hey, there we go. And there's my flag. Let's see, you can if you want to get really fancy, you can you can make a bash script for sure and feel free to share those things. This is running the assembly and the object copied. So running this command, I can just hit up and hit this. It will do that in the bin. I can even then also then do a challenge run so that ampersand here just says, Hey, if the thing on the left was successful, then do the thing on the right. And so this means first assemble it and then copy it out. If that was successful, then copy it out. And then if that was successful, run it. And of course, I would want and now that I have that in, now I can do this for any level and start editing my assembly file and this whole pipeline still works. Cool. All right. Let's learn more about assembly. Yeah. Cool. Okay. Oh, I guess we probably should have got there because we were already in it, but move is misnamed. If I moved you from this room to the other classroom over there, would you still be in this room? No, you cannot physically exist yet in two places at once. But the move instruction is incorrect. It actually copies data from one location to the other. So the data still exists in the, in the destination in the source. So you're not deleting that. It's still, it makes sense. Like what, what would you put there zeros? Like, I don't know, it doesn't kind of make sense. I mean, but anyways, if you actually start thinking about what does a move mean, or if you're thinking like, Hey, on Linux, if I move a file from one location to the other, it no longer exists in the source. But if I copy a file, it exists in both places. So, so like this example, move hex 539 into RAX and then move RAX into RBX, 539 at the end of this still exists in both registers. And we maybe could use that fact. Okay. And also moving into partial registers, like we said, so we can move, this is like, actually a pretty good test, 539 into RAX, move zero into RBX, move AL into BL. So what's the value in RBX at the end of all this? BL would be the lower eight bits of RBX. Yeah, hex 39, right? So two hexadecimal values are one byte. You can also remember that because a byte is zero to XFF. That's the values you can fit in there. So that's how you can see easily just by looking at this saying, okay, moving this value into RAX, setting RBX all values to zero, and then moving the AL, which is the lower eight bits, which the lower eight bits of here will be this 39 hex and moving that into BL. Cool. Okay. So this is where fun stuff happens. Now, we talked about representing negative numbers, how are negative numbers represented? Yeah. So two is complement, but specifically how can we tell if a number is negative or positive by looking at it? Is this number negative? X539? Is this number negative? The most significant bit is one. So you need to know actually the size of what you're talking about. That's actually one part of that trick question. That's why I was hopefully pointing to RAX values. So 64 bit values. So for 64 bit value, the hex value of 539 is not a negative number. And so we have this case of when data is being extended. So let's say we want to move negative one into EAX. Now, so for the, if RAX register was zero initially, and we move negative one into the lower 32 bits, if you interpreted the whole 64 bits as negative, would it be negative or positive? So this, this value in 32 bits, is it negative or positive? It's negative, right? Because of the first bit. But RAX, if you looked at RAX, is that number negative? It's the same value, right? But because of the size we're talking about, it's different. Because what we mean by the highest bit is one or zero depends on how many bits we have, right? Okay. But this is actually fine, except in the case like, Oh, but we actually, if we're actually trying to move the actual number negative one from a 32 bit value into a 64 bit value, we'd need to actually move all of those ones. Because otherwise we get into this case where we have a number that we interpret as 32 bits is negative one. But if we interpret as 64 bits is 4.2 million, billion? I can never remember a lot. So there's a special operation called move Sinex that extend, move SX will, if you're moving will sign extend the bit such that if there is a one at the most bit of whatever size you're moving, we'll extend that to the destination so that it still preserves that signed number. So if we did here, if we move negative one into EAX, and then moved with Sinextension EAX to RAX, now it's at it's extending all those ones. So now it would be how you'd expect. So no matter what you interpret that number, it's going to be negative one, if you're interpreting it as a negative number. Cool? Okay. So we move data around, moving data around, moving data around. Fun facts, if you look this up, the move instruction is actually fully Turing complete, so you actually don't need anything else. Yeah. So you could literally do this whole assembly module and everything. I guess theoretically, no, maybe not because it forces you to use different things, but theoretically, you could program assembly and only move instructions. You can actually go look up people that implemented the game do using only move instructions, but that's no fun. And I guess CBUs would be very different if we only had that. We want to actually compute and do things with the numbers. So this is the different values and the different operations we can have on those. We talked about some of these. I'm not going to go through all of the, I guess I could go through them, but we can add numbers together. But it seems kind of weird, right? With math, you usually have, if you're going to add numbers, you have three things, one number one, number two, and then some destination to put it in, right? You have A equals B plus C. Everyone familiar with that? Yeah. Well, here we don't have that, but we have an implicit destination. So the way to remember it is these instructions are always, the destination is the first operand. So add RAX, RBX says take whatever is in RAX, add it to RBX, and put the result in RAX. And so that's how you go through all those. Subtraction, same thing. Subtract RBX from ECX, put it in RBX. Multiply is complicated. You should look up multiplication and division, especially when you get to those levels, because I think it'll tell you about it, but the resulting number can be larger. You can have two 64-bit numbers. If you multiply them together, you could get a 128-bit number. So it means ways to deal with that. Other things, increment numbers by one is what increment means. So just fix one, decrement, negate it, not. So flip each bit, and it, or it, xor it, shift it left, shift it right, shift right to sign extend it or rotate the bits. So they just like keep going through all kinds of fun stuff. This stuff is actually used like your compiler will generate code even if you don't use these operations because it knows that certain things are fast. So the point of this assignment is to A, get familiar with x86, B, get familiar with programming assembly, C, get familiar with different types of register operations that you will come across. But there's no, like, calculus in here, right? Everyone knows arithmetic, addition, subtraction, maybe even some multiplies. Yeah, this is actually the shocking thing about cybersecurity, well, except for the crypto stuff that's set through. A lot of, like, this low-level hacking stuff has no, there's no advanced math. It's literally just addition, subtraction, those kind of things. Cool. Okay, like I mentioned, some registers are special. So for instance, RIP, the instruction pointer, you can't directly read it or write to it. It always is the memory address of the next location to be executed. We'll talk about how to redirect control flow around, which implicitly changes this. Similar thing with RSP is a region of memory that you can store arbitrary data. We'll talk about this later. Okay, lots of registers. I don't want to get into this. All right, how to get things from memory. So we just talked about how to get values in and out. Part of this slide didn't load. Fix that, please. I can download slides or I can show slide just or stream, I guess, not both. Like I'm looking at this thing. So like, what is it? There we go. Okay, assembly. So memory, right? We talked about registers, registers are super fast, but they literally are on the CPU die. Like if you look at a CPU, you can look at like dies and layouts and like what of that area of the CPU is dedicated to what purpose. A ton of it is actually cash, but a lot of it is register values. And so that's expensive. And that's why there's not a million register values because they have to be physically on the CPU. So we'd still like to access a lot of memory, like more than what was there, like eight registers or 10 registers, I don't know, even with 20 registers of eight bits, that's still not a lot of data. So we have memory, right? So we want to be able to go get information from memory, get it, take it and then compute on it. So as we talked about, now we're digging into memory. So we've looked at registers, how to move data in and out of registers, compute on that data. And now we're going to be looking at memory. So it's like I mentioned, it's actually used a lot very frequently. This is actually used by your program to talk to disk or network. So it's actually your interface for a lot of things to the rest of that world. Process memory. So you can think of your memory. So this also relates to what we talked about the size of your register values corresponds to how many bytes your program can address in memory. So if you only have eight bits, how much memory can you have? Yeah, how many different memory addresses you can have? Every memory address addresses a byte. Four, more than four, with eight bits. How many different values of eight bits are there? Oh, you have to study these powers, two. Not 32. 256, thank you. Yeah, you can keep going. You just multiply by two, eventually you'll get that. Yeah, so 256, right? It makes sense. The value in a byte can go from zero to FF. So zero to 256 or zero to 255 representing 256 values. So this means that you would only be able to address 256 different memory locations. It's pretty useless to have a computer with that limited amount of memory. So this is why the move from 32 bits to 64 was super important because 32 bit applications by default can only address up to four gigs of memory. And we want this, I think this computer has like 64 gigs of memory, but you would want an application to be able to use more memory than four gigs, even at the time, that's kind of insane. So they tried to do some shims and then eventually like change the whole architecture to 64 bit. And now you can technically address up to two to the 64 bits of memory, which is if somebody looks that up, it's a petabytes or something? Yeah. Zillabytes, yeah. Into a lot of bytes, two to the 64 bytes of memory. Cool. The memory is addressed linearly, like technically zero, I think you whatever, you can't really access that anymore. But anyway, different memory regions are made for different things for different purposes. Oh, there we go. 127 terabytes of address RAM. I feel like that's small. We need more. One of you invented 128 bit machine so I can address more memory. Anyways, so lots of addressable RAM. So, okay, don't freak out about this, even though your program can technically access that much, your programs don't all blow up and not every program is trying to do this. The operating system is very smart. You'll learn about this in operating systems, we'll cover this a little bit, but your operating system actually makes sure that A, each process that's running on your computer thinks that it has access to its own dedicated memory location. To your process, it doesn't know anything about any other processes existing. You used to actually have to, I think, a program. Well, anyways, other operating systems didn't have this and it caused massive, massive problems. So, the stack, oh no. Okay. So, the stack is used to store temporary values. This will be useful and is part of what you're learning. So, right now, we'll talk about temporary data storage. So, you can use the push operation to push either a register or a value onto the stack. So, here's that warning. This is what you asked me about. So, we can, for instance, move the value C001CA75 into RAX. So, now that's in there. We can now push RAX. So, what this will do is decrement the value in RSP, which is a stack pointer memory address, and store whatever was in RAX there. So, the stack is moving this way. So, this we can see here at the top of the stack here, C001CA75. Now, a push of Boba Cafe. But, again, this will come up when even you can only push 32-bit values onto the stack in an immediate value. How do you get 64-bit values on the stack? Registers. We push registers just like we did here. It'll be a 32-bit immediate. That's actually 64-bits, because the stack always will be aligned by 64-bits. And then push RAX. So, here, zooming in. Oh, I can zoom in. Whoa, that's cool. That's insane. Okay. Oh no. All right. This was too much power. Okay. So, the stack will be, the top of the stack will be the first RAX, and then our Boba Cafe, and then, oh, I guess it's Cool Cafe. Nice. Now, I have no idea how to get back. I've zoomed in too far, got too close to the sun. Okay. And then we can pop, use the pop to get things off the stack. So, we can pop into RBX. And now RBX will have whatever is in the top of the stack, which was what we just pushed here. So, that will have Cool Cafe. And we can pop RCX, and now we have Boba Cafe in RCX. But there's still a value on the top of the stack. What do we know that's above Cool Cafe? We have no idea what's there. It could be anything there. We didn't put anything there. We can only guarantee when we push and pop things off the stack. And that's because of the register RSP. So, here's the same example, but using the register RSP with an actual memory location to say this is where the memory location is. So, after you push Boba Cafe, it is a very small font, but the end bytes here are 50. In the first example, then after we push, what's the size that it's going to push? How many bytes? Eight bytes, because it's a 64-bit machine. So, it's going to push eight bytes onto the stack, and it will increase this by eight, now decrease. Sorry, I was going backwards. Stacks grow in negative locations, just a convention, but this should be minus eight. Oh yeah, that's a hex subtraction. So, that makes sense. To 48, and then if we pop again, then we're back to 50. So, here we go. Historical oddity, the stack grows negatively. So, pushing decreases the stack value, and popping increases it. Okay, but how do we get data in and out of memory? So, the stack is one special location. We can use push and pop to get values on there. We use this nice syntax of brackets. So, that's the Intel syntax way of specifying a memory location. So, this says, hey, move the immediate value 1, 2, 3, 4, 5 hex into RAX, then move, dereference that, and take whatever is stored at memory location 1, 2, 3, 4, 5, move that into RBX. So, what's the value going to be in RBX after this executes? Will it be 1, 2, 3, 4, 5? Maybe. We don't know. It all depends on what's there. It's a trick question. We don't know what's in that memory location. So, we don't know exactly what the value is in RAX after this executes. It depends on whatever's at this memory address. Now, we can put things in memory using something like this. We can move 1, 3, 3, 3, 3, 7 into RAX, then move whatever's in RBX at that memory location, and now we've modified memory. So, now we've moved data from a register into a memory location. This is equivalent as a push. As we saw, so push is subtracted and then push it, copy it there. We talked about this. Every memory location has one byte. If we want to not write 64 bits to memory, yeah, so we can use, there we go. So, the destination addresses, sorry, I'm a little bit off here. Okay, so in this last example, move EBX into RAX, bracket RAX. So, because we're using EBX, EBX is how big? How many bits? 32 bits. So, we're only overwriting 32 bits at that memory location. Here, we're reading into an 8-bit register. So, how many bits are we reading? Eight bits from that memory location. So, this is how we can control how big and how small we're reading or writing from or to memory. Okay, well, we'll have to talk about Andy in this, I guess on Monday.