|
摘要:本文讨论了如何使用VB编程,通过穷举法解除EXCEL文档和WORD文档的密码。并在破解过程中加入了中断,以方便用户随时中断破解过程。
关键字:穷举法、解密、EXCEL文档、WORD文档、密码
Excel和Word提供了多种方法限制访问用户文档,以免未经授权者的查看和更改。但在信息化的今天,用户需要记忆的密码太多,一旦密码丢失,用户将无法打开或访问该文档,给用户造成很大的损失。能否借助计算机的高速运行,解开密码呢?通过尝试,笔者认为:在无法弄清Excel和Word加密算法的情况下,利用穷举法尝试解密文档,是解密唯一的选择。
1. 实现原理 本程序选用VB6.0编写,并充分利用了Office组件中的对象库,穷举尝试各种口令,达到解密文档的目的。 ⑴ 巧用整数的取整及取余,产生密码字符串 Excel和Word文档密码可以是字母、数字、空格以及符号的任意组合,最长可达 15 个字符,且区分大小写。 本程序的破解过程利用一个两层循环,产生选定字符的排列组合(尝试密码),其中外层循环控制密码的位数,内层循环生成N位密码的所有排列组合。产生尝试密码的方法是:将一个N位字符串密码(password)作为一个“数值”,该“数值”每个位上的“数字”属于选定字符范围,且该“数值”与一个整数(X)一一对应,并满足以下条件: 0 ≤X ≤ArrayLenN-1(ArrayLen是选定密码字符范围的总字符数,如:仅选定数字时,ArrayLen=10;仅选定数字和小写字母时,ArrayLen=10+26=36);对X整除、取余N-1次,对每次的余数Y做以下操作:password = password + CharArray(Y) (注:CharArray是存放选定字符的一维数组),最后做以下操作:password = CharArray(X MOD ArrayLen) + password,产生的password 就是整数X对应的N位字符串。 ⑵ 利用VB的错误处理功能,尝试口令破解 当运行程序尝试一个密码时(用该密码打开文档),若密码错误,则会产生运行错误。为此,必须在尝试口令前,使用On Error 语句打开一个错误处理程序;由于本程序是尝试各种口令,当一个口令错误时,直接尝试下一个口令即可,因此,应使用 “On Error Resume Next”语句。 那么,如何得知找到口令了呢? VB有一个内部错误对象Err,它的 Number 属性中的值是用来确定发生错误的原因。在尝试一个口令后,检查Err.Number中的值,以确定该口令是否正确。 ⑶ 破解过程中的中断 利用穷举法解密对系统资源的占用是十分惊人的,在解密的过程中CPU的利用率几乎是100%,若不加入解密过程中的中断,计算机系统会处于一种假死机状态。为此,在破解过程的内循环中加入了DoEvents函数。DoEvents函数提供了一种取消任务的简便方法,它将控制切换到操作环境内核。只要此环境中的所有应用程序都有机会响应待处理事件,应用程序就又恢复控制。使用该函数的优点是:不会使应用程序放弃焦点,且后台事件能够得到有效处理。 2. 具体实现过程 编程实现时,需要机器安装有VB应用程序及Microsoft Office组件。 ⑴ 新建VB工程,并对其初始化 新建一个VB工程,取名Get_Password,将启动窗体命名为FrmMain。首先选择“工程”菜单中的“引用”,在“引用”对话框中选择“Microsoft Excel10.0 Object Library”和“Microsoft Word10.0 Object Library”(注意:如果安装的是Office2000或Office97,应该选择Excel对象库和Word对象库的9.0版或8.0版)。其次在“工程”菜单中“部件”对话框中,选择添加“Microsoft Windows common controls -2.5(sp2)”和“Microsoft Common Dialog control 6.0”,以便在窗体设计中使用微调控件和对话框控件。 ⑵ 在FrmMain窗体上添加控件 在FrmMain窗体上,按照下图的位置添加表1中的控件,然后根据表1修改每个对象的属性。 表1: 序号 控件名称 控件属性及其属性值 1 Frame Name=Frame1,Caption=选择加密文件(*.DOC、*.XLS) 2 Frame Name=Frame2,Caption=选定密码字符范围: 3 Frame Name=Frame3,Caption=选择密码的长度: 4 ComboBow Name=Combo1 5 CommandButton Name=CmdBrowse,Caption=浏览 6 CommandButton Name=CmdStartCrack,Caption=开始破解 7 CommandButton Name=CmdQuit,Caption=退出系统 8 CheckBox Name=ChkDigital,Caption=数字(10) 9 CheckBox Name=ChkLowercase,Caption=小写字母(26) 10 CheckBox Name=ChkUppercase,Caption=大写字母(26) 11 CheckBox Name=ChkSpace,Caption=空格(1) 12 CheckBox Name=ChkBracket,Caption=括号(6) 13 CheckBox Name=ChkOthers,Caption=其他OEM字符(26) 14 TextBox Name=txtPasswordStartLong, Text=2 15 TextBox Name=txtPasswordEndLong,Text=2 16 TextBox Name=Text1 17 UpDown Name=UpDown1,BuddyProperty=Text,Wrap=TRUE,Increment=1 BuddyControl=txtPasswordStartLong,Max=15,Min= 18 UpDown Name=UpDown2,BuddyProperty=Text,Wrap=TRUE,Increment=1 BuddyControl=txtPasswordEndLong,Max=15,Min=1 19 CommonDialog Name=Dialog,DialogTitle=请选择加密的Excel或Word文档 Filter=Excel(*.xls),Word(*.doc)|*.xls;*.doc 20 Label Name=Label1, Caption=破解进度: 21 Label Name=Label3,Caption=从: 22 Label Name=Label5,Caption=到:
⑶ 为以上对象编写下列代码 为了便于理解,程序中增加了适当的注释。 Option Explicit Private Sub CmdBrowse_Click() Dialog.ShowOpen 'show the dialog Combo1.Text = Dialog.FileName 'set the Filename text box to the selected file Combo1.Refresh End Sub
Private Sub CmdQuit_Click() End End Sub
Private Sub CmdStartCrack_Click() Static blnProcessing As Boolean Dim wd As New Word.Application, xls As New Excel.Application Dim OpenReturn Dim strpath, pass, StrTemp, all_char(100) As String Dim J, K, Password_Start_Long, Password_End_Long, ArrayLen As Integer Dim I, Temp As Long ArrayLen = 0 '数组初始化 If ChkDigital.Value = 1 Then For J = ArrayLen To ArrayLen + 9 all_char(J) = Chr(Asc("0") + J - ArrayLen) Next J ArrayLen = ArrayLen + 10 End If If ChkLowercase.Value = 1 Then For J = ArrayLen To ArrayLen + 25 all_char(J) = Chr(Asc("a") + J - ArrayLen) Next J ArrayLen = ArrayLen + 26 End If If ChkUppercase.Value = 1 Then For J = ArrayLen To ArrayLen + 25 all_char(J) = Chr(Asc("A") + J - ArrayLen) Next J ArrayLen = ArrayLen + 26 End If If ChkSpace.Value = 1 Then all_char(ArrayLen) = " " ArrayLen = ArrayLen + 1 End If If ChkBracket.Value = 1 Then all_char(ArrayLen) = "(" all_char(ArrayLen+1) = ")" all_char(ArrayLen+2) = "{" all_char(ArrayLen+3) = "}" all_char(ArrayLen+4) = "[" all_char(ArrayLen+5) = "]" ArrayLen = ArrayLen + 6 End If If ChkOthers.Value = 1 Then For J = ArrayLen To ArrayLen + 6 '33 to 39 all_char(J) = Chr(33 + J - ArrayLen) Next ArrayLen = ArrayLen + 7 For J = ArrayLen To ArrayLen + 5 '42 to 47 all_char(J) = Chr(42 + J - ArrayLen) Next J ArrayLen = ArrayLen + 6 For J = ArrayLen To ArrayLen + 6 '58 to 64 all_char(J) = Chr(58 + J - ArrayLen) Next J ArrayLen = ArrayLen + 7 all_char(ArrayLen) = Chr(92) ArrayLen = ArrayLen + 1 For J = ArrayLen To ArrayLen + 2 '94 to 96 all_char(J) = Chr(94 + J - ArrayLen) Next J ArrayLen = ArrayLen + 3 all_char(ArrayLen) = Chr(124) all_char(ArrayLen+1) = Chr(126) ArrayLen = ArrayLen + 2 End If If ArrayLen = 0 Then MsgBox "错误:没有选择'密码使用的字符'", , "请选择密码使用的字符范围..." Exit Sub End If If blnProcessing Then If MsgBox("真的要中断解密过程吗?", vbYesNo, "用户中断任务") = vbYes Then blnProcessing = False Else CmdStartCrack.Caption = "中断破解" blnProcessing = True strpath = Combo1.Text If strpath = "" Then MsgBox "错误:没有选择'需要解密的文件'", , "请选择需要解密的文件..." Exit Sub End If strpath = Trim(strpath) Password_Start_Long = Val(txtPasswordStartLong.Text) Password_End_Long = Val(txtPasswordEndLong.Text) If Password_Start_Long > Password_End_Long Then Password_Start_Long = Val(txtPasswordEndLong.Text) Password_End_Long = Val(txtPasswordStartLong.Text) End If Label1.Caption = "破解进度:" Label1.Refresh On Error Resume Next If UCase(Right(strpath, 3)) = "XLS" Then For K = Password_Start_Long To Password_End_Long '破解excel开始 For I = 0 To ArrayLen ^ K - 1 pass = "" Temp = I For J = 1 To K - 1 Temp = Temp \ ArrayLe pass = all_char(Temp Mod ArrayLen) + pass Next J pass = pass + all_char(I Mod ArrayLen) Set OpenReturn = xls.Workbooks.Open(FileName:=strpath, Password:=pass) Text1.Text = pass '显示破解进度 Text1.Refresh If Err.Number <> 0 Then '如果解密成功,打开文档,显示密码,退出过程 Err.Clear Else Label1.Caption = "文档密码:" Text1.Text = pass Me.Refresh xls.Visible = True CmdStartCrack.MousePointer = 0 CmdStartCrack.Caption = "开始破解" blnProcessing = False Set xls = Nothing Exit Sub End If DoEvents If Not blnProcessing Then Exit For Next I If Not blnProcessing Then Exit For Next K xls.Quit Set xls = Nothing Else For K = Password_Start_Long To Password_End_Long '破解word开始 For I = 0 To ArrayLen ^ K - 1 pass = "" Temp = I For J = 1 To K - Temp = Temp \ ArrayLen pass = all_char(Temp Mod ArrayLen) + pass Next J pass = pass + all_char(I Mod ArrayLen) OpenReturn = wd.Documents.Open(FileName:=strpath, passworddocument:=pass) Text1.Text = pass '显示破解进度 Text1.Refresh If Err.Number <> 0 Then '如果解密成功,打开文档,显示密码,退出过程 Err.Clear Else 'MsgBox "word password" Label1.Caption = "文档密码:" Text1.Text = pass Me.Refresh wd.Visible = True CmdStartCrack.MousePointer = 0 CmdStartCrack.Caption = "开始破解" blnProcessing = False Set wd = Nothing Exit Sub End If DoEvents If Not blnProcessing Then Exit For Next I If Not blnProcessing Then Exit For Next K wd.Quit Set wd = Nothing End If CmdStartCrack.Caption = "开始破解" If blnProcessing Then MsgBox "没有找到密码,可能是密码位数不对!", , "提示信息..." blnProcessing = False End Sub 3. 时间复杂度分析 一个算法的时间复杂度,是指该算法的时间耗费,是该算法所求解问题规模n的函数。根据前面讲的实现原理,我们知道,破解算法的时间耗费主要集中在尝试打开OFFICE文档上,因此,当我们假设破解一个N位字符串密码,且选定密码字符范围的总字符数为ArrayLen时,该算法的时间复杂度是O(ArrayLen^N)。即,当N确定后,该算法的时间复杂度是N次方阶;当ArrayLen确定后,该算法的时间复杂度是指数阶。都是高数量级的时间复杂度。 4. 说明 穷举法解密对系统资源的占用是十分惊人的,在解密的过程中最好不要运行其他应用程序。如果安装有瑞星等杀毒软件,应将杀毒软件的“office安全助手”去掉,以便加快程序的运行速度。 该程序在WinXP+OfficeXP+VB6.0环境下测试通过,笔者随便测试了一个5位数字密码,在P4机器上,8分钟左右即可解开口令。
参考文献: [1] 王建华 译. Visual Basic 6 开发人员指南. 北京:机械工业出版社,1999
友情提示:按住Ctrl+D可以直接将本文加入收藏夹,方便下次访问。
|