Kyoto.なんか #4
JPEG を壊す話Shimpei Makimoto (@makimoto)Kyoto.なんか #4 (18th Aug 2018)
View Slide
誰?- Shimpei Makimoto- Software Engineer in Tokyo- 自分でも厳密な所属がわからない- https://twitter.com/makimoto- https://github.com/makimotohttps://twitter.com/makimoto/status/1027473102437904386
JPEG- Joint Photographic Experts Group https://en.wikipedia.org/wiki/JPEG- 厳密には JPEG は画像圧縮手法のことを指す- 人間たちが JPEG と呼んでいるのは大体のケースで JPEG を用いて画像をファイルに保存するための形式である JFIF (JPEG File Interchange Format) のことを指す- グリッチの文脈ではもっともロバストな画像フォーマットの1つ
いろいろな画像形式でグリッチを試すデモ- iTerm2 と Docker Hub の makimoto/glitch-playground イメージを使う- docker run -v /path/to/data:/data \-i -t makimoto/glitch-playground
何これ?- https://hub.docker.com/r/makimoto/glitch-playground/- https://github.com/makimoto/glitch-playground- ImageMagick と各種画像処理ライブラリをインストールした Docker コンテナの中で画像を変換して sed して表示させるスクリプトを動かしている- iTerm2 で動く imgcat を使って表示させているhttps://www.iterm2.com/documentation-images.html
ロバスト #とは- JPEG 形式の画像は割と壊れない- PNG とか結構すぐ壊れる- GIF とか WebP とかは割と良い
何故壊れるのか- 壊してはいけない場所を壊す- 雑なヒューリスティックをする手もあるhttps://github.com/makimoto/glitch/blob/9b5b9b3c59fbcddae15e40e2e4cd522964b8749e/commands.go#L98-L102- (割とちゃんと動くんだけど) 雑すぎ- ちゃんと画像フォーマットを理解した上で壊せば壊れない
JPEG の仕様とか- https://www.w3.org/Graphics/JPEG/- https://www.w3.org/Graphics/JPEG/itu-t81.pdf- 画像圧縮手法としての JPEG の仕様- https://www.w3.org/Graphics/JPEG/jfif3.pdf- 画像フォーマット (JFIF) の仕様- 読むのが辛い場合は Go のライブラリのコードを追うと良いかも- https://golang.org/pkg/image/jpeg/
xxd -g1 lena.jpg00000000: ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01 ......JFIF......00000010: 00 01 00 00 ff db 00 43 00 03 02 02 02 02 02 03 .......C........00000020: 02 02 02 03 03 03 03 04 06 04 04 04 04 04 08 06 ................00000030: 06 05 06 09 08 0a 0a 09 08 09 09 0a 0c 0f 0c 0a ................00000040: 0b 0e 0b 09 09 0d 11 0d 0e 0f 10 10 11 10 0a 0c ................00000050: 12 13 12 10 13 0f 10 10 10 ff db 00 43 01 03 03 ............C...00000060: 03 04 03 04 08 04 04 08 10 0b 09 0b 10 10 10 10 ................00000070: 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 ................00000080: (snip)
xxd -g1 lena.jpg00000000: ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01 ......JFIF......00000010: 00 01 00 00 ff db 00 43 00 03 02 02 02 02 02 03 .......C........00000020: 02 02 02 03 03 03 03 04 06 04 04 04 04 04 08 06 ................00000030: 06 05 06 09 08 0a 0a 09 08 09 09 0a 0c 0f 0c 0a ................00000040: 0b 0e 0b 09 09 0d 11 0d 0e 0f 10 10 11 10 0a 0c ................00000050: 12 13 12 10 13 0f 10 10 10 ff db 00 43 01 03 03 ............C...00000060: 03 04 03 04 08 04 04 08 10 0b 09 0b 10 10 10 10 ................00000070: 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 ................00000080: (snip)SOI APP0 DQT DQT
JPEG- JPEG (JFIF) 内で \xff から始まる値はマーカーとして扱われる- \xff\xd8 - SOI (Start of Image)- \xff\xe0 - APP0 (Reserved for application segments)- \xff\xdb - DQT (Define quantization table(s))
https://www.w3.org/Graphics/JPEG/itu-t81.pdf
マーカーのプレフィックスを壊すと即死- ruby -e 'print ARGF.read.b.gsub("\xff".b, "\xfe".b)' lena.jpg > out.jpg
マーカーの後の2バイトの値を壊しても即死- ruby -e 'print ARGF.read.b.gsub(/(\xff.)[^\xff]./n, "\\1\x00\x00".b)' lena.jpg >out.jpg- マーカーに続く2バイトは大体各セクションの長さを示すので破壊されると画像が開けなくなるhttps://www.w3.org/Graphics/JPEG/itu-t81.pdf
jpegsan.gem- https://rubygems.org/gems/jpegsan- https://github.com/makimoto/jpegsan- ~/misc に転がっていた jpeg.rb を整えてさっき push した
使用例[3] pry(main)> jpeg.data[4]=> #code_suffix="\xC0",symbol="SOF0",description="non-differential, Huffman coding - Baseline DCT",data_sequence="\x00\x11\b\x02\x00\x02\x00\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01">
使用例[4] pry(main)> jpeg.data[4].sequence_in_hex=> "00 11 08 02 00 02 00 03 01 11 00 02 11 01 03 11 01"
使用例
他の例- に の量子化テーブルを適用
他の例- に のハフマン符号テーブルを適用
まとめ- 画像フォーマットを考慮して画像を破壊すると安全に壊せるし、逆に完全に壊さない感じにもできる- フォーマットを意識してやるのはそれなりにコストがかかるのでできるだけ自動化したいですね
About JPEG corruptionShimpei Makimoto (@makimoto)Kyoto.なんか #4 (18th Aug 2018)