Войти или зарегистрироваться
  • Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.
  • Данный раздел создан исключительно для релизов! Вопросы по лаунчеру или обвязке задавайте ТОЛЬКО в соответсвующей теме автора. Любые другие темы будут удалены, а авторы понесут наказание.

Лаунчер [C++17|Avn2]: Пишем защиту вместе! #7 Виртуализация на службе у читера

ПРИВЕТ ПОМОГИ ПЖ!!!!
у меня не работает плиз помогии!!!!!!!!
я даун!!!
дебаг из лаунчер - https://pastebin.com/mTz5j5Ws
дебаг из cmd - https://pastebin.com/JuKTwLh8
Ругался, ругался, а теперь просишь помощи?
Подозреваю, что проблема в этой строчке:
Код:
2019-08-30 09:59:06 [SEVERE] [ForgeModLoader] FML appears to be missing any signature data. This is not a good thing
Проверь свою сборку - в частности, корректность форджа.
Не знаю, какая версия моей библиотеки там стоит, но, в любом случае, сработок нет, лог чистый.
 
Последнее редактирование:
#6: Защищаемся от скана памяти.

Маленькая заметка о том, как можно было бы защититься от CheatEngine, если бы не одно но.

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

Отдельные страницы памяти, к которым длительное время не обращался процессор, ради экономии могут быть сброшены на диск в файл подкачки, а набор страниц, размещённых в данный момент в оперативной памяти, называется "рабочим набором" процесса.

Если страница сброшена в файл подкачки, то любое обращение к ней заставит систему загрузить страницу обратно в оперативную память. Скан памяти перебирает все страницы процесса и все сброшенные в подкачку страницы будут загружены в рабочий набор. На этом и построен детект.

Концепция проста: с помощью VirtualAlloc выделяем страницы, за наличием которых в рабочем наборе мы будем следить. И принудительно сбрасываем эти страницы в файл подкачки функцией VirtualUnlock. Периодически проверяем наличие страниц в рабочем наборе с помощью функции QueryWorkingSetEx. Как только одна из этих страниц снова окажется в рабочем наборе (загружена в оперативную память из свопа) - значит, кто-то попытался к ней обратиться. А так как никто из нашего процесса к ней обратиться не мог - делаем вывод, что нашу память сканируют.

Пример:
Код:
#include <Windows.h>
#include <Psapi.h>

class MemoryWatcher {
private:
    PVOID m_readwrite;
    PVOID m_executable;
public:
    MemoryWatcher()
        : m_readwrite(VirtualAlloc(NULL, USN_PAGE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))
        , m_executable(VirtualAlloc(NULL, USN_PAGE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE))
    {
        memset(m_readwrite, 0xAA, USN_PAGE_SIZE);
        memset(m_executable, 0xAA, USN_PAGE_SIZE);
        removeFromWorkingSet();
    }
    ~MemoryWatcher()
    {
        VirtualFree(m_readwrite, 0, MEM_RELEASE);
        VirtualFree(m_executable, 0, MEM_RELEASE);
    }
    void removeFromWorkingSet()
    {
        VirtualUnlock(m_readwrite, USN_PAGE_SIZE);
        VirtualUnlock(m_executable, USN_PAGE_SIZE);
    }
    void loadToWorkingSet()
    {
        *reinterpret_cast<ULONG*>(m_readwrite) = 0xAA;
        *reinterpret_cast<ULONG*>(m_executable) = 0xAA;
    }
    bool isAnyInWorkingSet()
    {
        PSAPI_WORKING_SET_EX_INFORMATION info[2] = {};
        info[0].VirtualAddress = m_readwrite;
        info[1].VirtualAddress = m_executable;
        BOOL status = QueryWorkingSetEx(GetCurrentProcess(), info, sizeof(info));
        if (!status) return false;

        for (unsigned int i = 0; i < _countof(info); ++i)
        {
            if (info[i].VirtualAttributes.Flags != 0x0D400000)
            {
                return true;
            }
        }

        return false;
    }
};

