用vc++窮舉windows應用程序密碼

一、引言

  隨着計算機信息技術的發展,人們越來越重視信息的安全性,信息數據的安全保密已經成爲影響計算機發展的一個重要課題。機密文件、商業情報、銀行賬號、網絡密碼、科技成果、包括私人信件等等,都成了用戶爲難以存放發愁的心病。密碼可以說是他們的唯一的精神寄託,通過密碼,他們可以對這些信息進行加密,或者通過密碼對用戶存取信息進行授權,非法用戶禁止存取有關信息。

  但是有了密碼,用戶也不能高枕無憂,因爲密碼都是人工鍵入的,都是由鍵盤的可見字符組成(包括漢字),如果一個非法用戶不幸猜中了你的密碼,哪怕只有千萬分之一的機率,也會給你的數據安全帶來潛在威脅,而不光會污染你的數據,喪心病狂的人甚至會在瞬間摧毀你苦心經營多年的成果。更何況現在有了電腦作爲工具,它可以在一分鐘之間窮舉成千上萬個密碼,利用局域網分佈式計算,一個小時內窮舉十位以下的所有密碼,更不幸的是我們的用戶所用的密碼都是出奇的易記(擊),他們偏好單用數字和字母,這爲他們數據安全埋下了危機。

  本文正是通過引用一個窮舉密碼的例子來提醒用戶,在密碼問題上不要大意,密碼要求儘可能長,而且不要鄙視非數字和非字母字符,密碼要定期更換。動態密碼,相對更爲安全。

  二、實現原理:

  我們的用戶一般都過輸入密碼的經歷,一般情況下系統都會顯示一個對話框,提醒用戶輸入密碼,密碼編輯框一般具有ES_PASSWORD 風格,用戶輸入完成後,要求按《確定》按鈕確認,如果密碼正確,系統就會開始工作,否則系統會提示你密碼錯誤,要求按《確定》按鈕重新輸入。無論我們運用鼠標的技能有多高,如果我們想在短時間內窮舉所有可能密碼,根本不現實。但是高速運行的計算機可以做到。

  我們可以通過編程,利用Windows API 函數EnumWindows 和EnumChildWindows對當前運行的所有程序的所有窗口(包括子窗口即控件)進行遍歷,通過窗口標題查找密碼輸入和出錯確認重新輸入窗口,通過按鈕標題查找我們應該單擊的按鈕,通過ES_PASSWORD 查找我們需要鍵入的密碼窗口。

  我們可以通過向密碼輸入窗口發送WM_SETTEXT消息模擬輸入密碼,通過向按鈕窗口發送WM_COMMAND消息模擬單擊。所有這一切我們可以把它放在一個線程內運行,我們用戶可以隨時暫停、隨時中斷退出。我們可以在枚舉密碼的過程中,把密碼保存在一個文件中,以便下次接着下一個序列的密碼再次窮舉。直到找到密碼爲止。找到密碼後,由於不再出現密碼輸入窗口,程序雖然仍在繼續枚舉窗口,但由於找不到對應窗口,不會發送任何消息。我們打開記錄文件推算前一個序列的密碼即可找到對應的密碼。

  枚舉密碼的方法有多種,這跟密碼的組成有關,如果你忘記了你的wps 2000 的文件密碼,而且你確切知道密碼由數字組成,你就可以採用數字窮舉,當然程序還提供了其它窮舉方法,包括大寫字母、小寫字母、大小寫混合、字母數字、標點符號字母數字組合等等。每一種窮舉方法都有進度記錄保存,下次窮舉不用從頭開始,字符個數從一位到多位自動增長。你可以通過編輯配置文件setup.ini控制窮舉進度,尤其是當你知道密碼的某一位確切爲某一個字符時,或者確切知道密碼有幾位時,通過修改當前密碼(退出程序情況下),可以大大加快窮舉速度,以便短時間內找回那根遺忘的神經,喚醒那存儲密碼的神經元細胞。

  三、具體細節:

  ◆進程和線程

  Windows應用程序有一個或多個進程組成。所謂進程,用最簡單的術語說就是裝入內存並準備運行的可執行的程序。進程是資源分配的獨立單位。進程具有動態、併發、獨立等特點。進程具有就緒、執行、堵塞三種基本狀態,win 32中的每個進程都有自己的私有虛擬地址空間,進程有代碼、數據和進程中的線程可用的其他系統資源組成,每個進程都由單線程開始,並可創建新的線程和其他進程。

  在一個進程中運行着一個或多個線程,線程是操作系統分配處理器時間片的最小單位,一個線程可以執行進程中的任何一部分代碼,包括當前被其他線程執行的部分。線程能獨立執行程序代碼的任何部分,共享虛擬地址空間並能訪問全局變量和進程系統資源。各個線程根據其調度優先級分配CPU,線程具有進程的許多特徵,又稱爲輕量級的進程。由於線程基本上不擁有系統資源,僅佔有一點在運行中不可缺少的資源(機器寄存器、內核堆棧、線程環境塊和用戶堆棧等),由於應用程序由進程組成,進程由線程組成。同一進程線程的切換不會引起進程的切換,因此,線程的調度開銷要遠遠小於進程的調度開銷。

  在MFC類庫中,每個CWinThread對象表示程序的一個執行線程,MFC 將線程分爲兩種類型:用戶界面線程(user-interface thread)和工作者線程(worker thread),前者用於消息循環或消息泵,用於消息處理。後者沒有消息循環用於無需用戶響應的後臺任務。

  工作者線程分兩步創建:

  1.創建線程函數

  DWORD WINAPI ThreadFunc( LPVOID );

  參數值是在創建線程對象時傳遞給構造函數的值,它既可爲標量值,也可以爲指向多個參數結構的指針,還可以省略。

  2.調用AfxBeginThread啓動工作者線程。此時,全局函數AfxBeginThread採用以下原型:

