最近一直在研究加密,一层一层加进去,终于对swf结构算有了一个清晰的认识,本回合重点说文件头的解析
为了引起大家的性趣,先引用前辈的一个例子吧
上边是一个swf导出类查看器,拿到类名 导出素材不难,如何通过解析tag 导出类名是个学问…
下边开始正文
SWF文件格式规范
适合屏幕显示——需要适合屏幕显示同时支持抗锯齿。能够快速渲染各种颜色格式的位图、
动画和交互按钮。(ps:比如ARGB、RGBA 等)
易于扩展——使用标签格式,让他能够很容易保证与Flash Player 之前的版本兼容同时又能
够随意扩展新的特性。
方便网络传输——要能够在有限或者不确定的带宽下传输。文件使用压缩来减少尺寸同时支
持流式渲染。采用的是二进制格式的标签而不是像HTML 一样的可读性标签,同时使用了bitpack(ps:相当于内置一些编译好的二进制)和标记位结构(structures with optional
fields)的技巧来让文件跟小。(ps: 标记位结构表示用一个字节中的某几个位来作为标记,比如:某字节的二进制位:10001010,最高位的为1 表示某个标记位true,如果为0 表示某个标记位false)
简单——这种格式需要尽量简单以使他的播放器小一点容易实现。同时他还必须尽量少依赖
操作系统的特性,方便跨平台。
文件独立——这种文件的现实不要依赖像字体这样外部的资源
可伸缩性——在有限硬件条件下能够运行,同时在硬件条件好的情况下能够充分发挥硬件优
势。这一点很重要因为计算机有不同的显示分辨率和处理能力。
迅速——高速、高质量的渲染。
脚本实现——这种格式包含各种标签,标签提供堆栈机解释需要的字节码。字节码支持
ActionScript 语言。Flash Player 提供运行时的ActionScript 对象模型允许Flash Player 的图
元、服务交互。
OK 理论与实践相结合,下面我们用一个二进制查看器(我用的是HWorkS32,大家google之,很容易下载)查看一个最简单的swf
图一
好了,上图就是一个普通的swf用HWorkS32打开的效果,下面开始穿插理论
SWF文件头
所有的SWF
文件都由文件头开始。
(类型中U
表示无符号,I
表示整型。下面的UI8
表示占8
位二进制的无符号整型,其实就是16进制的两个字节)
图二
文件头都是由三个字节开始的0x46,0x57,0x53(“FWS”);或者0x43,0x57,0x53
(“CWS”)。FWS
表示文件没有压缩,CWS
表示第8
个字节后面是经过ZLIB
开放标准压
缩的(文件长度字段后面)。SWF6
之后的版本才开始使用压缩。
版本号占一个字节紧跟在标志之后。版本数字不是一个ASCII
字符而是一个8
位的数
字。例如SWF4,版本号字节为0x04,而不是ASCII
字符“4”(0x35)。
文件长度字段记录SWF
文件的总长度,包括文件头。对于未压缩的swf
文件(标志位
FWS),文件长度字段的数值跟该文件长度一致。而对于压缩的swf
文件(标志为CWS),
文件长度字段的长度表示第8
个字节之后的数据解压缩之后的长度。(ZLIB
标准)
显示尺寸字段定义了屏幕显示的宽度和高度。这个字段使用一个RECT
结构来存储(一
种可变长度的存储结构,详细信息看swf_file_format_spec_v10中基本数据结构中对于RECT
的介绍),这表示它的占位长度会根据bits
的描述来随时改变。显示尺寸字段的RECT
结构的Xmin
和Ymin
通常为0;Xmax
和Ymax
定义宽度和高度。
帧速字段定义了每秒的播放速率。这个速率无法绝对保证,比如CPU
忙的时候或者慢
的时候。
帧总数定义了SWF
文件的总帧数。(ps:注意到没有?只有16
位,那么帧总数的极限只
能是65535
帧了)
大家看图一中我红线圈出来的东东,很显然,这是一个压缩过的swf(CWS),SWF的压缩方式 使用的是标准的ZLIB压缩的,(FP11出测试版了,改用LAMA了,据说压缩率提高40%)
Adobe默认会对生成的swf进行压缩的
,压缩过的是CWS,未压缩的是FWS,上图中(图二)有说明,这里
有一点补充
压缩过的swf =
(CWS+文件版本+文件版本)
+
压缩的内容
这个我们后边用bytearray解压会用到
在理论不太充足的情况下我们还是用工具解压,OK,SWF Compressor,这个工具google之也很多,专门用于flash压缩解压,很容易用明白,这里不赘述
解压后的文件我们继续用HexWorkstop打开,如下图
好吧
,文件头的说明我在上边做了标注,下边是开始逐个解析
首先: 前面 8 字节
数据 |
含义 |
43 |
“F”,表示未压缩的 |
57 |
“W” |
53 |
“S” |
0a |
SWF文件版本为10 |
44 |
文件大小为 0×00000344=836字节(注意44跟33调换位置) |
接着分析 70 00 09 60 00 00
4B 00 00:
第一个 字节 70
= 01110000
取 前5位 01110
= 14 表示定义位数
我们在重新算一下需要的数组数,5(定义位数)+(xmin,xmax,ymin,ymax)×14(定义位数的值)=61,61/8=
7.625
也就是要取8个字节(这里两位十六进制算一个字节,区别与常规的字节)
接着 要 取 8 位
读取 70 00 09 60 00 00 4B
00
换成2进制 : 0111
0000 0000 0000 0000 1001 0110 0000 0000 0000 0000 0000 0100 1011
0000 0000
接着按位排列下: 01110+
00000000000000(xmin)+
01001011000000(xmax)
+00000000000000
(ymin)+00100101100000(ymax)+
000
代表的意义: (定义位数5)+(xmin=0) (xmax=4800) (ymin=0)
(ymax=2400) +(多余的)
得到的值 width
= (xmax-xmin)/20 ; height =
(ymax-ymin)/20;
说明:SWF文件格式中所有的x-y
坐标信息都被存为整数,计量单位称作缇(twips)。在SWF
中,1缇是1/20个逻辑像素
最后得到的 SWF 文件的尺寸大小:240×120;
接着是帧频:00
18 ,表示帧频为 24
然后是帧数:01
00 ,这个也要倒序来算 所以是 00
01,是1帧
下边是我用AS3写的一个解释文件头的代码,大家参考之,需要对ByteArray有一定的了解
public
function
ByteArrayTest()
{
vartempByteArray:ByteArray
=
new
TestSwf();
//是否
压缩
var
compressed:String = tempByteArray.readUTFBytes(3);
//swf
版本
_version = tempByteArray.readByte();
//文件长度
var
length:uint = tempByteArray.readUnsignedInt();
tempByteArray.readBytes(_swfByteArray);
//判断文件格式
是否解压
if(compressed
== COMPRESSED)
{
_swfByteArray.uncompress();
}
//这个很重要,通过这个设置可以反顺序读取双字节字符串,例如
44 11 读完之后是11 44 详细内容百度之
_swfByteArray.endian = Endian.LITTLE_ENDIAN;
//
解析swf 宽度 高度 数据 rect 数据
_swfSize =
_swfByteArray.readUnsignedByte()>>3;
_swfByteArray.position =
Math.ceil(5+(_swfSize*4)/8);//
计算 rect 结束位置
_frameRate = _swfByteArray.readShort()/256;//读取帧频
因为低8位是小数,所以需要除以2的8次方
_frameTotal = _swfByteArray.readShort();//读取
总帧数
trace(“compressed:”,compressed,“swf_version:”,_version,“frameRate:”,
_frameRate,“frameTota:”,_frameTotal);
}
通过这个方法能够输出swf文件头的大部分信息
OK
,本回合到此结束,关于Tag的解析,且听下回讲解
参考资料
http://rcant.com/wordpress/archives/260
http://www.swfdiy.com/?p=675
swf_file_format_spec_v10.pdf
avm2overview.pdf
原文地址:http://blog.sina.com.cn/s/blog_6859df370100wsv2.html
人生没有失败,只有自我放弃;只要不放弃,梦想总有一天会变成现实。
最新评论