Hack 99 Make Your SWF Phone Home

figs/moderate.gif figs/hack99.gif

Protect your content from being displayed anywhere but on your site?make it location-dependent.

If a cracker can find your SWF file [Hack #98], before decompiling your work [Hack #97], he will most likely try to run your SWF from his local machine to see what it does. The Flash Player prohibition against loading content from other domains merely forces a cracker to change all the URLs in the SWF (which is the first thing he would do to repurpose your site with minimum modification).

By making your SWF run only if it finds itself in the expected place (i.e., on your server), you make sure the SWF cannot be run (or easily repurposed) without the cracker spending some time trying to break your protection.

The MovieClip._url property tells a SWF where it is being run from. Using this property, your code can check whether the SWF is being run from the correct location on the Web, namely your domain, or whether it is being run locally (which is one indication that someone is trying to repurpose some or all of your SWF). For example, if you use the following code:

var myLocation = this._url;

the myLocation variable stores a URL if the SWF is accessed from the Web (e.g., "http://www.futuremedia.org.uk/test/test.swf") or a local file path if it is viewed locally (e.g., "file://C:\Documents and Settings\Sham B\Desktop\test.swf"). If myLocation doesn't contain the expected location, you can take appropriate defensive action.

Cause the SWF to Fail

If the Flash Player detects a loop that carries on for a large number of iterations lasting more than 15 seconds, it will stop executing scripts (or issue a warning and give you the option to exit if you are testing a movie within the Flash authoring environment). The following code causes the SWF to enter an infinite loop if it finds itself being run from unfamiliar territory:

myLocation = this._url;

if (myLocation != "http://www.futuremedia.org.uk/test/test.swf") {

  do {

    // This infinite loop will hang up the Player

  } while (true);

}

This disabling code will cause the cracker some trouble in working out what the SWF does. You can obscure it even further by inserting long delays that do not cause the warning dialog but still make the SWF seem hung up. Here we execute a delaying function every millisecond:

myLocation = this._url;

if (myLocation != "http://www.futuremedia.org.uk/test/test.swf") {

  // Invoke our delaying function every millisecond

  setInterval (delayMe, 1);

}

function delayMe ( ) {

  // Perform 10,000 calculations just to slow the Player down

  for (var i = 0; i < 10000; i++) {

    x = Math.random( );

  }

}

Jump to Your Home Site

You can use getURL( ) to jump to your site if the SWF is being run from the incorrect location. The cracker, noticing that the SWF keeps launching your site, will likely assume you are using getURL( ) to go to a different URL. So he will search for the URL string (using something like URL Action Editor, http://buraks.com/uae), although it will still take him time to work it out. To make it harder for the cracker, you can write the code so that it jumps to a new URL only occasionally, such as "If I find myself in an unfamiliar place and it is Thursday, jump to Sham's home site via getURL( )." The cracker will be thinking that he has gotten away with his crime until Thursday comes along. If you want to be really nasty, you can have it jump to a pornography site or something likely to get him in hot water with the client.

The following code jumps to http://www.futuremedia.org.uk/test/test.swf (not a porn site) if the current SWF is not located at that URL and the day is Thursday (4 is the code for Thursday when using the Date.getDay( ) method). Notice the cryptic variable names. Ideally, p, q, r, and s should be defined elsewhere to further obfuscate what is happening.

var p:String = this._url;

var q:String = "http://www.futuremedia.org.uk/test/test.swf";

var r:Date = new Date( );

var s:Number = 4;

if (r.getDay( ) == s) {

  if (p != q) {

    getURL(q);

  }

}

Use Cross-Protection

It's easier for the cracker to work on a single file than it is for him to work on a site that is divided into a number of SWFs, particularly if you have also given dummy names to some of your SWFs [Hack #98] and made them all location-dependent. Also worth considering is placing your protection code in a SWF other than the one it is actually protecting (I call this cross-protection). For example, place the following code in a SWF loaded in by the main SWF:

myLocation = _level0._url;

if (myLocation != "http://www.futuremedia.org.uk/test/test.swf") {

  do {

  } while (true);

}

The protection scheme can appear in a SWF that the cracker is not likely to want (e.g., place it in a SWF containing content rather than the main SWF containing your oh-so-cool UI, so he won't find it easily).

Using setInterval( ) to run the protection code (rather than running it as soon as the SWF loads) makes locating the protection code much harder for the cracker because he will not be able to deduce which loaded SWF contains the protective payload. For example:

function test( ) {

  clearInterval(m);

  var myLocation:String = _level0._url;

  if (myLocation != "http://www.futuremedia.org.uk/test/test.swf") {

    do {

      } while (true);

  }

}

var m:Number = setInterval(test, 30000);

You can add the protection scheme at the end of your development cycle, leaving yourself to develop the protection-free main SWF in peace.

Final Thoughts

As soon as SWF decompilers became available, a spate of copycat sites and example FLAs that looked suspiciously familiar to previously unpublished code appeared. Take steps to prevent your carefully created work from being paraded where it shouldn't be!

Flash developers often ask how to protect themselves from clients who fail to pay after receiving all deliverables. Withholding the source FLA files until final payment is received is a common approach (the client gets the SWF to post to his site but the developer maintains some leverage by withholding the FLA). You can't use the phone home trick to disable the SWF in such a case because the SWF is supposed to run from the client site, but you can put an XML file on a remote server over which you (the developer) has control. The Flash movie (on the client's server) should check the remote XML file each time it initialized. This gives the developer the ability to "turn off" the application by setting an appropriate flag in the XML file if the client doesn't pay on the agreed schedule. However, such validation schemes may be contrary to your development contract and can get you in hot water if they malfunction. For example, if the SWF cannot access the remote server providing the XML file (which may become inaccessible due to downtime), the default behavior should be for the SWF to work without it. Use such "time bomb" schemes with caution and be sure to deliver an unfettered version of the SWF and/or FLA once the client pays up.