虽然VBA程序加了密码使程序代码不可见,但这也很容易被破解。网上一查,果然有一段VBA代码写了如何破解Excel里的VBA密码。破解的方法是新建一个Excel文件,用开发工具创建一个模块,只要把下面这段代码写到这个模块里,然后打开待破解的带宏程序的Excel文件,运行下面代码中的PasswordCracking()方法,就可以把待破解的宏程序密码去除。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
Private Sub RecoverBytes()
If Flag Then MoveMemory ByVal pFunc, ByVal VarPtr(OriginBytes(0)), 12
End Sub
Private 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
Sub PasswordCracking()
If Hook Then
MsgBox "VBA Project password protection has been removed.", vbInformation, "Password Cracking"
Else
MsgBox "No encryption VBA Project found.", vbInformation, "Password Cracking"
End If
End Sub
对于solidworks的VBA程序也有其他工具可以轻松破解,无论是多长多复杂的密码,都能轻松破解。为了保护程序代码,必须另辟蹊径,使用封装DLL的方法可能是其中一个选择。下面就以最简单的实例说明如何制作dll文件,并在Excel里使用。首先,在Visual Studio里创建一个VB类库项目,如下图所示。注意选择的是含有.NET Framework、VB和Windows这三个特征的那种类库,不要选成“通用windows”类库。项目名称可使用默认的ClassLibrary1,当然也可以自行命名。
创建好项目后,程序自动打开项目,可在资源管理器里看到当前项目已自动创建了一个类Class1。右键选中这个Class1,删除它。
在资源管理中再用右键选中项目名称,选择“添加”-->"类",在弹出的选项里选择“COM类”,这时就自动创建了一个名为COMClass1的类,并自动生成了如下的代码:<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)> _
Public Class ComClass1
#Region "COM GUID"
' 这些 GUID 提供此类的 COM 标识
' 及其 COM 接口。若更改它们,则现有的
' 客户端将不再能访问此类。
Public Const ClassId As String = "9bc632f6-cb98-40dd-809d-584ac35f7dd9"
Public Const InterfaceId As String = "09b8d875-d7b9-4531-9634-65b97fe76177"
Public Const EventsId As String = "3a401de1-af99-4f46-9347-c1fc9298a453"
#End Region
' 可创建的 COM 类必须具有一个不带参数的 Public Sub New()
' 否则, 将不会在
' COM 注册表中注册此类,且无法通过
' CreateObject 创建此类。
Public Sub New()
MyBase.New()
End Sub
End Class
我们需要在这个类里添加自己的方法,但是不能删除原有的代码,下面添加一个方法Test,用于计算2个整数相加,代码改成下面这样:<ComClass(ComClass1.ClassId, ComClass1.InterfaceId, ComClass1.EventsId)> _
Public Class ComClass1
#Region "COM GUID"
' 这些 GUID 提供此类的 COM 标识
' 及其 COM 接口。若更改它们,则现有的
' 客户端将不再能访问此类。
Public Const ClassId As String = "9bc632f6-cb98-40dd-809d-584ac35f7dd9"
Public Const InterfaceId As String = "09b8d875-d7b9-4531-9634-65b97fe76177"
Public Const EventsId As String = "3a401de1-af99-4f46-9347-c1fc9298a453"
#End Region
' 可创建的 COM 类必须具有一个不带参数的 Public Sub New()
' 否则, 将不会在
' COM 注册表中注册此类,且无法通过
' CreateObject 创建此类。
Public Sub New()
MyBase.New()
End Sub
Public Function Test(ByVal a As Integer, ByVal b As Integer) As Integer
Test = a + b
End Function
End Class
程序写完后,在Visual Studio的主菜单里选择“生成”-->"生成ClassLibrary1",(可能会要求以管理员身份打开Visual Studio才可以生成),ClassLibrary1是默认的项目名称,根据你所取的项目名称不同,这个子菜单名称也会不同。此时在项目目录下的bin\debug文件夹中就生成了ClassLibrary1.dll文件和ClassLibrary1.tlb文件。此时,新建一个Excel文件,打开开发工具,新建一个Visual Basic模块,在编辑器的主菜单中选择“工具”-->"引用"就可以看到ClassLibrary1已经被添加到引用里,勾选ClassLibrary1,如下图。
Sub main()
Dim cls As New ComClass1
Debug.Print cls.Test(10, 20)
End Sub
至此,程序在本机运行完全没问题了。但是把Excel保存成xlsm文件后复制到其它电脑运行,却是报错的。原因是找不到ClassLibrary1.tlb这个文件,即使我们把这个文件也复制过去,仍然是报错,这是因为这个自定义的dll文件没有在这台电脑里注册过。为什么在其它电脑没注册就不可以使用,在自己电脑同样也没注册却可以使用?这是因为在用Visual Studio编译程序时,Visual Studio已经自动注册了这个dll,这也是为什么要求用管理员身份运行Visual Studio才可以编译程序的原因。那么在其它电脑该如何注册dll文件呢。首先,要新建一个注册批处理文件regist.bat,用记事本或其它文本编辑器在regist.bat里写下如下代码:set p=ClassLibrary1
set w=C:\Windows\
copy =%~dp0%p%.dll %w%%p%.dll
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe %w%%p%.dll /tlb:%w%%p%.tlb /codebase
pause
上面这段批处理文件的意思是,先将当前目录下(%~dp0%就表示当前批处理文件所在目录)的ClassLibrary1.dll文件复制到C:\windows\目录下,然后调用C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe程序,注册ClassLibrary1.dll文件,同时在C:\windows\里生成一个ClassLibrary1.tlb文件。批处理文件写好后,把ClassLibrary1.dll文件和批处理文件regist.bat放在同一个文件夹里。用管理员身份运行regist.bat文件,完成dll文件注册。此时再打开带有宏程序的Excel文件,运行程序就不会再报错了。
该文章在 2024/9/18 9:02:53 编辑过