为了保护自己写的VBA程序代码不被他人抄袭,你可能想到给程序添加查看密码。然而这种密码是很容易被破解的,其中的一种破解方法详见我之前写的一篇文章:如何把Excel的VBA程序封装成DLL并分发给他人使用。其实还有很多种破解方法,包括下面即将介绍的这种隐藏代码模块的方法也可以改造成破解密码的方法。除了使用密码,其实还可以使用代码混淆和隐藏代码模块的办法。下面就介绍一种可以隐藏代码模块的方法。 VBA程序的文件其实是一种“复合文件”,无论是在Excel里写的VBA程序,还是在Solidworks里写的程序,都属于这种“复合文件”。首先要了解这种“复合文件“的内部结构,下面用一个VBA方法(可以在Excel里写,也可以在solidworks里写这个方法)打印出一个Solidworks里编写的swp程序文件的内部结构,代码如下:
'打印出复合文件的内部目录结构 PrivateSub Test_PrintDirs() Dim fAs CFile Set f= New CFile() '打开文件,以字节方式打开 f.OpenFile "D:\VBA\隐藏模块测试.swp" Dim cf As CCompoundFile Set cf=New CCompoundFile Dim ret As String ret= cf.Parse(f) If VBA.Len(ret) Then Debug.Print ret EndIf Dim fs() As String fs= cf.DirsName() Dim i As Long For i=0 To UBound(fs) Debug.Print i, fs(i) Next Set cf=Nothing Set f=Nothing End SubView Code
上面这段代码用于打印“D:\VBA\隐藏代码测试.swp”这个“复合文件”的内部结构,这个文件在solidworks里打开的结果如下图所示,代码主要由Main和Hide这两个模块组成,还有一个UserForm1窗体。
运行上面的代码段后,得到下面这样的输出结果:
0 Root Entry 1 Root Entry\apc 2 Root Entry\apc\The VBA Project 3 Root Entry\apc\The VBA Project\_VBA_Project 4 Root Entry\apc\The VBA Project\Host Project Item Names 5 Root Entry\apc\The VBA Project\VBA Project Data 6 Root Entry\apc\The VBA Project\Host Project Items 7 Root Entry\apc\The VBA Project\VBA Project Signature 8 Root Entry\apc\The VBA Project\Host Project Item Names\ThisLibrary 9 Root Entry\apc\The VBA Project\Host Project Item Names\Project_Data_CurVer 10 Root Entry\apc\The VBA Project\Host Project Item Names\Host Project Item List Data 11 Root Entry\apc\The VBA Project\_VBA_Project\VBA 12 Root Entry\apc\The VBA Project\_VBA_Project\PROJECTwm 13 Root Entry\apc\The VBA Project\_VBA_Project\PROJECT 14 Root Entry\apc\The VBA Project\_VBA_Project\VBA\ThisLibrary 15 Root Entry\apc\The VBA Project\_VBA_Project\VBA\Main 16 Root Entry\apc\The VBA Project\_VBA_Project\VBA\__SRP_2 17 Root Entry\apc\The VBA Project\Host Project Item Names\ThisLibrary\Project Item Data 18 Root Entry\apc\The VBA Project\Host Project Item Names\ThisLibrary\Control List Data 19 Root Entry\apc\The VBA Project\Host Project Item Names\ThisLibrary\ReqControl List Data 20 Root Entry\apc\The VBA Project\_VBA_Project\VBA\__SRP_3 21 Root Entry\apc\The VBA Project\_VBA_Project\VBA\UserForm1 22 Root Entry\apc\The VBA Project\_VBA_Project\UserForm1\f 23 Root Entry\apc\The VBA Project\_VBA_Project\UserForm1\o 24 Root Entry\apc\The VBA Project\_VBA_Project\UserForm1 25 Root Entry\apc\The VBA Project\_VBA_Project\UserForm1\[1]CompObj 26 Root Entry\apc\The VBA Project\_VBA_Project\UserForm1\[3]VBFrame 27 Root Entry\apc\The VBA Project\_VBA_Project\VBA\Hide 28 Root Entry\apc\The VBA Project\_VBA_Project\VBA\__SRP_4 29 Root Entry\apc\The VBA Project\_VBA_Project\VBA\__SRP_5 30 Root Entry\apc\The VBA Project\_VBA_Project\VBA\_VBA_PROJECT 31 Root Entry\apc\The VBA Project\_VBA_Project\VBA\dir 32 Root Entry\apc\The VBA Project\_VBA_Project\VBA\__SRP_0 33 Root Entry\apc\The VBA Project\_VBA_Project\VBA\__SRP_1 34 Root Entry\apc\The VBA Project\Host Project Item Names\ThisLibrary\ReqControl List Data\ReqControl List Data 35 Root Entry\apc\The VBA Project\Host Project Item Names\ThisLibrary\Control List Data\Control_Data_CurVer 36 Root Entry\apc\The VBA Project\Host Project Item Names\ThisLibrary\Control List Data\Control List DataView Code
在这个“复合文件”内部,有许多组成文件,而VBA模块的定义就放在“Root Entry\apc\The VBA Project\_VBA_Project\PROJECT”这个文件里,我们只需要改写这个文件,就可以达到隐藏其中某个模块的目的。为了改写这个文件,首先要了解它有哪些内容,可以用下面这段代码把它的内容显示出来:
Private Sub Test_GetStream() Dim f As CFile Set f = NewCFile() f.OpenFile"D:\VBA\隐藏模块测试.swp" Dim cf As CCompoundFile Set cf=New CCompoundFile Dim ret As String ret= cf.Parse(f) Dim b() As Byte ret= cf.GetStream("Root Entry\apc\The VBA Project\_VBA_Project\PROJECT", b) If VBA.Len(ret) Then Debug.Print ret End If Debug.Print VBA.StrConv(b, vbUnicode) Set cf=Nothing Set f=Nothing End SubView Code
运行上面这段代码后,得到下面的输出结果:
ID="{6366A273-ED0F-4463-BE89-B6DD8ECD755B}" Document=ThisLibrary/&H00000000 Module=Main Module=Hide Package={AC9F2F90-E877-11CE-9F68-00AA00574A4F} BaseClass=UserForm1 Name="Macro4" HelpContextID="0" VersionCompatible32="393222000" CMG="888A859389938993899389" DPB="C4C6C9EF392A3A2A3A2A" GC="00020D0E0E0E0EF1" [Host Extender Info] &H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 [Workspace] ThisLibrary=0, 0, 0, 0, C Main=534, 155, 1812, 802, Z UserForm1=49, 97, 1327, 744, , 756, 68, 2034, 715, Hide=224, 224, 1187, 708,View Code
从上面的输出结果可以看到,程序文件一共有2个模块:Main和Hide,如果要隐藏Hide模块,那么只需要把Module=Hide这行删除即可。下面再用一段VBA代码来改写上面的“复合文件”,使Hide模块隐藏。
'改写对应的文件 Private Sub Test_ReWriteStream() Dim f As CFile Set f= New CFile() f.OpenFile "D:\VBA\隐藏模块测试.swp" Dim cf As CCompoundFile Set cf=New CCompoundFile Dim ret As String ret= cf.Parse(f) If VBA.Len(ret)Then Debug.Print ret End If Dim b()As Byte ret= cf.GetStream("Root Entry\apc\The VBA Project\_VBA_Project\PROJECT", b) If VBA.Len(ret)Then Debug.Print ret End If Dim strSrc As String strSrc= VBA.StrConv(b, vbUnicode) '替换后模块将被隐藏 'strSrc = VBA.Replace(strSrc, "Module=MMain" & vbNewLine, "") strSrc= VBA.Replace(strSrc,"Module=Hide"& vbNewLine,"") Debug.Print"更改后的文本:"& Chr(13)& strSrc b= VBA.StrConv(strSrc, vbFromUnicode) ret= b Debug.Print"转换后的文本"& Chr(13)& ret ret= cf.ReWriteStream("Root Entry\apc\The VBA Project\_VBA_Project\PROJECT", b) If VBA.Len(ret) Then Debug.Print ret EndIf Set cf=Nothing Set f=Nothing EndSubView Code
经过改写文件后,再用solidworks打开swp文件,发现Hide模块不见了,但是程序还能正常运行。学会了隐藏模块的方法,那么恢复模块可见就很简单了,只需要给文件重新添加上对应的模块名即可。其实上面这种方法不仅可以隐藏模块,也可以用于解除VBA程序设置的密码,下次我们再详细说说如何解除程序密码。
上面的代码段用到了一些未公开的方法和代码,如果你想要深入学习和了解,请关注微信公众号“全栈开发的码农”,欢迎私信或留言探讨。
标签:VBA,ret,Project,模块,apc,Entry,Root,隐藏 From: https://www.cnblogs.com/wwwzgy/p/18622409