当前位置:网站首页>Easyanticheat uses to inject unsigned code into a protected process (1)
Easyanticheat uses to inject unsigned code into a protected process (1)
2022-06-24 04:11:00 【franket】
Responsibility statement
It's not right EasyAntiCheat The attack of .EasyAntiCheat Doing a great job in protecting the game , And will continue to do so in the coming years . I passed on EasyAntiCheat The module's private research gathered these elements , It has nothing to do with the work of public game hacking publishers or other entities . I am not interested in writing secret scripts , Everything here is just for educational purposes . Please do not contact me for help with any cheating related problems , Because I will not respond to any such requests .
It is also important to pay attention to , In the whole article , Yes EasyAntiCheat The internal structure of . I didn't reverse engineer anti cheating from top to bottom , So I can't confidently say whether this will allow you to create undiscovered cheating . Best hypothesis EasyAntiCheat The detection mechanism has been implemented . There are some items with similar attack vectors , For example, those who have achieved similar goals modmap.
Introduce
EasyAntiCheat yes Epic Games Have a commercial anti cheating solution , At present, it claims that ( And as we all know ) It was prevented by game hackers “ Industry leader ” Solution . For game developers , This allows for the smooth implementation of anti cheating in their games , Prevent multiple forms of game manipulation . from AHK Script to cheating hidden in the game ,EasyAntiCheat Has been firmly established in the anti cheating industry , Pave the way for a more honest gaming experience .
For the attacker , An important challenge is to understand how anti cheating works . therefore , Knowing what happens inside anti cheating can hide your tracks ( Or place hooks and attacks ). Let's see EasyAntiCheat How to build a bridge between the kernel and the game through its module set . This will reveal how an overlooked design flaw in the driver could allow an attacker to attack any victim EasyAntiCheat The game of protection ( Or games that may be protected by the services of other competitors ) Unlimited execution of unsigned code in .
This effectively entices the anti cheating program to protect your memory as your own memory , And endow it with various abilities , For example, create a thread 、 Deliberately place hooks, etc . That being the case ,EasyAntiCheat The design of contains a series of executable files , We will examine only the three main modules in this exploit .
Before we start , The following figure shows some of the standard procedures responsible for EasyAntiCheat Initialized module , Its operation mode is briefly explained .
Be careful : These are not EasyAntiCheat The only module used , But these are the only modules necessary to understand what is about to happen .
x86 modular
As shown above , The anti cheating program injects a tag called EasyAntiCheat.dll Module . This module is one of the main modules of the service , Used to send data to the server for background analysis . Don't forget its own set of heuristic data collection routines . But this DLL How is it injected ? consider x86 The set of functions in the module :
using LauncherCallback = VOID( __stdcall* )( INT, ULONG*, UINT );
enum EasyAntiCheatStatus
{
Successful = 0,
FailedDriverHandle = 1,
IncompatibleEasyAntiCheatVersion = 2,
LauncherAlreadyOpen = 3,
DebuggerDetected = 4,
WindowsSafeMode = 5,
WindowsSignatureEnforcement = 6,
InsufficientMemory = 7,
DisallowedTool = 8,
PatchGuardDisabled = 11,
KernelDebugging = 12,
UnexpectedError = 13,
PatchedBootloader = 15,
GameRunning = 16,
};
const EasyAntiCheatStatus SetupEasyAntiCheatModule( PVOID InternalModule, SIZE_T InternalModuleSize )
{
// The current value is 0x3C but is subject to change....
if ( GetDriverVersion( this->DriverHandle ) != CurrentVersion )
return EasyAntiCheatStatus::FailedDriverHandle;
// sizeof( MapModuleStructure ) == 0x140
SIZE_T BufferSize = InternalModuleSize + sizeof( MapModuleStructure );
MODULE_MAP_STRUCTURE* Buffer = static_cast< MODULE_MAP_STRUCTURE* >( new UINT8[ BufferSize ] );
// Copy the image into the heap allocation....
// Currently Heap+0x140
memcpy( Buffer->Image, InternalModule, InternalModuleSize );
// Game initialization data such as the name are then copied over...
// Do note that although this buffer is encrypted with XTEA, the module is also encrypted with its own algo...
// The following DeviceIoControl tells the driver where to map the DLL (the game).
XTEA_ENCRYPT( Buffer, InternalModuleSize + sizeof( MapModuleStructure ), -1 );
SIZE_T ReturnedSize = 0;
const BOOL Result = DeviceIoControl( this->DriverHandle, MAP_INTERNAL_MODULE, Buffer, BufferSize, &Buffer, BufferSize, &ReturnedSize, nullptr );
if ( Result && ReturnedSize == BufferSize )
{
// Some processing comes here....
return EasyAntiCheatStatus::Successful;
}
// Other data processing occurs and error handling....
return EasyAntiCheatStatus::UnexpectedError;
}
// The exported name of this function is called "a" inside the x86 package but I have chosen a more fit name for reference.
__declspec( dllexport ) UINT InitEasyAntiCheat( LauncherCallback CallOnStatus , PVOID SharedMemoryBuffer, UINT Num )
{
//
// Sends EasyAntiCheat.sys through an open shared memory buffer "Global\EasyAntiCheatBin"
// This code is chopped off due to its irrelevance
// ...
//
const EasyAntiCheatStatus Status = SetupEasyAntiCheatModule( InternalModule, sizeof InternalModule /* Some arguments are redacted as they are irrelevant */ );
switch ( Status )
{
case EasyAntiCheatStatus::Successful:
{
SetEventStatus("Easy Anti-Cheat successfully loaded in-game");
LoadEvent("launcher_error.success_loaded");
break;
}
// Handles error codes and generates an error log...
}
// ...
}As you can see from the following set of code ,EasyAntiCheat adopt XTEA The encryption buffer will EasyAntiCheat.dll Together with other necessary information ( Such as GameID、 Process name, etc ) Send to driver .
Does this seem hateful to you ? Because it really works for me . At first glance , You will notice that they also use their own algorithms to encrypt the modules , Because the first few bytes A7 ED 96 0C 0F.... Not expected Windows PE header format . Considering that the driver module seems to follow the same format , reverse EasyAntiCheat.exe Will allow us to locate decryption . The current situation is as follows :
Image encryption
VOID DecryptModule( PVOID ModuleBase, ULONG ModuleSize )
{
if ( !ModuleSize )
return;
UINT8* Module = static_cast< UINT8* >( ModuleBase );
ULONG DecryptionSize = ModuleSize - 2;
while ( DecryptionSize )
{
Module[ DecryptionSize ] += -3 * DecryptionSize - Module[ DecryptionSize + 1];
--DecryptionSize;
}
Module[ 0 ] -= Module[ 1 ];
return;
}So the reverse is true ,
VOID EncryptModule( PVOID ModuleBase, ULONG ModuleSize )
{
UINT8* Module = static_cast< UINT8* >( ModuleBase );
ULONG Iteration = 0;
Module[ ModuleSize - 1 ] += 3 - 3 * ModuleSize;
while ( Iteration < ModuleSize )
{
Module[ Iteration ] -= -3 * Iteration - Module[ Iteration + 1];
++Iteration;
}
return;
}In view of this code , People can easily decrypt modules , And operate it as they see fit . for example , You can choose to inject an older version of this module , this Probably Allow users to avoid adding anything to EasyAntiCheat.dll Module . Or even modify its content to map its own image . however , It's best to stay away from assumptions . Since there is not much information disclosed in this module , Our new focus should be on checking EasyAntiCheat.sys To understand what happens when the module is delivered .
EasyAntiCheat.sys
once EasyAntiCheat.sys Receive module , It will decrypt XTEA buffer , Then decrypt the encrypted PE image . after ,KeStackAttachProcess Before running the following code , It switches the context to the protected game ( Use ) To prepare for manual mapping .
Manual mapping
The following code is used to map images into the game :
BOOLEAN MapSections( PVOID ModuleBase, PVOID ImageBuffer, PIMAGE_NT_HEADERS NtHeaders )
{
if ( !ModuleBase || !ImageBuffer )
return FALSE;
UINT8* MappedModule = static_cast< UINT8* >( ModuleBase );
UINT8* ModuleBuffer = static_cast< UINT8* >( ImageBuffer );
ULONG SectionCount = NtHeaders->FileHeader.NumberOfSections;
const PIMAGE_SECTION_HEADER SectionHeaders = IMAGE_FIRST_SECTION( NtHeaders );
const ULONG PEHeaderSize = SectionHeaders->VirtualAddress;
// Copy the PE header information.....
memcpy( ModuleBase, ImageBuffer, PEHeaderSize );
while( SectionCount )
{
const PIMAGE_SECTION_HEADER SectionHeader = &SectionHeaders[ SectionCount ];
if ( SectionHeader->SizeOfRawData )
memcpy( &MappedModule[ SectionHeader->VirtualAddress ], &ModuleBuffer[ SectionHeader->PointerToRawData ], SectionHeader->SizeOfRawData );
--SectionCount;
}
return TRUE;
}
BOOLEAN MapImage( PVOID ImageBase, SIZE_T ImageSize, PVOID* MappedBase, SIZE_T* MappedSize, PVOID* MappedEntryPoint, /* x86 only */ OPTIONAL ULONG* ExceptionDirectory, /* x86 only */ OPTIONAL ULONG* ExceptionDirectorySize )
{
if ( !ImageBase || !ImageSize || !MappedBase || !MappedSize || !MappedEntryPoint )
return FALSE;
*MappedBase = nullptr;
*MappedSize = 0;
*MappedEntryPoint = nullptr;
if ( ExceptionDirectory && ExceptionDirectorySize )
{
// These parameters are only used to resolve the exception directory if the DllHost module is being mapped into Dllhost.exe....
*ExceptionDirectory = 0;
*ExceptionDirectorySize = 0;
}
ImageType ModuleType;
const PIMAGE_NT_HEADERS NtHeaders = RtlImageNtHeader( ImageBase );
if ( NtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 )
{
ModuleType = ImageType::Image64;
}
else if ( NtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 )
{
ModuleType = ImageType::Image86;
}
PVOID MemBuffer = ExAllocatePool( ImageSize );
if ( MemBuffer )
{
// This will be used to effectively "hide" the module within the process...
const ULONG RandomSizeStart = RandomSeed( 4, 16 ) << 12UL;
const ULONG RandomSizeEnd = RandomSeed( 4, 16 ) << 12UL;
memcpy( MemBuffer, ImageBase, ImageSize );
ULONG64 SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage + ( RandomSizeEnd + RandomSizeStart );
BOOLEAN VirtualApiResult =
NT_SUCCESS( NtAllocateVirtualMemory( NtCurrentProcess(), MappedBase, 0, &SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );
if ( VirtualApiResult )
{
ULONG OldProtect = 0;
VirtualApiResult = NT_SUCCESS( NtProtectVirtualMemory( NtCurrentProcess(), MappedBase, SizeOfImage, PAGE_EXECUTE_READWRITE, &OldProtect ) );
if ( VirtualApiResult )
{
// This region is used to throw people off from the module.
RandomizeRegion( *MappedBase, RandomSizeStart );
VirtualApiResult = NT_SUCCESS( NtProtectVirtualMemory( NtCurrentProcess(), MappedBase, RandomSizeStart, PAGE_READWRITE, &OldProtect ) );
if ( VirtualApiResult )
{
PVOID ModuleEnd = static_cast< UINT8* >( *MappedBase ) + ( SizeOfImage - RandomSizeEnd );
RandomizeRegion( ModuleEnd, RandomSizeEnd );
VirtualApiResult = NT_SUCCESS( NtProtectVirtualMemory( NtCurrentProcess(), &ModuleEnd, RandomSizeEnd, PAGE_READONLY, &OldProtect ) );
if ( VirtualApiResult )
{
PVOID RealModule = static_cast< UINT8* >( *MappedBase ) + RandomSizeStart;
ResolveRelocations( RealModule, MemBuffer, ModuleType, NtHeaders );
NtHeaders->OptionalHeader.ImageBase = RealModule;
if ( MapSections( RealModule, MemBuffer, NtHeaders ))
{
// Applies the correct memory attributes for each section (.text = RX, .data = RW, .rdata = R, etc)
CorrectSectionProtection( RealModule, NtHeaders );
*MappedBase = RealModule;
*MappedSize = NtHeaders->OptionalHeader.SizeOfImage;
*MappedEntryPoint = static_cast< UINT8* >( RealModule ) + NtHeaders->OptionalHeader.AddressOfEntryPoint;
if ( ExceptionDirectory && ExceptionDirectorySize )
{
*ExceptionDirectory = NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXCEPTION ].VirtualAddress;
*ExceptionDirectorySize = NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXCEPTION ].Size;
}
}
}
}
}
}
}
if ( MemBuffer )
{
ExFreePool( MemBuffer );
MemBuffer = nullptr;
}
return *MappedEntryPoint != NULL;
}边栏推荐
- How to adjust the incompleteness before and after TS slicing of easydss video recording?
- How to set up a web server what is the price of the server
- Black hat actual combat SEO: never be found hijacking
- Difference and efficiency between get winevent and get eventlog
- Web technology sharing | [map] to realize customized track playback
- Two edges are applied by default, one of which is a solid color icon. How to delete that solid color icon?
- High availability architecture design to deal with network failure of operators
- 黑帽SEO实战之通用301权重pr劫持
- 微博国际版更名为微博轻享版
- Kubernetes 资源拓扑感知调度优化
猜你喜欢

Opengauss version 3.0 source code compilation and installation guide

Openeuler kernel technology sharing issue 20 - execution entity creation and switching

Black hat actual combat SEO: never be found hijacking

应用实践 | Apache Doris 整合 Iceberg + Flink CDC 构建实时湖仓一体的联邦查询分析架构

ClickHouse(02)ClickHouse架构设计介绍概述与ClickHouse数据分片设计

What is etcd and its application scenarios

Common content of pine script script

ServiceStack. Source code analysis of redis (connection and connection pool)

Kubernetes resource topology aware scheduling optimization

Congratulations to Zhong Jun for becoming the maintainer of chaos metric model working group
随机推荐
华为云GaussDB(for Redis)揭秘第19期:GaussDB(for Redis)全面对比Codis
黑帽SEO实战之通用301权重pr劫持
Idea 1 of SQL injection bypassing the security dog
openGauss 3.0版本源码编译安装指南
Download files and close the enhanced module security configuration to visit the website for the first time using IE browser
Tell you about mvcc
An open source monitoring data collector that can monitor everything
How can the new generation of HTAP databases be reshaped in the cloud? Tidb V6 online conference will be announced soon!
黑帽实战SEO之永不被发现的劫持
618 promotion: mobile phone brand "immortal fight", high-end market "who dominates the ups and downs"?
The use of char[0] and char[1] in C language structure
脚本之美│VBS 入门交互实战
What is FTP? What is the FTP address of the ECS?
Black hat actual combat SEO: never be found hijacking
多任务视频推荐方案,百度工程师实战经验分享
flutter系列之:flutter中的offstage
Black hat SEO actual combat search engine snapshot hijacking
Go operation mongodb
What is a virtual host server? What are the advantages?
开源之夏2022中选结果公示,449名高校生将投入开源项目贡献