最近,遇到的一个Word文档引起了我的注意,因为它一看就是一个恶意文档。它奇葩的地方在于,注释内容五花八门,从随机的变量名称到流行歌词,应有尽有。最重要的是,在从宏指令向机器码转移控制权的时候,它使用了一种非常罕见同时也非常酷的方法。
分析宏指令
宏指令的开头部分,创建许多指向已被Word载入内存中的DLL导出函数的指针:
'Run from the noise of the street and the loaded gun
Public Declare Function whitworth Lib "kernel32.dll" Alias "VirtualAllocEx" (castroism As Long, accidence As Long, ByVal graze As Long, ByVal footstool As Long, ByVal vicariate As Long) As Long
'Life can be so cruel
Public Declare Sub intermission Lib "ntdll.dll" Alias "RtlMoveMemory" (septentrional As Any, ByVal ploy As Any, ByVal cinders As Long)
'Every time you give yourself away
Public Declare Function bruckenthalia Lib "kernel32.dll" Alias "EnumTimeFormatsW" (ByVal khartoum As Any, ByVal grinding As Any, ByVal fie As Any) As Long
'So run my baby run my baby run
Public Declare Function briefcase Lib "user32" Alias "SetParent" (ByVal anomalousness As Long, ByVal chewink As Long, advert As Long) As Long
'Run my baby run my baby run
Public Declare Function ex Lib "user32" Alias "GetUpdateRect" (drakes As Long, lubricitate As Long, pelham As Long) As Boolean
'You can keep it pure on the inside
Public Declare Function charioteer Lib "user32" Alias "EndPaint" (guttling As Long, cervical As Long) As Long
'You can keep it pure on the inside
Public Declare Function gigartinaceae Lib "user32" Alias "OpenClipboard" (enliven As Long) As Boolean
'You can keep it pure on the inside
Public Declare Function malnourished Lib "kernel32.dll" Alias "Sleep" (subsequent As Long)
这里要特别注意函数指针whitworth和bruckenthalia,因为它们允许宏指令以相应的权限分配内存(VirtualAllocEx),然后跳转到分配的内存区并执行任意代码。
VirtualAllocEx的作用是显而易见的,因为宏代码使用它返回一个指向设置为RWX(读写执行权限)的内存块的指针。
EnumTimeFormatsW更加让人感兴趣,其代码如下所示:
BOOL EnumTimeFormats(
_In_ TIMEFMT_ENUMPROC lpTimeFmtEnumProc,
_In_ LCID Locale,
_In_ DWORD dwFlags
);
这个宏代码可以通过第一个参数来传递指向内存中的任意函数的指针,并在返回时执行它。根据MSDN的介绍:
lpTimeFmtEnumProc [in]
指向应用程序定义的回调函数的指针。有关更多信息,请参阅EnumTimeFormatsProc。
通过跟踪宏代码的执行,我发现whitworth的返回值是一个表示内存位置的长整数,具体来说,是VirtualAllocEx返回的地址:
当然,这个地址可能会有所变化,但这里whitworth返回的是115212288,转换为地址的话就是0x06DE0000。
在调用EnumTimeFormatsW并最终将控制权转移到shellcode之前,这个宏会给该地址加上一个偏移量0xE5D:
在本例中,作为回调函数传递的最终值是115215965,也就是0x6DE0E5D。
下图中突出显示的是已经分配的具有RWX权限的内存段:
这个内存块中的内容是一些看似随机的数据:
由于该回调函数使用了一个0xE5D的偏移量,所以我认为这个位置肯定有代码,那就反汇编看看吧:
这里的断点能够帮我们弄清楚控制权从这个宏那里传过来时会发生什么情况。
Shellcode Harness
为了简化调试工作,可以将这部分内存保存到磁盘,并将其添加到shellcode harness。所谓shellcode harness,就是一个任意的可执行文件,只要它有一个节能够容下这个shellcode(大约12kb)就行了:
这个可执行文件(sc.exe)有一个足以容纳shellcode的.data节。所以,我们可以安全地将shellcode写入到.data节中,然后使用OllyDumpEx插件转储所做的修改,即从内存中导出程序到文件里。
如对本文有疑问, 点击进行留言回复!!
网友评论