Easy Anti-Cheat 分析

转载自GuidedHacking
我在pastebin上发现了一些其他信息:

EAC进行的硬件扫描:

EAC总是在启动驱动程序时获取您的硬盘序列。他们也会获取您的mac地址。任何游戏都经常发生这种情况,但是我认为对于每个EAC版本/游戏,他们所做的扫描都是不同的。
他们似乎对游戏之间的不同游戏\eac版本进行了不同的扫描。它们具有此数字数组,指向要执行的扫描。他们虽然循环。它似乎是静态的/硬编码的,但可能会随每个游戏的变化而变化。

他们分配了0x400字节来将所有这些信息存储在下面,因此他们抢占了很多。

扫描是:

硬件扫描ID 0-3:reg值键抓取

使用我之前在该数组中的两个DWORD上方讨论的数组,确定它们将从注册表中提取的路径和键。
在内存中,该数组是dword值的数组,例如,reg扫描看起来像[3,5,1,…,…,…]。
这意味着我们正在执行扫描ID 1,并提取BIOSReleaseDate以及\Registry\Machine\Hardware\Description\System\BIOS,
因为该阵列的阵列中有3,5。

这些是它们可以抓取的键和路径字符串(不要问我为什么它们没有数字7)
下面列出了:

1 = \Registry\Machine\System\CurrentControlSet\Control\SystemInformation
2 = ComputerHardwareId
3 = \Registry\Machine\Hardware\Description\System\BIOS
4 = BIOSVendor
5 = BIOSReleaseDate
6 = SystemManufacturer
8 = SystemProductName
9 = \Registry\Machine\Hardware\DeviceMap\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0
10 = Identifier
11 = SerialNumber
12 = \Registry\Machine\Hardware\Description\System\CentralProcessor\0
13 = ProcessorNameString
14 = <\Registry\Machine\System\CurrentControlSet\Control\Class{4d36e968-e325-11ce-bfc1-08002be10318}\0000
15 = \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion
16 = InstallDate
17 = DriverDesc
18 = ProductId
19 = \Registry\Machine\Software\Microsoft\Windows\CurrentVersion\WindowsUpdate
20 = SusClientId
21 = \Registry\Machine\System\CurrentControlSet\Control\Class{4d36e972-e325-11ce-bfc1-08002be10318}\0001

Hardware Scan Id 4 = 查找所有正在运行的驱动程序,并在.sys文件中获取校验和版本信息(资源编辑器)

他们使用QuerySystemInformation使所有驱动程序在您的系统上运行(我认为它们不包括easyanticheat.sys)。
对于返回的每个驱动程序,他们从文件系统读取它,检查它是否具有有效的pe标头,如果存在,请尝试找到该文件的“资源部分”。 当他们这样做时,他们会寻找版本信息资源,然后在版本信息资源中找到产品版本并对其进行校验和。 他们似乎也存储图像的大小,但我不是100%。 如果右键单击文件并选择.sys文件的属性,然后转到详细信息,则可能会看到“产品版本”字段。 这就是他们的校验和。 我发现在我的计算机上,它们至少具有校验和“ Classpnp.sys”,因为它具有产品版本。 它可以是本质上加载的任何.sys文件。 它们捕获文件名,产品版本字符串的校验和,并且我相信还可以从pe获取图像大小。

Hardware Scan Id 5 = 64位或32位

他们检查您使用的是64位版本的Windows还是32位版本。 并非真正有用,但已包含在他们的扫描结果中。

Hardware Scan Id 6 = PCI 和 USB 驱动名称:

他们使用此GUID使用IoGetDeviceInterfaces获取所有设备(我不知道这要花多长时间
假设是,但这是指向guid的指针的第一个字节):

{84,84,C8,CA,15,75,3,4C,82,E6,71,A8,7A,BA,C3,61,F2,A3,46,21,82,39,2D,C0,A8 }

如果它们包含在符号链接名称中 \??\PCIor\??\USB,则将其添加到最终校验和中。 注意?? 就像一个{4d36e968-e325-11ce-bfc1-08002be10318}之类的十六进制字符串,因此他们在设备名称中使用这些十六进制字符串来标识。

硬件扫描ID 7 =处理器功能
他们从内存地址0xfffff78000000274获得0x40字节,并将其加密并发送。

硬件扫描ID 8 =读取SystemRoot\System32\restore\MachineGuid.txt的内容(如果存在)

他们读取SystemRoot\System32\restore\MachineGuid.txt的内容,并对其进行加密或散列。

这是从Rust EAC 2018年12月17日构建中获取的扫描阵列(请参见下文)

struct ScanData {
unsigned int parameter1ForScan;
unsigned int parameter2ForScan;
unsigned int scanCode;
};

因此,对于第一个,我们看到的是扫描代码0,我们看到的parameter1Scan为1,看到的parameter2ForScan为2。扫描代码0为reg扫描,并且获取字符串1(\ Registry \ Machine \ System \ CurrentControlSet \ Control \ SystemInformation)和2(ComputerHardwareId )
Code:
/Registery/Machine/System/CurrentControlSet/Control/SystemInfomation/

  • ComputerHardwareId

HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\BIOS

  • BIOSVendor
  • BIOSReleaseDate
  • SystemManufacturer
  • SystemProductName

HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0

  • Identifier
  • SerialNumber

HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0

  • ProcessorNameString

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class{4d36e968-e325-11ce-bfc1-08002be10318}\0000

  • DriverDesc

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion

  • InstallDate
  • ProductId

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate

  • SusClientId

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class{4d36e972-e325-11ce-bfc1-08002be10318}\0001

Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\Windows Activation Technologies\AdminObject\Store

  • MachineId
  • 64-bit
  • 32-bit

SystemRoot\System32\restore\MachineGuid.txt <– 他们会寻找此文件并使用此文件中的信息(并非每个人都有此文件)


Easy Anti Cheat可能是最流行的内核模式反作弊,它在许多游戏中使用,并由Epic Games拥有。 它比Battleye更好,因此更难绕过。 如果要绕过它,则还必须具有内核驱动程序。 如果游戏容易发生焦炭,您将无法注入,连接调试器(包括作弊引擎)或对游戏进程进行任何其他操作,直到您绕开EAC

本指南中将遵循的大多数信息都归功于@iPoweradrianyy,因此对他们有充分的贡献。

您将需要在继续之前阅读我们的内核防热线,它将拥有绕过内核防热线开始所需的一切:
指南-防热旁路的内核模式驱动程序信息

如果手动映射驱动程序,则必须清除包括PiDDBCacheTable在内的跟踪,因为它们会基于该跟踪检测到您

哪些游戏用了EAC?

Apex Legends
Fortnite
Rust
Paladins
Dead by Daylight
For Honor
Gears 5
Ghost Recon Wildlands
The Division 2
ArcheAge
Cabal Online
Combat Arms
Darkfall: Rise of Agaon
Dauntless
Dirty Bomb
Xenoverse 2
FlyFF Online
Halo Mastier Chief Collection
Special Force 2
and many more

EAC功能

由于EAC是内核反作弊,因此它可以检测任何事物。您必须在启动反作弊之前首先加载内核驱动程序,以防止此情况发生

阻止与游戏过程的所有互动
阻止流程句柄的创建
扫描隐藏的流程和模块
扫描已知的可疑DLL模块
扫描已知的可疑驱动程序
获取所有打开的句柄的列表
扫描磁盘和设备
记录所有已加载的驱动程序
收集HWID信息
检测调试器
查找手动映射的驱动程序
检测手动映射的驱动程序跟踪
检查内核补丁
查找物理内存的句柄
使用VirtualProtect检测模块
从没有实际模块支持的区域中转储可疑字符串
在没有模块支持的区域中扫描可能的syscall存根
进行窗口枚举以检测可疑覆盖图
枚举可疑的共享内存部分
检测钩子
检查所有服务
扫描所有线程和系统线程
堆栈回溯
检测手动映射的模块
Turla驱动程序装载程序检测
虚拟机监控程序和VM检测
DbgUiRemoteBreakin补丁
PsGetProcessDebugPort
手动设置HideFromDebugger标志
读取DR​​6和DR7
仪表回调

手动映射的驱动检测

PiDDBCacheTable & MmUnloadedDrivers
system pool detection
system thread detection

EAC HWID生成

EAC非常清楚的知道你的机器码,所以你可能需要伪造很多地方
KUSER_SHARED_DATA.ProcessorFeatures ( 0xFFFFF78000000274 )
Registry
WMI
Ntoskernl.exe version
Mac address
Disk serials
Registry Keys for HWID
HKEY_LOCAL_MACHINE\Hardware\Description\System\CentralProcessor\0
SystemProductName
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0
Identifier
SerialNumber
SystemManufacturer
Computer\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SystemInformation
ComputerHardwareId
Computer\HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\BIOS
BIOSVendor
BIOSReleaseDate
ProductId
ProcessorNameString
Computer\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class{4d36e968-e325-11ce-bfc1-08002be10318}\0000
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
InstallDate
DriverDesc
Computer\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\WindowsUpdate
SusClientId
Registry\Machine\System\CurrentControlSet\Control\Class{4d36e972-e325-11ce-bfc1-08002be10318}\0001
Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\Windows Activation Technologies\AdminObject\Store

转储模块

Easy Anticheat使用内核驱动程序和用户模式模块。 您必须先绕过EAC,才能附加调试器,因此反转EAC本身就成为问题。 但是,如果您可以进入内核,则可以转储模块,以便以后进行静态分析。 这些模块经常更新,但是我们有一些转储可用。 这是学习如何绕过EAC的第一步,您可以静态分析这些二进制文件并发现Easy Anti Cheat的工作方式。

EasyAnticheat虚拟机监控程序和VM检测-secret.club
当前,EAC在驱动程序初始化时执行单个vmread

vmread

RDTSC / CPUID / RDTSC
EasyAntiCheat还使用标准定时攻击,使它们可以通过适当的TSC仿真(在前面的小节中进行了描述)被规避。

IA32_EFER
引起我们注意的是,在大约30分钟的游戏时间之后,EAC询问了IA32_EFER。我们等待了更长的时间,以查看是否再进行了对MSR的读取/写入,但是经过40分钟的静坐并等待之后,显然没有其他事情发生了。以下是iPower跟踪器中收到的通知。

IofCallDriver / NtDeviceIoControlFile

绕过EasyAntiCheat完整性检查

“作弊者对反作弊自我完整性检查特别感兴趣。如果可以规避它们,则可以有效地修补或“钩住”任何可能导致反踢甚至禁令的反作弊代码。在EasyAntiCheat的情况下,他们使用包含一些有趣的检测例程的内核模式驱动程序,我们将检查它们的完整性检查如何工作以及如何规避它们,从而有效地使我们能够禁用反作弊功能。

反转过程

首先要做的实际上是确定是否存在任何类型的完整性检查。最简单的方法是修补.text中的任何字节,然后查看反作弊是否会在一段时间后决定踢您或禁止您。在修补随机函数后大约10至40秒,我被踢了,发现他们确实在内核模块中进行完整性检查。在使用EPT工具的基于虚拟机管理程序的调试器的帮助下,我在由LoadImage通知例程调用的函数上设置了一个内存断点(请参阅PsSetLoadImageNotifyRoutine)。一段时间后,我可以找到他们正在访问内存的位置。

在IDA Pro中检查了外部参照并设置了一些指令断点之后,我发现了从哪里调用完整性检查功能,其中之一在CreateProcess通知例程内(请参阅PsSetCreateProcessNotifyRoutine)。此例程负责防作弊初始化的某些部分,例如创建将用于表示游戏过程的内部结构。如果EAC发现其内核模块已被篡改,则不会初始化…

这是EAC记录的可疑模块的列表(来自adriayny
Dumper.dll
Glob.dll
mswsock.dll
perl512.dll
vmclientcore.dll
vmwarewui.dll
virtualbox.dll
qtcorevbox4.dll
vboxvmm.dll
netredirect.dll
atmfd.dll
cdd.dll
rdpdd.dll
vga.dll
workerdd.dll
msvbvm60.dll

if ( AttachToProcess(process, (__int64)&v5) )
{
    if ( GetUsermodeModule((UNICODE_STRING *)(StringTable + 4830))// Dumper.dll
        && GetUsermodeModule((UNICODE_STRING *)(StringTable + 4852))// Glob.dll
        && GetUsermodeModule((UNICODE_STRING *)(StringTable + 4870))// mswsock.dll
        && GetUsermodeModule((UNICODE_STRING *)(StringTable + 4894))// perl512.dll
        || GetUsermodeModule((UNICODE_STRING *)(StringTable + 4918))// vmclientcore.dll
        || GetUsermodeModule((UNICODE_STRING *)(StringTable + 4952))// vmwarewui.dll
        || GetUsermodeModule((UNICODE_STRING *)(StringTable + 4980))// virtualbox.dll
        || GetUsermodeModule((UNICODE_STRING *)(StringTable + 5010))// qtcorevbox4.dll
        || GetUsermodeModule((UNICODE_STRING *)(StringTable + 5042))// vboxvmm.dll
        || GetUsermodeModule((UNICODE_STRING *)(StringTable + 5066)) )// netredirect.dll
    {
        v3 = 1;
    }


EAC还会检查一些驱动
Dbgv.sys
PROCMON23.sys
dbk64.sys

LOBYTE(v11) = 1;
if ( !(unsigned int)strstr2((__int64)&a1, (const char *)(StringTable + 8038), v11) )// Dbgv.sys
    break;
LOBYTE(v16) = 1;
if ( !(unsigned int)strstr2((__int64)&a1, (const char *)(StringTable + 8047), v16) )// PROCMON23.sys
    break;
LOBYTE(v17) = 1;
if ( !(unsigned int)strstr2((__int64)&a1, (const char *)(StringTable + 8061), v17) )// dbk64.sys
    break;


EAC user-mode hooks:

hk_BaseThreadInitThunk (Kernel32ThreadInitThunkFunction - ntdll.dll)
hk_D3DXCreateFontA (EAT Hook)
hk_D3DXCreateFontIndirectA (EAT Hook)
hk_D3DXCreateSprite (EAT Hook)
hk_D3DXCreateTextureFromFileInMemory (EAT Hook)
hk_D3DXCreateTextureFromFileInMemoryEx (EAT Hook)
hk_D3DXLoadSurfaceFromMemory (EAT Hook)
hk_Dllmain_mono_dll (Inline Hook)
hk_LoadAppInitDlls (Inline Hook)
hk_LoadLibraryExW_user32 (IAT Hook - user32.dll)
hk_LoadLibraryExW_ws2_32 (IAT Hook - ws2_32.dll)
hk_LockResource_kernel32 (IAT Hook - kernel32.dll)
hk_NtCreateFile_kernelbase (IAT Hook - kernelbase.dll)
hk_NtDeviceIoControlFile_mswsock (IAT Hook - mswsock.dll)
hk_NtOpenFile_kernelbase (IAT Hook - kernelbase.dll)
hk_NtProtectVirtualMemory_kernelbase (IAT Hook - kernelbase.dll)
hk_NtQueryDirectoryFile_kernelbase (IAT Hook - kernelbase.dll)
hk_NtUserGetAsyncKeyState_user32 (IAT Hook - user32.dll)
hk_NtUserSendInput_user32 (IAT Hook - user32.dll)
hk_QueryPerformanceCounter (IAT Hook - game.exe)
hk_RtlExitUserProcess_kernel32 (IAT Hook - kernel32.dll)
hk_VirtualAlloc_iat_kernel32 (IAT Hook - kernel32.dll)
hk_mono_assembly_load_from_full (Inline Hook)
hk_mono_assembly_open_full (Inline Hook)
hk_mono_class_from_name (Inline Hook)
hk_mono_runtime_invoke (Inline Hook)


用于手动映射代码的EAC Suspect Threads检测例程

用于枚举线程并打开它们的句柄的API:CreateToolhelp32Snapshot,Thread32First,Thread32Next,OpenThread

获取线程信息:NtQueryInformationThread(ThreadBasicInformation和ThreadQuerySetWin32StartAddress)

堆栈遍历:GetThreadContext,RtlLookupFunctionEntry和RtlVirtualUnwind

检测可疑线程的步骤:

从当前进程中的所有线程获取信息(线程ID,堆栈信息,线程基地址)

//getting thread info
if ( thread_info_obtained )
    {
      thread_info.ExitStatus = thread_basic_info.ExitStatus;
      thread_info.TebBaseAddress = (__int64)thread_basic_info.TebBaseAddress;
      thread_info.Priority = thread_basic_info.Priority;
      thread_info.BasePriority = thread_basic_info.BasePriority;
      thread_info.StartAddress = v18;
      if ( thread_basic_info.TebBaseAddress )
      {
        thread_info.StackBase = *((_QWORD *)thread_basic_info.TebBaseAddress + 1);
        thread_info.StackLimit = *((_QWORD *)thread_basic_info.TebBaseAddress + 2);
      }
      stack_walk_thread(*v8, v14, &thread_info.RipsStackWalk);
LABEL_22:
      v15 = v1->CurrentEntry;
      if ( v1->LastEntry == v15 )
      {
        reallocate_vector_thread_information(v1, v15, &thread_info);
      }
      else
      {
        memcpy_thread_information(v11, v15, &thread_info);
        ++v1->CurrentEntry;
      }
    }
    reset_thread_information_struct(&thread_info);
    ++v8;
    v19 = v8;
  }


堆栈回溯

//stack walking routine
run_count = 0;
  while ( run_count < 9 )
  {
    entry_pc = RtlLookupFunctionEntry(Context.Rip, &v20, 0i64);
    if ( entry_pc )
    {
      RtlVirtualUnwind_0(0i64, v20, Context.Rip, entry_pc, &Context, &v23, &v22, 0i64, thread_rip_1);
      if ( !Context.Rip )
        return vec_rips_stackwalk->FirstEntry != vec_rips_stackwalk->CurrentEntry;
      thread_rip_1 = Context.Rip;
      current_entry = vec_rips_stackwalk->CurrentEntry;
      if ( vec_rips_stackwalk->LastEntry == current_entry )
      {
        reallocate_vector_qword(vec_rips_stackwalk, current_entry, &thread_rip_1);
      }
      else
      {
        *current_entry = Context.Rip;
        ++vec_rips_stackwalk->CurrentEntry;
      }
    }
    ++run_count;
    RtlLookupFunctionEntry = *(__int64 (__fastcall **)(DWORD64, __int64 *, _QWORD))RtlLookupFunctionEntry_0;
  }
  return vec_rips_stackwalk->FirstEntry != vec_rips_stackwalk->CurrentEntry;


查询所有区域以获取有关它们的信息

//as the code is huge I'll be only posting their structure for memory regions
 
struct MEMORY_REGION_INFORMATION
{
  MEMORY_BASIC_INFORMATION mbi;
  STRING_STRUCT DllName;
  STRING_STRUCT SectionName;
};


Finding suspect threads from start addresses/stack walk rips outside modules’ ranges
You don’t have an eac bypass unless you are hiding from this

//start address check
  start_address = thread_info_1->StartAddress;
  if ( start_address
    && (unsigned __int8)get_region_from_address(start_address, memory_region_info_vec_1, &memory_region_info_) )
  {
    if ( (memory_region_info_.mbi.Protect & 0x10
       || memory_region_info_.mbi.Protect & 0x20
       || memory_region_info_.mbi.Protect & 0x40) //executable region
      && !memory_region_info_.DllName.Length ) //not associated with a module
    {
        //copy data from suspect region
    }
  ////////////////////////////////////////////////////////////////////////
 
  //stack walk rips check
  entry = thread_info_1->RipsStackWalk.FirstEntry;
  current_entry = thread_info_1->RipsStackWalk.CurrentEntry;
  while ( entry != current_entry )
  {
    if ( *entry
      && (unsigned __int8)get_region_from_address(*entry, memory_region_info_vec_1, &memory_region_info_)
      && (memory_region_info_.mbi.Protect & 0x10
       || memory_region_info_.mbi.Protect & 0x20
       || memory_region_info_.mbi.Protect & 0x40) //executable region
      && !memory_region_info_.DllName.Length ) //not associated with a module
    {
        //copy data
    }
    //...
  }
//...


Copying data and sending to their server

//...
CEasyAntiCheat::send(eac_instance,
                     281i64,
                     Dst.FirstEntry,
                     (unsigned int)(LODWORD(Dst.CurrentEntry) - LODWORD(Dst.FirstEntry)));
//...


希望在阅读完所有这些内容后,您意识到绕过EAC并非一件容易的事

当然,您可以进入内核,并且可以访问游戏的进程

但是EAC知道您在做什么,他们禁止您只是时间问题。 如果您只是为了绕开EAC而绕过EAC,那很好

但是,如果要在有很多用户的地方进行欺骗,则需要确保EAC bypass是完美的

幸运的是,我们有足够的资源,一旦您进入内核,转储模块并开始反转就不太困难了

最后,博主的话~

挑战和机遇也许不能同时存在,但遇到任何一个,都将会改变你

为什么要转载并详细讲解该程序?

很简单,博主很喜欢找一些强大的反作弊或者加密混淆的程序进行解析;不是为了显得我有多么厉害,就是为了提升自我,并且给这些作者,甚至帮助他们一起强化该程序

花了多久时间?

真不久,还要感谢ExtremeBlackLiu帮助分析,大概几天的样子

什么目的?

挑战自我,帮助他人,学习交流,天天向上😛

暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