16

记一次VMware的崩溃调试分析过程

 3 years ago
source link: https://www.freebuf.com/vuls/249722.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一.研究背景

VMware Workstation是一款主流的虚拟机软件,近期启明星辰ADLab安全研究员在使用VMware虚拟机的过程中遇到虚拟机异常崩溃的问题,当从7zip中直接将文件拖拽到VMware虚拟机中,会造成虚拟机异常关闭。目前已测试过VMware 15.5.0、15.5.2、15.5.5 以及7zip 19.0、20.02等版本。本文将通过对VMware和7zip程序进行跟踪分析,最终定位虚拟机异常关闭原因。

二.VMware端调试分析

使用WinDbg-I指令将WinDbg设置为即时调试器,VMware-vmx.exe程序崩溃后自动弹出WinDbg。堆栈信息如下:

ZbQRjy.jpg!mobile

调试信息显示stack buffer overrun异常,最初推断可能是缓冲区溢出漏洞。

Rr2UZfy.jpg!mobile

通过查询资料后发现,从Windows 8开始,Windows设计了一个新的中断INT 29H,用以快速抛出失败,在sdk中被声明为__fastfail, __fastfail内部函数不会返回。

A7VJFvA.jpg!mobile

在上图中,程序终止于int 29h,而它的参数为0xa,对应FAST_FAIL_GUARD_ICALL_CHECK_FAILURE,由此推断问题可能出现在CFG的检查过程中。

RrIBZvZ.jpg!mobile

从函数调用栈中vmware_vmx+0x58b21地址向上追溯,动态调试程序,比较程序正常运行与异常崩溃的函数调用区别,定位到与程序崩溃相关的函数sub_1400965A0。

使用Windbg Attach vmware-vmx.exe程序,在sub_1400965A0函数设置断点,开始动态调试。从7z打开的压缩文件中拖拽cdp.pcapng的文件,程序在断点处停下。通过动态调试可知该函数中calloc分配了三个堆空间,分别用于存放:主机临时文件路径temp_path、目标文件名file_name以及VMware中的缓存目录名vm_cache_dir_name。

URrEvun.jpg!mobile

但是打开主机Temp目录下却没有发现该文件,于是初步断定这是程序崩溃原因。继续往下看,3个文件相关参数全都传入了sub_140579b30函数。

fYZFbaQ.jpg!mobile

进入函数sub_140579b30,定位temp_path参数的处理。其中,sub_14057FF90函数对传入的temp_path进行了逐一遍历,sub_1405B2080函数对传入的temp_path进行了非法性检查。下面重点分析sub_140576460函数。

yARvmqN.jpg!mobile

sub_140576460函数将路径参数temp_path传入了sub_14049DA50。

UZzumqU.jpg!mobile

首先,函数sub_14049DA50通过sub_140477C70对字符串进行了处理。然后,调用wstat64获取相应路径的文件状态,如果成功获取则保存到一个结构体中,否则返回0xffffffff。由于Temp目录下并未发现备份文件,导致获取状态失败,从而返回0xffffffff。

byQjayQ.jpg!mobile

UBNje27.jpg!mobile

返回0xffffffff后,重新回到sub_140579b30函数中,程序跳出while循环到达如下位置,输出错误信息并跳转至sub_140572A70。

VjMfuyF.jpg!mobile

从sub_140572A70最终执行到sub_1400960C0,到达如下位置将vmware_vmx+0xb1ed90处的值赋给了rsi,即为0。

UzqeM3Y.jpg!mobile

继续往下执行,将rsi中0值赋值到rax中,然后调用0x7ff8fab0c510处,即ntdll!LdrpDispatchUserCallTarget。

qAZRnmv.jpg!mobile

此处与静态下的过程有一点不同,静态下该处调用如下:

1601604571570.jpg!mobile

如果按照静态过程执行,应当到达sub_1407C7650,即如下位置:

R36zMf3.jpg!mobile

在ntdll.dll被加载之前,该处数据依旧为上图所示地址:

VR7ZNv.jpg!mobile

后来在ntdll.dll中实施CFG(ControlFlowGuard)保护机制,将vmware_vmx+0x7c9668地址处数据进行了改写,从而执行到ntdll!LdrpDispatchUserCallTarget中。

IF7B3ar.jpg!mobile

在ntdll!LdrpDispatchUserCallTarget函数中,取r11+r10*8处的值赋值给r11时出现了问题,该地址为空,就造成了空指针引用,从而执行了int 29h,造成异常。然而,即使没有CFG机制,程序也会在执行“jmp rax”处崩溃,通过下图可以看出,CFG机制仅仅是在原本程序跳转指令前添加了一些检查。

Jb6ZV32.jpg!mobile

uQnyaiU.jpg!mobile

至此,VMware崩溃的原因基本分析清楚了。另一个疑问是,为什么7zip已经在系统Temp下生成了文件,并且VMware也已经获取到了路径参数,却在移动前自动删除了文件呢。这就需要从7zip中寻找答案。

三. 7zip端调试分析

由上一节分析可知,Vmware crash原因是Temp目录下文件被删除。阅读7zip源码,锁定了CPP/Windows/FileDir.cpp中的文件删除函数。

VF3YfqN.jpg!mobile

使用WinDbg加载7zip,然后在Remove函数位置进行下断,程序运行后进行拖拽操作,在Remove函数中断后对应的调用堆栈如下所示。

AjAfAvq.jpg!mobile

堆栈中7zFM+0x5b212地址位于函数CPanel::OnDrag中,该函数为鼠标拖拽操作函数。当检测到对7zip打开的目录进行操作时,便会在Temp目录下生成一个以7zE开头的随机命名文件夹。

NZNbQvq.jpg!mobile

然后,将该文件夹设置为目标目录,并且设置了一些数据及IpDropSourse结构体。

f2QjYfN.jpg!mobile

继续往下可以看到一个DoDragDrop函数,该函数功能是进行OLE拖放相关操作,通过检测光标的行为分别调用一些方法并返回对应的数值。

InQrIna.jpg!mobile

然后,根据DoDragDrop函数的返回值来判断光标的拖拽是否有效,从而执行对应的操作。

amemIbM.jpg!mobile

aARZrq.jpg!mobile

从7zip中拖拽文件到虚拟机,由于无法获知文件拖拽的目标路径,因此DoDragDrop会返回DRAGDROP_S_CANCEL(0x40101),不会执行拷贝操作的分支,而是直接将Temp目录下生成的临时目录删除。

Qz63uyV.jpg!mobile

四.小 结

7zip压缩包中文件拖拽操作会触发DoDragDrop函数调用,该函数会获取文件数据及光标停止的位置。但是将文件拖拽到VMware窗口时,DoDragDrop函数不能获取准确的目标路径,因此无法将文件拷贝到目标位置,从而直接删除临时文件,最终导致VMware无法获取文件状态造成崩溃。

参考链接:

[1]https://0cch.com/2016/12/13/int29h/
[2]https://docs.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-dodragdrop
[3]https://github.com/kornelski/7z/tree/20e38032e62bd6bb3a176d51bce0558b16dd51e2

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK