通过前面的文章能够知道,每一个模块的代码,在VBAProject中也就是一个数据流,这个数据流经过了run length encoding的算法进行压缩。
前面介绍的是自己使用VBA代码来解压缩,其实也有现成的API RtlDecompressBuffer可以使用,具体用法可以网上找找。
所以,只要能找到模块的数据流,然后进行解压缩就可以还原模块的代码。模块的数据流也就是在复合文档中读取一个数据流,另外要注意的是,这样读取出来的模块数据流并不都是我们写的VBA代码,还需要结合解析dir流时候得到的模块信息进行截取,再进行解压缩:
'读取某个模块的代码'ModuleName 模块的名称'StrCode 返回模块的代码'Return 返回出错信息Function GetModuleCode(ModuleName As String, ByRef StrCode As String) As String Dim ret As String Dim b() As Byte '读取原始的流 ret = cf.GetStream(PrePath & "VBA\" & ModuleName, b) If VBA.Len(ret) Then GetModuleCode = ret Exit Function End If 'vba代码只是后面的一部分 Dim bCode() As Byte Dim moduleIndex As Long moduleIndex = GetModuleIndex(ModuleName) If moduleIndex = -1 Then GetModuleCode = "CVBAProject: 在ModuleInfo_中没有找到模块[" & ModuleName & "]" Exit Function End If Dim i As Long, j As Long '跳过前面不需要的部分 ReDim bCode(UBound(b) - ModuleInfo_(moduleIndex).Offset) As Byte For i = ModuleInfo_(moduleIndex).Offset To UBound(b) bCode(i - ModuleInfo_(moduleIndex).Offset) = b(i) Next ''run length encoding解码dir流 Dim cr As CRLE Set cr = New CRLE ret = cr.UnCompress(bCode, bCode) If VBA.Len(ret) Then GetModuleCode = ret Exit Function End If Set cr = Nothing StrCode = VBA.StrConv(bCode, vbUnicode)End Function