How To Protect Your Game From Being Rebranded

We’ve been hearing a lot of complaints recently about game “rebranding theft” — where unscrupulous websites hack your newly-released game and change your sponsor splash screen, logo, and other identifying assets. This practice is mostly confined to a few countries, especially Chinese portals, and has been happening for years, but it seems to be growing more common.

This amounts to game theft, of course, and it goes completely against the sponsorship model. It’s also quite illegal to modify and redistribute a copyrighted game like this… which is why it is less common in the US, where a sponsor could easily sue another portal for such behavior. But for portals operated in other countries, it can be difficult to take legal action against them.

But you, the developer, can take action! It is actually pretty easy to protect your game from being rebranded. First, you need to know a bit about SWF files.

SWF Format Makes Image Changing Easy

The SWF file format is an open format, well documented by Adobe itself [pdf]. SWF files are made up of little individual chunks, kind of like how a .ZIP file is made up of lots of files. Your pictures are each stored as separate chunks in the file.

Much as you can unzip a .zip file, you can unzip a SWF into its parts. Then you can change some parts (such as the images) and zip it all back into a SWF again. (I’m simplifying a lot, of course — it’s more complicated than the .ZIP file format, but the idea is very much the same!) Your images, your sounds, your shapes, and your code are all stored as separate little units inside the file.

This isn’t a flaw in the SWF format — it’s a feature! Adobe has made the format quite easy to use so that it can be read and manipulated by anybody. The convenience of this format is why there are so many great tools and languages for Flash. But it has a down side, too… it means it’s easy for somebody to replace your images with their own. There are tons of very good tools that can break your SWF down into parts and then put it back together again, with new images included.

Encryption Tools Protect Source Code, Not Images…

You may be wondering, “Well then, what do the various SWF encryptors do?” These don’t encrypt your images. They encrypt your code. If we use the zip-file analogy again, your compiled AS2 or AS3 source code is stored in the SWF file as separate chunks, completely isolated from the images and sounds and so on. What encryptors like Kindisoft do is munge those particular “code” chunks so that they are much harder for human beings to figure out.

But they don’t protect your images… since those are just stored directly as JPEGs, there isn’t much that can be “encrypted” about them. If an encryptor changed the image data, the Flash player wouldn’t know how to read the file!

… So Use Your Code To Protect Your Images

So if only code is protected, how do you protect your images? You write code that verifies your images are what you expect! Then you take advantage of Kindisoft or another code-encryptor to make sure that malicious users can’t remove your code checks.

But how does your code know if the image is right? What we need are “checksums” — a small value that mathematically represents a larger data unit. You may have heard of MD5 or SHA1 checksums… same idea. But there are actually tons of ways to checksum something. Here’s the simplest (and hence, fastest-to-calculate) checksum:

function checksum_Basic(bmp:BitmapData):uint
{
var bounds:Rectangle = new Rectangle(0, 0, bmp.width, bmp.height);
var bytes:ByteArray = bmp.getPixels(bounds);
var total:uint = 0;
for (var loop:uint = 0; loop < bytes.length; ++loop)
{
total += bytes[loop];
}
return total;
}

This function just loops over every pixel in your image, and adds all the RGB values of every pixel together. This results in a number. If the image changes, the number will change, too. Tada! Now your game just needs to check your images at runtime to make sure that it calculates the same number that you calculated originally. If the number’s not what you expected, the image was changed.

First, write a little throw-away program to find out the checksum numbers for the image(s) you want to protect. Assuming you have a DisplayObject or Image control named “picture”, this is how you call the above function on it:

var bitmapData:BitmapData = new BitmapData(picture.width, picture.height);
bitmapData.draw(picture, new Matrix());
trace("This image's checksum is " + checksum_Basic(bitmapData));

Now you should see something like this in your trace output window: “This image’s checksum is 4921452″. Collect these numbers for each image you want to protect, and then copy them into your actual game. In your game, you call the same function and just check against those numbers:

