<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
	<id>https://game.etao.net/w/index.php?action=history&amp;feed=atom&amp;title=GIF</id>
	<title>GIF - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://game.etao.net/w/index.php?action=history&amp;feed=atom&amp;title=GIF"/>
	<link rel="alternate" type="text/html" href="https://game.etao.net/w/index.php?title=GIF&amp;action=history"/>
	<updated>2026-05-05T22:01:23Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://game.etao.net/w/index.php?title=GIF&amp;diff=249&amp;oldid=prev</id>
		<title>127.0.0.1：​创建页面，内容为“{{Ctf_Wiki}} &lt;span id=&quot;gif&quot;&gt;&lt;/span&gt; = GIF =  == 文件结构 ==  一个GIF文件的结构可分为  * 文件头（File Header） ** GIF 文件署名（Signature） ** 版本号（Version） * GIF 数据流（GIF Data Stream） ** 控制标识符 ** 图象块（Image Block） ** 其他的一些扩展块 * 文件终结器（Trailer）  下表显示了一个 GIF 文件的组成结构：  File:./figure/gif.png  中间的那个大块可以被重复任意次  ===…”</title>
		<link rel="alternate" type="text/html" href="https://game.etao.net/w/index.php?title=GIF&amp;diff=249&amp;oldid=prev"/>
		<updated>2023-07-03T03:48:53Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“{{Ctf_Wiki}} &amp;lt;span id=&amp;quot;gif&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; = GIF =  == 文件结构 ==  一个GIF文件的结构可分为  * 文件头（File Header） ** GIF 文件署名（Signature） ** 版本号（Version） * GIF 数据流（GIF Data Stream） ** 控制标识符 ** 图象块（Image Block） ** 其他的一些扩展块 * 文件终结器（Trailer）  下表显示了一个 GIF 文件的组成结构：  [[File:./figure/gif.png]]  中间的那个大块可以被重复任意次  ===…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Ctf_Wiki}}&lt;br /&gt;
&amp;lt;span id=&amp;quot;gif&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= GIF =&lt;br /&gt;
&lt;br /&gt;
== 文件结构 ==&lt;br /&gt;
&lt;br /&gt;
一个GIF文件的结构可分为&lt;br /&gt;
&lt;br /&gt;
* 文件头（File Header）&lt;br /&gt;
** GIF 文件署名（Signature）&lt;br /&gt;
** 版本号（Version）&lt;br /&gt;
* GIF 数据流（GIF Data Stream）&lt;br /&gt;
** 控制标识符&lt;br /&gt;
** 图象块（Image Block）&lt;br /&gt;
** 其他的一些扩展块&lt;br /&gt;
* 文件终结器（Trailer）&lt;br /&gt;
&lt;br /&gt;
下表显示了一个 GIF 文件的组成结构：&lt;br /&gt;
&lt;br /&gt;
[[File:./figure/gif.png]]&lt;br /&gt;
&lt;br /&gt;
中间的那个大块可以被重复任意次&lt;br /&gt;
&lt;br /&gt;
=== 文件头 ===&lt;br /&gt;
&lt;br /&gt;
GIF 署名（Signature）和版本号（Version）。GIF 署名用来确认一个文件是否是 GIF 格式的文件，这一部分由三个字符组成：&amp;lt;code&amp;gt;GIF&amp;lt;/code&amp;gt;；文件版本号也是由三个字节组成，可以为 &amp;lt;code&amp;gt;87a&amp;lt;/code&amp;gt; 或 &amp;lt;code&amp;gt;89a&amp;lt;/code&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;逻辑屏幕标识符logical-screen-descriptor&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== 逻辑屏幕标识符（Logical Screen Descriptor） ===&lt;br /&gt;
&lt;br /&gt;
Logical Screen Descriptor（逻辑屏幕描述符）紧跟在 header 后面。这个块告诉 decoder（解码器）图片需要占用的空间。它的大小固定为 7 个字节，以 canvas width（画布宽度）和 canvas height（画布高度）开始。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;全局颜色列表global-color-table&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== 全局颜色列表（Global Color Table） ===&lt;br /&gt;
&lt;br /&gt;
GIF格式可以拥有global color table，或用于针对每个子图片集，提供local color table。每个color table由一个RGB（就像通常我们见到的（255，0，0）红色 那种）列表组成。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;图像标识符image-descriptor&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== 图像标识符（Image Descriptor） ===&lt;br /&gt;
&lt;br /&gt;
一个 GIF 文件一般包含多个图片。之前的图片渲染模式一般是将多个图片绘制到一个大的（virtual canvas）虚拟画布上，而现在一般将这些图片集用于实现动画。&lt;br /&gt;
&lt;br /&gt;
每个 image 都以一个 image descriptor block（图像描述块）作为开头，这个块固定为 10 字节。&lt;br /&gt;
&lt;br /&gt;
[[File:./figure/imagesdescription.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;图像数据image-data&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== 图像数据（Image Data） ===&lt;br /&gt;
&lt;br /&gt;
终于到了图片数据实际存储的地方。Image Data是由一系列的输出编码（output codes）构成，它们告诉decoder（解码器）需要绘制在画布上的每个颜色信息。这些编码以字节码的形式组织在这个块中。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;文件终结器trailer&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== 文件终结器（Trailer） ===&lt;br /&gt;
&lt;br /&gt;
该块为一个单字段块，用来指示该数据流的结束。取固定值0x3b.&lt;br /&gt;
&lt;br /&gt;
更多参见 [http://www.jianshu.com/p/df52f1511cf8 gif 格式图片详细解析]&lt;br /&gt;
&lt;br /&gt;
== 空间轴 ==&lt;br /&gt;
&lt;br /&gt;
由于GIF的动态特性，由一帧帧的图片构成，所以每一帧的图片，多帧图片间的结合，都成了隐藏信息的一种载体。&lt;br /&gt;
&lt;br /&gt;
对于需要分离的GIF文件,可以使用&amp;lt;code&amp;gt;convert&amp;lt;/code&amp;gt;命令将其每一帧分割开来&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;console&amp;quot;&amp;gt;$ convert cake.gif cake.png&lt;br /&gt;
$ ls&lt;br /&gt;
cake-0.png  cake-1.png  cake-2.png  cake-3.png  cake.gif&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== 例题 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;WDCTF-2017:3-2&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
打开gif后，思路很清晰，分离每一帧图片后，将起合并得到完整的二维码即可&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;from  PIL import Image&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
flag = Image.new(&amp;quot;RGB&amp;quot;,(450,450))&lt;br /&gt;
&lt;br /&gt;
for i in range(2):&lt;br /&gt;
    for j in range(2):&lt;br /&gt;
        pot = &amp;quot;cake-{}.png&amp;quot;.format(j+i*2)&lt;br /&gt;
        potImage = Image.open(pot)&lt;br /&gt;
        flag.paste(potImage,(j*225,i*225))&lt;br /&gt;
flag.save(&amp;#039;./flag.png&amp;#039;)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
扫码后得到一串16进制字符串&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;03f30d0ab8c1aa5....74080006030908&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
开头&amp;lt;code&amp;gt;03f3&amp;lt;/code&amp;gt;为&amp;lt;code&amp;gt;pyc&amp;lt;/code&amp;gt;文件的头，恢复为&amp;lt;code&amp;gt;python&amp;lt;/code&amp;gt;脚本后直接运行得到flag&lt;br /&gt;
&lt;br /&gt;
== 时间轴 ==&lt;br /&gt;
&lt;br /&gt;
GIF文件每一帧间的时间间隔也可以作为信息隐藏的载体。&lt;br /&gt;
&lt;br /&gt;
例如在当时在XMan选拔赛出的一题&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;XMAN-2017:100.gif&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
通过&amp;lt;code&amp;gt;identify&amp;lt;/code&amp;gt;命令清晰的打印出每一帧的时间间隔&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;$ identify -format &amp;quot;%s %T \n&amp;quot; 100.gif&lt;br /&gt;
0 66&lt;br /&gt;
1 66&lt;br /&gt;
2 20&lt;br /&gt;
3 10&lt;br /&gt;
4 20&lt;br /&gt;
5 10&lt;br /&gt;
6 10&lt;br /&gt;
7 20&lt;br /&gt;
8 20&lt;br /&gt;
9 20&lt;br /&gt;
10 20&lt;br /&gt;
11 10&lt;br /&gt;
12 20&lt;br /&gt;
13 20&lt;br /&gt;
14 10&lt;br /&gt;
15 10&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
推断 &amp;lt;code&amp;gt;20 &amp;amp;amp; 10&amp;lt;/code&amp;gt; 分别代表 &amp;lt;code&amp;gt;0 &amp;amp;amp; 1&amp;lt;/code&amp;gt;，提取每一帧间隔并进行转化。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;shell&amp;quot;&amp;gt;$ cat flag|cut -d &amp;#039; &amp;#039; -f 2|tr -d &amp;#039;66&amp;#039;|tr -d &amp;#039;\n&amp;#039;|tr -d &amp;#039;0&amp;#039;|tr &amp;#039;2&amp;#039; &amp;#039;0&amp;#039;&lt;br /&gt;
0101100001001101010000010100111001111011001110010011011000110101001101110011010101100010011001010110010101100100001101000110010001100101011000010011000100111000011001000110010101100100001101000011011100110011001101010011011000110100001100110110000101100101011000110110011001100001001100110011010101111101#&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
最后转 ASCII 码得到 flag。&lt;br /&gt;
&lt;br /&gt;
== 隐写软件 ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/matthewgao/F5-steganography F5-steganography]&lt;/div&gt;</summary>
		<author><name>127.0.0.1</name></author>
	</entry>
</feed>