小沈龙最新小品全集:用vc 穷举windows应用程序密码(上)

来源:百度文库 编辑:中财网 时间:2024/05/06 02:42:15
用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函数以便释放互斥量的拥有权,从而使其他没有得到响应的线程唤醒。
BOOL ReleaseMutex(
HANDLE hMutex   // handle of mutex object
);
◆窗口枚举
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   // 应用程序定义的参数值
);
3 TEXTINCLUDE DISCARDABLE
BEGIN
"#define _AFX_NO_SPLITTER_RESOURCESrn"
"#define _AFX_NO_OLE_RESOURCESrn"
"#define _AFX_NO_TRACKER_RESOURCESrn"
"#define _AFX_NO_PROPERTY_RESOURCESrn"
"rn"
"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)rn"
"#ifdef _WIN32rn"
"LANGUAGE 4, 2rn"
"#pragma code_page(936)rn"
"#endif //_WIN32rn"
"#include ""res\GetCode.rc2""  // non-Microsoft Visual C++ edited resourcesrn"
"#include ""l.chs\afxres.rc""          // Standard componentsrn"
"#endifrn"
""
END
#endif    // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDR_MAINFRAME           ICON    DISCARDABLE     "res\GetCode.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_GETCODE_DIALOG DIALOGEX 0, 0, 320, 221
STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP |
WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "密码穷举设置"
FONT 9, "宋体"
BEGIN
DEFPUSHBUTTON   "应用",IDOK,262,19,51,14
PUSHBUTTON      "退出",IDCANCEL,263,63,50,14
GROUPBOX        "密码输入窗口设置",IDC_STATIC,7,44,221,51
EDITTEXT        IDC_EDIT1,113,52,83,14,ES_AUTOHSCROLL
LTEXT           "密码窗口标题",IDC_STATIC,19,56,49,8
LTEXT           "密码输入确认按钮标题",IDC_STATIC,19,76,81,8
EDITTEXT        IDC_EDIT2,113,73,83,14,ES_AUTOHSCROLL
GROUPBOX        "密码输错窗口设置",IDC_STATIC,7,98,221,51
EDITTEXT        IDC_EDIT3,113,106,83,14,ES_AUTOHSCROLL
LTEXT           "密码出错提示窗口标题",IDC_STATIC,19,110,81,8
LTEXT           "重新输入确认按钮标题",IDC_STATIC,19,130,81,8
EDITTEXT        IDC_EDIT4,113,127,83,14,ES_AUTOHSCROLL
GROUPBOX        "穷举密码方法设置",IDC_STATIC,7,152,221,62,WS_GROUP
CONTROL         "数字",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON | WS_GROUP,
13,164,32,10
CONTROL         "小写字母",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON |
WS_GROUP,45,164,48,10
CONTROL         "大写字母",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON |
WS_GROUP,93,164,48,10
CONTROL         "大小写字母组合",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON |
WS_GROUP,150,164,72,10
CONTROL         "数字字母组合",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON |
WS_GROUP,14,177,64,10
CONTROL         "所有字符",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON |
WS_GROUP,81,176,48,10
CONTROL         "字典穷举法",IDC_RADIO7,"Button",BS_AUTORADIOBUTTON |
WS_GROUP,150,175,71,10
PUSHBUTTON      "暂停",IDPause,263,41,50,14
GROUPBOX        "枚举线程数目",IDC_STATIC,7,7,221,34
LTEXT           "线程数目",IDC_STATIC,14,23,57,8
EDITTEXT        IDC_EDIT5,86,19,42,14,ES_AUTOHSCROLL
LTEXT           "枚举文件名",IDC_STATIC,15,195,42,19
EDITTEXT        IDC_EDIT6,66,194,111,14,ES_AUTOHSCROLL
PUSHBUTTON      "浏览...",IDC_BROWSE,185,193,31,14
END
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080404B0"
BEGIN
VALUE "CompanyName", ""
VALUE "FileDescription", "GetCode Microsoft 基础类应用程序"
VALUE "FileVersion", "1, 0, 0, 1"
VALUE "InternalName", "GetCode"
VALUE "LegalCopyright", "版权所有 (C) 1999"
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "GetCode.EXE"
VALUE "ProductName", "GetCode 应用程序"
VALUE "ProductVersion", "1, 0, 0, 1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x804, 1200
END
END
#endif    // !_MAC
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_GETCODE_DIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 313
TOPMARGIN, 7
BOTTOMMARGIN, 214
HORZGUIDE, 139
END
END
#endif    // APSTUDIO_INVOKED
#endif    // Chinese (P.R.C.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#define _AFX_NO_SPLITTER_RESOURCES
#define _AFX_NO_OLE_RESOURCES
#define _AFX_NO_TRACKER_RESOURCES
#define _AFX_NO_PROPERTY_RESOURCES
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
#ifdef _WIN32
LANGUAGE 4, 2
#pragma code_page(936)
#endif //_WIN32
#include "resGetCode.rc2"  // non-Microsoft Visual C++ edited resources
#include "l.chsafxres.rc"          // Standard components
#endif
/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED
2.对话框头文件
// GetCodeDlg.h : header file
//
#if !defined(AFX_GETCODEDLG_H__B5583AA8_7FDB_11D3_BF20_D9C0F13E2367__INCLUDED_)
#define AFX_GETCODEDLG_H__B5583AA8_7FDB_11D3_BF20_D9C0F13E2367__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
/////////////////////////////////////////////////////////////////////////////
// CGetCodeDlg dialog
class CGetCodeDlg : public CDialog
{
// Construction
public:
CGetCodeDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CGetCodeDlg)
enum { IDD = IDD_GETCODE_DIALOG };
CButton  m_Quit;
CEdit   m_EditPath;
CButton  m_BtnBrowser;
CButton  m_Pause;
CButton  m_OK;
UINT    m_nThreadCount;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CGetCodeDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CGetCodeDlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnOK();
afx_msg void OnCANCEL();
afx_msg void OnPause();
afx_msg void OnBrowse();
afx_msg void OnRadio7();
afx_msg void OnRadio1();
afx_msg void OnRadio2();
afx_msg void OnRadio3();
afx_msg void OnRadio4();
afx_msg void OnRadio5();
afx_msg void OnRadio6();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_GETCODEDLG_H__B5583AA8_7FDB_11D3_BF20_D9C0F13E2367__INCLUDED_)
3。对话框源文件
// GetCodeDlg.cpp : implementation file
//
#include "stdafx.h"
#include "GetCode.h"
#include "GetCodeDlg.h"
#include "stdlib.h"
#include "ctype.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define INPUTDIALOGID 1001  //枚举子窗口时标识对话框的类别为密码输入对话框
#define INPUTRETRYDIALOGID 1002//枚举子窗口时标识对话框的类别为确认重新输入对//话框
#define MAX_THREAD 50
/////////////////////////////////////////////////////////////////////////////
// CGetCodeDlg dialog
struct ThreadStru
{CWinThread * pThread;
}m_pEnumThread[MAX_THREAD];//定义线程结构数组,用以存放多线程的线程指针
BOOL m_bEnum;//枚举控制布尔变量,若此值为假,终止所有线程枚举。
HWND m_hwnd;//存放对话框窗口句柄,用于在公共模块访问对话框控件
HWND hButton1,hButton2;//存放两个对话框确认按钮的窗口句柄。
BOOL m_bPasswordStyle;//窗口风格标志,标识子窗口为编辑框的子窗口是否                  //具有口令风格。
bool bFetched;//枚举的密码是否被取走标志,
UINT  nThreadCount;//线程数目计数
char lpszDialogCaption[80];//对话框标题
char lpszButtonConfirmCaption[20];//对话框确认按钮标题
char lpszDialogRetryCaption[80];//重试对话框标题
char lpszButtonRetryCaption[20];//重试对话框标题按钮标题
char lpszThreadCount[4];//线程数目计数
char lpszPath[MAX_PATH];//字典穷举的文件路径
char lpszMethod[30]="";//穷举密码方法
HANDLE m_hMutex;//互斥信号量句柄
TCHAR lpszPassword[30];//枚举密码产生的密码
DWORD WINAPI EnumProc( LPVOID );//线程函数声明
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam );
//窗口函数枚举声明
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam);
//子窗口函数枚举声明
void EnumPasswordString(void);
//密码字符发生器,产生密码序列
CGetCodeDlg::CGetCodeDlg(CWnd* pParent /*=NULL*/)
: CDialog(CGetCodeDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CGetCodeDlg)
m_nThreadCount = 0;//线程数目初始化为零
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_bPasswordStyle=FALSE;
m_bEnum=TRUE;
bFetched=true;
m_hwnd=this->m_hWnd;
//以下语句用于从记录文件读取信息以便使系统恢复到上次退出时的状态。
GetPrivateProfileString("设置","线程计数","1",lpszThreadCount,4,"Setup.ini");
GetPrivateProfileString("设置","口令输入窗口标题","LOGIN",lpszDialogCaption,80,"Setup.ini");
GetPrivateProfileString("设置","口令输入窗口确认按钮标题","OK",lpszButtonConfirmCaption,20,"Setup.ini");
GetPrivateProfileString("设置","提示口令错要求重新输入窗口标题","Login",lpszDialogRetryCaption,80,"Setup.ini");
GetPrivateProfileString("设置","提示口令错要求重新输入窗口确认按钮标题","确认",lpszButtonRetryCaption,20,"Setup.ini");
GetPrivateProfileString("设置","穷举方法","数字",lpszMethod,30,"Setup.ini");
GetPrivateProfileString("设置","穷举文件","",lpszPath,MAX_PATH,"Setup.ini");
this->m_nThreadCount=atoi(lpszThreadCount);
nThreadCount=this->m_nThreadCount;
m_hIcon= AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CGetCodeDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CGetCodeDlg)
DDX_Control(pDX, IDCANCEL, m_Quit);
DDX_Control(pDX, IDC_EDIT6, m_EditPath);
DDX_Control(pDX, IDC_BROWSE, m_BtnBrowser);
DDX_Control(pDX, IDPause, m_Pause);
DDX_Control(pDX, IDOK, m_OK);
DDX_Text(pDX, IDC_EDIT5, m_nThreadCount);
DDV_MinMaxUInt(pDX, m_nThreadCount, 1, 50);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CGetCodeDlg, CDialog)
//{{AFX_MSG_MAP(CGetCodeDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDCANCEL, OnCANCEL)
ON_BN_CLICKED(IDPause, OnPause)
ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
ON_BN_CLICKED(IDC_RADIO7, OnRadio7)
ON_BN_CLICKED(IDC_RADIO1, OnRadio1)
ON_BN_CLICKED(IDC_RADIO2, OnRadio2)
ON_BN_CLICKED(IDC_RADIO3, OnRadio3)
ON_BN_CLICKED(IDC_RADIO4, OnRadio4)
ON_BN_CLICKED(IDC_RADIO5, OnRadio5)
ON_BN_CLICKED(IDC_RADIO6, OnRadio6)
ON_BN_CLICKED(IDOK, OnOK)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGetCodeDlg message handlers
BOOL CGetCodeDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//
// Set the icon for this dialog.  The framework does this automatically
//  when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);           // Set big icon
SetIcon(m_hIcon, FALSE);
// Set small icon
//创建互斥信号量
m_hMutex=::CreateMutex(NULL,FALSE,NULL);
//设置对话框控件
SetDlgItemText(IDC_EDIT1,lpszDialogCaption);
SetDlgItemText(IDC_EDIT2,lpszButtonConfirmCaption);
SetDlgItemText(IDC_EDIT3,lpszDialogRetryCaption);
SetDlgItemText(IDC_EDIT4,lpszButtonRetryCaption);
SetDlgItemText(IDC_EDIT6,lpszPath);
CString lpszTemp;
lpszTemp.Format("%s",lpszMethod);
if(lpszTemp=="数字") CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO1);
if(lpszTemp=="小写字母") CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO2);
if(lpszTemp=="大写字母")CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO3);
if(lpszTemp== "大小写字母组合")CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO4);
if(lpszTemp== "数字字母组合")CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO5);
if(lpszTemp== "所有字符")CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO6);
if(lpszTemp== "数据字典")
{CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO7);
m_EditPath.EnableWindow(TRUE);
m_BtnBrowser.EnableWindow(TRUE);
}
else
{m_EditPath.EnableWindow(FALSE);
m_BtnBrowser.EnableWindow(FALSE);
}
// TODO: Add extra initialization here
return TRUE;  // return TRUE  unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below  //  to draw the icon.  For MFC applications using the document/view model,  //  this is automatically done for you by the framework.     void CGetCodeDlg::OnPaint()  {      if (IsIconic())      {          CPaintDC dc(this); // device context for painting             SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);             // Center icon in client rectangle          int cxIcon = GetSystemMetrics(SM_CXICON);          int cyIcon = GetSystemMetrics(SM_CYICON);          CRect rect;          GetClientRect(&rect);          int x = (rect.Width() - cxIcon + 1) / 2;          int y = (rect.Height() - cyIcon + 1) / 2;             // Draw the icon          dc.DrawIcon(x, y, m_hIcon);      }      else      {          CDialog::OnPaint();      }  }     // The system calls this to obtain the cursor to display while the user drags  //  the minimized window.  HCURSOR CGetCodeDlg::OnQueryDragIcon()  {      return (HCURSOR) m_hIcon;  }  void CGetCodeDlg::OnOK()  {   //读取控件文本,并保存到文件      GetDlgItemText(IDC_EDIT1,lpszDialogCaption,80);      GetDlgItemText(IDC_EDIT2,lpszButtonConfirmCaption,20);      GetDlgItemText(IDC_EDIT3,lpszDialogRetryCaption,80);      GetDlgItemText(IDC_EDIT4,lpszButtonRetryCaption,20);      GetDlgItemText(IDC_EDIT5,lpszThreadCount,20);      GetDlgItemText(IDC_EDIT6,lpszPath,MAX_PATH);      nThreadCount=(int)GetDlgItemInt(IDC_EDIT5,NULL,true);      if ((nThreadCount<1)||(nThreadCount>50))      {SetDlgItemText(IDC_EDIT5,"5");      GetDlgItem(IDC_EDIT5)->SetFocus();      return ;      }      WritePrivateProfileString("设置","线程计数",lpszThreadCount,"Setup.ini");      WritePrivateProfileString("设置","口令输入窗口标题",lpszDialogCaption,"Setup.ini");      WritePrivateProfileString("设置","口令输入窗口确认按钮标题",lpszButtonConfirmCaption,"Setup.ini");      WritePrivateProfileString("设置","提示口令错要求重新输入窗口标题",lpszDialogRetryCaption,"Setup.ini");      WritePrivateProfileString("设置","提示口令错要求重新输入窗口确认按钮标题",lpszButtonRetryCaption,"Setup.ini");      WritePrivateProfileString("设置","穷举文件",lpszPath,"Setup.ini");      LPTSTR lpszTemp;      if(this->GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO7)==IDC_RADIO1)lpszTemp="数字";      if(this->GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO7)==IDC_RADIO2)lpszTemp="小写字母";      if(this->GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO7)==IDC_RADIO3)lpszTemp="大写字母";      if(this->GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO7)==IDC_RADIO4)lpszTemp="大小写字母组合";      if(this->GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO7)==IDC_RADIO5)lpszTemp="数字字母组合";      if(this->GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO7)==IDC_RADIO6)lpszTemp="所有字符";      if(this->GetCheckedRadioButton(IDC_RADIO1,IDC_RADIO7)==IDC_RADIO7)lpszTemp="数据字典";      WritePrivateProfileString("设置","穷举方法",lpszTemp,"Setup.ini");      //按钮互锁      m_OK.EnableWindow(FALSE);      m_Quit.EnableWindow(FALSE);      m_Pause.EnableWindow(TRUE);      m_Pause.SetFocus();      //对话框最小化      this->PostMessage(WM_SYSCOMMAND,SC_MINIMIZE,0);      //如果对话框尚未创建线程,创建线程,且允许线程运行结束自动销毁      if (m_pEnumThread[0].pThread ==NULL)      {   UINT i;          for(i=1;i<=this->m_nThreadCount ;i++)          {//优先级最低可以相应的提高密码应用程序的对话框响应速度      m_pEnumThread[i].pThread=AfxBeginThread((AFX_THREADPROC)EnumProc,(LPVOID)0,THREAD_PRIORITY_LOWEST,0,0,NULL);          m_pEnumThread[i].pThread->m_bAutoDelete =true;          }      }      else //如果线程已经创建,唤醒挂起的线程          {   UINT i;          for(i=1;i<=this->m_nThreadCount;i++)          m_pEnumThread[i].pThread->ResumeThread();          }  }  DWORD WINAPI EnumProc( LPVOID )  {//通过布尔变量m_bEnum 实现循环枚举窗口,若 m_bEnum 为假,线程退出自动销毁  while (m_bEnum)  {   ::EnumWindows((WNDENUMPROC)EnumWindowsProc,NULL);  }  return true;  }  BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam )  {      if (!IsWindowVisible(hwnd)) return true;//当窗口不可见时,接着枚举下一窗口      char lpString[128]="";         ::GetWindowText(hwnd,(LPSTR)lpString,sizeof(lpString));      //通过窗口标题查找所需窗口      if(strstr(lpString,(const char *)lpszDialogCaption)!=NULL)      {//第一发现所需窗口的线程,获得互斥信号量,其它线程被阻住      ::WaitForSingleObject(m_hMutex,INFINITE);      //枚举父窗口下的子窗口      ::EnumChildWindows(hwnd,(WNDENUMPROC) EnumChildProc,INPUTDIALOGID);      //线程执行完毕释放信号量,以便另外线程进入      ::ReleaseMutex(m_hMutex);      return false;//返回假,枚举过程不再进行      }      if(strstr(lpString,(const char *)lpszDialogRetryCaption)!=NULL)      {::WaitForSingleObject(m_hMutex,INFINITE);      ::EnumChildWindows(hwnd,(WNDENUMPROC) EnumChildProc,INPUTRETRYDIALOGID);      ::ReleaseMutex(m_hMutex);      return false;      }        return true;非所需窗口,继续枚举  }  BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)  {    if (!IsWindowVisible(hwnd)) return true;//子窗口不可见继续枚举下一子窗口      char szTemp[128]="";      DWORD   dwStyle;      switch((long)lParam)      {case INPUTDIALOGID:           if(!m_bPasswordStyle)          {//尚未找到密码编辑框进入              dwStyle=(DWORD)GetWindowLong(hwnd,GWL_STYLE);              if((dwStyle & ES_PASSWORD)== ES_PASSWORD)              {   //是密码编辑框                  //枚举新密码,保存到公共变量lpszPassword中                  EnumPasswordString();          ::SendDlgItemMessage(::GetParent(hwnd),GetWindowLong(hwnd,GWL_ID),WM_SETTEXT,0,(LPARAM)(LPCTSTR)lpszPassword);                  m_bPasswordStyle=true;//置密码编辑框发现标志                  if (hButton1!=NULL)//若已经发现确定按钮,发送消息                  //复位各个变量,返回false 停止枚举                  {::SendMessage(::GetParent(hButton1),WM_COMMAND,(WPARAM)::GetWindowLong(hButton1,GWL_ID),(LPARAM)hButton1);                     bFetched=true;                  hButton1=NULL;                  m_bPasswordStyle=false;                  return false;                  }              return true;//还未发现确定按钮,继续枚举子窗口              }          }          if(hButton1==NULL)          {//通过子窗口标题寻找指定按钮          ::GetWindowText(hwnd,(LPSTR) szTemp,sizeof(szTemp));              if(strstr(szTemp,(const char *)lpszButtonConfirmCaption)!=NULL)              {hButton1=hwnd;                  if (m_bPasswordStyle)//若已经找到密码编辑框,发送键盘鼠标消息,//复位系统变量,退出枚举过程                  {::SendMessage(::GetParent(hButton1),WM_COMMAND,(WPARAM)::GetWindowLong(hButton1,GWL_ID),(LPARAM)hButton1);                     bFetched=true;                  hButton1=NULL;                  m_bPasswordStyle=false;                  return false;                  }              return true;//未找到密码编辑框继续枚举              }          return true;不是确定按钮,继续枚举          }          return true;          break;  case  INPUTRETRYDIALOGID:      ::GetWindowText(hwnd,(LPSTR) szTemp,sizeof(szTemp));      if(strstr(szTemp,(const char *)lpszButtonRetryCaption)!=NULL)      {hButton2=hwnd;      ::SendMessage(::GetParent(hButton2),WM_COMMAND,(WPARAM)GetWindowLong(hButton2,GWL_ID),(LPARAM)hButton2);      hButton2=NULL;      return false;      }      return true;      break;  default:return true;  }  return false;  }     void CGetCodeDlg::OnCANCEL()  {      m_bEnum=FALSE;//销毁线程         CDialog::OnCancel();      // TODO: Add your control notification handler code here     }     void CGetCodeDlg::OnPause()  {          //暂停枚举线程挂起             UINT i;          for(i=1;i<=this->m_nThreadCount;i++)          {m_pEnumThread[i].pThread->SuspendThread ();          }      //按钮联动      m_Pause.EnableWindow(FALSE);      m_OK.EnableWindow(TRUE);      m_Quit.EnableWindow(TRUE);      m_OK.SetFocus();  }
void  EnumPasswordString(void)  {   if(!bFetched) return;        //若产生的密码尚未使用,不再产生密码,直接返回退出      bFetched=false;      CString lpszCharSet;      char  lpszCurrentPassword[30]="";      CString lpszTmpCurrentPassword;      GetPrivateProfileString("设置","穷举方法","数字",lpszMethod,sizeof(lpszMethod),"Setup.ini");      //得到上一次密码产生的办法,不同的办法定义不同的密码字符集,并得到相应的密码      if(strstr(lpszMethod,"数字")!=NULL)      {lpszCharSet.Format ("%s","0123456789");      GetPrivateProfileString("数字","当前密码","0",(LPTSTR)lpszCurrentPassword,sizeof(lpszCurrentPassword),"Setup.ini");      }      if(strstr(lpszMethod,"小写字母")!=NULL)      {lpszCharSet.Format("%s","abcdefghijklmnopqrstuvwxyz" );      GetPrivateProfileString("小写字母","当前密码","a",(LPTSTR)lpszCurrentPassword,sizeof(lpszCurrentPassword),"Setup.ini");      }      if(strstr(lpszMethod,"大写字母")!=NULL)      {lpszCharSet.Format("%s","ABCDEFGHIJKLMNOPQRSTUVWXYZ" );      GetPrivateProfileString("大写字母","当前密码","A",(LPTSTR)lpszCurrentPassword,sizeof(lpszCurrentPassword),"Setup.ini");      }      if(strstr(lpszMethod, "大小写字母组合")!=NULL)      {lpszCharSet.Format("%s","abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ;      GetPrivateProfileString("大小写字母组合","当前密码","a",(LPTSTR)lpszCurrentPassword,sizeof(lpszCurrentPassword),"Setup.ini");      }      if(strstr(lpszMethod, "数字字母组合")!=NULL)      {lpszCharSet.Format("%s","0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ;      GetPrivateProfileString("数字字母组合","当前密码","0",(LPTSTR)lpszCurrentPassword,sizeof(lpszCurrentPassword),"Setup.ini");      }     if(strstr(lpszMethod, "所有字符")!=NULL)      { lpszCharSet.Format("%s","0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+`-=,./';[]\{}|:"<>?" );       GetPrivateProfileString("所有字符","当前密码","0",(LPTSTR)lpszCurrentPassword,sizeof(lpszCurrentPassword),"Setup.ini");      }     if(strstr(lpszMethod, "数据字典")!=NULL)      {unsigned long  nFilePos=GetPrivateProfileInt(lpszPath,"文件指针",0,"Setup.ini");//得到上次取密码的文件指针      CFile m_file;      m_file.Open (lpszPath,0,NULL);      if(nFilePos==m_file.GetLength())      {   m_file.Close ();          m_bEnum=false;          ::EnableWindow(::GetDlgItem(m_hwnd,IDOK),TRUE);          ::EnableWindow(::GetDlgItem(m_hwnd,IDCANCEL),TRUE);          ::EnableWindow(::GetDlgItem(m_hwnd,IDPause),FALSE);          ::SetFocus(::GetDlgItem(m_hwnd,IDOK));          return ;      //密码字典已经遍历完毕,停止线程枚举      }      m_file.Seek (nFilePos,0);      int i=0;      for(;;)      {m_file.Read(lpszPassword+i,1);//依次读取密码字符,跳过回车换行符      if ((char)lpszPassword[i]!=0x0d)      {nFilePos++;      i++;      m_file.Seek (nFilePos,0);      continue;      }      else      {   m_file.Close ();          TCHAR lpszFilePos[10];          lpszPassword[i]='';          nFilePos++;          nFilePos++;//进度信息存盘          _stprintf(lpszFilePos,"%d",nFilePos);          WritePrivateProfileString(lpszPath,"文件指针",lpszFilePos,"Setup.ini");          WritePrivateProfileString(lpszPath,"当前穷举密码",lpszPassword,"Setup.ini");      break;      }      }     return;     }  bool bSetOk=false;  lpszTmpCurrentPassword.Format("%s",lpszCurrentPassword);  int nStrLen=lpszTmpCurrentPassword.GetLength ();  int i=nStrLen;  while (i>0)  {  CString CharCode=lpszTmpCurrentPassword.Mid(i-1,1);  if (CharCode!=lpszCharSet.Right(1))  {int nIndex=lpszCharSet.Find(CharCode,0);  CharCode=lpszCharSet.Mid (nIndex+1,1);  if(i!=nStrLen)lpszTmpCurrentPassword.Format("%s%s%s",lpszTmpCurrentPassword.Left(i-1),CharCode,lpszTmpCurrentPassword.Right(nStrLen-i));  else  lpszTmpCurrentPassword.Format("%s%s",lpszTmpCurrentPassword.Left(i-1),CharCode);  WritePrivateProfileString(lpszMethod,"当前密码",(LPCTSTR)lpszTmpCurrentPassword,"Setup.ini");  lpszTmpCurrentPassword.Format ("%s",lpszCurrentPassword);  lstrcpy(lpszPassword,lpszTmpCurrentPassword,lpszTmpCurrentPassword.GetLength ()+1);     bSetOk=true;  break;  }      else      {CharCode=lpszCharSet.Left(1);  if(i!=nStrLen)lpszTmpCurrentPassword.Format("%s%s%s",lpszTmpCurrentPassword.Left(i-1),CharCode,lpszTmpCurrentPassword.Right(nStrLen-i));  else  lpszTmpCurrentPassword.Format("%s%s",lpszTmpCurrentPassword.Left(i-1),CharCode);      WritePrivateProfileString(lpszMethod,"当前密码",(LPCTSTR)lpszTmpCurrentPassword,"Setup.ini");          i--;      }  }  if(bSetOk)      {         return;      }  lpszTmpCurrentPassword.Insert(0,lpszCharSet.Left(1));  WritePrivateProfileString(lpszMethod,"当前密码",(LPCTSTR)lpszTmpCurrentPassword,"Setup.ini");  lpszTmpCurrentPassword.Format ("%s",lpszCurrentPassword);     lstrcpyn(lpszPassword,lpszTmpCurrentPassword,lpszTmpCurrentPassword.GetLength ()+1);        return;     }     void CGetCodeDlg::OnBrowse()  {CFileDialog m_FileOpen(TRUE,"*.txt","*.txt",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,NULL,NULL);  TCHAR lpBuffer[MAX_PATH];  LPTSTR *lpFilePart=NULL;  GetFullPathName(lpszPath,sizeof(lpBuffer),lpBuffer,lpFilePart);  m_FileOpen.m_ofn.lpstrInitialDir =lpBuffer;  m_FileOpen.DoModal();  m_EditPath.SetWindowText(m_FileOpen.GetPathName());     }     void CGetCodeDlg::OnRadio7()  {   m_EditPath.EnableWindow(TRUE);      m_BtnBrowser.EnableWindow(TRUE);      CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO7);  }     void CGetCodeDlg::OnRadio1()  {   m_EditPath.EnableWindow(FALSE);      m_BtnBrowser.EnableWindow(FALSE);      CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO1);  }     void CGetCodeDlg::OnRadio2()  {   m_EditPath.EnableWindow(FALSE);      m_BtnBrowser.EnableWindow(FALSE);      CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO2);  }     void CGetCodeDlg::OnRadio3()  {   m_EditPath.EnableWindow(FALSE);      m_BtnBrowser.EnableWindow(FALSE);      CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO3);  }     void CGetCodeDlg::OnRadio4()  {   m_EditPath.EnableWindow(FALSE);      m_BtnBrowser.EnableWindow(FALSE);      CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO4);  }     void CGetCodeDlg::OnRadio5()  {   m_EditPath.EnableWindow(FALSE);      m_BtnBrowser.EnableWindow(FALSE);      CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO5);  }     void CGetCodeDlg::OnRadio6()  {   m_EditPath.EnableWindow(FALSE);      m_BtnBrowser.EnableWindow(FALSE);      CheckRadioButton(IDC_RADIO1,IDC_RADIO7,IDC_RADIO6);  }