H ow T o D ecompile Actionscript Code I n Swf
Author: xy7 [80sec]
EMail: xy7 #80sec.com /xuanmumu@gmail.com
Site: h ttp://www.80sec.com
Date: 2009- 7 -2 7
[ 目录 ]
0 x 00 前言
0 x 01 swf 文件头分析
0 x 02 swf 文件结构
0 x 03 swf tag类型
0 x 04 寻找Actionscript代码
0 x 05 还原带有变量的AS代码段
0 x 06 总结
0x07 代码示例
0x00 前言
随着 F lash 的应用越来越广泛,针对 F lash 的安全性问题也被人们所重视。 通过提取 Flash 文件中的 AS 代码,可以进行恶意行为检测(网马分析),代码安全性分析( HP 的 SWFSCAN )或者针对 AS 代码中出现的 URL 进行进一步检测分析( APPSCAN )。本文只是一篇工作笔记,通过实现一个简单的 Swf Decompiler 来提取 SWF 文件中的 AS 代码。
0x01 swf 文件头分析
首先新建一个 flash 文件,默认大小,背景,无任何其他元素,只添加一个 geturl 函数,里面随便写上一个链接 http:// 1.1.1 .1 。这个新创建的 flash 文件就作为我们的分析对象。
SWF 文件头格式如下 :
SWF File Header
Field Type Comment
Signature UI8 Signature byte:
“ F ” indicates uncompressed
“ C ” indicates compressed (SWF 6 and later only)
Signature UI8 Signature byte always “ W ”
Signature UI8 Sig nature byte always “ S ”
Version UI8 Single byte file version (for example, 0x06 for SWF 6)
FileLength UI32 Length of entire file in bytes
FrameSize RECT Frame size in twips
FrameRate UI16 Frame delay in 8.8 fixed number of frames per second
FrameCount UI16 Total number of frames in file
UE 打开 新建的 flash 文件,首先读前三个字节, 46 57 53 =FWS ,说明该文件是未经过 zlib 压缩 。
下一个字节是代表 flash 的版本, 0a = 10 。
继续后四个字节代表 flash 文件的大小 4E 05 00 00 ,这里需要转成大尾存储 0000054e=1385bytes 。
接下来是 flash 的尺寸,这里定义了一个 RECT 结构用来存储这些数据 。
RECT 结构如下:
RECT
Field Type Comment
Nbits UB[5] Bits in each rect value field
Xmin SB[Nbits] x minimum position for rect
Xmax SB[Nbits] x maximum position for rect
Ymin SB[Nbits] y minimum position for rect
Ymax SB[Nbits] y maximum position for rect
继续往后读 1 个字节 78 ,转换成 2 进制补齐 8 位 78=01111000 ,根据 RECT 的格式取前五位 01111=15 ,表示剩下的数据要按每 15 位进行划分,由于还剩下 4 组数据要表示,所以需要 60 位, 60 位至少需要读 8 个字节,所以 RECT 结构需要的字节数为 00000008h: 78 00 05 5F 00 00 0F A0 00 ,都转为 2 进制进行 15 位分割,最后不足 15 位的舍去,最后得出的结果为 twip ( 20twip=1 像素),所以最后输入应该是这样:
01111
000000000000000
010101011111000
000000000000000
001111101000000
RECT binary value:0
RECT binary value:550
RECT bi nary value:0
RECT binary value:400
接下来 2 个字节代表帧速 00 18 =>18 00 =>24
最后 2 个字节代表帧数 01 00 =>00 01 => 1
至此, swf 文件头就结束了。
0x02 swf 文件结构
S wf 文件主体是由一连串的 tag 组成,最终以一个 end tag 为结尾。大概结构如下:
[ 文件头 ]---[ FileAttributes ]---[tag]---[tag] … [end tag]
| |
[tag typ e] [tag type]
| |
[tag data] [tag data]
0x03 swf tag 类型
根据 tag 头可以将 tag 分为短 tag 和长 tag ,具体格式如下:
RECORDHEADER (short)
Field Type Comment
TagCodeAndLength UI16 Upper 10 bits: tag type
Lower 6 bits: tag length
RECORDHEADER (long)
Field Typ e Comment
TagCodeAndLength UI16 Tag type and length of 0x 3F
Packed together as in short header
Length SI32 Length of tag
也就是说高 10 位都代表着 tag 类型,后 6 位如果长度大于等于 0x 3f 则为长 tag ,其余的则是短 tag 。
按 tag 类型来分, tag 也可分做 2 类: Definition tags 和 Control tags 。其中 Definition tags 主要包含了 flash 中的文本,声音,图像等资源,而 Control tags 则包含了一些文件的处理流程等控制元素。
既然已经分清楚了 swf tag 类型,那么就可以进一步分析 tag 以寻找我们需要的 AS 代码。
文件头已经分析完毕,接下来就来分析第一个 tag : FileAttributes 。继续上面的例子,到了分析 tag 的时候依次读 2 个字节: 44 11 =>11 44 => 0001000101000100 => 0001000101 ( 高 10 位 ) => 69, 在 swf 文件格式中查找 Tag type = 69 ,正是 FileAttributes ,接着低 6 位代表 tag 长度: 000100 =>4 ,向后再读 4 个字节: 10 00 00 00 => 00 00 00 10 =>16 => 00010000 , 这段数据就是 FileAttributes tag 的数据内容了, FileAttributes tag 到此结束。数据可以对照着 FileAttributes 数据结构来看,结构比较长就不贴出来了,其中第 4 位是 1 ,表明这个 flash 中含有 matadata ,继续往后读 2 个字节 7F 13 ,按位 取 高 10 位 =77 。
Metadata
Field Type Comment
Heade r RECORDHEADER Tag type = 77
Metadata STRING XML Metadata
低 6 位全为 1 ,所以说 matadata 是第一个长 tag ,长 tag 需要 4 个字节来表示数据长度,这些数据对实际分析没有什么作用,所以分析出数据长度就可以跳过了。
0x04 寻找 Actionscript 代码
通过前面 2 个 tag 的分析,已经能够清楚的知道 swf tag 的固定格式以及取数据的方法了,那么我们定义的 AS2 中 geturl 函数到底存在哪里呢?继续读下 2 个字节: 3f 03 => 03 3f , 取高 10 位 0000001100 =>12 ,这个 12 是什么意思呢 , 查 swf 文档:
DoAction
Field Type Comment
Header RECORDHEADER Tag type = 12
Actions ACTIONRECORD [zero or more] List of actions to perform (see
following table, ActionRecord)
ActionEndFlag UI8 = 0 Always set to 0
注意 ACTIONRECORD
Fie ld Type Comment
ActionCode UI8 An action code
Length If code >= 0x80, UI16 The number of bytes in the
ACTIONRECORDHEADER, not
counting the ActionCode
现在可以确定 ActionCode 是包含在 Actions ACTIONRECORD 中, Actions ACTIONRECORD 又是属于 DoAction 。判断低 6 位得知 DoAction 是长 tag ,继续读后面 4 个字节来确定 DoAction 的数据长度: 1A 00 00 00 =>26 。至此就可以判定我们之前建立的 AS 代码就包含在这 26 个字节中。接下来根据 ACTIONRECORD 的定义, 1 个字节代表 ActionCode ,继续读: 83 ,查找 swf 文档:
Field Type Comment
ActionGetURL ACTIONRECORDHEADER ActionCode = 0x83
UrlString STRING Target URL string
TargetString STRING Target string
找到了我们定义的 geturl 函数,所以继续读下面 2 个字节 16 00 =>00 16=>22 ,那么这 22 个字节就是 geturl