Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Гайд Античит — Обход защиты через уязвимый драйвер Steam Overlay (Read/Write Memory)

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
13 Фев 2026
Сообщения
126
Реакции
3
Народ, кто сейчас ковыряет обходы античитов, зацените тему: нашли уязвимость в драйвере, который подгружается через Steam Overlay Performance Monitor. Суть в том, что он дает прямой доступ к чтению и записи физической памяти через MmMapIoSpace, а это, по сути, готовый ключ для создания экстернал-софта с Kernel-правами.

1774356647961.png


Сама механика простая: подрубаете оверлей в настройках Steam, и драйвер готов к работе. Ниже набросал базу для взаимодействия с этой дырой.

Код:
Expand Collapse Copy
#include <windows.h>
#include <stdio.h>
 
#define SeLockMemoryPrivilege     04ull
#define SeLoadDriverPrivilege    10ull
#define AdjustCurrentProcess    0ull
#define SwapAddress(x)            ((((ULONG_PTR)(x)) >> 32) | (((ULONG_PTR)(x)) << 32))
 
BOOL AcquirePrivilege(DWORD Privilege, BOOLEAN Proc)
{
    NTSTATUS(NTAPI *RtlAdjustPrivilege)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN);
    RtlAdjustPrivilege = reinterpret_cast<decltype(RtlAdjustPrivilege)>(GetProcAddress(LoadLibraryW(L"ntdll.dll"), "RtlAdjustPrivilege"));
 
    BOOLEAN Enabled = 0;
    return !RtlAdjustPrivilege(Privilege, static_cast<BOOLEAN>(1), Proc, &Enabled) || Enabled;
}
 
HANDLE OpenDriverHandle()
{
    return CreateFileW(
        L"\\\\?\\GLOBALROOT\\Device\\cpuz160",
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        0ul,
        NULL
    );
}
 
BOOLEAN ReadPhysicalMemory(HANDLE hDriver, ULONG_PTR PhysicalAddress, PVOID Buffer, SIZE_T Size)
{
    #pragma pack(push,1)
    struct IOCTL_CONTEXT {
        union {
            struct {
                ULONG AddressHigh;
                ULONG AddressLow;
            };
            ULONG64 Address;
        };
        ULONG Length;
        union {
            struct {
                ULONG BufferHigh;
                ULONG BufferLow;
            };
            ULONG64 Buffer;
        };
    } Context;
    #pragma pack(pop)
 
    Context.Address = SwapAddress(PhysicalAddress);
    Context.Length = Size;
    Context.Buffer = SwapAddress(Buffer);
 
    DWORD BytesReturned;
    return DeviceIoControl(hDriver, 0x9C402540, reinterpret_cast<LPVOID>(&Context), static_cast<DWORD>(sizeof(Context)), reinterpret_cast<LPVOID>(&Context), static_cast<DWORD>(sizeof(Context)), &BytesReturned, NULL);
}
 
BOOLEAN WriteVirtualMemory(HANDLE hDriver, PVOID VirtualAddress, PVOID Buffer, SIZE_T Size)
{
    const SIZE_T PageSize = 0x1000;
    SIZE_T PagesCount = (Size / PageSize) + 1;
    PULONG_PTR PagesArray = reinterpret_cast<PULONG_PTR>(VirtualAlloc(NULL, sizeof(ULONG_PTR) * PagesCount, MEM_COMMIT, PAGE_READWRITE));
    if (!PagesArray)
        return FALSE;
 
    if (!AllocateUserPhysicalPages(GetCurrentProcess(), &PagesCount, PagesArray)) {
        VirtualFree(PagesArray, 0, MEM_RELEASE);
        return FALSE;
    }
 
    PVOID Mapped = VirtualAlloc(NULL, Size, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE);
    if (!Mapped) {
        FreeUserPhysicalPages(GetCurrentProcess(), &PagesCount, PagesArray);
        VirtualFree(PagesArray, 0, MEM_RELEASE);
        return FALSE;
    }
 
    if (!MapUserPhysicalPages(Mapped, PagesCount, PagesArray)) {
        VirtualFree(Mapped, 0, MEM_RELEASE);
        FreeUserPhysicalPages(GetCurrentProcess(), &PagesCount, PagesArray);
        VirtualFree(PagesArray, 0, MEM_RELEASE);
        return FALSE;
    }
 
    // Copy virtual memory
    RtlCopyMemory(Mapped, Buffer, Size);
 
    // Write virtual memory per page
    BOOLEAN Result = TRUE;
    for (SIZE_T Offset = 0, Page = 0; Page < PagesCount; Page++) {
        SIZE_T WriteSize = min(PageSize, Size - Offset);
        Result &= ReadPhysicalMemory(hDriver, PagesArray[Page] << 12, reinterpret_cast<PVOID>(reinterpret_cast<ULONG_PTR>(VirtualAddress) + Offset), WriteSize);
        Offset += WriteSize;
    }
 
    // Release physical memory
    VirtualFree(Mapped, 0, MEM_RELEASE);
    FreeUserPhysicalPages(GetCurrentProcess(), &PagesCount, PagesArray);
    VirtualFree(PagesArray, 0, MEM_RELEASE);
 
    return Result;
}
 
