All right, so we're going to be talking about reverse engineering Python. We're going to be talking about dynamic languages but it's specifically going to be dealing with Python in its binary forms. Just going to do a quick about us. We work for Tipping Point, mix IPS systems based out of the US and Austin, Texas. Our team is specifically responsible for reverse engineering, Volendev, bug hunting, all sorts of fun stuff. We are authors and contributors to that stuff. I'm sure you've heard of PyMAE released here, OpenRCE, I'm sure you're all familiar with. Quick outline of the talk. We're going to deal with Python as you all know is interpreted in languages I'm sure. You write the source and you assume that people release it via source but there's a few different ways that you can release it in binary form. We're going to have a full case study on how you can cheat it in one of those massively multiplayer online role playing games. We have a bunch of videos for that. We're going to deal with disassembling code objects, modifying them. We're going to deal with all sorts of different static modifications you can do to a code object. We're going to talk about the serialization, how they're all stored and all sorts of ridiculous stuff you can do via runtime modifications in the Python interpreter and all sorts of stuff that you can do because Python is a dynamic language. Okay, so we start with what is a dynamic language? Really it isn't whether a language is dynamic or not dynamic, it's whether it contains features that can be considered dynamic. Pretty much the biggest most important thing I think is that type information is done and checked at runtime as opposed to compile time. Now that allows for all sorts of advantages to dynamic languages. Like pretty much when it comes to dynamic language, we use them for development speed, like it says portability, flexibility. We can reuse just anything and just do it all during runtime. It's pretty much just great for lazy developers. Why did we choose Python in particular? Because it implements so many dynamic features. It's gaining popularity. There's all kinds of toolkits out there that are developed using Python and we're already a little bit familiar with its internals. All right, so the game that we're going to be showing you guys how to cheat at and all the videos and all that's included with that is Hire to the Caribbean. They have about 10,000 subscribers according to some other sites. It's not really one of those huge ones like World of Warcraft that has 6.5 million, but it is written in Python. It's distributed in a binary form. As far as I know, nobody's documented any way to cheat at these games at this particular game or any game in Python. We chose this game because, well, one, I've seen the commercial for it on TV about 20 times and it was interrupting my shows and I wanted to stick around with it. Well, Pedram asked me to figure out how to cheat at it. That's how this project started. Thank you, Pedram. So first look, we're going to do a little empirical run down of how I approach the problem statically and Ali's going to cover some of the runtime stuff. So first look, if you download the game and you look in this directory, you'll see it's got a Python interpreter DOL. So you have to assume that most of it's written in Python and it's got these gigantic PYD files. We didn't know what a PYD file was at the time, so Googling it, you realize that it's a, Google tells you it's a frozen serialized Python objects. The thing was 130 megs or somewhere around there, so it's pretty safe to assume there's some cool stuff in there. If you throw it in an editor, a hex editor, and you start grep it around, you'll see all sorts of pirates like namespaces of Python code objects. You'll see constant values, string values, all sorts of stuff that you probably want to mess around with. We also saw references to the Panda 3D library, which Googling that again, you'll see it's a 3D library written in Python, distributed by Disney, and it's what this game is based on and where you take advantages of the fact that a lot of the physics for that library is performed or all the calculations are done client side and that lets us do all sorts of fun stuff. We'll show you later. What do we currently know about Python? Well, we know that with a lot of dynamic language, people release in source. We know that it's interpreted, it's probably going to be compiled to a bytecode, it has, it implements its own virtual machine. Since it's dynamic, there's got to be type information somewhere existing during runtime because that would only make sense. So, first thing I did when I looked at that PYD is I threw it in IDA and this is one of the more interesting little snippets here of the stuff that I saw. Look in the.data section, it's got a huge data section. Code section is very small because it just has this little stub loader that actually like deserializes all this stuff and from the previous Google search PYD, they say it's frozen serialized objects. So, looking at this table, you can kind of glean that it's, you know, pretty easy structure. It's name, pointer, length. Because we know it's serialized, we can assume that that pointer points to a serialized code object of length, whatever that D word is and the name of the code object is whatever that string value is. So, we have some IDA Python scripts that we wrote just to extract all that but we have some other cool stuff to do with that. Next stuff, the next thing we want to cover is serialization on how we would extract all that. So, pretty much this just consisted of digging through Python source code. Python has a, has a, an it frozen module which does all this and actually uses an internal Python module called Marshall. The Marshall module is responsible for serialize, for serialization and deserialization of Python internal types or C implemented types that are, that come with Python. It's kind of like Pickle except Pickle can't handle Python internal types, so that's what Marshall is for. This is, Marshall is used normally for actually serialization of code objects and you'll see it in a.pyc file. That's actually, it's pretty much a magic value, a time stamp and the serialized code object. So, they use that to avoid having to recompile the source code for speed, for speed reasons. There was also, I think, Python 1.4 or something like that. There was a developer develop, used Marshall to develop what's known as a squeezed object, it's extensions.pyz and that later evolved into the pyd format which is what we analyzed specifically for this presentation. All right, so I'm going to run through the Python code object. Well, he mentioned the Marshall module which allows you to serialize and deserialize data. If you were to take that, that table that was in the pyd and you were to call Marshall.loads, that will pull out an object and that object is returned as a Python object of type code. That's what we're going to be messing around with for the most part because that contains all the different type information, strings and values and data and everything that you'd want to modify to affect the runtime execution. So, I list out the properties of the code object there. The one that, as a reverser that we're interested in, mostly is called CL code. That's actually just a string and it's the object's bytecode. So, I'm going to go ahead quickly do a little bytecode primer. That string is, consists of Python bytecode instructions. An instruction is a one byte opcode and it has arguments when required. All the arguments are 16 bits. If you happen to need more than 16 bits for an argument, they have support for that. It's called extended args. But if you have 64,000 defined constants in your code, I can't think of anything other than a ridiculous getop implementation that you might be doing that for. There's actually no data in the bytecode string itself. There's just index references. So, remember I showed all the other properties of the code object here. Like CO const, CO bar names, CO names. That's where the data is actually stored. So, the bytecode has like an index reference into that tuple list. So, here's a quick example. Here's an example of bytecode. Every line of this is a Python instruction. So, the first byte is an actual, is 64, hex 64, which maps to load const. The argument, if you put the end in this, is just two. The instruction before that is another load const with a different argument. So, it disassembles to this. Load a constant, load a constant, load a constant, build the tuple out of them, return it. Python operates on a last in first out stack. So, load constant loads a constant from the CO const tuple list, pushes it to the stack at index, pushes the value at index two of the CO const onto the stack. Likewise, for the load, the other load const, build tuple pops those three values off because it has an argument of three, creates a tuple, returns it to the list, return value pops it off to the caller. So, it's fairly straightforward. So, code object modification. Now, earlier I mentioned code objects are immutable because they're implemented in C. However, how do you modify it? Well, we figured out that you can actually, because of Python's dynamicness, you can actually take a type from any object and just use its constructor. And the code type, which is, which is there, what we do is that blurb is just evaluating a lambda which gives us a function and gets a fun code object, takes the type and then we use the constructor to pretty much clone the original code object with the same attributes but we modify them and then we have a new code object that we could assign wherever we want and then call that and that could be used for hooking which will be discussed later. All right. So, I did, originally I did all this by hand. I took the PYD, I started, you know, using Marshall to pull out objects and it's a huge pain when you want to modify a code object inside of, you know, that's inside a code object in terms of hierarchy. If you have a name space and you have a class and there's a, you know, a function inside a class or a function inside a function inside a function, it gets to be a huge pain to do this manually. So, we coded up this tool set called Antifreeze. It's called Antifreeze because PYD is considered frozen Python so Antifreeze makes sense. It's web-based. It's, I'll show you a screenshot in a minute but it's, it uses the XJS framework, just JavaScript library to make it all pretty and the components of it, they have a disassembly engine so it'll take a Python bytecode. There is a disassembly module called dis but it kind of sucks so we will, he mostly rewrote it and you'll see the disassembly output that we have. It's a lot better. It has support for labels, has support for comments and all sorts of cool stuff. There's actually an assembler so that in the editor which is a big text box in our tool set, you can literally just start coding your own instructions if you want, putting in changing indexes, whatever and the assembler will handle all that for you. Strips comments for it, it's a two pass, does a bunch of stuff. We also, another component is the functionality for extracting all the different objects. That consists of a PE parser for actually locating the object table that I showed in the editor earlier and a complete working Intel disassembler which if you happen to look at the source code, you'll notice it's coded a little bit weird and that's only because we have some really generous friends who don't mind doing data entry for us. They're all friends. But they're not technical so we code, it's coded in a way such that someone who's a layman or doesn't deal with the stuff can actually put in all the Intel opcodes for you because it's kind of a pain in the ass to do by hand if you're reading through the Intel books. So if you happen to look at the code, that's why it's designed that way. Here's a big screenshot. You probably can't see this in the back but I'll zoom in in a second but that's just the overview of how you can kind of use this tool. Zooming in, the left column of that big pane there is the entire hierarchy of the PYD. So it pulls out all those objects, descends recursively into all of them, pulls out all their internal code objects, pulls out all the functions, all the different attributes and you can browse through it and click one. So if you were to choose say the namespace here is pirates.pirate.dynamichuman, class dynamic human function apply body shaper. So if you were to click that, you would get, this is a small snippet of the assembly but that's the format that would be in that center pane that you saw there. You can see, got support for labels, anything past that pound, this is just going to be a comic, it's stripped by the assembler. But yeah, if you wanted to change like a constant value, any of the index, so if you want to change the data, for instance, it's all referenced by index. So if there's, they're loading index two and that's an integer and you want to load say index 12, it's a higher integer which is how we do some of the different hacks that I'm going to show you in the game. You can literally just type it in right there and hit assemble. On the right is all the code properties. So all the code properties I showed earlier, they're all available via that drop down. So you can click that drop down and it will choose one of the objects that populates in here and you can just edit any of those text fields to change values arbitrarily. So enough about the static stuff. We're going to go into all the cool stuff you can do because Python is a dynamic language and all the runtime awesomeness. Okay, this is really confusing slide so bear with me. Objects and types, objects and types of objects, objects and types of objects and types and whatever the hell else is there. But in Python, every object is of type or inherits from the object type. A type of an object is also a type and its type is type. It inherits from base. Its base inheritance is from object. So it's like this ridiculous cyclical relationship graph that like I say there, you may have an aneurysm if you try to figure out. So just kind of say okay and we're good and we'll move on. But... Yeah, to be honest, we tried to make that slide really confusing. But that is actually how it's represented. So anyways, looking at Python, it's a dynamic language. There's a lot of information that should exist during runtime. So I felt, you know, the best way is why not look at it from a runtime perspective. So anyways, all Python objects and all, pretty much all variables and stuff that are objects are prefix with that data structure right there. That data structure can use the reference count, the pointer to the actual type and the size of the object. The reference counter is used for Python's garbage collection if anyone's ever messed with that. So... So I'm just going to cover how say any random Python object is actually stored in memory. This is just some window bug output. And the DD here on that address, 1663, 660 is just a pointer to a Python object. And if you look at the slide previous to this, you see those offsets 0, 4 and 8. You can apply them to that big memory dump right there. And the next, the LN instruction that we pull out there actually dereferences at offset 4, which if you look back here, offset 4 is the object type and you'll see that it returns Python 2, 4, PyDIC. So it's a Python dictionary object. It's just a quick way of how they're stored in memory. So it's more for reference if you were reading the slides. So the execution of a code object. There's two main functions that you kind of need to worry about if you want, if you're curious about how Python itself builds and compiles and executes a code object. The, you want Py, all right, Py eval eval code is what actually takes in a bytecode object and builds, builds, takes in a bytecode string and actually creates the Python code object. Eval frame takes that code object and associates it with and creates all the references between that object and its locals and its globals, which is pretty useful stuff and that's all because of Python's dynamicness. So, how does Python execute? How does it support multi-threading? So concurrent execution of code objects is actually handled more like FreeBSD 4.0's big giant lock if anyone's been familiar with it. What it is is each interpreter that's executed has a lock associated with it and while one, while one code object or one frame object actually is being executed, that lock is held. So nothing else will execute until Py eval frame decides to be like, okay, here you go, now you guys can run and then that's pretty much how it executes. Py eval frame is essentially purely responsible for cooperatively sharing, sharing a slice of time with each thread. So now, diving in with the debugger, this is probably the most boring part of this presentation. While looking at a Python process, we have three things or rather I had three questions that I wanted to know. I wanted to be able to identify what interpreters were currently executing as Python has support for multiple interpreters in the same process, what threads are associated with each interpreter and what current, what's the current code object that's being executed. That pretty much, that's sort of like Ltrace but in process. So, that would pretty much answer every question anyone would want to know if they want to look at something statically and identify what code object is being executed at a certain time. So, interpreters, it's just a plain simple stack, it's a pointer. The key thing is it's not exported by the Python DLL so we need to find some way of identifying the head of the stack so we could enumerate all the, enumerate every single interpreter that's currently running. Python has, is MAD-friendly. They have a Py interpreter state head which is exactly what we're looking for. So, what we do is we just unassemble it and that's the address we're looking for, 21B87C0. Once we have that, then we can actually go through and enumerate each thread. This is the data structure, T state head is actually the thread stack for the interpreter. So, then you could enumerate each thread and then from it, you could extract the actual frame object which will identify exactly what's being executed. Python threads are also one-to-one with the operating system. The thread ID is pretty much if you're using Linux or if you're using Windows, that's your thread ID. So, if you're in a debugger and you want to see, you know, what current thread is executing, you want to set a break point only in certain thread, you could just look at that data structure and just, that's your thread you're debugging with. So, here's the frame object. The frame object is the most important part. This is where our code actually gets executed. There's the code object that references it and the globals and locals that are bound by eval code X. So, because of support for introspection and reflection, we have the names of all the variables and anything inside any code object which makes it really handy because a lot of stuff that we have to do during reversing is already done for us because the language supports these features. So, here we go. All code must pass through eval code or eval frame essentially for like instructions that, for a bytecode instruction that actually executes a call of a function or a call of an instance method. Essentially, those two, those two calls, pyobject and pycall method and call function are responsible for simulating that instruction. So, we have to thank Windabug for this. This is how to, in Windabug, the Windabug way of displaying and resolving structure. Don't try to read it. So, now, one thing is when applying to a game is, it's, sorry, this is your side. My bad. Oh, it's cool. But anyway, the problem with what he just mentioned with pyval code and py, or rather, pycall function and call method is if you try to break point on those, they get hit so often when you run, when you actually run a Python application that it's, it's unusable and it's, you know, we had to do a different way of, or a different way of actually determining what functions were called during runtime. So we do standard user space hooking which is the DV alloc. You allocate a bunch of room. This, just essentially, you're hooking the very beginning of the function, redirecting it to the allocated space that you, that you previously allocated and you put all your instructions of whatever you want to do there and you return back restoring whatever instructions you may have clobbered. You see here we do with the, the SBB got clobbered because we created the jump which was too many instructions. So, in our actual memory that we allocated, we restore those instructions and jump back to their code. So this allows us to, very quickly, if you have this set up, it'll just instantly log every single call of any function in Python by the name of the actual Python object which is like a run trace and it's really, really useful for things that you may want to modify especially when you're trying to cheat in a game and you want to know what happens when you jump. You do something like this and you just have it right to a file, you'll know exactly every single Python function that was called. So that sounds really complex to me, like that's a lot of strings sucked. So, but dynamic recompilation, the cool thing about dynamic recompilation and reflection is why don't we just inject code into the currently running Python interpreter? We could use that to do all kinds of interesting things such as just hooking in Python rather than patching binary and writing assembly for it. Now, any language that supports this is capable of this. Now, the easiest one that I found is Pyrun string. All you got to do is pass it, your pointer to your globals, to your locals and the Python code you want to execute. Then Python will compile it, produce your code object and then evaluate it for you. So, it pretty much does all the work for you, very simple. So function hooking in Python, everything in Python is a reference, this means functions and objects. So essentially, if you want to hook a function, just reassign the name and as you see, I define a function, just call it new, I hook it, just I print the args, return the result and I just reassign it to old. So if you call old, it will execute new and then new will execute old. So, instant method hooking. Now, instant methods are a little bit different because every Python object is immutable or every C implemented Python object is immutable. We end the requirement that a method has to be, has to have some sort of context with it like for object oriented programming and specifically, we have to essentially re-instantiate the code object and bind it to the original variable. So, we do type sneaking here, we sneak the type of an instance method, I chose exception string because it's everywhere, it's short and that's the prototype for it. So you call function, you supply the instance and you supply the type that it's associated with. Now, once you get that, it just consists of, you know, I instantiate the object, it consists of just reassigning the method name with the new instance method that you just created. So, Python supported debugging hooks. Because we can inject code, you know, there's a Python debugger, we could just leverage all the functionality that they have. There's assist.setTrace function, so we could use that and see what's being executed because Python is really friendly like that. And there's I hooks if you feel like hooking like imports, if you want to see if something is going to be imported, you could just use the I hooks module that's provided by them and just dump it. All right. So, yeah. I guess that speaks for itself. We covered essentially how you can modify static PYD stuff and how you can modify at runtime. Now, we're going to talk a little bit about exactly case study specifically what I modified when I first decided to cheat this game a little bit. So, using Antifreeze, you can kind of get a big listing of all the different namespaces and what you want to look at. I found that anything that ends in globals tends to be perfect for modifying because it's just static values that they use and assume nobody will change because it's all handled client side such things like the level cap. Everyone in the game is max level of 40. So, I thought it was hilarious to change our max level to 41 and then also our jump height is like 400 feet. So, when we jump 400 feet, we just tell people that's, you know, you got to get to level 41 and they spend all their time trying to figure that out. It's awesome. So... You see a lot of people jumping too. It's hilarious. Yeah. When you start jumping around, everyone tries to copy you and it's just hilarious because they're way down there. But you can change reputation globals, for instance, that's a level and experience. So, overnight, like not even overnight, technically one run and then the next run, I went from level one to level 40 and that takes all these kids who are 15 playing this game like, I don't know, four or five months to get that far. There's economy globals which is gold cheats that you'll see in the screen shots. It's stuff like a ship cost 60,000 gold. I can instantly change it to one. It has a required level of 15. I can change it to zero. All sorts of stuff like that. Pirates globals is speed, acceleration, jump height. Kind of feel like the Hulk when you play this game now because you can just run and jump 30, 40, 50, 60 feet over buildings. It's kind of cool. I'm going to try to do a live demo. Hopefully, the wireless is still working. Ship globals, that stuff's really cool because everybody's ship in this game moves like this slow. My ship is like, you almost can't even see it if you're the other player. It's pretty much like a speed boat. We got some videos of that too. But people get really, really ticked off when it takes them an hour to get from Port Royal to Tortuga and it takes me about 12 seconds. It's pretty good. We timed it. Here's a quick little screen shot. Can you guys see that in the back? I don't know. This is just me jumping over stuff. The highlight of stuff is just the economy cheats like the gold. That was a $60,000 ship which is now one and it used to require level 15. Now I can buy it. Oh, this is really cool. They have two modes of playing the game. You can play it when you're on land but then when you go out to sea, you're on your ship. You can't get off your ship. If you try to jump off your ship, you just get blocked because you can only jump what? Two, three feet unless you're cheating. If you're cheating, you can jump off your ship and play Jesus and walk on water which is really confusing to people when you're floating 50 feet above their ship shooting them down with a pistol and they can't figure out how the hell you got up there. It's really, really funny because you can board the NPC ships and we have videos of that which is cool. You jump off your ship and whatever height you leave the sphere of your ship is the height your character stays at so you kind of fly. The other thing is if you cheated with the speed hack, you can also walk faster than every ship can sail. If you see a ship you want to get to, you just jump off your ship and run at them. I can do that a lot. The cool thing is once you get over their sphere of influence, for some reason their physics engine lets you drop down and land on their ship. It does try to push you off a little but it is kind of fucking weird for you to be driving around and have some dude just kind of dropping land on your ship and it's really strange. Oh and this is really cool. So I thought I got caught. So I'm sitting there and all of a sudden I get this email in my Gmail and it's like you've been banned. I'm like for 72 hours and I was like oh shit, they caught me. Turns out I met this guy in the game who's like a 40 year old software engineer and he saw that I was kind of cheating at it and I was trying to explain the specifics of it but he's not a reverser but he kind of had an idea of hex editors and stuff. So I was explaining it to him and I was giving him the list of files to cheat with like which ones to edit and I gave him my email. So their Autobot banned me for giving him my email. Nobody looked at the content of the conversation which has the file names that you want to change right there. So that ban got lifted and I'm still playing the game so I guess nobody reviews their ban logs but I thought that was pretty funny at the time. Oh and this is something that I'm going to go ahead and do right now. They have a screenshot contest that happens to coincide exactly with Recon. It's a ship battle screenshot. So you win an iPod touch to the top 10 people. So I want to, I've got some good screenshots so I'm going to exit out of PowerPoint and show you guys now just to see what happens and hopefully like if they didn't know we were cheating before they're definitely going to know now. Oh, do it for them? Well I'll use Wi-Fi. I don't care. This is cool. But like here's the screen. Never mind. Maybe I won't use Wi-Fi. Well here's, I'll do it after the talk, whatever. Here's one. You're not supposed to be able to get in the water when you're at sea. So that's a cool screenshot I thought and this is me hovering, shooting some random other ship. So I'm going to submit those two. Hopefully I win an iPod. I don't think it will happen. I think they'll just try to sue me or whatever they do. At least it will make them laugh. Yeah. I just hope the developers get a kick out of it but yeah. All right. So I guess we're kind of going quickly through this but I'll show you some videos. What do we got here? Okay. This is like when we first found this patch. You know what? I guess it's not working. So we're going to go ahead and just play this game live because... Man, we put all that work. Yeah. Oh well. Oh and actually to play this game, there is one thing that they do. They do have MD5 checks. I was going to show you guys the IDV but I figure it's a two byte patch so you guys can figure that shit out if you really want to. Like most. Oh man. I got to get on the wireless. Hold on a minute. Come on buddy. There you go. I'll just do this. Yes, connect anyway. I might as well just BS for a little bit. Like one thing that's really cool also about the martial object which I kind of wanted to mention but is really off topic is this could be like originally I found out about it because I wanted to be able to save the current state of my currently running Python process and the whole reason for that is because I wanted to be able to like, hey, say I break Python up. I can just reload everything that I've already defined and another cool thing about that is that serialized Python code can be distributed to another computer too. So that way I could constantly just, you know, run tools, save my state, copy it to a shell that I develop on and then so forth, you know. Yeah, I'll submit them both. I wonder if I can do it. Well, their EULA does specifically say no reverse engineering so I'm pretty sure they're going to disqualify me. They don't know we reversed it. Not yet. Hopefully they analyze it before this video gets out. We could just claim Photoshop but I don't think that will work. So it's been successfully uploaded so we'll see. Don't forget to submit the second one. It increases our chances. Just do a live demo of the ship. I just recently while I was just sitting here watching someone talk, I changed my ship speed from like, the normal ship speed is like 0.8 because I use it as a float value and they do like a scale like multiply on it. I changed it to like 22 and the ship moves so fast you can pretty much, yeah, John McClain, that was the name of my pirate. I don't know why they accepted that but yeah, the ship moves so fast you can almost jump over certain islands. I don't know why these won't play though. Oh, there we go. Okay, so this is... Here's me jumping. Yeah, the long way, like the regular way is pretty long so that was a lot shorter. All right, here's me walking and running just to show the speed and the jump. Yeah, most people jump keeping my two to three feet so. And right up here you're going to see that I actually stopped and let a guy run by me, another player just to show you for reference how fast they walk. So watch out. Three counts. That's him. Then we decide to just go. Oh, yeah. I was actually looking around for him because we were recording videos and then I finally caught him. Oh, this is the cool ship stuff. I was like, you know, I want to board this ship and see if I can interact with the driver of it. Keep in mind, he doesn't have the ship hack on. Yeah, this is how slow you actually move and I want to jump up there. Can't make it so... We've got better ones. Yeah, and then this was a long distance one. I said, I'm going to go to that ship all the way over there. And we're moving faster than any other ship can even sail which is really funny because they can't run away. It's just a long video but bear with it. It's kind of funny. I was surprised it actually rendered that far. I wonder what you thought when I dropped in front of him and tried to slash him with the sword. All right, so here's just for reference, this is a regular sailing speed right here. So this is all we ship and I'll show you mine. What are you trying to say there, buddy? So, and here's my ship. Go. It's funny because inertia just pushes you. It's almost like hard to control. You can't really... I can only imagine what these people are thinking. It's really awesome. I think I've got one more. Oh yeah. This is circle strafing in the ship. I just want to do some loops around this guy just to screw with him because he thought he was badass with his 60,000 gold ship. This is the default ship you get, first ship you get in the game. You got like one sail. It's pitiful. What are you saying there's a problem with circle strafing and shooting your cannons or something like that? The other thing about this is when they try to actually attack you, their cannonballs, I go faster than cannonballs. So you're pretty much invincible. You can take out any ship in the game because they just can't hit you unless they're really good at predicting what you're going to do. Not really. Oh, but I guess the game's loaded so I can actually play it. So let's go this way. One thing that's also interesting is there's no, on ceilings and stuff, there's no collision detection. You're not supposed to be able to get in here, but if you jump like this, then you can. Yeah, see, and there's no collision detection. You're not supposed to be able to get behind this counter. This confuses the shit out of people. The best thing to do back there is to dance a jig and wait until people start trying to get it there. Yeah, actually, I'll show you. Watch, so this is the best one because you can do these emotes in the game. So I like to, like, when I'm not playing the game and I'm going to go watch TV or something, I just let my guy dance. Another thing that's actually interesting is we've been doing that so much that someone actually found a bug in the walls and was able to actually jump back there. So it's like... They found a weird clipping bug. Yeah. And they were like, oh, we did it. They actually figured a legitimate way. All right, so this is the new modification of my ship, which is obscenely fast. I mean, I can't even control turning. It's just like the drifting ship. But anyways, I guess that's pretty much our talk. I know we're probably cutting it short, but it is the last talk of the day. So if you guys have questions... We just want to drink anyways. Here's our question slide. Are there any questions? Yeah, question slide. Whatever. Anyone? Questions? No? What is your money in that game? Are you interested in the game? Well, the interesting thing about, like, this game isn't as popular as, say, WoW. Like, WoW actually has that gold conversion. Like, if you have gold in Warcraft, you can sell it for real money in the real world, which is cool. This game doesn't have that because I don't think it's popular enough. I did find where, like, I found the code where if you attack someone, it has, like, a function like getGoldDrop, and it does this, it does a random integer check between the minimum level and, like, the minimum and maximum that it could possibly do, and I changed it so it maxed out to something ridiculous. But I think that they have some kind of check server side because I didn't get it to work, but I found the code where they actually handle that. Yeah, so, like, technically, I mean, I can change the cost of any object, so gold is insignificant. You have one gold, you're rich. Like, you can do whatever you want. So, anyone else? Yeah, I tried that. I found the scale for, like, they have a class called Make a Pirate when you actually make your pirate, and they have all these scale values for, like, the length of your chin and all that kind of crap. So I tried changing that, but I don't think it gets distributed to everyone else. I think it's just a local thing, and it didn't actually work. The other thing you can do is all the textures are actually stored in this.mf. We haven't actually, like, reversed the.mf, and I don't know if you guys know what an.mf file is, but all the textures are actually in there. So I was going to make my guy, if I had time, I was going to find the texture for my character, make it all green, name him the Hulk, and just start jumping around and hope that, like, it got distributed. But I didn't really have time for that. But I don't think a lot of that kind of stuff is broadcasted to all the different people. And it probably only happens during character creation, then it's stored. So, any other questions? All right, I think that's it. Cool. Thanks. Thank you.