 So, we had some AV issues. I had a really cool demo that was going to be running on Dolphin emulator. We're not going to get to see that, I don't think, which sucks because I was going to hack Luigi's mansion. Maybe we'll figure it out if we have time, but we're just going to jump in right now. So, this is XenoScan, scanning memory like a boss. Of course my remote just stopped working. It loves me today, guys. Sorry. Okay, there we go. So, I'm Nick Kano. I'm 24 years old. I wrote the book Game Hacking, Developing Autonomous Bots for Online Games. I'm the CEO and lead engineer at XenoBot, which is where I make and sell my own bots for online games, and I'm also a senior security architect at Silents. So, XenoScan is an open source memory scanner, and it's written using modern C++ with Lua embedded. It's highly extensible, and I wrote it with advanced users and automation in mind. A lot of memory scanners out there don't have that, so that's kind of what I targeted with this. So, you might say, okay, wait, what's a memory scanner? Is it this thing? No, that is not a memory scanner. As cool as that looks, I am not that cool. So, this is a memory scanner. Basically, what a memory scanner does is you start a scan with some initial criteria, then you run the scan, and it'll scan the memory of a remote process looking for anything that matches that criteria. If you've found your target, which general means you have one or two addresses, then you're good to go, you're done. If not, you keep updating your criteria to reflect changes in the game, and then you keep scanning until you've narrowed down the list to something you want. So, in practice, that looks something like this. We have a game and we have 500 health. So, we set our criteria to 500 and you went 32. Let's say that's the type of health. And then we do a scan and we get these results back. We have like 12,345 results or whatever that are equal to 500. Obviously, that's probably too many. So, then we'll change our health in the game to 450, and when we do that, those values will change accordingly. And then we can run a new scan and narrow them down. Some of the values changed to 450 as well. Some didn't. Some stayed 500, but we narrow it down to the ones that are now 450. Now, we still don't have enough. We still have a couple hundred. So, we'll set up our criteria again to where we heal in the game. And now we have 550 health. So, we'll set that criteria, scan. Boom. We have our final value, our health, we're done. So, in practice, that's how a memory scanner works. And that's what all of the memory scanners that a lot of you have probably heard of or seen before do. I take it a step beyond this, but I just wanted to get this out of the way and say, this is what we have, and then we're going to look at what I've added and what I haven't seen before that I think is cool. So, you might be asking why another memory scanner? Well, existing ones, they just don't cut it. So, their source is either closed and you can't look under the hood, you can't add your own stuff, or it's extremely messy, hard to understand, outdated. And they're lacking a lot of easy to make features. So, there's a lot of stuff that you can write scripts for in existing memory scanners, but sometimes you don't want to write a script to do something, you just want it to be there for you. And that comes from their lack of vision, really. They don't sit down and say, how can I make this better for people to use? And they're designed for beginners. Like, cheat engine is like point and click. You just put in the number, hit next, keep scanning, you have your values, but you can't really do much with it. You can't automate it, which is if you're hacking games at a very high level, you want to be able to automate the scanning. You want to be able to throw something open and run scripts against it to find memory addresses, stuff like that. So, I went with a focus on that. And so, why am I telling you? Like, why do you care? Well, I think memory scanners are cool and very powerful, even if you're not hacking games. And we'll get to that at the end. They can show you how to work with raw memory at like the lowest deepest levels. And there's a very specialized set of like app sex skills that you need to understand them and make them, knowing how to pull memory from other processes without crashing them, knowing how to tell different types of memory apart, whether it's readable or not readable, and all that cool stuff you'll have to do. So, we're going to jump into a technical overview and just look at what the code looks like. And then we'll get to some demos that I hope work. So, the languages and tool chain are CMake, C++, LuaJIT, and Git. Git for source control, CMake for building projects, and then C++ with embedded Lua using LuaJIT, which is just a just-in-time compiler. You can see two scripts here. The top one, if you're compiling on Windows with Visual Studio, you do that. You have a Visual Studio solution. It'll compile. Everything's done. Compiles LuaJIT and everything. If you're on another system, you might have to do something like on the bottom. You probably don't have time to like memorize this, but you can get the slides afterwards. And there's no user interface. So, instead of having a user interface we're going to click through, you're going to write code to do your scans. And this code just reflects the scan that we went through with the diagram a few slides back. It scans for 500, then 450, then 550, waiting for user input in between each scan. And then it just takes the results, serializes them to a table, prints them out, and you're done. So, the code is architected into three main projects. There's the project you can see on the left here called XenoScanEngine. That's the core scanning code. That's the heart of the scanner. That's what knows how to search for certain types of values, knows how to flip endianness, knows how to search for chunks and thread all of that. All the fancy stuff is there. It exposes three things, a scan variant, scan target, and a scanner. A scan variant just wraps any type that you might be scanning for. So, integers, strings, and everything. Whereas the scanner target is the wrapper for what you're scanning. So, you can scan a Windows process. You can scan a game running in an emulator. There's a lot of different things you'll be able to scan in the future as that is extended. We'll get to that as well. And then the scanner that's exposed is what actually does the scanning. Then the project all the way on the right, XenoLua, is just a wrapper around Lua. Lua's kind of old school written in C, not really easy to use. So what I've done is write a wrapper around that that has a variant system and everything to make it easier to use. And then in the middle you have XenoScanLua which ties everything together like so. There's C++ code doing object translation of the scanner targets and the scanner as you can see with the orange lines. And then there's a type translation of the variants. And that C++ level translation then goes and talks to XenoLua and exposes these objects and types to Lua. Now you can see these green connections. The dotted green connections are kind of, they're like indirect connections through Lua. So you can see those on either side of the XenoScan Lua. What that means is once the values are pushed from C++ into Lua, there's then a Lua library that wraps them and makes them even cleaner to use. Those are those dotted lines. Then the green lines are the scripts the user will be running and the library itself and they have a green line joining them which means they can talk to each other. And those are running in pure Lua code which is what is user facing. If you're not writing code on the scanner, you're just using the scanner, you're going to be writing Lua which is really ubiquitous in the world of gaming both for game hacking and actually game dev. So I think it's a good language choice here. So we have general basic scanning functionality. We support all the types. So integers of all witnesses from 8 to 64 are both signed and unsigned as well as 32-bit floating points, 64-bit floating points and strings that can both be single byte or multi byte. And it just, there's also composable types. So instead of just saying I want to scan for this integer, you can say, well, I've torn this game apart before. I know exactly what the structures look like and what I'm doing now is I'm automating the process of launching the new version of the game, putting in known values and then scanning for those to find the new addresses where that stuff is located. So you might make a structure for that that reflects what the actual structure of the thing is in that game and then you can fill in all the values and it will search for the entire structure. And really what's beautiful about this is that, you know, 500 might appear in the game a lot of times and 600 might appear in the game a lot of times. But how many times do 500 and 600 appear sequentially back to back right next to each other? A lot less. So as you make a structure and you compose it and you set up all your values, you narrow the margin of error when scanning, taking it from having to do like five re-scans, six re-scans to one. So we're going to try to do the demo here. So the demo is just this code right here, scanning against the little video game that it's going to pop up. And I don't have the code open like I planned to because I had to switch laptops. If everything goes as planned, what's going to happen? It's going to scan for a structure doing one scan like we just looked at. And if it finds the right address, it's going to overwrite the X and Y value of the little object in this game to the finishing value and the game should say, okay, you're a winner. So I'm just going to run that really quick one sec. So you can see your game there. When I hit a button, it's going to start the scan. You won't be able to see it because I can't move everything over to that screen as planned. So sorry about that. So I'm starting the scan now. It's going to search for the exact same values we just saw or it's going to freeze on me. Oh, I'm in the wrong window. Okay, running the scan, we're winner. You can see the green box move to the bottom right there for a second. That was it moving from its starting position to the finishing position. Obviously this is a really contrived game that I threw together just for an example, but it works. And now we need to try and close it when we can barely see. Cool. So on top of that, I have put ranges in so that if you don't know exactly what a value is, but you know, it must be between 500 and 1,000, then you can just say, okay, between 500 and 1,000. And you can do that by either specifying the type and then inside of the type function, putting the range function and the type system will sort that out for you. Or you can say, I have a range and then put the type first and then put the two values, it'll sort that out for you. If you're doing it in a strongly typed way, such as a structure where you've already defined all the types, you don't even have to do any of that. As you can see in the bottom code block, you just say equals range and it's going to figure out the types automatically. There's also place holders. So think of this as like a wild card, like dot star, if you're familiar with Reg X, where you just put in these empty brackets, which is an empty Lua table. And what that's going to do, it's going to say, I know this is part of the structure and it takes up this much size, but I don't know the value. So when you hit this part of the structure in scanning, except anything, move on to the next thing. So that might look like this. This is the same as before, but our stage is now set to a place holder, our level is the same, X is the same, but Y is now a range and Max Health is now a range. And if we run that demo again, what we should see is that it still works with those changes. So I'll go over this really quickly. So we have that little green square on the left. That green square needs to move to the yellow square to win. I forgot to say that last time. So we're going to do the same scan as before and then we're going to pull the first result and overwrite the X and Y values of that first result. That's all we're going to do. And what should happen there is it should go to the end as it did before. The thing is, is the first result going to be right? Because now our structure doesn't have the constraints that it had before because we have ranges in there. It allows for more error in there. But if we run it, we see that we still win because even though we lowered our constraints, the constraints with the structure there were still enough to find exactly what we're looking for. Even though there's all these graphics going on and all this drawing and all this other state in the game, that might just happen to look similar. Sorry. That's supposed to be at this slide when I did that. So and there's variable typed values as well. What I mean by that is you don't have to use strong types like we've been talking about. You can specify type mode exact, which is what we've been talking about and is only what supported in structures. Because if you try to do variable size types and structures, the complexity just blows up. Because you have to generate a new instance of that structure for every combination of every week type you have in there and then you end up with like 500,000 different ways the structure can look and it just blows up. Can't sustain. But for everything else, if you're just scanning for a value, you can say type mode type, which will do other values of similar types. So if you say you just put 500 in there and you say type mode type, it's going to do all integer types and floating types. If you do type mode exact, it's only going to do the integer type you specify. If you type mode loose and you put 500 in there, it's going to search for 500 as any integral type of any signedness or floating point types or strings that say 500 because why not? Not sure why you want that, but we have it anyways. And if you search for a string with type mode type, it'll search for it as both wide or single byte. So now this is the part of the talk that this is what I really want to talk about because right now we've gone over generic memory scanner stuff. If you've hacked games before, everything I just told you, you're like, oh, that's cool. The structures are cool, but you can write a script for that. There's not really anything new. Why the hell are you here? And this is what I want to talk about is data structure detection. So in my book, I showed some cheat engine scripts to do this. And after I wrote the book, I was like, wait, why do I have to write a cheat engine script to do this? Why don't I have a memory scanner that does this? So that's what I set out to do. So we have to make a few assertions first. The first assertion is that a data structure is just a complex interconnected web of pointers. Just pointer pointing here, pointing there, pointing there, pointing there. But each data structure has very specific characteristics and shapes. And if we can detect those characteristics and detect those shapes, we can detect the entire data structure. Furthermore, a process is just a massive super complex data structure. So if we take the web that is that process and try to sort through it, then we can find all of the data structures which it contains. So I said in the last slide, I said hypothetically you could do this, but it's not hypothetical anymore because I've done it and it looks something like this. So as you can see on the top left, first we're going to scan for all of the valid pointers in the process we're attached to. Now what I mean by a valid pointer is anything that is a value that looks like a value for valid memory space within that process. So it could be a value that's not a pointer and by chance hits valid memory space, but we're going to use it anyway because we can't tell the difference. And we're going to organize those results into a pointer map. The pointer map is this weird thing you can see here, bottom left. So you can think of it as like just a map, key value pairs, where the key is a pointer and the value is a list of pointers that point back to that pointer. So if you take the top example here, we have OX0001, 000, and it fans out up into the right and shows all of the values that point to that pointer. So once we have these maps, we can then begin to walk them and look at the characteristics of each pointer in this map and see if it looks like a data structure. And if it does, well, we found our data structures, right? So for each one we find, we add it to a results map and then we're done, theoretically. So we're going to talk about class instances because this is the most simple example of data structure detection because really a class instance is just a data structure. The assertions we have to make here are that we're talking about abstract classes where there's a virtual function table as a first member of the class and that's basically it. So if we want to find a class like this, you see here this blue box, that's what we're searching for. That's the pointer we want all the way on the left. The blue box needs to be a non-module pointer. If it's a pointer that falls within the address space of a module, meaning if it's a pointer that's in code, then it could just be assembly code that's moving a VF table into place. Assembly code is in a class instance, so it's important to make sure it's a non-module pointer. And this pointer then needs to point to another pointer in read-only memory. That's important because a virtual function table is typically going to exist in read-only memory somewhere in the P header of the module that instantiates that class. So once we have that something pointing to a read-only pointer, that's a non-module pointer, that read-only pointer should then have an element there that points to an executable pointer, which is indicative of a function. So if we have something in read-only memory pointing to a function being connected to by memory on the heap, then it's probably a class instance with a VF table. So this is what the code actually looks like to do that. Once we have the pointer map, you can't really take much from it, but it could fit in a slide. So I wanted to show how condensed it is once it's actually written out. And we're going to do a demo of that. Let me open the code really quick because I don't have it open anymore. I don't know if you guys can read that well, but let's just go through it really quickly. So we're going to declare a class base. This base is going to have a virtual function called do stuff. And it's going to have a type field that is a Uint32. Then we're going to implement base as one class called Knop. That Knop class will set its type to Knop, which you can see at the top in the enum, is 0x90. And its do stuff function will do nothing, which is really not characteristic of a do stuff function, but that's what it does. Cool. So then we have another class instance called win. It's do stuff function does something different and that is print, I am a winner. And its type is type win, which if we scrolled up, we'd see is 0x1337. So what we're going to do is we're going to run a class instance data structure scan, which looks like this. So the first thing we're going to do is we're going to find all class instances after running the process and attaching to it. Once we found all class instances, we're just going to loop through them. We're going to find one whose type is 0x90. That's the instance of our Knop class. When we find that, we're just going to store its address. We're going to do the same for our win class, which is 1337. And then we're going to come down here and we're going to overwrite the virtual function table of the Knop instance with the win instance. Now what that's going to do, if we look at our C++ code, again, what's happening is we're going to instantiate an instance of each class instance. We're going to call the function play, which you can see here with Knop. And the play function right above the main function, what it's going to do, it's just going to loop forever and it's going to say instance do stuff. So our instance of Knop should do nothing when do stuff is executed, but our instance of win should print stuff. And as you can see, we're using a Knop instance. So if the scanner works, it's going to scan this process, replace the virtual function tables, and the Knop class instance will start acting like the Win class instance does. So this is the window of the program we just looked at in C++. And when I run the scan, if everything works out, this should start spamming I am a winner. Right now it's just looping and calling a do stuff function that just returns and does nothing. Cool. I haven't tested anything on this laptop and that was a scary one. So let's let's get a bit more complex. Class instances are pretty basic. There's three things we have to look for. But let's look for something crazier like a linked list. And let's look at the STD list implementation just because that's pretty commonly used in games since they're written in C++. So as before, the blue box on the left is what we're looking for. And that's a pointer. This pointer must be followed by an integer N. That integer N we're going to get to in a minute. That pointer needs to point to something called a node, which you can see just to the right of it. Now, a node has two definitions. The first definition branching off to the bottom is that it must point forward to something which when that pointer is incremented points back to it. Because on a duly linked list you have a forward pointer and a back pointer. So it should point to something which points back to it and it should point back to something. So when you increment the pointer that is that node it should point to something that points back to it again. If it does that we know it's a node. The next criteria for a node which we're only going to apply to the first node we find is that if you keep walking the forward pointer as you see here on the right you just keep going forward you should eventually end up back at the node you started with. Because these are circular lists, right? And the amount of steps it takes, the amount of nodes you iterate over before you get back to your original node is that integer N we talked about. So what we're looking for is a pointer followed by an integer N such that that pointer points to a node which when walking the node the next chain that N follows the pointer. Okay, so this demo is pretty simple. The C++ code is just we're going to declare a list of U and 32s. And we're going to fill it with every value from 0 to 100 that is an integer including 0 itself. And then in a while loop we're just going to sum all of those things. So the sum of everything from 0 to 100 is 5,050. So if the value is not 550 we're going to print oh no somebody modified our list. So the code looks like this. We're going to look for all instances of STD list after running the application. Then we're going to loop through them and we're going to look for a list which has an item count of 101. Because we have every value from 0 to 100. So there's 101 values. Once we find that we're just going to store the list header in a variable and then we're going to move on. We're going to take that list header, we're going to read memory from it which is going to give us a pointer to our first node. Once we have the pointer to our first node we're going to overwrite the memory. 8 bytes past the start. So at 0 to 4 is a pointer to the next node or 0 to 3. At 4 to 7 is a pointer to the previous node. So starting at 8 is the value in that list node. So if we overwrite the value at 8 with a unit 32 of 1 we've just changed 0 to 1 and the program should start saying that something modified the list. So this is our window and as you can say it's behaving normally which is that it's doing nothing because the list is summing to exactly what it expects the list to sum to. But if I go ahead and run the scan we're able to pull all lists out of memory, find the one just based on its size, no other information and then overwrite a value in it and completely change the behavior of the program. Thank you. Okay. So now we're going to move on to the one that really gave me hell. So up until recently when I've moved and got worse internet this project was completely done on a live stream where I streamed myself coding, small webcam in the corner, streamed the dev and I could talk to people and tell them why I'm doing stuff. When coding this on the live stream I was completely unresponsive to anyone in chat. I was melting into my hands. I was trying to figure it out. I actually had some screenshots but they would have taken up too much time. But this one really messed with my head because you can know the theory. You can know exactly what a binary tree looks like. You can know exactly how the pointer should interact but since the structure is so complex you're going to end up in these loops and these chains of pointers which look like binary trees but aren't and loop infinitely until you run out of stack space and it was really a pain. So I consider myself a pretty good coder and if I could barely get this code working I definitely can't get a diagram made for it because I'm terrible at making diagrams. So we don't have a diagram like before. We have all of this text. What it boils down to is that an STD map which is a binary tree underneath can be defined as something that has a parent node or a root node and that node has a parent which when you point to its parent's parent is itself. So the root node is basically like fry from Futurama. It's its own grandparent. If you find a node that is its own grandparent you know that's a parent node. Then you want to walk every single node from the parent node left and right. So each node has a left pointer, a right pointer, and a parent pointer. You want to walk every discoverable pointer from something that seems to be a valid root node and each one must follow some criteria. Now there's a lot of criteria here. For instance there can be a one node tree which is just a root node by itself and you can see this second line of code or the first indented line of code shows how we detect that. The node can also be in a two node tree that is left heavy. That means we have our root node and then it points to the left side to one more node. That node then is going to point back to the root node on its left and right to mark that it's the end of the tree. And you can also have a right heavy two node tree which is the same thing but on the right side. In addition you can have a node that's at the bottom of a tree so each side points back to the root node but it's parent is not the root node. All of that's defined here. Or you can have a regular node and a regular node is defined as something which has a parent which points back to it on either the left or the right and it has at least one left or right that is not the root node. Because if both left and right pointed to the root node it would be at the bottom of a tree. So if actually any two of those three are correct then it's just a normal node. So then the tree is valid if a root node exists and if every discoverable node from the root node is a valid node which we've just discussed. But on top of that if every discoverable node is unique so if we walk the tree how you expect to walk a tree which is recursively left right left right left right until you hit the root node at the bottom of each side no node should be discovered twice. There should be no looping pointers and if there is that's going to get you into this crazy loop where you loop forever and it runs out of memory and crashes your memory scanner. So that's not good. So we're just going to look at what this actually looks like. So I think you guys can see this pretty well. We're going to define a map where the key is a 32 bit integer and the value is a string. Then we're going to fill that map consecutively with integer keys one through five and string values one through five such that the string names of the numbers are the value associated with their integer key. Then we're just going to loop through it clear the screen and then just print the entire contents of the map out to the console and then sleep for a bit and do that again. I'm going to actually increase the text size on this window really quick so that it can be seen better. Or not because my console is being dumb. Sorry. So I'm really not sure. I guess you probably can read this and it's doing exactly as we said. It's printing out the value followed by its key so we have one, one, two, two, so on all the way to five. So if we look at our code, what we're going to do is we're going to search for all map instances and then we're going to loop through all of the found map instances until we find one which has a length of five. Once we've found one with a length of five, we're then going to store that here and we're going to iterate over it, just walking the tree left and right recursively and we're going to rewrite the nodes with some other text than what they currently have. So let me find my mouse. So the window is up there so I'm going to run the script now. So we replace the text even though we're using an SCD string inside of an SCD map, we were able to just know that it's in an SCD map, know its size and then go in there and completely replace the text even though it's running in another application. So now we're going to get to extensibility and I'm, this is sad because I have ten minutes left, which means I have no way to get this demo working. But one of the points of this memory scanner was that I wanted it to be extensible. I don't want a memory scanner where oh, you like games are starting to pop up on Linux or games are starting to pop up on Mac or Android games just became a thing. Well, you can't use Machete Engine on it until the guy updates it and however long, right? I want it to be just a few lines of code and this can run on anything and not necessarily memory. It's a memory scanner but when I went into this I realized it doesn't need to be just a memory scanner. So we have this interface. You have four public functions, two protected functions and a couple of protected variables. Anything that you can implement this properly for, it can scan because all of the scanner logic lives outside of this and relies on only these functions and values. So the example that I've done here is I've taken Dolphin Emulator which runs GameCube and Wii games and I've put in Luigi's Mansion and I've implemented this for Dolphin. You can see a demo right now but it's not here. Basically what I've done is I patched Dolphin to have a shared memory segment where it allocates all the memory for the game and then I acquire that shared memory segment in my implementation of that interface and then scan through it knowing like what the mapping looks like. We can find stuff. So if I had the demo here, the first thing I'd do is show Luigi losing health and then I'd freeze the health at 100 and you'd see he won't lose health anymore and then I'd freeze it at 101 because why not if we can do 100, we can do 101 and he'd have these wings that were like hearts, just hearts flying out of his back looking like angel wings because that's the animation the game makes when you lose health and it keeps trying to decrease his health from 101 but the scanner's overriding it with rate 100 every time. So it kind of looks funny to play on and then I was going to change it to 1337 and when it gets that high the screen completely trips out. There's a little heart in the corner that's supposed to be your health. It grows to the size of the screen and it's just beating and there's like this pink flashing going on like I guess Luigi was like I have so much fucking health I'm going to go rave. So that would have been great and I figured that would be a demo that would carry this talk but sadly we don't have it. I'll put a video online with the slides afterwards. So future work. I want to add a lot of stuff. So targets for OSX and Linux where we just implement that same interface but for these different operating systems and theoretically it should compile. We're using CMake, we're using nothing Windows specific except for in the Windows scanner target so if we add targets for OSX and Linux everything should work so I want to do that. On top of that I want to add targets for all major emulator types and for memory dump files because like I said before we can scan anything that is bytes while in our self-processes. I also want to add symbolic execution. So what some games will do is they'll store your health in a variable and that variable will be zored against another value in another variable somewhere in global memory or in the heap. And what that looks like is if you try to scan for your health you try to scan for 500, 455, 50 you're not going to find it because it's encrypted with just a single integer zore cipher. And it doesn't work, right? And that's pretty common because zores so fast you can do that and mess with the noobs who don't know what they're doing. So what I want to do is be able to go through the assembly and find patterns like that where we have a zore followed by a zore of another value, make the scanner take that into account and when it does the scanning, zore the two together instead of just saying this address has this value it'll say these two addresses when this zore operation is applied has the value you want. So I have some prototypes for that but it's nothing great and it kind of breaks extensibility because I need disassembling for all the different architectures and stuff. Don't have that yet I want to add it. And then I want to add native support for strings of fixed length within structures. Structures are only integers right now. You can hack it together in Lua pretty easily using placeholders to just hold the place of the string pointer and verify it after the installation but it's not there. And native support for pointers within strings stuff like that. So a lot of you here are like look, dude this is Defcon. My company sent me here. Hacking games is fun but I don't do it. I have work to do. How does this apply to me? How can you use this? How can I use this in my normal day to day life? So if you're reverse engineering I find this helps me a lot because I don't have to focus on figuring out what the relationships in the data are and what values are related. I can use the data structure detection to just tell me that. And once I have that information it makes reversing it easier. Instead of going in IDA and seeing okay all these pointers are being followed. Kind of looks like a map. Now I have to somehow pull all the values out. Memory scanner does it for you. Helps. And it's also great for just getting this hard to grasp glimpse of how the program is architected and designed. Which can be hard to get from assembly code sometimes. So just seeing how all the data is interconnected and where the values live can help out there. For offense you can really just say screw the Lua and just take the Xeno scan engine library which stands alone and embed an application. If you're a bad guy or you're red teaming or whatever and you want to steal passwords out of a browser or a password manager or steal cookies or whatever you don't have to write your own memory scanner. You embed this thing. You search for things that you know are going to be there or just search for data structures and then look at them and pull the values out. Instead of dumping all the memory and X filling entire processes memory over the network which can be expensive, you can embed a memory scanner that can make that job much easier. And it's great for research too which kind of goes back to reverse engineering where it helps you focus on what the applications are doing aside from the data. Because anything you reverse engineer, anything you research, you have to focus a lot on how the data is connected. But if you can forget about that you can focus on the algorithms that are changing and mutating that data. So I find it helpful there too. So the code is right here on GitHub, completely open source. When I get good Internet I will go back to streaming on dev. I would love contributions from anyone who is probably a better C++ programmer than I am. The slides will go up after the con at Zeno Scan Slides. You can probably just take down github.com slash Nick Cano and find everything through there. Me, I'm at Nick Cano 93 on Twitter. github.com slash Nick Cano. NoStarch.com slash gamehacking is where you can find my book or you can pick it up at the NoStarch booth because I will be signing after this talk. Thank you so much. You've been awesome.