¿Existe alguna forma de descifrar la contraseña en un proyecto Excel VBA?
Me pidieron que actualizara algunas macros de Excel 2003, pero los proyectos de VBA están protegidos con contraseña y parece que falta documentación... nadie conoce las contraseñas.
¿Existe alguna forma de eliminar o descifrar la contraseña en un proyecto VBA?
Puedes probar este VBA
enfoque directo que no requiere edición HEX. Funcionará con cualquier archivo (*.xls, *.xlsm, *.xlam...).
Probado y funciona en:
Excel 2007
Excel 2010
Excel 2013 - versión de 32 bits
Excel 2016 - versión de 32 bits
¿Busca la versión de 64 bits? ver esta respuesta
Cómo funciona
Haré todo lo posible para explicar cómo funciona. Disculpe mi inglés.
- El VBE llamará a una función del sistema para crear el cuadro de diálogo de contraseña.
- Si el usuario ingresa la contraseña correcta y hace clic en Aceptar, esta función devuelve 1. Si el usuario ingresa la contraseña incorrecta o hace clic en Cancelar, esta función devuelve 0.
- Una vez cerrado el cuadro de diálogo, VBE comprueba el valor devuelto de la función del sistema.
- si este valor es 1, VBE "pensará" que la contraseña es correcta y, por lo tanto, se abrirá el proyecto VBA bloqueado.
- El siguiente código intercambia la memoria de la función original utilizada para mostrar el cuadro de diálogo de contraseña con una función definida por el usuario que siempre devolverá 1 cuando se llame.
Usando el código
¡Primero haga una copia de seguridad de sus archivos!
- Abra los archivos que contienen sus proyectos VBA bloqueados
Cree un nuevo archivo xlsm y almacene este código en el Módulo1
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
Pegue este código debajo del código anterior en el Módulo 1 y ejecútelo
Sub unprotected() If Hook Then MsgBox "VBA Project is unprotected!", vbInformation, "*****" End If End Sub
Vuelve a tus proyectos VBA y disfruta.
Sí, siempre que utilice un .xls
formato de hoja de cálculo (el formato predeterminado para Excel hasta 2003). Para Excel 2007 en adelante, el valor predeterminado es .xlsx
, que es un formato bastante seguro y este método no funcionará.
Como dice Treb, es una comparación simple. Un método es simplemente cambiar la entrada de contraseña en el archivo usando un editor hexadecimal (consulte Editores hexadecimales para Windows ). Ejemplo paso a paso:
- Cree un nuevo archivo de Excel simple.
- En la parte de VBA, establezca una contraseña simple (por ejemplo, 1234).
- Guarda el archivo y cierra. Luego verifique el tamaño del archivo; consulte el mensaje de Stewbob.
- Abra el archivo que acaba de crear con un editor hexadecimal.
Copie las líneas que comienzan con las siguientes claves:
CMG=.... DPB=... GC=...
PRIMERO HAGA UNA COPIA DE SEGURIDAD del archivo de Excel del que no conoce la contraseña de VBA, luego ábralo con su editor hexadecimal y pegue las líneas copiadas anteriormente del archivo ficticio.
- Guarde el archivo de Excel y salga.
- Ahora, abra el archivo de Excel en el que necesita ver el código VBA. La contraseña para el código VBA será simplemente 1234 (como en el ejemplo que muestro aquí).
Si necesita trabajar con Excel 2007 o 2010, hay otras respuestas a continuación que podrían ayudar, en particular estas: 1 , 2 , 3 .
EDITAR en febrero de 2015: para conocer otro método que parece muy prometedor, mire esta nueva respuesta de Đức Thanh Nguyễn.
Me he basado en la fantástica respuesta de Đức Thanh Nguyễn para permitir que este método funcione con versiones de 64 bits de Excel. Estoy ejecutando Excel 2010 de 64 bits en Windows 7 de 64 bits.
- Abra los archivos que contienen sus proyectos VBA bloqueados.
Cree un nuevo archivo xlsm y almacene este código en el Módulo1
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
Pegue este código en el Módulo 2 y ejecútelo.
Sub unprotected() If Hook Then MsgBox "VBA Project is unprotected!", vbInformation, "*****" End If End Sub
DESCARGO DE RESPONSABILIDAD Esto funcionó para mí y lo he documentado aquí con la esperanza de que ayude a alguien. No lo he probado completamente . Asegúrese de guardar todos los archivos abiertos antes de continuar con esta opción.
Hay otra solución (algo más sencilla), sin problemas de tamaño. Utilicé este enfoque hoy (en un archivo XLS de 2003, usando Excel 2007) y tuve éxito.
- Copia de seguridad del archivo xls
- Abra el archivo en un editor HEX y localice la
DPB=...
pieza. - Cambie la
DPB=...
cadena aDPx=...
- Abra el archivo xls en Excel
- Abra el editor VBA ( ALT+ F11)
- la magia: Excel descubre una clave no válida (DPx) y le pregunta si desea continuar cargando el proyecto (básicamente ignorando la protección)
- Podrás sobrescribir la contraseña, así que cámbiala por algo que puedas recordar.
- Guarde el archivo xls*
- ¡Cierra y vuelve a abrir el documento y haz tu magia de VBA!
*NOTA: Asegúrese de haber cambiado la contraseña a un nuevo valor; de lo contrario, la próxima vez que abra la hoja de cálculo, Excel informará errores (Error inesperado), luego, cuando acceda a la lista de módulos de VBA, ahora verá los nombres de los módulos fuente pero recibe otro error al intentar abrir formularios/código/etc. Para remediar esto, regrese a las Propiedades del proyecto VBA y establezca la contraseña en un nuevo valor. Guarde y vuelva a abrir el documento de Excel y ¡ya estará listo!
Editar: esta es una versión actualizada de la respuesta aceptada y debería funcionar en más versiones de Office. ¡Es difícil, pero llevemos esta respuesta a la cima!
En mi turno, esto se basa en la excelente respuesta de kaybee99, que se basa en la fantástica respuesta de Đức Thanh Nguyễn para permitir que este método funcione con ambas versiones de Office de 32/64 bits .
Una descripción general de lo que ha cambiado: evitamos push/ret, que está limitado a direcciones de 32 bits, y lo reemplazamos con mov/jmp reg.
cómo funciona
Abra los archivos que contienen sus proyectos VBA bloqueados.
Cree un nuevo archivo con el mismo tipo que el anterior y almacene este código en el Módulo1
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
Pegue este código en el Módulo 2 y ejecútelo.
Sub unprotected() If Hook Then MsgBox "VBA Project is unprotected!", vbInformation, "*****" End If End Sub