Even though the point of code obfuscation will always remain arguable, it may sometimes be a good idea to mess around a bit and make your ActionScript code harder to steal. The following review will highlight the features of SWF Protector, analyse the code and impact on SWF file size as well as performance.

Interface

The interface of SWF Protector is pretty straightforward and easy to follow:

SWF Protector Simple modeAdvanced mode of SWF ProtectorSWF Protector protection complete

It was a 1-second process for a 50 KB ActionScript 3 SWF. It also preserves your original SWF file renaming it to [yourSWFFilename]_original.swf.

Decompiling the protected SWF

To test the protection, 2 programs were used:

  1. Flash Decompiler Trillix
  2. Sothink SWF Decompiler

Allegedly, protectors have some built in functionality to crash the decompilers and that is exactly what happened in both scenarios:

SWF Protector withstands Flash Decompiler Trillix just fine SWFDecompiler quit unexpectedly

Whilst Trillix’s decompiler crashed consistently, Sothink’s counterpart finally worked and made it possible to get some ActionScript out of the SWF.

Resulting ActionScript

Here’s the original ActionScript 3 file before protection:

package {
 
    import flash.display.StageQuality;
    import flash.events.Event;
    import nl.demonsters.debugger.MonsterDebugger;
    import org.papervision3d.view.BasicView;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Sphere;
    import org.papervision3d.view.stats.StatsView;
 
    public class SWFProtectorTest extends BasicView {
 
        private var debugger:MonsterDebugger;
        private var pivotDO3D:DisplayObject3D;
        private var sphere:Sphere;
        private var stats:StatsView;
 
        public function SWFProtectorTest() {
            stage.frameRate = 40;
            stage.quality = StageQuality.BEST;
            init();
            startRendering();
        }
 
        private function init():void {
            debugger = new MonsterDebugger(this);
            pivotDO3D = new DisplayObject3D();
            addSpheres(5);
            scene.addChild(pivotDO3D);
            stats = new StatsView(renderer);
            addChild(stats);
            MonsterDebugger.trace(this, "SWFProtectorTest initialised!");
        }
 
        private function addSpheres(amount:int):void {
            while(amount--) {
                var radius:Number = 200 + 30 * amount;
                sphere = new Sphere(null, radius, 24, 24);
                pivotDO3D.addChild(sphere);
            }
        }
 
        override protected function onRenderTick(event:Event = null):void {
            pivotDO3D.localRotationY--;
            super.onRenderTick();
        }
    }
 
}

and here’s the very same code after being protected and then decompiled by Sothink SWF Decompiler:

    import SWFProtectorTest.*;
    import flash.display.*;
    import flash.events.*;
    import nl.demonsters.debugger.*;
    import org.papervision3d.objects.*;
    import org.papervision3d.objects.primitives.*;
    import org.papervision3d.view.*;
    import org.papervision3d.view.stats.*;
 
package 
{
    import SWFProtectorTest.*;
    import flash.display.*;
    import flash.events.*;
    import nl.demonsters.debugger.*;
    import org.papervision3d.objects.*;
    import org.papervision3d.objects.primitives.*;
    import org.papervision3d.view.*;
    import org.papervision3d.view.stats.*;
 
    public class SWFProtectorTest extends BasicView {
        private var debugger:MonsterDebugger;
        private var pivotDO3D:DisplayObject3D;
        private var sphere:Sphere;
        private var stats:StatsView;
 
        public function SWFProtectorTest() {
            if (true){
                // label
            }
            // label
            // Jump to 26;
            // label
            // Jump to 37;
            // label
            switch(-92) branch count is:&lt;0>[-3] default offset is:< -8>;
            fewymrzygqh.ztg(this);
            stage.frameRate = 40;
            stage.quality = StageQuality.BEST;
            this.init();
            startRendering();
            return;
        }
        private function init() : void {
            // label
            if (true){
                // label
                // Jump to 17;
            }
            else{
                // Jump to 26;
                // label
                // Jump to 37;
                // label
                switch(-1) branch count is:&lt;0>[-28] default offset is:< -8>;
                this.debugger = new MonsterDebugger(this);
                this.pivotDO3D = new DisplayObject3D();
                this.addSpheres(5);
                scene.addChild(this.pivotDO3D);
                this.stats = new StatsView(renderer);
                addChild(this.stats);
                MonsterDebugger.trace(this, "SWFProtectorTest initialised!");
                return;
            }
        }
        private function addSpheres(:int) : void {
            if (true){
                // label
                // Jump to 16;
            }
            else{
                // label
                // Jump to 26;
                // label
                // Jump to 40;
                // label
                switch(0) branch count is:&lt;1>[-8, -13] default offset is:< -3>;
                var _loc_2:Number;
                while (--){
                    // label
                    _loc_2 = 200 + 30 * ;
                    this.sphere = new Sphere(null, _loc_2, 24, 24);
                    this.pivotDO3D.addChild(this.sphere);
                }
                return;
            }
        }
        override protected function onRenderTick(:Event = null) : void {
            if (!true){
                // label
                // label
                // label
            }
            // label
            // Jump to 27;
            // label
            // Jump to 38;
            // label
            switch(0) branch count is:&lt;0>[-8] default offset is:< -3>;
            var _loc_2:* = this.pivotDO3D;
            _loc_2.localRotationY = this.pivotDO3D.localRotationY--;
            super.onRenderTick();
            return;
        }
    }
}

So the 2nd codepiece is in a pretty bad shape. Anyone trying to make sense here should wonder if it’s worth it – a strong argument for using such obfuscation tools.

SWF file size

Obviously any such protection algorithm will have its impact on file size. The above ActionScript made a 78 KB SWF that went up to 115 KB with both protection and obfuscation applied to all classes incl. those of Papervision3D. That’s +47%.

Without Papervision3D protection it went up to 98 KB, +25%. Also, the fact that you may want to uncheck a library of a size of Papervision3D will set you unchecking each and every class in a library one by one. A serious usability setback that the makers of SWF Protector have missed entirely.

Performance

Measuring FPS and memory usage on a busy Papervision3D loop (as per above ActionScript) didn’t reveal any setbacks, StatsView was identical.

Even so, it’s always hard to cope with anything that is going to mess with your code. In fact, it’s the very reason to avoid obfuscation tools or any other tools in that matter.

SWF Protector business licence for one user is $59.95. Personal licence is $39.95.

Related resources and articles: