通过前面的文章能够知道,每一个模块的代码,在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