CWinThread * AfxBeginThread(
AFX_THREADPROC pfnThreadProc ,

LPVOID pParam,

int nPriority=THREAD_PRIORITY_NORMAL,

UINT nStackSize=0,

DWORD dwCreateFlags=0,

LPSECURITY_ATTRIBUTES lpsecurityAttrs=NULL);
 


  其中:pfnThreadProc 即爲工作者線程的線程函數。

  pParam 爲傳遞給工作者線程函數的入口參數。

  nPriority 創建優先級別可以使用SetThreadPriority設置,默認值爲THREAD_PRIORITY_NORMAL

  dwCreateFlags 創建標誌0爲創建後立即運行,若爲CREDTE_SUSPEND,創建後處於掛起狀態。

  在工作者線程函數中,執行return 語句或者執行AfxEndThread函數將導致線程運行終止。

  我們可以通過設置CWinThread 對象的成員變量和成員函數來對線程進行控制。

  m_bAutoDelete爲true ,表示線程終止後自動銷燬。

  m_hThread 表示當前線程句柄。

  ResumeThread 使掛起線程恢復運行

  SuspendThread掛起運行線程

  SetThreadPriority設置線程的運行優先級

  其他成員請參考MFC 類庫和MSDN幫助文檔。

  ◆同步對象

  由於系統爲了提高窮舉效率,採用了多線程編程,以便加快模擬輸入響應速度,在儘可能短的時間內得到真正的密碼。

  由於線程之間共享進程資源,這樣就會帶來同步的問題。譬如,由於多個線程併發地存在於系統之中同時運行(時間片輪轉),可能會存在這樣的情況,兩個線程都在修改窗口密碼編輯框文本,前一個線程修改後還未來得及按《確定》按鈕,另一個線程又修改了窗口的文本,造成前一個密碼文本丟失,導致窮舉密碼不全,可能窮舉失敗。一個線程正在向密碼編輯框填寫文本,而另一個線程又在改寫該文本,這樣會導致前一個線程無法辨識究竟用的是哪一個版本的密碼文本。會導致重複窮舉或者殘缺窮舉,甚至系統死鎖。

  爲了保證進程或線程能夠按照一定的順序推進向前執行,windows 提供了一組等待函數和同步對象用於控制同步。包括信號燈、互斥量、事件、臨界區。同步的思想很簡單,如果一個線程遇到一個信號變量無信號時,它能使自己處於睡眠狀態一旦有了信號系統會喚醒線程,使線程接着執行。

  本文僅僅簡要敘述以下互斥信號量,其他信號量不在本文談論之列,請用戶自行參考《win 32 編程指南》或 MSDN .

  互斥信號量用於串行某一資源的使用,即任一時刻僅允許至多一個線程訪問某一資源,一個互斥信號燈只能爲一個線程所擁有,任何試圖要求互斥標誌的其他線程都將被鎖住,直到互斥標誌被釋放爲止。

  在程序採用了多個線程對窗口進行枚舉,一旦某線程發現密碼窗口或出錯要求重試窗口,該線程便首先獲得互斥信號量,該線程具有枚舉子窗口的權利,能夠向密碼編輯框輸入文本,發送鍵盤鼠標消息,其他線程因無法獲得互斥標誌處於睡眠狀態。這正如列車上的衛生間,一次只能進一個人,進去後先關門,其他人被擋在大門之外,直到裏面的人出來,別人方可進去。

  CreateMutex 函數用於創建一個命名的或無命名的互斥量對象。

HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,

  // 安全屬性指針

    BOOL bInitialOwner, // 最初的擁有標誌

    LPCTSTR lpName // 指向互斥量的對象名

   );
 


參數:

    lpMutexAttributes

    指向一個安全屬性結構,決定返回句柄能否被子進程繼承並擁有,如果此值爲NULL,那麼句柄無法繼承擁有。

    bInitialOwner

    指示互斥對象的最初擁有者,此值爲真,請求互斥量的線程可以直接獲得互斥量的擁有權。否則互斥量不被擁有。
lpName

    指向一個以0結尾的字符串, 來表示互斥對象的名字,名字限於MAX_PATH 個字符串,可以包含除 / 以外的任何字符,名字大小寫敏感。

    若此值爲NULL ,互斥對象沒有名字。

    返回值:

    函數執行成功,返回指向互斥對象的句柄。

    WaitForSingleObject函數只有在下列情況發生時才返回,否則處於睡眠狀態。

    1. 指定的對象處於信號狀態,

    2. 等待事件超時。

 DWORD WaitForSingleObject(
    HANDLE hHandle, // 等待對象的句柄

    DWORD dwMilliseconds    // 超時的毫秒數

    );
 


  參數:

  hHandle

  等待對象標識,可以採用上面CreateMutex返回的句柄

  dwMilliseconds

  指定的超時的毫秒數,若爲INFINITE,超時不限

  返回值:

  執行成功,返回值預示着導致函數返回的事件發生。

  註釋:

  WaitForSingleObject函數首先檢查指定的對象當前狀態,如果當前對象處於無信號狀態,調用函數的線程將進入有效等待狀態,在信號來臨或超時發生之前,在等待信號的過程中線程消耗非常有限的處理器時間。

  在返回之前,等待函數會修改某些同步對象的狀態。修改僅適用於那些會導致函數返回的對象。對互斥量對象,互斥量有信號時,它不爲任何線程所擁有,用線程的等待函數會獲得互斥量的擁有權,一旦得到互斥量的擁有權,它就會修改互斥量爲無信號狀態。

  枚舉操作完成後,線程要調用ReleaseMutex函數以便釋放互斥量的擁有權,從而使其他沒有得到響應的線程喚醒。

  ◆窗口枚舉

  EnumWindows 函數通過藉助於應用程序定義的回調函數傳遞每個窗口句柄枚舉所有頂層的屏幕窗口。直到最後一個頂層窗口被枚舉或者回調函數返回false ,EnumWindows 函數纔會退出停止枚舉過程。

  函數原型:

