Home > AIR | ActionScript3.0 | Flash > SWF デコンパイル対策2

SWF デコンパイル対策2

MotionDecompiler の穴らしきもの編です。

以前書いた SWF デコンパイル対策(http://blog.bk-zen.com/2008/12/30/105/)
について、
こるなご さんから プログラムと音楽  Flash自体を暗号化して画像、音楽、ActionScriptソースを保護する (http://thorshammer.blog95.fc2.com/blog-entry-261.html)
のような記事を書いていただきました。
ありがとうございます。

穴をつぶされてしまうかも知れない、
あわよくば手伝ってくださる方がいれば、(募っているとの事を書いてなかったけどw)
と思ったのでとりあえず情報は伏せておいたけど、
そろそろ一人で抱えている問題でも無い気がしてきましたし、
こるなご さんが興味を示してくれたのでw
以前見つけた穴らしきものを公開してみる。

穴らしきものも、完璧な穴とは言えず、”現在は” というものであることを理解しておいてください。

さて、その穴の入り口は以下のようになる。

MotionDecompiler で SWF をデコンパイルする行為は簡単だ。
サイトの SWF をぶっこぬいて、ぶっこ抜いてきた SWF を右クリックで デコンパイルを選ぶだけ。
用意周到というか、 SWF キャッチャーなるものも MotionDecompiler にはついている。
コレは、 IE などで表示されている SWF を列挙して、 SWF をダウンロードしてくれるツールだ。
このサイトのこの SWF がどうなってるんだろう?
と思ったら1分以内にソースがほぼ完璧に再現されてしまう。

その MotionDecompiler の穴らしきものとは。
実は Embed に隠されていた。
以前から Embed に興味を持っていた俺は SWF なり、 MP3 なり、PNG なりを色々と
Embed していたりした。
その中で偶然 SWF を Embed したときに、
その中身がデコンパイラでは再現されていないことに気付いた。

中身がどのように再現されているかというと、
Main_EmbedChild といったクラスで感じの名前定義されていて、
Main_EmbedChild は MovieClipLoaderAsset を継承している。
MovieClipLoaderAsset の movieClipData を override している。
その中で Main_EmbedChild_dataClass という感じの名前になっているクラスを new して返している。
Main_EmbedChild_dataClass は ByteArrayAsset を継承している。
そして、一番重要な部分 Main_EmbedChild_dataClass の中身は何も見えていない状態になっている。
ここが穴だ。

さて、この穴らしきものを突っついて SWF の中身を隠すには、普通に作った SWF を埋め込めばよいのだが、
今回は、前回の記事のように、その部分にローダーとKEYと暗号化のアルゴリズムを隠す方法を載せておく。
ということでこんなものを作った。encript(http://www.bk-zen.com/lab/as3/encript/com.zip)

ちょっと紹介。
Encript クラス : ローダーを取得するクラス。
Cript クラス : 暗号化クラス。
EncriptLoader : ローダークラス。

使い方。
1. Cript クラスを使用して SWF を暗号化して書き出す。(要AIR)

var data: ByteArray = file.data; // file == 読み込んだ SWF。
var cript: Cript = new Cript();
var newfile: File = new File(file.nativePath);
newfile.save(cript.cript(data, "HOGEHOGE_KEY_MOJAMOJA"), "criptswf.swf");

2. ローダークラスを用意する。
これは、Encript クラスを使う。
Encript クラスの以下の部分を変える。

public function get loader(): IEncriptLoader
{
     // return new EncriptLoader("%ENCRIPT_KEY%", new Cript()); // ↓に変える
     return new EncriptLoader("HOGEHOGE_KEY_MOJAMOJA", new Cript());
}

書き換えたら Encript クラスをコンパイルする。
3. メインクラスを作る。
メインクラスは、2で作った SWF を Embed して、 SWF の root を IEncript クラスにキャストして、
loader を取得する。

// SWF の root 取得までを省略。
var encript: IEncript = IEncript(e.target.content);
var loader: IEncriptLoader = encript.loader;
loader.addEventListener(Event.COMPLETE, onComp);
loader.load(new URLRequest("hoge.swf")); // または以下
/*
[Embed (source= "hoge.swf", mimeType = "application/octet-stream")]
private var EmbedChild: Class; // って感じにEmbedしておく。
loader.loadBytes(new EmbedChild());
*/
function onComp(e: Event): void
{
    var swf: MovieClip = MovieClip(e.target.content);// 複合化された SWF の root
}

ポイントとしては Embed した SWF の root を取得しておくことと、
インターフェースを使うこと。
ここでインターフェースを使わなかった場合、
メインクラスと一緒に書き出されてしまうので、KEY も 暗号化のアルゴリズムも丸わかりになってしまいます。

こるなご さん のエントリーを見ると RC4 で暗号化しているようですね。
確かにそのほうがよさそうな気がします。
自分は恥ずかしながら RC4 を知らなかったので独自の方法でやっていましたが、
こっちのほうがより安全性が高いかと思います。
RC4、または別の方法で、もしくは多種から選べるようにしておくのも手かも知れません。
そのため、Cript クラスは ICript インターフェースを持っているクラスとしました。
ICript インターフェースを実装していれば、何でも差し替えが可能になるわけですね。

まぁコレを作った後に、SWF 自体、穴に突っ込んでおけばよくね?って思ってポカーンとしていたわけですwww

ただし、
コレにはこんな落とし穴もあった。

SWF を 2回以上 Embed すると 1回目 Embed された、SWF の インターフェースが忘れられる?
どういうことかというと、
MainA というクラスがあったとする。
MainA はインターフェースとして、 IMainA というクラスを実装している。
MainA をコンパイルして MainA.swf としておく。
MainB は MainA.swf を Embed して、 IMainA として MainA を使用する。
MainB をコンパイルして MainB.swf としておく。
MainB.swf を使うクラスとして MainC があり、 MainC をコンパイルして MainC.swf とすると、エラーが起きる。
エラーが起こっている場所は MainA.swf の root を IMainA にキャストしているところだ。
MainB.swf では起こっていなかったエラーが起きている。
エラーの内容としては MainA は IMainA を実装していないですよ。
といった内容。
どういうことだろうか?
確かに実装したはずの IMainA がどこかへ消えたのだろうか?

で、考えたもう一段階再現を難しくする方法。
今回のこの方法は、「SWF を暗号化」 -> 「KEY を元に復号化」といった手順を踏みますので
つまり、 KEY と暗号化、復号化のアルゴリズムがわかってしまえば、復元できてしまいます。
例えば、今回のように、こんな方法で隠せます。
と公言したことで、そうか、あの方法で隠されているのは RC4 で隠されているんだ。
と思った悪い子は KEY を入手しようとするでしょう。
サーバに KEY を持っておく場合、プロクシを通したりすればさっくりと KEY が割れてしまいます。
そうすると KEY と RC4 のアルゴリズムを使って復号化した SWF を再現できてしまいます。
そうされないために、暗号化の部分複数用意しておくってのはどうでしょう?
一般的な例として、RC4 や何かを使うとして、
独自で作ったアルゴリズムなら、十人十色の暗号化の方法があるので楽に復号化はできないはず。

と、言っている自分は暗号化のスペシャリストでも何でもないので確信はもてません。

あと、こんなのがあった。
SWF Encript 5.0 (http://www.amayeta.com/software/swfencrypt/)
secureSWF (http://www.kindisoft.com/)

まだ試してはいないが、デモを見る限り secureSWF が強力そうだ。

他にも、
「こんな落とし穴ありました」
「こうしたほうがよさそうです」
「こんなの作りました。」
「コレで身長が5cm伸びました。」
的なことがあったら教えてほしいです。
よろしくお願いします。><

でわ。友人のブックマークの「ネタ」カテゴリにブックマークされていてショックだった俺でした。

Comments:2

vim 10-02-10 (水) 20:35

有益な情報ありがとうございます。インターフェイスの意味はデコンパイル(ActionScriptViewer)してみて理解できました。
以下のページで使ってみました。
http://www.eqliquid.com/blog/2010/02/actionscript30gui.html

Yasu 10-05-18 (火) 21:12

ども、おつかれさまです。

記事を投稿されてから1年半もたっているので、既に新しい情報をお持ちかもしれませんが、参考までにコメントを。

SecureSWFを試してみました。
難読化のレベルとしてはデコンパイルソフトと対決させてみたところ次の結果となりました。

・Flash Decompiler Trillix
→ Decompiler Trillixが解読途中に強制終了し、解読不可
・Sothink SWF Decompiler
→ASの読み取りができたが、難読化されており解読がほぼ不可能な状態になっている。そのASコードを再コンパイルしようとすると、確実にコンパイルエラーになるようなコードが含まれている。

参考までにwonderflにどのくらいsecureSWFによって難読化されているかサンプルをアップしました。

セキュア前
http://wonderfl.net/c/k2fy

セキュア後
http://wonderfl.net/c/FtBy

secureSWFではSWCファイルも難読化可能なので、コアロジックだけSWCにしてsecureSWFを適用するのもいいかもしれませんね。

Comment Form
Remember personal info

Trackbacks:1

Trackback URL for this entry
http://blog.bk-zen.com/2009/02/02/128/trackback/
Listed below are links to weblogs that reference
SWF デコンパイル対策2 from 馬鹿全
pingback from 馬鹿全 - SWF デコンパイラ対策 09-02-02 (月) 7:34

[...] SWF デコンパイラというものをご存知だろうか? SWF をそのデコンパイラにかけるとソースが再現されてしまうというものだ。 コレは、便利といえば便利だが、基本的にはそういう行為を禁止している場合が多い。 例えば、Flash ゲームサイトなどではほとんどがそうなっているだろう。 チート歓迎なんてところは何処にも無い。 当たり前といえば当たり前だ。 ゲームのバランスが崩壊するからだ。 メモリ上を弄られたら全てが終わりだが、 それをできる人は少ないだろう。 せめて、SWF のデコンパイルさえ防止できれば、とひたすら勉強していた。 [追記]http://blog.bk-zen.com/2009/02/02/128/ [...]

Home > AIR | ActionScript3.0 | Flash > SWF デコンパイル対策2

Search
Feeds
Meta

Return to page top