有没有办法破解 Excel VBA 项目的密码?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1026483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a way to crack the password on an Excel VBA Project?
提问by Jonathan Sayce
I've been asked to update some Excel 2003 macros, but the VBA projects are password protected, and it seems there's a lack of documentation... no-one knows the passwords.
我被要求更新一些 Excel 2003 宏,但 VBA 项目受密码保护,而且似乎缺少文档......没有人知道密码。
Is there a way of removing or cracking the password on a VBA project?
有没有办法删除或破解 VBA 项目的密码?
回答by ??c Thanh Nguy?n
You can try this direct VBAapproach which doesn't require HEX editing. It will work for any files (*.xls, *.xlsm, *.xlam ...).
您可以尝试这种VBA不需要 HEX 编辑的直接方法。它适用于任何文件(*.xls、*.xlsm、*.xlam ...)。
Tested and works on:
经过测试并适用于:
Excel 2007
Excel 2010
Excel 2013 - 32 bit version
Excel 2016 - 32 bit version
Excel 2007
Excel 2010
Excel 2013 - 32 位版本
Excel 2016 - 32 位版本
Looking for 64 bit version? See this answer
寻找 64 位版本?看到这个答案
How it works
这个怎么运作
I will try my best to explain how it works - please excuse my English.
我会尽力解释它是如何工作的 - 请原谅我的英语。
- The VBE will call a system function to create the password dialog box.
- If user enters the right password and click OK, this function returns 1. If user enters the wrong password or click Cancel, this function returns 0.
- After the dialog box is closed, the VBE checks the returned value of the system function
- if this value is 1, the VBE will "think" that the password is right, hence the locked VBA project will be opened.
- The code below swaps the memory of the original function used to display the password dialog with a user defined function that will always return 1 when being called.
- VBE 将调用一个系统函数来创建密码对话框。
- 如果用户输入正确的密码并单击“确定”,则该函数返回 1。如果用户输入错误的密码或单击“取消”,则该函数返回 0。
- 对话框关闭后,VBE检查系统函数的返回值
- 如果此值为 1,则 VBE 将“认为”密码正确,因此将打开锁定的 VBA 项目。
- 下面的代码将用于显示密码对话框的原始函数的内存与用户定义的函数交换,该函数在调用时将始终返回 1。
Using the code
使用代码
Please backup your files first!
请先备份您的文件!
- Open the file(s) that contain your locked VBA Projects
Create a new xlsm file and store this code in Module1
code credited to Siwtom (nick name), a Vietnamese developerOption 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 FunctionPaste this code under the above code in Module1and run it
Sub unprotected() If Hook Then MsgBox "VBA Project is unprotected!", vbInformation, "*****" End If End SubCome back to your VBA Projects and enjoy.
- 打开包含锁定的 VBA 项目的文件
创建一个新的 xlsm 文件并将此代码存储在Module1 中
code credited to Siwtom (nick name), a Vietnamese developerOption 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 项目并享受。
回答by Colin Pickard
Yes there is, as long as you are using a .xlsformat spreadsheet (the default for Excel up to 2003). For Excel 2007 onwards, the default is .xlsx, which is a fairly secure format, and this method will not work.
是的,只要您使用.xls格式电子表格(Excel 2003 之前的默认设置)。对于 Excel 2007 以后的版本,默认为.xlsx,这是一种相当安全的格式,此方法无效。
As Treb says, it's a simple comparison. One method is to simply swap out the password entry in the file using a hex editor (see Hex editors for Windows). Step by step example:
正如 Treb 所说,这是一个简单的比较。一种方法是使用十六进制编辑器简单地换出文件中的密码条目(请参阅Windows 的十六进制编辑器)。分步示例:
- Create a new simple excel file.
- In the VBA part, set a simple password (say - 1234).
- Save the file and exit. Then check the file size - see Stewbob's gotcha
- Open the file you just created with a hex editor.
Copy the lines starting with the following keys:
CMG=.... DPB=... GC=...FIRST BACKUPthe excel file you don't know the VBA password for, then open it with your hex editor, and paste the above copied lines from the dummy file.
- Save the excel file and exit.
- Now, open the excel file you need to see the VBA code in. The password for the VBA code will simply be 1234 (as in the example I'm showing here).
- 新建一个简单的excel文件。
- 在 VBA 部分,设置一个简单的密码(比如 - 1234)。
- 保存文件并退出。然后检查文件大小 - 请参阅Stewbob's gotcha
- 使用十六进制编辑器打开您刚刚创建的文件。
复制以以下键开头的行:
CMG=.... DPB=... GC=...首先备份你不知道 VBA 密码的 excel 文件,然后用你的十六进制编辑器打开它,并粘贴上面从虚拟文件中复制的行。
- 保存excel文件并退出。
- 现在,打开您需要查看 VBA 代码的 excel 文件。 VBA 代码的密码仅为 1234(如我在此处展示的示例)。
If you need to work with Excel 2007 or 2010, there are some other answers below which might help, particularly these: 1, 2, 3.
如果您需要使用 Excel 2007 或 2010,下面还有一些其他答案可能会有所帮助,尤其是这些:1, 2, 3。
EDITFeb 2015: for another method that looks very promising, look at this new answerby ??c Thanh Nguy?n.
编辑2015 年 2 月:对于另一种看起来非常有希望的方法,请查看??c Thanh Nguy?n 的这个新答案。
回答by kaybee99
I've built upon ??c Thanh Nguy?n's fantastic answer to allow this method to work with 64-bit versions of Excel. I'm running Excel 2010 64-Bit on 64-Bit Windows 7.
我已经建立在 ??c Thanh Nguy?n 的绝妙答案上,允许此方法与 64 位版本的 Excel 一起使用。我在 64 位 Windows 7 上运行 Excel 2010 64 位。
- Open the file(s) that contain your locked VBA Projects.
Create a new xlsm file and store this code in 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 FunctionPaste this code in Module2and run it
Sub unprotected() If Hook Then MsgBox "VBA Project is unprotected!", vbInformation, "*****" End If End Sub
- 打开包含锁定的 VBA 项目的文件。
创建一个新的 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
DISCLAIMERThis worked for me and I have documented it here in the hope it will help someone out. I have not fully tested it. Please be sure to save all open files before proceeding with this option.
免责声明这对我有用,我在这里记录了它,希望它能帮助别人。我还没有完全测试它。在继续使用此选项之前,请确保保存所有打开的文件。
回答by Pieter
There is another (somewhat easier) solution, without the size problems. I used this approach today (on a 2003 XLS file, using Excel 2007) and was successful.
还有另一种(更简单的)解决方案,没有大小问题。我今天使用了这种方法(在 2003 XLS 文件上,使用 Excel 2007)并且成功了。
- Backup the xls file
- Open the file in a HEX editor and locate the
DPB=...part - Change the
DPB=...string toDPx=... - Open the xls file in Excel
- Open the VBA editor (ALT+ F11)
- the magic:Excel discovers an invalid key (DPx) and asks whether you want to continue loading the project (basically ignoring the protection)
- You will be able to overwrite the password, so change it to something you can remember
- Save the xls file*
- Close and reopen the document and work your VBA magic!
- 备份xls文件
- 在十六进制编辑器中打开文件并找到
DPB=...零件 - 将
DPB=...字符串更改为DPx=... - 在 Excel 中打开 xls 文件
- 打开 VBA 编辑器 ( ALT+ F11)
- 神奇之处:Excel 发现无效密钥 (DPx) 并询问您是否要继续加载项目(基本上忽略保护)
- 您将能够覆盖密码,因此请将其更改为您可以记住的内容
- 保存 xls 文件*
- 关闭并重新打开文档并发挥您的 VBA 魔法!
*NOTE: Be sure that you have changed the password to a new value, otherwise the next time you open the spreadsheet Excel will report errors (Unexpected Error), then when you access the list of VBA modules you will now see the names of the source modules but receive another error when trying to open forms/code/etc. To remedy this, go back to the VBA Project Properties and set the password to a new value. Save and re-open the Excel document and you should be good to go!
*注意:请确保您已将密码更改为新值,否则下次打开电子表格 Excel 会报错(Unexpected Error),然后当您访问 VBA 模块列表时,您现在将看到该电子表格的名称源模块,但在尝试打开表单/代码/等时收到另一个错误。要解决此问题,请返回 VBA 项目属性并将密码设置为新值。保存并重新打开 Excel 文档,您应该一切顺利!
回答by Stewbob
Colin Pickard has an excellent answer, but there is one 'watch out' with this. There are instances (I haven't figured out the cause yet) where the total length of the "CMG=........GC=...." entry in the file is different from one excel file to the next. In some cases, this entry will be 137 bytes, and in others it will be 143 bytes. The 137 byte length is the odd one, and if this happens when you create your file with the '1234' password, just create another file, and it should jump to the 143 byte length.
科林·皮卡德 (Colin Pickard) 有一个很好的答案,但对此有一个“注意”。在某些情况下(我还没有弄清楚原因)文件中“CMG=........GC=....”条目的总长度从一个 excel 文件到下一个。在某些情况下,此条目为 137 字节,而在其他情况下为 143 字节。137 字节长度是奇数,如果在使用“1234”密码创建文件时发生这种情况,只需创建另一个文件,它就会跳转到 143 字节长度。
If you try to paste the wrong number of bytes into the file, you will lose your VBA project when you try to open the file with Excel.
如果您尝试将错误数量的字节粘贴到文件中,当您尝试使用 Excel 打开文件时,您将丢失 VBA 项目。
EDIT
编辑
This is not valid for Excel 2007/2010 files. The standard .xlsx file format is actually a .zip file containing numerous sub-folders with the formatting, layout, content, etc, stored as xml data. For an unprotected Excel 2007 file, you can just change the .xlsx extension to .zip, then open the zip file and look through all the xml data. It's very straightforward.
这对 Excel 2007/2010 文件无效。标准的 .xlsx 文件格式实际上是一个 .zip 文件,其中包含许多带有格式、布局、内容等的子文件夹,存储为 xml 数据。对于未受保护的 Excel 2007 文件,您只需将 .xlsx 扩展名更改为 .zip,然后打开 zip 文件并查看所有 xml 数据。这非常简单。
However, when you password protect an Excel 2007 file, the entire .zip (.xlsx) file is actually encrypted using RSA encryption. It is no longer possible to change the extension to .zip and browse the file contents.
但是,当您使用密码保护 Excel 2007 文件时,整个 .zip (.xlsx) 文件实际上是使用 RSA 加密进行加密的。无法再将扩展名更改为 .zip 并浏览文件内容。
回答by Matt
For a .xlsmor .dotmfile type you need to do it a slightly different way.
对于.xlsmor.dotm文件类型,您需要以稍微不同的方式进行操作。
- Change the extension of the
.xlsmfile to.zip. - Open the .zip file (with WinZip or WinRar etc) and go to the xl folder.
- Extract the
vbaProject.binfile and open it in a Hex Editor (I use HxD, its completely free and lightweight.) - Search for
DPBand replace withDPxand save the file. - Replace the old
vbaProject.binfile with this new on in the zipped file. - Change the file extension back to
.xlsm. - Open workbook skip through the warning messages.
- Open up Visual Basic inside Excel.
- Go to Tools > VBAProject Properties > Protection Tab.
- Put in a new password and save the
.xlsmfile. - Close and re open and your new password will work.
- 将
.xlsm文件的扩展名更改为.zip. - 打开 .zip 文件(使用 WinZip 或 WinRar 等)并转到 xl 文件夹。
- 提取
vbaProject.bin文件并在十六进制编辑器中打开它(我使用HxD,它完全免费且轻量级。) - 搜索
DPB并替换DPx并保存文件。 vbaProject.bin在压缩文件中用这个新文件替换旧文件。- 将文件扩展名改回
.xlsm. - 打开工作簿跳过警告消息。
- 在 Excel 中打开 Visual Basic。
- 转到工具 > VBAProject 属性 > 保护选项卡。
- 输入新密码并保存
.xlsm文件。 - 关闭并重新打开,您的新密码将起作用。
回答by Andy
It's worth pointing out that if you have an Excel 2007 (xlsm) file, then you can simply save it as an Excel 2003 (xls) file and use the methods outlined in other answers.
值得指出的是,如果您有 Excel 2007 (xlsm) 文件,那么您只需将其另存为 Excel 2003 (xls) 文件并使用其他答案中概述的方法即可。
回答by VePe
With my turn, this is built upon kaybee99's excellent answer which is built upon ??c Thanh Nguy?n's fantastic answer to allow this method to work with both x86 and amd64 versions of Office.
轮到我了,这是建立在 kaybee99 的出色答案之上的,该答案建立在 ??c Thanh Nguy?n 出色的答案之上,以允许此方法与 x86 和 amd64 版本的 Office 一起使用。
An overview of what is changed, we avoid push/ret which is limited to 32bit addresses and replace it with mov/jmp reg.
更改内容的概述,我们避免使用仅限于 32 位地址的 push/ret,并将其替换为 mov/jmp reg。
Tested and works on
经过测试和工作
Word/Excel 2016 - 32 bit version.
Word/Excel 2016 - 64 bit version.
Word/Excel 2016 - 32 位版本。
Word/Excel 2016 - 64 位版本。
how it works
这个怎么运作
- Open the file(s) that contain your locked VBA Projects.
Create a new file with the same type as the above and store this code in 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 FunctionPaste this code in Module2and run it
Sub unprotected() If Hook Then MsgBox "VBA Project is unprotected!", vbInformation, "*****" End If End Sub
- 打开包含锁定的 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
回答by greg
Have you tried simply opening them in OpenOffice.org?
您是否尝试过在 OpenOffice.org 中简单地打开它们?
I had a similar problem some time ago and found that Excel and Calc didn't understand each other's encryption, and so allowed direct access to just about everything.
前段时间我遇到了类似的问题,发现 Excel 和 Calc 不理解彼此的加密,因此允许直接访问几乎所有内容。
This was a while ago, so if that wasn't just a fluke on my part it also may have been patched.
这是前一段时间,所以如果这不仅仅是我的侥幸,它也可能已被修补。
回答by Spangen
In the event that your block of
CMG="XXXX"\r\nDPB="XXXXX"\r\nGC="XXXXXX"in your 'known password' file is shorter than the existing block in the 'unknown password' file, pad your hex strings with trailing zeros to reach the correct length.
如果
CMG="XXXX"\r\nDPB="XXXXX"\r\nGC="XXXXXX"“已知密码”文件中的块比“未知密码”文件中的现有块短,请用尾随零填充十六进制字符串以达到正确的长度。
e.g.
例如
CMG="xxxxxx"\r\nDPB="xxxxxxxx"\r\nGC="xxxxxxxxxx"
CMG="xxxxxx"\r\nDPB="xxxxxxxx"\r\nGC="xxxxxxxxxx"
in the unknown password file, should be set to
在未知密码文件中,应设置为
CMG="XXXX00"\r\nDPB="XXXXX000"\r\nGC="XXXXXX0000"to preserve file length.
CMG="XXXX00"\r\nDPB="XXXXX000"\r\nGC="XXXXXX0000"以保留文件长度。
I have also had this working with .XLA (97/2003 format) files in office 2007.
我也在 office 2007 中使用了 .XLA(97/2003 格式)文件。

