Assembly Live Coding: Bootloader & XOR Cipher - Uncut Learning Session

NeuralNine · Intermediate ·💻 AI-Assisted Coding ·9mo ago

Key Takeaways

The video demonstrates building a basic bootloader and an XOR cipher in Assembly language, covering topics such as symmetric key encryption, register usage, and addressing modes. The speaker also explores the concept of a minimal bootloader and discusses the size constraint and optimization for a bootloader.

Full Transcript

Welcome back everybody. We're going to do another assembly session today, which means I'm going to learn assembly, code assembly, play around with assembly on camera without cutting, without scripting, without even necessarily teaching you something. It's more like I'm teaching myself. I'm learning myself and keeping the camera going and commenting on what I'm doing, but not with a focus on teaching, more with a focus on learning. And maybe I say some stuff on the side. Uh, I don't know if you guys enjoyed the first episode because I recorded it yesterday from my perspective and I'm already doing the next session today just because I want to keep learning assembly today and I thought I'm going to record it. So, you're probably going to see this even if you didn't like the first episode. So, if it didn't get a lot of traction, let's say. Uh, but yeah, I probably, if you're seeing this right now, published the last episode a week ago and or something like a week ago and I'm doing the second one already the day after. So, as a quick recap, we're not going to spend too much time recapping, but last time I built this addition or I coded this edition in assembly. Not the most optimal script, I guess, but we had a buffer for the input. We had two buffers for number one, number two. We had a flag to control first and second and basically uh we read from standard input. We read from standard input. We had a register for the result. Then we just went character by character and uh basically subtracted 48 which is the code for zero for the character zero. And by doing that until we encounter something that is not a number, not a digit, we basically continue to do that. Then we jump to done. The first time we saved into number one. The second time we saved into number two and then we just uh exited with the result which of course was modulo 256 which is yeah suboptimal but it was more like an exercise. So today I have actually um some ideas. I have an ideas markdown file here of a couple of things that I could try to implement uh because I asked Chad GPT essentially what are some easy beginner level assembly projects that I could I could try to do and it came up with a couple of things and I wrote down four of them. So I think string reversal is an interesting one which is more like a lead code problem in assembly. So I don't know if I want to do that but I wrote it down because I think it's not extremely difficult and it could be interesting to implement. Bubble sort same thing same idea just an algorithm and try to do it in assembly. A little bit more interesting is the bootloader. Now you cannot think about a bootloadader in terms of an actual bootloader. So not something that will actually boot into the kernel and stuff like that. But I saw that it's probably not too difficult to just have something that runs on the raw hardware. So the BIOS uh the BIOS sends the computer to the bootloader and then it displays hello world or something. Um and then also trying to actually get it to a disk and to actually boot it in a virtual machine. I don't know if this is possible, if this is easy to do, but this is something I would like to look into. And then I thought also an XOR cipher which basically the idea of an XOR cipher is you have uh some message let's say hello world and each of these characters has a bite or each of these characters is a bite and a bite is basically eight bits. So even though this is not going to be correct now for hello world uh it would look something like this. that would be one character or maybe if you want to write it as a bite that would be one character that could be another character that could be another character and so on. So basically you always have these eight bits and then what we would do is we would have an xor mask. So we would have something like this for example and exoring that would result in something. So in this case would result in 0 0 0 1 1 1 and so on. And I think if you then do it back you get the original thing. So 1 1 is 0 1 0 is 1 1 1 0. Uh that's basically the idea. So that's a symmetric key for encryption. Maybe we can do that uh in assembly. And I think actually I'm going to start with this. So I'm going to try to do an X or cipher myself. Uh of course I'm going to Google. I'm going to use chatpt but not to get the solution immediately. I'm going to try to do it myself. The idea being user inputs stuff into std in we apply an xor mask. We print result to std out. And of course it works the other way around. the user can take what we print and feed it into sdin same mask and then we get the clear text that is the idea this is what I would like to build so let's actually start a file called exorcipher assembly let's do the usual stuff section text is the most important one we're going to have start as always the entry point global start and we're going to say start like this. All right. What do we need? We need an input buffer because the user will input something. Let's limit it to 32 32 bytes, 32 characters. So, section BSS input buffer res 32. We have buffer 32 bytes and the user feeds in some string 32 bytes. And we're trying to By the way, I have a shirt here. That is beautiful. I use Arch, by the way, if you didn't know. Um, yeah. So, the user feeds in 32 bytes. Now, we need to have a static XOR mask, let's say. And for this, I think we can just use the data section. I'm not sure about this. I'm also not sure how do we take 32 bytes because the idea of course has to be the key needs to be of the same size as the input unless of course you want to repeat the key that's also possibility. So if I have uh if I have something like this is input and my key is this let's say then what I can do is I can just repeat the key all the time but yeah that's of course easier to crack. So let's see let's say that my key is equal to and now which data type do we choose for 32 bits bytes um in assembly in data section which key do I choose for 32 bytes uh not key which data type. By the way, my voice as always uh has some problems. I do have some chronic stuff with my nose and uh throat and so on, which is why I basically for already 5 months sound like I'm sick. Um yeah, so you need to get used to that occasionally. So that is eight bytes. Uh since I need 32 bytes that is what is this? I actually do care about initialization. I do want to define a con. I want to hardcode the key into into the code. So what is this here? Zero DB. I can reserve 32 bytes because that is just a single bite as we know already. And that is 32. What is this dup? I mean probably it's zero initialized. Duplicate the value. Okay. So basic. Okay. That's the same thing as saying DB and then 0000. Okay. Good to know. I'm going to comment this out is same as key db uh let's say 32 zero just so we know that new piece of information so the thing is I don't want to have zero so actually I don't even I won't even use that I need to decide on a key okay so can I do key db B and then a string. My fancy key that has or whatever like can I do that? So null terminator as far as I understand it I don't need a null terminator in assembly if I know that it's going to be 32 bytes. So I just need to find some key that is 32 characters. So let's see. Let's just write something that will have probably close to 32 characters. My fancy key for this cipher in assembly. I guess this is going to be probably 33. There you go. So one too much. Uh yeah, let's just remove the Y. It's easiest thing we can do. All right. So that is my key. Now this is my fancy password and or actually maybe we can do assembly and then instead of this we're going to do the so that should be 32 now. There you go. All right. I think it should not be too difficult to do this now because all I need to do is I need to load the buffer. The problem is I will probably need to use two registers because as far as I understand it a register has eight bytes. Eight bytes is 64 bit. Yes. So I need to probably do something like rax and rbx are considered to be one. So I load one part into REX, one part into RBX, and then I do just exort. This should not be too difficult. At least in my head right now, it makes sense. So what if I move? Of course, I need to do sedd in first. So I need to do uh we need the codes again. Assembly sys call codes. So needed to mute myself briefly for uh the cuffing. So let's go here again. We had sd in reading from sd in was sis call zero. I'm actually just interested in registers here. So we move into rex one uh sorry zero. We move into RDI0. We move into RSI the input buffer. We move into RDX 32. Not sure if this is a problem if I do it like this, but I think this should work. Sis call. This is our SD in. And now I have this in the input buffer. What I would like to do is I would like to move into RAX. Now, how do I do that? How do I move eight bytes from my or actually no sorry we have eight bytes per register? So I need four registers or I need to do it four times because I cannot load 32 bytes into a register. I don't have a register of that size. Probably there's an intelligent way to do this in assembly. I'm just going to use the knowledge I already have which is not a lot to try to do this myself and then I'm going to ask Chad GPT if there's a more reasonable way to do it. So, my idea is let's boot up Excaliraw again. Uh, still have the same stuff from yesterday. Can I clear this somehow? How can I start a new project? Can I start a new project somehow? Not sure. I What I definitely can do is I can just select and remove everything. Not sure if that is the only thing I can do, but yeah, doesn't matter. So yeah, my idea is we have now an input buffer. Let's just use different numbers for the sake of simplicity here. I'm of course working with 32 and 8, but let's say I only have registers with two bytes and I have a input an input of eight bytes 1 2 3 4 5 6 7 8. So now I have eight bytes and I have registers of two bytes. What I would have to do is if I have here A B C D E F G H I would want to start with some bytes and load them here. Let's say these two bytes into register A. For example, let's say this is R A X. We know it's eight, but let's say it's two. And then I would like to perform the same thing. I have the key as well. And I want to load the first characters. If I haven't key a key of size eight as well, my key whatever, then of course I want to load into another register. I want to load into RBX for example. I want to load M Y. And then I want to do an exor operation and store the result let's say in rax r a uh not ra come on r a x has the resulting thing whatever that is and I think I need to have a results buffer so I'm going to allocate 32 for the result buffer So basically I just take that and move it into the result buffer. That makes sense. So I just need to have a pointer which could be RSI. It's already pointing to input buffer. So how do I do that? How do I load eight bytes? There was a I think keyword is the right thing, right? Keyword assembly. What is a keyword? 64-bit value. That's eight bytes. Yes. Okay. So, if I'm not mistaken, all I have to do is I have to load the first eight bytes from input buffer into reex. So, I need to say keyword rest or not rest re. But do I need re? Let let me see. In assembly, when do I use re for addresses. Emit a rip relative relocation instead of an absolute one. You need it whenever you want to reference a symbol via the instruction pointer, which is especially important for accessing data in 64bit mode. Generates an absolute relocation only supports relative loads. So, NASM will complain or give you a large Mhm. Okay. So I guess I need I'm going to ask it again to explain that later on probably. But let's say real input buffer keyword that should load eight bytes. So if I'm pointing right now to the first bite, it should load eight bytes. And the same thing I guess I can do for key. Um, not sure if I'm if I have a syntax error because the highlighting is different. Probably. I don't know. Yeah, let's let's just keep it like this for now. But basically I should be loading now eight bytes from each and then I can just do exor of these two. And then I should be able to load a keyword into result buffer of course with relean from rax that should work for eight bytes. So, in my opinion, if I just change this or let's let's not change this, but I think this should not sure if if this should work, but what if I now say move into RAX? Move into RAX uh one. Move into RDI1. Move into RSI result buffer. Move into our DX8 SIS call. And then move into rack 60. Move into uh RDI zero this call. So that is uh sd out writing to sd out and that is uh exiting with code zero. Not sure if this will even assemble. Let's see. So, XOR. Okay, works. Linker XOR cipher O XOR cipher. Uh, let's do something simple. Let's say I have hello world or something. doesn't print anything. Would be it would be nice now to see. Okay, let me let me take a look at my code. So, this uh this confuses me a little bit because I think that there usually when one keyword is highlighted like this and one is not, there's some problem. So, let me see. Let's keep it simple and just do eight for now. In this case, now this should be perfectly fine. But also let's see what happens. Let's open up an ASKI table because I also want to see what happens when I actually do that. So my key is of course now I need to change this one 2 3 4 5 6 7 8 comment out the rest. So my fancy key like this translates to the following bytes 109 actually we can I think we can do this easily just for checking in Python. So if I have key is equal to my fancy K and then I have message is equal to hello were like this then I should be able to do this. No. Okay. Uh then let me briefly see in Python how can I exor two strings. I actually did this. I even did this in the video, I think, but I don't want to research this now. Yeah, but I don't want to specify the bytes. Okay, I need to encode them. Okay, so let's say key keyb is equal to key.enccode. But of course, we want to encode an as key, not an UTF8. And same thing for message B is messaging code. And now uh bytes bytes bytes what is that? Okay. So let's say bytes x x or y for x y in zip key b message B or actually yeah doesn't matter it's commutative okay and can I take this now and decode it as ASI Okay. Uh, what do I have to? These are the raw bytes. Hex would be cool. Okay. Uh, but can I not render these bytes somehow? Can I render the bytes in Python? So I don't see the bite code byte codes but the representation. Yeah. I don't want to see the hex. I don't know why you don't understand this. I don't want to see the bites. I want for example back slashn to be rendered as new line or maybe to not confuse them too much. Yeah, decode should do that, but it doesn't do that. But this print this prints I want to render this Oh, is this maybe because I'm not printing? Oh, there you go. Okay, I need to print this. But cool. So, that's basically what I get. So, I wouldn't even know. That's a bit uh Okay. So, okay. Other thing when I run something on Linux, how can I get std out as hex code? XXD. So, basically, if I take that, okay, I don't have this now. Uh, let me try to do exor again, but I'm going to pipe this to xxd. I'm going to say hello W. Okay, I don't think I understand what's happening here. That is what I get as an output here. So, let me try something else. If I specify a bunch of I mean zero is not zero. I know it's 48 but interesting. So maybe let's try something else. Let's try to provide something here for for my message. So what should be the output if I say message is equal to a bunch of zeros. So actually how many characters do we have here? Eight. Right? So we have 1 2 3 4 5 6 7 8 and we have the message B encoding and then I have my printing here. Okay, it works actually at least for the most part. It only prints one, two, three, four, five, six because SK is not part of this anymore, I think. But maybe that's also a problem with XXD, but I'm not sure. I don't know what XXD is even about. Create a hexadimal representation from a binary file or vice versa. Hex dump. Interesting. What is this SKIC when using XXD? Can I somehow what if I say dohex and what if I do this here again? So here my message was oh actually 0000 sorry 000000 okay 5D 49 56 51 5E 53 49 5B okay works the printing is a different problem of course you're not going to get this I'm not going to do B64 encoding in assembly you can forget that I'm going to work with a hex Here the question is now can I do this with 32 bytes? So if I do this with 32 bytes I need to do it multiple times four times to be precise. This should be quite simple I think. If I say XOR loop move into RCX 4. So I basically decrease I have three. I decrease I have two. I decrease I have one. I decrease I have zero. Four times. Yes. So I do this once. Then I decrease R CX. I also need to adjust the pointer. So the pointer that's that's pointing to input buffer. Uh or does this make sense? Wait a second. because I'm not using a pointer here. I'm using re I need to say now the brute force solution would be to use let's say move into think I can use rdx I could say zero no probably it makes more sense to use something like a pointer so Maybe let's say RSI pointing to input buffer and then basically I need to say I don't know if that's how you do it but can I just add to RSI 8? Not sure if this is how it works, but my idea then is to say, okay, test rcx rcx jump if not zero to x or loop and otherwise we're done. Not sure, but in my world this could make sense. It assembles, it links Command not found. I mean, of course. But let me just see. There's a problem in Why do I only get this much? Okay, let me ask JHBT something. In assembly, when I point to a buffer that has 32 bytes by doing move RSI input buffer, how can I shift this pointer by eight bytes to the right? Oh, I don't use move. I use I use the effective address calculation. Good point. So, I actually say LEA, but I don't want to do plus eight. I want to do plus whatever we have. LEA is fine for the for initialization. But what if but can I not shift the current position by eight? Question mark. I mean, I can actually tells me to do whatever it tells me to do what I already did. Not sure if the if this changes something. Oh, no. Wait. If I move, I think I should not be using square brackets because then I'm dreer referencing and going to the actual value. Still there's something I'm not understanding correctly. Let's go step by step again. I have an input buffer. I have a result buffer. I have my key which is 32 bytes long. I start by getting 32 bytes of input into input buffer. This should work. Then I say I have a counter for I'm loading the input buffer address to RSI. I'm saying move. Oh, of course. Wait a second. I should not be doing that. I should be using RSI. So actually I need to do the same thing for the key actually as well. So maybe I can use RDI for the key. So I say rax RSI RD uh RBX RDI and then I need also something pointing to the result buffer. So what are register names in assembly? Because I know that there are other registers as well. We have uh they're not listed here, but we have something like R8 or whatever they're called. Why are they not listed here? Yeah, these ones R8. Okay, so move into R8. Uh, actually I should do that in the beginning. R8 should be pointing to the result buffer. And then I can just say move into R8 racks. And then I don't just add to RSI, I add to RDI and to R8. This could work. It doesn't work. Okay. Um, it doesn't work. I'm pointing to the beginning of input buffer to the beginning of key to the beginning of result buffer that here in my opinion from my understanding that I have right now which is quite limited. This should take the first eight bytes from input buffer and load them into rax. This should take the first eight bytes from key and load them in rbx. This should result in an XOR in RAX. And this should take that XOR result from RAX and store it into R8 which is pointing to does it work like this. We did that already yesterday. I think pointing to input buffer or getting the value. Yeah, I need to get the value. Not sure if I do need to do it here, but let's see if that works. No, I think I'm not quite understanding the assignment uh in these these square brackets. This means take the value that RDA is pointing to. RDA is a pointer to input buffer. So this like like my addition example from last time input buffer is the buffer. RDA RDI is pointing to that input buffer. Here I'm taking the value and I'm storing it here. Now what am I doing here? I'm pointing to the input buffer. Actually I don't need to do this again I think. But yeah let's keep it for now. I'm taking the value from the input buffer and storing it in rax is what I would think. I'm not sure if this is problematic. Let me just try even though I don't know why this should be the case. Now, actually, this doesn't make sense. If anything makes sense, it would be that. But I don't think that I don't think this makes sense. It does. Okay. So, basically Okay. So I think if I do move R8 RAX I am saving the value of RAX as an address into R8 by doing move R8 R X I save what is in RAX into the address or memory location that R8 is pointing to. Got it. I'll probably make this mistake a couple of times because you can see how I learn stuff. I don't learn stuff by following uh some guide and learning stuff how you're supposed to do it. I usually do trial and error until it works and then I try to understand to reverse engineer why it worked. But yeah, let's see if this is now reasonable. Let's go into Python again and say my key. Where's my key? My fancy uh let's go into my code here. Let's copy this. And in Python, I'm going to say now my fancy key for the cipher in assembly. And then I'm going to say that my message is going to be equal to a bunch of zeros. And then I'm going to do what I did before. I'm going to encode the key. I'm going to encode the message. I'm going to do the exor. And okay, nice. And then I'm going to try also to see what the hex code looks like because that's uh easier to follow. And now I'm going to try to do the same thing. So 1 2 3 4 5 6 7 8 9 10. 1 2 3 4 5 6 7 8 9 10. 1 2 3 4 5 6 7 8 9 10. 1 2 I get the exact same output and I get the exact same hex code. Ladies and gentlemen, we implemented an exor cipher in assembly. Perfect. Cool. So, this works. Um, I would still like to know I think I had a question. Did I have a question? I'm not sure. But one thing that I would like to know is if this could be done way easier. So, I'm going to ask Chad GPT. I implemented an XOR cipher in assembly. It works. But could this be done more easily and professionally? And probably I shouldn't use um 04 for this, but yeah. Okay, so this uses a calculation for the key. That's fine. But in this case, I think this doesn't matter really. Input buffer. Okay, makes sense. This is just some numbers, some some aliases, let's say. Okay. So, increment basically shifts eight bytes. Oh, no. I'm do Okay. This is doing it bit by bit. Uh, bite by bite. Sorry. Okay, but this is this is actually kind of stupid now because it says here easier to read and understand and juggling 64bit chunks unless you need the speed. So would you say my solution is faster in terms of performance. Cool. Yeah, then shut up. Awesome. Cool. So, let us try the other thing which I think is more interesting. I'm not sure if this is even a project that I should attempt, but I'm going to ask Chad GBT. How realistic is it to code a simple minimal bootloadader in assembly as a beginner? ambitious but certainly doable with the right mindset. Thank you very much. Wow. Uh okay. On PCs, the bias initially loads your first sector at address and jumps to it in 16bit real mode. You'll be writing instructions that manipulate segment registers, work with 16bit registers, and use BIOS interrupts for screen output. Size constraint uh size constraint exactly 512 bytes including the boot signature in the final two bytes. Every instruction and data bite counts. You often optimize for size and turn macros, turn to macros, or self modifying tricks. Hardware interaction. You're talking directly to video memory. Disio ports. BIOS routines. No OS abstractions. This is cool. Must know NASM syntax. I think we know that to some degree now. Understand 16 bit registers. Yeah, you basically just don't go you don't use racks or EAX. You use AX BX. So you use the last 16 uh bits which is the last four bytes. Then we use interrupt with code this not is this 10 I think this not 10 this is 16 right or am I understanding this wrong now I think it's 16 because you have 0 * 1 1 * 16 uh for text output and this for discretets how to assemble using a debugger like GDB Cool. This looks a little bit more ambitious. So, I'm not sure if I'm going to be able to do that today. I think I'm going to try. And in the worst case, I'm just going to let it do it for me. And I'm going to try to understand what it did. So, let's ask some questions. Help me understand what a bootloadader actually is and how we even get into it from the boot up or BIOS. When you press the power button on your PC, a lot happens before your familiar operating system, definitely not Windows, ever shows up. The bootloader is a tiny piece of code whose job is to bridge the gap between your firmware BIOS and UAE, if this is how it's pronounced, um, and a full-blown OS. So, the CPU holds itself in reset until the power supply signals It's stable. Okay. On older PCs, the BIOS runs and its built-in code runs its building code. On newer systems, the firmware takes over. Performs a post power on self test. Checks RAM, CPU, GPU, discs, etc. Finding the boot device, boot order. Okay, this is all still in the BIOS. This is not something that we need to care about. Let's say it finds my hard drive and then what happens is first stage bootloadader master boot record on a BIOS boot disc. The very first sector 0 to 512 bytes is reserved for the master boot record. The firmware reads that sector into memory at physical address this and jumps there. What's in those bytes? The stage one boot loader. Minimal code to locate and load a larger stage two from disk. A partition table and a boot signature. A magic value that tells BIOS this is valid boot code. Okay, cool. Um, from stage one to stage two. Okay, this is already quite quite uh crazy. I don't want to actually boot into an OS kernel. I don't I don't want to build an actual bootloadader. I would just like to get to the point where these 512 bytes are executed and I can print hello world to the screen without using a sys call because I don't have an OS of course. Um, now my goal is to actually build a simple bootloadader that is automatically started by the BIOS and then prints hello world without any OS underneath it. And that's it. Is this something I can do as a beginner in assembly? So I don't know how how comprehensive this is. Okay, this provides the code. I don't want to look at that. Um but let's see what it says before that. You can definitely pull this off the first project. Okay, we fit this into this size. Running it in 16 bit. We understood that already. Assemble emulator. Okay, let's say I have this ready and implemented. Can I also test this bootloadader in a virtual box? Okay, cool. So without providing me with the full code, I want to do this myself. How would I even approach this at all? How do I start? Okay, I already have this I don't care about the emulator. I don't care about the editor. Okay. I don't care about this. I meant more like a like a template for the code incremental developmental step. Okay. So, I think I will need to let it show me. I meant in terms of code, how do I get started? What are the first couple of lines? Okay, this is way too much. Um, just one or two lots. Okay. So I basically specify with bit 16 that I'm using 16 bit real mode. So assembly bits command all x86 instructions. I don't see a bits command. Am I understanding something wrong or Okay, so a couple of questions. Why can I not find bits in the list of x86 instructions? Also, what does orc do? Why do I not specify 0x 0 0 but the end? They are assembler directives, not CPU instructions. Okay. Okay. So, this is basically something that tells uh NASA what to do, not not the CPU what to do. Okay. So, it doesn't execute that. It just tells NASAM this is 16 bit code and this sets the origin in a bias boot scenario. The firmware reads your Mhm. by saying every label and date reference in your code is assembled as if it lives at that offset. I don't think I understand that you don't declare segment register here. What happens? But why the offset? I thought my code will live uh I thought my code will live between 0 and 0x 0 and 0x7 C 0. Is this wrong? Okay. So this is a different syntax. This does not mean from two. It means it loads it here with an offset of this. Okay. So, so does 0x 0 0x7 C 0 mean that um or not mean from to but at and offset. I know this is not a prop proper English sentence. Okay, then I need to figure out y 7. So if I get this correct, um we have 16 to the^ of 2 16 to the^ of 3 that would be 40 96 * 7 + 256 * 12 Y 0x7 C I mean probably this is just a convention I don't know probably there's no logic to it simply okay cool I don't need to understand this then so instruct NASM to assemble to 16 bit real mode whatever real mode means But basically I said now origin it's that legacy convention. also written as this. Cool. Then it says after that I define start Okay. Okay. So after these two lines, what do I do again? Just one, two lines. I think it's more like understanding how to build one than actually building one myself because I think this is a bit too much. So why do we call this? Why can we just say start and don't need to define section text global start etc. Okay. So we have no linker. We're going to write some stuff down here. No linker because makes sense because we don't produce elf 64 code or formatted binary. We uh we assemble into raw 512 byte blob. Cool. Because of that we start with a simple start. Now you never went through a linker that needs section or global. Let me write this down as well. Because of this we don't need section and global etc. So this is moving something here for whatever reason offset of your null terminated string. Okay. Now without providing the code itself tell me what the steps are I need to implement here. just conceptually. Okay. Tell the assembler your environment. We did that already. Set up segment registers. Ensure DS and ES if needed. Point to your point at your code data so your pointers resolve correctly. We need to understand what DS and ES is. Point to your string. Load an index register, for example, SI with the o offset of your zero terminated message. Read a bite, test for zero, call bias to output it, increment pointer, and repeat. Once you hit the terminator, disable interrupts. Halt the CPU pad with zeros up to byte 510. Then write the two byte boot signature. Okay, this is that makes it this is the stuff that makes it uh an actually valid code. So I have a couple of questions. A couple of questions. One, what is DS and ES? Two, what is SI? Three, what is 0x 10 0x0E? Probably some sys call to the bias. Four. Is intext similar to a sys call to the OS just for the bias. Five. Uh why do why do I need to do CLI and HLT and then the rest is clear. I understood that. Okay. So DS and ES are actually let me let me take a look here. x86 um registers again because I think I should actually no I don't understand that because I do have okay these are segment registers these are different we have general registers and we have segment registers and then we have index and pointers I need to understand the difference here okay segment registers In 16 bit real mode, each memory axis uses a segment offset pair. So the default segment used for most data accesses extra segment default segment used for most data most data axis. I don't quite understand what this means. Second data segment often used by string or block moves. You typically set them so that your code and data buffers life in the same 64 kilobyte window. Not sure I understand this source index register. When do you when you do string or bite operations? SI holds the offset within DS of the next bite to read. Okay. So that basically does this then hold the initial address and this then holds the offset and it's increased. I'm not sure. Okay. I think I need to understand something first. What is the difference between general registers, segment registers and index registers? Are these just conventions or are they actually different in terms of functionality each of which can also be accessed as different registers. Okay. Primary use hold operants for logic loops counters function return values and so on flexibility. You can do a lot of stuff with that. Okay. Segment registers that form the high half of a segment offset address in real and protected mode. Primary use define the base of code data stack or extra segments implicitly or explicitly anytime you reference memory instruction fetches use CSIP data loads okay think I'm missing a lot of basic knowledge here that is required to understand this less flexible you can't do arithmetic directly on segment registers okay changing them requires special instruction instructions and may trigger a hidden descriptor table lookup in protected mode. I I find this super interesting. Really, I I I think this low-level programming stuff, it's difficult and and I'm not really competent at it, but I really enjoy doing it. I just don't know if I want to spend too much time with this because I don't know if this is super relevant to my career, so to say, but I think it will make you inevitably a way better programmer. So, I think you're not wasting your time if you learn assembly, even if you never code in assembly. But yeah, I think this is super fascinating. So index registers uh with instructor CPU uses SI implicitly as pointers into okay this is stuff I don't really understand here in a nutshell fully flexible for all sorts of things. Segment registers define where in memory different categories of data and code live. You can't treat them like normal data registers. index registers, dual row general purpose and the implicit pointers for string memory instructions. Okay, now that we know that sort of. So what does DS SI mean for my message engine X? Interesting choice. When you see an instruction that implicitly explicitly references this, it simply means holds the upper part of the address multiplied by 16 to get the physical segment base holds the offset from the Okay, that's actually what I that's actually what I thought. This is like like here essentially. Okay, so back to our step-by-step plan. We told the assembler about the environment. We need to ensure now that DS point at your code data. So your pointers point to your string load an index register with the offset. Okay. So to the first step I need to use ds and si to point to my string hello world without providing the code. How do I do this conceptually? The message does not exist yet. Remember that after the bias jump, your code and data both live in the same 64 kilobyte window starting at this. Okay. You need the data segment to cover that window. So you load into DS whatever segment value makes DS * 16 be that in practice that means copying the segment the code segment value the bias set into DS. Okay. So it seems like uh this is the wrong page. It seems like there's a code segment holds the code segment in which your program runs. So basically that should be set. Okay. CS is the code segment register. The bias bias should set this to 0x7 C 0. We need to load into DS. Now, I'm not sure I understood exactly because Okay, wait a second. Why do I need to load into DS something that needs to be multiplied by 16. In real mode, every memory axis uses a segment offset pair and the CPU does the multiplication for you. shifted left four bytes. So the physical address is the segment shifted four bytes plus offset. But why is this done? Okay. So, you have more address space. Not sure I understand this, but okay. Let's just take this. Let's just accept this. Due to some stuff I don't quite understand yet, DS needs to hold an address value that multiplied by 16. So shifted by 4 bytes results in 0x 7 C 0. We can do this by setting DS to 0x0 7 C 0 I think. Is this what he said? Yes. Or by just copying CS2 DS I think. Please don't judge me if this is not correct. I'm still learning. So I point that to the code segment. So let's just um say move ds cs. Let's say alternative moved DS 0x07 C0 load the strings offset. Your message label lifts some bytes after the start of that window. You compute its offset. Assemble will know message is at at runtime. But I don't understand the you say your message label lifts some byes after the start. Why I never defined a message? How do I know what to choose as an offset? You don't pick a magic number for the offset yourself. Instead, you'll let the assembler do it for you. Conceptually, the flow is you reserve space for your message. Somewhere after your code, you'll eventually write message is equal to reserve byte hello world and so on. at assembly time. Okay. So, basically I need but do I do this do I do this um in a data section or where do I define message? Okay, I do this at I do this just somewhere else. So I say message and I say db. I'm not sure if I can just say hello world like this. I'm not sure if I need a null terminating bite. Let's just do it like this. And then essentially what I do is I say I load into this the message as an offset. So if I get this correctly, it was the tell the assembler your environment set up the segment register. point to your string print loop. So read a bite. If I understand this correctly, this means I define a waypoint print loop and I then say I'm pointing to the string read a bite. Okay, where do I need to load the bite I want to print before doing int 0x10? What is this? Okay, so there seems to be lot SB lot SB assembly load string. Okay, that that seems to be super simple and it also advances SI. Okay, so probably I need a null terminating string just to know when to stop. But essentially I think I can just do load string. So L O DSB. So what is move ah 0x0 E4 high bite of the AX register. Okay. When you execute this in the bias, the ah the bias looks at the ah to decide which video function to run. Okay, this is just a sis call basically like a sis call to the bias. Okay, so I think if I do this and I then do this which is just a call and then I call this then I need to check if uh how do I do that? How do I check now if the bite I'm pointing to is zero? Can I do test and then dsi dsi jump if not zero to print loop? Can I do that? I'm just going to leave it like this and then ask it if I did any mistakes. But if I understand this correctly now, once I did that, I do a clean exit. Not sure if I just have to do um CL C cli HLT. Okay, how do I properly call CLI and HLT? Okay, I just call them. And how do I pat the remaining byes? Okay, cool. So that basically actually I don't need to do this in uppercase times 510. I need to understand the syntax later on. I'm just going to copy it for now. DB0 boot signature. Okay. So I write now 0x AA55. So this is my current code. Would this work or are there mistakes? You're almost there, but there are a few small corrections. Loading DS, you can't move DSCS directly. Must be done in two stacks via the stack. Okay, so I can push CS onto the stack and then pop it into DS. Okay. So, let's just do it like this then. Okay. I have a question though. Um, would this work though? No, I have to work with Okay, you can't load a register directly from an immediate. Okay, in real mode we cannot load directly into segment registers. We need to use the stack. So what we do is we push CS and we pop DS. Then I would like to know why does this work or does it not? But why can't I use move here and don't have to use the stack? There is an op code. Okay, I need to write this down. We can do this though because there is an op code for load a general purpose. I don't understand the difference. Oh, SI is a general purpose register. That is why it works. Okay. Can do this though because SI is not a segment. register op code exists. OP code does not exist. Okay. Cool. So, what else did he say? testing for the end of string after the bite you care about is already in al. So you should test that not test the entire thing makes sense because we're only testing a single bite. So I'm not testing this actually. I'm testing Why is it an al though? Okay. Uh I need to to ask the question here regarding point two. Is my testing wrong? So it does not work or is it just not optimal? actually incorrect. Okay. Okay. So, we're already pointing to the next one. Got it. So, probably this is something I don't understand here that this ends up in the A register. So, lot SB, let me write this down. Lot SB loads next character into AL and increases SR. So, I need to check if that is zero. Good loop structure. A more typical loop looks like this. If zero jump to done. Okay, so this is correct. what I don't understand is um regarding three you are testing right after LODsb and you jump. Oh, makes sense. Wait. Yeah, because you're loading and you want to see is the character I just loaded is this zero. If it is zero, you want to jump to Yeah, makes sense. Okay, I'm going to adjust this. Done. Then you want to jump to done. Otherwise, you want to move and call the instruction and jump always to the print loop at the end here. And if we go to done, we get to CLI, which I don't know again what it does. And we halt. Okay. What I don't understand why do you define halt and to halt jump halt after your last meaningful instruction. You don't want execution to fall through into your data or padding byes which would just run garbage op codes and likely crash. Rehalt after any stray interrupt even though you did CLI to disable. Mhm. You could still wake up the C CPU CPU. Okay. So we just want to have an endless loop for halting just in case. Okay. Understand? Okay. So let me just copy paste this again and see if this is so is this implementation now correct? Will it work? Almost there. Okay, there are two showstoppers. Uh, good. Okay, that's just a syntax stuff. That's just a syntax error. MSG is defined after your padding and signature. So it lives outside the 512. Okay, your code will try to read. Whereas I points to buy that were never loaded. You will get gibberish or a crash. What you need to adjust is you need to do the message before the padding. So, can I just do this? Would this be correct now? Almost. Okay. Small typo. He accidentally concatenated. Oh, I yeah, I mispressed something. Is this correct now? Yes, that looks like a valid 512 bias loadable Hello World bootloadader. You've got the right order as long as you assemble. Okay, so that would be interesting now to see if this actually works. So I assemble now with format bin bootloadader.asm minus o bootloadader.bin. It assembles. So let's take a look at bootloader.bin. I should not be able to read this. There you go. I can only read the string. And if I do object dump-d bootloadader bin, I should be able. Okay, it doesn't recognize the format. Interesting. Cool. Awesome. Now I want to run this in virtual box. Explain all steps. So I should have virtual box installed. I don't have virtual box installed. That's not a problem. Pseudo Pac-Man-S virtual box. Uh okay. Let me just see which is the correct one for arch. Okay. So, I guess two is the correct one. We're actually Okay, I'm just going to go with the default. Okay, so what I do now is I use DD to create an empty floppy image. Then I write my boot file into that floppy image. And then I load that into the VM. It would be really cool if this works. Then maybe next time we can try to boot into the Linux kernel or something. That would be super cool. All right, so let's see if I have virtual box now. Yeah, looks like it. Perfect. And now we're going to do what we were told. So I'm going to use DD. What is DD again? This is the thing that you use in the command line to create images. Okay. So, DD input file is going to be def0 which is nothing. So, we create just an empty thing. Output file is going to be equal to floppy dot image. BS is probably byte size is 512. And we're going to use 2,880 sectors, whatever that means. Okay. So, I should have now the floppy image. There you go. And now I'm going to say the input file is the bootloadader image. And I'm going to load it to this floppy file. And I'm not sure what this means. We're just going to write into the first sector, I guess. So conf equal to not run C no such file or directory that is not true is it bootloader bin sorry not image cool so now we have an image and now I should be able to create a virtual box so I'm going to open up now virtual box let me just open this here in uh what do I have to do here? Name your VM. I'm going to open up a new virtual box. This is some graphics issue I have here, but doesn't matter for now. So, let's go and follow the instructions. Create new. Name your VM bootloadader test or something. Okay, bootloadader test. Then I want to choose DOSs. Okay, this is interesting. I mean I guess it doesn't matter. I can use this for DOSs or I can use this for something else. So I basically use that. I provide base memory. I can go with 16 megabytes is more than enough. I'm going to use 32. That's fine. Disk size. I don't need that much disc size. So, let's go with maybe 100 megabytes. There you go. And finish. So, oh, I created a hard disk. Did I create a hard disk? Not sure if I created a hard disk right now. So, let me just try this again. Other DOSs. I mean, it asked for disk size. I'm not sure if this is what um Chad GBT meant, but now I should be able to say settings storage. Let me just briefly. So, what I'm going to do now is I'm going to go to controller floppy. Choose a disk file. I think this is choose a floppy disc. Yeah, I'm just going to open this on my second screen so I don't have to uh to sensor out stuff if there is some sensitive information. So I'm going to go to documents programming learning assembly floppy image. There you go. So I basically clicked on this button and then on choose uh or choose a disk file and then I selected the floppy disc image. And now make sure it's the only or first boot device. Settings. System. Motherboard. Boot order. Floppy. Cool. Let's see if this works. Terminated. Okay. Virtual box Linux kernel drivers either not either not loaded or not set up correctly. I'm not sure now if this is I think this might be an arch problem. This might be a problem with my system. Yeah. So, yeah, let let's just go with This. So I think this was just an arch thing. And load the modules. Once the right modules are installed, load the virtual box driver. Restart the service. Okay, I don't have secure boot, so that should not be a problem. Install some Nvidia stuff right now. So, this is not really a problem with virtual uh not really a problem with our code, but let's see. But this is awesome, man. I really enjoy coding and assembly, especially if it works. If it doesn't work, I hate it. Take some time. Take some time. So, what is this mod probe thing? I've used it a couple of times. TLDDR mod probe. What is the the goal of this tool? add or remove modules from the Linux kernel. Okay, so basically if I do this, okay, it works. And then I can also load this. Not found. Okay, let's just Which one didn't work? This one. Okay, let's just ignore this for now. Let's restart the virtual box service. doesn't exist. Okay. Not sure if this is what I wanted to do right now. I don't think so. What is the Vbox? web service. I don't know. Let's try virtual box again. Let's try to start this. Critical error has occurred. Let me try this again. Critical error has occurred while running the virtual machine and the machine execution has been stopped. Go to virtual box VMs bootloader test locks. Okay. Virtual box VMs bootloader test locks. Now before I try to troubleshoot this too much, let me just copy paste this into chat GPT to see if maybe the problem is not related to our code. I'm going to even switch to 03 for this. Um, it crashes and I see this lock. Is this because of my system or my bootloadader? Oh, this is too long. I didn't know it was that long. Uh, okay. So let me then maybe just take an example. Where is the arrow? I don't know. Maybe I can look for error. I don't have too many errors. So let me change that very long actually. Okay. It crashes and produces a lock file. When I search for error, I see these. But I'm not sure if this is actually why it crashes. Yeah, let's just give it a try. Maybe I have to look for critical. No red herrings. They are printed every time. For one sector bootloadader, the only thing that will make a virtual box crash is a triple fault. The CPU hit an invalid instruction. Okay, do I have a triple fault? I get default. Triple fault. Okay, seems like there is something with triple triple fault. Triple fault. But I'm not sure if that is I want to have fault. I want to have this fault. H the guest never left. Uh okay. So I don't think I have triple fault. No, I don't see that. image really. Is the image really that size? Let's see. Yes. Is the signature really proper? Hex dump boot bin tail. Oh, not boot. Boot loader. Yes, that should be a valid bootloadader, I think. Easier debugging. Qo plus GDB first. So, what does this do? Q emo Let's give it a try. Not found. Probably have to install this. So, what's happening now? I need to go to assembly again or I'm not sure if I need

