前提 :现在很多游戏使用模拟按键基本都会失效,例如 sendinput 函数模拟鼠标键盘,也有部分游戏转换键盘为虚拟代码可以模拟,但是也存在封号的风险。如果是dx的游戏可 hook DirectInput函数,而如今现在多数 利用最多的是 IDirectInput8 ,因为这个支持的种类多,具体可以百度。
具体有两个函数可以hook 之后可以注入鼠标以及键盘,即支持所有的键鼠操作,如果人家想检测那边封号肯定也是包封的,只是国内没什么帖子说这个。
其中一个是如下函数
HRESULT GetDeviceState(
IDirectInputDevice8* pThis,
DWORD cbData,
LPVOID lpvData
)
函数自行谷度,我会给例子
函数2
HRESULT GetDeviceData(
IDirectInputDevice8* pThis,
DWORD cbObjectData,
LPDIDEVICEOBJECTDATA rgdod,
LPDWORD pdwInOut,
DWORD dwFlags
)
本人尝试过写一个win32的例子 发现第一个和第二个函数都可以使用,但是实战中发现游戏不少用第二个函数,第二个函数 GetDeviceData 参数 LPDIDEVICEOBJECTDATA rgdod ,里面保存当前游戏中按下的键盘鼠标队列,因此可以修改这个参数的值达到注入按键和鼠标的用处。
代码如下 复制应该可以用的,需要自己使用minhook库,之后注入游戏。其他APIhook 框架也可以。
#pragma once
#define DIRECTINPUT_VERSION 0x0800
#include "framework.h"
#include <dinput.h>
#include <iostream>
#include "MinHook.h"
#include <cstdlib>
#include <deque>
#pragma comment(lib, "Dinput8.lib")
#pragma comment(lib, "Dxguid.lib")
extern HMODULE g_hModule;
inline volatile bool inject_mouse_flag;
inline std::deque<std::pair<int, bool>> keyboard_deque;
typedef HRESULT(__stdcall* GetDeviceDataT)(IDirectInputDevice8*, DWORD, LPDIDEVICEOBJECTDATA, LPDWORD, DWORD);
static GetDeviceDataT pGetDeviceData = nullptr; // original
HRESULT __stdcall hookGetDeviceData(IDirectInputDevice8* pThis, DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags);
typedef HRESULT(__stdcall* GetDeviceStateT)(IDirectInputDevice8* pThis, DWORD cbData, LPVOID lpvData);
typedef HRESULT(__stdcall* GetDeviceDataT)(IDirectInputDevice8*, DWORD, LPDIDEVICEOBJECTDATA, LPDWORD, DWORD);
static GetDeviceStateT pGetDeviceState = nullptr; //pointer to original function
static uintptr_t get_function_address(LPDIRECTINPUTDEVICE8 lpdid, int index)
{
uintptr_t avTable = *((uintptr_t*)lpdid); // 虚函数表地址
uintptr_t pFunction = avTable + index * sizeof(uintptr_t); // 虚函数表项的地址
return *((uintptr_t*)pFunction); // 目标函数地址
}
static HRESULT __stdcall hookGetDeviceState(IDirectInputDevice8* pThis, DWORD cbData, LPVOID lpvData) {
HRESULT result = pGetDeviceState(pThis, cbData, lpvData);
//if (cbData == sizeof(DIMOUSESTATE)) {
// if (((LPDIMOUSESTATE)lpvData)->rgbButtons[0] != 0) {
// printf("left %x", ((LPDIMOUSESTATE)lpvData)->rgbButtons[0]);
// std::cout << "[LMB]" << std::endl;
// }
// if (((LPDIMOUSESTATE)lpvData)->rgbButtons[1] != 0) {
// printf("right %x", ((LPDIMOUSESTATE)lpvData)->rgbButtons[0]);
// std::cout << "[RMB]" << std::endl;
// }
//}
//if (cbData == sizeof(DIMOUSESTATE2)) {//caller is also a mouse but different struct
// if (((LPDIMOUSESTATE2)lpvData)->rgbButtons[0] != 0) {
// std::cout << "[LMB2]" << std::endl;
// printf("left %x", ((LPDIMOUSESTATE2)lpvData)->rgbButtons[0]);
// }
// if (((LPDIMOUSESTATE2)lpvData)->rgbButtons[1] != 0) {
// std::cout << "[RMB2]" << std::endl;
// printf("right %x", ((LPDIMOUSESTATE2)lpvData)->rgbButtons[1]);
// }
//}
return result;
}
/**
* 参数1 按键key 例如 DIK_W
* 参数2 是否按下 按下为true 放开false
*
* 使用方式
* inject_keys(DIK_W ,true)
* inject_keys(DIK_W ,false)
*/
inline void inject_keys(int key)
{
keyboard_deque.push_back(std::make_pair(key, true));
// keyboard_deque.push_back(std::make_pair(key, false));
}
//模拟右键点击
inline void inject_mouse()
{
inject_mouse_flag = true;
}
//释放右键点击
inline void stop_mouse_inject()
{
inject_mouse_flag = false;
}
static HRESULT __stdcall hookGetDeviceData(IDirectInputDevice8* pThis, DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) {
HRESULT result = pGetDeviceData(pThis, cbObjectData, rgdod, pdwInOut, dwFlags);
//HRESULT result = veh::CallOriginal<HRESULT>(pGetDeviceData, pThis, //cbObjectData, rgdod, pdwInOut, dwFlags);
static ULONGLONG timeStart = 0;
if (keyboard_deque.size()>0)
{
ULONGLONG timeEnd = GetTickCount64();
//五秒注入一次不能太离谱好的机械键盘一般是五毫秒
if (timeEnd - timeStart > 700)
{
auto r = keyboard_deque.front();
timeStart = GetTickCount64();
rgdod[*pdwInOut].dwData = (r.second? 0x80 : 0x0);
rgdod[*pdwInOut].dwOfs = r.first;
*pdwInOut = *pdwInOut + 1;
keyboard_deque.clear();
}
}
if (inject_mouse_flag)
{
rgdod[*pdwInOut].dwData = 0x80;
rgdod[*pdwInOut].dwOfs = DIMOFS_BUTTON1;
*pdwInOut = *pdwInOut + 1;
rgdod[*pdwInOut].dwData = 0x0;
rgdod[*pdwInOut].dwOfs = DIMOFS_BUTTON1;
*pdwInOut = *pdwInOut + 1;
}
return result;
}
static void __stdcall hook_dinput()
{
if (MH_Initialize() != MH_OK && MH_Initialize() != MH_ERROR_ALREADY_INITIALIZED)
{
printf("MH_Initialize hook_input error \n");
}
IDirectInput8* pDirectInput = nullptr;
if (DirectInput8Create(g_hModule, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)& pDirectInput, NULL) != DI_OK) {
printf("DI Create failed! \n");
}
LPDIRECTINPUTDEVICE8 lpdiMouse;
if (pDirectInput->CreateDevice(GUID_SysMouse, &lpdiMouse, NULL) != DI_OK) {
pDirectInput->Release();
std::cout << "CreateDevice failed!" << std::endl;
}
auto hook_start = get_function_address(lpdiMouse, 9);
if (MH_CreateHook((LPVOID)hook_start, &hookGetDeviceState, reinterpret_cast<LPVOID*>(&pGetDeviceState)) != MH_OK || MH_EnableHook((LPVOID)hook_start) != MH_OK)
{
printf("hook getdecive error");
}
hook_start = get_function_address(lpdiMouse, 10);
//veh::Setup();
//veh::Hook((LPVOID)hook_start, hookGetDeviceData);
pGetDeviceData = (GetDeviceDataT)hook_start;
if (MH_CreateHook((LPVOID)hook_start, &hookGetDeviceData, reinterpret_cast<LPVOID*>(&pGetDeviceData)) != MH_OK || MH_EnableHook((LPVOID)hook_start) != MH_OK)
{
printf("hook hookGetDeviceData error");
}
}
调用 inject_keys 即可模拟键盘点击