Nov 13 2009
[AS3] Applying ROT128 Encryption On Embedded/Module SWFs
This post is a supplement to “Applying ROT128 Encryption On ByteArray”.
Some time back, we posted a simple technique for hiding assets and AS3 code from prying eyes by embedding one SWF within another SWF. In this post, we revisit that topic and look at how ROT128 can be used to provide an additional layer of protection.
Step I: Apply ROT128 To Actual SWF
Using the following code, we will apply ROT128 to the SWF that is going to be embedded:
// assuming the raw data of the SWF has been stored in a variable swfBytes var j:int = swfBytes.length; while (j--) { swfBytes[j] += 128; }
The following shows a simple tool you can create to load a SWF file, apply ROT128 to it, and save the encrypted file.
- Flash Player 10 is required.
- Click the Browse button to bring up a native file dialog.
- Select a Flash Movie (.swf) file.
- Click the Save button that will be shown after loading the SWF file.
(80×80 SWF, 2KB)
You can verify that encryption has been done by running the saved SWF file “ActualSWF.swf” – it should show a blank screen.
Remember, applying ROT128 twice restores the file, so the tool can also be used to restore a previously ROT128-encrypted file if the algorithm used was the same (same n increment, same conditional loop).
The ROT128SWF class:
(please feel free to customize to fit your own requirements)
package { import flash.display.Sprite; import flash.display.Stage; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.events.MouseEvent; import flash.events.IOErrorEvent; import flash.net.FileFilter; import flash.net.FileReference; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFieldType; import flash.text.TextFormat; public class ROT128SWF extends Sprite { // ** minimalist text button ** private var opButton:TextField; // ** browse/load/save ** private var swfFile:FileReference; public function ROT128SWF():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // entry point stage.align = StageAlign.LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.showDefaultContextMenu = false; // ** draw minimalist text button ** opButton = new TextField(); opButton.autoSize = TextFieldAutoSize.LEFT; opButton.background = true; opButton.backgroundColor = 0x000000; opButton.defaultTextFormat = new TextFormat("Tahoma", 14, 0xFFFFFF, true, null, null, null, null, null, 4, 4); opButton.selectable = false; opButton.text = "BROWSE"; opButton.x = (stage.stageWidth - opButton.width) * 0.5; opButton.y = (stage.stageHeight - opButton.height) * 0.5; addChild(opButton); // ** button click listener ** opButton.addEventListener(MouseEvent.CLICK, on_buttonClick, false, 0, true); } /** * handle browse or save */ private function on_buttonClick(evt:MouseEvent):void { var btn:TextField = evt.target as TextField; if (btn) { if (btn.text == "BROWSE") { swfFile = new FileReference(); swfFile.addEventListener(Event.SELECT, on_swfSelect, false, 0, true); swfFile.browse([new FileFilter("Flash Movie","*.swf")]); } else if (btn.text == "SAVE") { if (swfFile) { // ** BEGIN ROT128 ** var j:int = swfFile.data.length; while (j--) { swfFile.data[j] += 128; } // ** END ROT128 ** new FileReference().save(swfFile.data, "ActualSWF.swf"); } } } } /** * handle browse, load swf file */ private function on_swfSelect(evt:Event):void { swfFile.removeEventListener(Event.SELECT, on_swfSelect); swfFile.addEventListener(Event.COMPLETE, on_swfComplete, false, 0, true); swfFile.load(); } /** * handle load, change browse button to save button */ private function on_swfComplete(evt:Event):void { swfFile.removeEventListener(Event.COMPLETE, on_swfComplete); opButton.text = "SAVE"; opButton.x = (stage.stageWidth - opButton.width) * 0.5; } } }
Step II: Embed Actual SWF In Shell SWF
If you have not done so already, please see “Hiding Assets And Code By Embedding SWF Within Another SWF” for the original discussion on how the technique works.
The following is a MainShell class you can use to embed the ROT128-encrypted SWF:
package { import flash.display.Loader; import flash.display.Sprite; import flash.utils.ByteArray; public class MainShell extends Sprite { [Embed(source="ActualSWF.swf", mimeType="application/octet-stream")] private static const bytes:Class; /** * REMINDER * * MAKE SURE THAT THIS SHELL SWF IS PUBLISHED USING THE * ORIGINAL WIDTH/HEIGHT DIMENSIONS OF THE EMBEDDED SWF */ public function MainShell() { var swf:ByteArray = new bytes() as ByteArray; if (swf) { // ** BEGIN ROT128 ** var j:int = swf.length; while (j--) { swf[j] += 128; } // ** END ROT128 ** Loader(addChild(new Loader())).loadBytes(swf); } } } }
With the above code, the “ActualSWF.swf” file is embedded into the shell SWF. It is then instantiated as a ByteArray during run-time. ROT128 is then applied to the ByteArray before it is loaded into a Loader object.
Why Do This At All?
Hiding assets and code by embedding one SWF within another SWF is simple to implement and so far, there has not been any report on any decompiler overcoming the protection.
In the original post on the technique, I suggested that you could, if you wish, add another layer of protection by encrypting the embedded SWF just in case a decompiler may in future automatically identify a binary blob and “guess” that it is an embedded SWF (and decompile it separately).
I feel that ROT128 is light-weight and simple enough that can achieve that objective. Remember that the objective here is not to overcome meticulous hacking, but merely to thwart possible attempts to implement automatic extraction and identification of embedded binary blobs as separate SWFs.
The above is only an example of how the concept can be applied. As mentioned in the previous post on ROT128, you can also consider applying ROT128 only to part of the file so that the logic for reversing the encryption could be a little less predictable.
Module SWFs
Although the above mentioned only embedded SWFs, you can definitely apply the same concept to module SWFs that will be loaded into your application during run-time. By applying ROT128 to module SWFs, even if they are obtained via unauthorized means such as via the web browser’s cache, they are non-executable (or will just show a blank screen when run) if the ROT128 encryption is not reversed first.








Hi,
I read this complete tutorial and it is fantastic and you have explained it very clearly!!! But I need one information ..like, the way you are saving “ActualSWF.swf” file Can we save Text file in same manner… like i can take text from say TextArea and then save in a TextFile(fileNAME.txt)… I tried but it give error saying..
1061: Call to a possibly undefined method save through a reference with static type Class.
Your help will be appreciated!!! thank you and keep it up!!!
OK!!! I am using FLASH CS3 and i think CS3 do not support “FileReference.save()”… Am i right??
Pardon me, but that is not a Class method. It is probably my fault for over-shortening the code.
new FileReference().save(swfFile.data, “ActualSWF.swf”);
is the same as
var fileRef:FileReference = new FileReference();
fileRef.save(swfFile.data, “ActualSWF.swf”);
And yes, the save() method is available only for Flash Player 10+. If the CS3 compiler is giving you trouble, just use FlashDevelop or the Flex compiler
.