友情提示: 本文分析的是真实样本,请各位实验时千万千万不要在物理机上操作,务必使用虚拟机,并断开网络连接。
1.  目的
写这篇文章的目的是想简单介绍一下Flash样本分析的流程,以及一些分析Flash样本常用的工具包括自己写的小程序。
本文涉及的内容包括:Flash文件的提取、结构查看、ActionScript的反汇编和反编译、ActionScript中shellcode的定位和提取、shellcode调试。
本文不会涉及对漏洞成因进行分析调试的相关内容。
2.  使用的样本
本文中使用是一个利用CVE-2012-0754漏洞的Flash样本,还算是比较新的Flash漏洞样本。
样本来源是:ContagioDump
这里向大家推荐一下这个blog,该blog经常会放出一些最新的病毒样本,仔细挖掘的话还能找到一些样本的合集,非常有用。
不过国内应该无法直接访问,需要翻墙先。懒得翻墙的同学,我把样本打包传到附件里了,可以直接下载附件。
3.  从Doc中提取Flash文件
下载样本解压后,原始样本在original文件夹中,名为“Iran's Oil and Nuclear Situation.doc”。
等等,不是Flash样本吗,怎么是doc文件?你可能在想LZ是不是发错链接了。
其实真正的Flash样本是嵌在这个doc文件中的,这种手法并不是第一次被使用了,当年CVE-2010-0609(没记错的话)样本也是嵌在Excel文件里流出的。
打开word文档的话最后会有一只貌似熊(??)的谜样生物对你说“Hi~”,LZ觉得好诡异。。。
clip_image001


用16进制编辑器打开word文档,可以看到该文件是OLE SS格式的Office文件,
这种情况下,一般直接搜索字符串“FWS”(未压缩的SWF头部特征)和“CWS”(压缩过的SWF头部特征)就可以定位其中的Flash文件。
clip_image002
我写了一个python小脚本,用来从Office文档中提取内嵌的Flash文件,名为extract_swf.py,使用方式如下:

Code:

extract_swf.py   [office文件路径]

本例中我们这样使用:

Code:

C:\CVE-2012-0754_E92A4FC283EB2802AD6D0E24C7FCC857\original\extract_swf>extract_s
wf.py     "C:\CVE-2012-0754_E92A4FC283EB2802AD6D0E24C7FCC857\original\Iran's Oil and
Nuclear Situation.doc_"

输出如下:

Code:

extract_swf.py 1.0
[+] Searching embeded swf file in C:\CVE-2012-0754_E92A4FC283EB2802AD6D0E24C7FCC
857\original\Iran's Oil and Nuclear Situation.doc_
[+] Find embeded swf file at offset 0x2e08
[+] Save embeded swf file to C:\CVE-2012-0754_E92A4FC283EB2802AD6D0E24C7FCC857\o
riginal\Iran's Oil and Nuclear Situation.doc__offset_0x2e08.swf=

可以看到提取出来的Flash文件被命名为“Iran's Oil and Nuclear Situation.doc__offset_0x2e08.swf=”,这个就是真正样本文件了。
4.  使用SWF Investigator查看Flash文件信息
下面要重点介绍的是Adobe Lab发布的一款名为SWF Investigator的工具。
功能十分强大,可以查看Flash文件结构、反汇编ActionScript、编译ActionScript、直接运行flash、甚至可以用来Fuzz Flash文件。
是不是有点心动了呢,猛击如下链接下载吧:[下载SWF Investigator]
使用SWF Investigator时需要先安装Adobe AIR,可以从这里下载:[下载Adobe AIR]
将前面提取出来的SWF文件拖到SWF Investigator中,就可以查看各种信息了。
点击“Tag View”可以查看各个标签,其中DoABC2标签中包含ActionScript 3.0字节码。
选中DoABC2标签后,可以在右侧窗口中看到反汇编后的ActionScript代码,下图中一连串的pushint…writeInt其实是在做heap spray。
clip_image003
直接看字节码有点吃力,这时我们需要一个ActionScript 3.0的反编译工具。
5.  反编译ActionScript脚本
这里使用的工具是AS3 Sorcerer,下载地址为:http://www.as3sorcerer.com/
也可以使用Sothink Flash Decompiler,不过这两款都是商业软件。免费软件的话可以试试HP的SWF Scan,效果还可以,但是有时会反编译出错误的源代码。
将前面提取出的SWF文件拖入AS3 Sorcerer,可以看到反编译后的源码。附件中的CVE-2012-0754.as3包含完整的源代码。
ActionScript 3.0和JavaScript都基于ECMA标准,基本上能看懂JavaScript的样本就能看懂ActionScript的样本。
clip_image004
通过分析源代码可以看出,这里的_local2变量中包含shellcode数据。
_loca2写入shellcode的流程如下:
1.首先定义_local2,类型为为ByteArray(字节数组)
2.使用一系列的writeInt函数调用写入数据
3.调用自定义的Encrypt2函数解密出真正的shellcode。
相关代码整理如下:

