Begin work on file hashes (encrypted region files are incorrect)

This commit is contained in:
Deterous
2023-11-03 02:17:46 +13:00
parent 641e915a22
commit 8802ca10da
+82 -32
View File
@@ -125,6 +125,9 @@ namespace LibIRD
/// <remarks>Offset to use when reading the footer</remarks> /// <remarks>Offset to use when reading the footer</remarks>
private long UpdateEnd { get; set; } private long UpdateEnd { get; set; }
private long[] RegionStart { get; set; }
private long[] RegionEnd { get; set; }
#endregion #endregion
#region Constructors #region Constructors
@@ -135,7 +138,7 @@ namespace LibIRD
/// <param name="isoPath">Path to the ISO</param> /// <param name="isoPath">Path to the ISO</param>
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentNullException"></exception>
/// <exception cref="FileNotFoundException"></exception> /// <exception cref="FileNotFoundException"></exception>
/// <exception cref="InvalidDataException"></exception> /// <exception cref="InvalidFileSystemException"></exception>
internal PS3ISO(string isoPath) internal PS3ISO(string isoPath)
{ {
// Validate ISO path // Validate ISO path
@@ -153,7 +156,7 @@ namespace LibIRD
using FileStream fs = new FileStream(isoPath, FileMode.Open, FileAccess.Read) ?? throw new FileNotFoundException(isoPath); using FileStream fs = new FileStream(isoPath, FileMode.Open, FileAccess.Read) ?? throw new FileNotFoundException(isoPath);
// Validate ISO file stream // Validate ISO file stream
if (!CDReader.Detect(fs)) if (!CDReader.Detect(fs))
throw new InvalidDataException("Not a valid ISO file"); throw new InvalidFileSystemException("Not a valid ISO file");
// New ISO Reader from DiscUtils // New ISO Reader from DiscUtils
CDReader reader = new(fs, true, true); CDReader reader = new(fs, true, true);
@@ -184,13 +187,17 @@ namespace LibIRD
// Recursively process all files in ISO // Recursively process all files in ISO
FileCount = 0; FileCount = 0;
FileKeys = new ulong[99]; DiscDirectoryInfo dir = reader.GetDirectoryInfo("\\");
FileHashes = new byte[99][]; CountFiles(dir);
ProcessFiles(reader, "\\");
for (int i = 0; i < FileCount; i++) // Determine file offsets and hashes
FileKeys[i] = 0; FileKeys = new ulong[FileCount];
for (int i = 0; i < FileCount; i++) FileHashes = new byte[FileCount][];
FileHashes[i] = NullMD5; uint fileCount = FileCount;
FileCount = 0;
ProcessFiles(fs, reader, dir);
if (FileCount != fileCount)
throw new InvalidFileSystemException("Unexpected ISO filesystem error");
} }
#endregion #endregion
@@ -203,7 +210,7 @@ namespace LibIRD
/// <remarks>PS3UPDAT.PUP update file version number</remarks> /// <remarks>PS3UPDAT.PUP update file version number</remarks>
/// <param name="fs">ISO filestream</param> /// <param name="fs">ISO filestream</param>
/// <param name="reader"></param> /// <param name="reader"></param>
/// <exception cref="InvalidDataException"></exception> /// <exception cref="InvalidFileSystemException"></exception>
private void GetSystemVersion(FileStream fs, CDReader reader) private void GetSystemVersion(FileStream fs, CDReader reader)
{ {
// Determine PUP file offset via cluster // Determine PUP file offset via cluster
@@ -213,7 +220,7 @@ namespace LibIRD
// File too small for dedicated cluster, try get the offset from the file extents instead // File too small for dedicated cluster, try get the offset from the file extents instead
DiscUtils.Streams.StreamExtent[] updateExtents = reader.PathToExtents("\\PS3_UPDATE\\PS3UPDAT.PUP"); DiscUtils.Streams.StreamExtent[] updateExtents = reader.PathToExtents("\\PS3_UPDATE\\PS3UPDAT.PUP");
if (updateExtents == null || updateExtents.Length <= 0) if (updateExtents == null || updateExtents.Length <= 0)
throw new InvalidDataException("Unexpected PS3UPDAT.PUP file extent in ISO filestream"); throw new InvalidFileSystemException("Unexpected PS3UPDAT.PUP file extent in ISO filestream");
// PS3UPDAT.PUP file begins at start of first extent // PS3UPDAT.PUP file begins at start of first extent
UpdateOffset = updateExtents[0].Start; UpdateOffset = updateExtents[0].Start;
// Update file ends at the last extent plus its length // Update file ends at the last extent plus its length
@@ -257,6 +264,7 @@ namespace LibIRD
/// </summary> /// </summary>
/// <param name="fs">ISO filestream</param> /// <param name="fs">ISO filestream</param>
/// <param name="reader"></param> /// <param name="reader"></param>
/// <exception cref="InvalidFileSystemException"></exception>
private void GetHeader(FileStream fs, CDReader reader) private void GetHeader(FileStream fs, CDReader reader)
{ {
// Determine the extent of the header via cluster (Sector 0 to first data sector) // Determine the extent of the header via cluster (Sector 0 to first data sector)
@@ -266,7 +274,7 @@ namespace LibIRD
// File too small for dedicated cluster, try get the first sector from the file extents instead // File too small for dedicated cluster, try get the first sector from the file extents instead
DiscUtils.Streams.StreamExtent[] sfbExtents = reader.PathToExtents("\\PS3_DISC.SFB"); DiscUtils.Streams.StreamExtent[] sfbExtents = reader.PathToExtents("\\PS3_DISC.SFB");
if (sfbExtents == null || sfbExtents.Length <= 0) if (sfbExtents == null || sfbExtents.Length <= 0)
throw new InvalidDataException("Unexpected PS3UPDAT.PUP file extent in ISO filestream"); throw new InvalidFileSystemException("Unexpected PS3UPDAT.PUP file extent in ISO filestream");
FirstDataSector = sfbExtents[0].Start; FirstDataSector = sfbExtents[0].Start;
} }
else else
@@ -301,7 +309,6 @@ namespace LibIRD
/// Retreives and stores the footer /// Retreives and stores the footer
/// </summary> /// </summary>
/// <param name="fs">ISO filestream</param> /// <param name="fs">ISO filestream</param>
/// <param name="reader"></param>
private void GetFooter(FileStream fs) private void GetFooter(FileStream fs)
{ {
// Begin a GZip stream to write footer to // Begin a GZip stream to write footer to
@@ -326,6 +333,11 @@ namespace LibIRD
FooterLength = (uint)Footer.Length; FooterLength = (uint)Footer.Length;
} }
/// <summary>
/// Determines and stores the hashes for each disc region
/// </summary>
/// <param name="fs"></param>
/// <exception cref="InvalidFileSystemException"></exception>
private void HashRegions(FileStream fs) private void HashRegions(FileStream fs)
{ {
// Determine the number of unencryted regions // Determine the number of unencryted regions
@@ -336,8 +348,10 @@ namespace LibIRD
// Total number of regions is 2x number of unencrypted regions, minus 1 // Total number of regions is 2x number of unencrypted regions, minus 1
RegionCount = (byte)(2 * ((uint)decRegionCount[3]) - 1); RegionCount = (byte)(2 * ((uint)decRegionCount[3]) - 1);
if (RegionCount <= 0) if (RegionCount <= 0)
throw new InvalidDataException("No regions detected in ISO"); throw new InvalidFileSystemException("No regions detected in ISO");
RegionHashes = new byte[RegionCount][]; RegionHashes = new byte[RegionCount][];
RegionStart = new long[RegionCount];
RegionEnd = new long[RegionCount];
// Determine the extent for each region // Determine the extent for each region
byte[] regionSector = new byte[4]; byte[] regionSector = new byte[4];
@@ -353,6 +367,7 @@ namespace LibIRD
startSector[i] = BitConverter.ToInt32(regionSector) + 1; startSector[i] = BitConverter.ToInt32(regionSector) + 1;
else else
startSector[i] = BitConverter.ToInt32(regionSector); startSector[i] = BitConverter.ToInt32(regionSector);
RegionStart[i] = startSector[i];
// Determine end sector offset of this region // Determine end sector offset of this region
fs.Read(regionSector, 0, 4); fs.Read(regionSector, 0, 4);
Array.Reverse(regionSector, 0, 4); Array.Reverse(regionSector, 0, 4);
@@ -360,6 +375,7 @@ namespace LibIRD
endSector[i] = BitConverter.ToInt32(regionSector) - 1; endSector[i] = BitConverter.ToInt32(regionSector) - 1;
else else
endSector[i] = BitConverter.ToInt32(regionSector); endSector[i] = BitConverter.ToInt32(regionSector);
RegionEnd[i] = endSector[i];
} }
// Remove header from first region // Remove header from first region
@@ -383,7 +399,7 @@ namespace LibIRD
numBytes = fs.Read(buf, 0, buf.Length); numBytes = fs.Read(buf, 0, buf.Length);
// Check that an entire sector was read // Check that an entire sector was read
if (numBytes < buf.Length) if (numBytes < buf.Length)
throw new InvalidDataException("Disc region ended unexpectedly"); throw new InvalidFileSystemException("Disc region ended unexpectedly");
// Process MD5 sum one sector at a time // Process MD5 sum one sector at a time
md5.TransformBlock(buf, 0, buf.Length, null, 0); md5.TransformBlock(buf, 0, buf.Length, null, 0);
} }
@@ -395,35 +411,69 @@ namespace LibIRD
} }
/// <summary> /// <summary>
/// Process all files and files within subdirectories recursively /// Recursively determines file count
/// </summary>
/// <param name="dir"></param>
private void CountFiles(DiscDirectoryInfo dir)
{
foreach (DiscFileInfo _ in dir.GetFiles())
FileCount++;
foreach (DiscDirectoryInfo dirInfo in dir.GetDirectories())
CountFiles(dirInfo);
}
/// <summary>
/// Determine and store hashes for all files and files within subdirectories recursively
/// </summary> /// </summary>
/// <param name="reader"></param> /// <param name="reader"></param>
/// <param name="path"></param> /// <param name="path"></param>
private void ProcessFiles(CDReader reader, string path) private void ProcessFiles(FileStream fs, CDReader reader, DiscDirectoryInfo dir)
{ {
// Process current directory
DiscDirectoryInfo dir = reader.GetDirectoryInfo(path);
// Process all files in current directory // Process all files in current directory
foreach (DiscFileInfo fileInfo in dir.GetFiles()) foreach (DiscFileInfo fileInfo in dir.GetFiles())
{ {
FileKeys[FileCount] = 0; string filePath = fileInfo.FullName;
FileHashes[FileCount] = NullMD5; // Try get the first sector from the file extents instead
FileCount += 1; DiscUtils.Streams.StreamExtent[] fileExtents = reader.PathToExtents(filePath);
// Save directory full path if (fileExtents == null || fileExtents.Length <= 0)
// Save offset throw new InvalidFileSystemException("Unexpected file extent in ISO filestream for " + filePath);
// Save start sector (offset) if (fileExtents.Length > 1)
// Save total sectors (count) throw new InvalidFileSystemException("Non-contiguous file detected");
long firstByte = fileExtents[0].Start;
long fileLength = fileExtents[0].Length;
FileKeys[FileCount] = (ulong)firstByte / 2048;
// Start reading data from the beginning of the ISO file
fs.Seek(firstByte, SeekOrigin.Begin);
byte[] buf = new byte[SectorSize];
int numBytes;
// Read all data before the first data sector
MD5 md5 = MD5.Create();
for (long i = 0; i < (fileLength / SectorSize); i++)
{
numBytes = fs.Read(buf, 0, buf.Length);
// Check that an entire sector was read
if (numBytes < buf.Length)
throw new InvalidFileSystemException("Disc region ended unexpectedly");
md5.TransformBlock(buf, 0, numBytes, null, 0);
}
// Read remaining partial sector
if (fileLength % SectorSize != 0)
{
numBytes = fs.Read(buf, 0, (int)(fileLength % SectorSize));
md5.TransformBlock(buf, 0, numBytes, null, 0);
}
// Finalise and store MD5 hash
md5.TransformFinalBlock(buf, 0, 0);
FileHashes[FileCount] = md5.Hash;
FileCount++;
} }
// Recursively process all subfolders of current directory // Recursively process all subfolders of current directory
foreach (DiscDirectoryInfo dirInfo in dir.GetDirectories()) foreach (DiscDirectoryInfo dirInfo in dir.GetDirectories())
{ {
// Save directory full path ProcessFiles(fs, reader, dirInfo);
// Save offset
// Save start sector (offset)
// Save total sectors (count)
ProcessFiles(reader, dirInfo.FullName);
} }
} }