[C++] YouGame anti-cheat [Часть 1] LL Detect

Что описывать далее?

  • internal операции с памятью и файлами и детектить попытки промапить модуль (mmap)

    Голосов: 23 26.7%
  • не стандартные примеры инжекта NtCreateThreadEx/QueueUserAPC/RtlCreateUserThread и тп.

    Голосов: 32 37.2%
  • операции с дескрипторами (thread/mutex/process и прочие)

    Голосов: 6 7.0%
  • external Отладчики и мусор

    Голосов: 16 18.6%
  • Что-то другое.

    Голосов: 9 10.5%

  • Всего проголосовало
    86
Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
Помнится, обещал я пример простого анти-чита, появилась свободная минутка, таки своял на коленке заветную первую часть.
Предполагается, что пользователь на той стороне, имеет базовые навыки работы с компилятором и хотя бы начальные знания, в связи с чем готового исходника публиковать не буду, так как весь код и так будет описан в статье. Разумеется это изичный баян и с последующими частями задача будет усложнятся, условия будут меняться. Но а для тех кто базовых знаний не имеет, можете пропустить тему мимо глаз,я направляю внимание на тех, кто хочет развиваться.
Про общую теорию можно узнать в теме об >> Общей теории детекта << (Кликабельно)
Такэ, приступим.
Первый урок мы начнем с детекта простых инжектов, для разколупывания которых, возьмем за основу навесные хуки. Читавшие статью об основной теории ссылка на которую указана выше, начинается дело с вхождения, с первого отклонения от нормы, от которого можно далее плясать.
Ставить эти хуки мы будем через MinHook, где брать и с чем жевать описано в моей давнешней теме про
>> модификацию процесса на старте << (Кликабельно)
Сделаем простую консольку с выводом данных.

Определим зависимости. Я назвал этот файл "Include.h"
Код:
#include <windows.h>
#include <iostream>
#include <string>
#include <clocale>
#include "shlobj.h"
#include <Psapi.h>
#pragma comment(lib, "Psapi.lib")

using namespace std;
Определяем прототипы в удобном месте:​
Код:
typedef _Ret_maybenull_ HMODULE (WINAPI* _LoadLibraryA)(_In_ LPCSTR);
typedef _Ret_maybenull_ HMODULE(WINAPI* _LoadLibraryW)(_In_ LPCWSTR);
Откуда они берутся, эти прототипы? В случае с WinAPI на прямую из документации, они там же определены.
В иных случаях краткий экскурс описан в моей теме про >> Перехват данных << (Кликабельно)
Расписываем необходимое для работы и отсеивания системных модулей:​
Код:
cDetour<_LoadLibraryA>* t_LoadLibraryA;
cDetour<_LoadLibraryW>* t_LoadLibraryW;
//для LoadLibraryA
string system32;
string syswow64;
//для LoadLibraryW
wstring system32w;
wstring syswow64w;
//разрядность
BOOL x64 = FALSE;
И наконец, пишем сами хуки:
LoadLibraryA:
Код:
_Ret_maybenull_ HMODULE WINAPI myLoadLibraryA(_In_ LPCSTR lpLibFileName)
{
    auto hReturn = t_LoadLibraryA->GetTrampoline()(_In_ lpLibFileName);
    //маин
    if (hReturn == NULL)
        return hReturn;
    //модуль инфо
    MODULEINFO moduleInfo { };
    if (GetModuleInformation(GetCurrentProcess(), hReturn, &moduleInfo, sizeof(MODULEINFO)) == NULL)
    {
        printf("Last Error:  %d\n", GetLastError());
    }
    //загружаемый файл
    char patch[2048];
    GetModuleFileNameA(hReturn, patch, 2048);
    //обработка
    DataCheckA(moduleInfo.lpBaseOfDll, moduleInfo.SizeOfImage, moduleInfo.EntryPoint, patch);
    return hReturn;
}
LoadLibraryW: (с описанием, ибо 1 и те же комментарии заебусь писать)​
Код:
_Ret_maybenull_ HMODULE WINAPI myLoadLibraryW(_In_ LPCWSTR lpLibFileName)
{
    //сразу выполняем оригинал функции, но не возвращаем результат
    //выполнения вызывающему коду пока не получим нужные данные!
    auto hReturn = t_LoadLibraryW->GetTrampoline()(_In_ lpLibFileName);
    //если main модуль (наше приложение)
    if (hReturn == NULL)
        return hReturn;
    //получаем модульинфо
    MODULEINFO moduleInfo{};
    if (GetModuleInformation(GetCurrentProcess(), hReturn, &moduleInfo, sizeof(MODULEINFO)) == NULL)
    {
        printf("Last Error:  %d\n", GetLastError());
    }
    //получаем путь к файлу
    wchar_t patch[2048];
    GetModuleFileNameW(hReturn, patch, 2048);
    //передаем данные на обработку
    DataCheckW(moduleInfo.lpBaseOfDll, moduleInfo.SizeOfImage, moduleInfo.EntryPoint, patch);
    //возвращаем результат выполнения функции
    return hReturn;
}
Расписываем DataCheck для работы с полученными данными:​
Код:
void DataCheckA(LPVOID _base, DWORD _size, LPVOID _entryPoint, CHAR* _patch)
{
    //Вот тут у нас уже есть данные о модуле, можем чекать
 
    //Если ОС х64 разрядная системные дллки будут грузится из папки syswow64
    if (x64)
    {
        //Если путь к длл не содержит путь к системному каталогу - длл не системная.
        if (!strstr(_patch, syswow64.c_str()))
        {
            printf("\n detected x64, Start: 0x%X, size: 0x%X, Entry: 0x%X, patch: %s\n", _base, _size, _entryPoint, _patch);
        }
    }
    else //Если х32 разрядная дллки будут грузится из папки system32
    {
        //Если путь к длл не содержит путь к системному каталогу - длл не системная.
        //Так же можно проверять формат, является ли это длл? пример strstr(_patch, ".dll")
        if (!strstr(_patch, system32.c_str()))
        {
            //Далее можно манипулировать дллкой
            if (file_exitsA(_patch))
            {
                //Если у нас есть файл на жестком диске
                //можем сделать его копию и швырнуть на сервер
                //или же проверить наличие цифровой подписи. гугли по запросу winVerifyTrust
            }
            //И вот оно вхождение найдено, мы можем располагать данными,
            //Точка входа, базовый адрес, размер
            //Имея базовый адрес мы можем проверить PE/DOS заголовки модуля на валидность
            //Как получить заголовки насилуй гугл. Пример: С++ RtlImageNtHeader.
            //И это только минимум информации))
            //именно тут расписано как пример
            printf("\n detected x86, Start: 0x%X, size: 0x%X, Entry: 0x%X, patch: %s\n", _base, _size, _entryPoint, _patch);
        }
    }
}
//Далее по накатаной

void DataCheckW(LPVOID _base, DWORD _size, LPVOID _entryPoint, WCHAR* _patch)
{
    if (x64)
    {
        if (!wcsstr(_patch, syswow64w.c_str()))
        {
            wprintf(L"\n detected x64, Start: 0x%X, size: 0x%X, Entry: 0x%X, patch: %s\n", _base, _size, _entryPoint, _patch);
        }
    }
    else
    {
        if (!wcsstr(_patch, system32w.c_str()))
        {
            printf("\n detected x86, Start: 0x%X, size: 0x%X, Entry: 0x%X, patch: %s\n", _base, _size, _entryPoint, _patch);
        }
    }
}
И вот, 5 минутная мастурбация дала немного эффекта.
Точка входа для завершения пазла:​
Код:
int main()
{
    SetConsoleTitleA("yougame meme anti shit");
    //шобэ могли писать на рускам, а то заибали везде инеглеш делать.
    setlocale(LC_ALL, "");
    //Для LoadLibraryA
    char system_folder[MAX_PATH];
    //получаем путь к папке виндавус.
    SHGetSpecialFolderPathA(0, system_folder, CSIDL_WINDOWS, true);
    //папки систем 32 и сисвов 64
    system32 = std::string(system_folder) + "\\system32\\";
    syswow64 = std::string(system_folder) + "\\syswow64\\";
    //для LoadLibraryW
    wchar_t system_folderw[MAX_PATH];
    //получаем путь к папке виндавус.
    SHGetSpecialFolderPathW(0, system_folderw, CSIDL_WINDOWS, true);
    system32w = std::wstring(system_folderw) + L"\\system32\\";
    syswow64w = std::wstring(system_folderw) + L"\\syswow64\\";
    x64 = wow64();

    HMODULE hKernel = GetModuleHandleA("kernel32.dll");
 
    if (hKernel) {

        auto& pContext = cContext::GetInstance();

        auto dwAdress_LoadLibraryA = GetProcAddress(hKernel, "LoadLibraryA");

        pContext.ApplyDetour<_LoadLibraryA>(
            reinterpret_cast<_LoadLibraryA>(dwAdress_LoadLibraryA),
            reinterpret_cast<_LoadLibraryA>(myLoadLibraryA),
            &t_LoadLibraryA);


        auto dwAdress_LoadLibraryW = GetProcAddress(hKernel, "LoadLibraryW");

        pContext.ApplyDetour<_LoadLibraryW>(
            reinterpret_cast<_LoadLibraryW>(dwAdress_LoadLibraryW),
            reinterpret_cast<_LoadLibraryW>(myLoadLibraryW),
            &t_LoadLibraryW);

    }


    printf("Start\n");
    system("pause");
  //Снимаем хуки на выходе
    if (t_LoadLibraryA)
        t_LoadLibraryA->Remove();
    if (t_LoadLibraryW)
        t_LoadLibraryW->Remove();
    return 0;
}
Прикладные функции:​
Код:
BOOL DirectoryExistsA(const std::string& dirName_in)
{
    DWORD attribute = ::GetFileAttributesA(dirName_in.c_str());
    if (attribute == INVALID_FILE_ATTRIBUTES)
        return false; //путь не верный!
    return (attribute & FILE_ATTRIBUTE_DIRECTORY);
}
BOOL DirectoryExistsW(const std::wstring& dirName_in)
{
    DWORD attribute = ::GetFileAttributesW(dirName_in.c_str());
    if (attribute == INVALID_FILE_ATTRIBUTES)
        return false; //путь не верный!
    return (attribute & FILE_ATTRIBUTE_DIRECTORY);
}

