我被要求更新一些Excel 2003的宏,但是这些VBA项目都被密码保护了,并且似乎缺少文档...没有人知道密码。
有没有一种方法可以删除或破解VBA项目的密码?
我被要求更新一些Excel 2003的宏,但是这些VBA项目都被密码保护了,并且似乎缺少文档...没有人知道密码。
有没有一种方法可以删除或破解VBA项目的密码?
您可以尝试这种直接的VBA
方法,它不需要HEX编辑。它适用于任何文件(*.xls、*.xlsm、*.xlam ...)。
经过测试,以下版本可行:
Excel 2007
Excel 2010
Excel 2013 - 32位版本
Excel 2016 - 32位版本
寻找64位版本?请参见此答案
我将尽力解释它是如何工作的 - 请原谅我的英语。
请先备份您的文件!
创建一个新的xlsm文件,并将此代码存储在Module1中
代码由越南开发者Siwtom(昵称)提供
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项目并享受它。
.pptm
.ppam
文件也非常完美地工作。 - ant1j.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会报告错误(意外错误),然后当您访问VBA模块列表时,您现在将看到源模块的名称,但在尝试打开表单/代码等时会收到另一个错误。要解决此问题,请返回VBA项目属性,并将密码设置为新值。保存并重新打开Excel文档,您应该就可以继续使用了!
编辑:这是已被接受答案的更新版本,可适用于更多版本的 Office。虽然很困难,但让我们把这个答案排到最前面!
借用 kaybee99 出色的答案和 Đức Thanh Nguyễn 极好的答案,我要进行改进,以便此方法可用于 Office 的32/64位版本。
更改的概述,我们避免使用限制在32位地址上的 push/ret,并将其替换为 mov/jmp reg。
工作原理
打开包含锁定 VBA 项目的文件。
创建一个与上述文件类型相同的新文件,将此代码存储在 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
.xlsm
或.dotm
文件类型,你需要以稍微不同的方式来完成。
.xlsm
文件的扩展名更改为.zip
。vbaProject.bin
文件,并在十六进制编辑器中打开它(我使用 HxD,完全免费且轻巧)。DPB
并替换为DPx
,然后保存该文件。.xlsm
。.xlsm
文件。.zip
的步骤。在这种情况下,您只需右键单击 .xlsm
文件,然后选择 “7-Zip->打开归档文件” 。 - nkatsarColin Pickard在这个问题上给出了一个很好的答案,但是有一点需要注意。存在某些情况(我还没有找出原因),文件中“CMG=........GC=....”条目的总长度会因excel文件而异。在某些情况下,该条目的长度为137个字节,在其他情况下,它将是143个字节。137个字节长度是比较奇怪的,如果您使用“1234”密码创建文件时发生这种情况,请重新创建另一个文件,然后它应该会跳到143个字节的长度。
如果您尝试将错误数量的字节粘贴到文件中,则在尝试使用Excel打开文件时,您将失去VBA项目。
编辑
对于Excel 2007/2010文件无效。标准的.xlsx文件格式实际上是一个包含多个子文件夹的.zip文件,其中包含格式、布局、内容等存储为xml数据。对于未受保护的Excel 2007文件,您可以将.xlsx扩展名更改为.zip,然后打开zip文件并查看所有xml数据。这非常简单。
但是,当您使用RSA加密来保护Excel 2007文件时,整个.zip(.xlsx)文件都被加密。无法再将扩展名更改为.zip并浏览文件内容。
值得指出的是,如果你有一个Excel 2007 (xlsm)文件,那么你可以将其另存为Excel 2003 (xls)文件,然后使用其他答案中概述的方法。
1.
** 将 .xlsm 文件转换为 .xls 文件 2.
破解 .xls 文件的代码 3.
将 .xlsm 文件转换为 .xlsx 文件 4.
将模块中的代码从 .xls 复制到 .xlsx 文件中并将其另存为 .xlsm 文件。 - ZygDAccess、Excel、PowerPoint或Word文档的VBA项目密码(2007、2010、2013或2016
版本,扩展名为.ACCDB .XLSM .XLTM .DOCM .DOTM .POTM .PPSM
)可以被轻松地移除。
只需将文件扩展名更改为.ZIP
,解压文件,并使用任何基本的十六进制编辑器(如XVI32)“破解”现有密码,这会“困惑”Office,以便下一次打开文件时提示输入新密码。
.ZIP
扩展名。ZIP
并转到XL
文件夹。vbaProject.bin
并使用十六进制编辑器打开它。DPB
更改为DPX
。.bin
文件放回zip中,将其恢复为正常扩展名并像正常文件一样打开它。VBA项目属性
。保护
选项卡上,设置新密码。确定
,关闭文件,重新打开它,按ALT+F11。此时,如果需要,您可以完全删除密码。
完整说明和我创建的逐步视频(“很久以前”)在YouTube这里。请注意,所有HTML标签仍然保留。
令人震惊的是,这个解决方法已经存在多年,微软却没有修复这个问题。
微软Office VBA项目密码不应被视为任何敏感信息的安全保障。如果安全很重要,请使用第三方加密软件。
你尝试过在OpenOffice.org中打开它们吗?
我以前也遇到过类似的问题,发现Excel和Calc无法理解彼此的加密,因此可以直接访问几乎所有内容。
这是一段时间以前的事情,如果那不仅仅是我的偶然情况,那么它也可能已经修复了。