Original Description

In this video, I continue to learn Assembly. Today I learn how to build a basic bootloader as well as an XOR cipher. ◾◾◾◾◾◾◾◾◾◾◾◾◾◾◾◾◾ 📚 Programming Books & Merch 📚 🐍 The Python Bible Book: https://www.neuralnine.com/books/ 💻 The Algorithm Bible Book: https://www.neuralnine.com/books/ 👕 Programming Merch: https://www.neuralnine.com/shop 💼 Services 💼 💻 Freelancing & Tutoring: https://www.neuralnine.com/services 🖥️ Setup & Gear 🖥️: https://neuralnine.com/extras/ 🌐 Social Media & Contact 🌐 📱 Website: https://www.neuralnine.com/ 📷 Instagram: https://www.instagram.com/neuralnine 🐦 Twitter: https://twitter.com/neuralnine 🤵 LinkedIn: https://www.linkedin.com/company/neuralnine/ 📁 GitHub: https://github.com/NeuralNine 🎙 Discord: https://discord.gg/JU4xr8U3dm
Watch on YouTube ↗ (saves to browser)
Sign in to unlock AI tutor explanation · ⚡30

Playlist

Uploads from NeuralNine · NeuralNine · 0 of 60

← Previous Next →
1 Visualizing Stock Data With Candlestick Charts in Python
Visualizing Stock Data With Candlestick Charts in Python
NeuralNine
2 Python Beginner Tutorial #1 - Installation and First Program
Python Beginner Tutorial #1 - Installation and First Program
NeuralNine
3 Python Beginner Tutorial #2 - Variables and Data Types
Python Beginner Tutorial #2 - Variables and Data Types
NeuralNine
4 Python Beginner Tutorial #3 - Operators and User Input
Python Beginner Tutorial #3 - Operators and User Input
NeuralNine
5 Python Beginner Tutorial #4 - If Statements and Conditions
Python Beginner Tutorial #4 - If Statements and Conditions
NeuralNine
6 Python Beginner Tutorial #5 - Loops
Python Beginner Tutorial #5 - Loops
NeuralNine
7 Python Beginner Tutorial #6 - Sequences and Collections
Python Beginner Tutorial #6 - Sequences and Collections
NeuralNine
8 Python Beginner Tutorial #7 - Functions
Python Beginner Tutorial #7 - Functions
NeuralNine
9 Python Beginner Tutorial #8 - Exception Handling
Python Beginner Tutorial #8 - Exception Handling
NeuralNine
10 Python Beginner Tutorial #9 - File Operations
Python Beginner Tutorial #9 - File Operations
NeuralNine
11 Python Beginner Tutorial #10 - String Functions
Python Beginner Tutorial #10 - String Functions
NeuralNine
12 Python Intermediate Tutorial #1 - Classes and Objects
Python Intermediate Tutorial #1 - Classes and Objects
NeuralNine
13 Python Intermediate Tutorial #2 - Inheritance
Python Intermediate Tutorial #2 - Inheritance
NeuralNine
14 Python Intermediate Tutorial #3 - Multithreading
Python Intermediate Tutorial #3 - Multithreading
NeuralNine
15 Python Intermediate Tutorial #4 - Synchronizing Threads
Python Intermediate Tutorial #4 - Synchronizing Threads
NeuralNine
16 Python Intermediate Tutorial #5 - Events and Daemon Threads
Python Intermediate Tutorial #5 - Events and Daemon Threads
NeuralNine
17 Python Intermediate Tutorial #6 - Queues
Python Intermediate Tutorial #6 - Queues
NeuralNine
18 Python Intermediate Tutorial #7 - Sockets and Network Programming
Python Intermediate Tutorial #7 - Sockets and Network Programming
NeuralNine
19 Python Intermediate Tutorial #8 - Database Programming
Python Intermediate Tutorial #8 - Database Programming
NeuralNine
20 Python Intermediate Tutorial #9 - Recursion
Python Intermediate Tutorial #9 - Recursion
NeuralNine
21 Python Intermediate Tutorial #10 - XML Processing
Python Intermediate Tutorial #10 - XML Processing
NeuralNine
22 Python Intermediate Tutorial #11 - Logging
Python Intermediate Tutorial #11 - Logging
NeuralNine
23 Python Data Science Tutorial #1 - Anaconda and PyCharm Setup
Python Data Science Tutorial #1 - Anaconda and PyCharm Setup
NeuralNine
24 Python Data Science Tutorial #2 - NumPy Arrays
Python Data Science Tutorial #2 - NumPy Arrays
NeuralNine
25 Python Data Science Tutorial #3 - Numpy Functions
Python Data Science Tutorial #3 - Numpy Functions
NeuralNine
26 Python Data Science Tutorial #4 - Plotting Functions With Matplotlib
Python Data Science Tutorial #4 - Plotting Functions With Matplotlib
NeuralNine
27 Python Data Science Tutorial #5 - Subplots and Multiple Windows
Python Data Science Tutorial #5 - Subplots and Multiple Windows
NeuralNine
28 Python Data Science Tutorial #6 - Matplotlib Styling
Python Data Science Tutorial #6 - Matplotlib Styling
NeuralNine
29 Python Data Science Tutorial #7 - Bar Charts with Matplotlib
Python Data Science Tutorial #7 - Bar Charts with Matplotlib
NeuralNine
30 Python Data Science Tutorial #8 - Pie Charts with Matplotlib
Python Data Science Tutorial #8 - Pie Charts with Matplotlib
NeuralNine
31 Python Data Science Tutorial #9 - Plotting Histograms with Matplotlib
Python Data Science Tutorial #9 - Plotting Histograms with Matplotlib
NeuralNine
32 Python Data Science Tutorial #10 - Scatter Plots with Matplotlib
Python Data Science Tutorial #10 - Scatter Plots with Matplotlib
NeuralNine
33 Python Data Science Tutorial #11 - 3D Plotting with Matplotlib
Python Data Science Tutorial #11 - 3D Plotting with Matplotlib
NeuralNine
34 Python Data Science Tutorial #12 - Pandas Series
Python Data Science Tutorial #12 - Pandas Series
NeuralNine
35 Python Data Science Tutorial #13 - Pandas Data Frames
Python Data Science Tutorial #13 - Pandas Data Frames
NeuralNine
36 Python Data Science Tutorial #14 - Pandas Statistics
Python Data Science Tutorial #14 - Pandas Statistics
NeuralNine
37 Python Data Science Tutorial #15 - Pandas Sorting and Functions
Python Data Science Tutorial #15 - Pandas Sorting and Functions
NeuralNine
38 Python Data Science Tutorial #16 - Pandas Merging Data Frames
Python Data Science Tutorial #16 - Pandas Merging Data Frames
NeuralNine
39 Python Data Science Tutorial #17 - Pandas Queries
Python Data Science Tutorial #17 - Pandas Queries
NeuralNine
40 Python Machine Learning Tutorial #1 - What is Machine Learning?
Python Machine Learning Tutorial #1 - What is Machine Learning?
NeuralNine
41 Python Machine Learning Tutorial #2 - Linear Regression
Python Machine Learning Tutorial #2 - Linear Regression
NeuralNine
42 Python Machine Learning Tutorial #3 - K-Nearest Neighbors Classification
Python Machine Learning Tutorial #3 - K-Nearest Neighbors Classification
NeuralNine
43 Python Machine Learning #4 - Support Vector Machines
Python Machine Learning #4 - Support Vector Machines
NeuralNine
44 Python Machine Learning Tutorial #5 - Decision Trees and Random Forest Classification
Python Machine Learning Tutorial #5 - Decision Trees and Random Forest Classification
NeuralNine
45 Python Machine Learning Tutorial #6 - K-Means Clustering
Python Machine Learning Tutorial #6 - K-Means Clustering
NeuralNine
46 Python Machine Learning Tutorial #7 - Neural Networks
Python Machine Learning Tutorial #7 - Neural Networks
NeuralNine
47 Python Machine Learning Tutorial #8 - Handwritten Digit Recognition with Tensorflow
Python Machine Learning Tutorial #8 - Handwritten Digit Recognition with Tensorflow
NeuralNine
48 Generating Poetic Texts with Recurrent Neural Networks in Python
Generating Poetic Texts with Recurrent Neural Networks in Python
NeuralNine
49 Stock Portfolio Visualization with Matplotlib in Python
Stock Portfolio Visualization with Matplotlib in Python
NeuralNine
50 Analyzing Coronavirus with Python (COVID-19)
Analyzing Coronavirus with Python (COVID-19)
NeuralNine
51 Making Text Images Readable Again with Python and OpenCV
Making Text Images Readable Again with Python and OpenCV
NeuralNine
52 Neural Networks Simply Explained (Theory)
Neural Networks Simply Explained (Theory)
NeuralNine
53 Motion Filtering with OpenCV in Python
Motion Filtering with OpenCV in Python
NeuralNine
54 Top 5 Programming Languages To Learn in 2020
Top 5 Programming Languages To Learn in 2020
NeuralNine
55 Simple TCP Chat Room in Python
Simple TCP Chat Room in Python
NeuralNine
56 Image Classification with Neural Networks in Python
Image Classification with Neural Networks in Python
NeuralNine
57 Edge Detection with OpenCV in Python
Edge Detection with OpenCV in Python
NeuralNine
58 S&P 500 Web Scraping with Python
S&P 500 Web Scraping with Python
NeuralNine
59 Simple Sentiment Text Analysis in Python
Simple Sentiment Text Analysis in Python
NeuralNine
60 Introduction - Algorithms & Data Structures #1
Introduction - Algorithms & Data Structures #1
NeuralNine

