Hacking a freemium iOS app: Contract Killer … or unlimited play without spending a dime (or any other currency)

Let me start this post with a little rant. The iPad is a great product but it’s full of spyware and that sucks big time. One might argue that it’s not spyware, it’s just sending bits of information. Well, for me it’s damn spyware because I’m not authorizing the apps to send any information, much less unique pieces of information that can identify you forever. I can’t even conceive why the enterprise world will adopt the iPad with these kind of problems. If I was the CSO or CIO I would fight against this, and I mean real hard fighting. It sucks, seriously! It sucks so much, that I tried to firewall one of the ad networks and it starts connecting to different Amazon EC instances, more or less like a botnet client (this should be an interesting reversing project). The argument of high-availability for such behavior is weak – there are many HA solutions. If I want to firewall your shitty ad-network, let me, don’t try to fight it.
All this spyware crap is one of the reasons why I’m not fully using the iPad for web browsing and other more personal tasks. Apple should allow a Little Snitch like app, so users can have some control about what is going out of their devices. I really like Apple in some points, but this one pisses me off!

Back to the interesting juice… I was reading today some articles and I saw the announcement of this game, Contract Killer, based on a freemium business model – in app purchases. I decided to give it a try. After a while you need to buy energy credits so you can proceed in the game. Of course I was already more interested in exploring a way to remove that limitation than playing (I played a few rounds, it gets boring…). A reversing brain is a dangerous brain ;-)

The credits information is written into a save game file. This can be found at the Documents/default folder, with the name savebh.dat (by the way, the app has the name BountyHunter.app). These are binary and seem packed/crypted (by the way, if you want to have fun with virtual fishes and don’t want to wait, you can use the same trick with iQuarium – edit the plist file with the properties, it’s not encrypted nor packed – BBEdit can handle it fine).
Checking around the disassembly (don’t forget you need to decrypt the binary, use Crackulous for example) you find two interesting methods: CBH_XorCrypt::Decypher and CBH_XorCrypt::Cipher (CSaveManager class is also interesting, it calls the encrypt method). If you breakpoint on the Cipher method and try to buy some bullets, debugger will break :-). Prototype is CBH_XorCrypt::Cipher(char *, int), meaning that R0 holds the unencrypted data and R1 its size. Do a x/30s $r0 and see the XML file :-)

So my idea was to modify memory before it’s encrypted. I tried to modify one byte from the money, by computing the offset from R0 where it’s located and modifying its value – for example, from 500 to 900. This doesn’t work for some reason, probably some further checks. While doing this, I reversed the crypt routine (it’s a simple xor with a table) so I could write a small decryptor.

But before this, I was trying to breakpoint and modify the decryption. It happens when the game is loaded. Since you can’t load it from gdb (it’s not launched into the screen, so you can’t interact with the app), the only solution is to attach gdb. My dirty method is to launch gdb with the following command:
gdb –pid=`ps ax | grep Bounty | grep mobile | awk ‘{print $1}’`

Open the game in iPad and quickly launch this command, so we can attach gdb as soon as possible, hopefully before decryption. Voila, it works. Now the trick is to let the program decrypt the save game, and then modify memory as in the crypt method. Well, it works :-) And the new save game will use the new value so it means credits, experience, points, hits, guns, etc etc etc.
Now you just need to code a decryptor/encryptor and customize the whole XML file! Beware that the first 4 bytes in save game are a CRC32 and the next byte is the initial XOR key. I will not publish code on this to avoid any legal trouble (although these guys really deserve something like this due to the amount of spyware crap they use…!!!).

The security model applied here is weak because I have control of the data and I can manipulate it at my own pleasure. One of my ideas about the failure to modify at crypt stage was online storage of information regarding each player. I started sniffing traffic and that’s how I saw the amount of spyware ;-)
Probably a large majority of freemium games suffer from this kind of problems if there’s no data synchronization between the app and somewhere I don’t control (as it happens in online games, where only registered keys are allowed to play in servers).

Back to on track to what I was doing before this, damn curiosity!

Have fun, and fuck spyware (yeah I’m really annoyed ;-))
fG!

