我被要求更新一些 Excel 2003 宏,但 VBA 项目受密码保护,而且似乎缺少文档……没有人知道密码。
有没有办法删除或破解 VBA 项目的密码?
您可以尝试这种VBA
不需要十六进制编辑的直接方法。它适用于任何文件(*.xls、*.xlsm、*.xlam ...)。
经过测试并适用于:
Excel 2007
Excel 2010
Excel 2013 - 32 位版本
Excel 2016 - 32 位版本
寻找 64 位版本?看到这个答案
我会尽力解释它是如何工作的——请原谅我的英语。
请先备份您的文件!
创建一个新的 xlsm 文件并将此代码存储在Module1中
code credited to Siwtom (nick name), a Vietnamese developer
Option Explicit
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Long, Source As Long, ByVal Length As Long)
Private Declare Function VirtualProtect Lib "kernel32" (lpAddress As Long, _
ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Private Declare Function GetModuleHandleA Lib "kernel32" (ByVal lpModuleName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, _
ByVal lpProcName As String) As Long
Private Declare Function DialogBoxParam Lib "user32" Alias "DialogBoxParamA" (ByVal hInstance As Long, _
ByVal pTemplateName As Long, ByVal hWndParent As Long, _
ByVal lpDialogFunc As Long, ByVal dwInitParam As Long) As Integer
Dim HookBytes(0 To 5) As Byte
Dim OriginBytes(0 To 5) As Byte
Dim pFunc As Long
Dim Flag As Boolean
Private Function GetPtr(ByVal Value As Long) As Long
GetPtr = Value
End Function
Public Sub RecoverBytes()
If Flag Then MoveMemory ByVal pFunc, ByVal VarPtr(OriginBytes(0)), 6
End Sub
Public Function Hook() As Boolean
Dim TmpBytes(0 To 5) As Byte
Dim p As Long
Dim OriginProtect As Long
Hook = False
pFunc = GetProcAddress(GetModuleHandleA("user32.dll"), "DialogBoxParamA")
If VirtualProtect(ByVal pFunc, 6, PAGE_EXECUTE_READWRITE, OriginProtect) <> 0 Then
MoveMemory ByVal VarPtr(TmpBytes(0)), ByVal pFunc, 6
If TmpBytes(0) <> &H68 Then
MoveMemory ByVal VarPtr(OriginBytes(0)), ByVal pFunc, 6
p = GetPtr(AddressOf MyDialogBoxParam)
HookBytes(0) = &H68
MoveMemory ByVal VarPtr(HookBytes(1)), ByVal VarPtr(p), 4
HookBytes(5) = &HC3
MoveMemory ByVal pFunc, ByVal VarPtr(HookBytes(0)), 6
Flag = True
Hook = True
End If
End If
End Function
Private Function MyDialogBoxParam(ByVal hInstance As Long, _
ByVal pTemplateName As Long, ByVal hWndParent As Long, _
ByVal lpDialogFunc As Long, ByVal dwInitParam As Long) As Integer
If pTemplateName = 4070 Then
MyDialogBoxParam = 1
Else
RecoverBytes
MyDialogBoxParam = DialogBoxParam(hInstance, pTemplateName, _
hWndParent, lpDialogFunc, dwInitParam)
Hook
End If
End Function
将此代码粘贴到Module1中的上述代码下并运行它
Sub unprotected()
If Hook Then
MsgBox "VBA Project is unprotected!", vbInformation, "*****"
End If
End Sub
回到您的 VBA 项目并享受。
是的,只要您使用.xls
格式电子表格(Excel 到 2003 年的默认设置)。对于 Excel 2007 及更高版本,默认值为.xlsx
,这是一种相当安全的格式,此方法将不起作用。
正如 Treb 所说,这是一个简单的比较。一种方法是使用十六进制编辑器简单地换出文件中的密码条目(请参阅Windows 的十六进制编辑器)。一步一步的例子:
复制以以下键开头的行:
CMG=....
DPB=...
GC=...
首先备份你不知道 VBA 密码的 excel 文件,然后用你的十六进制编辑器打开它,然后从虚拟文件中粘贴上面复制的行。
如果您需要使用 Excel 2007 或 2010,下面还有一些其他答案可能会有所帮助,尤其是这些:1、2、3。
2015 年 2 月编辑:对于另一种看起来非常有前途的方法,请查看 Đức Thanh Nguyễn 的这个新答案。
我建立在 Đức Thanh Nguyễn 的出色答案的基础上,以允许此方法与 64 位版本的 Excel 一起使用。我在 64 位 Windows 7 上运行 Excel 2010 64 位。
创建一个新的 xlsm 文件并将此代码存储在Module1中
Option Explicit
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare PtrSafe Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As LongPtr, Source As LongPtr, ByVal Length As LongPtr)
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" (lpAddress As LongPtr, _
ByVal dwSize As LongPtr, ByVal flNewProtect As LongPtr, lpflOldProtect As LongPtr) As LongPtr
Private Declare PtrSafe Function GetModuleHandleA Lib "kernel32" (ByVal lpModuleName As String) As LongPtr
Private Declare PtrSafe Function GetProcAddress Lib "kernel32" (ByVal hModule As LongPtr, _
ByVal lpProcName As String) As LongPtr
Private Declare PtrSafe Function DialogBoxParam Lib "user32" Alias "DialogBoxParamA" (ByVal hInstance As LongPtr, _
ByVal pTemplateName As LongPtr, ByVal hWndParent As LongPtr, _
ByVal lpDialogFunc As LongPtr, ByVal dwInitParam As LongPtr) As Integer
Dim HookBytes(0 To 5) As Byte
Dim OriginBytes(0 To 5) As Byte
Dim pFunc As LongPtr
Dim Flag As Boolean
Private Function GetPtr(ByVal Value As LongPtr) As LongPtr
GetPtr = Value
End Function
Public Sub RecoverBytes()
If Flag Then MoveMemory ByVal pFunc, ByVal VarPtr(OriginBytes(0)), 6
End Sub
Public Function Hook() As Boolean
Dim TmpBytes(0 To 5) As Byte
Dim p As LongPtr
Dim OriginProtect As LongPtr
Hook = False
pFunc = GetProcAddress(GetModuleHandleA("user32.dll"), "DialogBoxParamA")
If VirtualProtect(ByVal pFunc, 6, PAGE_EXECUTE_READWRITE, OriginProtect) <> 0 Then
MoveMemory ByVal VarPtr(TmpBytes(0)), ByVal pFunc, 6
If TmpBytes(0) <> &H68 Then
MoveMemory ByVal VarPtr(OriginBytes(0)), ByVal pFunc, 6
p = GetPtr(AddressOf MyDialogBoxParam)
HookBytes(0) = &H68
MoveMemory ByVal VarPtr(HookBytes(1)), ByVal VarPtr(p), 4
HookBytes(5) = &HC3
MoveMemory ByVal pFunc, ByVal VarPtr(HookBytes(0)), 6
Flag = True
Hook = True
End If
End If
End Function
Private Function MyDialogBoxParam(ByVal hInstance As LongPtr, _
ByVal pTemplateName As LongPtr, ByVal hWndParent As LongPtr, _
ByVal lpDialogFunc As LongPtr, ByVal dwInitParam As LongPtr) As Integer
If pTemplateName = 4070 Then
MyDialogBoxParam = 1
Else
RecoverBytes
MyDialogBoxParam = DialogBoxParam(hInstance, pTemplateName, _
hWndParent, lpDialogFunc, dwInitParam)
Hook
End If
End Function
将此代码粘贴到Module2并运行它
Sub unprotected()
If Hook Then
MsgBox "VBA Project is unprotected!", vbInformation, "*****"
End If
End Sub
免责声明这对我有用,我在这里记录了它,希望它能帮助别人。我还没有完全测试它。请确保在继续此选项之前保存所有打开的文件。
还有另一种(稍微简单的)解决方案,没有尺寸问题。我今天使用了这种方法(在 2003 XLS 文件上,使用 Excel 2007)并且成功了。
DPB=...
零件DPB=...
将字符串更改为DPx=...
*注意:请确保您已将密码更改为新值,否则下次打开电子表格时 Excel 会报错(Unexpected Error),然后当您访问 VBA 模块列表时,您现在将看到源模块,但在尝试打开表单/代码/等时收到另一个错误。要解决此问题,请返回 VBA 项目属性并将密码设置为新值。保存并重新打开 Excel 文档,您应该一切顺利!
对于 a .xlsm
or.dotm
文件类型,您需要以稍微不同的方式进行操作。
.xlsm
将文件的扩展名更改为.zip
.vbaProject.bin
文件并在十六进制编辑器中打开它(我使用HxD,它完全免费且轻量级。)DPB
并替换为DPx
并保存文件。vbaProject.bin
文件。.xlsm
..xlsm
文件。Colin Pickard 有一个很好的答案,但有一个“小心”。在某些情况下(我还没有弄清楚原因)文件中“CMG=........GC=....”条目的总长度与一个excel文件不同下一个。在某些情况下,此条目将是 137 字节,而在其他情况下,它将是 143 字节。137 字节长度是奇数,如果在使用“1234”密码创建文件时发生这种情况,只需创建另一个文件,它应该会跳转到 143 字节长度。
如果您尝试将错误的字节数粘贴到文件中,当您尝试使用 Excel 打开文件时,您将丢失 VBA 项目。
编辑
这对 Excel 2007/2010 文件无效。标准的 .xlsx 文件格式实际上是一个 .zip 文件,其中包含许多以 xml 数据形式存储的格式、布局、内容等子文件夹。对于未受保护的 Excel 2007 文件,您只需将 .xlsx 扩展名更改为 .zip,然后打开 zip 文件并查看所有 xml 数据。这很简单。
但是,当您使用密码保护 Excel 2007 文件时,整个 .zip (.xlsx) 文件实际上是使用 RSA 加密进行加密的。无法再将扩展名更改为 .zip 并浏览文件内容。
轮到我了,这是建立在 kaybee99 的出色答案之上的,该答案是建立在 Đức Thanh Nguyễn 的出色答案之上的,以允许此方法适用于 x86 和 amd64 版本的 Office。
更改的概述,我们避免了仅限于 32 位地址的 push/ret,并将其替换为 mov/jmp reg。
经过测试和工作
Word/Excel 2016 - 32 位版本。
Word/Excel 2016 - 64 位版本。
这个怎么运作
创建一个与上面相同类型的新文件并将此代码存储在Module1中
Option Explicit
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Declare PtrSafe Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As LongPtr, Source As LongPtr, ByVal Length As LongPtr)
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" (lpAddress As LongPtr, _
ByVal dwSize As LongPtr, ByVal flNewProtect As LongPtr, lpflOldProtect As LongPtr) As LongPtr
Private Declare PtrSafe Function GetModuleHandleA Lib "kernel32" (ByVal lpModuleName As String) As LongPtr
Private Declare PtrSafe Function GetProcAddress Lib "kernel32" (ByVal hModule As LongPtr, _
ByVal lpProcName As String) As LongPtr
Private Declare PtrSafe Function DialogBoxParam Lib "user32" Alias "DialogBoxParamA" (ByVal hInstance As LongPtr, _
ByVal pTemplateName As LongPtr, ByVal hWndParent As LongPtr, _
ByVal lpDialogFunc As LongPtr, ByVal dwInitParam As LongPtr) As Integer
Dim HookBytes(0 To 11) As Byte
Dim OriginBytes(0 To 11) As Byte
Dim pFunc As LongPtr
Dim Flag As Boolean
Private Function GetPtr(ByVal Value As LongPtr) As LongPtr
GetPtr = Value
End Function
Public Sub RecoverBytes()
If Flag Then MoveMemory ByVal pFunc, ByVal VarPtr(OriginBytes(0)), 12
End Sub
Public Function Hook() As Boolean
Dim TmpBytes(0 To 11) As Byte
Dim p As LongPtr, osi As Byte
Dim OriginProtect As LongPtr
Hook = False
#If Win64 Then
osi = 1
#Else
osi = 0
#End If
pFunc = GetProcAddress(GetModuleHandleA("user32.dll"), "DialogBoxParamA")
If VirtualProtect(ByVal pFunc, 12, PAGE_EXECUTE_READWRITE, OriginProtect) <> 0 Then
MoveMemory ByVal VarPtr(TmpBytes(0)), ByVal pFunc, osi+1
If TmpBytes(osi) <> &HB8 Then
MoveMemory ByVal VarPtr(OriginBytes(0)), ByVal pFunc, 12
p = GetPtr(AddressOf MyDialogBoxParam)
If osi Then HookBytes(0) = &H48
HookBytes(osi) = &HB8
osi = osi + 1
MoveMemory ByVal VarPtr(HookBytes(osi)), ByVal VarPtr(p), 4 * osi
HookBytes(osi + 4 * osi) = &HFF
HookBytes(osi + 4 * osi + 1) = &HE0
MoveMemory ByVal pFunc, ByVal VarPtr(HookBytes(0)), 12
Flag = True
Hook = True
End If
End If
End Function
Private Function MyDialogBoxParam(ByVal hInstance As LongPtr, _
ByVal pTemplateName As LongPtr, ByVal hWndParent As LongPtr, _
ByVal lpDialogFunc As LongPtr, ByVal dwInitParam As LongPtr) As Integer
If pTemplateName = 4070 Then
MyDialogBoxParam = 1
Else
RecoverBytes
MyDialogBoxParam = DialogBoxParam(hInstance, pTemplateName, _
hWndParent, lpDialogFunc, dwInitParam)
Hook
End If
End Function
将此代码粘贴到Module2并运行它
Sub unprotected()
If Hook Then
MsgBox "VBA Project is unprotected!", vbInformation, "*****"
End If
End Sub
值得指出的是,如果您有 Excel 2007 (xlsm) 文件,那么您可以简单地将其保存为 Excel 2003 (xls) 文件并使用其他答案中概述的方法。
您是否尝试过在 OpenOffice.org 中简单地打开它们?
前段时间我遇到了类似的问题,发现 Excel 和 Calc 不了解彼此的加密,因此允许直接访问几乎所有内容。
这是不久前的事情,所以如果这不仅仅是我的侥幸,它也可能已被修补。
如果
CMG="XXXX"\r\nDPB="XXXXX"\r\nGC="XXXXXX"
您的“已知密码”文件中的块比“未知密码”文件中的现有块短,请用尾随零填充十六进制字符串以达到正确的长度。
例如
CMG="xxxxxx"\r\nDPB="xxxxxxxx"\r\nGC="xxxxxxxxxx"
在未知密码文件中,应设置为
CMG="XXXX00"\r\nDPB="XXXXX000"\r\nGC="XXXXXX0000"
保留文件长度。
我也曾在 Office 2007 中使用 .XLA(97/2003 格式)文件。
Access、Excel、Powerpoint 或 Word 文档(2007, 2010, 2013 or 2016
带有扩展名的版本.ACCDB .XLSM .XLTM .DOCM .DOTM .POTM .PPSM
)上的 VBA 项目密码可以轻松删除。
只需将文件扩展名更改为.ZIP
,解压缩文件,并使用任何基本的十六进制编辑器(如XVI32)来“破解”现有密码,这会“混淆”Office,因此它会在下次文件时提示输入新密码打开。
.ZIP
扩展名。ZIP
并转到XL
文件夹。vbaProject.bin
并使用十六进制编辑器打开它DPB
为DPX
..bin
文件放回 zip 中,将其恢复为正常扩展名,然后像平常一样打开文件。VBA Project Properties
.Protection
选项卡上,设置新密码。OK
,关闭文件,重新打开,按 ALT+F11。此时,您可以选择完全删除密码。
完整的说明以及我在YouTube 上制作的“时光倒流”的分步视频。
令人震惊的是,这种解决方法已经存在多年,而微软还没有解决这个问题。
这个故事的主旨?
不应依赖Microsoft Office VBA Project 密码来保护任何敏感信息的安全。如果安全很重要,请使用第三方加密软件。
对于 Excel 2007 及更高版本,您需要将文件扩展名更改为 .zip 在存档中有一个子文件夹 xl,您将在其中找到 vbaProject.bin。使用 vbaProject.bin 执行上述步骤,然后将其保存回存档中。修改你的扩展,瞧!(意思是按照上面的步骤)
Colin Pickard 大部分是正确的,但不要将整个文件的“密码打开”保护与 VBA 密码保护混淆,这与前者完全不同,对于 Office 2003 和 2007 相同(对于 Office 2007,重命名将文件转换为 .zip 并在 zip 中查找 vbaProject.bin)。从技术上讲,编辑文件的正确方法是使用 OLE 复合文档查看器(如 CFX)打开正确的流。当然,如果您只是替换字节,普通的旧二进制编辑器可能会工作。
顺便说一句,如果您想知道这些字段的确切格式,他们现在已经记录在案:
http://msdn.microsoft.com/en-us/library/dd926151%28v=office.12%29.aspx
我尝试了上面的一些解决方案,但它们都不适合我(excel 2007 xlsm 文件)。然后我找到了另一种甚至可以检索密码的解决方案,而不仅仅是破解它。
将此代码插入模块,运行它并给它一些时间。它将通过蛮力恢复您的密码。
Sub PasswordBreaker()
'Breaks worksheet password protection.
Dim i As Integer, j As Integer, k As Integer
Dim l As Integer, m As Integer, n As Integer
Dim i1 As Integer, i2 As Integer, i3 As Integer
Dim i4 As Integer, i5 As Integer, i6 As Integer
On Error Resume Next
For i = 65 To 66: For j = 65 To 66: For k = 65 To 66
For l = 65 To 66: For m = 65 To 66: For i1 = 65 To 66
For i2 = 65 To 66: For i3 = 65 To 66: For i4 = 65 To 66
For i5 = 65 To 66: For i6 = 65 To 66: For n = 32 To 126
ActiveSheet.Unprotect Chr(i) & Chr(j) & Chr(k) & _
Chr(l) & Chr(m) & Chr(i1) & Chr(i2) & Chr(i3) & _
Chr(i4) & Chr(i5) & Chr(i6) & Chr(n)
If ActiveSheet.ProtectContents = False Then
MsgBox "One usable password is " & Chr(i) & Chr(j) & _
Chr(k) & Chr(l) & Chr(m) & Chr(i1) & Chr(i2) & _
Chr(i3) & Chr(i4) & Chr(i5) & Chr(i6) & Chr(n)
Exit Sub
End If
Next: Next: Next: Next: Next: Next
Next: Next: Next: Next: Next: Next
End Sub
如果该文件是一个有效的 zip 文件(前几个字节50 4B
- 以类似的格式使用.xlsm
),则解压缩文件并查找子文件xl/vbaProject.bin
。这是一个 CFB 文件,就像.xls
文件一样。按照 XLS 格式的说明(应用于子文件),然后压缩内容。
对于 XLS 格式,您可以按照本文中的其他一些方法进行操作。我个人更喜欢搜索DPB=
块并替换文本
CMG="..."
DPB="..."
GC="..."
有空格。这避免了 CFB 容器大小问题。
Tom - 我最初犯了一个小学生错误,因为我没有注意字节大小,而是从“CMG”设置复制并粘贴到后续条目。不过,这两个文件之间有两种不同的文本大小,正如 Stewbob 警告的那样,我丢失了 VBA 项目。
使用 HxD,有一个计数器跟踪您选择的文件数量。从 CMG 开始复制,直到计数器读数为 8F(十六进制表示 143),同样在粘贴到锁定文件时 - 我在粘贴结束时得到了两倍的“...”数量,不知何故看起来很奇怪,感觉几乎不自然,但它奏效了。
我不知道这是否至关重要,但我确保在 Excel 中重新打开文件之前关闭了十六进制编辑器和 excel。然后我必须通过菜单打开 VB 编辑器,进入 VBProject 属性并输入“新”密码来解锁代码。
我希望这有帮助。
只要文档是在 Office 2007 或更早版本中创建的, ElcomSoft生产的Advanced Office Password Breaker和Advanced Office Password Recovery产品可能适用于这种情况。
我的工具VbaDiff直接从文件中读取 VBA,因此您可以使用它从大多数办公文档中恢复受保护的 VBA 代码,而无需求助于十六进制编辑器。
接受的答案在 Windows 10 上的 Excel 2019 中不起作用。找出我们需要采取的额外步骤来查看锁定的宏。我正在总结步骤。
将 .zip 添加到 excel 文件名的末尾,然后按 Enter
将文件更改为 ZIP 文件后,双击打开它
在里面你会看到一个名为 xl 的文件夹,如下所示
在 xl 中,您会找到一个名为 vbaProject.bin 的文件,将其复制/粘贴到桌面上
转到在线十六进制编辑器 HexEd.it
搜索以下文本 DPB=... 并将其更改为 DPx=...
保存文件并关闭 HexEd.it
将更新后的文件从桌面复制/粘贴到 ZIP 文件中(您需要覆盖它)
从文件名末尾删除 .zip 扩展名并再次添加 excel 扩展名。
在 excel 中打开文件 - 您可能会收到一些错误通知,只需单击它们即可。
==== 接受答案的额外步骤 =====
- 打开 Visual Basic 窗口(如果我没记错的话通常是 ALT+F11)并打开 VBAProject 属性(工具菜单)。
- 单击“保护”选项卡并将密码更改(在此阶段不要删除)简短易记的密码(我们将在下一步中删除)。
- 保存工作簿,然后关闭并重新打开。
- 再次打开 Visual Basic 窗口并输入您刚刚输入的密码。重做上一步,但这次您可以删除(删除)密码。
- 保存工作簿,您现在已经删除了密码。
额外步骤来自以下站点 https://confluence.jaytaala.com/display/TKB/Remove+Excel+VBA+password
保护是 Excel 中的简单文本比较。在您最喜欢的调试器中加载 Excel(Ollydbg是我选择的工具),找到进行比较的代码并将其修复为始终返回 true,这应该可以让您访问宏。
对于 Windows 10 机器上的 Excel 2016 64 位,我使用了一个十六进制编辑器来更改受保护的 xla 的密码(尚未针对任何其他扩展进行测试)。 提示:在执行此操作之前创建一个备份。
我采取的步骤:
我希望这对你们中的一些人有所帮助!
事实上,大多数启用宏的 Office 文档的代码文件都没有加密,密码只会阻止使用 Office 程序打开项目。这意味着,正如其他答案所建议的那样,您通常可以使用 Office 替代方法来访问和编辑文件。
但是,如果您只需要访问代码,则可以使用oledump.py之类的工具来提取宏代码。这对于恶意软件分析以及从文件中获取大部分代码很有用,这样您就不必在忘记密码时从头开始。
此外,许多excel文件在打开文件时会动态设置密码。这意味着如果您可以阅读代码,通常可以找到明文密码或对其进行去混淆处理。
oledump.py
例子:python oledump.py -v yourExcelFile.xlsm
输出:
A: xl/vbaProject.bin
A1: 2000 'PROJECT'
A2: 1500 'PROJECTwm'
A3: M 1224 'VBA/Module1'
A4: M 18694 'VBA/Module2'
A5: M 11877 'VBA/Module3'
...
M
旁边的流是宏,它是未加密的 VBA 代码
python oledump.py -s A3 -v yourExcelFile.xlsm > Module1.vba
这会将A3
流中包含的代码输出到Module1.vba
.
我通常将它与循环结合起来,将所有文件提取到一个文件夹中。这个快速的 PowerShell 脚本将提取大多数文件中的所有流:
New-Item -ItemType Directory "Output"
# just hardcode the highest stream outputted by oledump.py -v
$max = 5
for ($i = 1; $i -le $max; $i++) {
python oledump.py -s "A$i" -v yourExcelFile.xlsm > ".\Output\A$i"
}
请注意,这只会提取人类可读的文件。
您的 excel 文件的扩展名更改为 xml。并在记事本中打开。在 xml 文件中查找密码文本。
你看到像下面的线;
Sheets("Sheet1").Unprotect Password:="blabla"
(对不起,我的英语不好)
如果你在工作,Java
你可以试试VBAMacroExtractor
。从中提取 VBA 脚本后,.xlsm
我发现那里有明文密码。