This video teaches how to build a basic bootloader and an XOR cipher in Assembly language, covering key concepts such as symmetric key encryption and register usage. The speaker also explores the concept of a minimal bootloader and discusses the size constraint and optimization for a bootloader.

Key Takeaways
  1. Build an addition script in Assembly
  2. Implement a buffer for input
  3. Use a register for the result
  4. Subtract 48 from characters to convert to numbers
  5. Jump to done when encountering non-digit characters
  6. Create a file called exorcipher.asm
  7. Define the entry point as global start
  8. Create an input buffer of 32 bytes in the BSS section
  9. Define a static XOR mask in the data section
  10. Hardcode the key into the code as a string of 32 characters
💡 The key for the XOR cipher is 32 characters long and is generated in Assembly by removing the last character of a string that is initially 33 characters long.

Related Reads

📰
We Let AI Write a Third of Our Code. Here's the Review Process That Kept Us Sane.
Learn how to effectively review AI-generated code with a structured process, ensuring quality and sanity in AI-assisted development
Dev.to · Marketing wizr
📰
AI in Software Testing
Learn how AI is revolutionizing software testing and why it matters for efficient development
Dev.to · Thomas Silva
📰
If You Use GitHub Copilot or Cursor, You Need to See What You're Really Paying Per Sprint
Understand the true cost of AI-assisted coding tools like GitHub Copilot and Cursor by calculating the cost per sprint, as hidden costs can add up quickly
Dev.to AI
📰
SpaceX Just Bought the AI Coding Tool I Use. OpenAI Is Going Public at $852B. Here's What Nobody Is Explaining.
SpaceX's acquisition of Cursor and OpenAI's IPO filing signal a significant shift in the AI industry, with major implications for AI coding tools and cybersecurity
Dev.to AI
Up next
Azure Security Priorities for 2026: Identity, Governance, AI Security & Zero Trust
Valto Microsoft Specialists
Watch →