mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-04-25 23:59:59 +00:00
Use OpenMcdf for MSI
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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 '_';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user