xp下对dinput8.dll 游戏键盘输入的模拟 非函数hook
很多游戏或者3d模拟软件为了更好的支持外设使用directinput作为输入接口调用。那么如果要模拟鼠标或键盘来控制游戏或者3d软件进行自动作业如何才能做到呢?
我研究了键盘部分。鼠标应该以此类推
入手模块:dinput8.dll
使用软件:idapro5.0,ollydbg,C32asm
思路是这样的。在进行dinput编程的时候有一个循环查询状态的处理。被调用的函数为CKbd_GetDeviceState (此函数地址可以从idapro5.0的分析结果中找到)
调用代码类似:
HRESULT UpdateInputState(void)
{
DWORD i;
if(lpKeyboard != NULL)
{
DIDEVICEOBJECTDATA didod[DINPUT_BUFFERSIZE]; // Receives buffered data
DWORD dwElements;
HRESULT hr;
hr = DIERR_INPUTLOST;
while(hr != DI_OK)
{
dwElements = DINPUT_BUFFERSIZE;
hr = lpKeyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),didod,&dwElements,0); 这里调用 CKbd_GetDeviceState
if (hr != DI_OK)
{
hr = lpKeyboard->Acquire();
if(FAILED(hr))
return hr;
}
}
if(FAILED(hr))
return hr;
}
for(int i=0; i<dwElements; i++)
{
// 此处放入处理代码
// didod[i].dwOfs 表示那个键被按下或松开
// didod[i].dwData 记录此键的状态,低字节最高位是 1 表示按下,0 表示松开
// 一般用 didod[i].dwData&0x80 来测试
}
return S_OK;
}
那么键盘状态是如何被获得的呢?请看下面的ida分析结果
.text:6D18C5EA _CKbd_GetDeviceState@8 proc near ; DATA XREF: .text:6D18C37Co
.text:6D18C5EA
.text:6D18C5EA arg_0 = dword ptr 8
.text:6D18C5EA arg_4 = dword ptr 0Ch
.text:6D18C5EA
.text:6D18C5EA mov edi, edi
.text:6D18C5EC push ebp
.text:6D18C5ED mov ebp, esp
.text:6D18C5EF mov eax, [ebp+arg_0]
.text:6D18C5F2 mov ecx, [eax+8]
.text:6D18C5F5 test byte ptr [ecx], 2
.text:6D18C5F8 jz short loc_6D18C60D
.text:6D18C5FA push esi
.text:6D18C5FB mov esi, [eax+4] ;根据跟踪分析。esi指向的内存为一个键盘状态表不同的键位如果按下为0x80,没有按下为00
.text:6D18C5FE push edi
.text:6D18C5FF mov edi, [ebp+arg_4]
.text:6D18C602 push 40h ;拷贝长度为0x100字节40h*4
.text:6D18C604 pop ecx
.text:6D18C605 rep movsd ;拷贝键盘状态给外部接收缓冲区
.text:6D18C607 pop edi
.text:6D18C608 xor eax, eax
.text:6D18C60A pop esi
.text:6D18C60B jmp short loc_6D18C612
.text:6D18C60D ; ---------------------------------------------------------------------------
.text:6D18C60D
.text:6D18C60D loc_6D18C60D: ; CODE XREF: CKbd_GetDeviceState(x,x)+Ej
.text:6D18C60D mov eax, 8007001Eh
.text:6D18C612
.text:6D18C612 loc_6D18C612: ; CODE XREF: CKbd_GetDeviceState(x,x)+21j
.text:6D18C612 pop ebp
.text:6D18C613 retn 8
.text:6D18C613 _CKbd_GetDeviceState@8 endp
通过跟踪得知存放缓冲区的是一个全局变量内存区 键盘表对应键位如下 我列出常用键。
基地址为:6d1a4448 这个地址可以通过跟踪esi的内容得到
6d1a4448h+2 = 1 到 6d1a4448h+bh = 0
6d1a4448h+ch = -
6d1a4448h+dh = =
6d1a4448h+1eh = a
6d1a4448h+30h = b
6d1a4448h+2eh = c
6d1a4448h+20h = d
6d1a4448h+12h = e
6d1a4448h+21h = f
6d1a4448h+22h = g
6d1a4448h+23h = h
6d1a4448h+17h = i
6d1a4448h+24h = j
6d1a4448h+25h = k
6d1a4448h+26h = l
6d1a4448h+32h = m
6d1a4448h+31h = n
6d1a4448h+18h = o
6d1a4448h+19h = p
6d1a4448h+10h = q
6d1a4448h+13h = r
6d1a4448h+1fh = s
6d1a4448h+14h = t
6d1a4448h+16h = u
6d1a4448h+2fh = v
6d1a4448h+11h = w
6d1a4448h+2dh = x
6d1a4448h+15h = y
6d1a4448h+2ch = z
6d1a4448h+1ch = enter
6d1a4448h+c8h = up
6d1a4448h+d0h = down
6d1a4448h+cbh = left
6d1a4448h+cdh = right
那么如何在ollydbg中跟踪调试呢.
我们可以通过c32asm 修改CKbd_GetDeviceState 6D1880A7 8BFF mov edi, edi ;
函数的前一个字节的机器码为cc也就是int 3断点
目前是8BFF修改为CCFF 那么当执行到这个函数的时候会提示发现调试位置错误0x80000003根据提示进入调试
首先要把ollydbg设置为系统默认调试器。
在ollydbg中会停在
CC int3 ; CKbd_GetDeviceState
FF55 8B call dword ptr [ebp-75]
EC in al, dx
8B45 08 mov eax, dword ptr [ebp+8]
ctrl+e 修改cc为8b
单步走f8到这句。
.text:6D18C5FB mov esi, [eax+4]
再按一下f8
esi中就有地址了
察看esi指向的内容。会看到一片都是0。这里就是键盘缓冲区
那么既然知道键盘缓冲区地址固定。我们就可以编码模拟了。
首先要做的就是插入我们的代码到要修改的进程里面去。用hook也好远程线程也好。方法很多不讲了。
我这里使用的是键盘hook
BYTE keyMap[0x100]={NULL};
BYTE *dinput8KeyMap=(BYTE*)0x24448; //键盘映射区地址偏移
//在程序的初始化处计算缓冲区相对位置
HINSTANCE hDinput8 = 0;
hDinput8 = GetModuleHandle("dinput8.dll");
if(!hDinput8)
{
__asm
{
mov eax,dinput8KeyMap
add eax,hDinput8
mov dinput8KeyMap,eax
}
}else
{
hDinput8 = LoadLibrary("dinput8.dll");
__asm
{
mov eax,dinput8KeyMap
add eax,hDinput8
mov dinput8KeyMap,eax
}
FreeLibrary(hDinput8);
}
//先定义我们的按键表编写一个初始化函数
void InitKeyMap()
{
ZeroMemory(keyMap,0x100);
keyMap[0x2] ='1';
keyMap[0x3] ='2';
keyMap[0x4] ='3';
keyMap[0x5] ='4';
keyMap[0x6] ='5';
keyMap[0x7] ='6';
keyMap[0x8] ='7';
keyMap[0x9] ='8';
keyMap[0xa] ='9';
keyMap[0xb] ='0';
keyMap[0xc] ='-';
keyMap[0xd] ='=';
keyMap[0x1e] ='a';
keyMap[0x30] ='b';
keyMap[0x2e] ='c';
keyMap[0x20] ='d';
keyMap[0x12] ='e';
keyMap[0x21] ='f';
keyMap[0x22] ='g';
keyMap[0x23] ='h';
keyMap[0x17] ='i';
keyMap[0x24] ='j';
keyMap[0x25] ='k';
keyMap[0x26] ='l';
keyMap[0x32] ='m';
keyMap[0x31] ='n';
keyMap[0x18] ='o';
keyMap[0x19] ='p';
keyMap[0x10] ='q';
keyMap[0x13] ='r';
keyMap[0x1f] ='s';
keyMap[0x14] ='t';
keyMap[0x16] ='u';
keyMap[0x2f] ='v';
keyMap[0x11] ='w';
keyMap[0x2d] ='x';
keyMap[0x15] ='y';
keyMap[0x2c] ='z';
keyMap[0x1c] =VK_RETURN;
keyMap[0xc8] =VK_UP;
keyMap[0xd0] =VK_DOWN;
keyMap[0xcb] =VK_LEFT;
keyMap[0xcd] =VK_RIGHT;
}
//编写一个键盘按下设置为80的函数
void SetKeyDown(BYTE vk)
{
//大小写转换
if(vk>='A' && vk<='Z')
{
vk|=0x20;
}
for(int cnt=0;cnt<0x100;cnt++)
{
if(keyMap[cnt])
{
if(keyMap[cnt]==vk)
{
dinput8KeyMap[cnt]=0x80;
break;
}
}
}
}
//这个函数偷懒。如果按键弹起我们就全部清理0
void SetKeyUp(BYTE vk)
{
ZeroMemory(dinput8KeyMap,0x100);
}
//我用的键盘钩子。这样实现的
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{
if(lParam==0xc0000001)
{
SetKeyDown((BYTE)wParam);
}
if(lParam==1)
{
SetKeyUp((BYTE)wParam);
}
return CallNextHookEx(winKbd,nCode,wParam,lParam);
}
这样就完成了.可以通过程序自动控制了.是不是很有意思
开发环境:
vs2005,xp sp2
xp下对dinput8.dll 游戏键盘输入的模拟 非函数hook相关推荐
- python几个好朋友玩逢7拍腿游戏,从1开始报数,当尾数是7或7的倍数时则不报数而是拍腿,从1数到n,假定无出错,则拍多少下腿。n从键盘输入。
编程要求 根据提示,在右侧编辑器补充代码,计算并输出逢七排腿次数. 几个好朋友玩逢7拍腿游戏,从1开始报数,当尾数是7或7的倍数时则不报数而是拍腿,从1数到n,假定无出错,则拍多少下腿.n从键盘输入. ...
- C语言习题:/*键盘输入两个非零整数A和B,如果A和B都是偶数则输出两个数的和,如果A和B都是奇数则输出两个数的差,如果A是奇数B是偶数则输出两数积,如果A是偶数B是奇数输出AVB结果*/
#include<stdio.h> /*键盘输入两个非零整数A和B,如果A和B都是偶数则输出两个数的和, 如果A和B都是奇数则输出两个数的差, 如果A是奇数B是偶数则输出两数积, 如果A是 ...
- python3模拟键盘输入_Python模拟键盘输入
使用pynput库达到模拟键盘输入的目的(也可以进行鼠标模拟). 1.安装pynput库 pip install pynput 2.引入键盘所需类 from pynput.keyboard impor ...
- python如何模拟键盘输入_Python模拟键盘输入和鼠标操作
一.Python键盘输入模拟: import win32api import win32con win32api.keybd_event(17,0,0,0) #ctrl键位码是17 win32api. ...
- python如何模拟键盘输入_python 模拟键盘输入
python 模拟键盘输入 一.PyUserInput安装 python3.5的PyMouse和PyKeyboard模块都集成到了PyUserInput模块中.在python3.5中,直接安装PyUs ...
- python3模拟键盘输入_python 模拟键盘输入
一.PyUserInput安装 python3.5的PyMouse和PyKeyboard模块都集成到了PyUserInput模块中.在python3.5中,直接安装PyUserInput模块即可 Py ...
- java模拟器键盘输入_Java模拟鼠标和键盘输入
用途 在电脑(Windows/Mac)上模拟鼠标和键盘输入 Mac运行需要打开相关权限,详见文末说明. 效果图 代码 import java.awt.*; import java.awt.event. ...
- Windows下32位汇编语言读取键盘输入单字符
代码如下: INCLUDE Irvine32.inc INCLUDE Macros.inc includelib Irvine32.lib includelib S:\masm32\lib\user3 ...
- 解决 Windows XP 下微软拼音2007 无法正常输入的故障
Windows XP 上安装并使用 Office 2007 已经有很长一段时间,自从微软发布了 Live Messenger 9 之后赶紧安装上进行体验,但是很让人郁闷的是经常出现对方发给我信息自动弹 ...
最新文章
- CentOS6.0搭建DNS
- PyTorch 实现经典模型2:AlexNet
- 时间选择控件在不同场景下的应用
- python基础教程:Counter类
- 新 开通 自己 IT 博客
- 物体识别_小鼠新物体识别Protocol
- Java微服务(三)【本地maven配置与环境变量】(手把手编写,超级详细)
- 资源推荐—HTML5精品资源
- 关于自动布局更新约束方法的总结
- 入门科普:一文看懂NLP和中文分词算法(附代码举例)
- 虚拟机linux挂载光盘显示:mount: you must specify the filesystem type
- 【Elasticsearch】 es primary shard 主分片 PrimaryOperationTransportHandler
- [Angularjs]视图和路由(一)
- Android--多线程之Handler
- python中ascii的应用_Python程序中的ascii()
- 微软正式发布 Azure IoT Central
- 策略模式 (Strategy)
- android多屏互动方案,史上最实用的多屏互动教程之PC投屏安卓篇
- 一个INT 10H中断的小例子
- 智协云店通+BitCOO加入4WiN.io全球互贸链 | 翼次元空间+Fund++