RSS RSS
はるのうたたね
2010.04.11
カテゴリ:

SWFバイナリ解析

こんにちは。エンジニアの はる です。
今回はちょっとだけマニアックにswfのバイナリ解析方法について書いてみたいと思います。

バイナリって何となく苦手意識のある方も多いかと思いますが、swfのバイナリ解析は数パターンの計算方法だけ抑えてしまえば意外と素直に読み解けてしまいます。

文系大学出身&英語が読めない私でも大丈夫だったので、興味のある方は是非!

用意するもの

バイナリエディタ

まずはバイナリファイルを閲覧・編集できる環境を用意します。

バイナリエディタは様々なものがありますが、自分の環境や好みに合わせて選んでみてください。代表的なものを下記します。

  • vi
1. バイナリモードでswfファイルを開く
vi -b hoge.swf
2. テキスト形式から16進数ダンプ形式に変換
:%!xxd
3. 16進数ダンプ形式からテキスト形式に変換
:%!xxd -r

解析用SWF

解析するためにはSWFファイルが必要です。適当にSWFをパブリッシュして用意しておきましょう。
※今回の記事では、非圧縮のSWFをもとに解説させていただきます。解析用SWFは、「ファイル」→「パブリッシュ設定」→「SWF設定:ムービーの圧縮」のチェックをはずしたものをパブリッシュしましょう。

基数変換の基礎知識

解析中に2進数・10進数・16進数の相互変換が沢山あります。このあたりの計算方法は事前に覚えておくか、基数変換を簡単に行えるWEBサイトやソフトが沢山ありますので、用意しておきましょう。

以上の用意ができたら、解析用SWFをお好きなバイナリエディタで開けば、準備完了です。

SWFフォーマット

SWFのバイナリは下記のような形式で構成されています。
ヘッダ(header、header_movie)に基本情報が格納されており、コンテンツ(tag block)にシェイプやスクリプト等のコンテンツ情報が順々に格納されています。

SWF
header(8バイト) header_movie(可変長) tag block(可変長) tag block(可変長) .. end tag
圧縮有無(3バイト) SWFのバージョン(1バイト) ファイルサイズ(4バイト) ステージの幅・高さ(可変長) フレームレート(2バイト) _rootのフレーム数(2バイト) TLC構造(可変長) TLC構造(可変長) ... 2バイト

ヘッダ

まずはヘッダから読み解いていきましょう。ヘッダから読み取れる情報は以下の6種類です。

ヘッダから読み取れる情報

  1. 圧縮されているかどうか
  2. Flash Player のバージョン
  3. ファイルサイズ
  4. ステージの幅・高さ
  5. fps(frame per second)
  6. _rootのフレーム数

上記の情報が格納されているヘッダの構成は以下のようになっています。

ヘッダのバイナリフォーマット

ヘッダ
header(8バイト) header_movie(可変長)
圧縮有無(3バイト) SWFのバージョン(1バイト) ファイルサイズ(4バイト) ステージの幅・高さ(可変長) フレームレート(2バイト) _rootのフレーム数(2バイト)

それでは実際にバイナリを読み解いていきましょう。1バイト目から順に解説していきます。

バイナリ詳解

1. 1〜3バイト(長さ:3バイト)

SWFが圧縮されたものがどうかを判別します。

16進数 説明 備考
46 57 53 圧縮されていないSWF FWS
43 57 53 圧縮されたSWF(※SWF6以降のみ) CWS

CWSの場合、8バイト以降がZLIB圧縮されていることを示しています。この場合、8バイト以降をZLIB展開する必要があります。
※以降の解説はFWSの前提ですすめさせていただきます。

2. 4バイト目(長さ:1バイト)

SWFのバージョンが格納されています。以下の例の場合、SWF7形式であることが分かります。

16進数 説明 備考
07 SWFのバージョン

3. 5〜8バイト(長さ:4バイト)

swfファイルのファイルサイズが格納されています。ただし、数値はリトルエンディアン形式で格納されているため、注意が必要です。

16進数 説明 備考
ec 52 01 00 ファイルサイズ リトルエンディアン形式

<計算方法>

1. バイトスワップ
ec 52 01 00
逆順 00 01 52 ec
2. 10進数に変換
1.の結果(16進数) 000152ec
10進数 86764

3. ファイルサイズ = 86764 byte

4. 9バイト〜(長さ:可変長)

ステージの幅・高さが格納されています。ただし、数値はRECT構造体で表現されているのに加え、単位はTWIPSのため、注意が必要です。

16進数 説明 備考
70 00 09 60 00 00 96 00 00 ... ステージの幅・高さ RECT構造体で表現。単位はTWIPS(トゥイップ)

<計算方法>

1. 2進数に変換
16進数 70 00 09 60 00 00 96 00
2進数 01110000 00000000 00001001 01100000 00000000 00000000 10010110 00000000 00000000
2. 最初の5ビットを10進数に変換
2進数 01110
10進数 14
3. 2.の結果毎に6ビット目以降を区切る(余りのビットは捨てられます)
最初の5ビット 14ビット 14ビット 14ビット 14ビット 余りのビット
01110 000 00000000 000 01001 01100000 0 0000000 0000000 0 10010110 00000 000
4. 3.の結果を10進数に変換
X座標の最小値 X座標の最大値 Y座標の最小値 Y座標の最大値 余りのビット
16進数 00000000000000 01001011000000 00000000000000 01001011000000 000
10進数 0 4800 0 4800 -
5. 4.の結果がtwipのため、ptに変換(1pt=20twips)
X座標の最小値 X座標の最大値 Y座標の最小値 Y座標の最大値
twips 0 4800 0 4800
pt 0 240 0 240