bool file_exitsA(const std::string& path)
{
    return (GetFileAttributesA(path.c_str()) != 0xFFFFFFFF);
}

bool file_exitsW(const std::wstring& path)
{
    return (GetFileAttributesW(path.c_str()) != 0xFFFFFFFF);
}

BOOL wow64()
{
    BOOL ret;
    IsWow64Process(GetCurrentProcess(), &ret);
    return ret;
}
Само собой разумеется, это лишь соринка тех мер, которые нужны чтобы разьебать читодела. В дальнейшем опишу как это обойти, и как усложнить задачу с обходом.
читы от васьки этот код детектить будет.
После создания темы, добавлю опрос, на тему того что делать следующим.
Если че забыл уточнить спросите в коментах.
UD: для тех кто будет базарить за "ноп на проверке",
я уже описывал статью как >> проверять целестность кода <<

Показано, как я инжекчу сторонний модуль и системный, на сторонний ругается, системный - не трогает.
 
Последнее редактирование:
push me to the edge
Олдфаг
Статус
Оффлайн
Регистрация
22 Мар 2017
Сообщения
2,253
Реакции[?]
1,204
Поинты[?]
1K
Лайк за фразу "читы от васьки этот код детектить будет.", пиздец я выпал )))
по теме:
Годно ! Как я всегда говорю для новичков очень хорошо заходит и возможно даже появится обнова на вак)
 
Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
UD: добавил голосование на следующую тему.
 
Лайк за фразу "читы от васьки этот код детектить будет.", пиздец я выпал )))
дак у них и инжект обычный CRT, как в процессхакере и бомжеинжекторах, этот код реально может детектить читы от васьки. это не шутка - это остров пасхи.
 
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
Участник
Статус
Оффлайн
Регистрация
20 Апр 2017
Сообщения
1,298
Реакции[?]
377
Поинты[?]
2K
видимо тут некому оценить работу)
Сотрудники Valve тебе благодарны и вышлют почетную грамоту, отправь мне свой адрес в ЛС. :LUL:

А если по теме, очень полезная информация, жирный плюс тебе, действительно стоющее, это не как пастить в АУУ перчатки, чтоб они работали. :pogchamp:
 
Забаненный
Статус
Оффлайн
Регистрация
12 Май 2017
Сообщения
375
Реакции[?]
11
Поинты[?]
0
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
masta copypasta
Участник
Статус
Оффлайн
Регистрация
2 Июн 2017
Сообщения
683
Реакции[?]
253
Поинты[?]
0
#include <windows.h>
#include <iostream>
#include <string>
#include <clocale>
#include "shlobj.h"
#include <Psapi.h>

Почему
<>
<>
""
<>

Когда первыми должны быть ""?
 
bruh
Участник
Статус
Оффлайн
Регистрация
15 Апр 2017
Сообщения
1,299
Реакции[?]
365
Поинты[?]
0
#include <windows.h>
#include <iostream>
#include <string>
#include <clocale>
#include "shlobj.h"
#include <Psapi.h>

