A few weeks ago, some friends of mine started playing a Facebook game, Puzzle Adventures. This is a (pretty fun) jigsaw puzzle game, so I played a few levels at some point. The game limits you significantly in many areas (e.g. you can only play three or four games before you have to wait for minutes to play more, or pay). The game is also geared against you in that the time limits are pretty tight, but what irked me the most was that the puzzle pieces don’t snap together unless you get them really really close to each other, which is just a tactic for you to lose time, and isn’t fair.
Another fact that really annoys me is that I suck at jigsaw puzzle games, so my friends were beating me pretty handily. However, I am pretty handy with them computers, so I figured I’d have a look at the Flash binary and see if I can change anything to my benefit.
My exploration of the game’s internals follows.
Examining the server calls
After a short look at the server responses, it became clear that that wasn’t a way to go. Although the responses were trivial to change, the game synced everything to the server before and after every level, and if something wasn’t proper, the game produced an error. For example, I couldn’t give myself more hearts or boosts or anything, as the game told the server about this after the level, and the server knew I wasn’t supposed to have any hearts, so it didn’t count the level.
Not only that, but the game sent the actual moves in the level to the server, so that was another place where attack wasn’t feasible. I decided that it would be much simpler to change a local game mechanic instead.
Decompiling the flash file
Luckily, a friend of mine does some Flash work, and he owns a copy of Sothink Flash decompiler, a most excellent piece of software. I got a copy of the source code and started looking around for things I could do. I decided that changing the annoying snapping distance would be the easiest and most reasonable thing to do, so I searched for “snap”:
Sure enough, the constant SNAPPING_DISTANCE_MUTIPLIER above looks to be exactly what I need. Now, all I need to do is change it, which should be simple enough!
Apparently, it’s not that simple. Compiling the Flash binary again from the decompiled sources rarely succeeds (or so my friend told me), and, at any rate, I don’t own a copy of Flash, nor is it even available for Linux. The only thing that can be done is finding the constant in the Flash file and editing it with a hex editor.
Finding the constant
Editing the constant should also be pretty straightforward, all we need to do is find potential locations of the number “1.15” above and change it. However, it turns out that some flash binaries (including, unfortunately, the one I’m analyzing) are compressed, so trying to find the constant in the compressed binary will not yield any useful results. I need to decompress the file.
Decompressing the binary
As it turns out, Flash binaries are compressed very simply. All one needs to do is read the magic bytes (“CWS”, if the file is compressed) and the next 5 bytes, and then decompress the rest with zlib. Here’s a very simple Python script that decompresses compressed Flash files:
import zlib
infile = open("test.swf", "rb")
infile.seek(0, 0)
if infile.read(3) == "CWS":
data = "FWS" + infile.read(5) + zlib.decompress(infile.read())
open("decompressed.swf", "wb").write(data)
Our Flash binary is now decompressed, and we can look for the number.
Finding the constant (again)
Great, we are now ready to find the constant, but what’s the representation of a decimal in a Flash binary? Well, as it turns out, it’s stored as a little-endian IEEE 754 64-bit float (or, double).
Converting 1.15 to double, we get “333333333333c33f” in hex. Using the excellent Bless hex editor, and we can change it to, say, 2, which is “0000000000000040” and save. All done! To make sure, I can send the binary to my friend to decompile again, but I was pretty sure that was the right place so I skipped that step.
Is that all? Not quite, because now we need to override the remote swf with the local, edited one.
Replacing the remote swf with the local one
To do that, I used the excellent debugging proxy, Charles. After setting it up and loading the game, Charles shows the swf request, at which point we can override it by right-clicking on it and clicking “map to local”. Selecting the file, all is done!
Launching the replaced game, everything works normally, which is always a good sign. Playing a level, I see that pieces snap to each other from a fairly larger distance, so the change works! Finally, I can play without the trackpad messing my game up, and the game is now much fairer and more enjoyable.
And that’s how you win at Puzzle Adventures!