TippingPoint Digital Vaccine Laboratories

Hacking the Pirates of the Caribbean Online MMORPG

My colleague Ali and I recently presented on Reverse Engineering Dynamic Languages, specifically Python, at RECON 2008. As a case study, we demonstrated hacking cheats into Disney's Pirates of the Caribbean Online game (slides here). The game has received some pretty solid reviews and boasts over 10,000 paid online players. They also have a free download available for those of you who would like to follow along. Let's take a look at some of the hilarious effects of our case study and then cover some simple technical details so that readers can reproduce to join in on the fun.

To be clear, the cheats shown below are the results of client-side modifications. No malicious actions were performed against Disney's servers.

To start things off, here are the results of a simple jump hack which allows the avatar to leap over 15 times higher than what he otherwise should:


This next video demonstrates a similar cheat, modifying our character's speed. Towards the end of the video you'll see us stop and wait for another user to run by to give you a sense of what is "normal":



Here is what the ridiculous jump height looks like from the perspective of another user:


Some side effects of the jump hack include the ability to... fly? Apparently if a character is able to leave the "sphere" of influence of their ship, the physics engine sets the avatar's Z coordinate to the height at which they moved away from the ship:



Some more flying... we can actually fly along the water faster than any ship in the game can move:



Except of course, our ship, which can travel faster than enemy's cannonballs. This is the default ship given to you in the game. We have modified the ship's speed, acceleration, ramming power, maximum crew, maximum cannons, and other fun traits:



If you're interested in the technical aspects behind these modifications, read on...

There are three files we need to worry about modifying, all located within the install directory:
  • Phase1.pyd
  • phase_1.mf
  • Launcher1.exe
Phase1.pyd is a PE file containing frozen python objects that are deserialized and executed by a C stub function. This is where most of the values we will want to modify are located.

phase_1.mf is an archive containing DLLs needed during runtime, as well as a copy of Phase1.pyd. When the game is run, this file's contents are extracted and the internal Phase1.pyd overwrites the external one.

Launcher1.exe is a UPX-packed executable that contains MD5 checks to ensure integrity of the .mf and .pyd files. UPX is an executable packer commonly used by malware. However, it is quite efficient and is also used for non-malicious executables like this one. Here's an example unpacking session:

$ upx -d Launcher1.exe
        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   1925120 <-   1512960   78.59%    win32/pe     Launcher1.exe
Unpacked 1 file.

Once we've unpacked the file, we can make the 2-byte NOP patch to bypass the MD5 check, allowing us to arbitrarily modify the Python code within the other files. Here's the before:
Launcher1.exe (base address 0x400000)
    00422188 E8 88 8F FE+ call std::basic_string.... 
    0042218D 85 C0        test eax, eax 
    0042218F 75 49        jnz short loc_4221DA
    00422191 8D 75 94     lea esi, [ebp+var_6C]

And here's the after:

Launcher1.exe (base address 0x400000)
    00422188 E8 88 8F FE+ call std::basic_string.... 
    0042218D 85 C0        test eax, eax 
    0042218F 90           nop
    00422190 90           nop
    00422191 8D 75 94     lea esi, [ebp+var_6C]
The above code is where the Launcher does a string comparison between the calculated MD5 on disk and the MD5 value sent from the server. By overwriting the conditional jump that was there with NOP instructions, we force the check to always pass.

Now that the Launcher process ignores the integrity of the frozen Python code, we can go ahead and begin to modify the Python objects in Phase1.pyd.

The code objects within the PYD file are serialized, and while we could modify values in a hex editor for a quick and dirty cheat, there is a much more surgically precise and flexible method that we demonstrated in our presentation at REcon. The process involves deserializing and disassembling the Python code objects. You can then modify constant values, change byte code instruction logic, and re-inject the code back into the PYD. If you're interested in this method, you can peruse our slides. For the rest of you, we will continue and walk through some simple byte swap cheats that require nothing more than a hex editor.
 
If we load Phase1.pyd into a hex editor, or IDA, we can see string references to Python namespaces. Most of the interesting ones are suffixed with Globals. For example, pirates.reputation.ReputationGlobals, which governs experience needed to level up, pirates.economy.EconomyGlobals defines the cost of any item in the game, pirates.piratebase.PirateGlobals controls the physics of your character, including speed, acceleration, and jump height. The format of the object table within the PYD is: name, pointer, length. So, if you find a reference to a possibly interesting namespace, you can follow the pointer value to locate the serialized object. That would be where the values to change would reside.

