Гайд Простой чит-ревилер для вашего чита

anonymous
Участник
Статус
Онлайн
Регистрация
18 Окт 2022
Сообщения
607
Реакции[?]
216
Поинты[?]
144K
Перед началом хочу выразить огромную благодарность Satoru за помощь с отображением иконок читов в табе т.к я думал что без затрагивания panoramы и js это невозможно.

В данной статье будет использована информация с репозитория
Пожалуйста, авторизуйтесь для просмотра ссылки.
(noad)

Начнем с предисловия. В данной статье я не буду вдаваться в подробности как вообще работают голосовые пакеты в игре. Однако без понимания этого базиса будет очень сложно объяснить принцип работы. Поэтому рассмотрим краткий пример:

- Любая сетевая игра работает за счёт постоянного обмена данными между клиентом и сервером. В нашем же случае с ксго, игрок(клиент) создаёт новый "голосовой" пакет данных (экземпляр класса CCLCMsg_VoiceData и CSVCMsg_VoiceData), то есть конструирует и заполняет массив данных и в конечном итоге отправляет на сервер (CNetChan::SendNetMsg) другим игрокам. Читы делают это вручную, зачастую используя готовые функции движка игры, формируя свой "голосовой пакет" который ничем не отличается от нативного игрового кроме как будучи заполненным кастомными данными чита. Нам же нужно получить эти данные, расшифровать и сравнить нужные переменные для нашего чит ревилера.

- В добавку к этому всему, не забываем, что у каждого игрока есть разные идентификаторы и в данном случае нам понадобится идентификатор xuid_low (который так же присутствует в классах CCLCMsg_VoiceData и CSVCMsg_VoiceData), но для чего он нужен, мы узнаем немного позже.

Перейдём к написанию самого чит ревилера:

- Как любой нормальный кодер мы сразу сталкиваемся с логическими "проблемами" на которые нам нужно придумать решения, то как мы будем хранить полученные данные, как часто вызывать функции и как сделать так чтобы всё это дело было оптимизировано!

1) Хранение данных:
В моём конкретном случае, на момент написания ревилера, я использовал готовую базу чит опая (airflow) и в моём распоряжении имелась структура esp_player_t и класс c_esp, которые глобально использовались в проекте, поэтому, к счастью, мне не пришлось придумывать велосипед.

Проблема хранения решена.

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

2) Получение "голосовых" данных от сервера
Пожалуйста, авторизуйтесь для просмотра ссылки.
. Ставим хук на эту функцию

Пишем хук на эту функцию, для получения "голосовых" данных:
Код:
bool __fastcall msg_voice_data(void* ecx, void* edx, c_svc_msg_voice_data* message)
{
    // получаем оригинал функции
    static auto original = hooker::get_original(&msg_voice_data);
 
    // исключаем локального игрока т.к нам нужны данные соперников ну или тиммейтов
    if ( !HACKS->local || HACKS->local->index() == message->client + 1)
        return original(ecx, edx, message);

    // перехватываем нужные нам данные для ревилера
    CHEAT_REVEALER->handle_voice(message);

    // мы получили что хотели,
    // возвращаем оригинал функции чтобы не ломать работоспособность игры
    return original(ecx, edx, message);
}
Данные получены.
Переходим к их сравнению:

Создаём заголовки
cheat_revealer.hpp:
static unsigned char skeet_shellcode[] =
{
    0x81, 0xEC, 0x4C, 0x01, 0x00, 0x00, 0x53, 0x55, 0x56, 0x8B, 0xF1, 0x89, 0x54, 0x24, 0x54, 0x33,
    0xDB, 0xC7, 0x44, 0x24, 0x10, 0x68, 0x33, 0x05, 0x97, 0x57, 0xC7, 0x44, 0x24, 0x18, 0x36, 0x06,
    0xD4, 0xEA, 0xBF, 0x00, 0x01, 0x00, 0x00, 0x8B, 0x46, 0x10, 0x8B, 0x4E, 0x14, 0x89, 0x44, 0x24,
    0x30, 0x8B, 0x46, 0x28, 0x89, 0x44, 0x24, 0x38, 0x8B, 0x46, 0x24, 0x89, 0x44, 0x24, 0x3C, 0x8B,
    0x46, 0x2C, 0x89, 0x44, 0x24, 0x40, 0x8B, 0xC3, 0xC7, 0x44, 0x24, 0x1C, 0x4F, 0xC4, 0xA4, 0x3E,
    0xC7, 0x44, 0x24, 0x20, 0x85, 0xB2, 0xAC, 0x0F, 0x89, 0x4C, 0x24, 0x34, 0x89, 0x5C, 0x24, 0x28,
    0x88, 0x44, 0x04, 0x5C, 0x40, 0x3B, 0xC7, 0x72, 0xF7, 0x8A, 0xF3, 0x8B, 0xF3, 0x8A, 0x54, 0x34,
    0x5C, 0x8B, 0xC6, 0x83, 0xE0, 0x0F, 0x8A, 0x44, 0x04, 0x14, 0x02, 0xC2, 0x02, 0xF0, 0x0F, 0xB6,
    0xCE, 0x8A, 0x44, 0x0C, 0x5C, 0x88, 0x44, 0x34, 0x5C, 0x46, 0x88, 0x54, 0x0C, 0x5C, 0x3B, 0xF7,
    0x72, 0xDB, 0x8A, 0xE3, 0x8B, 0xFB, 0xBD, 0x80, 0x00, 0x00, 0x00, 0x8A, 0xF4, 0xFE, 0xC6, 0x0F,
    0xB6, 0xF6, 0x8A, 0x54, 0x34, 0x5C, 0x02, 0xE2, 0x0F, 0xB6, 0xCC, 0x8A, 0x44, 0x0C, 0x5C, 0x88,
    0x44, 0x34, 0x5C, 0x88, 0x54, 0x0C, 0x5C, 0x83, 0xED, 0x01, 0x75, 0xE1, 0xFE, 0xC6, 0x0F, 0xB6,
    0xF6, 0x8A, 0x54, 0x34, 0x5C, 0x8A, 0xDA, 0x02, 0xDC, 0x0F, 0xB6, 0xCB, 0x8A, 0x44, 0x0C, 0x5C,
    0x88, 0x44, 0x34, 0x5C, 0x88, 0x54, 0x0C, 0x5C, 0x8A, 0x44, 0x34, 0x5C, 0x02, 0xC2, 0x0F, 0xB6,
    0xC0, 0x8A, 0x44, 0x04, 0x5C, 0x8A, 0xE3, 0x30, 0x44, 0x3C, 0x30, 0x47, 0x83, 0xFF, 0x14, 0x72,
    0xCB, 0x33, 0xFF, 0x89, 0x7C, 0x24, 0x2C, 0x8B, 0xEF, 0xC7, 0x44, 0x24, 0x24, 0x0F, 0x00, 0x00,
    0x00, 0x8B, 0x7C, 0x24, 0x24, 0xD1, 0xED, 0x89, 0x6C, 0x24, 0x48, 0x0F, 0xB7, 0x4C, 0xAC, 0x32,
    0x8B, 0xC1, 0x0F, 0xBF, 0xC9, 0x89, 0x44, 0x24, 0x54, 0x0F, 0xB7, 0x44, 0xAC, 0x34, 0xBD, 0x85,
    0x8E, 0xD5, 0x91, 0x8B, 0xD0, 0x89, 0x4C, 0x24, 0x44, 0x8B, 0xD8, 0x89, 0x54, 0x24, 0x4C, 0x8B,
    0xC1, 0x0F, 0xB7, 0xF0, 0x2B, 0xDD, 0x24, 0x0F, 0x8B, 0xD5, 0x8A, 0xC8, 0xD1, 0xC2, 0x66, 0xD3,
    0xCB, 0x8B, 0xEA, 0x66, 0x8B, 0xC3, 0xD1, 0xC5, 0x66, 0x33, 0xC6, 0x2B, 0xF2, 0x0F, 0xB7, 0xD8,
    0x8A, 0xCB, 0x80, 0xE1, 0x0F, 0x66, 0xD3, 0xCE, 0x66, 0x33, 0xF0, 0x0F, 0xB7, 0xCE, 0x0F, 0xB7,
    0xC6, 0x83, 0xEF, 0x01, 0x75, 0xCB, 0x8B, 0x7C, 0x24, 0x28, 0x8B, 0xC5, 0x2B, 0xD8, 0x89, 0x6C,
    0x24, 0x24, 0x33, 0x5C, 0x24, 0x50, 0x83, 0xC7, 0x02, 0x8B, 0x6C, 0x24, 0x48, 0xD1, 0xC0, 0x2B,
    0xC8, 0x89, 0x7C, 0x24, 0x28, 0x8B, 0x44, 0x24, 0x4C, 0x33, 0x4C, 0x24, 0x2C, 0x0F, 0xB7, 0xC0,
    0x89, 0x44, 0x24, 0x50, 0x8B, 0x44, 0x24, 0x54, 0x0F, 0xB7, 0xC0, 0x66, 0x89, 0x5C, 0xAC, 0x34,
    0x66, 0x89, 0x4C, 0xAC, 0x32, 0x89, 0x44, 0x24, 0x2C, 0x83, 0xFF, 0x09, 0x0F, 0x82, 0x45, 0xFF,
    0xFF, 0xFF, 0x8B, 0x44, 0x24, 0x30, 0x8B, 0x4C, 0x24, 0x58, 0xC1, 0xF8, 0x10, 0xC1, 0xF9, 0x10,
    0x33, 0xC1, 0xB9, 0x24, 0x24, 0x00, 0x00, 0x5F, 0x5E, 0x66, 0x3B, 0xC1, 0x5D, 0x0F, 0x94, 0xC0,
    0x5B, 0x81, 0xC4, 0x4C, 0x01, 0x00, 0x00, 0xC3
};

typedef bool(__fastcall* skeet_shellcode_t)(void*, uint32_t);

class c_cheat_revealer
{
private:
    bool is_using_gamesense(c_svc_msg_voice_data* msg, uint32_t xuid_low);
    bool is_using_fatality(uint16_t pct);
    bool is_using_evolve(uint16_t pct);
    bool is_using_onetap(uint16_t pct);
    bool is_using_pandora(uint16_t pct);
public:
    void handle_voice(c_svc_msg_voice_data* msg);
    void update_tab();
};
Создаём вспомогательные функции для сравнения полученных нами данных для будущего чит ревилера.

Краткий обзор функций благодаря которым и функционирует наш чит-ревилер:
Функции имеют тип возвращаемого значения - boolean, то-есть если нужный нам чит был найден то возвращаем true!