ULONG_PTR GetSystemPML4(HANDLE hDriver)
{
    // Exist only on CPU with more then 1 logical processor
    __try {
        for (ULONG Address = 0x0; Address < 0x100000; Address += 0x1000) {
            UCHAR Buffer[0x1000];
            if (!ReadPhysicalMemory(hDriver, Address, Buffer, 0x1000))
                continue;
 
            if (0x00000001000600E9 != (0xffffffffffff00ff & *reinterpret_cast<ULONG_PTR*>(Buffer))) //PROCESSOR_START_BLOCK->Jmp
                continue;
 
            if (0xfffff80000000000 != (0xfffff80000000003 & *reinterpret_cast<ULONG_PTR*>(Buffer + 0x70))) // PROCESSOR_START_BLOCK->LmTarget
                continue;
 
            if (0xffffff0000000fff & *reinterpret_cast<ULONG_PTR*>(Buffer + 0xA0)) // PROCESSOR_START_BLOCK->CR3
                continue;
 
            return *reinterpret_cast<ULONG_PTR*>(Buffer + 0xA0); // PROCESSOR_START_BLOCK->CR3
        }
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        return 0x0ull;
    }
 
    return 0x0ull;
}
 
int main()
{
    if (!AcquirePrivilege(SeLockMemoryPrivilege, AdjustCurrentProcess)) {
        printf("failed to acquire required privileges");
        return 1;
    }
 
    if (!AcquirePrivilege(SeLoadDriverPrivilege, AdjustCurrentProcess)) {
        printf("failed to acquire required privileges");
        return 2;
    }
 
    HANDLE hDriver = OpenDriverHandle();
    if (!hDriver) {
        printf("failed to open handle to the vulnerable driver");
        return 3;
    }
 
    ULONG uValue = 0ul;
    printf("ReadStatus = 0x%0X\n", ReadPhysicalMemory(hDriver, 0x100400000, &uValue, sizeof(uValue)));
    printf("Value = 0x%0X\n", uValue);
 
    ULONG_PTR SystemDirectoryTableBase = GetSystemPML4(hDriver);
    printf("SystemDirectoryTableBase = 0x%p\n", SystemDirectoryTableBase);
 
    ULONG uValue1 = 0ul;
    printf("WriteStatus = 0x%0X\n", WriteVirtualMemory(hDriver, &uValue1, &uValue, sizeof(uValue)));
    printf("Value1 = 0x%0X\n", uValue1);
 
    system("pause");
 
    return 0;
}

  1. Технический нюанс: Драйвер позволяет работать с памятью напрямую, что экономит время на поиске путей обхода для маппинга.
  2. Безопасность: Юзайте строго на твинках. Хотя это и не "паблик-помойка", античиты типа EAC или BattlEye могут быстро пропалить такие методы при наличии специфических сигнатур в поведении.
  3. Важно: Обязательно тестируйте на отсутствие крашей при чтении Paged-памяти.

Пожалуйста, авторизуйтесь для просмотра ссылки.


Кто уже успел потестить на актуальных билдах? Есть ли смысл пилить под это полноценный лоадер или проще использовать как временный костыль для своих нужд? Скидывайте правки, если кто допиливал под свои нужды, особенно интересно по части стабильности при пуше в Kernel-мод.
 
Последнее редактирование модератором:
Назад
Сверху Снизу