RDTSC / CPUID / RDTSC
EasyAntiCheat还使用标准定时攻击,使它们可以通过适当的TSC仿真(在前面的小节中进行了描述)被规避。
总体而言,缺少这些虚拟化检查并且相对容易规避。ESEA,FACEIT,B5和eSportal等其他反作弊技术采用了更具攻击性的检查,通过捕获基于虚拟机管理程序的作弊手段,使其更具效力。我们预计随着虚拟机管理程序的普及,支持大多数游戏的反作弊将开始考虑到这一点。
IA32_EFER
引起我们注意的是,在玩了约30分钟之后,EAC进行了查询IA32_EFER
。我们等待了更长的时间,以查看是否再进行了对MSR的读取/写入,但是经过40分钟的静坐并等待之后,显然没有其他事情发生了。以下是iPower跟踪器中收到的通知。
显然,执行此读取的代码在代码的某些虚拟化部分中。经分析证实。
我们还确认了它正在检查的位是中的系统调用启用位(SCE)IA32_EFER
。由于使用了Daax和ajkhoury的博客上发布的EFER的syscall挂钩方法的发布,它会检查此位。在不混淆更多代码的情况下,我们认为可以肯定地说这是它所检查的唯一位置,因为它具有相关性。缓解措施涉及设置IA32_EFER
MSR位图中对应的位,IA32_EFER
并在VMCS中利用加载/保存空间。
IofCallDriver / NtDeviceIoControlFile
出于好奇,我们决定看一下BE和EAC对NtDeviceIoControlFile和IofCallDriver的调用。我们注意到EAC中有一个IofCallDriverWrapper,并且两个反作弊者都在不同的地方使用IofCallDriver。
代码语言:javascript复制NTSTATUS __fastcall IofCallDriverWrapper(__int64 IoctlCode, _DEVICE_OBJECT *DeviceObject, void *InputBuffer, ULONG InputBufferLength, void *OutputBuffer, ULONG OutputBufferLength);
EAC用于IofCallDriver
查询磁盘的存储属性。这可能会收集序列号,名称等信息,以用于硬件指纹识别。
if ( IofCallDriverWrapper(0x2D1400i64, DeviceObject, &InputBuffer, 0xCu, &StorageDescriptorHeader, 8u) < 0 )
return v3;
if ( StorageDescriptorHeader.Size <= 0x28 )
return v3;
pbuf = (PSTORAGE_DEVICE_DESCRIPTOR)alloc_memory(StorageDescriptorHeader.Size);
pbuf_1 = pbuf;
if ( !pbuf )
return v3;
memset(pbuf, 0, StorageDescriptorHeader.Size);
*(_DWORD *)InputBuffer.AdditionalParameters = 0;
InputBuffer.QueryType = 0;
InputBuffer.PropertyId = 0;
if (IofCallDriverWrapper(0x2D1400i64, Device_Disk_Sys, &InputBuffer, 0xCu, pbuf_1, StorageDescriptorHeader.Size) >= 0)
{
// ...
}
代码语言:javascript复制memset(&InputBuffer, 0, 0x21ui64);
v20 = -20;
if (IofCallDriver_ioctl(0x7C088i64, v5, &InputBuffer, 0x21u, OutputBuffer, 0x211u) >= 0)
{
// ...
}
EAC和BE也使用NtDeviceIoControlFile查询IDIS为IOCTL_NDIS_QUERY_GLOBAL_STATS和OID的NDIS驱动程序OID_802_3_PERMANENT_ADDRESS
。这用于获取系统的MAC地址,也用于硬件指纹识别。
if ( ZwCreateFile(&FileHandle, 0x120089u, &ObjectAttributes, &IoStatusBlock, 0i64, 0x80u, 7u, 1u, 0x20u, 0i64, 0) >= 0 )
{
current_thread = __readgsqword(0x188u);
FileHandle_1 = FileHandle;
old_previous_mode = GetPreviousMode(current_thread);
SetPreviousMode(current_thread, 0);
if ( NtDeviceIoControlFile )
{
OutputBufferLength = 6;
InputBufferLength = 4;
IoctlCode = 0x170002;
status = NtDeviceIoControlFile(
FileHandle_1,
0i64,
0i64,
0i64,
&IoStatusBlock,
IoctlCode,
&InputBuffer,
InputBufferLength,
&OutputBuffer,
OutputBufferLength);
}
// ...
}
这可能是也可能不是为进行硬件指纹识别而进行的查询的完整列表,因为我们没有做更多的研究。它们可以直接从SSDT获取并直接调用,也可以使用其他方式间接调用这些函数。我们打算做自己的硬件指纹图谱的更深入的分析,在以后的文章-这只是挂钩时,迅速倾倒出于好奇NtDeviceIoControlFile
和IofCallDriver
。
结论
在本文中,我们介绍了可用于管理程序的许多不同检测方法。一些有效,其他却不太有效。我们还详细介绍了一些规避记录在案的检测向量的方法,但是实际的实现方式将取决于读者。这并不是要为每种检测方法提供完整的解决方案(即使对于本文来说,也太多了)。但是,无论稳定性如何,我们都希望记录最常用的方法。
我们还简要介绍了EAC和BE的虚拟化检查,鉴于使用开源虚拟机管理程序平台作弊的情况越来越普遍,这些检查有些令人失望。我们为他们的检查提供了规避方法,并计划将来发布用于TSC仿真的完整,完善的解决方案。但是,如果读者不热衷于等待,我们提供了如何实现的逻辑演练。在以后的文章中,我们将讨论这两种特殊的防欺诈功能,我们计划更深入地研究它们的硬件指纹识别,报告和检测程序。
我们希望您喜欢阅读有关如何利用虚拟化平台中的各种错误来检测自省引擎的信息,以及通过这些检查的方法。