`

用vc++穷举windows应用程序密码(上)

阅读更多
<meta content="MSHTML 6.00.2900.3199" name="GENERATOR"> <style></style>2007年10月12日 02:14:00

一、引言

随着计算机信息技术的发展,人们越来越重视信息的安全性,信息数据的安全保密已经成为影响计算机发展的一个重要课题。机密文件、商业情报、银行账号、网络密码、科技成果、包括私人信件等等,都成了用户为难以存放发愁的心病。密码可以说是他们的唯一的精神寄托,通过密码,他们可以对这些信息进行加密,或者通过密码对用户存取信息进行授权,非法用户禁止存取有关信息。

但是有了密码,用户也不能高枕无忧,因为密码都是人工键入的,都是由键盘的可见字符组成(包括汉字),如果一个非法用户不幸猜中了你的密码,哪怕只有千万分之一的几率,也会给你的数据安全带来潜在威胁,而不光会污染你的数据,丧心病狂的人甚至会在瞬间摧毁你苦心经营多年的成果。更何况现在有了电脑作为工具,它可以在一分钟之间穷举成千上万个密码,利用局域网分布式计算,一个小时内穷举十位以下的所有密码,更不幸的是我们的用户所用的密码都是出奇的易记(击),他们偏好单用数字和字母,这为他们数据安全埋下了危机。

本文正是通过引用一个穷举密码的例子来提醒用户,在密码问题上不要大意,密码要求尽可能长,而且不要鄙视非数字和非字母字符,密码要定期更换。动态密码,相对更为安全。

二、实现原理:

我们的用户一般都过输入密码的经历,一般情况下系统都会显示一个对话框,提醒用户输入密码,密码编辑框一般具有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_bAutoDeletetrue ,表示线程终止后自动销毁。

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

指定一个传递给EnumWindowsEnumDesktopWindows的应用程序定义参数值。

返回值:

若应用程序想持续枚举窗口,必须返回true。返回false停止枚举。

注释:

这个回调函数可以执行任何渴望的任务,应用程序必须通过传递函数地址给 EnumWindowsEnumDesktopWindows注册回调函数。

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来注册回调函数。

· 密码枚举

我们知道组成密码的字符由许多种,有人喜欢单用数字,有人喜欢单用字母(包括大小写),也有的是用一些诸如!·#“等符号,我们可以分情况区别对待。密码的长短也是一个制约穷举的一个重要因素,密码长度越长,密码的排列组合种类越多,穷举时间越长。

我们把所有的密码字符都看成字符串,把字符组成集合视为密码字符集。如{0123456789}{ABCDEFGHIJKLMNOPQRSTUVWXYZ}等都称之为密码字符集。每一个密码每一位都由这些字符集的任意一个字符组成。若字符集中有N个元素,则长度为M的密码根据排列组合共有NM次方种排法。我们只要将密码字符集的各个要素逐次地放入密码的各个位置,就能穷举长度为M的密码。而长度M可以从1开始自动增长。就像密码开始从 0穷举到9,长度变化为 2,密码在从00穷举到99一样,我们只需变换密码字符集即可变换密码的组成元素。给出密码的算法都一样。每得出一个密码,我们都可以将其存入文件,下次枚举时可以通过这个密码推算下一个密码,如上一个密码为ZZ,则下一个密码应为AAA,再下一个为AAB AAZABA..ABZAZZBAA…依次类推。一直推算到ZZZ,接着又是AAAA。有点类似于十进制、二十六进制、五十二进制,只不过这里是各位数不是数字而是字符,字符来自我们自己定义的密码字符集。组成的密码不是数字,而是字符串。

程序还采用了字典穷举法,密码字典采用纯文本文件(.txt,该文件可以用edit notepadultraedit建立,每一个密码之间采用回车符和换行符间隔。程序穷举时会自动保存文件读写指针和当前穷举密码。

穷举密码时程序会自动保存穷举进度,以便下次穷举时不用从头开始。通过修改配置文件setup.ini, 我们很容易实现控制穷举进度,也可以实现多人穷举时的任务分工。

下面是一个穷举电子图板文件密码的setup.ini例子

[设置]

口令输入窗口标题=输入文件密码

口令输入窗口确认按钮标题=确定

提示口令错要求重新输入窗口标题=Eb

提示口令错要求重新输入窗口确认按钮标题=确定

穷举方法=大写字母

线程计数=5

穷举文件=C:\TOOLS\部门.txt

[C:\TOOLS\部门.txt]

文件指针=171

当前穷举密码=AB

[大写字母]

当前密码=AC =〉将密码改成AAAA开始穷举四位密码,当然你也可以改为BAAACAAADAAA等等。

程序对密码限制不超过 30 位。

四、程序代码

1.资源文件 GETCODE.RC

<shapetype id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:spt="75" coordsize="21600,21600" stroked="f" filled="f" o:preferrelative="t"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 279pt; HEIGHT: 205.5pt" type="#_x0000_t75"><imagedata o:title="" src="file:///F:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.png"></imagedata></shape>

//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



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1821048


分享到:
评论

相关推荐

    用vc++穷举windows应用程序密码

    用vc++穷举windows应用程序密码

    穷举法破解路由器密码的软件

    穷举法破解路由器密码的软件 常见的TPlink dlink之类的路由器密码 需挂字典穷举破解

    vc中用穷举法来破解密码的原理

    穷举法是破解密码的一种方法,即通过编程,利用 Windows API 函数 EnumWindows 和 EnumChildWindows 遍历当前运行的所有程序的所有窗口,通过窗口标题查找密码输入和出错确认重新输入窗口,通过按钮标题查找我们应该...

    用穷举法设计程序教学设计说明.doc

    《用穷举法设计程序》的教学设计旨在帮助学生理解和掌握穷举法这一基本的算法思想,以及如何利用穷举法来设计程序解决实际问题。在高中信息技术(选修1)的《算法与程序设计》课程中,这是一节重要的内容,通常需要...

    用穷举法设计程序教学设计.doc

    - 情感态度与价值观:培养逻辑思维能力和算法优化意识,了解穷举法在现实应用中的价值,如密码破解,同时强调信息安全意识。 6. **教材分析**: - 穷举算法的核心在于全面无遗漏地检查所有可能情况,教材中强调了...

    穷举的应用 希望大家喜欢

    3. 广度优先搜索(BFS)和深度优先搜索(DFS):在图和树结构中应用广泛,DFS通常用于深度优先穷举,BFS用于宽度优先穷举。 五、注意事项 尽管穷举在某些情况下是有效的,但其效率往往较低,可能导致时间超限或资源...

    穷举法C/C++程序

    在编程领域,穷举法是一种常见的解决问题的策略,尤其在C和C++这两种语言中,开发者经常使用这种方法来实现特定的算法。穷举法,也称为全搜索或枚举,是指在解决一个问题时,尝试所有可能的情况,直到找到正确答案。...

    模拟密码破解 6为以内 穷举法 破解

    密码破解 穷举破解 6为以内字母、数字等 破解

    穷举密码算法

    通过穷举所有可能的字符组合来寻找目标密码,或者生成一个包含大量可能密码的字典文件供后续使用。 #### 三、穷举密码算法实现原理 在给定代码示例中,穷举密码算法的核心是生成指定长度范围内的所有可能密码组合...

    在vb.net里,怎么实现使用暴力穷举算法通过自动化脚本来实现在其他程序中输入密码(1).txt

    #### 知识点三:在Windows窗体应用程序中集成暴力穷举算法 如果希望将暴力穷举算法集成到一个用户界面中,可以在VB.NET中创建一个Windows窗体应用程序。该应用程序可以包括几个按钮和文本框,以便用户能够控制暴力...

    算法与程序设计:第2章 穷举法与迭代法.ppt

    算法与程序设计:穷举法与迭代法 本章节主要介绍了穷举法和迭代法这两种基本的算法设计方法。穷举法是一种简单、基础的算法,它的特点是穷举所有可能的候选区间,找出...4. 穷举法和迭代法在程序设计中的应用非常重要

    应用密码学:协议、算法与C源程序

    《应用密码学:协议、算法与C源程序》是一本深入探讨密码学理论与实践的著作,涵盖了密码学的基础知识、重要协议以及实用的加密算法,并提供了C语言实现的源代码,为读者提供了理论与实践相结合的学习体验。密码学是...

    SADirRead 穷举目录 穷举文件

    开发者也可以通过调用SADirRead的API,集成到自己的应用程序中,实现文件和目录的遍历功能。 总的来说,SADirRead是一个利用C++和Visual C++编写的,用于遍历Windows文件系统目录的实用工具。它通过递归遍历目录...

    穷举法入门

    对于初学者,使用VC++6.0这样的IDE进行实践,可以帮助更好地理解和运用穷举法。通过编写和运行"myEasyCM"和"Exhaustive"这样的程序,可以直观地感受穷举法的工作过程,并从中学习如何解决实际问题。

    穷举密码组合

    穷举用指定字符生成指定位数的所有密码组合,穷举用户名等。

    sql server密码穷举查看器

    可运行在win环境中,预设字母和数字及符号后,通过穷举来测试sql server的连接密码,本人亲测,6位的纯数字密码大约用了3小时被穷举成功

    一个vb穷举密码的算法

    自己写的一个密码穷举,递归调用,代码非常简单,但大家都应该知道,凡是递归都是低效率的,而居然是穷举,也就不必要去讨论效率了!虽然很简单,但没想到这个方法的,要解决这个问题还是比较难的,希望对大家有用。

    S7-200 SMART200 项目密码 POU子程序块密码 4种解密软件

    (注意,是解电脑上程序加密。不是去连PLC上传解密) SMART200电脑上程序.smart 文件 S7-200电脑上程序mwp文件 第1 S7-200 POU子程序块密码解密 第2 S7-200 项目密码解密 第3 SMART200 POU子程序块密码解密 第4 ...

    密码穷举算法

    在许多情况下我们需要穷举组合的算法,比如密码词典。 这个算法的关键是密码下标进位的问题。 另外本例子中的写文件语句效率比较低,为了降低算法复杂度没有优化。 如果要提高写文件的效率,可以使用缓冲区,分批...

    matlab程序(穷举法).rar_matlab_枚举法_穷举法 matlab_穷举法MATLAB_穷举算法 tsp

    MATLAB优化算法案例分析与应用(进阶篇)1-10章程序下载

Global site tag (gtag.js) - Google Analytics