摘要:本文讨论了如何使用 VB 编程,通过穷举法解除 EXCEL 文档和 WORD 文档的密码。并在破解过程中加入了中断,以方便用户随时中断破解过程。
关键字:穷举法、解密、 EXCEL 文档、 WORD 文档、密码
Excel 和 Word 提供了多种 方法限制访问用户文档,以免未经授权者的查看和更改。但在信息化的今天,用户需要记忆的密码太多,一旦密码丢失,用户将无法打开或访问该文档,给用户造成很大的损失。能否借助计算 机的高速运行,解开密码呢?通过尝试,笔者认为:在无法弄清 Excel 和 Word 加密算法的情况下,利用穷举法尝试解密文档,是解密唯一的选择。
- 实现原理
本程序选用 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 函数提供了一种取消任务的简便方法,它将控制切换到操作环境内核。只要此环境中的所有 应用 程序都有机会响应待处理事件, 应用 程序就又恢复控制。使用该函数的优点是:不会使应用程序放弃焦点,且后台事件能够得到有效处理。 - 具体实现过程
编程实现时,需要机器安装有 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 The n
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 The n
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 安全助手 ” 去掉,以便加快程序的运行速度。