我被要求更新一些Excel 2003宏,但是VBA项目有密码保护,而且似乎缺乏文档…没人知道密码。
是否有一种方法可以删除或破解VBA项目的密码?
我被要求更新一些Excel 2003宏,但是VBA项目有密码保护,而且似乎缺乏文档…没人知道密码。
是否有一种方法可以删除或破解VBA项目的密码?
当前回答
编辑:这是已接受答案的更新版本,应该适用于更多的办公室版本。这很难,但让我们把这个答案说出来吧!
轮到我了,这是建立在kaybee99的优秀答案之上的,它建立在Đức Thanh nguykun的出色答案之上,允许这种方法与32/64位版本的Office一起工作。
概览一下更改的内容,我们避免了push/ret,它仅限于32位地址,并将其替换为mov/jmp reg。
它是如何工作的
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 Function Paste this code in Module2 and run it Sub unprotected() If Hook Then MsgBox "VBA Project is unprotected!", vbInformation, "*****" End If End Sub
其他回答
您可以尝试这种不需要HEX编辑的直接VBA方法。它将适用于任何文件(*.xls, *.xls, *.xls)。xlsm, *。xlam……)。
测试和工作:
Excel 2007 Excel 2010 Excel 2013 - 32位版本 Excel 2016 - 32位版本
寻找64位版本?请看这个答案
它是如何工作的
我会尽我最大的努力解释它是如何工作的-请原谅我的英语。
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.
使用代码
请先备份您的文件!
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 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 Paste this code under the above code in Module1 and run it Sub unprotected() If Hook Then MsgBox "VBA Project is unprotected!", vbInformation, "*****" End If End Sub Come back to your VBA Projects and enjoy.
还有另一种更简单的解决方案,不存在尺寸问题。今天我使用了这种方法(在一个2003年的XLS文件上,使用Excel 2007),并且取得了成功。
备份xls文件 在HEX编辑器中打开文件,并找到DPB=…部分 更改DPB=…string to DPx=… 在Excel中打开xls文件 打开VBA编辑器(ALT + F11) 魔术: Excel发现一个无效的键(DPx),并询问您是否要继续加载项目(基本上忽略保护) 您将能够覆盖密码,因此将其更改为您可以记住的密码 保存xls文件* 关闭并重新打开文档并使用您的VBA魔法!
*注意:请确保您已将密码更改为新值,否则下次打开电子表格Excel将报告错误(意外错误),然后当您访问VBA模块列表时,您现在将看到源模块的名称,但在尝试打开表单/代码/等时收到另一个错误。要解决这个问题,请返回VBA项目属性并将密码设置为新值。保存并重新打开Excel文档,您应该可以开始了!
你试过在OpenOffice.org中打开它们吗?
前段时间我遇到了类似的问题,发现Excel和Calc不能理解彼此的加密,因此允许直接访问几乎所有内容。
这是一段时间以前,所以如果这不仅仅是我的侥幸,它也可能已经被修补。
我的工具VbaDiff直接从文件中读取VBA,因此您可以使用它从大多数办公文档中恢复受保护的VBA代码,而无需求助于十六进制编辑器。
Colin Pickard is mostly correct, but don't confuse the "password to open" protection for the entire file with the VBA password protection, which is completely different from the former and is the same for Office 2003 and 2007 (for Office 2007, rename the file to .zip and look for the vbaProject.bin inside the zip). And that technically the correct way to edit the file is to use a OLE compound document viewer like CFX to open up the correct stream. Of course, if you are just replacing bytes, the plain old binary editor may work.
顺便说一句,如果你想知道这些字段的确切格式,他们现在有文档:
http://msdn.microsoft.com/en-us/library/dd926151%28v=office.12%29.aspx