恶意代码常见驻留分析
Posted 孤客浪子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了恶意代码常见驻留分析相关的知识,希望对你有一定的参考价值。
前言
恶意代码的一个重要功能就是要实现内存常驻,只要常驻内存,恶意代码就可以一直执行恶意行为,不会因为电脑重新启动、切换用户等原因停止。前文介绍的启动、Hook、注入中的很多技术都可以实现内存常驻,除此之外,恶意代码还可以利用一些系统功能实现内存常驻。本文就与你娓娓道来。
辅助功能
辅助功能介绍
windows提供了一些辅助功能,比如放大镜、讲述人等。Windows的辅助功能又叫做“轻松使用”,你可以在控制面板中查看他们。
这些辅助功能可以在用户登录界面启动,当你在登录界面按下win+U,就会弹出辅助功能的选项。
这些辅助功能分别对应以下进程:
攻击者可以攻击这些辅助功能程序,通过(远程桌面)登陆界面进行未经过身份验证的访问。
对于WindowsXP、WindowsServer 2003 /R2及更低版本操作系统可以通过二进制文件替换进行攻击。例如将utilman.exe替换为“cmd.exe”(或任意恶意程序)。随后,在登录屏幕上按下相应的组合键将导致”cmd.exe”以SYSTEM权限执行。
对于WindowsVista、WindowsServer2008及更高版本的系统无法使用上述方法,因为上述辅助功能在启动前会进行数字签名的校验,但是我们可以利用映像劫持技术启动恶意程序。
除了攻击微软提供的辅助功能,攻击者还可以自定义辅助功能,执行恶意代码。
自定义辅助功能
辅助功能的配置信息都记录在注册表中,注册表项路径:HKLM\\ SOFTWARE \\ Microsoft \\ Windows NT \\ CurrentVersion \\ Accessibility\\ ATs。
下图是放大镜功能的注册表信息:
ApplicationName键:
记录应用程序的名称,形式@<ResDllPath\\ResDLLFilename>,- [ID]
ResDLLFilename是资源DLL的路径;
ID字符串的资源ID;
ATExe键:
应用程序可执行文件或图像的名称;
CopySettingsToLockedDesktop键:
指示是否将辅助功能应用程序的设置复制到锁定的桌面;
Description键:
应用程序的简要说明;
Profile键:
一小段XML,指定应用程序在轻松使用中显示的类别等;
PassiveAutoStartBehavior键:
默认值为0,锁屏或者登录时、开机启动时、运行atbroker.exe时、按下Ctrl+Alt+Del时、触发UAC时均会启动辅助功能程序;
当值为1,则需要进行设置才能启动,在控制面板中可以进行设置。
SimpleProfile键:
简介;
StartExe键:
可执行文件的完整路径;
StartParams键:
命令行参数,这些值与StartExe一起使用以启动应用程序;
TerminateOnDesktopSwitch键:
如果此值不存在或为1,则Windows会在每次进出安全桌面的过渡时终止并重新启动应用程序;
如果此值为0,则Windows不会在桌面转换时终止辅助功能应用程序;
了解了如何配置辅助功能,接下来我们就可以将自定义应用程序注册为辅助功能了。
我们可以通过设置注册表将恶意程序设置为辅助功能程序:
接着配置HKCU\\ Software \\ Microsoft \\ Windows NT \\ CurrentVersion \\ Accessibility\\ Configuration,将malware加入该项
配置该项windows将在安装后立即启动malware应用程序。此外,只要登录桌面处于活动状态,windows就会自动运行您的应用程序。
malware应用程序将会在以下场景中启动:
①锁屏或者登录时
②开机启动时
③运行atbroker.exe时
④按下Ctrl+Alt+Del时
⑤触发UAC时
也可以配置HKLM\\SOFTWARE\\Microsoft\\WindowsNT\\CurrentVersion\\Accessibility\\Session14\\Configuration
配置该项将只能应用于当前会话。
除了配置Configuration注册表项,我们还可以直接使用命令行启动malware程序:
C:\\WINDOWS\\System32\\ATBroker.exe /start malware
ATBroker.exe是专门用于启动辅助功能的应用程序。启动进程监视,然后使用快捷键启动辅助程序(例如放大镜),可以看到辅助程序不是由explorer.exe启动的,而是AtBroker.exe启动(AtBroker.exe由winlogon.exe启动):
MBR
MBR介绍
MBR(MasterBoot Record 主引导记录)位于整个硬盘的0磁道0柱面1扇区,0磁道0柱面1扇区被称作MBR扇区。
计算机通电后最先执行的就是Bios,BIOS进行硬件初始化工作,之后校验启动盘中位于0盘0道1扇区(MBR扇区)的内容。如果此扇区末尾的两个字节分别是魔数0x55 0xaa,BIOS便认为此扇区中确实存在可执行的程序,便加载该扇区到0x7c00,随后跳转到此地址(JMP0:0x7c00),继续执行。
MBR执行优先级非常高,仅次于BIOS,只要控制了MBR就完全控制了计算机。很不幸的是,攻击者很容易就能直接修改MBR扇区数据,完全控制计算机。
修改MBR
使用DiskGenius修改MBR
我们可以直接使用硬盘分析工具查看编辑MBR扇区数据,这里使用DiskGenius工具。
选中磁盘——打开16进制扇区编辑,就可以查看编辑MBR扇区了:
使用代码修改MBR
在操作系统中,可以直接通过名字空间访问物理设备。例如,程序可以直接使用.\\PhysicalDisk0访问计算机的第一个磁盘,于是我们就可以通过.\\PhysicalDisk0修改MBR。
第一种方式:使用C库函数修改MBR扇区:
FILE * fd = fopen("\\.\\PHYSICALDRIVE0", “rb+”);
char buffer[512];
fread(buffer, 512, 1, fd);//可以修改510个字节
fseek(fd, 0, SEEK_SET); //很重要
fwrite(buffer, 512, 1, fd); //把修改后的MBR写入到你的机器
fclose(fd); //大功告成
第二种方式:使用CreateFile修改MBR扇区:
hDevice = CreateFile(TEXT("\\.\\PhysicalDrive0"),//打开磁盘
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
DeviceIoControl(hDevice, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL)
WriteFile(hDevice, pMBR, sizeof(pMBR), &dwBytesWritten, NULL)// 写入病毒内容 DeviceIoControl(hDevice, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
无论使用哪种方式修改MBR,都需要管理员权限才可以。
组件对象模型劫持—COM劫持
COM基础知识
COM——Component object class,组件对象类,简称组件。
在COM构架下,人们可以开发出各种各样的功能专一的组件,然后将它们按照需要组合起来,构成复杂的应用系统。这样的组合方式有很多优点:在系统变更的时候,只需要修改相应的组件就可以了;同一个组件可以在多个应用系统中被重复利用;COM与语言、平台无关,COM库可以被任何语言、进程调用。
在windows中,COM可以是dll、exe、ocx、tle、sct等,他们提供了一些接口,可以被其他程序使用。
COM可以在不同环境下被不同的程序使用,这就需要有一种方式标识COM,保证COM可以全球唯一,而这种标识就是CLSID(classidentifier)——COM组件标识符。
CLSID是采用特殊算法生成的。这种算法被称为UUID标准,它结合机器的网卡、当地时间、一个随即数来生成的128bit的数字,这个数字被称为GUID(GloballyUnique Identifiers)。GUID可能是CLSID也可能是IID,CLSID代表COM组件中的类,IID代表COM组件中的接口。
CLSID的结构定义:
typedefstruct_GUID {
DWORD Data1; // 随机数
WORD Data2; // 和时间相关
WORD Data3; // 和时间相关
BYTE Data4[8]; // 和网卡MAC相关
} GUID;
typedefGUIDCLSID; // 组件ID
typedefGUIDIID; // 接口ID
一个典型的CLSID如下图所示:
所有的CLSID都记录在注册表中,程序就是借助注册表调用COM的。注册表中有三个地方记录着CLSID:
HKCU\\Software\\Classes\\CLSID 用户注册的
HKLM\\Software\\Classes\\CLSID 全系统注册的
HKCR\\CLSID HKCU和HKLM里CLSID的合并
注册表中,LocalServer32键表示可执行(exe)文件的路径、InprocServer32键表示动态链接库(DLL)文件的路径。
我们可以在运行界面(WIN+R)使用CLSID打开相应的程序,如在运行界面中输入::{20D04FE0-3AEA-1069-A2D8-08002B30309D} 或shell::{20D04FE0-3AEA-1069-A2D8-08002B30309D} 就可以打开我的电脑。
我们也可以利用文件夹,将文件夹命名为”name.CLSID”的形式,打开文件夹,就运行了相应的COM
除了我的电脑,有很多常用的标识符:
我的电脑{20D04FE0-3AEA-1069-A2D8-08002B30309D}
我的文档{450D8FBA-AD25-11D0-98A8-0800361B1103}
拨号网络{992CFFA0-F557-101A-88EC-00DD010CCC48}
控制面板{21EC2020-3AEA-1069-A2DD-08002B30309D}
计划任务{D6277990-4C6A-11CF-8D87-00AA0060F5BF}
打印机{2227A280-3AEA-1069-A2DE-08002B30309D}
记事本{1FBA04EE-3024-11D2-8F1F-0000F87ABD16}
网络邻居{208D2C60-3AEA-1069-A2D7-08002B30309D}
回收站{645FF040-5081-101B-9F08-00AA002F954E}
公文包{85BBD920-42A0-1069-A2E4-08002B30309D}
字体{BD84B380-8CA2-1069-AB1D-08000948F534}
Web 文件夹{BDEADF00-C265-11d0-BCED-00A0C90AB50F
“上帝模式”{ED7BA470-8E54-465E-825C-99712043E01C}
CLSID的值是比较难记忆的,ProgID是程序员给某个CLSID指定的一个易记的名字,记录在HKCU\\Software\\Classes\\或HKLM\\Software\\Classes\\中:
COM劫持
COM劫持的原理和DLL劫持差不多,就是在程序读取注册表信息中的DLL或者EXE功能的路径上,做一个拦截,让程序提前读取我们的设置好的恶意DLL或者EXE。
程序在调用COM时,先搜索注册表HKCU\\Software\\Classes\\CLSID,再搜索HKLM\\Software\\Classes\\CLSID。
那么,我们便有了以下几种劫持思路:
①修改注册表中的LocalServer32键或InprocServer32键,修改为我们想加载的dll/exe;
②针对HKLM\\Software\\Classes\\CLSID中存在,而HKCU\\Software\\Classes\\CLSID中不存在的COM,我们可以在HKCU\\Software\\Classes\\CLSID中注册一个同名的COM,并设置为恶意dll/exe;
③注册恶意COM,新建CLSID的文件夹并诱导用户打开;
除此之外我们还有几种劫持思路。
①劫持TreatAs:
“TreatAs”项表示CLSID可以被另一个CLSID模拟,TreatAs指向另一个能够模拟当前CLSID的CLSID,所有的请求都转发给TreatAs中的CLSID,攻击者可以通过添加或修改TreatAs项来劫持合法的CLSID。
②劫持ProgID
有些程序使用ProgID调用COM,这种时候如果我们修改了ProgID键,就能劫持COM了。
③使用script
可以使用scrobj.dll运行远程站点上的sct脚本,利用COM技术,我们也可以执行sct脚本,我们需要设置注册表:
InprocServer32 = C:\\Windows\\system32\\scrobj.dll
ScripletURL = .sct 文件的位置(本地磁盘或URL)
下图是metasploit生成的一个demo:
屏幕保护程序
屏幕保护程序实际上是一个历史遗留问题,远古时代的计算机屏幕如果较长时间内显示相同图像而可导致的图像烧录问题,损害显示屏,于是人们设计了屏幕保护程序。
用户在一定时间内不活动鼠标键盘之后会自动执行屏幕保护程序,屏保程序的后缀名是.scr,但它就是一个标准的可执行文件(PE)
屏幕保护程序的配置信息都记录在HKCU\\ControlPanel\\Desktop中:
各个键的含义:
SCRNSAVE.EXE - 屏幕保护程序可执行文件的路径;
ScreenSaveActive - “1”表示启用屏幕保护程序;
ScreenSaverTimeout - 指定在屏幕保护程序启动之前系统保持空闲的时间;
你可以通过控制面板打开屏幕保护程序,微软提供了几个默认的屏幕保护程序供我们选择。除了微软提供的屏保程序,我们也可以自己编写屏保程序,为了实现屏幕保护程序预览、设置等功能,你需要使用QApplication类型,你可以参考这里(超链接:https://zhuanlan.zhihu.com/p/44993673)编写自己的屏保程序。
一些攻击者会利用屏幕保护程序来维持后门的持久性。
攻击者可以通过注册表设置SCRNSAVE.EXE、ScreenSaveActive、ScreenSaverIsSecure等键值安装屏幕保护程序。
攻击者也可以使用desk.cpl模块安装恶意屏幕保护:
rundll32.exe desk.cpl,InstallScreenSaver c:/win/system/malware.scr
用户登录
用户登录过程
用户的登录过程是从用户登录进程(Winlogon.exe)开始的,当Winlogon收到登录通知时,Winlogon就会调用登录用户界面进程(LogonUI)打开用户登录界面。
在用户登录界面,“凭证提供者”获取用户输入的用户名和密码。“凭证提供者”是位于DLL中的COM对象,默认的是%SystemRoot%\\System32\\authui.dll和%SystemRoot%\\System32\\SmartcardCredentialProvider.dll。
当用户输入账号和密码后,Winlogon调用LSASS的LsaLookupAuthenticationPackage来获取一个指向“认证包”认证包的句柄,调用LsaLogonUser将登录信息传递给认证包。认证包对登录信息进行验证,一旦验证包认证了一个用户,Winlogon便继续登录过程,否则终止登录过程。
然后,Winlogon查看注册表的HKLM\\Software\\Microsoft\\WindowsNT\\CurrentVersion\\Winlogon\\Userinit值,该值是一个字符串,Winlogon创建一个进程来运行该字符串的值(该值可能是几个用逗号隔开的.exe文件)。该值默认是Userinit.exe,Userinit.exe完成一些初始化的工作,管理不同进程的启动顺序。Userinit.exe会查看HKLM\\Software\\Microsoft\\WindowsNT\\CurrentVersion\\Winlogon\\Shell的值,如果不存在该项则查看HKCU\\Software\\Microsoft\\WindowsNT\\CurrentVersion\\Winlogon\\Shell,该值也是一个字符串,默认是Explorer.exe,Userinit.exe启动Explorer.exe。Userinit.exe还会处理登录脚本,注册表HKCU\\Environment\\UserInitMprLogonScript记录登录脚本文件路径。完成一系列引导后,Userinit退出,用户登录过程结束。
认证包——AP和SSP
用户登录过程的身份验证是由LSASS调用认证包完成的。认证包实际上就是一个DLL,它能够执行用户登录信息的验证检查。
认证包一共有两类AP和SSP。AP全称AuthenticationPackages,身份验证包,SSP全称SecuritySupportProvider,安全支持提供程序。当系统在进行交互式登录时使用AP进行登录验证,当系统在进行非交互式登录时使用SSP进行登录验证。需要用户提供账户密码的登录过程就是交互式登录;非交互式登录只能在进行交互式登录后使用,在非交互式身份验证期间,用户不输入登录数据,而是使用先前建立的凭据。
微软提供了两个身份验证包:KerberosSSP/AP和MSV1_0身份验证包。MSV1_0用于本地计算机登录,KerberosSSP/AP用于远程计算机登录。
除了微软提供的认证包,我们也可以实现自定义的认证包。编写自定义的身份验证包可以参考这里(超链接:https://stackoverflow.com/questions/50785694/implementation-of-custom-windows-authentication-package)。
所有的认证包都记录在注册表HKLM\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\中:
其中AuthenticationPackages中记录的就是AP,SecurityPackages 中记录的就是SSP。
可以看到,注册表中还有一个NotificationPackages的键值,这是通知包,是Windows在用户更改其密码时调用的包(DLL)。
攻击AP和SSP注册表
攻击者可以直接将恶意DLL放到注册表AuthenticationPackages/Security Packages/NotificationPackages键里,然后,在用户登录(或修改密码)加载Packages时,系统就会执行恶意dll。
超级火焰病毒Flame(md5:bdc9e04388bda8527b398a8c34667e18)就是利用了此技术,它修改注册表HKLM\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\AuthenticationPackages=mssecmgr.ocx实现内存常驻。但是,利用此技术的恶意程序必须具备认证包的基本功能,可以看到Flame病毒中就有很多身份认证相关的函数:
攻击Winlogon注册表
在用户登录的后期,Winlogon会执行注册表Userinit键值和Shell键值指向的exe程序:
HKLM\\Software\\Microsoft\\WindowsNT\\CurrentVersion\\Winlogon\\Userinit
HKLM\\Software\\Microsoft\\WindowsNT\\CurrentVersion\\Winlogon\\Shell
HKCU\\Software\\Microsoft\\WindowsNT\\CurrentVersion\\Winlogon\\Shell
所以有些攻击者会将恶意代码直接放到Userinit键值或Shell键值中,如下图所示(md5:0de10082977ccc05ad1b83035378e635):
除了Userinit键和Shell键,在注册表中还存在一个Notify项:HKLM\\Software\\Microsoft\\WindowsNT\\CurrentVersion\\Winlogon\\Notify
该项又被称作Winlogon通知包,是接收和处理Winlogon生成的事件的DLL。攻击者可以攻击通过修改该注册表项,执行恶意代码,实现持久化。APT组织PLATINUM曾使用过该技术(sha1:dff2fee984ba9f5a8f5d97582c83fca4fa1fe131)修改Notify项,注册Winlogon通知包:
攻击登录脚本
攻击者直接修改HKCU\\Environment\\UserInitMprLogonScript键值就能修改登录脚本了。
下图是Zebrocy利用登录脚本实现持久化:
SIP
SIP和信任提供程序
windows使用数字签名来验证程序是否是来自特定供应商的合法文件。数字签名在PE文件中的使用比较多,不过除了PE文件,powershell脚本、msi等文件也都含有数字签名。
PE文件的数字签名记录在数据目录表[IMAGE_DIRECTORY_ENTRY_SECURITY]字段中:
powshell脚本的数字签名记录在文件尾部:
msi文件的数字签名记录在Identifier中:
可以看到不同类型的文件具有不同的数字签名格式,为了支持多变的数字签名,微软采用了可扩展的架构来进行数字签名的验证,SIP(subjectinterface package)架构就是基于这一目的设计出来的。
SIP支持数字签名的创建、检索、哈希计算和验证,但执行签名代码验证的是信任提供程序。两者交互情况如下图所示
在验证数字签名的过程中,Windows将根据文件类型返回相应的SIPGUID。对于PE程序、powershell脚本、MSI文件等“已知”类型的文件将直接返回相应的SIPGUID。
对于其他的文件类型,将会尝试从“CryptSIPDllIsMyFileType”和“CryptSIPDllIsMyFileType2”的注册表项中取SIPGUID:
HKLM\\SOFTWARE[WOW6432Node]\\Microsoft\\Cryptography\\OID\\EncodingType0\\CryptSIPDllIsMyFileType
HKLM\\SOFTWARE[WOW6432Node]\\Microsoft\\Cryptography\\OID\\EncodingType0\\CryptSIPDllIsMyFileType2
一旦SIP被识别,系统就会知道如何从该文件中获取数字签名并验证签名。
系统以下通过注册表得知如何从文件在获取签名:
HKLM\\SOFTWARE[WOW6432Node]\\Microsoft\\Cryptography\\OID\\EncodingType0\\CryptSIPDllGetSignedDataMsg{SIP Guid}
系统通过以下注册表得知如何进行签名验证:
HKLM\\SOFTWARE[WOW6432Node]\\Microsoft\\Cryptography\\OID\\EncodingType0\\CryptSIPDllVerifyIndirectData{SIP Guid}
这两个注册表项的键值都是DLL+FuncName的形式,系统通过这两个键得知调用哪个DLL的哪个导出函数,如下图所示:
上图的demo中,{000C10F1-0000-0000-C000-000000000046}是msi文件的SIPGuid。也就是说系统在进行msi文件数字签名的验证时,将会调用MSISIP.DLL的导出函数MsiSIPGetSignedDataMsg获取MSI文件的数字签名;接着调用导出函数MsiSIPVerifyIndirectData验证签名hash。
CryptSIPDllGetSignedDataMsg中的MsiSIPGetSignedDataMsg和CryptSIPDllVerifyIndirectData中的MsiSIPVerifyIndirectData都是导出函数,它们的函数原型:
BOOL WINAPI CryptSIPGetSignedDataMsg(
IN SIP_SUBJECTINFO *pSubjectInfo,
OUT DWORD *pdwEncodingType,
IN DWORD dwIndex,
IN OUT DWORD *pcbSignedDataMsg,
OUT BYTE *pbSignedDataMsg);
BOOL WINAPI CryptSIPVerifyIndirectData(
IN SIP_SUBJECTINFO *pSubjectInfo,
IN SIP_INDIRECT_DATA *pIndirectData);
SIP和信任提供程序注册
通过注册SIP和信任提供程序,我们可以使用自定义的SIP和信任提供程序。
sip注册
自定义的SIP程序,必须拥有DllRegisterServer、DllUnregisterServer、CryptSIPGetSignedDataMsg、CryptSIPPutSignedDataMsg、CryptSIPCreateIndirectData、CryptSIPVerifyIndirectData、CryptSIPRemoveSignedDataMsg等导出函数。
我们一般调用“regsvr32.exe[SIPfilename].dll”来注册SIP,这个时候执行的就是DllRegisterServer。DllRegisterServer调用wintrust!CryptSIPAddProvider将其他导出函数注册到注册HKLM\\SOFTWARE[WOW6432Node]Microsoft\\Cryptography\\OID\\EncodingType0相应的项中:
DllUnregisterServer 注销功能,和DllRegisterServer的动作相反,该函数调用wintrust!CryptSIPRemoveProvider删除所有相关的SIP 注册表项。
注册信任提供程序
注册信任提供程序的过程和注册SIP的过程相似,也需要DllRegisterServer、DllUnregisterServer等导出函数。
不同的是,DllRegisterServer需要调用wintrust!WintrustAddActionID将各种导出函数注册到HKLM\\SOFTWARE[WOW6432Node]Microsoft\\Cryptography\\Providers\\Trust中;DllUnregisterServer调用wintrust!WintrustRemoveActionID进行卸载。
SIP劫持
SIP和信任提供程序在注册表中注册的方式很简单,都是Dll+FuncName的形式。我们只需要修改注册表相应键值,设置恶意的DLL和FuncName,就可以实现SIP劫持了。以下是常用于SIP劫持的三个注册表项:
①劫持CryptSIPDllGetSignedDataMsg
HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType0\\CryptSIPDllGetSignedDataMsg
②劫持CryptSIPDllVerifyIndirectData
HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType0\\CryptSIPDllVerifyIndirectData
③劫持FinalPolicy
HKLM\\SOFTWARE[WOW6432Node]Microsoft\\Cryptography\\Providers\\Trust\\FinalPolicy{{trustprovider GUID}}
当然,你也可以自定义恶意的SIP或信任提供程序,实现更完美的劫持,技术原理上文都介绍了,具体实现可以参考此文(超链接:https://3gstudent.github.io/3gstudent.github.io/Authenticode签名伪造-PE文件的签名伪造与签名验证劫持/)。
时间服务
Windows时间服务体系结构如下图所示:
Windows时间服务由服务控制管理器负责启动和停止。Windows时间服务管理器控制着windows时间服务的所有功能,包括启动时间提供程序(Input/OutputProvider)。
时间提供程序
时间提供程序时间上就是一个DLL,包括时间输入提供程序和事件输出提供程序。
微软默认提供了几个时间提供程序,他们全都记录在注册表项HKLM\\SYSTEM\\ControlSet001\\services\\W32Time\\TimeProviders:
间提供程序(DLL)的名称;
Enabled:是否启动时间提供程序,1表示启动;
InputProvider:1表示,时间提供程序是输入提供程序;否则,是输出提供程序;
除了微软默认的时间提供程序,windows也支持自定义时间提供程序。
一些攻击者通过将恶意代码放入自定义时间提供程序中,从而实现恶意代码的持久化。
创建时间提供程序
下列代码是微软给出的时间提供程序的样例:
#include<windows.h>
#include"timeprov.h"
// Global variables.
TimeProvSysCallbacks sc;
WCHAR ProviderName1[] = L"MyCompanyMyAppProvider1";
WCHAR ProviderName2[] = L"MyCompanyMyAppProvider2";
constTimeProvHandle htp1 = (TimeProvHandle)1;
constTimeProvHandle htp2 = (TimeProvHandle)2;
// Stores the current set of best samples.
TpcGetSamplesArgs Samples;
// Stores the polling interval the system requires to maintain clock
// stability. The provider need not poll more often.
DWORD dwPollInterval;
HRESULTCALLBACK TimeProvOpen(
WCHAR *wszName,
TimeProvSysCallbacks *pSysCallback,
TimeProvHandle *phTimeProv)
{// Spawn a thread to read configuration information from the registry.
;
// Copy the system callback pointers to a buffer.
CopyMemory(&sc, (PVOID)pSysCallback, sizeof(TimeProvSysCallbacks));// Return the handle to the appropriate time provider.
if (lstrcmp(wszName, ProviderName1) == 0)
*phTimeProv = htp1;
else *phTimeProv = htp2;
returnS_OK;
}
HRESULTCALLBACK TimeProvCommand(
TimeProvHandlehTimeProv,
TimeProvCmdeCmd,
PVOIDpvArgs)
{
switch (eCmd)
{
caseTPC_GetSamples:// Return the Samples structure in pvArgs.
CopyMemory(pvArgs, &Samples, sizeof(TpcGetSamplesArgs));
break;
caseTPC_PollIntervalChanged:// Retrieve the new value.
sc.pfnGetTimeSysInfo(TSI_PollInterval, &dwPollInterval);
break;
caseTPC_TimeJumped:// Discard samples saved in the Samples structure.
ZeroMemory(&Samples, sizeof(TpcGetSamplesArgs));
break;
caseTPC_UpdateConfig:// Read the configuration information from the registry.
break;
}
returnS_OK;
}
HRESULTCALLBACK TimeProvClose(
TimeProvHandlehTimeProv)
{
if (hTimeProv == htp1)
{// Terminate MyCompanyMyAppProvider1, performing any cleanup.
;
}
else
{// Terminate MyCompanyMyAppProvider2, performing any cleanup.
;
}
returnS_OK;
}
一个时间提供程序需要使用下列三个回调函数与时间服务管理器进行通信:
TimeProvClose
TimeProvCommand
TimeProvOpen
攻击者可以将恶意代码嵌入这三个回调函数中,当时间提供程序提供时间服务时,就会运行恶意代码。
WMI事件订阅
WMI最强大的功能之一是WMI能够响应WMI事件。除了少数例外,WMI事件可用于响应几乎任何操作系统事件。
WMI事件分两类,包括本地事件(单个进程的事件)和永久性WMI事件订阅。
本地事件有生命周期,为进程宿主的周期,而永久性WMI事件是存储在WMI库中,以SYSTEM 权限运行,并且重启后依然存在。
攻击者可以使用WMI的功能来订阅永久性WMI事件并在事件发生时执行任意代码,从而实现持久性。
要安装永久WMI事件订阅,需要执行以下三步:
1.注册事件过滤器,事件订阅触发条件;
2.注册事件消费者,触发事件时要执行的操作;
3.绑定事件消费者和过滤器;
我们可以通过
事件消费者( EventConsumers(事件处理))可用的标准事件处理类:
·LogFileEventConsumer:将事件数据写入到指定的日志文件
·ActiveScriptEventConsumer:用来执行VBScript/JScript程序
·NTEventLogEventConsumer:创建一个包含事件数据的日志入口点
·SMTPEventConsumer:将事件数据用邮件发送
·CommandLineEventConsumer:执行一条命令
其中ActiveScriptEventConsumer,允许执行任意脚本(支持 JScript 和 VBScript 引擎);CommandLineEventConsumer,允许执行任意命令。这两个点可以被攻击者利用
WQL
WMI使用WQL进行事件过滤。WQL是WMI查询语言,它是SQL的一个子集,具有较小的语义更改以支持WMI。WQL主要支持一下几种查询:
·Instance Queries(实例查询):查询WMI对象实例;
·EventQueries(事件查询):等同于在WMI对象创建/修改/删除的时候注册一个消息;
·Meta Queries(元查询):元查询用来获取WMI命名空间和类结构的元信息;
事件查询被用作一种消息机制来监听事件类的触发。通常用来在一个WMI对象实例创建/修改/删除的时候给用户发送一个消息。根据消息类型是 intrinsic(系统自带的)还是 extrinsic(第三方的),查询语句格式不同:
SELECT [Class property name | *] FROM [INTRINSIC CLASS NAME] WITHIN [POLLING INTERVAL] <WHERE [CONSTRAINT]>
SELECT [Class property name | *] FROM [EXTRINSIC CLASS NAME] <WHERE [CONSTRAINT]>
用于登陆时都会触发此事件:
SELECT * FROM __InstanceCreationEvent WITHIN 15 WHERETargetInstanceISA ‘Win32_LogonSession’ AND TargetInstance.LogonType=2
每次用户在插入可移除设备时都会触发此事件:
SELECT * FROM Win32_VolumeChangeEvent Where EventType=2
每次创建win32 进程时都会触发此事件:
Select * From __InstanceCreationEvent Where TargetInstance Isa"Win32_Process"
使用powershell实现事件订阅
powershell可以直接与WMI进行通信,攻击者可以使用Powershell实现WMI事件订阅:
EventFilterName= 'BotFilter11' EventConsumerName='BotConsumer22'
KaTeX parse error: Undefined control sequence: \\cimv at position 42: …amespace ='root\\̲c̲i̲m̲v̲2' Name =
EventFilterName
Query ='Select * From __InstanceCreationEvent Where TargetInstance Isa "Win32_Process"'
QueryLanguage="WQL"
}
KaTeX parse error: Undefined control sequence: \\subscription at position 46: …-NameSpace'root\\̲s̲u̲b̲s̲c̲r̲i̲p̲t̲i̲o̲n̲'-Class__EventF…
EventFilterArgs-ErrorActionStop
KaTeX parse error: Expected '}', got 'EOF' at end of input: …erArgs=@{ Name=
EventConsumerName
CommandLineTemplate='C:\\Windows\\System32\\calc.exe'
}
KaTeX parse error: Undefined control sequence: \\subscription at position 48: …-Namespace'root\\̲s̲u̲b̲s̲c̲r̲i̲p̲t̲i̲o̲n̲'-ClassCommandL…
CommandLineumerArgs
KaTeX parse error: Expected '}', got 'EOF' at end of input: …rgs= @{ Filter=
WMIEventFilter
Consumer=
KaTeX parse error: Expected 'EOF', got '}' at position 18: …IEventConsumer }̲ Set-WmiInstanc…
WMIEventFilterToConsumerArgs
使用WMIC实现事件订阅
注册事件过滤器
wmic /NAMESPACE:"\\root\\subscription"
PATH __EventFilter CREATE Name=“TopsecEventFilter”,
EventNameSpace=“root\\cimv2”,
QueryLanguage=“WQL”,
Query=“SELECT * FROM __InstanceModificationEvent WITHIN 20 WHERE TargetInstance ISA ‘Win32_PerfFormattedData_PerfOS_System’ AND TargetInstance.SystemUpTime >=120 AND TargetInstance.SystemUpTime < 150”
注册事件处理:
wmic /NAMESPACE:"\\root\\subscription"
PATH CommandLineEventConsumer CREATE Name=“TopsecConsumer”,
ExecutablePath=“C:\\Windows\\System32\\cmd.exe”,
CommandLineTemplate=" /c Rundll32 C:\\topsec.dll RunProc" /执行恶意dll
绑定
wmic /NAMESPACE:"\\root\\subscription"
PATH __FilterToConsumerBinding CREATE Filter="__EventFilter.Name=“TopsecEventFilter”", Consumer=“CommandLineEventConsumer.Name=“TopsecConsumer””
以上是关于恶意代码常见驻留分析的主要内容,如果未能解决你的问题,请参考以下文章