¿Existe alguna forma de descifrar la contraseña en un proyecto Excel VBA?

Resuelto Jonathan Sayce asked hace 15 años • 25 respuestas

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?

Jonathan Sayce avatar Jun 22 '09 17:06 Jonathan Sayce
Aceptado

Puedes probar este VBAenfoque 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.

  1. El VBE llamará a una función del sistema para crear el cuadro de diálogo de contraseña.
  2. 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.
  3. Una vez cerrado el cuadro de diálogo, VBE comprueba el valor devuelto de la función del sistema.
  4. si este valor es 1, VBE "pensará" que la contraseña es correcta y, por lo tanto, se abrirá el proyecto VBA bloqueado.
  5. 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!

  1. Abra los archivos que contienen sus proyectos VBA bloqueados
  2. 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
    
  3. 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
    
  4. Vuelve a tus proyectos VBA y disfruta.

Đức Thanh Nguyễn avatar Dec 16 '2014 15:12 Đức Thanh Nguyễn

Sí, siempre que utilice un .xlsformato 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:

  1. Cree un nuevo archivo de Excel simple.
  2. En la parte de VBA, establezca una contraseña simple (por ejemplo, 1234).
  3. Guarda el archivo y cierra. Luego verifique el tamaño del archivo; consulte el mensaje de Stewbob.
  4. Abra el archivo que acaba de crear con un editor hexadecimal.
  5. Copie las líneas que comienzan con las siguientes claves:

    CMG=....
    DPB=...
    GC=...
    
  6. 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.

  7. Guarde el archivo de Excel y salga.
  8. 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.

Colin Pickard avatar Jun 22 '2009 10:06 Colin Pickard

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.

  1. Abra los archivos que contienen sus proyectos VBA bloqueados.
  2. 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
    
  3. 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.

kaybee99 avatar Jun 23 '2015 14:06 kaybee99

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.

  1. Copia de seguridad del archivo xls
  2. Abra el archivo en un editor HEX y localice la DPB=...pieza.
  3. Cambie la DPB=...cadena aDPx=...
  4. Abra el archivo xls en Excel
  5. Abra el editor VBA ( ALT+ F11)
  6. 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)
  7. Podrás sobrescribir la contraseña, así que cámbiala por algo que puedas recordar.
  8. Guarde el archivo xls*
  9. ¡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!

Pieter avatar Nov 05 '2010 15:11 Pieter

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

  1. Abra los archivos que contienen sus proyectos VBA bloqueados.

  2. 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
    
  3. 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
    
VePe avatar Nov 18 '2018 08:11 VePe