...

unsigned int getSeconds()
{
    return static_cast<unsigned int>(__rdtsc() >> 32);
}

int main()
{
    auto time = getSeconds();

    MemoryWatcher watcher;

    while (true)
    {
        auto current = getSeconds();
        if (current - time > 1)
        {
            bool isScanned = watcher.isAnyInWorkingSet();
            if (isScanned)
            {
                __fastfail(0);
            }
            time = current;
        }
    }
}

Однако, не всё так просто.
Этот способ спасёт от сканирования памяти из юзермода, работающего на основе ReadProcessMemory, или от поиска сигнатур из внедрённой в процесс дллки чита. Однако, способ не будет работать на сканах памяти из ядра, т.к., в большинстве случаев, скан производится не в памяти самого процесса, а в отображении этих страниц на ядерное адресное пространство (KeStackAttachProcess -> MmProbeAndLockPages -> MmMapLockedPagesSpecifyCache) - таким образом, рабочий набор процесса не затрагивается.

В CheatEngine режим скана из драйвера активируется в настройках (Edit -> Settings):
upload_2020-2-28_0-39-16.png

И, разумеется, файл подкачки может быть отключен - нужно дополнительно обрабатывать этот случай, чтобы избежать ложных срабатываний из-за того, что наши контрольные страницы всегда будут в рабочем наборе процесса.
 
Последнее редактирование:
Спасибо за топик, очень познавательно и информативно. Будешь ли разбирать примеры защиты с помощью jni и jmvti?
 
Спасибо за топик, очень познавательно и информативно. Будешь ли разбирать примеры защиты с помощью jni и jmvti?
Моя область интересов - внутреннее устройство операционок и околожелезячный уровень, а про внутреннее устройство джавы почти ничего не знаю, так что нет. По джаве пинай @NyanKa, это его вотчина.
 
Спасибо за топик, очень познавательно и информативно. Будешь ли разбирать примеры защиты с помощью jni и jmvti?
Не умеет он в такое, потому его античиты блокируют всех кроме самих читаков :D.
Себе дороже такое юзать.
 
#7: Виртуализация на службе у читера

upload_2020-5-31_22-32-20.png​

Развитие технологий аппаратной виртуализации (Intel VT-x и AMD-V) открывает широкие возможности по контролю выполнения кода на самом низком уровне. Привычные всем гипервизоры (Hyper-V, KVM, VMware или VirtualBox - и многие другие) позволяют запускать операционные системы в изолированном окружении: это становится возможным, благодаря способности процессоров работать в специальном режиме, в котором он может контролировать доступ к ресурсам и обрабатывать выполнение некоторых инструкций и событий.

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

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

Так как разработка гипервизоров - обширная тема, выходящая за рамки одной статьи, ограничимся лишь вводным экскурсом и рассмотрим виртуализацию живой системы на примере проекта Kernel-Bridge.

Несмотря на то, что Intel VT-x (другое название VMX - Virtual Machine Extensions) и AMD-V (SVM - Secure Virtual Machine) очень сильно различаются в деталях реализации, они работают по схожему и простому принципу:
1. В процессоре включается поддержка виртуализации.
2. Настраивается контекст процессора (состояние регистров), с которым он выполнит первую инструкцию в виртуальном режиме (в режиме гостя).
3. Настраивается гостевое адресное пространство (память, что будет доступна виртуальному процессору).
4. Настраиваются события, которые требуют специальной обработки (доступ к портам, регистрам и памяти, выполнение особых инструкций и т.д.).
5. Настраивается состояние монитора виртуальных машин (VMM), который получит управление при наступлении одного из событий, заданных в пункте 4.
6. Процессор переводится в виртуальный режим выполнением специальной инструкции ("vmlaunch" на VT-x и "vmrun" на AMD-V) и начинает работу в настроенном гостевом окружении.

