Create and use manifesr version utility

This commit is contained in:
Matt Nadareski
2021-03-20 17:34:31 -07:00
parent deb3c01362
commit 07882f7632
3 changed files with 101 additions and 111 deletions

View File

@@ -22,24 +22,17 @@ namespace BurnOutSharp.PackerType
byte[] check = new byte[] { 0x53, 0x00, 0x65, 0x00, 0x74, 0x00, 0x75, 0x00, 0x70, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x79, 0x00 };
if (fileContent.Contains(check, out int position))
{
// "<?xml"
byte[] check2 = new byte[] { 0x3C, 0x3F, 0x78, 0x6D, 0x6C };
if (fileContent.Contains(check2, out int position2))
{
string version = GetVersionXML(fileContent, position2);
if (version == null)
return $"Setup Factory (Unknown Version)" + (includePosition ? $" (Index {position})" : string.Empty);
return $"Setup Factory {version}" + (includePosition ? $" (Index {position}, {position2})" : string.Empty);
}
else
{
string version = Utilities.GetFileVersion(file);
if (version == null)
return $"Setup Factory (Unknown Version)" + (includePosition ? $" (Index {position})" : string.Empty);
// Check the manifest version first
string version = Utilities.GetManifestVersion(fileContent);
if (!string.IsNullOrEmpty(version))
return $"Setup Factory {version}" + (includePosition ? $" (Index {position})" : string.Empty);
}
// Then check the file version
version = Utilities.GetFileVersion(file);
if (!string.IsNullOrEmpty(version))
return $"Setup Factory {version}" + (includePosition ? $" (Index {position})" : string.Empty);
return $"Setup Factory (Unknown Version)" + (includePosition ? $" (Index {position})" : string.Empty);
}
return null;
@@ -63,36 +56,5 @@ namespace BurnOutSharp.PackerType
{
return null;
}
// I was only able to test version detection with version 9.1.0.0 and version 5.0.1.0, but any other versions that use XML or the "File Version" field to store the version number should be detected as well.
// Version 5.0.1.0 contains the string "Setup Factory 32-Bit Setup Module 5.00", which adds confusion about the version but may be used as an additional check
private static string GetVersionXML(byte[] fileContent, int xmlStartPosition)
{
// </assembly>
byte[] check = new byte[] { 0x3C, 0x2F, 0x61, 0x73, 0x73, 0x65, 0x6D, 0x62, 0x6C, 0x79, 0x3E };
if (fileContent.Contains(check, out int position, start: xmlStartPosition))
{
int offset = position + 11 - xmlStartPosition;
string xmlString = Encoding.ASCII.GetString(fileContent, xmlStartPosition, offset);
try
{
// Load the XML string as a document
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
// Get the version attribute, if possible
string xmlVersion = xmlDoc["assembly"]["assemblyIdentity"].GetAttributeNode("version").InnerXml;
return $"Version {xmlVersion}";
}
catch
{
return null;
}
}
return null;
}
}
}

View File

@@ -19,26 +19,12 @@ namespace BurnOutSharp.PackerType
// WinZip Self-Extractor
byte[] check = new byte[] { 0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70, 0x20, 0x53, 0x65, 0x6C, 0x66, 0x2D, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6F, 0x72 };
if (fileContent.Contains(check, out int position))
{
// "<?xml"
byte[] check2 = new byte[] { 0x3C, 0x3F, 0x78, 0x6D, 0x6C };
if (fileContent.Contains(check2, out int position2))
return $"WinZip SFX {GetV3PlusVersion(fileContent, position2)}" + (includePosition ? $" (Index {position}, {position2})" : string.Empty);
else
return $"WinZip SFX {GetV2Version(fileContent)}" + (includePosition ? $" (Index {position})" : string.Empty);
}
return $"WinZip SFX {GetVersion(fileContent)}" + (includePosition ? $" (Index {position})" : string.Empty);
// _winzip_
check = new byte[] { 0x5F, 0x77, 0x69, 0x6E, 0x7A, 0x69, 0x70, 0x5F };
if (fileContent.Contains(check, out position))
{
// "<?xml"
byte[] check2 = new byte[] { 0x3C, 0x3F, 0x78, 0x6D, 0x6C };
if (fileContent.Contains(check2, out int position2))
return $"WinZip SFX {GetV3PlusVersion(fileContent, position2)}" + (includePosition ? $" (Index {position}, {position2})" : string.Empty);
else
return $"WinZip SFX {GetV2Version(fileContent)}" + (includePosition ? $" (Index {position})" : string.Empty);
}
return $"WinZip SFX {GetVersion(fileContent)}" + (includePosition ? $" (Index {position})" : string.Empty);
return null;
}
@@ -103,44 +89,14 @@ namespace BurnOutSharp.PackerType
return null;
}
private static string GetV3PlusVersion(byte[] fileContent, int xmlStartPosition)
private static string GetVersion(byte[] fileContent)
{
// </assembly>
byte[] check = new byte[] { 0x3C, 0x2F, 0x61, 0x73, 0x73, 0x65, 0x6D, 0x62, 0x6C, 0x79, 0x3E };
if (fileContent.Contains(check, out int position, start: xmlStartPosition))
{
int offset = position + 11 - xmlStartPosition;
string xmlString = Encoding.ASCII.GetString(fileContent, xmlStartPosition, offset);
try
{
// Load the XML string as a document
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
// Get the version attribute, if possible
string xmlVersion = xmlDoc["assembly"]["assemblyIdentity"].GetAttributeNode("version").InnerXml;
// Some version strings don't exactly match the public version number
switch (xmlVersion)
{
case "3.0.7158.0":
return "3.0.7158";
case "3.1.7556.0":
return "3.1.7556";
case "3.1.8421.0":
return "4.0.8421";
case "3.1.8672.0":
return "4.0.8672";
case "4.0.1221.0":
return "4.0.12218";
default:
return $"(Unknown Version - {xmlVersion})";
}
}
catch { }
}
// Check the manifest version first
string version = Utilities.GetManifestVersion(fileContent);
if (!string.IsNullOrEmpty(version))
return GetV3PlusVersion(version);
// Assume an earlier version
return GetV2Version(fileContent);
}
@@ -160,7 +116,7 @@ namespace BurnOutSharp.PackerType
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
};
if (fileContent.Contains(check, out _))
return "Version 2.0 (MS-DOS/16-bit)";
return "2.0 (MS-DOS/16-bit)";
check = new byte[]
{
@@ -174,7 +130,7 @@ namespace BurnOutSharp.PackerType
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
};
if (fileContent.Contains(check, out _))
return "Version 2.0 (16-bit)";
return "2.0 (16-bit)";
check = new byte[]
{
@@ -216,7 +172,7 @@ namespace BurnOutSharp.PackerType
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
};
if (fileContent.Contains(check, out _))
return "Version 2.1 RC2 (MS-DOS/16-bit)";
return "2.1 RC2 (MS-DOS/16-bit)";
check = new byte[]
{
@@ -230,7 +186,7 @@ namespace BurnOutSharp.PackerType
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
};
if (fileContent.Contains(check, out _))
return "Version 2.1 RC2 (16-bit)";
return "2.1 RC2 (16-bit)";
check = new byte[]
{
@@ -272,7 +228,7 @@ namespace BurnOutSharp.PackerType
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
};
if (fileContent.Contains(check, out _))
return "Version 2.1 (MS-DOS/16-bit)";
return "2.1 (MS-DOS/16-bit)";
check = new byte[]
{
@@ -286,7 +242,7 @@ namespace BurnOutSharp.PackerType
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
};
if (fileContent.Contains(check, out _))
return "Version 2.1 (16-bit)";
return "2.1 (16-bit)";
check = new byte[]
{
@@ -334,7 +290,7 @@ namespace BurnOutSharp.PackerType
0x53, 0x46, 0x58,
};
if (fileContent.Contains(check, out _))
return "Version 2.0 (32-bit)";
return "2.0 (32-bit)";
// .............]<5D>92....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SRE.SFX
check = new byte[]
@@ -364,7 +320,7 @@ namespace BurnOutSharp.PackerType
0x53, 0x46, 0x58,
};
if (fileContent.Contains(check, out _))
return "Version 2.1 RC2 (32-bit)";
return "2.1 RC2 (32-bit)";
// .............<2E><><EFBFBD>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SRE.SFX
check = new byte[]
@@ -394,7 +350,7 @@ namespace BurnOutSharp.PackerType
0x53, 0x46, 0x58,
};
if (fileContent.Contains(check, out _))
return "Version 2.1 (32-bit)";
return "2.1 (32-bit)";
// .............{<7B><>3....<2E>P..............<2E>P..<2E>P..<2E>P..VW95SRE.SFX
check = new byte[]
@@ -427,7 +383,7 @@ namespace BurnOutSharp.PackerType
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
};
if (fileContent.Contains(check, out _))
return "Version 2.2.4003";
return "2.2.4003";
// PE..L.....[:........<2E>........V...*.......?.......p....@.
check = new byte[]
@@ -447,5 +403,25 @@ namespace BurnOutSharp.PackerType
return "Unknown Version 2.X";
}
private static string GetV3PlusVersion(string version)
{
// Some version strings don't exactly match the public version number
switch (version)
{
case "3.0.7158.0":
return "3.0.7158";
case "3.1.7556.0":
return "3.1.7556";
case "3.1.8421.0":
return "4.0.8421";
case "3.1.8672.0":
return "4.0.8672";
case "4.0.1221.0":
return "4.0.12218";
default:
return $"(Unknown Version - {version})";
}
}
}
}

View File

@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
namespace BurnOutSharp
{
@@ -232,5 +234,55 @@ namespace BurnOutSharp
else
return fvinfo.ProductVersion.Replace(", ", ".");
}
/// <summary>
/// Get the assembly version as determined by an embedded assembly manifest
/// </summary>
/// <remarks>TODO: How do we find the manifest specifically better?</remarks>
public static string GetManifestVersion(byte[] fileContent)
{
// <?xml
byte[] manifestStart = new byte[] { 0x3C, 0x3F, 0x78, 0x6D, 0x6C };
if (!fileContent.Contains(manifestStart, out int manifestStartPosition))
return null;
// </assembly>
byte[] manifestEnd = new byte[] { 0x3C, 0x2F, 0x61, 0x73, 0x73, 0x65, 0x6D, 0x62, 0x6C, 0x79, 0x3E };
if (!fileContent.Contains(manifestEnd, out int manifestEndPosition, start: manifestStartPosition))
return null;
// Read in the manifest to a string
int manifestLength = manifestEndPosition + "</assembly>".Length - manifestStartPosition;
string manifestString = Encoding.ASCII.GetString(fileContent, manifestStartPosition, manifestLength);
// Try to read the XML in from the string
try
{
// Load the XML string as a document
var manifestDoc = new XmlDocument();
manifestDoc.LoadXml(manifestString);
// If the XML has no children, it's invalid
if (!manifestDoc.HasChildNodes)
return null;
// Try to read the assembly node
var assemblyNode = manifestDoc["assembly"];
if (assemblyNode == null)
return null;
// Try to read the assemblyIdentity
var assemblyIdentityNode = assemblyNode["assemblyIdentity"];
if (assemblyIdentityNode == null)
return null;
// Return the version attribute, if possible
return assemblyIdentityNode.GetAttribute("version");
}
catch
{
return null;
}
}
}
}