BOOL EnumWindows(
    WNDENUMPROC lpEnumFunc, // 指向回調函數

LPARAM lParam     // 應用程序定義的參數值

   );
 


  參數:

  lpEnumFunc

  指向一個應用程序定義的回調函數。

  lParam

  指定一個32位的應用程序定義的參數值傳遞給回調函數。

  返回值:

  函數執行成功返回非零,否則返回零。

  註釋:

  EnumWindows 函數不會枚舉子窗口,這個函數相比而言比循環調用GetWindows函數可靠。調用GetWindow函數的應用程序枚舉窗口時可能會陷入一個死循環,或者引用的窗口句柄已經被破壞。

  EnumWindowsProc 函數是一個用戶定義的回調函數,它能夠接受頂層窗口句柄,並把返回的函數值傳遞給EnumWindows 函數或 EnumDesktopWindows 函數。

  函數原型:

BOOL CALLBACK EnumWindowsProc(
    HWND hwnd,  // 父窗口句柄

    LPARAM lParam   // 應用程序定義的參數值

   );
 


參數:

    hwnd

    標是一個頂層窗口

    lParam

    指定一個傳遞給EnumWindows或EnumDesktopWindows的應用程序定義參數值。

    返回值:

    若應用程序想持續枚舉窗口,必須返回true.返回false停止枚舉。

    註釋:

    這個回調函數可以執行任何渴望的任務,應用程序必須通過傳遞函數地址給  EnumWindows或EnumDesktopWindows註冊回調函數。

    EnumWindowsProc 是一個應用程序定義的函數名,該函數聲明爲 WNDENUMPROC 類型。

    ◆子窗口枚舉

    EnumChildWindows 函數通過藉助於應用程序定義的回調函數傳遞每一個子窗口的窗口句柄枚舉所有隸屬於指定父窗口的子窗口,直到最後一個子窗口被枚舉或者回調函數返回false,

    EnumChildWindows 纔會停止枚舉子窗口。

    函數原型:

BOOL EnumChildWindows(
    HWND hWndParent,    // 父窗口句柄

    WNDENUMPROC lpEnumFunc, // 回調函數指針

    LPARAM lParam   // 應用程序定義的參數值

   );
 
參數:

  hWndParent

  標識一個其子窗口將被枚舉的子窗口。

  lpEnumFunc

  指向一個應用程序定義的回調函數。

  lParam

  標識一個傳遞給回調函數的應用程序定義的32位參數值

  返回值:

  執行成功返回非零,否則返回零。

  註釋:

  EnumChildWindows 函數既不會枚舉爲指定窗口擁有的頂層窗口,也不會枚舉其它擁有的窗口。如果一個子窗口已經創建它自己的子窗口,這個函數同樣也會枚舉這些子窗口。

  在枚舉的過程中,子窗口按照Z順序被移動或被改變位置,不會影響枚舉結果。函數不會枚舉一個在枚舉之前被破壞的子窗口,也不會枚舉在枚舉過程中創建的子窗口。

  同EnumWindows 函數一樣,這個函數比調用GetWindow函數可靠,因爲後者會可能陷入死循環,或者參考到一個已經破壞的句柄。

  EnumChildProc函數是一個應用程序定義的回調函數,這個函數能夠接受子窗口句柄,作爲調用EnumChildWindows 的結果。

  函數原型:

BOOL CALLBACK EnumChildProc(
    HWND hwnd,  // 子窗口句柄

    LPARAM lParam   // 應用程序定義的參數值

   );
 


  參數:

  hwnd

  標識一個隸屬於由EnumChildWindows指定的父窗口的子窗口。

  lParam

  指定一個在EnumChildWindows 給定的應用程序定義的參數值。

  返回值:

  持續枚舉子窗口,程序必須返回true.返回false 停止枚舉。

  註釋:

  回調函數可以執行任何渴望的任務。應用程序必須通過傳遞函數地址給EnumChildWindows來註冊回調函數。

  ·密碼枚舉

  我們知道組成密碼的字符由許多種,有人喜歡單用數字,有人喜歡單用字母(包括大小寫),也有的是用一些諸如!。#“等符號,我們可以分情況區別對待。密碼的長短也是一個制約窮舉的一個重要因素,密碼長度越長,密碼的排列組合種類越多,窮舉時間越長。

  我們把所有的密碼字符都看成字符串,把字符組成集合視爲密碼字符集。如{0,1,2,3,4,5,6,7,8,9}、{A、B、C、D、E、F、G、H、I、J、K、L、M、N、O、P、Q、R、S、T、U、V、W、X、Y、Z}等都稱之爲密碼字符集。每一個密碼每一位都由這些字符集的任意一個字符組成。若字符集中有N個元素,則長度爲M的密碼根據排列組合共有N的M次方種排法。我們只要將密碼字符集的各個要素逐次地放入密碼的各個位置,就能窮舉長度爲M的密碼。而長度M可以從1開始自動增長。就像密碼開始從 0窮舉到9,長度變化爲 2,密碼在從00窮舉到99一樣,我們只需變換密碼字符集即可變換密碼的組成元素。給出密碼的算法都一樣。每得出一個密碼,我們都可以將其存入文件,下次枚舉時可以通過這個密碼推算下一個密碼,如上一個密碼爲ZZ,則下一個密碼應爲AAA,再下一個爲AAB … AAZ…ABA……ABZ…AZZ…BAA…依次類推。一直推算到ZZZ,接着又是AAAA.有點類似於十進制、二十六進制、五十二進制,只不過這裏是各位數不是數字而是字符,字符來自我們自己定義的密碼字符集。組成的密碼不是數字,而是字符串。

  程序還採用了字典窮舉法,密碼字典採用純文本文件(。txt),該文件可以用edit 、notepad、ultraedit建立,每一個密碼之間採用回車符和換行符間隔。程序窮舉時會自動保存文件讀寫指針和當前窮舉密碼。

  窮舉密碼時程序會自動保存窮舉進度,以便下次窮舉時不用從頭開始。通過修改配置文件setup.ini, 我們很容易實現控制窮舉進度,也可以實現多人窮舉時的任務分工。

  下面是一個窮舉電子圖板文件密碼的setup.ini例子

  [設置]

  口令輸入窗口標題=輸入文件密碼

  口令輸入窗口確認按鈕標題=確定

  提示口令錯要求重新輸入窗口標題=Eb

  提示口令錯要求重新輸入窗口確認按鈕標題=確定

  窮舉方法=大寫字母

  線程計數=5

  窮舉文件=C:/TOOLS/部門。txt

  [C:/TOOLS/部門。txt]

  文件指針=171

  當前窮舉密碼=AB

  [大寫字母]

  當前密碼=AC =〉將密碼改成AAAA開始窮舉四位密碼,當然你也可以改爲BAAA、CAAA、DAAA等等。

  程序對密碼限制不超過 30 位。

  四、程序代碼

  1.資源文件 GETCODE.RC

//Microsoft Developer Studio generated resource script.
//

#include "resource.h"

 

#define APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////

//

// Generated from the TEXTINCLUDE 2 resource.

//

#include "afxres.h"

 

/////////////////////////////////////////////////////////////////////////////

#undef APSTUDIO_READONLY_SYMBOLS

 

/////////////////////////////////////////////////////////////////////////////

// Chinese (P.R.C.) resources

 

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)

#ifdef _WIN32

LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#pragma code_page(936)

#endif //_WIN32

 

#ifdef APSTUDIO_INVOKED

/////////////////////////////////////////////////////////////////////////////

//

// TEXTINCLUDE

//

 

1 TEXTINCLUDE DISCARDABLE

BEGIN

    "resource.h/0"

END

 

2 TEXTINCLUDE DISCARDABLE

BEGIN

    "#include ""afxres.h""/r/n"

    "/0"

END

 

本篇文章來源於 黑客基地-全球最大的中文黑客站 原文鏈接:http://www.hackbase.com/tech/2009-03-23/51788_1.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章