Пользователь
Пользователь
- Статус
- Оффлайн
- Регистрация
- 6 Май 2025
- Сообщения
- 110
- Реакции
- 59
Данная тема создана в образовательных целях. Она не направлена на нанесение вреда EasyAntiCheat'y или другим организациям. Обратная разработка анти-чита была проведена с целью изучения и пополнения знаний о работе EasyAntiCheat'a.
В качестве примера, мы возьмем игру Rust ( в ней как раз находится последняя версия анти чита )
В качестве примера, мы возьмем игру Rust ( в ней как раз находится последняя версия анти чита )
О чем пойдет речь в этой теме:
Понятие, на какие модули делится анти чит и за что отвечает каждая часть
Создание программы, которая будет извлекать внутренний модуль
Введение:
EasyAntiCheat делится на 3 части:
eac_launcher.dll, eac_internal.dll, easy_anti_cheat.sys
В этой теме мы рассмотрим только внутренний модуль и немного лаунчер
eac_launcher - модуль, который загружается в rust.exe. С помощью него происходит запуск драйвера анти чита и передача буфера внутреннего модуля
eac_internal - модуль, который загружается в rustclient.exe. В этом модуле находятся основные проверка в игре ( сканирование памяти, общения с анти читом, отправка репортов на сервер )
Анализ:
Изначально, буфер внутреннего модуля передается зашифрованным. Немного пореверсив лаунчер, я нашел функцию шифровки модуля:
C++:
void encrypt_module( uint8_t* address, const uint32_t size ) {
uint32_t new_size{ };
address[ size - 1 ] += 3 - 3 * size;
while ( new_size < size ) {
address[ new_size ] -= -3 * new_size - address[ new_size + 1 ];
++new_size;
}
}
На основе этого алгоритма, я сделал и функцию дешифрования модуля:
C++:
void decrypt_module( uint8_t* address, const uint32_t size ) {
uint32_t new_size = size - 2;
address[ size - 1 ] += 3 - 3 * size;
while ( new_size ) {
address[ new_size ] += -3 * new_size - address[ new_size + 1 ];
--new_size;
}
address[ 0 ] -= address[ 1 ];
}
Для перехвата зашифрованного буфера с модулем, я буду ставить брейкпоинт на функцию сетапа анти чита.
После того, как сработал брейкпоинт, то мы получаем следующее:
По адресу [ RSP + 0x28 ] будет находится указатель на энкриптнутый буфер
По адресу [ RSP + 0x30 ] будет находится указатель на размер зашифрованного буфера
Создание дампера:
Исходя из всей информации, написанной сверху, мы можем написать дампер модуля:
Сейчас я покажу один основной момент из кода ( дабы не растягивать статью ), а ниже я оставлю сурс дампера и сдампленный модуль.
Поиск функции сетапа анти чита и установление на нее точки останова:
C++:
void thread( ) {
while ( 1 ) {
MEMORY_BASIC_INFORMATION mbi{ };
for ( uint64_t address{ }; VirtualQuery( reinterpret_cast< void* >( address ), &mbi, sizeof( MEMORY_BASIC_INFORMATION ) ); address += mbi.RegionSize ) {
if ( mbi.Protect == PAGE_EXECUTE_READWRITE && mbi.State & MEM_COMMIT ) {
const auto& found = reinterpret_cast< void* >( utils::find_pattern( address, mbi.RegionSize, ( uint8_t* )"\x44\x89\x4C\x24\x00\x4C\x89\x44\x24\x00", "xxxx?xxxx?" ) );
if ( !found ) {
Sleep( 5 );
continue;
}
// found
hooks::hook.handler = &hooks::setup_easy_anti_cheat;
hooks::hook.hook_address = found;
hooks::hook.original = *reinterpret_cast< uint8_t* >( found );
*reinterpret_cast< uint8_t* >( found ) = 0xCC;
return ExitThread( 0xeac );
}
}
}
}
В хуке сетапа анти чита, нет ничего примечательного. Я декрипчу модуль, выделяю страницу, копирую модуль, сохраняю его на диск.
К теме приложу сурс и сдампленный модуль
Большое спасибо за прочтение, это была моя первая статья, надеюсь на конструктивную критику.