Как только на виртуализованном процессоре происходит событие, заданное при настройке, он выходит в монитор виртуальных машин (VMM) - этот процесс называется #VMEXIT. Процессор сохраняет состояние виртуальной машины и отдаёт управление заданному обработчику. Тот обрабатывает событие (например, меняет значение регистров или содержимое памяти) и снова передаёт управление виртуальной машине.

Основываясь на этих принципах, можно перевести все логические процессоры в виртуальный режим прозрачно для работающей системы - таким образом, что виртуальная система продолжит выполнять код хоста, находясь в общем с хостом адресном пространстве. Таким образом, это потребует минимальной настройки гипервизора:
- Физическая память гостевого режима соотносится с физической памятью хоста один к одному (т.е., гостевой физический адрес 0x12345 будет соответствовать такому же хостовому физическому адресу 0x12345).
- Состояние регистров гостя на момент входа в виртуальный режим задаётся равным регистрам хоста.

С заданными начальными условиями виртуальный процессор "продолжит" выполнять за хостом его код - но уже под виртуализацией. Таким образом будет виртуализована вся операционная система.

Детали реализации гипервизоров можно посмотреть здесь (подмена CPUID, обработка скрытия памяти).

Пример:
Код:
#include <Windows.h>

#include "WdkTypes.h"
#include "CtlTypes.h"
#include "User-Bridge.h"

void* GetFuncPtr(const void* Func)
{
    if (!Func) return nullptr;
    const auto* FuncDataPtr = reinterpret_cast<const unsigned char*>(Func);
    if (*FuncDataPtr == 0xE9)
    {
        auto Offset = *reinterpret_cast<const int*>(FuncDataPtr + 1);
        return const_cast<unsigned char*>((FuncDataPtr + 5) + Offset);
    }
    else
    {
        return const_cast<void*>(Func);
    }
}

#pragma section(".hidden", read, execute, nopage)
__declspec(code_seg(".hidden")) unsigned int HiddenFunc()
{
    printf("Called from the hidden func\n");
    return 0x1EE7C0DE;
}

VOID TestMemoryHiding()
{
    using namespace Hypervisor;
    using namespace PhysicalMemory;

    constexpr unsigned int PageSize = 4096;

    // Выделяем память, на которую будем подменять нужную страницу (отдельно на чтение и запись):
    volatile PBYTE Read = reinterpret_cast<PBYTE>(VirtualAlloc(NULL, PageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE));
    volatile PBYTE Write = reinterpret_cast<PBYTE>(VirtualAlloc(NULL, PageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE));
    volatile PBYTE Execute = reinterpret_cast<PBYTE>(GetFuncPtr(HiddenFunc));

    // Предотвратим сброс страниц в своп:
    VirtualLock(Read, PageSize);
    VirtualLock(Write, PageSize);
    VirtualLock(Execute, PageSize);

    // Заполним подменные страницы данными, которые будут показываться на чтение и запись:
    memset(Read, 0xFF, PageSize);
    memset(Write, 0xEE, PageSize);

    // Получим физические адреса всех страниц:
    WdkTypes::PVOID64 ReadPa = 0, WritePa = 0, ExecutePa = 0;
    KbGetPhysicalAddress(NULL, reinterpret_cast<WdkTypes::PVOID>(Read), &ReadPa);
    KbGetPhysicalAddress(NULL, reinterpret_cast<WdkTypes::PVOID>(Write), &WritePa);
    KbGetPhysicalAddress(NULL, reinterpret_cast<WdkTypes::PVOID>(Execute), &ExecutePa);
 
    // Установим на чтение и запись подменные страницы, на исполнение - оригинал:
    KbVmmInterceptPage(ExecutePa, ReadPa, WritePa, ExecutePa);
    HiddenFunc(); // Проверим
    KbVmmDeinterceptPage(ExecutePa);

    VirtualUnlock(Execute, PageSize);
    VirtualUnlock(Write, PageSize);
    VirtualUnlock(Read, PageSize);

    VirtualFree(Write, 0, MEM_RELEASE);
    VirtualFree(Read, 0, MEM_RELEASE);
}

