SWFバイナリ編集のススメ第二回
こんにちは。メディア開発部のよやです。
バイナリ編集のタイトルにもかかわらず前回はバイナリの読み方で終わってしまいました。
すみません。今回は編集まで話しを進めます。
バイナリ編集の手始め
まず、バイナリデータを切り出し、プログラムで適切に決めた内部形式に保存して、
それを何も加工せず出力し、元と一致するバイナリデータが生成されるのを確認する所から始めます。
前回、BitReader クラスを使ってバイナリのデータを切り出しました。今回は、
バイナリデータを組み立てる BitWriter 機能が加わった IO_Bit クラスを利用します。
-
http://svn.openpear.org/IO_Bit/branches/1.0/IO/Bit.php
- IO_Bit のインストール方法
1 2 |
pear channel-discover openpear.org pear install openpear/IO_Bit |
swfcopy
前回の swfdump プログラムを改造する流れで説明します。
swfdump で行っていた
- バイナリから切り出したデータをそのまま echo で表示
の処理をクラスに包み、swfdump のコードを入力ロジック(a)と表示ロジック(b)に分けて、かつ(a)を元に出力ロジック(c)を作成します。
- (a) バイナリから切り出したデータをクラス変数に保存 (parse)
- (b) クラス変数を echo で表示 (dump)
- (c) クラス変数を元にバイナリとして組み立て (build)
具体的なコードとしては、swfdump では、
1 2 3 4 |
$reader = new BitReader(); $reader->input($swfdata); echo 'Signature: '.$reader->getData(3).PHP_EOL; echo 'Version: '.$reader->getUI8().PHP_EOL; |
としていたコードを以下のように書き換えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
require_once 'IO/Bit.php'; class IO_SWF { var $_headers = array(); function parse($swfdata) { $reader = new IO_Bit(); $reader->input($swfdata); $this->_headers['Signature'} = $reader->getData(3); $this->_headers['Version'] = $reader->getUI8(); } function dump() { echo 'Signature: '.$this->_headers['Signature'].PHP_EOL; echo 'Version: '.$this->_headers['Version'].PHP_EOL; } function build() {] $writer = new IO_Bit(); $writer->putData($this->_headers['Signature']); $writer->putUI8($this->_headers['Version']); } |
あとは単純作業で、残り全てのデータについて上記の対応を行うと以下のクラスが出来上がります。
- http://svn.openpear.org/IO_SWF/branches/1.0/IO/SWF.php
- http://svn.openpear.org/IO_SWF/branches/1.0/IO/SWF/Dumper.php (dump function はこちらに分離)
- IO_SWF のインストール方法
1 2 |
pear channel-discover openpear.org pear install openpear/IO_SWF |
さて、IO_SWF を用いて SWFのバイナリを取り込み、加工せずにそれを組み立て直してみます。
1 2 3 4 5 |
require 'IO/SWF.php'; $swfdata = file_get_contents($argv[1]); $swf = new IO_SWF(); $swf->parse($swfdata); echo $swf->build(); |
実行
1 2 3 4 |
% php swfcopy.php orz.swf > t.swf % md5sum orz.swf t.swf 337a4edee9590382133f8f66ff67259b orz.swf 337a4edee9590382133f8f66ff67259b t.swf |
完璧に一致しました。
後は、クラス変数を書き換えてからバイナリを組み立てる事で、好きなようにバイナリをいじる事が出来ます。
背景色変更
試しに、IO_SWF を利用して背景色を変更するだけのプログラムを作成してみます。
背景色を表すタグは SetBackgroundColor (Tag Code=9) です。
8bit depth RGB で 3Byte のデータを保持するので、そこを書き換えます。
タグ番号を指定して保持するデータを入れ替えるメソッドは以下のように実装できます。
IO_SWF の parse でタグのリストがクラス変数の $this->_tags に入るのを利用します。
1 2 3 4 5 6 7 8 9 10 11 12 |
class IO_SWF_Editor extends IO_SWF { // var $_tags; // protected function replaceTagContent($tagCode, $content) { foreach ($this->_tags as &$tag) { if ($tag['Code'] == $tagCode) { $tag['Length'] = strlen($content); $tag['Content'] = $content; break; } } } } |
上のメソッドを利用して、引数で指定した色の値で入れ替えます。
1 2 3 4 5 6 |
$swfdata = file_get_contents($argv[1]); $swf = new IO_SWF_Editor(); $swf->parse($swfdata); $color = pack('CCC', $argv[2], $argv[3], $argv[4]); $swf->replaceTagContent(9, $color); echo $swf->build(); |
- 実行
1 2 |
% php swfsetbgcolor.php orz.swf 0 0 255 > blueorz.swf % php swfsetbgcolor.php orz.swf 0 255 0 > greenorz.swf |
- 実行前 SWF (orz.swf)
- 実行後 SWF (blueorz.swf)
- 実行後 SWF (greenorz.swf)
背景色が変わりました。
書き換える際の注意ですが、サイズが変わる書き換えを行う場合(例えば画像や音声のデータを入れ替える等)は、
tag の length と header の FileLength のフィールドもあわせて書き換える必要があります。
サイズフィールドの書き換えについては、次回のブログで取り上げます。
次回予告
次回は内部ID入れ替えと、画像の入れ替え処理についてお話します。
それでは失礼します。