Начинающий
- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 189
- Реакции
- 5
Народ, кто сейчас ковыряет DMA-сетки под актуальный софт, держите годноту. Опять пришлось дампить вручную через kernel-память, чтобы нормально считать инпут с геймпада напрямую, минуя всякие прослойки.
Короче, суть простая: вытягиваем данные через winlogon.exe и xusb22.sys. Работает на всех актуальных версиях винды. Важный момент: геймпад должен быть воткнут физически, если гоняете на PlayStation, юзайте DS4 для эмуляции, иначе дрова не подхватят структуру.
Техническая часть:
Слил это, потому что сам юзаю похожий метод для внешних аимов, чтобы не палиться через хуки в юзермоде. По фактам — это самый надежный способ считывать инпут для макросов или AI-читов, когда нужно выжать максимум из мувмента и при этом оставаться андетект для античита.
Кто уже тестил этот подход на свежих патчах античитов? Есть просадки по ФПС при частом опросе памяти через VMMDLL или все норм? Кидайте свои фиксы, если кто допиливал структуру под новые версии драйверов xusb.
Короче, суть простая: вытягиваем данные через winlogon.exe и xusb22.sys. Работает на всех актуальных версиях винды. Важный момент: геймпад должен быть воткнут физически, если гоняете на PlayStation, юзайте DS4 для эмуляции, иначе дрова не подхватят структуру.
Техническая часть:
- Architecture: Чистый C++, работаем через VMMDLL.
- Workflow: Ищем глобалы драйвера, вычисляем адрес структуры контроллера, дальше просто рипаем память по оффсетам.
- Compatibility: Нужен DMA-девайс (Screamer/Enigma/и аналоги) + KMBox для нормального ввода.
Код:
#define XINPUT_DPAD_UP 0x0001
#define XINPUT_DPAD_DOWN 0x0002
#define XINPUT_DPAD_LEFT 0x0004
#define XINPUT_DPAD_RIGHT 0x0008
#define XINPUT_START 0x0010
#define XINPUT_SHARE 0x0020
#define XINPUT_L3 0x0040
#define XINPUT_R3 0x0080
#define XINPUT_LB 0x0100
#define XINPUT_RB 0x0200
#define XINPUT_XBOX 0x0400
#define XINPUT_A 0x1000
#define XINPUT_B 0x2000
#define XINPUT_X 0x4000
#define XINPUT_Y 0x8000
#define XINPUT_LT 0x10000
#define XINPUT_RT 0x20000
struct XInputState {
uint16_t buttons;
uint8_t lt;
uint8_t rt;
int16_t lx;
int16_t ly;
int16_t rx;
int16_t ry;
};
bool Controller::InitController() {
winlogonPID = mem.GetProcessID(("winlogon.exe"));
PVMMDLL_MAP_MODULEENTRY moduleInfo = mem.GetProcessModuleInformation(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, ("xusb22.sys"));
if (!moduleInfo)
return false;
uint64_t driverGlobals = mem.Read<uint64_t>(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, mem.FindSignature(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, ("48 8B 0D ? ? ? ? 8B D3"), moduleInfo->vaBase, moduleInfo->vaBase + moduleInfo->cbImageSize, 7));
if (driverGlobals < 0xFFFF000000000000)
return false;
uint64_t xenonBusInformation = mem.Read<uint64_t>(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, driverGlobals + 0x48);
if (xenonBusInformation < 0xFFFF000000000000)
return false;
uint64_t gamepadInformation = mem.Read<uint64_t>(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, xenonBusInformation + 0x30);
if (gamepadInformation < 0xFFFF000000000000)
return false;
xInputControllerDevice = mem.Read<uint64_t>(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, gamepadInformation + 0x88) + mem.Read<uint8_t>(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, mem.FindSignature(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, ("66 89 43 ? 8A 43"), moduleInfo->vaBase, moduleInfo->vaBase + moduleInfo->cbImageSize) + 0x3);
if (xInputControllerDevice < 0xFFFF000000000000)
return false;
return true;
}
void Controller::UpdateState() {
previousState = state;
mem.Read(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, xInputControllerDevice, &state, sizeof(XInputState));
}
void Controller::UpdatePressedState() {
mem.Read(winlogonPID | VMMDLL_PID_PROCESS_WITH_KERNELMEMORY, xInputControllerDevice, &state, sizeof(XInputState));
}
bool Controller::IsButtonDown(uint32_t button) {
if (xInputControllerDevice < 0xFFFF000000000000)
return false;
if (std::chrono::system_clock::now() - lastDown > std::chrono::milliseconds(100)) {
UpdateState();
lastDown = std::chrono::system_clock::now();
}
if (button == XINPUT_LT)
return state.lt > 128;
if (button == XINPUT_RT)
return state.rt > 128;
return state.buttons & (uint16_t)button;
}
bool Controller::IsButtonPressed(uint32_t button) {
if (xInputControllerDevice < 0xFFFF000000000000)
return false;
if (std::chrono::system_clock::now() - lastPressed > std::chrono::milliseconds(100)) {
UpdatePressedState();
lastPressed = std::chrono::system_clock::now();
}
if (button == XINPUT_LT) {
bool cur = state.lt > 128;
bool prev = previousState.lt > 128;
if (cur)
previousState.lt = state.lt;
else
previousState.lt = 0;
return cur && !prev;
}
if (button == XINPUT_RT) {
bool cur = state.rt > 128;
bool prev = previousState.rt > 128;
if (cur)
previousState.rt = state.rt;
else
previousState.rt = 0;
return cur && !prev;
}
bool current = state.buttons & (uint16_t)button;
bool previous = previousState.buttons & (uint16_t)button;
bool isPressed = current && !previous;
if (current)
previousState.buttons |= (uint16_t)button;
else
previousState.buttons &= ~(uint16_t)button;
return isPressed;
}
Слил это, потому что сам юзаю похожий метод для внешних аимов, чтобы не палиться через хуки в юзермоде. По фактам — это самый надежный способ считывать инпут для макросов или AI-читов, когда нужно выжать максимум из мувмента и при этом оставаться андетект для античита.
Кто уже тестил этот подход на свежих патчах античитов? Есть просадки по ФПС при частом опросе памяти через VMMDLL или все норм? Кидайте свои фиксы, если кто допиливал структуру под новые версии драйверов xusb.