I will cover one simple jump hack and leave the rest as an exercise for the reader. The default value for a character's speed and jump force in Pirates is 24.0. I discovered this using our AntiFreeze tool (see slides mentioned previously). For the purposes of continuing this walkthrough, here is what the disassembly of the Python code looks like that initializes the in-game character's physics attributes:
    load_const  161  # '24.0'
    store_name  196  # "'ToonForwardFastSpeed'"      
    load_const  161  # '24.0'
    store_name  197  # "'ToonJumpFastForce'"
    load_const  162  # '8.0'
    store_name  198  # "'ToonReverseFastSpeed'"
    load_const  163  # '120.0'
    store_name  199  # "'ToonRotateFastSpeed'"
    load_const  161  # '24.0'
    store_name  200  # "'ToonForwardSpeed'"
    load_const  161  # '24.0'
    store_name  201  # "'ToonJumpForce'"
The code above is from a disassembled python code object stored within the PYD. The float values themselves can be found with a simple byte search. However, because of how Python code objects are structured, these data values are not necessarily next to each other within the file. Also, if you are not rebuilding the PYD's object table, any changes must not affect the size of the file. Otherwise, the game will bail while trying to deserialize the code objects.

When a float value is serialized in Python, it is stored in a string representation. So, 24.0 is stored in file as "24.0f", the "f" indicating it's a float. For the purposes of a demonstration everyone can easily follow along with, simply search Phase1.pyd for all occurrences of "24.0f". Now, if we simply replace the correct 24.0 value to, say, a 99.0 value, our character will be able to leap buildings.

After we do that, however, we also have to consider the phase_1.mf archive file. This file contains a copy of Phase1.pyd, and it overwrites our changes upon game execution. Here is a quick Python script that will copy the contents of your Phase1.pyd file into the phase_1.mf so that the changes are persistent:
    #!c:\python\python.exe
    #
    # injects Phase1.pyd into phase_1.mf in parts because 
    # the file size is too large for python to manipulate 
    # in memory as a string.    

    pyd = file('Phase1.pyd', 'rb').read()
    old_mf = file('phase_1.mf', 'rb')
    
    foo = old_mf.read(1770) # index of PYD within MF
    foo += pyd

    old_mf.seek(1770+len(pyd))
    bar = old_mf.read()
    
    result = foo + bar
    
    old_mf.close()
    
    new_mf = file('phase_1.mf', 'wb')
    new_mf.write(result)
Once this has been completed, we are able to run the game and test out the injected cheat. If all went well, our character should be able to jump as depicted in the videos above. The cheats involving modification of the game economy and ship characteristics become more complicated--too complicated to attempt using simply a hex editor--but our slides give the information needed to start down that path.
 
Hopefully you've got a basic understanding of how to mess around with this game. The demonstrated method above is a quick solution, so check out the slides if you'd like to see the "correct" way to do it. Also, keep in mind these techniques can be applied to any game written in a dynamic language due to the inherent type information requirements. For those who would like to extend the research, take a look at EVE Online, which reportedly also utilizes Python.

If you've got any questions, feel free to e-mail me @tippingpoint.com, my e-mail id is aportnoy.
Tags:
Published On: 2008-06-23 13:05:55

