Restoring OUYA game purchases

With a bit of setup work, you can again play all the games you bought on your OUYA gaming console.

Back to trial

When the OUYA server shut down in July 2019, many users noticed that the games they paid for now went back to demo/trial mode:

So I just hooked up my ol' Mad Catz M.O.J.O., and was pretty surprised to find that a vast majority of my games that I purchased through the Ouya store no longer work, and act like I've never purchased them

(Sonic 4 episode 1, for example, just launches the "Trial" version now).

glow162, 2019-11-16 on reddit

Soul Power is one of my paid Ouya games that reverted to demo mode since the servers went down.

Would it be possible to recieve a different, working, version of the game if I show you my Ouya receipt?

Starfig the boyo, 2019-08-22 on Twitter

@x10interactive Hi! The Ouya version of So Many Me isn't working anymore, it's reverted to demo mode!

Starfig the boyo, 2019-08-21 on Twitter

Would it be possible to release some kind of patch to play Evocreo on the Ouya?

I bought a copy and no longer have access to it after the server shutdown

Chance Crane, 2019-08-22 on Twitter

@SquareEnixFR @SquareEnixMtl @SquareEnix @SquareEnixUSA

After #ouya shutdown, How can I keep playing Final Fantasy 3 as I bought it and the DRM now keeps me off ? Thanks.

LC, 2019-07-27 on Twitter

A long while back, I bought the Final Fantasy 3 remake on the Ouya. I really enjoyed it and got all the way up to the final dungeon. Things happened and I wasn't able to play it for a long time.

Then Razer shut down the Ouya servers and the game stopped working.

E. Zachary Knight 2019-12-02 on Twitter

I did buy Babylonian Twins and that one also went back to demo mode.

The shutdown casualty list thread on the OUYA Forum lists many games that reverted back to demo mode.

Nice developers

Some developers were very gracious and published a final game update before the store shut down that removed the DRM code and made the game fully free to play.

List of games I know got a final unlock release:

I'm very thankful for them doing that.

Other developers could not do that for various reasons. I contacted the developers of Bloo Kid 2. They would like to have helped me, but the machine that was used to develop and compile Bloo Kid 2 for Android/OUYA crashed and could not be restored :/

Purchases

OUYA's own Purchasing documentation describes how purchases happen on the OUYA:

  1. Game starts up and fetches previous purchases (receipts) from the store
  2. If the game has not yet been bought and the user clicks "buy", a purchase request is sent to the server. The server responds with yes/no and the game unlocks from demo to full version. The purchase is stored on the server and added to the list of receipts.

Encryption

OUYA's creators wanted to make it very hard to tamper with the purchase process. Purchase requests are sent encrypted to the server, and receipt responses are encrypted twice.

For that they needed two kind of key pairs:

Gamer key
Upon registration, the user's OUYA generates a private and a public RSA key. It sends the public key to the server that stores it.
Developer key (game key)
When a game is registered in the developer portal, a private key is generated for this game, and the developer gets the public key. It will be compiled into the game.

When buying a game, the purchase request is AES-encrypted. The AES key itself is encrypted with the game's public key. The store server has the private game key and can decrypt it.

The receipt list is encrypted twice: Data themselves are encrypted with the public gamer key, and the console has the private key to decrypt it. The second "inner" encryption was made with the private developer/game key, and the in-game public key is used to decrypt it (that is reverse to what private and public keys are normally used, but it works somehow).

The problem for my own OUYA server is that I do not possess the private keys of all of the 1200 games. I am not able to decrypt the purchase requests, and not able to encrypt the receipt lists in a way that the game can decrypt them.

Patching

I might not able to break purchasing, but I could unlock the individual games.

Bloo Kid 2

Bloo Kid 2 was the first game I tried. I already knew where to look for and modified isFullVersion in the smali code to always return true. Then I re-compiled the smali code, created the .apk and signed it.

But now I had the problem that my signature was different from the original signature, and Android refused to install the new game version over the old one. Even uninstalling the game while keeping the data (pm uninstall -k) did not work; Android refused to install the modified game with the new signature as long as it had data for the original signature :/

This would mean that people would lose all their progress and settings.

Comment by Jesús Higueras: At least on regular Android devices you can run pm uninstall -k and then restart the device. The data will still be there but the signature will no longer be cached, so you'll be able to install your modified version on top without losing data.

Babylonian Twins

Each game has a "purchase success" and an equal "purchase failure" handler. My idea was that upon game start, I would call the purchase success code with the right product key and be done with it.

I did that, and the game crashed - inside the C code that I could not inspect so easily. I even installed Ghidra to be able to look into the C code.

It took me three evenings to get the game to the point that it actually worked. The solution was to call the purchase success method from the purchase failure handler :) When calling it directly on startup, some things in the C code were not yet initialized and that caused the crash.

Here again I faced the impossible-to-upgrade and the keep-my-savegames problem.

I stopped the work because patching individual games does not scale.

Nocryption

The OUYA saviors very early had the idea to use Xposed to overwrite OuyaEncryptionHelper methods and prevent them from doing any encryption/decryption.

Unfortunately this helper is compiled into every application, and more often than not obfuscated with methods names like a.a.a.d.c. We would need a list that mapped that class name for each of the games, which would mean a lot of manual work.

While reading through the decompiled OUYA Framework source code and the game-specific implementations I saw something:

Cipher instance = Cipher.getInstance("AES/CBC/PKCS5Padding");
instance.init(2, secretKeySpec, ivParameterSpec);
receipts = new JSONObject(new String(instance.doFinal(decode), "UTF-8"));

The framework and every game used Java's Cipher.doFinal(byte[] input) to actually execute the encryption or decryption operation. If it was possible to let doFinal() return the input bytes unmodified, then my server would get plain text purchase requests and could return plain text receipts!

It took a whole day of installing Xposed on the OUYA, learning how to build an Xposed module and write a pre-execution hook for Cipher.doFinal. The actual code is disappointing:

XposedHelpers.findAndHookMethod(Cipher.class, "doFinal", byte[].class, new XC_MethodHook() {
    @Override
    protected void beforeHookedMethod(MethodHookParam param) {
        byte[] input = (byte[]) param.args[0];
        param.setResult(input);
    }
});

The result was this:

Bloo Kid 2: Main menu Bloo Kid 2: Purchase confirmation Bloo Kid 2: Thanks for supporting winterworks GmbH! "Purchased" in OUYA's system menu

And all this without modifying the game apk itself! The savegames are safe!

How to use

Using my "plain-purchases" xposed module currently takes a bit of work:

  1. Follow the Root the OUYA instructions until you have the following:

    1. SuperSU (required by Xposed installer)
    2. Xposed installer with activated Xposed framework

    Do not install ModCollection nor Google Play.

  2. Download and install my ouya-plain-purchases xposed module.
  3. Activate it in the Xposed installer by going to "Modules" and then use the touchpad to click the checkbox that activates the plain purchases module. The controller buttons cannot be used to activate the module.
  4. Reboot
  5. Configure your OUYA to use my server or Devin's server.

Xposed module "OUYA plain purchases"

You may now enjoy all your OUYA games in their full glory again, half a year after the official server shutdown.

Takedown!

If you are a game developer and do not want your game unlocked on the couple of dozen OUYAs that are left on the world, send me an e-mail and I will remove the purchase receipt from my server. The game will then fall back to demo mode on all OUYAs.

Also on: Twitter, ouya.world.

Written by Christian Weiske.

Comments? Please send an e-mail.