This morning, we have a pre-recorded talk for you. Atlas is going to be talking to us about emulation-driven reverse engineering. Please sit back and enjoy. I, unfortunately, was unable to make it out there this year due to family health issues. But hopefully, I'll be back there next year. Thankfully, Nikita was kind enough to let me record something and send it out to you. Hopefully, you'll enjoy it. Now, some of you have seen me speak in the past. And if you've seen me talk in the last few years, you've noticed that I've talked a lot about emulation. I've talked a lot about symbolic execution and emulation and static analysis for reversing and bug hunting. So, today's talk, unsurprisingly, is about emulation. Today is about emulation-driven RE. You'll figure out what that means in a few minutes. Basically, how do we let the computer do that? How does the computer do more of the hard work so you can do more of the fun stuff and not rot your brain? So, a little bit about who am I. Many of you know me. I broke out of VMware with an amazing team. Done a lot of power grid hacking. Generated a tool called RFCAT. Done a lot of car hacking lately. I'm a Vivisec core dev. I've played a lot of Capture the Flag. Some might say that I'm addicted. More importantly, I am a Jesus follower, a daddy-husband. And not a daddy-husband, a daddy and a husband. And I'm a principal researcher for the company named Grim. Just to give you a quick refresher before we jump into the fun stuff on emulation. What is emulation? How do you do emulation? Oh my gosh, you're going crazy. Emulation is actually very simple. You have to keep track of registers. You have to keep track of memory. And you have to implement instructions that an architecture would that act on the memory and the process. And you have to keep track of the registers. You might implement peripherals if you're trying to go a little bit further. I know that QMU and a lot of the emulators that you see definitely do. For our purposes, it's not necessarily always important. Sometimes can help. Sometimes you will also implement system calls and interrupts and handle those. So what does emulation do for us? Well, in many cases, we can write analysis modules using an emulator, a lightweight emulator that can answer questions that might be a lot harder to answer or at least abstract to cover a whole bunch of different circumstances and architectures. You can also use emulator to get immediate context. And I'll show you about that in just a minute within a function. And basically, the answer of the day, emulation does the thing you need it to. So it's like you're creating. These little minions that you go off and you tell them to do this thing, and they return back with this big milk crate full of junk that may have really awesome stuff, and it may have a little bit of cruft. You got to weed through it, or you write your code even more intelligent to weed through it even better. So a little bit more beyond the idea of emulation, because you guys have run into emulation before, whether it's Game Boy emulation or QMU, partial emulation is the idea of emulating code that you don't have. You don't have the full context for so most emulators that you would run into probably all the emulators you knowingly ran into start at a given point like the start of a binary program or the start of a firmware and you start off and it's got the initialization process and it goes through everything, setting up everything, and gee, that sounds a lot like execution and you can debug execution. Partial emulation allows you to get around some of the issues of of getting full context by providing things like safe reads and writes. If the emulator runs into a read of memory location that doesn't exist or a write, it'll just say, let's pretend that that worked. And on a read, it'll just give you the correct amount of bytes back of some known value so that you can say, oh, hey, that looks like a lowercase a or a bunch of them. In our case, that's what we'll run into for safe reads. We can log reads and writes through an emulation pass. So if you run through a function, emulate through it, you can have all the things that are read to and written to tracked for you, as well as a path that you carved through the that your emulation pass carved through the function or code. You can also snap in analysis monitors or emulation monitors. Analysis monitor is just a special version of one with a lot of wrapped in goodies. An emulation monitor is simply something that gets to watch as emulation. happens and maybe make decisions or at least track information and we'll talk about that in a few minutes and then taint tracking, we have the ability with it, we've got a great taint engine that we can say, hey, just give me a number, I'm going to show that number in here and here, that number really means uninitialized register RDX or, you know, this argument zero, for example, so this kind of feels like it's going to be a lot of work, but it's going to be a lot of work, but it's going to be a lot of work, but it's going to be a lot of work, but it's going to be a lot of work, but it's going to be a lot of work. It feels like baby monitor protocol and in a lot of really amazing ways. It is in a good way. Don't be offended. So a few examples of emulation at work. We're going to talk about four specific ones today. Immediate context. We've already gone over it before. If you've seen one of my previous talks, but it's still so amazing and so easy to use that I got to call it out. We're going to talk about the built in vivisect i386 calling convention analysis module because it uses analysis monitors. It uses a lot of the emulation stuff. It uses a lot of the emulation stuff that we that we're talking about, and then we'll go on to a little gizmo that I created and continue to implement on my own called funk recon or function recon I implemented as a vivisect extension vivisect is my is my tool of choice and to implement it provides a ton of these emulation partial emulation toys for me. And then at the end, the whole reason that you're here and not at a previous talk is Ninja EMU. And how we can use emulators to drive our reverse engineering. So starting off immediate context so built into vivisect when you When you're displaying a function, you can right click on anywhere in the function and go to the function sub menu. And there's an option called show emulator state. Basically, what's going to happen is When you click on this. Vivisect is going to spin up workspace emulator, which has all the bells and whistles with safe reads and tank tracking and path tracking and all that. And it will say, I'm going to find a path and emulate to this location. And what I do. I'm going to spit out the context of that path. So at the bottom of the screen is the output from show emulator state running emulator to and it's that address three to DOE and you can see that right in the in the function title at the head. Are on the top showing register magic state at that location stack delta zero. We haven't actually changed the stack at all. Okay, that's good to know. And here's the instruction three T three to DOE is the LD LDR age are two from a D reference of the R to register. This is a power PC or I'm sorry there's an arm function. Now it says, I know these operands. Operand are two. I know that that is at this emulation point zero zero x zero eight zero one zero E zero C. And here's the decimal version of it and The other operand, which is a D reference of the register are two shows that the references of our to the same address. It's the same register and it spits back capital A is for one for one for one for one. Now the The original tank. The original safe reads used to read all capital is we shifted to lowercase is for for various reasons. And actually, it is suitable now. So this can be wildly beneficial while trying to reverse through a complicated function, trying to get an idea of where you've taken an argument and you've added to it and you're subtracted to it and Yada, yada, yada down the line. Next example, we're going to talk about the calling.py the the analysis of The analysis module used for Intel I 36 in other words 32 bit functions to identify special things like the arguments to a function call The local variables that are using a function call how deep the stack goes and including something cool called mnemonic distribution, where it goes through all the instructions and a function. And it just tracks how many usage of each are in the function. So if you've got 32 moves, it'll say mo V 32 and any pushes pumps other reads rights X, or X or is a pretty interesting one, and it just stores that as part of the metadata for the function and which can be very useful, particularly when interested finding interesting things like hash functions crypto functions, things like that. One example of using emulation in Vivisect on a daily basis is calling convention identification. So, for example, what I'm talking about is this function right here, sub020A030 in this code, has a number of arguments to it. It is identified as a system 5AMD64 call and has these stack variables identified, and we can go through and we can name them as we do analysis. This is all done on Intel 386, for example. We're just going to use this for example. Each of the architectures have their own version. We have an analysis module, which starts out, as analysis modules do, using analyze function. Calling.py has analyze function. We hand in a Vivisect workspace and a function virtual address. It immediately spins up an emulator. And this analysis module... This monitor and snaps in the emulation monitor right here and then runs the function. Here's the it says run function. Here's the virtual address. Max hit one. So do all the paths. If you run into something you've done before, quit. Down here, it then calls build function API based on the results of that emulation pass. So it hands in the workspace, the function address, the emulator itself and the emulator, the emulation monitor. And what we get back from that allows the setting of all the things that Vivisect makes use of. So let's take a look at that build function API. Specifically, one of the things that it does is it grabs the number of arguments and it starts off determining that using the emulation monitors tracking of the stack max. What is the maximum stack address that it has access? Because... Because for Intel 386, you put your arguments on the stack. So from the base, it then you access up from the stack base. So if we end up with more than 40 arguments, we think maybe that's a little weird. So we default to Cdecl, the calling convention in i386. There were dozens of calling conventions and the compilers all went nuts, thought their stuff was the best. But then if we return using the ret number for Intel, that means return, but also clear off this much space off the stack, because that was arguments. Basically, it's the call-y cleanup. We have a different way to identify the arg count because that ret bytes, divide that by four, 32 bits each, actually is the number of arguments, clear and simple. We then go on to say, hey, any uninitialized registers that are used in the function without an initialization, let's figure that out and identify calling convention from there. Because Cdecl and standard call are very common, but there are a whole bunch of derivations off them that add in handing in arguments in EAX and ECX and yada yada. So we have a dictionary that we look up. Based on... Based on the undefined registers, and voila, we've got our calling convention and our argument count. All right, next example we're going to talk about is probably code. This is another internal function of a vivisect that heuristically determines what a pointer points to, particularly looking for executable code. It's part of a family of is probablis, and we'll show that in just a second. It starts out by spinning up a workspace emulator with partially emu, bells and whistles. It attaches an analysis monitor and then emulates every branch. Now, one of the cool things about our partial emulation, if I didn't mention earlier, is the ability to say, hey, we're going to go to a conditional branch. Yeah, let's do both. So I'm going to take one path this time. We'll just store off the state over here. And then when I'm done doing this path, I'll come back. And I'll... I'll emulate through that path as well, given the same state that we hit right there. Wildly powerful. And so we hand in what's the argument max hit. So sometimes as we're going through a function, we'll get to a loop or we'll get to something where we've got a couple different paths that end up in the same place. And as soon as we run into the same opcode twice in the same location, then we just... say, ah, we're good. We have enough, which allows us to get through all code without triggering the halting problem and using up all the time, all the RAMs, all the resources in the universe. And at the end, make a decision. Is this code? Is it not? So this example of using partial emulation, this built-in analysis module for Vivisect proper. I want to... take you through the core code here. Analyze pointer is called a number of places wherever Viv finds a pointer. And it looks first to see if there's already a location specified, because at that point, you don't care. Is it probably unicode? It checks to see if it's unicode, or then it checks to see if it's a string. And then it calls this isProbablyCode. So isProbablyCode makes use of partial emulation. A Vivisect emulator, or a workspace emulator. We handed in a virtual address, the location that we're looking at to see if it's code. And it does a few simple checks like, hey, is this executable? If not, probably not code. Or is there a function signature? If so, very likely it is. And other things is, have we already run this? We then set down log level so we can emulate through nasty stuff that's not code and not throw error messages. There's just everywhere. We then call get emulator. And since this is the workspace itself, it's calling it on itself. Normally, I will name the workspace emulator VW. So you'll often see in my code VW.getemulator. And it hands in anything that we happen to hand in to isProbablyCode. It then creates this watcher object, which is an analysis module that we'll look at. In just a second. We call set emulation monitor onto the emulator that we just created. We hand in the watcher. And then we try to run the function. We hand in specifically the virtual address that we want to run. And the max hit. So if you remember, a lot of partial emulation isn't straight through code. It actually says, oh, there's a branch here. Save that for later. We'll run it again later. And we're just going to continue through one branch. And so this is a way of saying, emulate everything. But if you run into code you've already run into in some other branch, just stop. Call that an end. And that allows us to actually emulate through every part of code without eating up a ton of time. And give relatively good context to each instruction. If we throw an exception, then no, it's not code. So we just store that. So that it's not code. And we then do a check at the end. Hey, watcher, does it look good? Is that code cool? If it is, we store it. If not, we move on. So let's take a look at this watcher, which is an emulation monitor. And it stores a number of different local fields and has this ability to log anomalies. If something goes weird, we can log anomalies. And then it looks good and is code. But specifically, this emulation monitor has a prehook. So before each instruction is emulated, this prehook code is run. And so we hand in an emulator, the emulator we're using, we hand in the opcode that we've parsed out, and the starting instruction pointer. If our opcode is in our list of bad opcodes. So we've generated a list of bad opcodes that are very, very common when you're looking through firmware or code. And including, like, how do you parse out zeros? How do you parse out all ones, like FFFFF? And so we'll hand in, we'll parse that out, and we'll get whatever instruction that is. And then we have a list of those we compare against. And if it's a bad op, meaning we're emulating into something that's very likely just all zeros. Or all ones. And so that's, we throw an exception there. We then look through and say, hey, have we run into a return in any of the code paths that we've emulated through? If we have, probably pretty good. So done with that. We then grab the location of the current instruction as stored in the Vivisac database. If the type that we run into is not an opcode. Okay. We're done. This is an API built into Vivisac where we'll go through and analyze, does this not actually return? So there are many functions, particularly in libc or Windows kernel 32, that legitimately, they don't return. Many of them are error codes or exits or things like that where you go here and you're just done. So we work hard to identify. And so we store that information, make it available to the API. Is this a known return VA? If it is, then we say, okay, this is known not to return. So we're going to say that it has a return because we want it to look good. And, you know, that's very likely code again. And then we tell the emulator to stop. So at the end, we call, after we've emulated through the function with a max hit of one. As long as it didn't throw an exception. And many times when you have code or if you're trying to emulate things that aren't code, you'll throw an exception. Most often, it's just not a valid instruction. And so this will catch most of the things. And if not, we ask the watcher, does this look good? If it looks good, it's pretty simple. If it doesn't have a return set or there is bad code, then return false. It doesn't look good. Otherwise, if you have just repetitive of the same instruction, you can end up with what looks like good code, but it just really isn't. And so we look through the mnemonic distribution and we do some heuristics here and say, you know, if we're over a certain percentage of one instruction, then that's probably not code two. We're going to just basically reproduce the functionality listed here and it's probably code. And we're going to use a binary that came from the Hackasat qualifier rounds this year. Something from the Rossinante Authenticator. So I've zeroed in. I've got an interesting function here and I want to know more about it. All right. So I ran the function, max hit one, and it completed. Okay. So watcher. These are all the details of watcher. Watcher. It's got the workspace trivia and hacks. That's actually the address that we handed in. Does it have a return? Yes, it has a return. Yay. It has 27 different instructions. Is there bad code? No. So that looks pretty good. So I wanted to show you that because you create a you create a emulation monitor. You store what's in it. You tell it what to do with it. And it drags along behind. So you can write an analysis module that easily straps in an emulation monitor. And you let it go. And then you get back the results. You can look at. So here's our mnemonic distribution. Probably one of the coolest things about is the watcher emulation monitor. Okay. The next one we're going to look at is the funk recon vivisect extension that I wrote. It's my way of easily deciding. Or determining what kinds of things are going on in a given function branch. So oftentimes you'll start off maybe a main function or you'll have a main loop. Something, you know, deeper down in. But, you know, you've got huge amounts of potential functionality. And you can get down a rabbit hole really fast and lose complete sight of where you're going and where you've been and what's next. So I wrote function recon so that I can say, oh, going through here. I just want to stay right here. I'll just do a recon of that function. Recon of that function. Recon of that function. And try to get a really fast feeling for what's going on there. So this is part of my own collection. The Icarus collection that I started years ago. And given a starting point, a function, we emulate through all the paths and all the function calls. And we grab information like strings, imports. Functions. Immediates. Pointers. And indirect branches. Which actually isn't going to be a part of today's demo because that's not ready for you yet. So now let's show you function recon in action. We're going to go back to our Resonante authenticator from Hackasat. And I've picked up a function here that's kind of annoying. But a lot of stuff going on here. I'm just going to say let's run function recon. Function recon right here. See that? Well, let's magnify this. So... Okay. So I'm looking through and I see HMAC. I see delete auth. Create auth. Lib orbital. I'm seeing decrypting protected data. I like that. Auth data.bin. That's something that they provided. Along with the binary. I see unset. I see RB. So we're probably going to be reading something with binary. I see decrypting. Using key. Decrypted. Blah, blah, blah. File. And I see error messages. And then I see rollover period and latitude and longitude. We're talking about Hackasat. So that's to be expected. HMAC key. Secret key. Allow me to make a lot of sense. I'm going to make a lot of sense out of this function without actually having to delve into it. I also see that it's importing a number of things, including dlopen and dlsim. That's a dynamic library loader and symbol resolver. We also see allocator and a bunch of C++ standard lib function calls, which is probably why I chose this one. fopen. fseq. ftel. rewind. operator new. So those are the imports. And then it goes down and says, okay, do I recognize any functions that don't start in the name sub underscore, which is the default unknown function name? And so we see actually the PLT entries for a lot of these. So I haven't updated the string version as recently as I've updated the non-string version. Where... We can see... Here are the different strings that are interesting. Again, the same ones. Here are the imports that are referenced. And again, these are... I like this better than the text version right now because it just reads nicer. I can select... Select and show things, and I can actually drag that into... I can drag that into someplace and view what's going on there. Down here, looking at the addresses, calling functions. I don't know what other functions that we saw. And then we've added in... Since the strings were updated, we've added in a search for immediate values. So if there are immediate values that we found during emulation, including where we build a pointer... On Intel, this isn't as big a deal, but on many RISC architectures, actually almost every other architecture besides Intel, you'll find the code building addresses that are absolute addresses because you've got a fixed instruction set that simply can't store the entire address in the instruction set. So it'll say, okay, load this half and then add this half to it or it or whatever. So the emulator will go through that and each point say, hey, I got this number here. Is it interesting to you? And so we store immediate values. Zero is referenced 152 times. One is 34, kind of like you'd expect. And then we've got different smaller numbers. Safe reads will give you... In this case, it'll give you lowercase a's. So hex 61616161. So if we see that, then we know that we've read from someplace that we didn't know what to do with. It wasn't an existing map or it was trying to reference something built on an argument that wasn't legitimate. You'll also see these 4156 values. These represent vivisect emulator taints. So at the beginning of an emulator pass, the emulator defaults to loading all the things that could hold arguments for a function call with a taint that indicates what it is. And all the registers are pre-tainted with a taint that returns, oh, this is uninitialized ECX or RCX or whatever. So as you can see, there's a lot of potential value. So if you see like the number 1024 or you see the number 8080 or you see the number C00 blah, blah, blah, some error message. These are numbers that just inherently make sense to you once you've been reversing in particular areas long enough. And it can make your life a lot easier, like hex 7DF, for example, if you're an automotive person. Hey, next, let's jump on and take a look at vivisection. Vivisection is a huge helper trying to give you all the access to be powerful in emulation and driving your reverse engineering using an emulator. So the problem is reversing is, I couldn't think of a good word. It's hard. It's tedious. It's exhausting. Yeah, it's all these things. But I don't want to sound like a wimp because reversing is really fun. I get a huge rise out of it. It's what gets me up in the morning. I'm exploring that and making tools that allow reversing to be easier. But it can really rot your brain. You can get lost down big rabbit trails. I just recently had to reverse engineer and do vulnerability research on a modified form of Apache as one of a CTF, part of a CTF. It was insane. Brain drain is very real. So how do we make tools that allow for great understanding, easy setup so that we can? It's a tool that we're not like, I'm not sure if I really want to do that heavy. No, it's easy. Let's make that easy. We want to make it so that it's repeatable, something that I don't have to get the program to a certain point with a certain inputs with the debugger and stand on one toe and hold my hand up here. And then maybe it might be. No, I don't want to have to. Again, easy setup. I want it to be repeatable easily. I want it to limit my brain drain. And maybe be a little fun. I find it very fun. So that's why I'm actually talking about it today. So Ninja EMU is a part of vivisection. And it basically wraps the workspace emulator that we can get from a vivisect workspace. It provides interactive debugging, kind of like a more intelligent version of GDB. I wouldn't go as far as Jeff or one of those full GDB environments. But something more along the lines. Just giving you what you need at each step along the way. So Ninja EMU, in addition to this UI, allows you to hook function calls and then replace it with Python code. So let's say you have a function call into some logging thing in the target binary that you know the arguments. You can kind of just write it in. So you're not actually stepping into. Custom focus code. Or maybe the code is fraught with peril. Like, you know, things that need a ton of setup. And you're like, I know what that is. I don't need to know how to set it up. Let's just go. We can hook. One of the biggest uses that I've found is I hook malloc, calloc, heapalloc. All the things that actually do a memory allocation. I hook. And I emulate. And I've got basically a special heap implementation that actually doesn't free anything. So you end up tracking everything. It's not really good for heap grooming. But it's amazing for tracking and seeing what's going on in a system. You can hook system calls like interrupt calls and hex 80 or a 2E. Not a problem. In the process of doing all this, in order to support all the function calls that I wanted to emulate, we've created. Three primary fake OS kernels. We've got the fake Win32 kernel. We've got the fake POSIX kernel for Linux, whatever. And we've got a raw kernel, which basically is just kind of fitting in the kernel space. But it's for firmware that doesn't actually have a kernel. But it allows us a great deal of flexibility to expand and extend. We provide our own heap. We provide rudimentary file system ability. Including the ability to create fake files just by name. Hey, here's a path. Here are the bytes that are in that file. And some attributes for the file. Or we also allow the mapping of a particular file directory. A fake directory space. And we redirect that into a real directory space in your host operating system. So you want to make sure that... Be warned and be careful. Right now, we don't actually allow... We don't actually protect against directory traversal. So if you're reversing something that knows that you're reversing it in Fivisection or in NJMU, they may be able to do shenanigans. So just be warned. There's also default file policies that try to help you keep from shooting yourself in the foot. We also have a fake registry because a lot of times when you're reversing Windows programs, a fake registry is pretty important. And so you can just stick in your own stuff and satisfy what you need to get by. And we also do environment variables because those are very important as well. They are all hackery. This is not something that's intended to run an enterprise software solution on. So please don't bite... Please don't yell at me if it bites you in the ass. And then NJMU, one of the more recent additions, is the ability to drive a function graph to walk through emulation through a graph view. There are two ways that we do this. First of all, we've got in-process function graph driving, which means basically from within Vivisect, you jump out, you drop out to a shell from the same terminal that you started Vivisect up in. It gives you an IPython or interactive prompt. And you set up the... You set up the NJMU and you run it from there, telling it what function graph name that you want to drive. And as you emulate through, it will track it through that function graph. The other way is the more massively online multiplayer version, either using a Viv server or a shared workspace, where they're intended to have many people all sharing a Vivisect workspace. We're able to set up a follow the leader session from the NJMU. And the follow the leader session then just sends out where it's at at any given point in time. And any number of people can follow through, follow along with the emulator as it walks through. It is a lot of fun. A little bit of setup goes a long way. So you can start off with basically not knowing anything and just spin up the emulator and walk through. You'll have taint tracking. You'll have safe reads and writes. But as you start zeroing in on important functions, you can then have special setup like, oh, make this the arg list. And I want to hand in this string, which will generate a heap allocation for it and then put that value into the right location. I want to hand in this number and this number. You hand in a list and NJMU, sets it all up for you and allows you to just continue to make more and more sense. Now let's take a look at this 2005F7C function that I mentioned earlier. It did turn out to be very interesting, but it's a little bland. But let's start off by running function recon on this boy. So we don't see a whole heck of a lot. Calls to calc, memcopy, malloc, and free. So pretty generic, but if you think about it, compared to the last thing that we looked at, very limited. This isn't really about function recon. This is about making sense of what a function does. And you're going to have to forgive me because I only have one screen that I can present to you. I'm not going to be able to do as good a job showing off just how awesome this is. Typically, I will have three monitors running at the same time, so I can do things on one and have my disassembler window completely fullscreen on another and my emulator window open on another. This will be something that you select off of a context menu for a function. But for now, let's just walk you through the old-fashioned way. So for this example, a lot of times when I'm using the Ninja emulator, I am starting to set up just function calls that set up the environment the way that I want. This is not necessary. But as I dive deeper and I do more, I want to set up the call with arguments the way that I want them. So if we don't, we just jump in and we say import set. Let's just say our nameU is vivisection. So we start off, you look at the registers are printed here, and you recognize these now as being tainted. Doped, if you will. This user interface prints out the address, the bytes of the address, the instruction that we get there, and then as a comment, our first operand, because notice that this actually has an operand, which is the weirdest thing ever. It is, and this is translating from the taint value, because as you can see, edx is the actual, the full thing is rdx, and it is a taint value. And so that taint value translates back into uninitialized register rdx. So we know that. Our next thing, push rdp, which we also helpfully spit out that that's an uninitialized rdp register. And now we move rsp into rdp. Now rsp is initialized, but still, this is saying our first operand is an uninitialized rdp. So let's create some space on the stack. Now what you're not able to see, and I'm going to move over, because you don't need to see everything going on with the registers all the time. Do notice that registers that change, they get highlighted, but I'm just going to drag this off over here, like this for a moment, so we can see what's going on on this side of the fence. Oh, nothing is going on on this side of the fence. Why, you might ask? Well, because I didn't tell it to. This is all stuff that's often set up, and it will be set up for us as we... as we move forward with the release of div section. So let's just say... Yeah, we handed in an emulator, but we didn't actually hand in a GUI func graph name. This is one way to to have the emulator drive a function graph around. There's another that is more network-friendly, where you're going to have a shared workspace, and dozens of people can follow along with the emulator, but I'm not going to demo that for you today. That is a part of the div section release coming up, though. So let's start over again. Run step. Okay, we got the same thing as we had. Now, as we hit enter, we notice that our function graph, highlighted the next instruction. So this allows us to be very emulator-driven. Even if I don't want to pay attention to the emulator, I can say, you know, I'm more interested in the disassembler right now, so I'm going to say that's not really that important. But I just hit enter into the emulator UI, and it moves on, and I'm able to now look through as the code goes through, but sometimes looking, I'm more looking at patterns in here, and sometimes I will miss actual detailed things. So sometimes having the emulator forced me to just say, oh, okay, cool, going through and actively, visually helping me focus and identify what's going on. I'm going to call into this get emu, because that's going to return me an emulator, for do the crypto thing decrypt. Now, I did some work for that name, and we basically just say, hey, parse this expression, and here's a string. I could have used the file name plus an offset or sub underscore, blah, blah, blah, whatever the name is, and it takes that string, converts it into an integer. Then grab me an emulator and set that address as the virtual address that we start. Let's log reads, let's log writes, and turn off safe mem, because if it goes wonky and tries to read the code, it's going to read from someplace that I don't want. Then I actually want to know it, so I can come back here and fix this up. Then we hand that emulator, the workspace emulator, into this ninja emulator that's generated here. We then read the off data dot bin that I mentioned before, and put that into the file if we don't hand in file data, because I can hand in a string that is the same thing as the file. Then I call, this is actually pretty magical, ninja emulator has a setup call function. Then it takes a list of arguments. If it's an integer, it'll push that to the right location, the stack or the register that's used for this calling convention. File data is actually a string, so it's going to call its internal malloc function, create some space that ninja emulator manages, and shove that string into that space just by handing it in here. We then hand in the length of the file data, so that's just a number. It's going to push that into the register for the second argument. We then know that this is a secret key. I know, a super secret key. And so that is, the ninja emulator takes this, says again, this is a string, malloc something that's that size, plus some buffer space, and store this here, and then put that address into the appropriate location for the calling convention. And then here's a special way of handing in an argument. I've labeled it out count. And I'm just going to say, hey, this is a 64-bit value of zeros. I could have said, yeah, no, I wanted this to malloc out a location because it's going to be handed in by reference. So this will call malloc. It'll put in the emulator metadata this name, out count, and give you the address so I can do post-mortem inspection when I'm done. And so that's initialized. So I'm just going to go in and do that. There. So auth emu is this thing that I was just showing you. The get emu do crypto thing decrypt. And I hand it in the workspace, and it does the rest. And then I do run step. So if we emulate through, boom, boom, boom, boom. OK, so RDI, we're going to store RDI. What is RDI? RDI is our first heap allocation. And we can look at the heap allocations by typing in heap here. And our heap dump shows this is what was handed in from the auth data. Here's our passcode, our secret. And here's the output buffer that was allocated. So if I wanted to, I'll talk more about this later, but let's just take a look at this looks like something interesting, probably as a string. So let's just say, hey, show me that as a string. Sure enough, it's a string. There's a whole bunch of functionality that you can use from this horrible command line. I apologize in advance. It looks horrible. We'll keep working on it. But we do have a help that gives you the commands. Including quit and go silent. So you don't print out all this memory and register stuff. Then we can do a backtrace. We can use the go command to say, hey, go until this virtual address or go this number of instructions forward. Then we also have the next instruction. So if we go to a call, for example, and we don't want to actually dive into the call, we can just do an I and skip it. It'll emulate it. It'll actually spit out all the data from the emulation, but you won't have to single step it. B means emulate to the next branch instead of, again, single stepping. We can show our stack as we did before. But our stack, we can do, we can control how much of the stack we want to show. Apparently, I ran past the end of the stack because there's not 100 entries. I can create new heap items just because. Like if I'm emulating through and I run into a thing where I'm like, yeah, no, that's really supposed to be a heap alloc that I need to shove some data in. So I can say, yeah, malloc that. Give me 100 bytes. And it says, okay, your new chunk is there. So now I can say, hey, make that. And that's a string. And make that equal to, yo, dog. Hello, Defcon crew. Boom. So now we say, what's on the heap? Okay, again. Let's take a look at that as a string. All right. So, I mean, at that point, if we're like, no, that really needs to be an RBX right now, we can do that. We can say RBX equals that address. And then refresh. And now we see RBX is that address. And if that's the thing that keeps the thing going, you can go back and update your starter script. But you can also keep going. Now, the beauty is if it doesn't work out and I figure out, oh, whoops, I screwed up. It's in the, if I have it in the starter script, I can just say, hey, go back to the starter script and then go to this address. And it'll, boom, snap through all the stuff again. All right. So moving right along. So much I want to show you. Sorry, I only have a little bit of time. Boom, boom, boom, boom, boom, boom, boom, boom, boom, boom, boom. Oh, branch. Okay, cool, branch. I don't really care what's going on in this. Okay, I really do care. But for the sake of time, we do nexty. It emulates through the function. Returns. I got a return value. Huh. Let's take a look at the heap for a second. So in addition to what I typed, I allocated there, there is what looks to be some text, some string data. So let's see. Let's see the return value that they returned. Let's just use rex, string. And this is looking very close to what they gave us in the hint for the resonante authenticator challenge. So that's Vivisection, guys. Here is the location of the project. It should be released by the end of DEF CON. If you have any questions, please feel free to holler. Anyway, what are you waiting for? Solve problems with emulation. Reach out for help if you need it. Here's how to get a hold of me. Play around. The rest will come. And when you get the slides, there's a whole bunch of salvage yard stuff. Thank you very much. Looking forward to seeing you guys next year. Thank you.