Comments post a comment

  1. Anonymous commented on 2008-06-23 @ 15:00

    Hilarious! nicely done! Are you guy going to release the Antifreeze tool?

  2. Ali Rizvi-Santiago commented on 2008-06-23 @ 15:17

    anonymous, it's not really ready for release as there aren't any docs written nor do we really want to be held responsible for it's maintenance ;). however, if enough people ask for it on the blog we might get around to documenting it and cleaning up some of the code for the UI to make it a "proper" tool release.

    there's a bunch of other modules that were written for messing around with pyd also which some people might find interesting.

    if you want to shoot me or aaron an email, we can send you the code as-is.
    arizvisa [at] tippingpoint.com
    aportnoy [at] tippingpoint.com

  3. Sirmabus commented on 2008-06-23 @ 17:04

    Ehh boy flagrant behavior, as if you want to get caught? Didn't you think other players would notice the super jumps and speed hacks? You force their hand to "fix" these and add more server side checking etc. Well grandstanding gets you noticed, and sells consulting services, etc. ANYHOW, not meant as a flame.

    Interesting approach. I ran into similar concerns working on "Tabula Rasa", which is also heavily Python based. It's interesting you went towards byte code modifications et al.

    I think one thing you miss to point out is that you can convert the bytecode back to .PY files if you can find or make a "decompiler" for it.

    There was a open source one that works up to Python version 2.3, but went comercial after that.

    I was able to find one for 2.4 of a Korean site, that I had to heavily modify to work. Unfortunately the link is bad now.

    I was able to decompile a large percentage of TR's Python files.
    I really want to make a proper decompiler written in C++ that will be fast and not run out of memory so easy.

    Seems to be this would be a more exploitable approach.
    The launcher might have to be replaced, at least modified enough so it would load decompiled .PY files.
    It would be the ultimate, here you would have basically the
    source and you could write little bots or what ever inside the origional code.

  4. Aaron Portnoy commented on 2008-06-23 @ 17:21

    @Sirmabus:

    I'm not so concerned about being caught cheating. We only approached this game as a case study so that we could apply our knowledge of python internals in a real world scenario. In fact, Disney had a screenshot contest that coincided with RECON and I submitted some obviously cheating screenshots while on stage.

    Regarding decompilation, we looked at a few of the existing decompilers out there and came to the conclusion that decompyle from http://www.crazy-compilers.com was the most developed. However, for our project, we didn't feel we had a need to decompile back into .py source. Reading disassembled python bytecode is easy enough.

    I could see how it'd be useful to decompile to source if you wanted to create bots, as you mention, but that was beyond the scope of our initial project.

    Thanks for the comment :)

  5. Ali Rizvi-Santiago commented on 2008-06-23 @ 17:27

    sirmabus, it's a little bit more than just a byte-patch. the presentation talks about how to approach reverse engineering python dynamically, not really about how to write a decompiler.

    essentially the point that we tried to make was that if your language supports dynamic features such as introspection, recompilation, and has dynamic typing. the implementation of the language is required to have all this information available during runtime. we chose python primarily because of all the reasons laid out in the slides (http://dvlabs.tippingpoint.com/pub/aportnoy/RECON2008-PortnoySantiago.pdf) and because of all of the functionality it throws out there for someone to play with.

  6. kevo commented on 2008-06-24 @ 20:51

    I thought this was great, especially when yall sent in the picture of yall cheating to the contest. Yall really should release that anti freeze tool. :)

  7. dennis commented on 2008-06-25 @ 01:35

    nice stuff! exactly to my taste ;)

  8. Anonymous commented on 2008-06-26 @ 22:11

    dude thats AWESOME!!!!

  9. ExtremeDuck commented on 2008-07-02 @ 12:02

    So, if enough people ask for this u would consider to release?
    I'm kinda asking for it right now :)
    cause i didint understand much of what u all are saying my english is very bad..

    But. if you can make those code's into an nice bot/trainer
    it would be so cool :)

    Yours,
    ExtremeDuck.

  10. Anonymous commented on 2008-07-05 @ 23:00

    Where could i get a reliable hex editor?

  11. Aaron Portnoy commented on 2008-07-07 @ 13:00

    @ExtremeDuck:

    Shoot me an e-mail, aportnoy [at] tippingpoint.com

    @Anonymous:

    Check out http://en.wikipedia.org/wiki/Comparison_of_hex_editors

  12. Anonymous”}~ commented on 2008-07-07 @ 22:35

    Couldn't the same affect be reached using a simple memory editor? I mean, you're only editing client side functions and addresses, so using something like "Cheat Engine" would have the same outcome, would it not?

  13. Ali Rizvi-Santiago commented on 2008-07-08 @ 11:29

    @Anonymous"}~:

    technically, you're right. ;)

    this can all be achieved with a simple memory/hex editor. One can even use a memory editor to modify the bytecode that gets executed, which'd be a win. however...this would eventually become incredibly tedious which is the reason the tools developed in antifreeze were written.

    the presentation kind of tries to show that using the exact same tools and methodologies that one might usually use (such as cheatengine) to interact with an application implemented in a dynamic language is quite possibly the wrong way to go. some of the features available in the target language can allow for much easier comprehension and even manipulation of the target application. we discuss how to utilize these properties of the language to get to one's goal. be it cheating at some game, patching some logic out
    of some function, or writing an in-game hit-tracer to see what methods the application calls when you hit a certain key.

  14. Anonymous commented on 2008-07-09 @ 22:11

    i appreciate the time you took in writing this, but the truth is it didn't help much... isn't there an easier way to explain this? too many big words, at least for me...

  15. someguy commented on 2008-07-20 @ 17:39

    Since the modifications are client sided would it be possible to just upload the modified files to the internet so others can use them to replace their normal files? Just wondering if it is can I have a copy? Lol

  16. Anonymous commented on 2008-07-21 @ 05:13

    i downloaed the Revision 2: /trunk code from:

    http://antifreeze.googlecode.com/svn/trunk/

    used python 2.5.2

    installed source to c:\Python25\trunk

    under dos ran:

    C:\Python25python trunk\server.py

    the server started with a localhost:80 response

    i navigated to /pyd but the index.html file did not post got a 404 "W***T**F***" error code

    do i need to run an apache server or iis?

    souldn't i be able to run just the python code?

    btw - tried apache 2.2.9 + mod_python 3.3.1 as an alternative to calling the cmd in the readme.txt file - /mpinfo worked fine but server.py always failed to post with a handler error code.

    any thoughts?

    how did you run this program for your case study - i.e. environment?


  17. Aaron Portnoy commented on 2008-07-21 @ 09:56

    @Anonymous:

    The requirements for that "as-is" distribution that is currently on google code are as follows:

    1. You must be using python 2.4. The marshal module de/serializes data differently between major python versions. Thus, if you're using 2.5 but Disney used 2.4, you cannot deserialize their PYD.

    2. The software assumes the PYD is within the default directory for the game (C:\Program Files\Disney\Disney Online\PiratesOnline\Phase1.pyd).

    You do not need to run any external webserver, the server.py included is an httpd. The URL you should need is simply http://localhost/pyd/index.html.

    If you are still having problems, I can help you via e-mail.

  18. Anonymous commented on 2008-07-23 @ 09:35

    ok - got it working. tried to find float value 24.0f as per the tutorial for jump / speed, but could not find values - im not recognizing the semantics as i would if it were c++ or vc++. please lead me in the right direction - work demands prevent me from learning an entirely new language.

    antifreeze rocks btw

    just my training is not python based - even though most langs are all based on similar semantics.

    thanks in advance

  19. Aaron Portnoy commented on 2008-07-23 @ 10:03

    @Anonymous:

    If you're used to C/C++ you might be searching for float values stored in IEEE format. This is not the case for serialized python. If you load the Phase1.pyd file into a hex editor (I'm using UltraEdit) you can do an ASCII search for 24.0f and there should be 7 occurrences.

  20. Anonymous commented on 2008-07-24 @ 10:07

    please release the cheats soon

  21. Bobby commented on 2008-07-26 @ 11:50

    Can yout please help me out? I have unpacked the Launcher1 file with UPX, but how do I edit it to make the 2-byte NOP patch?

  22. Mitchell-------Mac--------- commented on 2008-07-28 @ 19:58

    thats awsome!!!lol!! can u give me copys to do the speed and jump thing and the boat modifications cuz i havent hacked in 3 years so im awful. plz let me know
    thanks

  23. Ali Rizvi-Santiago commented on 2008-07-30 @ 10:43

    We put the antifreeze repository up for grabs for everybody that is interested. We'll probably be doing a little development here and there depending on spare time, so if anybody has any sane feature requests that you think would be useful, feel free to ask.

    http://code.google.com/p/antifreeze/

  24. WAnna_HAck commented on 2008-07-31 @ 21:28

    Wich upx do i need? Also whill i get ban if i get caught?

  25. Anonymous commented on 2008-08-02 @ 17:07

    Wow! Really cool! But is there anyway I could do this with a Mac?

    And, uh... can you give the instructions to me in layman's terms please? LOL

    Thanks!

  26. Anonymous commented on 2008-08-02 @ 21:13

    To the other poster interested in Mac OS X - I tried to follow the same approach on 10.5 and I'm hitting my first snag trying to muck with Launcher

    ./upx -d Launcher

    File size Ratio Format Name
    -------------------- ------ ----------- -----------
    upx: Launcher: NotPackedException: not packed by UPX

    :P

  27. Aaron Portnoy commented on 2008-08-03 @ 15:04

    My coworker Cameron (who runs OS X) pointed out that the Launcher1 that is distributed for that platform is not packed by UPX. So, only the Windows one appears to be. The code written for the two is going to be different, so the NOP patch is likely at a different position in the file. Therefore, this little walkthrough only applies to the Windows version.

    However, the python marshalling and demarshalling for the Phase1.pyd should be the same, regardless of platform.

  28. Sirmabus commented on 2008-08-07 @ 17:43

    Should have said, "well done" anyhow.
    Neat technique you use(ed).

    Problem with "crazy-compilers" (and, another Japanese outfit) they charge quite a bit IMHO.
    It would have cost over $1000 to decompile the TR files.

    I haven't messed with it for a long time, but I still have the 2.4 decompile stuff laying around.
    It would take a lot of work and testing to get it working 100%, and needs to be updated for 2.5,.
    There are several spots where nested loops break it.
    Also it runs out of memory pretty easy.

    Ahh well maybe another interesting project will come up and I'll finish it (and putting those guys out of business).

    Again, interesting and nice work :-)

  29. Anonymous commented on 2008-08-12 @ 00:14

    Is there any programs similiar to antifreeze? im having probs wit antifreeze

  30. Anonymous commented on 2008-08-18 @ 14:35

    I went to the link in the that you provided but i can't download the antifreeze software i used my xp and my vista computer. I'm just learning these things, but I'm pretty good because i even put leopard on my 2nd vista pc. You guys should do the gold hacks and the other stuff.

  31. Anonymous commented on 2008-08-18 @ 16:50

    Antifreeze problem
    problem in index.js
    line ~428
    Char ~13
    error 'code.Store.getAT(...)' is null or not an object
    Url localhost/pyd/index.htlm
    It won't disassemble!!!
    please help, Thanks

  32. Anonymous commented on 2008-08-22 @ 23:38

    i dont get it how do you get the jump hack and stuff?

  33. Anonymous commented on 2008-08-24 @ 04:00

    hi everyone can any one tell me how exactly use UPX i will be thank full

  34. Anonymous commented on 2008-08-26 @ 11:59

    http://code.google.com/p/antifreeze/ is not working for me, but on the other hand can you show me how to do toontown that would be a good one. You should do all the stuff you figure out otherwise you leave us diing to know what is next.

  35. Aaron Portnoy commented on 2008-08-26 @ 15:23

    Anonymous:

    Google code was down earlier for "network maintenance" according to their site. Works fine, now.

    As for ToonTown, I don't think we'll be looking into that game as it's user base isn't large enough to merit the attention.

  36. Aleksandr Surguy commented on 2008-08-29 @ 00:43

    Please help me with unpacking or using the ollydbg to disable the MD5 check.
    Maybe someone could also post a zipped archive of this antifreeze.

  37. pwnage commented on 2008-09-05 @ 19:02

    how u do that? BTW my name on potco is peter scuzzyhazzord

  38. Aleksandr commented on 2008-09-06 @ 00:56

    Ok I had 3 to 5 days of learning ollydbg and the unpacking stuff so now I got the game to stop patching. All I need is to know how to work with antifreeze.
    Says CGI script exit status 0x1 and when I open antifreeze it just shows Loading PYD file and then when that dissapears(little window) it just has the word PYD under the navigation window. I did set my pyd folder right though unless it doesn't read the config.py.

  39. Anonymous commented on 2008-09-19 @ 07:31

    Wow! This tutorial is excellent. I attempted to use your antifreeze tool. It would be great if you could turn AntiFreeze into an executable. Do you think that you will do thissometime? Is it even possible???

  40. Charles commented on 2008-09-19 @ 21:13

    Okay im very interested in doing this since ive worked with code before and hack WoW daily but for some reason everytime i go to the code for google search it never shows any download. any resolution would be nice

    Xfire me at - Gamercharles
    MSN me at above email

  41. helpless commented on 2008-10-01 @ 02:57

    can you offer a modified game file for dumb people like me or a step by step video...

  42. NubHacka :p commented on 2008-10-07 @ 19:40

    Uhh, well, myname says everything... How do I un-pack Launcher1??

  43. Anonymous commented on 2008-11-01 @ 10:15

    you know you should bring outa pack or atleast a video step-by-step tutorial

  44. Ali Rizvi-Santiago commented on 2008-11-05 @ 10:06

    Anyone who couldn't find the link to the download in the code repo: http://code.google.com/p/antifreeze/downloads/list

    As the basis of this work was the underlying research into the techniques for instrumenting Python. We chose Pirates as an interesting case study but we do not promote mass cheating and as such we will not release any point-and-click modifications.


Links To This Post

  1. jon.oberheide.org - blog - woot 2008: the good, the bad, and the ugly
    linked on 2008-10-21 @ 18:30 Show Comment

    Aaron Portnoy and Ali-Rizvi Santiago from TippingPoint DVLabs had some hilarious videos from the Pirates of the Caribbean MMORPG showing off their modifications to certain in-game attributes such as physics values.  Definitely worth a look.


Trackback