var bitmapData:BitmapData = new BitmapData(picture.width, picture.height);
bitmapData.draw(picture, new Matrix());
if (checksum_Basic(bitmapData) != 4921452)
{
// do something, we've been hacked!
}

Repeat this process for each image. (Make sure the images are fully loaded before you do this!)

If your game detects that it’s been hacked, it should display a polite message and then shut down. Warning: Always be polite in these sorts of messages; never do anything unprofessional. Remember that anything you do on the internet will eventually be taken out of context! It may sound funny to show a picture of the goatse guy when you’re hacked, but somehow, somewhere, that gag is going to backfire on you. Just show a polite message and make the game stop working.

Be Double Secure – Use Two Checksums Together

The above method is all you need to protect your game from having other images stuck into it. But the checksum function I used above is mathematically pretty weak. If a hacker was willing to try enough different pictures, they would find one that has the same number as your picture. It’s probably not worth their trouble, but you never know how determined they’re going to be.

So since we’re feeling paranoid, let’s double it up with a second checksum! We’ll use the well-known SHA256 algorithm. Why? Because it’s very secure… and also because it’s easy to get ahold of! No math is required on our part. If you’re using Flex, then it’s built right in:

import mx.utils.SHA256;
function checksum_Flex(bmp:BitmapData):String
{
var bounds:Rectangle = new Rectangle(0, 0, bmp.width, bmp.height);
var bytes:ByteArray = bmp.getPixels(bounds);
return SHA256.computeDigest(bytes);
}

Or if you aren’t using Flex, you can download the source of the AS3 Core Lib, drop that into your project folder, and use the SHA256 function that comes with that, instead:

import com.adobe.crypto.SHA256;
function checksum_AS3CoreLib(bmp:BitmapData):String
{
var bounds:Rectangle = new Rectangle(0, 0, bmp.width, bmp.height);
var bytes:ByteArray = bmp.getPixels(bounds);
return SHA256.hashBytes(bytes);
}

These functions work exactly like checksum_Basic above, except they return a string like “ce68f9ebff02e8019702a3b4bc8d93535ffcf6b4844f24c0cf37e93bb871b97b” instead of a number. So you just collect those strings and then plug them into your program, same as above. If a picture has a different string at runtime, then it’s obviously changed!

You may wonder, why use both? Why not just use the string function, since it’s harder to trick? The answer is very pragmatic: it turns out that the SWF file format stores all the strings in your game together in little bundles, separate from the code. So even if your code is encrypted, a hacker can sometimes still see and change your string literals! (Kindisoft’s encryptor has a mode that encrypts strings as well as code, but other encryptors don’t.) So a savvy hacker could look for any string that looks like a checksum value, and replace it with the checksum of their own new image, fooling your code. It would be tedious, especially if you have a bunch of images with different checksums — they’d have to experiment to figure out which checksum went with which picture. But it doesn’t pay to underestimate the patience of game thieves.

It’s much harder to track down integer values, especially if you use a lot of constants in your program. Using both a string and an integer at the same time makes it quite difficult to trick your app.

That is, unless you don’t use an encryptor! Remember, this only works if you encrypt your code. If you don’t, then all of this was a waste of time, because thieves can just view your code, see exactly what you did, and remove all those if-statements! If you still haven’t bought an encryptor, do so — it’s a necessary investment. FGL’s encryptor of choice is Kindisoft’s secureSwf product — in our tests, this is much more effective than the other encryptors we tested. It’s also quite reasonably priced for FGL members, as Kindisoft has provided us with a special coupon code for FGL users.

Finally, Beware The Cheap Trick of Moving Your Image Off-Screen!