6. 縦幅 = 240px, 横幅 = 240px

5. 長さ:2バイト

フレームレートが格納されています。

16進数 説明 備考
00 08 フレームレート 逆順にした結果の1ビット目が整数部、2ビット目が小数部

<計算方法>

1. バイトスワップ
00 08
逆順 08 00
2. 整数部、小数部を10進数に変換
1.の結果(16進数) 08.00
10進数 8.0

3. フレームレート = 8 fps

6. 長さ:2バイト

_root(メインタイムライン)のフレーム数が格納されています。

16進数 説明 備考
14 00 _rootのフレーム数 リトルエンディアン形式

<計算方法>

1. バイトスワップ
14 00
逆順 00 14
2. 10進数に変換
1.の結果(16進数) 00 14
10進数 20

3. _rootのフレーム数 = 20

ヘッダの解析はこれで終了です。SWF解析の肝は次バイトからのコンテンツ(tag block)ですが、これはヘッダ解析で行った計算方法の応用です。

ここから先は、tagの種類毎にtag blockの構造が異なるため、Adobe社が配布している『SWF file format specification』を片手にtagの種類を特定し、それに合った計算方法で解析していくことになります。

今回は一例として、ヘッダに続くtab block(SetBackgroundColor)の解説を行います。

コンテンツ

コンテンツのバイナリフォーマット

  • コンテンツは tag block毎に続き、tag blockは[ tag | length | contents ]の構造(以下、TLC構造)となる。
  • tag block の構造は2種類存在し、"「length < 3f」の場合"と"「length >= 3f」または特殊形式の場合"で異なる。
1. タグ形式1(※「length < 3f」)の場合
コンテンツ
tag block(可変長) ...
record header(2バイト) contents(lengthバイト) ...
tag(10ビット) length(6ビット) contents(lengthバイト) ...
2. タグ形式2(※「length >= 3f」または特殊形式)の場合
コンテンツ
tag block(可変長) ...
record header(6バイト) contents(lengthバイト) ...
tag(10ビット) 3f(6ビット) length(4バイト) contents(lengthバイト) ...

バイナリ詳解

16進数 43 02 ff ff ff ff 0a 05 00 00 00 69 6e 69 74 00 3f 03 3a 03 00 00 88 06 01 1e 00 00 ...
2進数 01000011 00000010 11111111 11111111 11111111 11111111 ...

1〜2バイト(長さ:2バイト)

16進数 説明 備考
43 02 tag(10ビット)+length(6ビット) リトルエンディアン形式

<解析方法>

1. バイトスワップ
43 02
逆順 02 43
2. 2進数に変換
16進数 02 43
2進数 00000010 01000011
3. 10ビット、6ビットに分割
tag length
0000001001 000011
4. 『SWF file format specification』のp.271〜p.273をもとにtagの種類とlengthを算出する
2進数 10進数 結果
タグ種別 0000001001 9 SetBackgroundColor
length 000011 3 3

5. タグ形式2(※「length >= 3f」または特殊形式)の場合、続く4ビットを取得し、lengthを算出する

6. 続くlengthバイトを取得し、『SWF file format specification』の各タグ処理の記載に沿って解析
※SetBackgroundColorの場合
RGB ff ff ff
※setBackgroundColorは、必ずコンテンツの先頭に位置し、「長さ:5バイト」となる
setBackgroundColor(5バイト)
tag(1バイト) length(1バイト) RGB(3バイト)
あとはtagの種類毎に決められたフォーマットで解析していき、順々にコンテンツ(tag block)を解析していきます。
このswfのバイナリ構造を抑えておくと、例えば、Flash単体では通常取得することが困難な情報をバイナリレベルでswf内に埋め込んでから出力するアプリケーション開発したり、swfmillで出力されるxmlフォーマットもバイナリ構造と近いので理解しやすくなったりします。 皆さんもちょっとアブノーマルなバイナリの世界にいかがでしょうか?

コメント (0)  |トラックバック (0)

ブックマークに追加する

トラックバック URL
この記事にコメントをする
ニックネーム:
メールアドレス:
URL:


.
web開発ならKBMJ
Rubyでのwebシステム開発は
実績豊富なKBMJにお任せ下さい
iPhone開発
iPhone開発は
KBMJにお任せ下さい
ブラウザゲーム エインヘリアル
ブラウザゲーム「エインへリアル」
αテスター募集中
オープンソースECパッケージ エレコマ
オープンソースECパッケージ
「エレコマ」

プロフィール

はる(fujita)
はる(fujita)
おまえのハートにピッ!ピカチュー!
どうも、シビれる爽快感でおなじみの fujita です。

最近チェックした記事

最新記事

アーカイブ

アクセスランキング

KBMJのWebソリューション
Ruby on railsの開発ならKBMJ
株式会社ケイビーエムジェイ