GIF
Last updated
Last updated
一个GIF文件的结构可分为
文件头(File Header)
GIF 文件署名(Signature)
版本号(Version)
GIF 数据流(GIF Data Stream)
控制标识符
图象块(Image Block)
其他的一些扩展块
文件终结器(Trailer)
下表显示了一个 GIF 文件的组成结构:
中间的那个大块可以被重复任意次
GIF 署名(Signature)和版本号(Version)。GIF 署名用来确认一个文件是否是 GIF 格式的文件,这一部分由三个字符组成:GIF
;文件版本号也是由三个字节组成,可以为 87a
或 89a
。
Logical Screen Descriptor(逻辑屏幕描述符)紧跟在 header 后面。这个块告诉 decoder(解码器)图片需要占用的空间。它的大小固定为 7 个字节,以 canvas width(画布宽度)和 canvas height(画布高度)开始。
GIF格式可以拥有global color table,或用于针对每个子图片集,提供local color table。每个color table由一个RGB(就像通常我们见到的(255,0,0)红色 那种)列表组成。
一个 GIF 文件一般包含多个图片。之前的图片渲染模式一般是将多个图片绘制到一个大的(virtual canvas)虚拟画布上,而现在一般将这些图片集用于实现动画。
每个 image 都以一个 image descriptor block(图像描述块)作为开头,这个块固定为 10 字节。
终于到了图片数据实际存储的地方。Image Data是由一系列的输出编码(output codes)构成,它们告诉decoder(解码器)需要绘制在画布上的每个颜色信息。这些编码以字节码的形式组织在这个块中。
该块为一个单字段块,用来指示该数据流的结束。取固定值0x3b.
由于GIF的动态特性,由一帧帧的图片构成,所以每一帧的图片,多帧图片间的结合,都成了隐藏信息的一种载体。
对于需要分离的GIF文件,可以使用convert
命令将其每一帧分割开来
WDCTF-2017:3-2
打开gif后,思路很清晰,分离每一帧图片后,将起合并得到完整的二维码即可
扫码后得到一串16进制字符串
03f30d0ab8c1aa5....74080006030908
开头03f3
为pyc
文件的头,恢复为python
脚本后直接运行得到flag
GIF文件每一帧间的时间间隔也可以作为信息隐藏的载体。
例如在当时在XMan选拔赛出的一题
XMAN-2017:100.gif
通过identify
命令清晰的打印出每一帧的时间间隔
推断 20 & 10
分别代表 0 & 1
,提取每一帧间隔并进行转化。
最后转 ASCII 码得到 flag。
更多参见