The way the SWF file format works is both a blessing and a curse. Well, for game devs trying to keep their games safe, it’s mostly a curse. Case in point: even if you protect your images as described above, hackers may still be able to remove your branding! How? By moving it off the screen! If you use the Flash development IDE and place the image on a MovieClip frame, then that frame data gets stored separately from your code. As explained above, only your code is encrypted… so a clever hacker can simply change the x,y coordinates of your image so they’re off the screen, or shrink the width and height to be 1 pixel in size!

If you’ve placed your logo and splash screen on frames in Flash, you should write code that makes sure the images are where you intended them to be. If the picture’s supposed to be at 0, 0, and 640×480 wide (or whatever), your game code should make sure it’s where it’s supposed to be!

If you code directly in pure AS3, or if you use Flex Builder, Alchemy, or haXe, you aren’t susceptible to this problem because your code is what positions the images. The only games that are susceptible to having their images moved off-screen are the ones written directly in Flash player, when the image is placed directly onto a frame.

EDIT: pjbaron pointed out that there are more variables that can be adjusted: alpha should be 1.0, visible should be true, and scaleX and scaleY should be the values you expect them to be. Hmm, this is a lot of variables to validate!

EDIT #2: Rocketman had another approach: use checksums on your fully-rendered splash screens, instead of just the splash screen images. This is easy to do — just dump the entire stage to a BitmapData, get the checksum of it, and use that checksum as described above. If your stage’s checksum changes from what you expected, then something on the stage has gotten moved around somehow.

EDIT #3: But that idea doesn’t work too great because if your game gets resized on some portal, the fully-rendered splash screen checksum will come out wrong. So I don’t recommend that plan after all.

EDIT #4: My current “best recommendation” is to simply not put important branding like splash screens on a movieclip frame at all… in other words, don’t place them on the screen in the Flash IDE. Instead, write some ActionScript code on that frame that creates the image and adds it to the stage or movieclip via addChild(). That way you bypass all of the nonsense about the variables getting manipulated, and it’s much harder to screw up unintentionally.

AS2 Users… All Of This Applies To You, Too!

Unfortunately, I don’t know how to code in AS2… at least, not well enough to make blog examples for it! But the same ideas described here apply for you, too.

AS2 has a BitmapData object also, but it doesn’t have a way to dump all of its pixels at once, so you’ll need to use BitmapData.getPixel() to get each pixel out of your image and add it to your checksum. This method will be much slower than the AS3 version, so you may not be able to do it to all the images in a large game — it might be noticeably slow — so just pick the ones that really matter!

Hopefully a savvier AS2 blogger will pick this up and provide good examples for you to work from.

So there you have it! You can protect your games from being illegally rebranded with less than an hour’s work. Definitely worth the effort to keep your sponsor logo and game branding visible.

