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.