Kae Travis

Split PE Files into Separate Components

Description:

This script will split PE files into separate components, as per Windows Installer Best Practices.

Usage

CScript.exe {Script} {MSI}

Script

'set up log file
Dim fso : Set fso = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
'create a name/path for log file
Dim MSIPath : Set MSIPath = fso.GetFile(WScript.Arguments(0))  
Dim logFile : logFile = Left(MSIPath.Path, InStrRev(MSIPath.Path, ".") - 1) & ".log"
Dim objLogFile : Set objLogFile = fso.OpenTextFile(logFile, ForAppending, True)
WriteLog "Splitting PE Files into Separate Components"
WriteLog "Processing: " & MSIPath.Name
'create 2 constants - one for when we want to just query the MSI (read) and one for when we want to make changes (write)
Const msiOpenDatabaseModeReadOnly = 0
Const msiOpenDatabaseModeTransact = 1
Const msiViewModifyReplace = 4
'create WindowsInstaller.Installer object
Dim oInstaller : Set oInstaller = CreateObject("WindowsInstaller.Installer")
'open the MSI (the first argument supplied to the vbscript)
Dim oDatabase : Set oDatabase = oInstaller.OpenDatabase(WScript.Arguments(0),msiOpenDatabaseModeTransact) 
Dim tempComponent : tempComponent = ""
Dim tempFilename : tempFilename = ""
Dim tempFileKey : tempFileKey = ""	
Dim	tempDirectory : tempDirectory = ""
Dim	tempAttributes : tempAttributes = ""
Dim	tempCondition : tempCondition = ""
Dim	tempFeature : tempFeature = ""
Dim tempKeypath : tempKeypath = ""
Dim tempExtensionArray
Dim TableView, TableRec, fileView, fileRec, tempExtension, id, compExistView, compExistRec
If oDatabase.TablePersistent("Component") = 1 AND oDatabase.TablePersistent("File") = 1 Then 
'select component
Set Tableview = oDatabase.OpenView("SELECT `Component`.`Component`,`Component`.`Directory_`,`Component`.`Attributes`,`Component`.`Condition`,`Component`.`KeyPath`,`FeatureComponents`.`Feature_` FROM `Component`,`FeatureComponents` WHERE `Component`.`Component` = `FeatureComponents`.`Component_`")
Tableview.Execute
Set TableRec = Tableview.Fetch
'component table has records
Do Until TableRec Is Nothing
tempComponent = TableRec.StringData(1)
tempDirectory = TableRec.StringData(2)
tempAttributes = TableRec.StringData(3)
tempCondition = TableRec.StringData(4)
tempKeypath = TableRec.StringData(5)
tempFeature = TableRec.StringData(6)
If Not isMSMData(tempComponent) Then
'select every file in this component except the keypath
Set fileView = oDatabase.OpenView("SELECT `File`,`FileName`,`Version` FROM `File` WHERE `Component_`='" & tempComponent & "' and `File` <> '" & tempKeypath & "'")
fileView.Execute
Set fileRec = fileView.Fetch
Do Until fileRec Is Nothing
tempFileKey = fileRec.StringData(1)
tempFilename = fileRec.StringData(2)
If InStr(tempFilename,"|") Then
'attempt to get actual filename if there is a sfn equivalent
tempFilename = Split(tempFilename,"|")(1)
End If
If InStr(tempFilename,".") > 0 Then
tempExtensionArray = Split(LCase(tempFilename),".")
tempExtension = "." & tempExtensionArray(UBound(tempExtensionArray))
Else
tempExtension = ""
End If			
'If current file is a PE file, separate it into another component
If Len(tempExtension) = 4 And InStr(1,".ica,.lnk,.inf,.ini,.dll,.exe,.ocx,.tlb,.chm,.drv,.hlp,.sys,.ttf,.mdb,.mdf,.ldf,.jar,.dbf,.vbs,.rll",tempExtension)>0 Then
id = 0		
Do While componentExists(tempFilename)	
id = id + 1			
tempFilename = tempFilename & id
Loop
WScript.Echo "tempext: " & tempExtension
WriteLog "Moving File: " & tempFileKey & " into new Component: " & tempFilename
oDatabase.OpenView("INSERT INTO `Component` (`Component`,`ComponentId`,`Directory_`,`Attributes`,`Condition`,`KeyPath`) VALUES ('"& tempFilename &"','"& returnGuid &"','"& tempDirectory &"',"& tempAttributes &",'"& tempCondition &"','"& tempFileKey &"')").Execute
oDatabase.OpenView("UPDATE `File` SET `Component_` = '" & tempFilename & "' WHERE `File` = '"& tempFileKey &"'").Execute
oDatabase.OpenView("INSERT INTO `FeatureComponents` (`Feature_`,`Component_`) VALUES ('"& tempFeature &"','"& tempFilename &"')").Execute
End If
Set fileRec = fileView.Fetch
Loop
Set fileView = Nothing
Set fileRec = Nothing
end If
Set TableRec = Tableview.Fetch
Loop
Set TableRec = Nothing
Set Tableview = Nothing
Set fileRec = Nothing
End If
oDatabase.Commit	
objLogFile.Close
Set fso = Nothing
Set objLogFile = Nothing	
Set oDatabase = Nothing
Set oInstaller = Nothing
Sub WriteLog(LogMessage)
WScript.echo Now() & ": " & LogMessage
objLogFile.Writeline(Now() & ": " & LogMessage)
End Sub
'return a random guid for when we create a new component
Function returnGuid()
Dim TypeLib : Set TypeLib = CreateObject("Scriptlet.TypeLib")
Dim tg : tg = TypeLib.Guid
returnGuid = Left(tg, len(tg)-2)
Set TypeLib = Nothing
End Function
'returns true if tempData contains MSM decoration
Function isMSMData(tempData)
isMSMData = False
Dim Match
Dim regEx : Set regEx = New RegExp
regEx.MultiLine = vbTrue
regEx.global = vbTrue
regEx.Pattern = "[A-Za-z0-9]{8}_[A-Za-z0-9]{4}_[A-Za-z0-9]{4}_[A-Za-z0-9]{4}_[A-Za-z0-9]{12}"
For Each Match in regEx.Execute(tempData)
isMSMData = True
Next
Set regEx = Nothing
End Function
'used to see if a component exists or Not
Function componentExists(component)
'this function is called initially with '1' as the id.  Then this value gets incrememnetd if the component exists
Set compExistView = oDatabase.OpenView("SELECT `Component` FROM `Component` WHERE `Component`='" & component & "'")
compExistView.Execute
Set compExistRec = compExistView.Fetch
If Not compExistRec is Nothing Then
Set compExistView = Nothing
Set compExistRec = Nothing
componentExists = True			
Else
Set compExistView = Nothing
Set compExistRec = Nothing
componentExists = False
End If	
End Function

 

Split PE Files into Separate Components
Split PE Files into Separate Components

1 thought on “Split PE Files into Separate Components

  1. hello

    thanks for your script

    it’s work but i have an error ICE03 like this:

    Invalid identifier; Table: File, Column: Component_, Key(s): File Component_

    and other

    can you advice how i an fix it?

     

Leave a Reply