13 Responses to “How To Protect Your Game From Being Rebranded”

  1. great post, very informative

  2. [...] (AS2) Leave a comment » Eric Heimburg from FlashGameLicense.com wrote an article aboutHow to protect your game from beeing rebranded for Actionscript3. Because i’m developing flash-based-games here and there i found this [...]

  3. Lots of good tips, thanks! But this one got me wondering:

    “EDIT CONTINUED: Rocketman had another approach: use checksums on your fully-rendered splash screens, instead of just the splash screen images. This is easy to do — just dump the entire stage to a BitmapData, get the checksum of it, and use that checksum as described above. If your stage’s checksum changes from what you expected, then something on the stage has gotten moved around somehow.”

    What if the renderer changes just a little due to optimizations? Or if the player changes the quality setting?

  4. ttursas – that is a good point. A more common concern is if some site that is hosting your game displays it in the wrong width and height. So I think in retrospect that plan won’t work very well.

    My current “best recommendation” is to just not put your splash screens on a movieclip frame at all… instead, put some ActionScript code on that frame that creates the image and adds it via addChild() to the scene. That way you bypass all of the nonsense about the variables getting muddled, and it’s much harder to screw up unintentionally.

  5. Very good article. I’m wondering the checksum only worked if someone try to replace the picture on your game but it cannot prevent people decompile your swf and rip your image for use in their own code right?
    i’m kinda interested for having a encryptor, but theres so many out there and some people tell me some of them is not very secure because many games seen to be rebranded even they have been encrypted with those encryptor.

  6. Have you ever thought about that no matter how nifty your checksum algorithms are, the hacker can simply bypass the if-statement that checks the checksum?

  7. blacksugar – right, this will not protect people from stealing your artwork. Only from editing your SWF with their artwork. If you are looking at encryptors, check out http://blog.swfdecrypt.com/, the blog there talks about which encryptors are useless. That blog recommends SecureSWF and IrrFuscator as the only “real” encryption programs. We use SecureSWF on FlashGameLicense.com.

    nook – yes, that was a big part of the blog post, and I discussed what to do about that problem. Hint: it involves using something that makes it hard to remove if-statements.

  8. Ah yes, you did mentioned it. But I meant even with an encrypted SWF, it would probably easier to find the if-statements rather than faking the checksums. But that’s just a guess.

  9. nook – it depends on the type of checksum. As I mentioned in the article, string-based checksums can often be hacked more easily than if-statements.

    But anyway, it’s always going to be possible to hack the game. Even AAA games written by huge teams get hacked. But you can make it quite difficult and tedious to hack your game, which will dissuade portals from bothering. The blog post shows how to use several different checksums AT THE SAME TIME. Ideally you would call them in separate parts of the game. When combined with a good obfuscator, this makes hacking your game much harder, and hopefully not worth the trouble.

  10. [...] How To Protect Your Game From Being Rebranded by flashGameLicense  #flash #gamedev #security [...]

  11. Ultimately it’s always possible to get into the files: whatever Flash Player can do to read and execute your SWF a dedicated hacker can do also. This includes decoding the ABC code and extracting media, and since the spec is open they can put it back together again.

    You can only make it harder and more time consuming, so much that it’s not worth their time to do hack your stuff. SWF encrypting is a good tool to use, and so is wrapping your application and assets in different layers and schemes of encoding.

    Something you can also do: using [EMBED] metadata to embed the bytes of a SWF (or your sponsor image) into the SWF, and load these (using Loader.loadBytes). This will hide your code from de-compiler because they cannot see it as a SWF with ABC tags but as a solid chunk of ByteArrayAsset and the bit of code you use to decode it and add to the stage.

    You should get creative with this and layer the concept a few times, and it’s even better to chunk your actual SWF into pieces (with a bit of PHP or AIR or something to generate encrypted chunks and the actionscript), then add a bit of clever AS and compile it again. Then repeat this a few times (don’t forget to swfprotect each layer).

    If the bad guys get through the outer layer of encryption and pieced together the wrapped SWF-bytes, only to discover it was not yet the game, but just another encrypted hell of unreadable actionscript and bits and pieces of files all over.

  12. Just some random idea, I knowthey do it in some other fields: maybe it’s cool for FGL to do a sort of security vs hacking competition? Where Blue teams can submit applications, and Red teams can try to get into them? If you play it right you can collaborate with Adobe, Kindi or some high-profile sites like Kongregate or ArmorGames for a bit of sponsoring, exposure and whatnot.

  13. I know this is a really old post, but I read it a few days ago and then now I had some Fridge Logic hit in.

    So you worry that the SHA256 checksums aren’t enough, because it is easy to change the string literals. But then why don’t you store the checksums in a ByteArray? The SHA256 checksum is actually just that – though most times it’s represented as a character string of hexadecimal numbers. But it can just be represented as an array of bytes, and then you won’t have the string literal in the code.

    Does Adobe’s function only handle strings? Write a conversion function. But of course you should never supply the checksum in string representation in the source code – you define a static ByteArray and then you convert it to string at runtime to compare it with the SHA256 function’s output.

RSS feed for comments on this post. - TrackBack URL

Leave a Reply

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