Защищенные области памяти


X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 085
Репутация
8 208
1711616112437.png


Всем привет, в этой статье было такое упоминание, как "Защищенные указатели", или что-то таке...

Мне стало интересно почитать, что это такое.

Вот что раскопал:

Что такое защищенные регионы?


Защищенные регионы — это, по сути, указатели, которые указывают на адрес, который не действителен. Чаще всего адрес начинается с 0x800000 и т.д. Однако игра их считывает, и они получают действительные результаты. Как, вы можете спросить? Дело в том, что stub.dll регистрирует обработчик исключений, который перенаправляет охраняемый указатель на реальный указатель после успешного выполнения нескольких проверок. И чтобы выполнить все проверки, мы собираемся найти заглушку, которую мы собираемся использовать для чтения адреса, который мы хотим прочитать.

Какие указатели используют защищенные регионы в играх ? Вот некоторые из них:
  • Мир
  • Корневой компонент актера
  • Здоровье актера
  • Контроллер игрока
  • Постоянный уровень
  • Экземпляр игры
Как мне прочитать этот охраняемый регион?

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

Вот примерный код с комментариями, как это можно сделать:

C:
#include <windows.h>
#include <iostream>

// Предположим, что External::HANDLE и External::Base уже определены
// и инициализированы в другом месте программы.

uint64_t FindPattern(uint64_t startAddress, const char* pattern, size_t length, char wildcard) {
    // Реализация функции поиска паттерна в памяти процесса.
    // Должна возвращать адрес найденного паттерна или 0, если паттерн не найден.
    // Данная функция должна найти заглушку, которую мы собираемся использовать для чтения адреса, который мы хотим прочитать.
    // Реализуйте функцию сами.)
    return 0; // Заглушка для примера.
}

uint64_t ReadAddressFromGame(uint64_t AddressToRead) {
    static uint64_t RandomPageLocation = 0x10000; // Начальный адрес для поиска

    if (!RandomPageLocation) {
        MEMORY_BASIC_INFORMATION Info;
        while (VirtualQueryEx(External::HANDLE, (void*)RandomPageLocation, &Info, sizeof(Info))) {
            RandomPageLocation = (uint64_t)Info.BaseAddress + Info.RegionSize;
            if (Info.State == MEM_COMMIT && Info.Protect == PAGE_EXECUTE_READWRITE) {
                chunk_t A;
                if (ReadProcessMemory(External::HANDLE, (void*)RandomPageLocation, &A, sizeof(A), nullptr)) {
                    bool Good = true;
                    for (size_t i = 0; i < sizeof(A.Buff); ++i) {
                        if (A.Buff[i] != 0 && A.Buff[i] != 0xCC) {
                            Good = false;
                            break;
                        }
                    }
                    if (Good) break;
                }
            }
        }
    }

    static uint64_t MemeStub = 0;
    if (!MemeStub) MemeStub = FindPattern(0, "\x48\x8B\x01\xC3", 4, 0xCC);
    if (!MemeStub) return 0;

    // Вместо 0xDEADBEEF нужно получить адрес
    // Это указатель функции .data, который вызывается каждый кадр.
    uint64_t DataPtr = External::Base + 0xDEADBEEF;
 
    static uint64_t OrigAddr = 0;
    if (!OrigAddr) ReadProcessMemory(External::HANDLE, (void*)DataPtr, &OrigAddr, sizeof(OrigAddr), 0);

    unsigned char ReadStub[] = {
        // Ассемблерные инструкции для чтения памяти...
        0x51, // push rcx
        0x52, // push rdx
        0x48, 0xB9, // mov rcx, AddressToRead (перезаписывается ниже)
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0xFF, 0xD1, // call rcx (вызов MemeStub, перезаписывается ниже)
        0x5A, // pop rdx
        0x59, // pop rcx
        0xC3  // ret
    };

    // Заполнение адресов в ReadStub
    *(uint64_t*)&ReadStub[4] = AddressToRead; // Адрес для чтения
    *(uint64_t*)&ReadStub[14] = MemeStub;     // Адрес MemeStub

    // Запись ReadStub в процесс
    WriteProcessMemory(External::HANDLE, (void*)RandomPageLocation, &ReadStub, sizeof(ReadStub), nullptr);

    // Изменение указателя на ReadStub в целевом процессе
    WriteProcessMemory(External::HANDLE, (void*)DataPtr, &RandomPageLocation, sizeof(RandomPageLocation), nullptr);

    // Чтение результата
    uint64_t ReadBuff = 0;
    while (true) {
        Sleep(100); // Краткая пауза для обеспечения выполнения кода в процессе
        if (ReadProcessMemory(External::HANDLE, (void*)(RandomPageLocation + sizeof(ReadStub)), &ReadBuff, sizeof(ReadBuff), nullptr)) {
            if (ReadBuff != 0) break;
        }
    }

    // Восстановление исходного адреса
    WriteProcessMemory(External::HANDLE, (void*)DataPtr, &OrigAddr, sizeof(OrigAddr), nullptr);

    // Очистка памяти
    unsigned char NullBuff[sizeof(ReadStub)] = {0};
    WriteProcessMemory(External::HANDLE, (void*)RandomPageLocation, &NullBuff, sizeof(NullBuff), nullptr);

    return ReadBuff; // Возвращаем прочитанное значение
}