P.S.: I know how metrics are important to business, I’m a firm supporter of that. But how does sending my iPad name, referral cookies and other stuff qualifies as useful and benign metrics? It doesn’t! Developers should record useful metrics such as software versions and other anonymous info that allows them to know their customer base and improve their work but that’s it. Stop there, don’t be fucking greedy and stupid.

P.S.2: Just finished my little cryptor/decryptor. Everything works fine although the game crashes if some fields are abused (trial & error). It’s easier to reverse and rip the program crc-32 implementation – it’s easier and fast. Unfortunately, the game is boring and too repetitive :-( I’m addicted to Doodle Jump!

15 thoughts on “Hacking a freemium iOS app: Contract Killer … or unlimited play without spending a dime (or any other currency)

  1. can you explain a little bit more about how to attach the gdb command after you open the game? what tool did you use to attach that command?

    Please email me if you don’t want to talk about it here publicly. Thanks!

    1. You need to install gdb and awk from Cydia repos (I think grep is installed by default). Then you must ssh into your iOS device, get the command ready in the command line, launch the game and quickly launch that command so gdb can attach asap.

      The crypt routine can be debugged without that trick. Just launch the game, find the pid for it (ps aux | grep Bounty), and launch gdb, either with –pid option or use the attach command after gdb loads.

  2. hiya,

    very nice research!
    i was able to follow your steps and glance at the decrypted XML in memory.
    writing a decryptor/encryptor would be the next task.. but being unable to “read” ARM-ASM,
    i wondered whether you have added annotations to your disassembly and whether you’d
    be willing to share those?
    i used to do 6502 and x86 …. looooong ago :)

    cheers!

    1. Hello,

      I can’t share that code since it has direct impact into their revenue, and that can bring legal troubles to my side :-) I searched the other day and it seems there are quite a few people searching for cheats to this game hehehe
      The code is easy to read, there’s nothing much advanced on it. I learned about ARM asm using this article, http://www.coranac.com/tonc/text/asm.htm. It is pretty good describing the basics and some ARM assembly pecularities.

      It’s a shame but the reversing world is a legal mess these days :-(

      fG!

  3. i wasn’t asking for code, but for annotations .. i _have_ the code ;)

    however.
    you wouldn’t believe this: i’m doing this for a friend (“hey, have you seen
    that new game.. cooool! i need more credits though.. can’t you do something
    about it!?!”)
    OK, OK.. i want to learn a bit about ARM cr*ckin’ too :)
    i’ve started already working my way through ARM instruction sets.. it’s really not that hard,
    just like you’ve said. any hint is welcome tho :)

    cheers!

    1. I was talking about my source code for my save files generator. The “biggest” difficulty is in the crc32 generator, you can’t apply already available code because it will not match the algorithm the program is using (at least I couldn’t find a working implementation and reversed myself the initialization of the lookup table and the checksum generator). You will probably have to swap endianness for the result of your crc32 (I had to in my code).

      P.S.: It seems there is a very active scene at iOS cheating -> http://www.icheats.org ! LOL

  4. thanks for your reply,

    hehe.. when i crack something, i document almost
    everything, cuz 3 month later i wouldn’t know what i was doing LOL.
    i thought you’d work in a similar way.. hence the question for annotations. nevermind.

    hmm. sounds like serious work with the crc32 – nicely done.
    not sure whether i’d take my chance here… would be much simpler to pursuade
    IsSaveValid() to always return TRUE ;)

    will have a look at that ARM tutorial and the “scene” site, thanks! :)

    1. Giving the annotations is giving the algorithm and that falls under the DMCA bullshit :-)

      Those guys at icheat.org patched the binary for a bunch of unlimited stuff. That works if the device is jailbroken. Since I have a legit save file it can be used in all devices – file explorers for iOS devices give access to the Documents dir so it’s easy to retrieve and replace the save files :-)

      It is a good reversing and coding exercise so it’s worth the time.

  5. okay…i know that all the ppl on top of me are awesome crazy ipad nerds that arent 100% nerds cuz all of them are kinda crappy with their words, but i aint 1 of em…
    so..
    can u put a video…on how to hack it…cuz i dont even noe wat u mean by editing the plist file with properties…

    1. Use a program to connect to the device (such as iFile or whatever is the new name).
      Go the the app folder and delete the save file.

      fG!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>