|
|
[求助]请问如何给后台窗口发送鼠标按键消息
下面这个也许对大家有点帮助: 转载自 e5bK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3u0D9L8$3N6Q4x3X3g2U0M7$3c8F1i4K6u0W2L8X3g2@1i4K6u0r3K9%4W2D9K9i4S2X3K9i4u0W2i4K6u0r3j5i4u0U0K9r3W2$3k6g2)9J5c8U0t1H3x3o6S2Q4x3V1j5H3y4W2)9J5c8U0l9&6i4K6u0r3x3U0f1J5y4U0j5^5z5q4)9J5k6h3q4K6M7s2R3`. 很多游戏或者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 |
|
|
瑞星,你让我魂牵梦萦。
看完这篇文章……瑞星,无语了。 |
|
|
|
|
|
[分享]全新原创Anti-rootkit软件SysReveal,欢迎试用
大家将那个ksbinsword忘记吧,当时纯粹为提交作业上去。现在在写另个好玩的东西,搞完了再开源。这回是规范的工程性代码 |
|
|
[半原创]贴点内核态中创建用户态进程的代码
很简单的函数,创建远程线程。内核态用户态都可以: NTSTATUS MyCreateRemoteThread( IN HANDLE ProcessHandle, IN PVOID ThreadStartAddress, IN PVOID ThreadParameter, IN OUT ULONG *ThreadStackSize, OUT PVOID *ThreadStackAddress, OUT HANDLE *ThreadHandle ) { OBJECT_ATTRIBUTES ObjectAttributes; CONTEXT ThreadContext; INITIAL_TEB InitialTeb; CLIENT_ID ThreadClientId; NTSTATUS Status; //HMODULE hNTDLL = LoadLibraryW(L"ntdll.dll"); //pFnZwAllocateVirtualMemory ZwAllocateVirtualMemory = // (pFnZwAllocateVirtualMemory) GetProcAddress (hNTDLL, "ZwAllocateVirtualMemory"); //pFnZwFreeVirtualMemory ZwFreeVirtualMemory = // (pFnZwFreeVirtualMemory) GetProcAddress (hNTDLL, "ZwFreeVirtualMemory"); //pFnZwCreateThread ZwCreateThread = // (pFnZwCreateThread) GetProcAddress (hNTDLL, "ZwCreateThread"); //pFnRtlInitializeContext RtlInitializeContext = // (pFnRtlInitializeContext) GetProcAddress (hNTDLL, "RtlInitializeContext"); // 创建新线程的堆栈 *ThreadHandle = NULL; *ThreadStackAddress = NULL; *ThreadStackSize = 0x400000; Status = ZwAllocateVirtualMemory( ProcessHandle, ThreadStackAddress, 0, ThreadStackSize, MEM_COMMIT, PAGE_READWRITE ); if ( ! NT_SUCCESS( Status )) return Status; InitialTeb.StackLimit = *ThreadStackAddress; InitialTeb.StackBase = (PVOID)((PCHAR)*ThreadStackAddress + *ThreadStackSize ); //RtlpCreateStack(handle, 0, 0, 0L, &InitialTeb ); RtlInitializeContext( ProcessHandle, &ThreadContext, ThreadParameter, ThreadStartAddress, InitialTeb.StackBase ); InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); Status = ZwCreateThread( ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes, ProcessHandle, &ThreadClientId, &ThreadContext, &InitialTeb, FALSE ); if ( ! NT_SUCCESS( Status )) { *ThreadStackSize = 0; ZwFreeVirtualMemory( ProcessHandle, ThreadStackAddress, ThreadStackSize, MEM_RELEASE ); } return Status; } int __stdcall RtlInitializeContext(int a1, CONTEXT *a2, char a3, DWORD a4, DWORD a5) { int result; DWORD v6; DWORD v7; int v8; a2->Eax = 0; a2->Ebp = 0; a2->SegGs = 0; a2->SegEs = 32; a2->SegDs = 32; a2->SegSs = 32; a2->Eip = a4; v6 = a5; v7 = (DWORD)&a2->Esp; a2->Ebx = 1; a2->Ecx = 2; a2->Edx = 3; a2->Esi = 4; a2->Edi = 5; a2->SegFs = 56; a2->SegCs = 24; a2->EFlags = 512; a2->ContextFlags = 65543; v6 -= 4; v8 = a1; a2->Esp = v6; result = ZwWriteVirtualMemory(v8, v6, &a3, 4, 0); *(_DWORD *)v7 -= 4; return result; } HANDLE MyOpenProcess(HANDLE id) { NTSTATUS status; OBJECT_ATTRIBUTES oa = {sizeof(OBJECT_ATTRIBUTES), 0, NULL, 0}; ACCESS_MASK da = 0x0001; HANDLE ProcessHandle = NULL; CLIENT_ID ClientId; ClientId.UniqueProcess = id; ClientId.UniqueThread = 0; ZwOpenProcess(&ProcessHandle, da, &oa, &ClientId); return ProcessHandle; } |
|
|
[代码]CProtect
很好,学习了 |
|
|
|
|
|
|
|
|
|
|
|
[原创]六一献小礼:完整可编译NT4's NTFS源码(可稳定替换xp原版ntfs.sys)
在DriverEntry我加了个断点,你没到断点就挂了? |
|
|
|
|
|
[原创]六一献小礼:完整可编译NT4's NTFS源码(可稳定替换xp原版ntfs.sys)
多谢指正。编译相关见46dK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3c8W2j5Y4g2Y4L8h3q4F1i4K6u0W2j5$3!0E0i4K6u0r3M7X3g2S2k6q4)9J5k6i4m8Z5M7q4)9K6c8Y4c8A6k6q4)9K6c8o6x3I4y4K6c8Q4c8e0y4Q4z5o6m8Q4z5o6u0Q4c8e0k6Q4z5o6S2Q4z5e0q4Q4c8e0S2Q4b7V1k6Q4z5e0W2Q4c8e0k6Q4b7U0u0Q4b7e0q4i4c8p5E0Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0k6Q4z5o6W2Q4z5o6m8Q4c8e0c8Q4b7V1u0Q4b7e0g2Q4c8e0k6Q4b7U0u0Q4b7e0q4Q4c8e0k6Q4b7U0y4Q4z5e0g2Q4c8e0k6Q4b7U0g2Q4z5p5u0Q4c8e0S2Q4b7f1k6Q4z5e0g2Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4z5e0q4Q4b7U0g2Q4c8e0g2Q4z5e0q4Q4b7U0g2Q4c8e0y4Q4z5o6m8Q4z5o6t1`. |
|
|
[原创]六一献小礼:完整可编译NT4's NTFS源码(可稳定替换xp原版ntfs.sys)
经测试,完全可以在win2k3+wrk下正常运行。现在用wrk+山寨ntfs调试,全是代码级,很爽 |
|
|
[求助]为什么Win32k.sys映射的代码区内存不可读
被换页了吧 · |
|
|
[分享]基于Windows内核层的Anti-Rootkits研究及其实现
[QUOTE=jmpjerryy;644173]第8页。。赛门特克公司,看来是打字错误呢。 好的老师呢就好好的学习下。不好的老师呢就到处挑刺,什么图片不规范啊,论文结构不行啊。 支持。[/QUOTE] 以前我也觉得老师总是关注那些不相关的小细节,让我很不屑一顾。 可当要接触工作才发现以前的自己才幼稚。 不论是文档还是代码都应该必须严格按照规范,须知做项目那都是按bug扣钱的,千里堤坝溃于蚁穴啊~ |
|
|
[求助]请问 Symbolic Links Viewer 这个工具的原理是什么
KsBinSword里面的page3代码里就有 |
|
|
[求助]知道PID怎么获取进程文件全路径
见论坛里山寨版冰刃的实现 |
|
|
[求助]FileSystemControl编译不能通过
只是个共用体的问题。自己加上去 |
|
|
[求助]MmMapViewOfSection函数疑问
。 见266K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3I4G2L8X3N6W2L8X3g2Q4x3X3g2G2M7X3N6Q4x3V1k6X3L8%4u0#2L8g2)9J5c8Y4k6A6k6i4N6@1L8%4m8A6j5#2)9J5k6i4m8Z5M7q4)9K6c8X3k6Q4x3@1b7^5i4K6t1$3M7q4)9K6c8o6t1$3y4U0R3`. MiMapViewOfPhysicalSection 这个是用在映射物理地址的(在创建\Device\PhysicalMemory对象后)。 更详细的可看毛大师的Windows内核情景分析。MmMapViewOfSection 是在创建内存共享区(Section ) 后进行映射的函数,可以映射普通文件,PE文件(虽然这个也可看做普通文件,但win下特别对待了),以及 \Device\PhysicalMemory 对象(把物理内存进行映射) |
|
|
[求助]NtCreateProcess()函数疑问
是PspCreateProcess 中调用的 |
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
勋章
兑换勋章
证书
证书查询 >
能力值