Code:

var _local2 = new ByteArray();
_local2.endian = Endian.LITTLE_ENDIAN;
_local2.writeInt(2590463591);
_local2.writeInt(213916234);
_local2.writeInt(3076656754);
_local2.writeInt(1088421207);
_local2.writeInt(700118367);
……………………
Encrypt2(_local2);

下面我们需要提取出解密后的shellcode数据,有如下选择:
1.读懂整个逻辑包括Encrypt2函数,使用自己熟悉的编程语言还原整个逻辑,得到shellcode数据。
这种方法的缺点在于,如果shellcode生成逻辑非常复杂,还原成其他语言的难度会很大。
2.直接执行相应的ActionScript,打印出shellcode数据
这里我们将介绍第二种方法。
6.  使用SWF Investigator编译执行ActionScript
SWF Investigator包含了而一个很强大的工具叫AS3 Compiler,可以编译和执行ActionScript 3.0脚本。
选中菜单中的Utilities => AS3 Compiler就可以调出这个工具。
下面我们开始准备要运行的脚本,首先加入如下代码:

Code:

namespace ns = "utils.AS3Compiler";
use namespace ns;
namespace nu = "flash.utils"
use namespace nu;
var HexChr:Array=new Array();
HexChr[0] = '0';HexChr[1] = '1';HexChr[2] = '2';HexChr[3] = '3';HexChr[4] = '4';HexChr[5] = '5';HexChr[6] = '6';HexChr[7] = '7';HexChr[8] = '8';HexChr[9] = '9';HexChr[10] = 'A';HexChr[11] = 'B';HexChr[12] = 'C';HexChr[13] = 'D';HexChr[14] = 'E';HexChr[15] = 'F';
public function Bin2HexString(arr:ByteArray):String
{
    var str = "";
  var len = arr.length;
  var i = 0;
  while (i < len) {
      var b = arr[i];
    str += HexChr[(b >> 4) & 0xf];
    str += HexChr[b & 0xf];
    i ++;                           
  }
  return str;
}

上面的代码定义了一个用于将字节数组的数据转化成16进制编码(hex encode)字符串的函数。
下一步需要把和_local2相关的代码和Encrypt2函数的代码复制进来,注意去掉Encrypt2函数定义中的“static”属性。
最后加入如下代码来打印出_local2中的数据:

Code:

Printer.print(Bin2HexString(_local2));

完整的代码在附件中的compile.txt中,大家可以自行查看。
将完整的代码拷贝到AS3 Compiler左边的源码窗口中,点击compile进行编译,再点击Run运行,就可以在右边的输出窗口中看到shellcode的16进制编码数据了:
clip_image005
7.  调试shellcode
将前面输出地shellcode字符串在转换成二进制数据(附件中的sc.bin),就可以开始调试了。
调试shellcode大家各有各的工具和方法,我使用的是自己写的一个名为ShellcodeDbg小工具。
用什么工具调无所谓,唯一要注意的是,在调试文档类shellcode时需要在调试进程中先打开原始文档,并保留这个原始文档的句柄,理由接下来会说明。
将OllyDbg设置为即时调试器,运行ShellcodeDbg.exe   “sc.bin”  “Iran's Oil and Nuclear Situation.doc”,会有一个Int3断点命中,唤起OD。
跳过这个Int3断点后,单步几下,最后一个jmp eax会跳到shellcode代码出。
Shellcode一开始无非是解密,获取API地址等例行公事,接着可以看到这样一个循环:

Code:

00343E1B    33DB            xor     ebx, ebx
00343E1D    83C3 04         add     ebx, 4
00343E20    6A 00           push    0
00343E22    53              push    ebx
00343E23    FF57 FC         call    dword ptr [edi-4]   ; kernel32.GetFileSize
00343E26    3B07            cmp     eax, dword ptr [edi]// edi=01a06c,即原始doc文件的大小
00343E28  ^ 75 F3           jnz     short 00343E1D

上述代码循环测试文件句柄值(从4开始),并使用对应句柄值来调用GetFileSize,并查看返回的size是不是等于01a06c(原始doc文件的大小),找到了合适的句柄才会继续运行。
这是文档类样本shellcode的常见行为,因为很多时候原始文件中包含进一步的shellcode或者PE文件数据,shellcode需要从中提取这些数据。
这就是为什么我们一开始讲要打开并保留一个原始文档句柄的理由了。
shellcode之后的代码,以及随后生成的PE文件的行为这里就不讲了,有兴趣的同学自己玩吧。

转自古河博客http://blog.sina.com.cn/s/blog_6fc131560100y8nd.html

看雪论坛链接: http://bbs.pediy.com/showthread.php?t=147686

源链接

Hacking more

...