Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPBinaryTips

yoya
November 10, 2015

 PHPBinaryTips

PHPでバイナリ処理Tips

yoya

November 10, 2015
Tweet

More Decks by yoya

Other Decks in Programming

Transcript

  1. 公開ライブラリ •  h8ps://github.com/yoya/IO_Bit   –  バイナリ編集ライブラリ   –  h8ps://github.com/yoya/IO_MIDI • 

    音楽の MIDI  ファイル編集   –  h8ps://github.com/yoya/IO_PNG   •  画像ファイルのPNG編集   –  h8ps://github.com/yoya/IO_ICC   •  ICCプロファイル編集
  2. 本発表について •  この発表の焼き直しです   – PHPでバイナリ変換プログラミング   – h8p://www.slideshare.net/yoyayoya1/ php-­‐10133775   • 

    PHP  でバイナリ変換するのは楽という話   – 小さなバイナリを処理するには良い感じ   – (メモリを沢山使うので、大きなバイナリを扱うの はキツい)  
  3. バイナリの例 •  バイナリの種類   – 実行ファイル (exe,  a.out,  jar)   • 

    セキュリティ界隈だと主にコレ   – マルチメディア系ファイル (JPEG,  PNG,  MPEG,  …)   – ネットワーク通信パケット (TCP,  ISDN,  …)   – 圧縮されたデータ (zip,  gzip)   – 暗号化されたデータ (SSL)   いろいろある!  
  4. 何故バイナリ処理するのか •  Webサービスでもテキスト以外の、画像や動 画、または生の通信プロトコルを扱う事があ る   •  そのデータを PHP  で改変する事で

      – より多くの種類の端末にサービスを提供できたり   – 通信データ量を減らせたり   •  エディタで開いて化けるだけで編集を諦める のは、勿体無い。
  5. ビット(Bit)について •  0  と 1  を用いて2通りの状態を示す   •  ビットを並べ4通り8通りと表現の幅を広げる 1

    0 2通り   (0〜1) 1 0 4通り   (0〜3) 1 0 1 0 256通り   (0〜255) 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 8通り   (0〜7) 1 0 1 0 00,  01,  10,11   0,  1 000,  001,  010,  011,   100,  101,  110,  111   00000000,  00000001,  00000010,  00000011,  …                            …,  11111101,  11111110,  11111111   1 0 0 0 0 1 1 1
  6. バイト(Byte)について •  (欧米の)1文字を表すビットの集まり   – 一般的にはビットを8つまとめた単位   – 16進数で表示する事が多い (バイナリダンプ等) 1 0

    4Bit  で   16進1文字 1 0 1 0 1 0 1 0 1 0 1 0 1 0 F  F 0  0 8Bit  で   16進2文字 8bitまとめて   1byte 実例 (JPEG の頭) FF D8 FF E0
  7. バイナリエディタ諸々 •  Macintosh なら 0xED,  Windows  なら S_rling,  Bz  

    Editor   •  手で編集するのが面倒になった時、PHP  の出番
  8. PHP でバイナリ大丈夫? •  PHP  の String  型はバイナリとして使える   –  h8p://www.php.net/manual/ja/

    language.types.string.php#language.types.string.details   •  文字列としての処理を勝手にしない   – 8bit  スルー、¥0  終端無視!   PHP  における文字列型は、バイトの配列と整数値 ( バッファ長)  で実装されています。 バイト列を文字列 に変換する方法については何の情報も持っておらず、 完全にプログラマ任せとなっています。
  9. String 型でバイト単位の処理 •  (バイナリ)ファイル入出力     •  連結と分解 file_get_contents file_put_contents

    ファイル ファイル input output 連結 $c = $a . $b $b = substr($a, $x, $y) 分解 $a $b $c $a $b $x $y
  10. String 型とInteger型変換 •  ord  と chr  で相互変換する $b = ord($a)

    $a = chr($b) バイナリ $a 整数値 $b $a = ‘Yoya’; $b = ord($a[0]); echo $b; $b = 89; $c = 111; $a = chr($b).chr($c); echo $a; 実行結果   ⇒  89          =  (0x59) 実行例   (分かりやすいようにテ キストで) Y   o   実行結果   ⇒  Yo Y   (string)   (integer  or  float)  
  11. Endian  に応じた処理 •  2byte以上のバイナリと整数値の相互変換   – Bit  Endian  (MSB  First)  

    – Li8le  Endian  (LSB  First) バイナリ 0x12 0x34 整数値 x y (x*256)+y 0x1234 = 4660 バイナリ 0x12 0x34 整数値 x y x+(256*y) 0x3412 = 13330 =0x100
  12. BigEndian  で unpack •  バイナリと整数値の相互変換 (BigEndian)   •  pack  で逆変換

    $b = unpack(‘n’, $a) バイナリ $a $b = unpack(‘N’, $a) $b[1] $b[1] 整数値 整数値 バイナリ $a w x y z (((((w*256)+x)*256)+y)*256)+z x y (x*256)+y
  13. Li8leEndian  で unpack •  バイナリと整数値の相互変換 (Li8leEndian)   •  pack  で逆変換

    $b = unpack(‘v’, $a) バイナリ $a $b = unpack(‘V’, $a) $b[1] $b[1] 整数値 整数値 バイナリ $a w x y z w+(256*(x+(256*(y+(256*z))))) x y x+(256*y)
  14. String 型のバイト処理 その他 •  strrev で前後リバース  (逆順にする)   •  substr_replace

     で一部入れ替え   •  strcmp でバイナリ比較  (一致するか否か)   •  str_pad, str_repeat  で同じバイトの繰り返し   str  系で色々なバイナリ操作が可能!  
  15. バイト処理の注意点 •  $a[0] •  文字列を配列のように参照すると、($a  の 0  番目の数値でなく)、0番 目の文字を切り出したものが取得できる。  

    •  $a[0] は substr($a, 0, 1) と同じ    (C言語出身者は多分ココで躓く)   •  unpack(‘N’,  …  と ‘V’の PHP  bug   –  N,  V  は unsigned  long  (32ビット値)のはずだが、実際は signed  long(符号付き)の値が出てくる   –  負の値が出てきたら 4294967296  を足して補正   •  足すと (integer    の範囲を超えて)型が float になる。要注意。   •  64bit環境ではこの問題がなくなりました。   •  でも、今度は 64ビット非負整数  (Q,  P)で同様の問題あり   –  pack  は正でも負でも受理してくれる  
  16. バイト処理の実例 JPEG分解 •  JPEGの画像サイズを抜き出す   – h8p://www.w3.org/Graphics/JPEG/  ← 仕様   • 

    JPEG  チャンクの並び   JPEG SOI DQT DHT RST APP1 SOS SOF0 EOI ここにサイズが 入っている   width height
  17. JPEG データ形式 •  JPEG  チャンクのデータ形式 SOF0 Marker   =0xffc0 Length

    2  bytes 2  bytes Data P height 1  byte width 2  byte 2  byte SOI,EOI Marker APP,DQT,  SOF0 Marker Length SOS,RSTx Marker 2  bytes 2  bytes 2  bytes 2  bytes 次のchunkまでscan Data Data Length Marker FF??  &   !  FF00
  18. JPEG  サイズ抽出サンプル <?php $data = file_get_contents($argv[1]); // JPEGfile input for

    ($i = 1 ; $i < strlen($data) ; $i++) { switch(ord($data[$i++])) { // chunk marker case 0xD8: case 0xD9: // SOI (or EOI) break; // skip default: $len = unpack('n', substr($data, $i, 2)); $i += $len[1]; break; // skip case 0xC0: // SOF0 $sof0 = unpack('CP/nH/nW', substr($data, $i + 2, 5)); echo "width:{$sof0['W']} heigth:{$sof0['H']}\n"; exit (0); // OK } }
  19. IO_Bit •  やっぱり str  系関数使うの面倒ですよね   – バイナリなのに str  使うの気持ち悪い  

    •  そんな人(自分含む)の為に     •  h8ps://github.com/yoya/IO_Bit   – バイナリ編集ライブラリ  
  20. IO_Bit ライブラリ •  ビットやバイトを頭から切り出す     •  Endian 処理も簡単 <?php

    require_once ‘IO/Bit.php’; $data = file_get_contents($argv[1]); $iobit = new IO_Bit(); $iobit->input($data); var_dump($iobit->getData(4)); // 2byte のBigEndian整数を取得 var_dump($iobit->getUI16BE());
  21. IO_Bit の使い方 •  バイナリを解釈して PHP  の配列に入れる   •  PHP  の配列を操作して、またバイナリに戻す

    [[Event:9, Note:43, Velocity:100], …⋯] PHP配列 バイナリ バイナリ Input   &  parse build   &  output
  22. IO_MIDI  使い方 •  h8ps://github.com/yoya/IO_MIDI   – MIDI編集ライブラリ (IO_Bit  でバイナリ分解)   <?php

    require_once 'IO/MIDI.php'; $data = file_get_contents($argv[1]); $midi = new IO_MIDI(); $midi->parse($data); var_dump($midi);
  23. IO_MIDI 構造 IO_MIDI header tracks header Format(1) NumberOfTracks  (9)  

    Division  (480)   0 track   DeltaTime   EventType   NoteNumber   Velocity   1 8 :   :   これを   書き換えて   みる   (音程) (音の強さ)
  24. 音程を変える •  1オクターブ上げる (半音で12個上) <?php require_once 'IO/MIDI.php'; $data = file_get_contents($argv[1]);

    $midi = new IO_MIDI(); $midi->parse($data); foreach ($midi->tracks as &$track) { foreach ($track['track'] as &$event) { if (isset($event['NoteNumber'])) { $event['NoteNumber'] += 12; // octave up! } } } echo $midi->build();
  25. 結果 •  元   h8p://diary.awm.jp/~yoya/data/2015/11/10/akatomb.mid       •  変換後)

     1オクターブup   h8p://diary.awm.jp/~yoya/data/2015/11/10/ akatomb-­‐12up.mid    
  26. 1オクターブ上がると   ピンとこない人用 •  元)   h8p://diary.awm.jp/~yoya/data/2015/11/10/akatomb.mid      

    •  変換後)  半オクターブup   h8p://diary.awm.jp/~yoya/data/2015/11/10/ akatomb-­‐6up.mid   // $event['NoteNumber'] += 12; // octave up! $event['NoteNumber'] += 6; // half octave up!