2008年2月16日(26日更新) 戻る
flashなどを使ったウェブ上のミニゲームで、パラメータをhtmlに直書きしているものがあります。 中にはゲームをクリアしたときの移動先やメッセージなどを書いているものもあり、がっかりします。 本格的な暗号化をする程のものでなくても、せめてパラメータは外部ファイルに書くようにしましょう。 パラメータファイルを簡単に難読化しておくとさらに有効です。
ここでは、パラメータが書かれた外部のxmlファイルを難読化し、 swfで解読して表示するサンプルを紹介します。
今回は以下のxmlファイルを使用します。 文字コードはUTF-8です。
<?xml version="1.0" ?> <data> <book> <title>仮の本</title> <author>仮野 緒砂</author> <publisher>架空出版</publisher> </book> </data>
xmlファイルはローカルであらかじめ難読化しておきます。
難読化ツールのairパッケージ => SimpleObfuscator.air
ソース => SimpleObfuscator_proj.zip
「Obfuscator.as」に難読化、解読のクラスが書いてあります。 ObfuscatorクラスはObfuscateとUnobfuscateの2つのstaticメソッドを持っています。 どちらもByteArrayを受け取って加工し、ByteArrayを返します。 複雑なアルゴリズムにする気は無いのでBase64を参考にして作りました。
Base64では文字テーブルは「ABC...」と順番に並んでいますが、このクラスでは文字テーブルをシャッフルしています。 チープなやりかたですが、xmlファイルを一目見てわからなければ良しとします。 ウェブサイトのミニゲームでswfの解析までする人はいないでしょう。 もしそういう人にまで対処するのならば本格的な暗号化をしなければなりません。 swf単体では不可能なので、サーバーとの連携が必要になるでしょう。
入力されたByteArrayの各要素とそのインデックスとのxorも取っています。 xorは同じ値で2回演算すると元の値に戻るという性質があります。 これも自前で適当な暗号化をするときに良く使われる手です。
「test.xml」をツールで難読化すると「test-Obfuscated.xml」というファイルができます。 Base64と同様に、ファイルサイズは1.3倍になります。
99DXPTh9k3cmf3h9f32lLIrErT8o6T5Bplg2y0+Xf3jXHC8wY4nG0ynUasMgpsJ44aFy-1L ...以下略
これを「SimpleObfuscatorTest.xml」とリネームして使います。 htmlのタグに書くパラメータの中で、アプリケーション固有のものはxmlファイルの名前だけです。
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="400" height="200"> <param name="movie" value="SimpleObfuscatorTest.swf" /> <param name="loop" value="false" /> <param name="quality" value="high" /> <param name="FlashVars" value="args=SimpleObfuscatorTest" /> <embed src="SimpleObfuscatorTest.swf" FlashVars="args=SimpleObfuscatorTest" width="400" height="200" loop="false" quality="high" type="application/x-shockwave-flash"></embed> </object>
flashでの表示は以下のようになります。
サンプルflashのソースは以下の通りです。
package
{
import flash.display.*;
import flash.text.*;
import flash.net.*;
import flash.events.Event;
import flash.utils.ByteArray;
public class Main extends Sprite
{
private var _tf:TextField;
private var xmldoc:XML;
public function Main():void
{
// 難読化されたパラメータファイルの名前を得る
var flashvars:Object;
flashvars = loaderInfo.parameters;
var argsfile:String = flashvars["args"] + ".xml";
// テキストフィールドを配置してパラメータファイル名を表示
_tf = new TextField();
var tformat:TextFormat = new TextFormat();
tformat.size = 32;
_tf.defaultTextFormat = tformat;
_tf.autoSize = TextFieldAutoSize.LEFT;
_tf.text = "[" + argsfile + "]";
addChild(_tf);
// パラメータファイルのロードを開始
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, onLoadComplete);
// 解読ルーチンがByteArrayを使用するので
// ロード形式もBINARY
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.load(new URLRequest(argsfile) );
}
private function onLoadComplete(event:Event):void
{
var loader:URLLoader = URLLoader(event.target);
var buff:ByteArray = loader.data;
// Obfuscatorクラスで解読
buff = Obfuscator.Unobfuscate(buff);
// ByteArray.readUTFBytes()はBOMを取ってくれないので
// 自分で読み飛ばす
if(hasBOM(buff) )
buff.position = 3;
var xmlstr:String = buff.readUTFBytes(buff.bytesAvailable);
xmldoc = new XML(xmlstr);
var str:String = "タイトル : " + xmldoc.book.title
+"\n著者 : " + xmldoc.book.author
+"\n出版社 : " + xmldoc.book.publisher;
_tf.text = _tf.text + "\n" + str;
}
private function hasBOM(buff:ByteArray):Boolean
{
return (buff[0] == 0xef) && (buff[1] == 0xbb) && (buff[2] == 0xbf);
}
}
}