How can i protect my swf from decompilers?
Simple answer would be:
you can try but it will probably fail, so don't.
A more elaborated answer would be:
you can try but it is unlikely to cover 100% of the cases and it will take a lot of efforts.
It's not impossible but it will really take a lot of hard work and unlikely to block 100% of all the "vilains".
Simply put, it's a whack-a-mole game and there is no silver bullet or other "magic solution" at the click of a button.
Still, you can make it really really hard for someone to decompile your SWF,
but don't fool yourself there is a cost: the time and involvement it takes.
What do you try to protect and why ?
If it's about the source code itself, is it about running the code or reading the code ?
Is it about you users security ? server security ? both ?
Is it about some secret algorithm or very unique way of doing things you think you have ?
Do you try to prevent a copy and paste clone of you game on some shady server ?
There are many things you can try to protect, some are easy some much harder.
So before going into a long development process to do this or that, first define what you try to protect.
I published a game on domain.com and I don't want some 3rd party to easily copy the game.swf on their own other domain.com
I published a game.swf and I don't want users to submit a hacked score
- as soon as you publish something online
it is publicly accessible by anyone
- either by a path on your server
- either in the browser cache
there are plenty of tools and browser add ons to extract SWF from the cache
- either from memory
even if the SWF was not cached you can
retrieve it from memory
- a SWF file is structured in such a way
that you can easily reverse it (from binary)
to source code (or pseudo code)
Technically, with just that you can imagine it not gonna be easy to protect a SWF from decompilation.
The case of obfuscation
Obfuscating is the principle of changing/renaming variables name and other definitions before (or after) compiling the source code.
The logic is: even if the code is decompiled it will then be really hard to read.
Some obfuscates claim they can obfuscate in such a way that the source can not be decompiled with some tricks, it can happen but see that as a temporary solution, again this is not 100% safe.
First, an obfuscator does not prevent the code to be decompiled it just make it less readable,
so as long as you can actually see the code logic, even if it's very hard to read it, it is not impossible
to retrieve the code.
Second, an obfuscator modify either your source code or the SWF binary and so could inject
any code it wants, and that could be much much worst than having your code decompiled.
Especially with an obfuscator that is closed source, you have no way to know what's going on,
what is modified or how, and so it could be used to inject malware in your SWF or advertising links,
and other tracking and nasty stuff.
Third, because the obfuscation modify the original code it can introduce instability.
For example, the normal SWF would work fine but the obfuscated SWF would crash and other niceties like that.
My advice: stay away from obfuscator unless they are from a high professional quality (which I had never seen in the Flash world, maybe with .NET and Java but not AS3).
So What do we do then?
Learn how the browser cache is working.
The very way to make a SWF not decompilable is to not give access to the SWF file in the first place.
The basic way to do that is
- use HTTP 1.1
- prevent HTTP caching
- use HTTPS
- load a shim.swf that load an encrypted child.swf
- the shim.swf decrypt the child.swf based on a "key"
We want to ban HTTP 1.0 as it allows to work around some caching and non-caching mechanism.
Also, we want to sniff the user-agent to block by default some old browser like IE6;
and yeah user-agent can be spoofed, but in our case it will work e.g..
- we do not want IE6 to cache the page
- so we block user-agent that identify as IE6
- IE6 has no way to fake its user-agent
- so we will effectively block IE6
But in fact there is an even better way: use HTTPS
depending on the cypher suite you use server-side some old browser
will be excluded and among them IE6
(someone can hack the registry, spoof the user-agent all they want)
see TLS/SSL support history of web browsers.
By enforcing the use of HTTP 1.1, HTTPS and a somewhat recent browser version
we can then control how the browser caching works.
In short you want the following HTTP headers
Cache-Control: no-cache, no-store, must-revalidate
But wait... that's only the beginning: HTTP/1.1, HTTPS with a modern cypher suite that enforce modern browsers.
The thing is you have also something else than browsers than can access a web page: robots, crawlers, spiders etc.
So before even the caching, you should prevent the downloading part.
If a user can simply do a
$ curl -X GET http://www.domain.com/files.swf
it is basically game over.
so we gonna use JS to filter out any cURL, wget and other robots crawler.
And at the same time, we gonna enforce the HTTP referrer, to be sure another site can not embed our HTML page with an iframe, and other little tricks like that.
Here how it works:
- the server deliver an HTML page that is almost empty
- but at the same time the server created a user session
which create user cookie with a unique value (HTTPS only)
- in this web page you use the "double submission of cookies" technique
to validate the referrer but also to send an HXR request to fetch
- from that the shim.swf load an encrypted child.swf
encrypted with a private key associated with the user session
- also you make it in such a way that if the user refresh the page
the unique session id change and so the private key have to change too
- that way the child.swf is always encrypted with a different private key
- now the tricky part is to compile the shim.swf "on the fly" with that key
to load an external binary on the stage
Loader.load() to load the encrypted SWF
- then use the key to decrypt the SWF
- finally use
Loader.loadBytes() to load the ByteArray in memory
Wait, we are not done yet, all the above could maybe block 99% of "vilains"
but even if there is no cache or file around an attacker can still scan and inspect the memory
to find out the unencrypted SWF data and dump it to a clean SWF file.
Well ... not yet .
Now, we gonna move some components of our client-side SWF to the server-side,
and keep some key logic purely server-side, the client will get the output it needs
but the code will stay resident on the server-side, and that is bullet proof.
So, yeah it's hard to implement, but it is also remotely impossible to crack,
here what we got for us so far
- the data stream goes trough HTTPS
so any client-request can not be spoofed
- but also we have a special unique id combined with a private token
all that in our user session
- that means we can sent request we from the client
that we can validate from the server-side
- whether you use a REST API, AMF, etc.
the request can be validated
simply take all your parameters and create a checksum
with you private key (a bit like OAuth validation)
Now, is the hard part: choosing the "logic" you want to delegate to the server,
is it a game ? is it an app ? etc., it will be a different choice for what actually happen in SWF.
Remember what I said at the beginning
What do you try to protect and why ?
If it was super easy to just protect a SWF everyone would just check the option "protect" for anything and everything.
But it is quite hard, take lot of resources (that could be used to actually program the app or game) and finally is it worth it ?
So, I'll take a recent personal app as an example: a client-server chat app.
Here what I need to protect
- the user data
for that I use HTTPS and Secure Socket
so the text one user send to another user can not be intercepted
- the user login/password
again HTTPS and Secure Socket
and depending where the app is running a save in Encrypted Local Storage
if the user does not want to re-enter his/her credential all the time
- protecting the SWF file ?
I could not care less
go ahead take it decompile it, have fun
- you will not be able to inject admin commands
because those are validated and verified server-side
you can try to spoof them but it will fail "by default"
- you can not impersonate another user
again validated and verified server-side
- you can not spy on other users private conversations
again the server decide to which user the messages are dispatched
you would have to impersonate another user to receive his/her message
and you can't do that
- oh you want to cheat at this little multi-player game?
sorry you can't, the server keep in-memory the game session
and validate the score every step of the way and so will know
if you try to submit a score that is way too high
I don't need to protect the SWF because the whole logic is already server-side,
the chat client is just that a client, there are some logic like building/interpreting commands
but those are harmless as the real data is stored server-side, for example:
to get the user list in a room, you send a command
not only the command can be locked to only "admin" role but also
can be allowed to only those who are actually in the room and that only the server knows,
and tons of things like that.
OK that example is a very specific one but again ask yourself why you want to protect a SWF,
in most case is the basic "reflex" "oh I want to keep my stuff private I'm so afraid they gonna steal my code from me" when in most case nobody cares.
And yeah there are other specific cases like games, if you have experienced your game being cloned and republished some other place, yeah I can understand you really don't want that to happen.
The thing is there are no easy way to protect a SWF, yeah I show a little above how it is possible, but even then it is not 100% sure nobody will ever be able to crack it, maybe 99% but certainly not 100%.
So think of it like that: what is harder and take more resources ?
- build a special limited SWF for online promo
that does not contain all the codes, assets, levels of the full game
- spend hours if not weeks in building online SWF protection
for the full game published online
I would say "the special limited SWF" is the way to go.
Now, you may be in a case where you really have to publish the full game as an online SWF
and still with that you have numerous choices you can make
- force a user registration to access the full game
- sequence the assets and game logic in such a way
that you have to actually beat the game to get all the assets of all the levels
(just that can be more effective that protecting the SWF, because it takes time)
- only allow a limited demo online
registered users can download the full game to play on the desktop
eg. you can automate the build of the desktop app with a fingerprint related to the user
and if the game is leaked you will know which user did it
All those things, even if they look complicated, are less complicated than protecting the online SWF.