 walking over to this talk, I was thinking to myself, I'm a full-time job as a developer and I'm thinking, you know, if there's one thing that developers love doing and we're super competent at, it's string handling. It's not like there's an entire industry based on just how poorly we've mangled that up over the years. And if there's a second thing we really love doing and are great at implementing correctly, it's Unicode. So I'm sure we're in for something exciting here with Unicode or emoji shell coding. So help me welcome Adrian and George. Hello DevCon. How are you today? Great. Welcome on board. Before we depart, please make sure that your seat is up, your tray table is towed, and your seat belt is securely fastened. If you have any electronic device, please switch it to DevCon mode now. Please be careful when opening your overhead bins as emojis may fall on you. Thanks. And enjoy your talk. So let's present ourselves. So this is Adrian. Hello. It's his third DevCon talk, and I'm George. It's my second DevCon talk. So security researchers at EcoNormal Superior in Paris, France, we are both French, as you may have guessed, and we both managed to fail at the Turing test, but that's another issue. What we're going to see today? So we're going to talk about some generic tooling and methods to write shell codes under heavy constraints. We'll dive into the dark art of shell coding. We'll play with emojis to make computers do things they definitely shouldn't do. By the way, you'll also see the first emoji shell code ever created. Brace yourselves. We're going to turn emojis into merciless payloads. So let's begin. Who has ever written a shell code? Just raise your hand. Come on. Just raise your hand. Don't be shy. Feds won't arrest you. Well, about 20%, 10 or 20%. So for the remaining, let's explain what a shell code is from the beginning. So a shell code is some code that you either found or managed to inject in your target. This code generally gives you some power. Usually, it pops a shell. That's why we call it a shell code. Now it can do a lot more things than simply spawning a shell. And generally, what you do is after injecting it in your target, you jump onto it using what we call a vulnerability. So you can have buffer overflow, use after fee, and so on and so on. Just go to the CVS list and you have all of them. And the typical scenario is you send a carefully crafted string to your target and you profit and generally you have your shell. However, there are many issues with shell codes. So the first thing, for example, if you have a buffer overflow using a scan F, so you need to input a C string. And a C string, you can't have a new character inside because it breaks everything. Same. If you treat it as input, same thing again about scan F, you can't have white spaces because it will just break your shell code in half. You can have other constraints. So for example, your name can only contain letters, so you can't have a name with digits. Or you can also have string escaping. So if you put it in a form, generally, you have string escaping which tends to break your shell code. And of course, trying to pass your input with containing slash bin slash SH as your first name is not really credible. So it does not look legit at all, so it gets deducted. What can we do? So here we go into the domain of constraint shell coding. So generally, many hackers want to pass their shell codes as pretty stealthy. So the idea is you want to reduce the set of characters that are used for your shell code. One of the normal constraints that have been studied for long is alpha and red shell coding. So your shell code must only use letters and digits. Here we're going to see on x86. And x86 has been solved quite a long time ago, so here it has been solved by Rix in 2001. And the idea is really simple. So you take your letters and your digits, you disassemble them, and you look what happens. So here on x86, it's pretty easy because you have single letter instructions for push and pop, which allow you to manipulate the stack. You can also increase increment and decrement registers with only single letter instructions. You also have control flow instructions like jump and comp. So this is pretty easy. They are all alphanumeric. And you also have the XOR operation, which does an exclusive OR with many, many operands that are all alphanumeric. So it's pretty easy shell coding on x86. And if you want to switch to x64, so it's pretty easy. You just put a capital H in front of every instruction you want, and it works, except for increasing and decreasing registers. So x86 is pretty easy. Actually, it's even so easy that other people manage to go much further than that. So people tried, so this is not alphanumeric anymore, because here we add some spaces and punctuation, but people manage to write shell codes entirely in English. So the idea is you take English words, punctuation signs and so on, and you want to make a shell code that looks like English. So this will be our first demo. So in this scenario, what we'll be doing on x86 computer, so we will do a set user ID exploit. So this happens on a lot of computers. So take for instance changing your password. To change your password, so any user can change his own password. For this, you have to modify the password file, which is on Linux on ETC shadow. And for this, you do not have the right permission to do so. So someone has to change the password for you. For this, we have a specially crafted program, which is called a set user ID program. So it's a program with a special permission that a user can execute that performs actions at the administrator level, which is root on Linux. So here we can check for this program here. We can see it's called main, it's in red. And we have the S bit in the permission that describes that it is a set user ID program. So if this program has a vulnerability, instead of changing just your password, what you can do is send a shell code to have other actions. So here we want a root shell from this vulnerable program. So it's purposely vulnerable here. So I just take my shell code so you can see indeed that it looks like English. If you try to understand it, actually it does not meet anything. And then when I paste it, I press enter. And here I have my root shell that just spawned. So I can check indeed. I have UID 0, which is root. Thank you, George. So we have seen that doing alphanumeric shell coding on x86 works fine. What about other architectures? Well, let's look typically at risk architectures, aka reduced instruction set. Well, then we don't have single characters instruction anymore. And we also have very few addressing modes. So no way to do instruction from memory to memory. And, moreover, we have very heavy constraints on the operand side of instruction. So basically this means that the previous techniques doesn't work anymore. So let me present you three ways to get around that. Namely, compilation, emulation, and unpacking. So the first one is compilation. And the idea is that you want to write a compiler, which instead of targeting your usual architecture, will target the constrained architecture. It has been done in the past for slightly different things, which is called single instruction set computer. Typically, the morph scatters is a compiler, which takes any arbitrary C code and compiles it for only the move instruction on x86 because this instruction happens to be too incomplete. So it works quite fine for one instruction set computer, much less when it comes to our risk setup, because then the constraints are on the operand and not on the opcode. So writing a compiler is much more difficult and like nobody really knows how to do that. So this approach is a bit bad for us. So the second one is the emulation way. And this time, the idea is to spend quite some time to write a small interpreter for some language. This interpreter will pass the filter. Typically, it would be a phonymeric. And then since you have an interpreter, you can encode any payload, arbitrary payload in your target language and interpret it. This is typically what Yunnan and Overs did in 2009. So they did it for ARM V7 and wrote a brain fuck interpreter. So it works fine. But there's an issue with this approach. Namely, it's that the harmfulness relies on what you can do with an interpreter. So if you want to use it on actual exploit, it means that you need to escape the interpreter or that the interpreter has to be able to write outside of its sandbox. And typically, in Yunnan case, it's not the case. So we're a bit stuck here too. Third one is unpacking. So this time, we want to encode our payload in a constrained, compliant way. Typically, I want to find a way to encode my payload in alphanumeric. Base 64 would be almost good for that. And then identify, like, high-level constrained and try to write some alphanumeric unpacker from that, which will be able to unpack my payload, then jump on it and execute it. So you spend some time writing this unpacker, which is alphanumeric. You have your payload, which is encoded in alphanumeric way, unpack it, jump on it, and then you can run arbitrary payload. So this is what George, me, and some of our colleagues did previously from ARM V8. So we're going to show a small demo of that. Good. So in this setup, we have a small account manager, which is very badly written and has an obvious buffer overflow vulnerability in it. So it's asking for your username. And obviously, before getting to the buffer overflow, there is some check to make sure that the username looks like a valid username. So alphanumeric works fine here because the username, which consists only of letters and digits, is quite legit. So we are going to use our payload here. As you can see, it is only made of letters and digits. And we're going to use that as our username and take control of this account manager. Here, the idea is to dump the ETC Shadow file, which is a Linux machine, the file which contains the hash of all user account passwords. It takes a bit of time because the terminal is a bit slow. Good. Let's finish. And then we have a win. Our payload just dumped the slash ETC slash Shadow file, and we have the hashes of all passwords. So in a sense, we can, I think, almost say that alphanumeric shell coding is solved. It even works for the RISC-5 architecture. And this is what some colleagues, George and I, presented in DEF CON 27. So don't hesitate to jump back in time and see our talk again. Back to emojis. A few months ago, Bluedit and Jorain, which is a security researcher, asked George and I, well, you have done alphanumeric shell coding. Could you maybe do emoji shell coding? I didn't think about it and found a very good reason why it was impossible. So just gave this reason and I was happy with it. Then, 2 a.m. next morning, I just wake up and realize that my reason is totally wrong. Like, I did a mistake. And so I tried to fix it. And after a few hours, I realized that, well, I can't fix it. So I'm only left with one possibility. That is to prove that doing emoji shell coding is possible. Hello. And then I woke up at 8 a.m. I opened my mailbox and what I found, a horde of wild emojis that were just saying hello world to me in KMU. So when you see that in your mailbox, the first thing you say is, what the fuck is this? And then you look into it. Then you ask for the source code. Then you look more into details and you find bugs. And with all the bugs I found, I said, how the fuck does it even work? There are bugs everywhere. And then I just went and saw Adrian and we sat together on the table and we said, let's clean this shit and send it to DevCon. And here we are. Good. So we want to execute emojis on some architecture. So execute emoji code. For that, we first need to look at emojis and try to define a bit what emojis are. Well, let's say I wanted like 10 years ago to send a nice text to my girlfriend. So I typed my nice I love you. The probability that she would get this instead was unfortunately quite high. And well, this is not exactly the same meaning. So we needed to do better. And fortunately we have Unicode which is now quite an old standard to the rescue. We can take the Wikipedia definition which is that Unicode is a standard for consistent accounting, representation and handling of text expressed in most of the world writing systems. Namely that like we want that everything displays quite the same and in a consistent way for everyone on any system. So what do we have in Unicode? Well, obviously we have Latin letters such as this capital A and on this part Unicode is actually compatible with ASCII. Then you can find many other scripts such as Japanese characters, more obscure stuff such as the whole set of alchemical symbols. Yes, it's in Unicode. You have also the whole set of playing cards, spilies and some odd characters such as QnA form. So this is a single Unicode component. So this very wide character is a single Unicode character. And then more stuff such as the Holy Han grenade of Antioch or Kim Kardashian. Well actually not the last two ones, at least, well, not yet. So we have a very small sample of Unicode characters and now the question is, well, what's an emoji in this? Capital A, well, clearly not an emoji. Smiley, clearly an emoji. But maybe what about the jack of spades? Well, you look into the Unicode standards and well, it's not an emoji. But let's replace the jack of spades with the black joker. Then the Unicode standard says that it is an emoji, starting to get a bit confusing. And let's switch it again from the black joker to the white joker. Then Unicode says this is not an emoji, even more confusing. So we are going to settle for a very simple yet a bit subtle definition, which is that if Unicode says it is a qualified emoji, then it is an emoji, period. And in UTF 8, which is a way to represent Unicode code point in bytes, emojis are at least three bytes such as this nice smiley face and at most 45 bytes. Moreover, there are new emojis every year and we are currently at Unicode version 14. So for today we are going to consider doing shell coding with UTF 8 emojis on Unicode version 14. Good, so we have emojis here and then we need to run the emojis on something. So we are going to use Rescribe. What's Rescribe? Well, Rescribe is the architecture of the future. Or well, this is what we said three years ago at the Con 27. I think now we can even say that Rescribe is the architecture of the present. Well, since 2021 you have some real Rescribe products that you can buy as a customer so maybe you already have Rescribe CPUs at home. And in more technical terms, let's see what we have in Rescribe. Well, this is a simple risk architecture. They push a lot to have open source ISAs and also they push a lot for open hardware. And in Rescribe you have two and four byte instructions and it is little engine. Remember that for later. Well, so now I need to execute my emojis on Rescribe. Let's try to look back at the method we saw previously in the previous work and see if it still works. So, Alpha numeric x86. You had to take the whole set of single letters. It gave you a set of instructions. You realized it was too incomplete so then you could shell code in that. Alpha numeric over risk architecture such as ARM v7, v8, or Rescribe you took the set of quadruplets of letters on digit. It gave you a set of instructions. Again, you figure out it was too incomplete so you were good. What about emoji Rescribe? Well, let's use the first method. I take my list of all emojis, see how many of them can be executable as Rescribe. Too bad, only ten of them are. So that's not too incomplete at all. Let's try the second method like pairs of emojis. We still have very, very few pairs of emojis which are valid Rescribe code. And if I go along and I take triplets, quadruplets, it's not getting better at all. So we are stuck. The previous method will not work here. So I'm going to try to present you the way it works before we are able to fix this issue with an example. So on the bottom of the screen you have this A-U-I-P-C instruction, which is in Rescribe a way to load the PC relative offset into the RA register. And if you look at how it is at its exact decimal representation, it is 97, F0, 9F, 97. And this is not a valid emoji. This UTF-8 is not a valid emoji. So we are going to split it into like this. 97 and write the other parts. So let's try to take all the left part. I want an emoji which ends with 97. So I look into my big bag of emojis. Find one, this is the OK emoji. We start with F0, 9F, 86. And too bad, these three first bytes are not Rescribe code. Typically, this is three bytes and as I told you, there are no three bytes instruction in Rescribe. But maybe we have another gadget which can do jumps and then you can jump directly on the 97 and execute our A-U-I-P-C. Let's look a bit more into our bag of emojis and this time we find the bang emoji, which ends with 97 and starts with E290. This time it's quite nice because E290 is a valid Rescribe emoji, add S11, S8. So at the expense of trashing the S11 register, I can then start directly this gadget, execute my add then my A-U-I-P-C which is my target. Good, we have two ways to do that and on the right side it's going to be quite similar. So this time I want an emoji which starts with F0, 9F, 97. Look again into my bag of emojis and I find the calendar emoji. It ends with 97, EF, B8, 8F which is a valid Rescribe instruction. So this time at the expense of trashing the T6 register, I can finish my gadget. Again, last time let's look into our bag of emojis and we find the bin emoji. This time the last four bytes are not valid Rescribe but 9-1-EF is a small forward jump. So again I can end my gadget by jumping out of it. In the end this is quite good because I can use any combination of OK bin, OK calendar, bang bin or bang calendar and execute things and I have quite a trade-off between the gadget styles and trashing registers or not. Good, so the question is, well I could do it for one specific instruction, how can I do that, how can I find a way to generate all possible gadgets and a whole list of emoji compatible Rescribe instructions. Well, for this we have to take a little step back. So we'll be talking about code reuse attacks. So for the people who know it already think about return-oriented programming or just-in-time sparing. But here let's present for those who do not know it. So return-oriented programming has been published originally by Shaham and others in 2007 and the idea is really simple. So you take a huge binary, typically the C-standard library, and then you just scan it and you find small, little reusable code snippets. So those little code snippets are called gadgets. And the idea is once you have a whole collection of gadgets, what you do is you try to assemble them together, you chain them in order to have your shellcode. So you just rebuild the shellcode in the form of what we call a rob chain. Then you send this rob chain as input in the vulnerable program, and you still have your shell that pops. There is a variant of it which is called JIT spraying that has been published by Blazakis in 2010. And the idea is instead of scanning your binary to find gadgets, what you do is you just create them by controlling some code that then is compiled using a JIT sprayer, just-in-time compiler. So here the attacker, for instance, has on the right side of the screen, on the top part the attacker can control and write any code he wants. So this is typically JavaScript, for instance. So what the attacker does, he assigns to the variable y some immediate that are absorbed together. If you send it to Firefox, this goes through the just-in-time compiler and is then compiled as the binary code that you see below. And in this case, it's pretty easy because the attacker manages to control four out of five bytes of the final program. So here you can generate gadgets as you want, and you can just do your return-oriented programming as before. So this is JIT spraying. So here we have to do the same with emojis. So we can control emojis, and we need to build gadgets from it. So how do I create gadgets from emojis? Here it's a little bit complex because do you remember the infinite monkey theorem? It states that if you take a monkey, you give it a keyboard, and if the monkey types on the keyboard for an infinite amount of time, then almost surely he will type any given sequence. So here we do the same, and we take our monkey, and we give him an emoji keyboard. Only problem is that there is no algorithm to look for gadgets in an infinite stream. So previous methods were only scanning binaries, but not infinite streams. So here we have the output of a monkey here. We need to invent a new algorithm. So let me explain this algorithm. So here we have three lines. So on the first line, what we have is the emoji stream. So this will be a stream of emojis. This will be what our monkey will type. Then this emoji stream will have a hexadecimal representation that is on the middle, and we must synchronize it with some executable stream. So this is risk five instructions, and both should coincide on their hexadecimal representation. So let's start with an instruction. So let's take, for instance, add S7, S7, S7, S8. So here I have an excess of my instruction stream. So what I must do is find an emoji, which starts with E290. So let's take our bag of emojis and take, for instance, the chain emoji here. So here I go on the opposite side. So I have an excess of emojis. So I must find some executable instructions that fits the hexadecimal representation here. So let's look what is inside. So I find an OR immediate, which fits. And here is something very interesting, because here I managed to end my emoji stream and my instruction stream at the same point. So both are synchronized here. Both are synchronized here. And what I can do is I can just stop here and consider that this is a gadget because I can reuse the chain emoji independently without taking care of what comes before or after. So this is a gadget. Let's go to a second case. If I take the basketball player emoji. So again, I have an excess of emojis here, so I must find an instruction. So this B9EF is a branching instruction. So it's a small branch forward. So this is another very interesting case because now I can escape out of my gadget and I do not need to end my basketball player with other described instructions. So this is another gadget. So we can see here the second gadget that we managed to generate and we can reuse it as it is. Let's go to the third case. So let's take the snowman emoji. So again, I look for an instruction that starts with 84. So let's take for instance, store word. And then here I come back to the beginning where I have an excess of instructions and I complete it with an emoji. So the copyright emoji here. And again, I can do the same as before. And here I have a branch which ends my gadget again. So I do this for every possibility. And in the end, I have a whole list of gadgets that are usable for shell coding. And so on and so on. Just a side note, for people who know a little bit about grammars, so the method we use actually is really generic. As you may have guessed, the algorithm follows derivations of a grammar. In the form, we have a non-terminal that produces a terminal followed by a non-terminal. Here our terminal is emojis. So for people who know about it, this exactly describes what we call a right linear grammar. And there has been a very interesting property detailed by Patel in 1971 who says that any regular gram expression, which is typically for computer scientists what we call a regexp, is converted to a right linear grammar. Of course, adapting the tool is left to the reader as an exercise. Well, let's get back to emoji now. So I managed to generate all gadgets that can be implemented using emojis. Now we just have to change them. Good. So let's try to write our emoji change. Using the output of our previous algorithm, we want to look at which instructions are indeed emoji compatible. And well, at the beginning it looks quite fine because we have a bit more than 4,000 RISC-5 instructions which I can find in at least one of the gadgets. And if you look at what kind of instruction we have, first we have some logic instructions like add, end, sub, and more. So that's quite good. We have branches, both conditional and unconditional, both forward and backward. That's very good because for control flow, that's very useful. We can address many registers. So here we can see we can address 14 registers, but not the stack pointer. Don't worry, even if we cannot touch the stack pointer, we can still find ways around. And in practice, it's not that much of an issue. However, we have very few immediate, so very difficult to load constants. And actually in this 4,000 instruction, we have quite a lot of floating point instructions which we don't want to use. To give you more idea of what we have, for some families of instruction, such as the CSR family, we only have a single one of them. So this is the one displayed here. And in the end, what we see is that we have a tiny bit of everything. So the set of risk-5, effemogic or compatible risk-5 is very diverse and very difficult to work with because it's very difficult to combine one instruction with the other. Yet, we do manage to do this. And I'm going to show you the overall view of what our shell code looks like. So we use the unpacking method that we showed you previously. And basically we have a small initialization part, then our unpacker which embeds the encoded payload. So the unpacker will unpack this payload in memory, then jump on it. And it means that it's very easy to change the payload because we can generate the unpacker easily from the payload. Let's focus on the unpacker. So in our last talk, we went very far into finding ways to do very efficient unpackers and with many gadgets to do that. For this time, we're going to go the very opposite and write a very simple unpacker. So for that, we will only use three gadgets. One is increment the A1 register, second one is write the value of A1 in the pointer pointed to by A3 and the last one is incrementing the A3 register. So with that, we can write an unpacker. I will show you how. So for this, we take an initial payload, which is a very dummy payload of only three bytes, three, 20, and 10. And if we go back to initialization, what we do here is that we make sure that A1 is zero and then A3 is set to the first address of where we want the payload to be decoded at. So let's back to it. We have A1 equals to zero. Let's output three times the increment A1 gadget. So then A1 is free. And we can store A1 in A3, increment A3. From three to 20, it's 1D. So we output 1D times the increment A1 gadget. A1 is not 20. We can write it. We're good. And from 20 to 10, well, we have to output the A1 plus plus gadget at zero times so we can write it in memory. So this is the way that we generate our encoded payload. If we execute this, well, then we start from A1 equals zero. A1 plus plus three times A1 equals three. We write three to memory. Then we add 1D to three. It's 20. We write 20 to memory. And add F0 to one. So A1 is 10, write it to memory. It means that the initial payload is equal to the decoded payload. And we have found a way to encode any payload into our encoded payload which will decode at the exact same initial payload. And since all of this gadget, A1 plus plus, A3 plus plus and store A1 is in A3 are emoji compatible, it means that the whole encoded payload is only made of emojis. Let's present you, like, a bit in details how we do this A1 plus plus, A3 plus plus gadget. Okay. Time to switch to GDB over Beamer. So here, let me present you what we have. So on the first line, we have the emoji stream as before and we have its hexadecimal representation on the bottom. So here, let me spawn my binary code. You have the two gadgets on the left part of the screen. You have the registers on the right part of the screen and you have the memory where we want to store our payload on the bottom right part of the screen. So let's start with an up-like operation for the first gadget. So this will just trash the value of S3. If we go to the next one, we store A1, which has been initialized to AB before, to the address pointed to by A3 which is 8,000. Then we just take our branch, which will jump to the next gadget and we start with another up-like instruction. Same, we have a branch to the next two bytes, which is also an up-like instruction. And in the end, we add the value... In the end, we add the value of T2, which is 1, to A3, which will increment A3. And we can continue as we want. Here, I have a small gap between the two gadgets and I can fill it with whatever I like. So here, I can fill it, for instance, with three England flag emojis. All right. Let's switch to the demo. So here, I will present you a demo on a high-five-unleashed board. So this is a quad-core RISC 5 64-bit board. So now it has been discontinued, so we can't buy it anymore, unfortunately. And it manages to run a Linux. So if it has a Linux, let's play with it. So in this case, what I made is a small network interface that is vulnerable to a shell code. And here, I can check that I have my shell code, which is all emojis. So you can see my emoji shell code here. And what I will do is I will just send it through the network to my high-five-unleashed board on its vulnerable interface. So let's send this shell code to the high-five-unleashed. So I just cut it through Netcat. I press Enter. And here, I managed to get my shell. So let me check if the CPU is correct. So let's see. I can see that indeed I have a RISC 5 CPU from C5. And if I just check who am I, I'm root. So I managed to get my root shell. Well, I went a little bit quickly over one thing. So I have my gap between my two emojis. So what I can do instead of just putting England emojis? So I can put whatever I want. I just need to find emojis whose size is compatible with the gap. So this is just a variant of the subset sum problem. So you can look in Wikipedia how we solve it. And in our case, it's very easy because we have three and four bytes emojis. And as we know, every number above six can be written as a sum of three and fours. So it's really easy to solve it. If we want to have a little bit fun, so we can instead, for example, try to look at how I can fill this gap with the minimal number of emojis. And this is standard dynamic programming. It took me exactly four minutes and 13 seconds to solve it and implement it. So you can try it and it's pretty easy. Well, and now I can fit with whatever I want. And this gives me something very interesting which is called polymorphism. And this is almost trivial to have polymorphism. What is the purpose of polymorphism is to generate many variants of the same shell code that all behave the same. And this is very useful because now you can pass antiviruses that generally use the notion of signature, so they compute the hash of your shell code and check in the database if it's already known. So now I can generate as many shell codes as I want, whose hashes are all different. So for example, I can put five emojis here. I can also put these 10 emojis or more emojis as much as I like. When you do shell coding for real, sometimes it happens that pointer arithmetic is a bit flawed and you don't know exactly where the vulnerable program will jump on your payload. So to make up for this, you start your payload with a long list of knobs, which makes that even if it doesn't jump exactly where you want, it will just follow the list of knobs until it gets to the start of the meaningful part of your payload. So this is what we call an upslade. And in Unicode, we have something which is called... we have like a sled emoji. So obviously as hackers, our first question was, well, can we do our upslade using the sled emoji? Well, the answer is yes, we can. So we have to copyright it, put a few knobs, and as many slides as you want. So believe me or not, but this is perfectly executable RISC-5 code. And with that, we can do another demo. So this time, this is on RISC-5 32-bit. So this time, I have the word with me. So this is a nice, expressive ESP-32 SIFRI board. If it is too small for you to see, well, just look at the slides. You have a picture in much bigger. And a nice thing about this one is it costs nothing. You can get it for less than $10 from your favorite distributor. So it's very nice to hack with. Good. So for this demo, we have decided to use a very bad coin wallet. So this one is again, vulnerable to an obvious buffer overflow. And it's going to ask for the passphrase to just access it. And so obviously we want to use our emoji shellcode to, well, get the private key of the wallet. And if we can get that, this private key, we are rich because we get all coins. Let's get that. This will be a bit slow because we don't get that. Good. So here you have the end of our emoji shellcode. We have used polymorphism here. This is why it looks a bit nicer than the previous. And at the end, you can see that it worked. So we have done the private key of the wallet. And so now we are rich unless you manage to get the private key and extract the money before the end of the talk. So it worked. As a conclusion, well, we have shown you that we are able to do RISC-5 emoji shellcoding on both 32-bit 64-bit slides. And that's the method that represented you, even if it was a bit technical, could be used for other kinds of filters, other kinds of constraints. And we have to talk a bit about what happened during the making of this project. So it might not be easy to see, but all of these slides are made with latex. So we had many issues with latex. And typically, we did crash Tech Studio, we did crash Real Attack, and more. Most PDF readers cannot display our slide correctly. Acrobat reader is probably the worst. And all other PDF readers have various glitches. We even had issues with VLC. We found that recording the demos would not play on VLC. So I had to convert them all from MKV to MP4. We found a way to break Firefox. So this is Firefox explaining currently the... I'll do it. Yes, good. And if you press F5 with PDF in fullscreen, then you lose crawling in the tab. Like, I cannot crawl anymore in the screen with PDF. And if I press F5 again, this is this. Good. Well, it is still broken, so I have persistently broken this tab. So well, I'm good to switch to the new tab, the backup tab to finish this talk. Well, other things such as terminal slowness and cups, if you know about it, this is what we use in Linux to print things. So I did there, George, to print the slides. Tell us what happened. So I tried to print the slides, and I managed to break both my computer and the printer at the same time. And since then, I was not able to use my printer for any task at all. I have to do a factory reset, I think. Good. We also have a GCCseq fault, which we need to investigate, and very big things for Windows, for the occasional BSOD when compiling the slides. Bottom line, emoji support is hard. There are still many issues in libraries, software dealing with images. If you want to find exploiting them, it's probably a good bet to look at them. In the end, obviously, we do release all of what we did. So you have a GitHub repository. Don't hesitate to click on the link. If you cannot click on the link on the big screen, just remember the short link. You have our email address if you want to contact us. And if you have any questions, don't hesitate to come to the bottom of the stage, and we will happily answer them. Thank you very much.