Почему
<>
<>
""
<>

Когда первыми должны быть ""?
о хоспаде, думал что хоть за год ты начнешь шарить в инклудах :FeelsBadMan:
 
видимо тут некому оценить работу)
Щас валве спастят и чо мы будем делать?
 
Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
#include <windows.h>
#include <iostream>
#include <string>
#include <clocale>
#include "shlobj.h"
#include <Psapi.h>

Почему
<>
<>
""
<>

Когда первыми должны быть ""?
<> - для файлов sdk (визуалки считай), "" - для файлов проекта. (твоего исходника)
 
masta copypasta
Участник
Статус
Оффлайн
Регистрация
2 Июн 2017
Сообщения
683
Реакции[?]
253
Поинты[?]
0
Эксперт
Статус
Оффлайн
Регистрация
12 Июн 2014
Сообщения
999
Реакции[?]
1,209
Поинты[?]
3K
Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
masta copypasta
Участник
Статус
Оффлайн
Регистрация
2 Июн 2017
Сообщения
683
Реакции[?]
253
Поинты[?]
0
блять, тебе все объяснять надо?

зайди в вс, создай консольное приложение

напиши код и закомпиль =)

Код:
#include <windows.h>
#include <conio.h>
#include <iostream>
#include "stdafx.h"

int main()
{
std::cout << "Test" << std::endl;
_getch();
return 0;
}
а потом закомпиль

Код:
#include "stdafx.h"
#include <windows.h>
#include <conio.h>
#include <iostream>


int main()
{
std::cout << "Test" << std::endl;
_getch();
return 0;
}
 
так что не пизди не зная
 
Эксперт
Статус
Оффлайн
Регистрация
12 Июн 2014
Сообщения
999
Реакции[?]
1,209
Поинты[?]
3K
блять, тебе все объяснять надо?

зайди в вс, создай консольное приложение

напиши код и закомпиль =)

Код:
#include <windows.h>
#include <conio.h>
#include <iostream>
#include "stdafx.h"

int main()
{
std::cout << "Test" << std::endl;
_getch();
return 0;
}
а потом закомпиль

Код:
#include "stdafx.h"
#include <windows.h>
#include <conio.h>
#include <iostream>


int main()
{
std::cout << "Test" << std::endl;
_getch();
return 0;
}
 

так что не пизди не зная
\omg
прочти что такое предварительно скомпилированный заголовок и как он используется в иерархии построения
Вадим просто не использует его, а в твоем примере он как раз присутствует, а из-за чего у тебя ошибки лезут ты найдешь в гугле
 
Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
блять, тебе все объяснять надо?
в прочем ответ выше,
ничего, медузы тоже без мозгов живут.
по всей видимости тебе объяснять все надо. те кто работают не на пеньке ебучем, не воебурят с прекомпилированными заголовками, которые нахуй не нужны по сути и просто отключают их встраивание еще при создании проекта.

для не глобальных целей, это в хуй не упало просто, а если чото вызывает сомнение, топай в википедию и на MSDN.
 
Забаненный
Статус
Оффлайн
Регистрация
12 Май 2017
Сообщения
375
Реакции[?]
11
Поинты[?]
0
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
в прочем ответ выше,

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

для не глобальных целей, это в хуй не упало просто, а если чото вызывает сомнение, топай в википедию и на MSDN.
А можно тутор по детекту новый потоков из инжекторов?Ну или совета куды копать :4Head:
 
midnight.im
Администратор
Статус
Оффлайн
Регистрация
1 Июл 2015
Сообщения
1,649
Реакции[?]
2,171
Поинты[?]
161K
Мне показалось, или если кинуть длл в папку system32 и инжектить оттуда то ничего не задетектит?)
//Если путь к длл не содержит путь к системному каталогу - длл не системная.

Я обосрался, там даже коммент есть, учтите что это не совсем правильно, проверяйте подпись лучше
 
Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
Мне показалось, или если кинуть длл в папку system32 и инжектить оттуда то ничего не задетектит?)



Я обосрался, там даже коммент есть, учтите что это не совсем правильно, проверяйте подпись лучше
ну, некоторые античиты действительно не пустят длл, если она не из системной папки, или не из папки с игрой. если из системной папки, проверят импорты/експорты, если из папки с игрой, подпись.
 
Пользователь
Статус
Оффлайн
Регистрация
28 Дек 2017
Сообщения
149
Реакции[?]
118
Поинты[?]
0
Сверху Снизу