Monday, April 18, 2011

Deactivate Zarqon Active License Control

Today, we tackle yet another commercial licensing system for Flash applications by reviewing the Zarqon Active License Control System from Futurescale.

While the name Zarqon may be unfamiliar to most developers, anyone who has spent some time in the field of RIA development should recognize the name Futurescale. This is the company that gave us the wildly popular and incredibly powerful PureMVC framework. PureMVC is a highly mature product and is used by developers from all over the world. The original codebase has been ported to many languages, including AS2, AS3, Java, Javascript, HaXe, C#, Coldfusion, and PHP.

The Zarqon Active License System is different from the other systems that we have reviewed by the fact that the server components (nothing more than a collection of encrypted license files) are hosted on your own Amazon S3 account. There is no server logic involved in the licensing system. The advantage is that you have complete control over your data servers and that you only have to pay Futurescale a one-time fee to purchase the licensing system.

It should be pointed out that the Zarqon licensing system is not dependent on the PureMVC framework. Yet given the fact that it is developed by the same folks at Futurescale, can we expect the same performance and reliability from Zarqon as we do from PureMVC?


If you read the Zarqon documentation carefully, you will notice that the folks at Futurescale made a strong argument on separating code protection from license control. "Zarqon is focused on facilitating license management with the simplest, and most reliable approach. The additional scope required to encrypt and/or obfuscate source code comes with a price of complexity, performance and reliability and should therefore be attended to by hardened professionals in that specific discipline." I must say this is a very refreshing, and honestly very valid, concept. Therefore, let's assume that we have found a perfect code protection mechanism, and we will try to see if we can break the licensing system WITHOUT decompiling the Zarqon library.

First, we need to get the demo application from Zarqon's website. Here is the main part of the code:

private function startup():void
{
    // Your Zarqon Key   (YOU MUST USE YOUR ZARQON LICENSE KEY HERE)
    var issuerKey:String = "ZQN-8F9579673774792FE4CA50D3D02C06D7";
    
    // The License key   (YOU MUST CREATE A PRODUCT AND ISSUE A SITE LICENSE)
    var licenseKey:String = "ZFD-E324F2E4AD83064553A98A440640E04E";

    // Create the LicenseManager     
    licenseManager = new LicenseManager( issuerKey, licenseKey );
    
    // Add Event Listeners
    licenseManager.addEventListener( LicenseManagerEvent.LICENSE_INVALID, licenseInvalid );
    licenseManager.addEventListener( LicenseManagerEvent.LICENSE_VALID, licenseValid );
    
    // Validate the License    
    licenseManager.validateLicense();
}

private function licenseInvalid( lme:LicenseManagerEvent ):void
{
    pnlLicense.status = "License Invalid!";
    lblSite.text = licenseManager.site;
}

private function licenseValid( lme:LicenseManagerEvent ):void
{
    license = lme.license;
    lblSite.text = licenseManager.site;
    pnlLicense.status = "License Valid!";
}

private function enableFeature(license:License, featureName:String):Boolean
{
    if (license == null || ! license.enabled ) {
        return false;
    } else { 
        return ( license.hasFeature(featureName) && license.getFeature(featureName).enabled );
    }
}

The Zarqon API is simple enough. All you need to do is to initialize the LicenseManager class, call the validateLicense method, and listen for the LicenseManagerEvent.

There are several tricks we can employ to bypass the LicenseManager class. For the purpose of this exercise, let's try to exploit an interesting property of the flash.system.ApplicationDomain class.

We can think of an ApplicationDomain as a storage space for class definitions inside the Flash Player. In a simple Flash application, all the class definitions should exist in the same ApplicationDomain. When you are building a larger Flash application, especially one that involves loading external SWFs into the parent SWF as modules, things can get interesting. The parent SWF has an option of loading the child SWF's class definitions into its own ApplicationDomain, or into a separate ApplicationDomain. In the latter case (separate ApplicationDomains), the parent SWF and the child SWF behave as if they are two independent Flash movies playing on the same stage. Most importantly, if the child SWF defines a class, whose name (e.g. com.hackabee.criticalClass) is identical to another class defined by the parent SWF, these two classes do NOT conflict with each other. The parent SWF can make calls to its own version of com.hackabee.criticalClass; the child SWF does the same to its own version of com.hackabee.criticalClass.

Interesting things happen when the parent SWF loads the child SWF's class definitions into its own ApplicationDomain. For some reasons, Adobe (more accurately Macromedia), has decided that the child SWF's class definitions should NOT override the parent SWF's class definition. As a result, when the child SWF tries to make a call to the com.hackabee.criticalClass class, the Flash Player will use the parent SWF's version of the com.hackabee.criticalClass class instead. I have long believed that this is a serious security bug, but Adobe (and Macromedia) has refused to fix this. Here is the problem: the parent SWF has complete control over the loading process, it stands to reason that if the parent SWF choose to load a child SWF onto its stage, it should implicitly trust the classes defined by the child SWF. In contrast, the child SWF has no control over the loading process (or whether it should be loaded into another SWF at all) and it has no way of identifying the parent SWF; therefore, there is no reason why it should trust the parent SWF's class definitions.

Until Adobe fixes this bug, let's try to see if we can have some fun with it. First, we create our own version of net.zarqon.api.system.LicenseManager, like so:

package net.zarqon.api.system {
 import flash.events.EventDispatcher;
 import net.zarqon.api.events.LicenseManagerEvent;
 import net.zarqon.api.entity.License;

 public class LicenseManager extends EventDispatcher {

  public function LicenseManager(issuerKey:*, licenseKey:*) {
  }

  public function validateLicense():void {
   this.dispatchEvent(new LicenseManagerEvent(LicenseManagerEvent.LICENSE_VALID, new License()));
  }
  
  public function get site():String {
   return "";
  }
 }
}

Next, we need to define our own version of net.zarqon.api.entity.License and net.zarqon.api.events.LicenseManagerEvent, like so:

package net.zarqon.api.entity {

 public class License {

  public function getFeature(featureName:String):Object {
   return {enabled: true}
  }

  public function hasFeature(featureName:String):Boolean {
   return true;
  }
  
  public function get enabled():Boolean {
   return true;
  }
 }
}
package net.zarqon.api.events {
 import flash.events.Event;
 import net.zarqon.api.entity.License;

 public class LicenseManagerEvent extends Event {

  static public const LICENSE_VALID:String = "LicenseManagerEvent/LicenseValid";
  static public const LICENSE_INVALID:String = "LicenseManagerEvent/LicenseInvalid";
  
  private var _license:License;

  public function LicenseManagerEvent(type:String, license:License) {
   super(type);
   _license = license;
  }
  
  public function get license():License {
   return _license;
  }
 }
}

Finally, we create a loader SWF to load the Zarqon Demo SWF as an embedded ByteArray using the flash.display.Loader class.
package {
 import flash.display.Loader;
 import flash.display.Sprite;
 import flash.system.ApplicationDomain;
 import flash.system.LoaderContext;
 import flash.utils.ByteArray; 
 import net.zarqon.api.system.LicenseManager;

 public class ZarqonLoader extends Sprite {

  public function ZarqonLoader() {
   var lm:LicenseManager = new LicenseManager(null, null);
   var loader:Loader = new Loader();
   var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
   loaderContext.allowCodeImport = true;
   loaderContext.allowLoadBytesCodeExecution = true;
   loader.loadBytes(new demoSWF() as ByteArray, loaderContext);
   this.addChild(loader);
  }
 }
}

Just compile and run the ZarqonLoader and watch the magic happens. Using similar techniques, I have successfully bypassed the licensing protection on the Zarqon Desktop Control Center as well. I will NOT publish the detail instructions on how to do that, because I believe if you really want to use Zarqon Active License Control System, you should pay Futurescale for it.

1 comment: