Как работают dll читы

Обновлено: 05.07.2024

Существуют разные виды читов. Можно разделить их на несколько групп.

  • External — внешние читы, которые работают в отдельном процессе. Если же мы скроем наш external-чит, загрузив его в память другого процесса, он превратится в hidden external.
  • Internal — внутренние читы, которые встраиваются в процесс самой игры при помощи инжектора. После загрузки в память игры в отдельном потоке вызывается точка входа чита.
  • Pixelscan — вид читов, который использует картинку с экрана и паттерны расположения пикселей, чтобы получить необходимую информацию от игры.
  • Network proxy — читы, которые используют сетевые прокси, те, в свою очередь, перехватывают трафик клиента и сервера, получая или изменяя необходимую информацию.

Есть три основные тактики модификации поведения игры.

  1. Изменение памяти игры. API операционной системы используется для поиска и изменения участков памяти, содержащих нужную нам информацию (например, жизни, патроны).
  2. Симуляция действий игрока: приложение повторяет действия игрока, нажимая мышкой в заранее указанных местах.
  3. Перехват трафика игры. Между игрой и сервером встает чит. Он перехватывает данные, собирая или изменяя информацию, чтобы обмануть клиент или сервер.

Редактирование памяти

Влиять таким образом можно на многое. К примеру:

  • Получать координаты игроков
  • Влиять на устройства ввода
  • Влиять на передвижение и поворот
  • Редактировать параметры, имеющиеся в движке


Пример: если записать какое-нибудь число по адресу m_iFOV, то можно менять угол обзора. А по адресу m_iHealth можно читать здоровье игрока. Любого. Оффсеты давно неактуальны.

Минусы такого метода:

  • Сделать что-то более сложное нельзя. По сути, Вы максимум можете управлять цифрами, редактируя текущее состояние. Вы не можете создать что-то новое (на самом деле можно, но это очень сложно).
  • Не всё можно редактировать. Иногда нельзя даже проверить видимость игрока.
  • Для каждой версии игры нужно искать свои адреса.
  • Скорость работы оставляет желать лучшего.

Но как же те ублюдки, которые вечно смотрят в пол и моментально раздают хедшоты?


Инъекция DLL

Если к движку есть SDK (комплект для разработки), то разработка читов становится ещё проще, т.к. всё задокументировано. Что можно делать таким образом:

Обход античитов

  • Читы, использующие редактирование памяти, быстрее всего обнаруживаются античитами, из-за использования функций Windows чтения и записи в память.
  • Читы, которые требуют инъекции DLL, обнаруживаются по сигнатуре. С точки зрения игры они не делают ничего незаконного, т.к. они не вторгаются в процесс извне.

Для оттягивания момента обнаружения последних, часто используют протекторы, такие как Themida, VMProtect (да-да, тот самый, и конечно же крякнутый), SafeEngine и т.д. Протектор обфусцирует (запутывает) код и меняет сигнатуру чита. Некоторые протекторы используют виртуальную машину. Выглядит это с точки зрения антивирусов весьма печально.


Продвинутые читы могут скрывать присутствие своих процессов. Опять же, благодаря встроенным функциям в Windows.

DLL инъекция дает возможность выполнять свой код в адресном пространстве уже запущенного процесса. Многие используют инфицирования для написания читов для игр, выполнения вредоносных действий для системы и т.п. Но данный прием не обязательно применять для реализации коварных планов, а например, для обновления своего приложения.

Опишем структуру, через которую мы получим необходимые нам данные:

typedef FARPROC (WINAPI *LPMessageBox)(HWND, LPCWSTR, LPCWSTR, UINT);

typedef struct _InjectData char title[50];
char msg[50];
LPMessageBox MessageB;
> InjectData, *PInjectData;

static DWORD WINAPI InjectionMain(LPVOID lpParams)

PInjectData info = (PInjectData)lpParams;

info->MessageB(NULL, (LPCWSTR)info->msg, (LPCWSTR)info->title, MB_OK);
return 0;
>

В нашем примере она довольно таки проста. В нем мы не выполняем подгрузку DLL, хотя для большинства задач вам это может быть необходимо, для этого необходимо передать указатели на ф-ции LoadLibrary и GetProcAddress, также как мы это делам для MessageBoxA, и при помощи их подгружать необходимые вам DLL.

Теперь нам нужно получить доступ к explorer.exe, записать наш код, данные в адресном пространстве процесса и создать поток в процессе для выполнения нашего кода.

Опишем ф-цию которая возвращает идентификатор процесса:

DWORD getProcessID() DWORD processID = 0;
HANDLE snapHandle;
PROCESSENTRY32 processEntry = ;

if ( (snapHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE ) return 0;
>

processEntry.dwSize = sizeof (PROCESSENTRY32);
Process32First(snapHandle, &processEntry);
do if ( wcscmp(processEntry.szExeFile, PROCESSNAME) == 0 ) return processEntry.th32ProcessID;
>
> while (Process32Next(snapHandle,&processEntry));

if ( snapHandle != INVALID_HANDLE_VALUE ) CloseHandle(snapHandle);
>


CreateToolhelp32Snapshot — возвращает нам фактически список процессов и их потоков. Обходим весь список и если найден наш процесс, то возвращаем его идентификатор или 0. Теперь, когда у нас есть идентификатор, мы можем получить доступ к процессу при помощи OpenProcess, но не сможем ни чего записать в его память. Для того, что бы наше приложение получило права, нам понадобиться следующая ф-ция:
BOOL setPrivilege(HANDLE hToken, LPCTSTR szPrivName, BOOL fEnable) TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
LookupPrivilegeValue(NULL, szPrivName, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof (tp), NULL, NULL);
return ((GetLastError() == ERROR_SUCCESS));
>

Подробней о правах можете почитать здесь . Не смотря на то, что ответа за 1998 год он еще актуален для XP SP3 и насколько я знаю, для Windows 7, хотя лично еще не тестил.

Теперь у нас есть все для того, что бы получить доступ к процессу:

DWORD processID = getProcessID();
HANDLE hCurrentProc = GetCurrentProcess();

if (!OpenProcessToken(hCurrentProc, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken)) addLogMessage( "OpenProcessToken Error" , GetLastError());
return 0;
> else if (!setPrivilege(hToken, SE_DEBUG_NAME, TRUE)) addLogMessage( "SetPrivlegesSE_DEBUG_NAME Error" , GetLastError());
return 0;
>
>

if (processID == 0) MessageBox(NULL, _T( "Process not found!" ), _T( "Error" ), MB_OK | MB_ICONERROR);
return 0;
>

processHandel = OpenProcess(PROCESS_ALL_ACCESS, false , processID);


Нам не хватает указателя на ф-цию MessageBoxA, которая находиться в user32.dll:
HINSTANCE userHinstance = LoadLibrary(_T( "user32.dll" ));
injectData.MessageB = (LPMessageBox) GetProcAddress(userHinstance, "MessageBoxA" );

Ну что ж, перейдем теперь к самому интересному, собственно к инфицированию, запишем наш данный и код в память и создадим поток, который все это запустит. Для модифицирования памяти нам понадобиться две ф-ции: VirtualAllocEx и WriteProcessMemory.
LPVOID lpProc = VirtualAllocEx(processHandel, NULL, ProcSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
LPVOID lpParams = VirtualAllocEx(processHandel, NULL, 1024, MEM_COMMIT, PAGE_READWRITE );
DWORD dwWritten;
if (WriteProcessMemory(processHandel, lpProc, InjectionMain, ProcSize, &dwWritten ) == 0) addLogMessage( "WriteProcessMemory error" , GetLastError());
return 0;
>
if (WriteProcessMemory( processHandel, lpParams, &injectData, sizeof (injectData), &dwWritten ) == 0) addLogMessage( "WriteProcessMemory error" , GetLastError());
return 0;
>

VirtualAllocEx — предоставляет физическую память в виртуальном адресном пространстве процесса, а WriteProcessMemory записывает наши данные в память процесса.

Теперь создадим поток в процессе, который воплотит наш коварный план в жизнь:

Читайте также: