解除VBA 密码,适用于新的offices
- 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() '若已经hook,则恢复原API开头的6字节,也就是恢复原来函数的功能
- 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
- 'VBE6.dll调用DialogBoxParamA显示VB6INTL.dll资源中的第4070号对话框(就是输入密码的窗口)
- '若DialogBoxParamA返回值非0,则VBE会认为密码正确,所以我们要hook DialogBoxParamA函数
- #If Win64 Then
- osi = 1
- #Else
- osi = 0
- #End If
-
- pFunc = GetProcAddress(GetModuleHandleA("user32.dll"), "DialogBoxParamA")
- '标准api hook过程之一: 修改内存属性,使其可写
- If VirtualProtect(ByVal pFunc, 12, PAGE_EXECUTE_READWRITE, OriginProtect) <> 0 Then
- '标准api hook过程之二: 判断是否已经hook,看看API的第一个字节是否为&H68,
- '若是则说明已经Hook
- MoveMemory ByVal VarPtr(TmpBytes(0)), ByVal pFunc, osi + 1
- If TmpBytes(osi) <> &HB8 Then
- '标准api hook过程之三: 保存原函数开头字节,这里是6个字节,以备后面恢复
- MoveMemory ByVal VarPtr(OriginBytes(0)), ByVal pFunc, 12
- '用AddressOf获取MyDialogBoxParam的地址
- '因为语法不允许写成p = AddressOf MyDialogBoxParam,这里我们写一个函数
- 'GetPtr,作用仅仅是返回AddressOf MyDialogBoxParam的值,从而实现将
- 'MyDialogBoxParam的地址付给p的目的
- p = GetPtr(AddressOf MyDialogBoxParam)
- '标准api hook过程之四: 组装API入口的新代码
- 'HookBytes 组成如下汇编
- 'push MyDialogBoxParam的地址
- 'ret
- '作用是跳转到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
- '标准api hook过程之五: 用HookBytes的内容改写API前6个字节
- MoveMemory ByVal pFunc, ByVal VarPtr(HookBytes(0)), 12
- '设置hook成功标志
- 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
- '有程序调用DialogBoxParamA装入4070号对话框,这里我们直接返回1,让VBE以为密码正确了
- MyDialogBoxParam = 1
- Else '有程序调用DialogBoxParamA,但装入的不是4070号对话框,这里我们调用RecoverBytes函数恢复原来函数的功能,在进行原来的函数
- RecoverBytes
- MyDialogBoxParam = DialogBoxParam(hInstance, pTemplateName, _
- hWndParent, lpDialogFunc, dwInitParam)
- Hook '原来的函数执行完毕,再次hook
- End If
- End Function