使用PoolTag识别主机指纹
写在前面的话
通常情况下,恶意软件会对它所在的主机进行指纹识别,以便发现更多的信息。这个过程会分析一些特定的数据,用来判断恶意软件是否在VM中运行,除此之外,还会检测其他软件的存在。例如,恶意软件经常试图找出系统监控工具是否在运行(procmon, sysmon等)和安装了哪些AV软件。在本文中,我们将介绍另一种被恶意软件滥用的主机进行指纹识别的方法。
指纹识别的常用方法
首先,我们介绍几种恶意软件检测VM环境的常见方法:
1.枚举进程
2.枚举加载的模块
3.枚举文件
4.从Windows注册表中提取的数据(硬盘,BIOS等)
5.枚举加载的驱动程序
6.打开特定设备对象的句柄
7.枚举系统资源(CPU内核,RAM,屏幕分辨率等)
PoolTag了解一下
如果您对Windows内核驱动程序的开发和分析有一定的经验,那么我想您应该熟悉ExAllocatePoolWithTag函数,该函数用于在内核级别上分配内存块。这里的关键部分是Tag'参数,用于为特定的分配提供某种标识。如果出现错误,例如由于内存损坏这种问题,我们可以使用指定的标记(最多4个字符)来将缓冲区与分配内存块的内核驱动程序中的代码路径关联起来。这种方法可以检测内核驱动程序的存在,因此,在内核中加载模块的软件可能会绕过上面提到的指纹方法,这些方法依赖于驱动程序可能更改的信息。换句话说,从恶意软件作者的角度来看,它是用来检测某些真正重要的东西很好选择。例如,安全或监控软件可能试图通过在内核级别注册回调过滤器来隐藏其进程和文件。分析师可能会试图通过从注册表中删除恶意软件通常搜索的东西来强化虚拟机环境。但是,安全软件供应商或分析人员可能并不会修改他们自己的程序或系统中VM环境使用的特定内核驱动程序,从而修改内核池分配的标记。
获取PoolTag信息
可以通过调用NtQuerySystemInformation函数并为SysteminformationClass参数选择SystemPoolTagInformation (0x16 )来获取此信息 。MSDN上记录了部分上述功能和相关的SysteminformationClass可能值,幸运的是,通过一些研究,我们找到研究人员完成的一些文档。Alex Ionescu在他的NDK项目中记录了许多关于Windows内容。为了证明这个,我们编写了一个可以自己的获取和解析PoolTag信息的小工具,但是如果你想用GUI方式,推荐使用PoolMonEx这个工具。源代码如下:
您可以将其与Nbtk标记的PoolMonEx分配结果进行比较,如下所示。
QueryPoolTagInfo.cpp
#include "Defs.h"
#include
using namespace std;
int main()
{
NTSTATUS NtStatus = STATUS_SUCCESS;
BYTE * InfoBuf = nullptr;
ULONG ReturnLength = 0;
_ZwQuerySystemInformation ZwQuerySystemInformation = (_ZwQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQuerySystemInformation");
do{
NtStatus = ZwQuerySystemInformation(SystemPoolTagInformation, InfoBuf, ReturnLength, &ReturnLength);
if (NtStatus == STATUS_INFO_LENGTH_MISMATCH)
{
if (InfoBuf != nullptr)
{
delete[] InfoBuf;
InfoBuf = nullptr;
}
InfoBuf = new (nothrow) BYTE[ReturnLength];
if (InfoBuf != nullptr)
memset(InfoBuf, 0, ReturnLength);
else
goto Exit;
}
} while (NtStatus != STATUS_SUCCESS);
PSYSTEM_POOLTAG_INFORMATION pSysPoolTagInfo = (PSYSTEM_POOLTAG_INFORMATION)InfoBuf;
PSYSTEM_POOLTAG psysPoolTag = (PSYSTEM_POOLTAG)&pSysPoolTagInfo->TagInfo->Tag;
ULONG count = pSysPoolTagInfo->Count;
cout "Count: " endl endl;
for (ULONG i = 0; i cout "PoolTag: ";
for (int k = 0; k sizeof(ULONG); k++)
cout Tag[k];
cout endl;
写在前面的话
通常情况下,恶意软件会对它所在的主机进行指纹识别,以便发现更多的信息。这个过程会分析一些特定的数据,用来判断恶意软件是否在VM中运行,除此之外,还会检测其他软件的存在。例如,恶意软件经常试图找出系统监控工具是否在运行(procmon, sysmon等)和安装了哪些AV软件。在本文中,我们将介绍另一种被恶意软件滥用的主机进行指纹识别的方法。
指纹识别的常用方法
首先,我们介绍几种恶意软件检测VM环境的常见方法:
1.枚举进程
2.枚举加载的模块
3.枚举文件
4.从Windows注册表中提取的数据(硬盘,BIOS等)
5.枚举加载的驱动程序
6.打开特定设备对象的句柄
7.枚举系统资源(CPU内核,RAM,屏幕分辨率等)
PoolTag了解一下
如果您对Windows内核驱动程序的开发和分析有一定的经验,那么我想您应该熟悉ExAllocatePoolWithTag函数,该函数用于在内核级别上分配内存块。这里的关键部分是Tag'参数,用于为特定的分配提供某种标识。如果出现错误,例如由于内存损坏这种问题,我们可以使用指定的标记(最多4个字符)来将缓冲区与分配内存块的内核驱动程序中的代码路径关联起来。这种方法可以检测内核驱动程序的存在,因此,在内核中加载模块的软件可能会绕过上面提到的指纹方法,这些方法依赖于驱动程序可能更改的信息。换句话说,从恶意软件作者的角度来看,它是用来检测某些真正重要的东西很好选择。例如,安全或监控软件可能试图通过在内核级别注册回调过滤器来隐藏其进程和文件。分析师可能会试图通过从注册表中删除恶意软件通常搜索的东西来强化虚拟机环境。但是,安全软件供应商或分析人员可能并不会修改他们自己的程序或系统中VM环境使用的特定内核驱动程序,从而修改内核池分配的标记。
获取PoolTag信息
可以通过调用NtQuerySystemInformation函数并为SysteminformationClass参数选择SystemPoolTagInformation (0x16 )来获取此信息 。MSDN上记录了部分上述功能和相关的SysteminformationClass可能值,幸运的是,通过一些研究,我们找到研究人员完成的一些文档。Alex Ionescu在他的NDK项目中记录了许多关于Windows内容。为了证明这个,我们编写了一个可以自己的获取和解析PoolTag信息的小工具,但是如果你想用GUI方式,推荐使用PoolMonEx这个工具。源代码如下:
您可以将其与Nbtk标记的PoolMonEx分配结果进行比较,如下所示。
QueryPoolTagInfo.cpp
#include "Defs.h"
#include
using namespace std;
int main()
{
www.wnhack.com
NTSTATUS NtStatus = STATUS_SUCCESS;
BYTE * InfoBuf = nullptr;
ULONG ReturnLength = 0;
_ZwQuerySystemInformation ZwQuerySystemInformation = (_ZwQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwQuerySystemInformation");
do{
NtStatus = ZwQuerySystemInformation(SystemPoolTagInformation, InfoBuf, ReturnLength, &ReturnLength);
if (NtStatus == STATUS_INFO_LENGTH_MISMATCH)
{
if (InfoBuf != nullptr)
{
delete[] InfoBuf;
InfoBuf = nullptr;
www.wnhack.com
}
InfoBuf = new (nothrow) BYTE[ReturnLength];
if (InfoBuf != nullptr)
memset(InfoBuf, 0, ReturnLength);
else
goto Exit;
}
} while (NtStatus != STATUS_SUCCESS);
PSYSTEM_POOLTAG_INFORMATION pSysPoolTagInfo = (PSYSTEM_POOLTAG_INFORMATION)InfoBuf;
PSYSTEM_POOLTAG psysPoolTag = (PSYSTEM_POOLTAG)&pSysPoolTagInfo->TagInfo->Tag;
ULONG count = pSysPoolTagInfo->Count;
内容来自无奈安全网
cout "Count: " endl endl;
for (ULONG i = 0; i cout "PoolTag: ";
for (int k = 0; k sizeof(ULONG); k++)
cout Tag[k];
cout endl;
无奈人生安全网