Use OpenMcdf for MSI

This commit is contained in:
Matt Nadareski
2022-06-23 13:58:48 -07:00
parent 3c1623cb22
commit bd40ca6d9d
3 changed files with 100 additions and 7 deletions

View File

@@ -22,6 +22,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenMcdf" Version="2.2.1.9" />
<PackageReference Include="SharpCompress" Version="0.32.1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
<PackageReference Include="Teronis.MSBuild.Packaging.ProjectBuildInPackage" Version="1.0.0">
@@ -58,9 +59,6 @@
<ItemGroup>
<ProjectReference Include="..\HLLibSharp\HLLibSharp\HLLibSharp.csproj" />
<ProjectReference Include="..\LibMSPackSharp\LibMSPackSharp\LibMSPackSharp.csproj" />
<ProjectReference Include="..\WixToolset\src\WixToolset.Dtf.WindowsInstaller\WixToolset.Dtf.WindowsInstaller.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
</Project>

View File

@@ -1,9 +1,10 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
using WixToolset.Dtf.WindowsInstaller;
using OpenMcdf;
namespace BurnOutSharp.FileType
{
@@ -40,9 +41,39 @@ namespace BurnOutSharp.FileType
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (Database msidb = new Database(file, DatabaseOpenMode.ReadOnly))
using (CompoundFile msi = new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.Default))
{
msidb.ExportAll(tempPath);
msi.RootStorage.VisitEntries((e) =>
{
if (!e.IsStream)
return;
var str = msi.RootStorage.GetStream(e.Name);
if (str == null)
return;
byte[] strData = str.GetData();
if (strData == null)
return;
string decoded = DecodeStreamName(e.Name).TrimEnd('\0');
byte[] nameBytes = Encoding.UTF8.GetBytes(e.Name);
// UTF-8 encoding of 0x4840.
if (nameBytes[0] == 0xe4 && nameBytes[1] == 0xa1 && nameBytes[2] == 0x80)
decoded = decoded.Substring(3);
foreach (char c in Path.GetInvalidFileNameChars())
{
decoded = decoded.Replace(c, '_');
}
string filename = Path.Combine(tempPath, decoded);
using (Stream fs = File.OpenWrite(filename))
{
fs.Write(strData, 0, strData.Length);
}
}, recursive: true);
}
// Collect and format all found protections
@@ -70,5 +101,68 @@ namespace BurnOutSharp.FileType
return null;
}
/// <remarks>Adapted from LibMSI</remarks>
private static string DecodeStreamName(string input)
{
if (input == null)
return null;
int count = 0;
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
int p = 0; // inputBytes[0]
byte[] output = new byte[inputBytes.Length + 1];
int q = 0; // output[0]
while (p < inputBytes.Length && inputBytes[p] != 0)
{
int ch = inputBytes[p];
if ((ch == 0xe3 && inputBytes[p + 1] >= 0xa0) || (ch == 0xe4 && inputBytes[p + 1] < 0xa0))
{
// UTF-8 encoding of 0x3800..0x47ff.
output[q++] = (byte)Mime2Utf(inputBytes[p + 2] & 0x7f);
output[q++] = (byte)Mime2Utf(inputBytes[p + 1] ^ 0xa0);
p += 3;
count += 2;
continue;
}
if (ch == 0xe4 && inputBytes[p + 1] == 0xa0)
{
// UTF-8 encoding of 0x4800..0x483f.
output[q++] = (byte)Mime2Utf(inputBytes[p + 2] & 0x7f);
p += 3;
count++;
continue;
}
output[q++] = inputBytes[p++];
if (ch >= 0xc1)
output[q++] = inputBytes[p++];
if (ch >= 0xe0)
output[q++] = inputBytes[p++];
if (ch >= 0xf0)
output[q++] = inputBytes[p++];
count++;
}
output[q] = 0;
return Encoding.ASCII.GetString(output);
}
/// <remarks>Adapted from LibMSI</remarks>
private static int Mime2Utf(int x)
{
if (x < 10)
return x + '0';
if (x < (10 + 26))
return x - 10 + 'A';
if (x < (10 + 26 + 26))
return x - 10 - 26 + 'a';
if (x == (10 + 26 + 26))
return '.';
return '_';
}
}
}

View File

@@ -7,12 +7,13 @@ C# port of the protection scanning ability of [BurnOut](http://burnout.sourcefor
In addition to the original BurnOut code, the following libraries (or ports thereof) are used for file handling:
- [HLLibSharp](https://github.com/mnadareski/HLLibSharp) - Various Valve archive format extraction
- [LibMSPackSharp](https://github.com/mnadareski/LibMSPackSharp) - Microsoft CAB extraction
- [openmcdf](https://github.com/ironfede/openmcdf) - MSI extraction
- [psxt001z](https://github.com/Dremora/psxt001z) - PS1 LibCrypt detection
- [SharpCompress](https://github.com/adamhathcock/sharpcompress) - 7zip/GZip/RAR/PKZIP extraction
- [StormLibSharp](https://github.com/robpaveza/stormlibsharp) - MPQ extraction
- [UnshieldSharp](https://github.com/mnadareski/UnshieldSharp) - InstallShield CAB extraction
- [WiseUnpacker](https://github.com/mnadareski/WiseUnpacker) - Wise Installer extraction
- [WixToolset.Dtf](https://github.com/wixtoolset/Dtf) - MSI and Microsoft CAB extraction
Please note that due to current library limitations, the functionality of StormLibSharp and WixToolset.Dtf are locked to Windows only.