int main() {
    uint64_t addressToRead = 0x0050F4; // Пример адреса для чтения
    uint64_t readValue = ReadAddressFromGame(addressToRead);
    std::cout << "Read value: " << readValue << std::endl;
    return 0;
}

Этот код делает следующее:
  1. Инициализирует ReadStub с инструкциями для выполнения чтения из памяти.
  2. Записывает ReadStub в найденный codecave.
  3. Изменяет указатель функции в целевом процессе на ReadStub.
  4. Читает значение из указанного адреса.
  5. Восстанавливает исходный указатель функции.
  6. Очищает использованную память в codecave.

Что такое External::HANDLE и External::Base и где их можно получить ?

Пример получения HANDLE процесса:

C:
// Функция для получения HANDLE по имени процесса
HANDLE GetProcessHandle(const wchar_t* processName) {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return NULL;
    }

    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);
    if (Process32First(hSnapshot, &pe)) {
        do {
            if (wcscmp(pe.szExeFile, processName) == 0) {
                CloseHandle(hSnapshot);
                return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
            }
        } while (Process32Next(hSnapshot, &pe));
    }

    CloseHandle(hSnapshot);
    return NULL;
}

External::Base относится к базовому адресу загружаемого модуля (обычно исполняемого файла процесса) в адресном пространстве процесса. Этот адрес используется как отправная точка для чтения или записи определенных данных в памяти процесса.

Пример получения базового адреса модуля:

C:
#include <psapi.h>

DWORD_PTR GetModuleBaseAddress(DWORD dwProcessId, const wchar_t* moduleName) {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwProcessId);
    if (hSnapshot != INVALID_HANDLE_VALUE) {
        MODULEENTRY32 ModuleEntry32 = {0};
        ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
        if (Module32First(hSnapshot, &ModuleEntry32)) {
            do {
                if (wcscmp(ModuleEntry32.szModule, moduleName) == 0) {
                    CloseHandle(hSnapshot);
                    return (DWORD_PTR)ModuleEntry32.modBaseAddr;
                }
            } while (Module32Next(hSnapshot, &ModuleEntry32));
        }
        CloseHandle(hSnapshot);
    }
    return 0;
}

Пример использования:

C:
int main() {
    const wchar_t* processName = L"valorant.exe"; // Имя процесса
    HANDLE processHandle = GetProcessHandle(processName);
    if (processHandle != NULL) {
        DWORD processId = GetProcessId(processHandle); // Получаем PID для дальнейшего использования
        DWORD_PTR baseAddress = GetModuleBaseAddress(processId, processName);
        std::wcout << L"Handle: " << processHandle << L", Base Address: " << std::hex << baseAddress << std::endl;
    } else {
        std::wcout << L"Process not found." << std::endl;
    }

    // Дальнейшие действия...

    return 0;
}
 
Последнее редактирование:
Верх Низ