void PrintCpuid()
{
    int regs[4] = {};
    __cpuid(regs, 0);
    char str[13] = {};
    // CPUID Vendor = RBX + RDX + RCX:
    *(int*)(str + 0) = regs[1]; // RBX
    *(int*)(str + 4) = regs[3]; // RDX
    *(int*)(str + 8) = regs[2]; // RCX
    printf("CPU: %s\r\n", str);
}

int main()
{
    if (KbLoader::KbLoadAsFilter(
        L"C:\\Temp\\Kernel-Bridge\\Kernel-Bridge.sys",
        L"260000" // Altitude of minifilter
    )) {
        if (Hypervisor::KbVmmEnable())
        {
            PrintCpuid();
            TestMemoryHiding();
            Hypervisor::KbVmmDisable();
        }
        KbLoader::KbUnload();
    }

    return 0;
}

Vmm.gif​

Что в итоге?
С помощью виртуализации можно скрывать перехваты (программа будет видеть одно, а исполнять - другое) и целые модули (например, для потоков защиты память будет невидима), подменять CPUID, заставлять процесс выполнять недоверенный код. Можно обойти PatchGuard (система проверки целостности кода ядра Windows) и перехватывать функции в ядре. Можно придумывать собственные машинные инструкции и реализовывать их произвольное поведение. Возможности ограничены лишь фантазией.

А что с защитой? Те же самые средства можно направить и на защиту: например, сделать всю память процесса недоступной для процессов извне. Таким образом, процесс будет работать в изолированном анклаве, доступ к которому извне (например, с помощью CheatEngine) получить будет невозможно. Или, обрабатывая отладочные прерывания, сделать невозможной отладку.

Time to choose.
 
А что с защитой? Те же самые средства можно направить и на защиту: например, сделать всю память процесса недоступной для процессов извне. Таким образом, процесс будет работать в изолированном анклаве, доступ к которому извне (например, с помощью CheatEngine) получить будет невозможно. Или, обрабатывая отладочные прерывания, сделать невозможной отладку.
vmprotect так работает.
 
Но ведь XSGuard от Котейки не защищает ни от чего, это пустышка...
С чего такой вывод? Он защищает от всех пабликовских и многих приватных JNI/JVMTI обходов, защищает от патчей в кодовых секциях модулей джавы (с чем эйвон не справляется, он в целом ни с чем не справляется, многие админы приобретали XSGuard из-за того, что эйвон ни от чего не спасал, даже от банального LoadLibrary, хоть и эйвон позиционируется как анти-инжект, который обходится в один клик).
 
С чего такой вывод? Он защищает от всех пабликовских и многих приватных JNI/JVMTI обходов, защищает от патчей в кодовых секциях модулей джавы (с чем эйвон не справляется, он в целом ни с чем не справляется, многие админы приобретали XSGuard из-за того, что эйвон ни от чего не спасал, даже от банального LoadLibrary, хоть и эйвон позиционируется как анти-инжект, который обходится в один клик).
Значит, я ошибся и у тебя действительно хорошая защита
 
Здравствуйте , нам надо сделать сайт и лаунчер (любой) , я сам пытался но получилось. Если бы вы помогли был бы очень благодарен, давайте всё обсудим в дс Dan Yer64#1720
 
Здравствуйте , нам надо сделать сайт и лаунчер (любой) , я сам пытался но получилось. Если бы вы помогли был бы очень благодарен, давайте всё обсудим в дс Dan Yer64#1720
Ты не по адресу пришел.
 
Хочется услышать насчет обфускации с виртуализацией типа vmware thinapp + themida
 
Хочется услышать насчет обфускации с виртуализацией типа vmware thinapp + themida
Слишком широкий вопрос.
Виртуализация в темиде никак не связана с аппаратной виртуализацией и с эмуляцией системных ресурсов, как в ThinApp
 
Хошик сдох бадабумц..
maxresdefault.jpg
 

Поделиться этой страницей

Назад
Верх