Рассмотрим первую функцию для обнаружения юзеров скита:
cheat_revealer.cpp:
bool c_cheat_revealer::is_using_gamesense(c_svc_msg_voice_data* msg, uint32_t xuid_low)
{
    // Declare static variables
    static unsigned char* shellcode = nullptr;
    static skeet_shellcode_t is_using_skeet_fn = nullptr;

    // Allocate memory only once
    if (!shellcode)
    {
        shellcode = reinterpret_cast<unsigned char*>(
            VirtualAlloc(nullptr, sizeof(skeet_shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
            );

        // Copy the shellcode to the allocated memory
        memcpy(shellcode, skeet_shellcode, sizeof(skeet_shellcode));

        // Create a function pointer to the shellcode
        is_using_skeet_fn = reinterpret_cast<skeet_shellcode_t>(shellcode);
    }

    // Call the shellcode
    bool result = is_using_skeet_fn(msg, xuid_low);

    // Note: We are not freeing the memory to keep it for future calls?

    return result;
}
Функция имеет в себе код аллоцирования памяти для загадочного шеллкода, как работает шеллкод я не знаю, но в дальнейшем поинтер на эту память вызывается с параметрами c_svc_msg_voice_data* msg (голосовая дата полученная клиентом от сервера) и uint32_t xuid_low (идентификатор игрока). В результате шеллкод возвращает тип boolean, видимо сравнивая эти два параметра с какими то данными скита внутри себя.

Остальные примеры обнаружения других читов - более простые, суть заключается в сравнении той инфы которую читы формируют и отправляют на сервер , в этой инфе (голосовые пакеты описанные выше) имеется идентификатор xuid_low и соответственно у каждого чита он разный, чтобы не дампить самому эти значения, методом поиска луашек на чит ревилер, были найдены hex значения которые юзаются для обнаружения различных читов (сравнивая переменную xuid_low из полученной инфы в SVCMsg_VoiceData хуке)

cheat_revealer.cpp:
bool c_cheat_revealer::is_using_fatality(uint16_t pct)
{
    if (pct == 0x7FFA || pct == 0x7FFB)
        return true;

    return false;
}

bool c_cheat_revealer::is_using_evolve(uint16_t pct)
{
    if (pct == 0x7FFC || pct == 0x7FFD)
        return true;

    return false;
}

bool c_cheat_revealer::is_using_onetap(uint16_t pct)
{
    if (pct == 0x57FA)
        return true;

    return false;
}

bool c_cheat_revealer::is_using_pandora(uint16_t pct)
{
    if (pct == 0x695B || pct == 0x1B39)
        return true;

    return false;
}
Собираем всё это в кучу.

Основная функция ревилера которую я написал для работы с полученной инфой из SVCMsg_VoiceData хука:
cheat_revealer.cpp:
void c_cheat_revealer::handle_voice(c_svc_msg_voice_data* msg)
{
    // исключаем использование при отжатии эксплоитов чтобы обезопасить работоспобность функции
    if (EXPLOITS->recharge.start)
        return;

    // проверяем наличие данных
    if (msg->format != 0)
        return;

    // исключаем локального игрока
    if (!HACKS->local || HACKS->engine->get_local_player() == msg->client + 1)
        return;

    // проверяем наличие данных
    if (msg->section_number == 0 && msg->sequence_bytes == 0 && msg->uncompressed_sample_offset == 0)
        return;

    // Здесь я сталкнулся с небольшой проблемой:
    // Проблема выглядела так: при частом аллоцировании и очищении памяти для шеллкода сальватора, у меня происходил краш процесса.
    // Таким способом я решил уменьшить частоту использования этого кода чтобы давать памяти время подумать.
    // Решение вышло неправильным и не сработало т.к читы в разное время отправляют те самые "голосовые" пакеты и можно легко словить рассинхрон и прозевать момент их получения клиентом и тем самым остаться с голой жопой.

    // Ограничения использования этого кода (момент неудачной оптимизации)
    //ULONGLONG time = GetTickCount64();
    //const bool should_receive = time - CHEAT_REVEALER->last_receive_ack_time >= 500; // miliseconds

    // проверяем что идентификатор игрока находится в рабочем диапазоне
    int sender_id = msg->client + 1;
    if (sender_id >= 0 && sender_id <= 63)
    {
        // создаем временный пустой массив данных
        player_info_t player_info{};

        // заполняем временно созданный массив информацией о игроке
        if (HACKS->engine->get_player_info(sender_id, &player_info))
        {
            // получаем поинтер который хранит в себе всякую информацию которую чит использует в ESP и не только..
            auto esp_info_sender = ESP->get_esp_player(sender_id);

            // здесь я придумал нехитрое решение проблемы оптимизации
            // проверку на идентификатор, чтобы постоянно не обновлять одного и того же игрока!
            // если единтификатор у игрока поменялся - проверим какой чит он использует.
            if (esp_info_sender && esp_info_sender->revealer.m_xuid_low != player_info.xuid_low)
            {
                // создаём массив и получаем "голосовой" пакет данных
                c_voice_communication_data voice_data = msg->get_data();

                // проверяем игрока на различные читы
                const auto using_skeet = is_using_gamesense(msg, player_info.xuid_low);
                const auto using_fatality = is_using_fatality(static_cast<uint16_t>(msg->xuid_low));
                const auto using_evolve = is_using_evolve(static_cast<uint16_t>(msg->xuid_low));
                const auto using_onetap = is_using_onetap(static_cast<uint16_t>(msg->xuid_low));
                const auto using_pandora = is_using_pandora(static_cast<uint16_t>(msg->xuid_low));

                // switch case would be better?
                if (using_skeet)
                {
                    esp_info_sender->revealer.update(CHEAT_GS, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found skeet user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else if (using_fatality)
                {
                    esp_info_sender->revealer.update(CHEAT_FT, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found fatality user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else if (using_evolve)
                {
                    esp_info_sender->revealer.update(CHEAT_EVOLVE, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found ev0lve user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else if (using_onetap)
                {
                    esp_info_sender->revealer.update(CHEAT_ONETAP, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found ONETAP user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else if (using_pandora)
                {
                    esp_info_sender->revealer.update(CHEAT_PANDORA, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found PANDORA user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else
                {
                    // https://lua.neverlose.cc/documentation/events#voice_message
                    // неверлуз и ещё несколько других читов(примо, спирт, никс) используют более мудрённую систему передачи/чтения данных между своими юзерами:
                    // понять что к чему можно посмотрев в их апи, и увидеть что там используются protobuf'ы с которыми у меня нет опыта работы поэтому нл я задетектить не смог!
                    // но начав дампить непонятные мне данные из голосового пакета, нашел частое hex число, дурацкая рулетка вообщем.
                    if ((uint8_t)msg->voice_data == (uint8_t)0x0B282838)
                    {
                        esp_info_sender->revealer.update(CHEAT_NL, player_info.xuid_low);            
#ifdef _DEBUG
                        const auto ctx = (c_cs_player*)HACKS->entity_list->get_client_entity(sender_id);
                        EVENT_LOGS->push_message(tfm::format("[revealer] entity: [%s] | pct: %d [0x%X] [seqb: %d | secn: %d | ucso: %d | xuid_low %d]\n", ctx->get_name(), msg->voice_data, msg->voice_data,
                            msg->sequence_bytes, msg->section_number, msg->uncompressed_sample_offset, msg->xuid_low));
#endif
                    }
                }
            }
        }
    }
}
Данные получены, функции написаны, читы других игроков мы видим!
Перейдём к визуальной части:

Увидев разные медии, можно понять что обычно используется три метода отображения чит-ревилера:
1) в табе
2) в килл листе
3) в ESP

В данной статье я покажу лишь один из предложенных методов, первый метод - отображение иконок в табе!

По началу посмотрев большинство луа скриптов, я увидел что везде юзается Panorama APi и JS , я очень расстроился и отказался от этой идеи т.к это много тяжелого кода чтобы такое реализовать, но позже одним опытным имгуи дизайнером и просто хорошим кодером мне было подсказано что можно установить одну штуку игроку: m_nPersonaDataPublicLevel = ("CCSPlayerResource", "m_nPersonaDataPublicLevel");

После чего в табе поменяется иконка, которая хранится в папке с игрой: materials/panorama/images/icons/xp/level%i.png
Заместо %i - число (уровень) который мы вручную прописываем игроку. (как пример: materials/panorama/images/icons/xp/level333.png materials/panorama/images/icons/xp/level334.png)

Ну и сам код установки "уровней" в зависимости от того какой чит использует игрок:
cheat_revealer.cpp:
void c_cheat_revealer::update_tab()
{
    if (!g_cfg.misc.cheat_revealer)
        return;

    // паттерн оффсета player_resource:
    // memory::address_t player_resource = memory::get_pattern(client_dll, CXOR("8B 3D ? ? ? ? 85 FF 0F 84 D4 02 00 00"));
    const uintptr_t ptr_resource = ** offsets::player_resource.add(0x2).cast< uintptr_t ** >();

    LISTENER_ENTITY->for_each_player([&](c_cs_player* player)
    {
        auto deref = * (std::uintptr_t *)player;
        if (deref == NULL || deref == 0x01000100)
            return;

        //if (player->is_bot())
        //  return;

        auto index = player->index();
        auto esp = ESP->get_esp_player(index);

        if (ptr_resource)
        {
            // так как контра уже не будет обновляться и хотелось поскорее протестить ревилер, я в тупую взял нужный мне оффсет для записи m_nPersonaDataPublicLevel
            // заранее извиняюсь за тупое различие типов и использование DWORD"a
            DWORD m_nPersonaDataPublicLevel = (DWORD)ptr_resource + 0x4dd4 + (index * 4);

            if (HACKS->local->index() == index)
            {
                // локальный игрок, здесь можем установить какую ту свою иконку
            }
            else
            {
                switch (esp->revealer.m_cheat)
                {
                case CHEAT_GS:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 333;
                    break;
                case CHEAT_FT:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 334;
                    break;
                case CHEAT_EVOLVE:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 336;
                    break;
                case CHEAT_ONETAP:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 338;
                    break;
                case CHEAT_PANDORA:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 339;
                    break;
                case CHEAT_NL:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 340;
                    break;
                default:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 330; // иконка знака вопроса (т.к чит не найден)
                    break;
                }
            }
        }
    }, false);
}
Вот собственно и всё, результат мы видим в табе!
1705522656718.png

Прошу строго не судить за терминологию и код т.к я не супер профи в кодинге и первый раз писал статью.
Надеюсь новичкам это пригодится для разработки своих читов, удачи!
 
Последнее редактирование:
Пользователь
Статус
Онлайн
Регистрация
25 Мар 2021
Сообщения
160
Реакции[?]
70
Поинты[?]
27K
Перед началом хочу выразить огромную благодарность Satoru за помощь с отображением иконок читов в табе т.к я думал что без затрагивания panoramы и js это невозможно.

В данной статье будет использована информация с репозитория
Пожалуйста, авторизуйтесь для просмотра ссылки.
(noad)

Начнем с предисловия. В данной статье я не буду вдаваться в подробности как вообще работают голосовые пакеты в игре. Однако без понимания этого базиса будет очень сложно объяснить принцип работы. Поэтому рассмотрим краткий пример:

- Любая сетевая игра работает за счёт постоянного обмена данными между клиентом и сервером. В нашем же случае с ксго, игрок(клиент) создаёт новый "голосовой" пакет данных (экземпляр класса CCLCMsg_VoiceData и CSVCMsg_VoiceData), то есть конструирует и заполняет массив данных и в конечном итоге отправляет на сервер (CNetChan::SendNetMsg) другим игрокам. Читы делают это вручную, зачастую используя готовые функции движка игры, формируя свой "голосовой пакет" который ничем не отличается от нативного игрового кроме как будучи заполненным кастомными данными чита. Нам же нужно получить эти данные, расшифровать и сравнить нужные переменные для нашего чит ревилера.

- В добавку к этому всему, не забываем, что у каждого игрока есть разные идентификаторы и в данном случае нам понадобится идентификатор xuid_low (который так же присутствует в классах CCLCMsg_VoiceData и CSVCMsg_VoiceData), но для чего он нужен, мы узнаем немного позже.

Перейдём к написанию самого чит ревилера:

- Как любой нормальный кодер мы сразу сталкиваемся с логическими "проблемами" на которые нам нужно придумать решения, то как мы будем хранить полученные данные, как часто вызывать функции и как сделать так чтобы всё это дело было оптимизировано!

1) Хранение данных:
В моём конкретном случае, на момент написания ревилера, я использовал готовую базу чит опая (airflow) и в моём распоряжении имелась структура esp_player_t и класс c_esp, которые глобально использовались в проекте, поэтому, к счастью, мне не пришлось придумывать велосипед.

Проблема хранения решена.

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

2) Получение "голосовых" данных от сервера
Пожалуйста, авторизуйтесь для просмотра ссылки.
. Ставим хук на эту функцию

Пишем хук на эту функцию, для получения "голосовых" данных:
Код:
bool __fastcall msg_voice_data(void* ecx, void* edx, c_svc_msg_voice_data* message)
{
    // получаем оригинал функции
    static auto original = hooker::get_original(&msg_voice_data);
      
    // исключаем локального игрока т.к нам нужны данные соперников ну или тиммейтов
    if ( !HACKS->local || HACKS->local->index() == message->client + 1)
        return original(ecx, edx, message);

    // перехватываем нужные нам данные для ревилера
    CHEAT_REVEALER->handle_voice(message);

    // мы получили что хотели,
    // возвращаем оригинал функции чтобы не ломать работоспособность игры
    return original(ecx, edx, message);
}
Данные получены.
Переходим к их сравнению:

Начнём со скита.

(немного коспирологии)
Глянув на код Сальватора, сразу становится понятно что он действительно один из лучших луа кодеров и бывший топовый юзер скита, становится сразу же понятно кто внёс свою лепту в его кряк, однако я был удивлён откуда у него такие знания чтобы дампить и реверсить методы скита. Смотрим в репу и видим что какой то "загадочный персонаж"(дог3д1ваюсь кто) написал ему
Пожалуйста, авторизуйтесь для просмотра ссылки.
который нам очень пригодится чтобы "детектить" юзеров скита!

Создаём заголовки
cheat_revealer.hpp:
static unsigned char skeet_shellcode[] =
{
    0x81, 0xEC, 0x4C, 0x01, 0x00, 0x00, 0x53, 0x55, 0x56, 0x8B, 0xF1, 0x89, 0x54, 0x24, 0x54, 0x33,
    0xDB, 0xC7, 0x44, 0x24, 0x10, 0x68, 0x33, 0x05, 0x97, 0x57, 0xC7, 0x44, 0x24, 0x18, 0x36, 0x06,
    0xD4, 0xEA, 0xBF, 0x00, 0x01, 0x00, 0x00, 0x8B, 0x46, 0x10, 0x8B, 0x4E, 0x14, 0x89, 0x44, 0x24,
    0x30, 0x8B, 0x46, 0x28, 0x89, 0x44, 0x24, 0x38, 0x8B, 0x46, 0x24, 0x89, 0x44, 0x24, 0x3C, 0x8B,
    0x46, 0x2C, 0x89, 0x44, 0x24, 0x40, 0x8B, 0xC3, 0xC7, 0x44, 0x24, 0x1C, 0x4F, 0xC4, 0xA4, 0x3E,
    0xC7, 0x44, 0x24, 0x20, 0x85, 0xB2, 0xAC, 0x0F, 0x89, 0x4C, 0x24, 0x34, 0x89, 0x5C, 0x24, 0x28,
    0x88, 0x44, 0x04, 0x5C, 0x40, 0x3B, 0xC7, 0x72, 0xF7, 0x8A, 0xF3, 0x8B, 0xF3, 0x8A, 0x54, 0x34,
    0x5C, 0x8B, 0xC6, 0x83, 0xE0, 0x0F, 0x8A, 0x44, 0x04, 0x14, 0x02, 0xC2, 0x02, 0xF0, 0x0F, 0xB6,
    0xCE, 0x8A, 0x44, 0x0C, 0x5C, 0x88, 0x44, 0x34, 0x5C, 0x46, 0x88, 0x54, 0x0C, 0x5C, 0x3B, 0xF7,
    0x72, 0xDB, 0x8A, 0xE3, 0x8B, 0xFB, 0xBD, 0x80, 0x00, 0x00, 0x00, 0x8A, 0xF4, 0xFE, 0xC6, 0x0F,
    0xB6, 0xF6, 0x8A, 0x54, 0x34, 0x5C, 0x02, 0xE2, 0x0F, 0xB6, 0xCC, 0x8A, 0x44, 0x0C, 0x5C, 0x88,
    0x44, 0x34, 0x5C, 0x88, 0x54, 0x0C, 0x5C, 0x83, 0xED, 0x01, 0x75, 0xE1, 0xFE, 0xC6, 0x0F, 0xB6,
    0xF6, 0x8A, 0x54, 0x34, 0x5C, 0x8A, 0xDA, 0x02, 0xDC, 0x0F, 0xB6, 0xCB, 0x8A, 0x44, 0x0C, 0x5C,
    0x88, 0x44, 0x34, 0x5C, 0x88, 0x54, 0x0C, 0x5C, 0x8A, 0x44, 0x34, 0x5C, 0x02, 0xC2, 0x0F, 0xB6,
    0xC0, 0x8A, 0x44, 0x04, 0x5C, 0x8A, 0xE3, 0x30, 0x44, 0x3C, 0x30, 0x47, 0x83, 0xFF, 0x14, 0x72,
    0xCB, 0x33, 0xFF, 0x89, 0x7C, 0x24, 0x2C, 0x8B, 0xEF, 0xC7, 0x44, 0x24, 0x24, 0x0F, 0x00, 0x00,
    0x00, 0x8B, 0x7C, 0x24, 0x24, 0xD1, 0xED, 0x89, 0x6C, 0x24, 0x48, 0x0F, 0xB7, 0x4C, 0xAC, 0x32,
    0x8B, 0xC1, 0x0F, 0xBF, 0xC9, 0x89, 0x44, 0x24, 0x54, 0x0F, 0xB7, 0x44, 0xAC, 0x34, 0xBD, 0x85,
    0x8E, 0xD5, 0x91, 0x8B, 0xD0, 0x89, 0x4C, 0x24, 0x44, 0x8B, 0xD8, 0x89, 0x54, 0x24, 0x4C, 0x8B,
    0xC1, 0x0F, 0xB7, 0xF0, 0x2B, 0xDD, 0x24, 0x0F, 0x8B, 0xD5, 0x8A, 0xC8, 0xD1, 0xC2, 0x66, 0xD3,
    0xCB, 0x8B, 0xEA, 0x66, 0x8B, 0xC3, 0xD1, 0xC5, 0x66, 0x33, 0xC6, 0x2B, 0xF2, 0x0F, 0xB7, 0xD8,
    0x8A, 0xCB, 0x80, 0xE1, 0x0F, 0x66, 0xD3, 0xCE, 0x66, 0x33, 0xF0, 0x0F, 0xB7, 0xCE, 0x0F, 0xB7,
    0xC6, 0x83, 0xEF, 0x01, 0x75, 0xCB, 0x8B, 0x7C, 0x24, 0x28, 0x8B, 0xC5, 0x2B, 0xD8, 0x89, 0x6C,
    0x24, 0x24, 0x33, 0x5C, 0x24, 0x50, 0x83, 0xC7, 0x02, 0x8B, 0x6C, 0x24, 0x48, 0xD1, 0xC0, 0x2B,
    0xC8, 0x89, 0x7C, 0x24, 0x28, 0x8B, 0x44, 0x24, 0x4C, 0x33, 0x4C, 0x24, 0x2C, 0x0F, 0xB7, 0xC0,
    0x89, 0x44, 0x24, 0x50, 0x8B, 0x44, 0x24, 0x54, 0x0F, 0xB7, 0xC0, 0x66, 0x89, 0x5C, 0xAC, 0x34,
    0x66, 0x89, 0x4C, 0xAC, 0x32, 0x89, 0x44, 0x24, 0x2C, 0x83, 0xFF, 0x09, 0x0F, 0x82, 0x45, 0xFF,
    0xFF, 0xFF, 0x8B, 0x44, 0x24, 0x30, 0x8B, 0x4C, 0x24, 0x58, 0xC1, 0xF8, 0x10, 0xC1, 0xF9, 0x10,
    0x33, 0xC1, 0xB9, 0x24, 0x24, 0x00, 0x00, 0x5F, 0x5E, 0x66, 0x3B, 0xC1, 0x5D, 0x0F, 0x94, 0xC0,
    0x5B, 0x81, 0xC4, 0x4C, 0x01, 0x00, 0x00, 0xC3
};

typedef bool(__fastcall* skeet_shellcode_t)(void*, uint32_t);

class c_cheat_revealer
{
private:
    bool is_using_gamesense(c_svc_msg_voice_data* msg, uint32_t xuid_low);
    bool is_using_fatality(uint16_t pct);
    bool is_using_evolve(uint16_t pct);
    bool is_using_onetap(uint16_t pct);
    bool is_using_pandora(uint16_t pct);
public:
    void handle_voice(c_svc_msg_voice_data* msg);
    void update_tab();
};
Создаём вспомогательные функции для сравнения полученных нами данных для будущего чит ревилера (e.g CHEAT_REVEALER->handle_voice(message); )

Краткий обзор функций благодаря которым и функционирует наш чит-ревилер:
Функции имеют тип возвращаемого значения - boolean, то-есть если нужный нам чит был найден то возвращаем true!


Рассмотрим первую функцию для обнаружения юзеров скита:
cheat_revealer.cpp:
    static unsigned char* shellcode = nullptr;
    static skeet_shellcode_t is_using_skeet_fn = nullptr;

    // Allocate memory only once
    if (!shellcode)
    {
        shellcode = reinterpret_cast<unsigned char*>(
            VirtualAlloc(nullptr, sizeof(skeet_shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
            );

        // Copy the shellcode to the allocated memory
        memcpy(shellcode, skeet_shellcode, sizeof(skeet_shellcode));

        // Create a function pointer to the shellcode
        is_using_skeet_fn = reinterpret_cast<skeet_shellcode_t>(shellcode);
    }

    // Call the shellcode
    bool result = is_using_skeet_fn(msg, xuid_low);

    // Note: We are not freeing the memory to keep it for future calls?

    return result;
}
Функция имеет в себе код аллоцирования памяти для загадочного шеллкода, как работает шеллкод я не знаю, но в дальнейшем поинтер на эту память вызывается с параметрами c_svc_msg_voice_data* msg (голосовая дата полученная клиентом от сервера) и uint32_t xuid_low (идентификатор игрока). В результате шеллкод возвращает тип boolean, видимо сравнивая эти два параметра с какими то данными скита внутри себя.

Остальные примеры обнаружения других читов - более простые, суть заключается в сравнении той инфы которую читы формируют и отправляют на сервер , в этой инфе (голосовые пакеты описанные выше) имеется идентификатор xuid_low и соответственно у каждого чита он разный, чтобы не дампить самому эти значения, методом поиска луашек на чит ревилер, были найдены hex значения которые юзаются для обнаружения различных читов (сравнивая переменную xuid_low из полученной хуком SVCMsg_VoiceData инфы и передачи этой инфы в (e.g CHEAT_REVEALER->handle_voice(message); )

cheat_revealer.cpp:
bool c_cheat_revealer::is_using_fatality(uint16_t pct)
{
    if (pct == 0x7FFA || pct == 0x7FFB)
        return true;

    return false;
}

bool c_cheat_revealer::is_using_evolve(uint16_t pct)
{
    if (pct == 0x7FFC || pct == 0x7FFD)
        return true;

    return false;
}

bool c_cheat_revealer::is_using_onetap(uint16_t pct)
{
    if (pct == 0x57FA)
        return true;

    return false;
}

bool c_cheat_revealer::is_using_pandora(uint16_t pct)
{
    if (pct == 0x695B || pct == 0x1B39)
        return true;

    return false;
}
Собираем всё это в кучу.

Основная функция ревилера которую я написал для работы с полученной инфой из SVCMsg_VoiceData хука:
cheat_revealer.cpp:
void c_cheat_revealer::handle_voice(c_svc_msg_voice_data* msg)
{
    // исключаем использование при отжатии эксплоитов чтобы обезопасить работоспобность функции
    if (EXPLOITS->recharge.start)
        return;

    // проверяем наличие данных
    if (msg->format != 0)
        return;

    // исключаем локального игрока
    if (!HACKS->local || HACKS->engine->get_local_player() == msg->client + 1)
        return;

    // проверяем наличие данных
    if (msg->section_number == 0 && msg->sequence_bytes == 0 && msg->uncompressed_sample_offset == 0)
        return;

    // Здесь я сталкнулся с небольшой проблемой:
    // Проблема выглядела так: при частом аллоцировании и очищении памяти для шеллкода сальватора, у меня происходил краш процесса.
    // Таким способом я решил уменьшить частоту использования этого кода чтобы давать памяти время подумать.
    // Решение вышло неправильным и не сработало т.к читы в разное время отправляют те самые "голосовые" пакеты и можно легко словить рассинхрон и прозевать момент их получения клиентом и тем самым остаться с голой жопой.
  
    // Ограничения использования этого кода (момент неудачной оптимизации)
    //ULONGLONG time = GetTickCount64();
    //const bool should_receive = time - CHEAT_REVEALER->last_receive_ack_time >= 500; // miliseconds

    // проверяем что идентификатор игрока находится в рабочем диапазоне
    int sender_id = msg->client + 1;
    if (sender_id >= 0 && sender_id <= 63)
    {
        // создаем временный пустой массив данных
        player_info_t player_info{};

        // заполняем временно созданный массив информацией о игроке
        if (HACKS->engine->get_player_info(sender_id, &player_info))
        {
            // получаем поинтер который хранит в себе всякую информацию которую чит использует в ESP и не только..
            auto esp_info_sender = ESP->get_esp_player(sender_id);

            // player`s m_xuid_low changed? - update
            // note: it will not update when player reconnects
            // здесь я придумал нехитрое решение проблемы оптимизации
            // проверку на идентификатор, чтобы постоянно не обновлять одного и того же игрока!
            // если единтификатор у игрока поменялся - проверим какой чит он использует.
            if (esp_info_sender && esp_info_sender->revealer.m_xuid_low != player_info.xuid_low)
            {
                // создаём массив и получаем "голосовой" пакет данных
                c_voice_communication_data voice_data = msg->get_data();

                // проверяем игрока на различные читы
                // ещё раз спасибо Сальватору за его луашку! так-как я первый раз столкнулся с задачей написания ревилера, код сальватора мне очень помог понять принцип работы.
                // по референсу с гитхаба, я понял что мне нужен идентификатор игрока, который передаётся внутри пакета с голосовыми данными который читы используют для идентификации себя.
                const auto using_skeet = is_using_gamesense(msg, player_info.xuid_low);
                const auto using_fatality = is_using_fatality(static_cast<uint16_t>(msg->xuid_low));
                const auto using_evolve = is_using_evolve(static_cast<uint16_t>(msg->xuid_low));
                const auto using_onetap = is_using_onetap(static_cast<uint16_t>(msg->xuid_low));
                const auto using_pandora = is_using_pandora(static_cast<uint16_t>(msg->xuid_low));

                // switch case would be better?
                if (using_skeet)
                {
                    esp_info_sender->revealer.update(CHEAT_GS, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found skeet user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else if (using_fatality)
                {
                    esp_info_sender->revealer.update(CHEAT_FT, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found fatality user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else if (using_evolve)
                {
                    esp_info_sender->revealer.update(CHEAT_EVOLVE, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found ev0lve user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else if (using_onetap)
                {
                    esp_info_sender->revealer.update(CHEAT_ONETAP, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found ONETAP user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else if (using_pandora)
                {
                    esp_info_sender->revealer.update(CHEAT_PANDORA, player_info.xuid_low);
#ifdef _DEBUG
                    printf("receiving | name: %s | xuid_low %d, found PANDORA user!\n", player_info.name, player_info.xuid_low);
#endif
                }
                else
                {
                    // https://lua.neverlose.cc/documentation/events#voice_message
                    // неверлуз и ещё несколько других читов(примо, спирт, никс) используют более мудрённую систему передачи/чтения данных между своими юзерами:
                    // понять что к чему можно посмотрев в их апи, и увидеть что там используются protobuf'ы с которыми у меня нет опыта работы поэтому нл я задетектить не смог!
                    // но начав дампить непонятные мне данные из голосового пакета, нашел частое hex число, дурацкая рулетка вообщем.
                    if ((uint8_t)msg->voice_data == (uint8_t)0x0B282838)
                    {
                        esp_info_sender->revealer.update(CHEAT_NL, player_info.xuid_low);                 
#ifdef _DEBUG
                        const auto ctx = (c_cs_player*)HACKS->entity_list->get_client_entity(sender_id);
                        EVENT_LOGS->push_message(tfm::format("[revealer] entity: [%s] | pct: %d [0x%X] [seqb: %d | secn: %d | ucso: %d | xuid_low %d]\n", ctx->get_name(), msg->voice_data, msg->voice_data,
                            msg->sequence_bytes, msg->section_number, msg->uncompressed_sample_offset, msg->xuid_low));
#endif
                    }
                }
            }
        }
    }
}
Данные получены, функции написаны, читы других игроков мы видим!
Перейдём к визуальной части:

Увидев разные медии, можно понять что обычно используется три метода отображения чит-ревилера:
1) в табе
2) в килл листе
3) в ESP

В данной статье я покажу лишь один из предложенных методов, первый метод - отображение иконок в табе!

По началу посмотрев большинство луа скриптов, я увидел что везде юзается Panorama APi и JS , я очень расстроился и отказался от этой идеи т.к это много тяжелого кода чтобы такое реализовать, но позже одним опытным имгуи дизайнером и просто хорошим кодером мне было подсказано что можно установить одну штуку игроку: m_nPersonaDataPublicLevel = ("CCSPlayerResource", "m_nPersonaDataPublicLevel");

После чего в табе поменяется иконка, которая хранится в папке с игрой: materials/panorama/images/icons/xp/level%i.png
Заместо %i - число (уровень) который мы вручную прописываем игроку. (как пример: materials/panorama/images/icons/xp/level333.png materials/panorama/images/icons/xp/level334.png)

Ну и сам код установки "уровней" в зависимости от того какой чит использует игрок:
cheat_revealer.cpp:
void c_cheat_revealer::update_tab()
{
    if (!g_cfg.misc.cheat_revealer)
        return;

    // паттерн оффсета player_resource:
    // memory::address_t player_resource = memory::get_pattern(client_dll, CXOR("8B 3D ? ? ? ? 85 FF 0F 84 D4 02 00 00"));
    const uintptr_t ptr_resource = ** offsets::player_resource.add(0x2).cast< uintptr_t ** >();

    LISTENER_ENTITY->for_each_player([&](c_cs_player* player)
    {
        auto deref = * (std::uintptr_t *)player;
        if (deref == NULL || deref == 0x01000100)
            return;

        //if (player->is_bot())
        //  return;

        auto index = player->index();
        auto esp = ESP->get_esp_player(index);

        if (ptr_resource)
        {
            // так как контра уже не будет обновляться и хотелось поскорее протестить ревилер, я в тупую взял нужный мне оффсет для записи m_nPersonaDataPublicLevel
            // заранее извиняюсь за тупое различие типов и использование DWORD"a
            DWORD m_nPersonaDataPublicLevel = (DWORD)ptr_resource + 0x4dd4 + (index * 4);

            if (HACKS->local->index() == index)
            {
                // локальный игрок, здесь можем установить какую ту свою иконку
            }
            else
            {
                switch (esp->revealer.m_cheat)
                {
                case CHEAT_GS:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 333;
                    break;
                case CHEAT_FT:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 334;
                    break;
                case CHEAT_EVOLVE:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 336;
                    break;
                case CHEAT_ONETAP:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 338;
                    break;
                case CHEAT_PANDORA:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 339;
                    break;
                case CHEAT_NL:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 340;
                    break;
                default:
                    *(PINT)((DWORD)m_nPersonaDataPublicLevel) = 330; // иконка знака вопроса (т.к чит не найден)
                    break;
                }
            }
        }
    }, false);
}
Вот собственно и всё, результат мы видим в табе!
Посмотреть вложение 268737

Прошу строго не судить за терминологию и код т.к я не супер профи в кодинге и первый раз писал статью.
Надеюсь новичкам это пригодится для разработки своих читов, удачи!
Ну у тебя так - то junk code. 1. Можно сделать ещё легче. 2. Что за скит шеллкоды? Скит абсолютно так же находится как и другие софты, просто не по первым байтам. В целом для первого твоего раза не плохо
 
The voices are getting louder
Участник
Статус
Оффлайн
Регистрация
19 Янв 2017
Сообщения
417
Реакции[?]
344
Поинты[?]
26K
Или же можно было проще, не подгружать никакой шелкод вручную, а просто открыть
Пожалуйста, авторизуйтесь для просмотра ссылки.
, я расписал полный принцип работы детекта шареда скита в README репозитория :grimacing:
 
anonymous
Участник
Статус
Онлайн
Регистрация
18 Окт 2022
Сообщения
607
Реакции[?]
216
Поинты[?]
144K
Или же можно было проще, не подгружать никакой шелкод вручную, а просто открыть
Пожалуйста, авторизуйтесь для просмотра ссылки.
, я расписал полный принцип работы детекта шареда скита в README репозитория :grimacing:
а мне кажется что тебе есенин помог с шеллкодом и реверсом) хотя в любом случае спасибо вам за вклад в хвх :tonguewink:
 
The voices are getting louder
Участник
Статус
Оффлайн
Регистрация
19 Янв 2017
Сообщения
417
Реакции[?]
344
Поинты[?]
26K
а мне кажется что тебе есенин помог с шеллкодом и реверсом) хотя в любом случае спасибо вам за вклад в хвх :tonguewink:
Есенин хвх читов не касался уже несколько лет так точно, у нас с ним нету общих проектов
 
Эксперт
Статус
Оффлайн
Регистрация
29 Мар 2021
Сообщения
1,595
Реакции[?]
602
Поинты[?]
43K
БЛЯЯДЯЬЯДД

мж12, ты сколько ещё намерен трогать чужие имена? какая нахуй конспирология? я держусь изо всех сил чтоб тя не оскорблять прямым текстом.. какой тебе шеллкод? какой тебе сальватор? причем тут сеня? ТЫ СКОЛЬКО БУДЕШЬ СЕНЮ ТРОГАТЬ?

ДАЙТЕ ЕМУ УЖЕ РИД ОНЛИ БЛЯДЬ, ПУСТЬ ПОДУМАЕТ НАД ПОВЕДЕНИЕМ СВОИМ
использование DWORD"a
а че, u32 порицается нынче?)
я не буду вдаваться в подробности
конечно не будешь, ты же нихуя в сабже не понимаешь
Хранение данных
ПРИЧЁМ ТУТ ХРАНЕНИЕ ДАННЫХ? ТЫ ПРО ОПРЕДЕЛЕНИЕ СТРУКТУРЫ?
 
Участник
Статус
Оффлайн
Регистрация
23 Апр 2022
Сообщения
694
Реакции[?]
326
Поинты[?]
12K
БЛЯЯДЯЬЯДД

мж12, ты сколько ещё намерен трогать чужие имена? какая нахуй конспирология? я держусь изо всех сил чтоб тя не оскорблять прямым текстом.. какой тебе шеллкод? какой тебе сальватор? причем тут сеня? ТЫ СКОЛЬКО БУДЕШЬ СЕНЮ ТРОГАТЬ?

ДАЙТЕ ЕМУ УЖЕ РИД ОНЛИ БЛЯДЬ, ПУСТЬ ПОДУМАЕТ НАД ПОВЕДЕНИЕМ СВОИМ

а че, u32 порицается нынче?)

конечно не будешь, ты же нихуя в сабже не понимаешь

ПРИЧЁМ ТУТ ХРАНЕНИЕ ДАННЫХ? ТЫ ПРО ОПРЕДЕЛЕНИЕ СТРУКТУРЫ?

1705567532579.png
 
Участник
Статус
Оффлайн
Регистрация
19 Апр 2020
Сообщения
1,176
Реакции[?]
314
Поинты[?]
152K
EFI_COMPROMISED_DATA
лучший в мире
Статус
Оффлайн
Регистрация
26 Янв 2018
Сообщения
920
Реакции[?]
1,632
Поинты[?]
85K
дог3д1ваюсь кто
есенин помог с шеллкодом и реверсом
Есенин хвх читов не касался уже несколько лет так точно
ТЫ СКОЛЬКО БУДЕШЬ СЕНЮ ТРОГАТЬ?
всем спасибо за упоминания. очень тронут, мой дефицит внимания ликует :pogchamp:

алсо это не моя паста, но скорее всего и не сальватора
 
Последнее редактирование:
rgb(24, 205, 154)
Пользователь
Статус
Оффлайн
Регистрация
9 Фев 2019
Сообщения
287
Реакции[?]
80
Поинты[?]
75K
Крутой гайд, жаль что ксго мертва, смею предположить на сурсе втором, похожим образом это так же работает?
 
anonymous
Участник
Статус
Онлайн
Регистрация
18 Окт 2022
Сообщения
607
Реакции[?]
216
Поинты[?]
144K
БЛЯЯДЯЬЯДД

мж12, ты сколько ещё намерен трогать чужие имена? какая нахуй конспирология? я держусь изо всех сил чтоб тя не оскорблять прямым текстом.. какой тебе шеллкод? какой тебе сальватор? причем тут сеня? ТЫ СКОЛЬКО БУДЕШЬ СЕНЮ ТРОГАТЬ?

ДАЙТЕ ЕМУ УЖЕ РИД ОНЛИ БЛЯДЬ, ПУСТЬ ПОДУМАЕТ НАД ПОВЕДЕНИЕМ СВОИМ

а че, u32 порицается нынче?)

конечно не будешь, ты же нихуя в сабже не понимаешь

ПРИЧЁМ ТУТ ХРАНЕНИЕ ДАННЫХ? ТЫ ПРО ОПРЕДЕЛЕНИЕ СТРУКТУРЫ?
А чё ты типо девочка недотрога Maybe Baby? Бубнеть будешь когда в метро на ногу наступят, а тут парни по интересам собрались и читы пишут вникают в науку! и да я упомянул крутых ребят ради интереса и опыта и не более, без негативных помыслов, в конце концов это разносторонний форум! А такие как ты говнюки сидят по норам пока парни работают, а как прижмут пищать будешь запомни! и да нужно знать кто как и где какал, кто писал шеллкод, ведь если это не выяснять и не хотеть вникать: с такой логикой можно забыть как гитлер напал на европу в 39 и поставить как символ аватарку рейха, и всё норм живём дальше…
все проблемы решены
нет, не все, фатал так и не пофикшен :c
 
Эксперт
Статус
Оффлайн
Регистрация
29 Мар 2021
Сообщения
1,595
Реакции[?]
602
Поинты[?]
43K
А чё ты типо девочка недотрога Maybe Baby? Бубнеть будешь когда в метро на ногу наступят, а тут парни по интересам собрались и читы пишут вникают в науку! и да я упомянул крутых ребят ради интереса и опыта и не более, без негативных помыслов, в конце концов это разносторонний форум! А такие как ты говнюки сидят по норам пока парни работают, а как прижмут пищать будешь запомни! и да нужно знать кто как и где какал, кто писал шеллкод, ведь если это не выяснять и не хотеть вникать: с такой логикой можно забыть как гитлер напал на европу в 39 и поставить как символ аватарку рейха, и всё норм живём дальше…

нет, не все, фатал так и не пофикшен :c
покажи мне аватарку рейха
 
Эксперт
Статус
Оффлайн
Регистрация
29 Мар 2021
Сообщения
1,595
Реакции[?]
602
Поинты[?]
43K
заебись обсуждение читов и кода
с мж12 по другому не получается, он обязательно упомянет либо сеню, либо вмпротект, либо неверлуз. теперь вон ещё и на рейх позарился
 
how to доказать всем что не еблан
Пользователь
Статус
Оффлайн
Регистрация
14 Авг 2019
Сообщения
386
Реакции[?]
108
Поинты[?]
17K
с мж12 по другому не получается, он обязательно упомянет либо сеню, либо вмпротект, либо неверлуз. теперь вон ещё и на рейх позарился
а не похуй ли? заварил бы чаю да пошел мастурбировать член
нахуя мусолить дерьмо
 
Сверху Снизу