Move psxt001z to its own library

This commit is contained in:
Matt Nadareski
2023-09-18 00:59:37 -04:00
parent 71fd5af48e
commit 9d4bc6bfab
14 changed files with 0 additions and 2990 deletions

View File

@@ -16,8 +16,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "psxt001z", "psxt001z\psxt001z.csproj", "{D9574B47-0D6B-445A-97BF-272B5EF9AD3F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryObjectScanner.Compression", "BinaryObjectScanner.Compression\BinaryObjectScanner.Compression.csproj", "{B55206B2-58FD-4A47-AADC-74982FEA8FAD}"
EndProject
Global
@@ -34,10 +32,6 @@ Global
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88735BA2-778D-4192-8EB2-FFF6843719E2}.Release|Any CPU.Build.0 = Release|Any CPU
{D9574B47-0D6B-445A-97BF-272B5EF9AD3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D9574B47-0D6B-445A-97BF-272B5EF9AD3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D9574B47-0D6B-445A-97BF-272B5EF9AD3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D9574B47-0D6B-445A-97BF-272B5EF9AD3F}.Release|Any CPU.Build.0 = Release|Any CPU
{B55206B2-58FD-4A47-AADC-74982FEA8FAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B55206B2-58FD-4A47-AADC-74982FEA8FAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B55206B2-58FD-4A47-AADC-74982FEA8FAD}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@@ -46,10 +46,6 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
<ProjectReference Include="..\psxt001z\psxt001z.csproj">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
</Project>

View File

@@ -7,7 +7,6 @@ C# protection, packer, and archive scanning library. This currently compiles as
The following libraries (or ports thereof) are used for file handling:
- [openmcdf](https://github.com/ironfede/openmcdf) - MSI extraction
- [psxt001z](https://github.com/Dremora/psxt001z) - PS1 LibCrypt detection [Ported to C#]
- [SharpCompress](https://github.com/adamhathcock/sharpcompress) - Common archive format extraction
- [SharpZipLib](https://github.com/icsharpcode/SharpZipLib) - zlib-based extraction
- [StormLibSharp](https://github.com/robpaveza/stormlibsharp) - MoPaQ extraction [Unused in .NET 6.0 builds due to Windows-specific libraries]

View File

@@ -1,53 +0,0 @@
namespace psxt001z
{
public class CRC16
{
// Table of CRC constants - implements x^16+x^12+x^5+1
private static ushort[] CRC16Table = new ushort[]
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
};
public static ushort Calculate(byte[] buf, int bufPtr, int len)
{
ushort cksum = 0;
for (int i = 0; i < len; i++)
{
cksum = (ushort)(CRC16Table[((cksum >> 8) ^ buf[bufPtr++]) & 0xFF] ^ (cksum << 8));
}
return (ushort)(~cksum);
}
}
}

View File

@@ -1,57 +0,0 @@
namespace psxt001z
{
internal class CRC32
{
#region Constants
private const uint CRC_POLY = 0xEDB88320;
private const uint CRC_MASK = 0xD202EF8D;
#endregion
#region Properties
protected uint[] Table { get; private set; } = new uint[256];
public uint m_crc32 { get; set; }
#endregion
#region Constructor
public CRC32()
{
for (uint i = 0; i < 256; i++)
{
uint r, j;
for (r = i, j = 8; j != 0; j--)
{
r = ((r & 1) != 0) ? (r >> 1) ^ CRC_POLY : r >> 1;
}
Table[i] = r;
}
m_crc32 = 0;
}
#endregion
#region Functions
public void ProcessCRC(byte[] pData, int pDataPtr, int nLen)
{
uint crc = m_crc32;
while (nLen-- != 0)
{
crc = Table[(byte)(crc ^ pData[pDataPtr++])] ^ crc >> 8;
crc ^= CRC_MASK;
}
m_crc32 = crc;
}
#endregion
}
}

View File

@@ -1,19 +0,0 @@
namespace psxt001z
{
public static class Common
{
public const int ZERO = 0;
public const string VERSION = "v0.21 beta 1";
/// <summary>
/// BCD to u_char
/// </summary>
public static byte btoi(byte b) => (byte)(((b) / 16 * 10 + (b) % 16));
/// <summary>
/// u_char to BCD
/// </summary>
public static byte itob(byte i) => (byte)(((i) / 10 * 16 + (i) % 10));
}
}

View File

@@ -1,178 +0,0 @@
using System;
using System.IO;
using System.Text;
namespace psxt001z
{
internal class FileTools
{
#region Properties
private Stream InputStream { get; set; }
private byte[] ExeName { get; set; } = new byte[20];
private byte[] DateValue { get; set; } = new byte[11];
#endregion
#region Constructor
public FileTools(Stream file)
{
InputStream = file;
}
#endregion
#region Functions
/// <summary>
/// Get file size
/// </summary>
public long size() => InputStream.Length;
/// <summary>
/// Get executable name
/// </summary>
public string exe()
{
InputStream.Seek(51744, SeekOrigin.Begin);
string filename = string.Empty;
while (filename != "SYSTEM.CNF")
{
byte[] buf = new byte[10];
InputStream.Read(buf, 0, 10);
filename = Encoding.ASCII.GetString(buf);
InputStream.Seek(-9, SeekOrigin.Current);
}
byte[] buffer = new byte[20];
InputStream.Seek(-32, SeekOrigin.Current);
InputStream.Read(buffer, 0, 4);
uint lba = BitConverter.ToUInt32(buffer, 0);
InputStream.Seek((2352 * lba) + 29, SeekOrigin.Begin);
InputStream.Read(buffer, 0, 6);
string iniLine = Encoding.ASCII.GetString(buffer);
while (iniLine != "cdrom:")
{
InputStream.Seek(-5, SeekOrigin.Current);
InputStream.Read(buffer, 0, 6);
iniLine = Encoding.ASCII.GetString(buffer);
}
InputStream.Read(buffer, 0, 1);
if (buffer[0] != '\\')
InputStream.Seek(-1, SeekOrigin.Current);
int i = -1;
do
{
InputStream.Read(buffer, ++i, 1);
} while (buffer[i] != ';');
for (long a = 0; a < i; a++)
{
ExeName[a] = (byte)char.ToUpper((char)buffer[a]);
}
return Encoding.ASCII.GetString(ExeName);
}
/// <summary>
/// Get human-readable date
/// </summary>
public string date()
{
byte[] buffer = new byte[12], datenofrmt = new byte[3];
InputStream.Seek(51744, SeekOrigin.Begin);
do
{
InputStream.Read(buffer, 0, 11);
buffer[11] = 0;
InputStream.Seek(-10, SeekOrigin.Current);
} while (Encoding.ASCII.GetString(ExeName) != Encoding.ASCII.GetString(buffer));
InputStream.Seek(-16, SeekOrigin.Current);
InputStream.Read(datenofrmt, 0, 3);
if (datenofrmt[0] < 50)
{
byte[] year = Encoding.ASCII.GetBytes($"{2000 + datenofrmt[0]}");
Array.Copy(year, 0, buffer, 0, 4);
}
else
{
byte[] year = Encoding.ASCII.GetBytes($"{1900 + datenofrmt[0]}");
Array.Copy(year, 0, buffer, 0, 4);
}
DateValue[4] = (byte)'-';
if (datenofrmt[1] < 10)
{
byte[] month = Encoding.ASCII.GetBytes($"0{datenofrmt[1]}");
Array.Copy(month, 0, buffer, 5, 2);
}
else
{
byte[] month = Encoding.ASCII.GetBytes($"{datenofrmt[1]}");
Array.Copy(month, 0, buffer, 5, 2);
}
DateValue[7] = (byte)'-';
if (datenofrmt[2] < 10)
{
byte[] day = Encoding.ASCII.GetBytes($"0{datenofrmt[2]}");
Array.Copy(day, 0, buffer, 8, 2);
}
else
{
byte[] day = Encoding.ASCII.GetBytes($"{datenofrmt[2]}");
Array.Copy(day, 0, buffer, 8, 2);
}
return Encoding.ASCII.GetString(DateValue);
}
/// <summary>
/// Resize the image
/// </summary>
public int resize(long newsize)
{
long oldsize = size();
if (oldsize < newsize)
{
InputStream.SetLength(newsize);
return 1;
}
else if (oldsize > newsize)
{
InputStream.SetLength(newsize);
return 2;
}
else
{
return 0;
}
}
/// <summary>
/// Get the reported sector count from the image
/// </summary>
public int imagesize()
{
InputStream.Seek(0x9368, SeekOrigin.Begin);
byte[] sizebuf = new byte[4];
InputStream.Read(sizebuf, 0, 4);
return BitConverter.ToInt32(sizebuf, 0);
}
#endregion
}
}

View File

@@ -1,108 +0,0 @@
using System;
using System.IO;
using System.Text;
using static psxt001z.Common;
namespace psxt001z
{
internal static class Functions
{
public static int CalculateEDC(in byte[] src, int srcPtr, int size, int[] edc_lut)
{
int edc = 0;
while (size-- != 0)
{
edc = (edc >> 8) ^ edc_lut[(edc ^ src[srcPtr++]) & 0xFF];
}
return edc;
}
public static bool ZeroCompare(byte[] buffer, int bufferPtr, int bsize)
{
for (int i = 0; i < bsize; i++)
{
if (buffer[bufferPtr + i] != 0x00)
return false;
}
return true;
}
public static void MSF(long lba, byte[] buffer, int bufferOffset)
{
lba += 150;
double mindbl = lba / 60 / 75;
byte min = (byte)Math.Floor(mindbl);
double secdbl = (lba - (min * 60 * 75)) / 75;
byte sec = (byte)Math.Floor(secdbl);
byte frame = (byte)(lba - (min * 60 * 75) - (sec * 75));
buffer[bufferOffset] = itob(min);
buffer[bufferOffset + 1] = itob(sec);
buffer[bufferOffset + 2] = itob(frame);
return;
}
public static bool GetEDCStatus(Stream file)
{
long currentposition = file.Position;
file.Seek(30572, SeekOrigin.Begin);
byte[] buffer = new byte[4];
file.Read(buffer, 0, 4);
file.Seek(currentposition, SeekOrigin.Begin);
return BitConverter.ToInt32(buffer, 0) == 0;
}
public static byte[] ExecutableName(Stream file)
{
byte[] buffer = new byte[20];
byte[] exename = new byte[20];
//Searching for SYSTEM.CNF
file.Seek(51744, SeekOrigin.Begin);
while (Encoding.ASCII.GetString(buffer) != "SYSTEM.CNF")
{
file.Read(buffer, 0, 10);
buffer[10] = 0;
file.Seek(-9, SeekOrigin.Current);
}
file.Seek(-32, SeekOrigin.Current);
byte[] lba = new byte[4];
file.Read(lba, 0, 4);
file.Seek((2352 * BitConverter.ToInt32(lba, 0)) + 29, SeekOrigin.Begin);
file.Read(buffer, 0, 6);
buffer[6] = 0;
while (Encoding.ASCII.GetString(buffer) != "cdrom:")
{
file.Seek(-5, SeekOrigin.Current);
file.Read(buffer, 0, 6);
}
file.Read(buffer, 0, 1);
if (buffer[0] != '\\')
file.Seek(-1, SeekOrigin.Current);
int i = -1;
do
{
file.Read(buffer, ++i, 1);
} while (buffer[i] != ';');
for (int a = 0; a < i; a++)
{
exename[a] = (byte)char.ToUpper((char)buffer[a]);
}
exename[i] = 0;
return exename;
}
}
}

View File

@@ -1,293 +0,0 @@
using System;
using System.IO;
using System.Linq;
using static psxt001z.Functions;
namespace psxt001z
{
public class Info
{
#region Constants
private static readonly byte[] edc_form_2 = { 0x3F, 0x13, 0xB0, 0xBE };
private static readonly byte[] syncheader = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 };
private static readonly byte[] subheader = { 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00 };
#endregion
#region Functions
public static int GetInfo(string filename, bool fix)
{
// Variables
bool errors = false;
byte[] buffer = new byte[2352], buffer2 = new byte[2352];
int mode = 15; // synñheader[15];
#region Opening image
Stream image;
try
{
FileAccess open_mode = fix ? FileAccess.ReadWrite : FileAccess.Read;
image = File.Open(filename, FileMode.Open, open_mode);
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
return 1;
}
long size = image.Length;
Console.WriteLine($"File: {filename}");
#endregion
#region Type
image.Read(buffer, 0, 12);
int sectorsize;
if (buffer.Take(12).SequenceEqual(syncheader.Take(12)))
{
sectorsize = 2352;
}
else
{
sectorsize = 2048;
}
if (size % sectorsize != 0)
{
Console.WriteLine($"{filename}: not ModeX/{sectorsize} image!");
return 1;
}
long sectors = size / sectorsize;
#endregion
#region Mode
if (sectorsize == 2352)
{
image.Seek(0xF, SeekOrigin.Begin);
mode = image.ReadByte();
if (mode != 1 && mode != 2)
{
Console.WriteLine($"{filename}: unknown mode!");
return 1;
}
}
else
{
mode = -1;
}
#endregion
#region Size
image.Seek(sectorsize * 16 + ((mode == 2) ? 24 : ((mode == 1) ? 16 : 0)) + 0x50, SeekOrigin.Begin);
// ISO size
byte[] buf = new byte[4];
image.Read(buf, 0, 4);
int realsectors = BitConverter.ToInt32(buf, 0);
image.Seek(0, SeekOrigin.Begin);
int realsize = realsectors * sectorsize;
if (sectors == realsectors)
{
Console.WriteLine($"Size (bytes): {size} (OK)");
Console.WriteLine($"Size (sectors): {sectors} (OK)");
}
else
{
Console.WriteLine($"Size (bytes): {size}");
Console.WriteLine($"From image: {realsize}");
Console.WriteLine($"Size (sectors): {sectors}");
Console.WriteLine($"From image: {realsectors}");
}
#endregion
#region Mode
if (mode > 0)
Console.WriteLine($"Mode: {mode}");
if (mode == 2)
{
#region EDC in Form 2
bool imageedc = GetEDCStatus(image);
Console.WriteLine($"EDC in Form 2 sectors: {(imageedc ? "YES" : "NO")}");
#endregion
#region Sysarea
string systemArea = "System area: ";
image.Seek(0, SeekOrigin.Begin);
CRC32 crc = new CRC32();
for (int i = 0; i < 16; i++)
{
image.Read(buffer, 0, 2352);
crc.ProcessCRC(buffer, 0, 2352);
}
uint imagecrc = crc.m_crc32;
systemArea += GetEdcType(imagecrc);
Console.WriteLine(systemArea);
#endregion
#region Postgap
image.Seek((sectors - 150) * sectorsize + 16, SeekOrigin.Begin);
image.Read(buffer, 0, 2336);
string postgap = "Postgap type: Form ";
if ((buffer[2] >> 5 & 0x1) != 0)
{
postgap += "2";
if (buffer.Take(8).SequenceEqual(subheader))
postgap += ", zero subheader";
else
postgap += ", non-zero subheader";
if (ZeroCompare(buffer, 8, 2324))
postgap += ", zero data";
else
postgap += ", non-zero data";
if (ZeroCompare(buffer, 2332, 4))
postgap += ", no EDC";
else
postgap += ", EDC";
}
else
{
postgap += "1";
if (ZeroCompare(buffer, 0, 8))
postgap += ", zero subheader";
else
postgap += ", non-zero subheader";
if (ZeroCompare(buffer, 8, 2328))
postgap += ", zero data";
else
postgap += ", non-zero data";
}
Console.WriteLine(postgap);
Array.Copy(buffer, buffer2, 2336);
#endregion
}
if (mode < 0)
return 0;
for (long sector = sectors - 150; sector < sectors; sector++)
{
bool bad = false;
image.Seek(sector * sectorsize, SeekOrigin.Begin);
image.Read(buffer, 0, sectorsize);
// Sync
string sectorInfo = string.Empty;
MSF(sector, syncheader, 12);
if (!syncheader.SequenceEqual(buffer.Take(16)))
{
sectorInfo += $"Sector {sector}: Sync/Header";
bad = true;
if (fix)
{
image.Seek(sector * sectorsize, SeekOrigin.Begin);
image.Write(syncheader, 0, 16);
sectorInfo += (" (fixed)");
}
}
// Mode 2
if (mode == 2 && buffer.Skip(16).Take(2336).SequenceEqual(buffer2))
{
if (bad)
{
sectorInfo += ", Subheader/Data/EDC/ECC";
}
else
{
sectorInfo = $"Sector {sector}: Subheader/Data/EDC/ECC";
bad = true;
}
if (fix)
{
image.Seek(sector * sectorsize + 16, SeekOrigin.Begin);
image.Write(buffer2, 0, 2336);
sectorInfo += " (fixed)";
}
}
Console.WriteLine(sectorInfo);
if (bad && (sector + 1 != sectors))
errors = true;
}
if (errors)
{
Console.WriteLine("NOTICE: One or more errors were found not in the last sector.");
Console.WriteLine("Please mention this when submitting dump info.");
}
else
{
Console.WriteLine("Done.");
}
#endregion
return 0;
}
#endregion
#region Utilities
internal static string GetEdcType(uint imageCrc)
{
switch (imageCrc)
{
case 0x11e3052d:
return "Eu EDC";
case 0x808c19f6:
return "Eu NoEDC";
case 0x70ffa73e:
return "Eu Alt NoEDC";
case 0x7f9a25b1:
return "Eu Alt 2 EDC";
case 0x783aca30:
return "Jap EDC";
case 0xe955d6eb:
return "Jap NoEDC";
case 0x9b519a2e:
return "US EDC";
case 0x0a3e86f5:
return "US NoEDC";
case 0x6773d4db:
return "US Alt NoEDC";
default:
return $"Unknown, crc {imageCrc:8x}";
}
}
#endregion
}
}

View File

@@ -1,825 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using static psxt001z.Common;
namespace psxt001z
{
internal class ScsiPassThroughDirect
{
public ushort Length { get; set; }
public byte ScsiStatus { get; set; }
public byte PathId { get; set; }
public byte TargetId { get; set; }
public byte Lun { get; set; }
public byte CDBLength { get; set; }
public byte SenseInfoLength { get; set; }
public byte DataIn { get; set; }
public uint DataTransferLength { get; set; }
public uint TimeOutValue { get; set; }
public byte[] DataBuffer { get; set; }
public uint SenseInfoOffset { get; set; }
public byte[] CDB { get; set; } = new byte[16];
}
public class LibCrypt
{
#region OLD
public static bool CheckSubfile(string subFilePath)
{
// Check the file exists first
if (!File.Exists(subFilePath))
return false;
// Check the extension is a subfile
string ext = Path.GetExtension(subFilePath).TrimStart('.').ToLowerInvariant();
if (ext != "sub")
return false;
// Open and check the subfile for LibCrypt
try
{
using (FileStream subfile = File.OpenRead(subFilePath))
{
return CheckSubfile(subfile);
}
}
catch
{
return false;
}
}
public static bool CheckSubfile(Stream subfile)
{
// Check the length is valid for subfiles
long size = subfile.Length;
if (size % 96 != 0)
return false;
// Persistent values
byte[] buffer = new byte[16];
byte[] sub = new byte[16];
int tpos = 0;
int modifiedSectors = 0;
// Check each sector for modifications
for (uint sector = 150; sector < ((size / 96) + 150); sector++)
{
subfile.Seek(12, SeekOrigin.Current);
if (subfile.Read(buffer, 0, 12) == 0)
return modifiedSectors != 0;
subfile.Seek(72, SeekOrigin.Current);
// New track
if ((btoi(buffer[1]) == (btoi(sub[1]) + 1)) && (buffer[2] == 0 || buffer[2] == 1))
{
Array.Copy(buffer, sub, 6);
tpos = ((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// New index
else if (btoi(buffer[2]) == (btoi(sub[2]) + 1) && buffer[1] == sub[1])
{
Array.Copy(buffer, 2, sub, 2, 4);
tpos = ((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// MSF1 [3-5]
else
{
if (sub[2] == 0)
tpos--;
else
tpos++;
sub[3] = itob((byte)(tpos / 60 / 75));
sub[4] = itob((byte)((tpos / 75) % 60));
sub[5] = itob((byte)(tpos % 75));
}
// MSF2 [7-9]
sub[7] = itob((byte)(sector / 60 / 75));
sub[8] = itob((byte)((sector / 75) % 60));
sub[9] = itob((byte)(sector % 75));
// CRC-16 [10-11]
ushort crc = CRC16.Calculate(sub, 0, 10);
byte[] crcBytes = BitConverter.GetBytes(crc);
sub[10] = crcBytes[0];
sub[11] = crcBytes[1];
// If any byte (except position 6) is different, it's a modified sector
for (int i = 0; i < 12; i++)
{
if (i == 6)
continue;
if (buffer[i] != sub[i])
{
modifiedSectors++;
break;
}
}
}
return modifiedSectors != 0;
}
#endregion
#region Constants
private const uint IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x4D014;
private const byte SCSI_IOCTL_DATA_IN = 0x1;
private const byte RAW_READ_CMD = 0xBE;
private const int BUFFER_LEN = 96;
private const int SENSE_SIZE = 0; //14
private const string F_NAME = "sectors.log";
private const int CYCLES = 5;
private const int LIBCRYPT_NUM_SECTORS = 64;
private const int READ_TIMES = 5;
private static readonly uint[] lc_addresses = new uint[LIBCRYPT_NUM_SECTORS]
{
13955, 13960, 14081, 14086, 14335, 14340, 14429, 14434,
14499, 14504, 14749, 14754, 14906, 14911, 14980, 14985,
15092, 15097, 15162, 15167, 15228, 15233, 15478, 15483,
15769, 15774, 15881, 15886, 15951, 15956, 16017, 16022,
41895, 41900, 42016, 42021, 42282, 42287, 42430, 42435,
42521, 42526, 42663, 42668, 42862, 42867, 43027, 43032,
43139, 43144, 43204, 43209, 43258, 43263, 43484, 43489,
43813, 43818, 43904, 43909, 44009, 44014, 44162, 44167
};
private static readonly byte[] lc1_sectors_contents = new byte[768]
{
0x41, 0x01, 0x01, 0x07, 0x06, 0x05, 0x00, 0x23, 0x08, 0x05, 0x38, 0x39,
0x41, 0x01, 0x01, 0x03, 0x06, 0x11, 0x00, 0x03, 0x08, 0x90, 0x5d, 0xa0,
0x41, 0x01, 0x01, 0x07, 0x07, 0x56, 0x00, 0x23, 0x09, 0x56, 0xdf, 0xde,
0x41, 0x01, 0x01, 0x03, 0x07, 0x60, 0x00, 0x03, 0x09, 0xe1, 0xf2, 0x50,
0x41, 0x01, 0x01, 0x03, 0x13, 0x10, 0x00, 0x03, 0x53, 0x10, 0x50, 0xec,
0x41, 0x01, 0x01, 0x43, 0x11, 0x15, 0x00, 0x01, 0x13, 0x15, 0x23, 0x1e,
0x41, 0x01, 0x01, 0x03, 0x12, 0x09, 0x00, 0x03, 0x14, 0x2d, 0x04, 0x73,
0x41, 0x01, 0x01, 0x03, 0x1a, 0x34, 0x00, 0x03, 0x04, 0x34, 0xe2, 0xcf,
0x41, 0x01, 0x01, 0x03, 0x13, 0x20, 0x00, 0x03, 0x15, 0x04, 0x82, 0x35,
0x41, 0x01, 0x01, 0x01, 0x13, 0x29, 0x00, 0x43, 0x15, 0x29, 0x72, 0xe2,
0x41, 0x01, 0x01, 0x03, 0x1e, 0x49, 0x00, 0x03, 0x08, 0x49, 0x32, 0xc5,
0x41, 0x01, 0x01, 0x01, 0x16, 0x54, 0x00, 0x43, 0x18, 0x54, 0xd4, 0x79,
0x41, 0x01, 0x01, 0x03, 0x18, 0x57, 0x00, 0x03, 0x20, 0xd6, 0xbc, 0x27,
0x41, 0x01, 0x01, 0x03, 0x38, 0x61, 0x00, 0x03, 0x24, 0x61, 0x91, 0xa9,
0x41, 0x01, 0x01, 0x0b, 0x19, 0x55, 0x00, 0x13, 0x21, 0x55, 0x14, 0x07,
0x41, 0x01, 0x01, 0x03, 0x19, 0x62, 0x00, 0x03, 0x21, 0x20, 0x5d, 0x48,
0x41, 0x01, 0x01, 0x03, 0x23, 0x17, 0x00, 0x03, 0x63, 0x17, 0x6d, 0xc6,
0x41, 0x01, 0x01, 0x43, 0x21, 0x22, 0x00, 0x01, 0x23, 0x22, 0x24, 0x89,
0x41, 0x01, 0x01, 0x03, 0x02, 0x12, 0x00, 0x03, 0x20, 0x12, 0x49, 0x43,
0x41, 0x01, 0x01, 0x03, 0x22, 0x07, 0x00, 0x03, 0x24, 0x1f, 0x3a, 0xb1,
0x41, 0x01, 0x01, 0x03, 0x23, 0x13, 0x00, 0x03, 0x25, 0x0b, 0x93, 0xc9,
0x41, 0x01, 0x01, 0x0b, 0x23, 0x08, 0x00, 0x13, 0x25, 0x08, 0xce, 0x5d,
0x41, 0x01, 0x01, 0x03, 0x06, 0x28, 0x00, 0x03, 0x2c, 0x28, 0xd7, 0xd6,
0x41, 0x01, 0x01, 0x0b, 0x26, 0x33, 0x00, 0x13, 0x28, 0x33, 0x9c, 0x29,
0x41, 0x01, 0x01, 0x03, 0x30, 0x59, 0x00, 0x03, 0x32, 0x1b, 0x2c, 0xc6,
0x41, 0x01, 0x01, 0x03, 0x20, 0x24, 0x00, 0x03, 0x3a, 0x24, 0xe6, 0xac,
0x41, 0x01, 0x01, 0x13, 0x31, 0x56, 0x00, 0x0b, 0x33, 0x56, 0x97, 0xed,
0x41, 0x01, 0x01, 0x03, 0x31, 0x65, 0x00, 0x03, 0x33, 0x41, 0xba, 0x63,
0x41, 0x01, 0x01, 0x01, 0x32, 0x51, 0x00, 0x43, 0x34, 0x51, 0xd7, 0xa9,
0x41, 0x01, 0x01, 0x03, 0x33, 0x56, 0x00, 0x03, 0xb4, 0x56, 0xc0, 0x9a,
0x41, 0x01, 0x01, 0x03, 0x32, 0x42, 0x00, 0x03, 0xb5, 0x42, 0x69, 0xe2,
0x41, 0x01, 0x01, 0x03, 0x33, 0x07, 0x00, 0x03, 0x35, 0x45, 0x1a, 0x10,
0x41, 0x01, 0x01, 0x09, 0x18, 0x65, 0x00, 0x09, 0x20, 0x41, 0x40, 0x72,
0x41, 0x01, 0x01, 0x19, 0x18, 0x50, 0x00, 0x01, 0x20, 0x50, 0x25, 0xeb,
0x41, 0x01, 0x01, 0x08, 0x20, 0x16, 0x00, 0x89, 0x22, 0x16, 0x95, 0xa8,
0x41, 0x01, 0x01, 0x09, 0x20, 0x01, 0x00, 0x09, 0x22, 0x25, 0xb8, 0x26,
0x41, 0x01, 0x01, 0x09, 0x23, 0x53, 0x00, 0x09, 0x25, 0x77, 0x21, 0x03,
0x41, 0x01, 0x01, 0x0b, 0x23, 0x62, 0x00, 0x49, 0x25, 0x62, 0x68, 0x4c,
0x41, 0x01, 0x01, 0x0d, 0x25, 0x55, 0x00, 0x29, 0x27, 0x55, 0xae, 0x41,
0x41, 0x01, 0x01, 0x09, 0x25, 0x61, 0x00, 0x09, 0x27, 0xe0, 0xe7, 0x0e,
0x41, 0x01, 0x01, 0x08, 0x26, 0x71, 0x00, 0x89, 0x28, 0x71, 0x95, 0xcb,
0x41, 0x01, 0x01, 0x09, 0x27, 0x21, 0x00, 0x09, 0x29, 0x05, 0x80, 0x4b,
0x41, 0x01, 0x01, 0x0b, 0x28, 0x63, 0x00, 0x49, 0x30, 0x63, 0xed, 0x18,
0x41, 0x01, 0x01, 0x09, 0x29, 0x68, 0x00, 0x09, 0xb0, 0x68, 0xb0, 0x8c,
0x41, 0x01, 0x01, 0x29, 0x31, 0x37, 0x00, 0x0d, 0x33, 0x37, 0x6c, 0x68,
0x41, 0x01, 0x01, 0x09, 0x31, 0x4a, 0x00, 0x09, 0x33, 0x52, 0x7c, 0x8b,
0x41, 0x01, 0x01, 0x09, 0x73, 0x52, 0x00, 0x09, 0x37, 0x52, 0x4b, 0x06,
0x41, 0x01, 0x01, 0x19, 0x33, 0x57, 0x00, 0x01, 0x35, 0x57, 0x38, 0xf4,
0x41, 0x01, 0x01, 0x09, 0x35, 0x04, 0x00, 0x09, 0x37, 0x1c, 0x54, 0x6a,
0x41, 0x01, 0x01, 0x09, 0x31, 0x19, 0x00, 0x09, 0x17, 0x19, 0xa4, 0xbd,
0x41, 0x01, 0x01, 0x01, 0x36, 0x04, 0x00, 0x19, 0x38, 0x04, 0x9c, 0xdf,
0x41, 0x01, 0x01, 0x09, 0x36, 0x0b, 0x00, 0x09, 0x38, 0x49, 0x6c, 0x08,
0x41, 0x01, 0x01, 0x49, 0x36, 0x58, 0x00, 0x0b, 0x38, 0x58, 0x99, 0xbf,
0x41, 0x01, 0x01, 0x09, 0x36, 0x73, 0x00, 0x09, 0x38, 0x6b, 0xfe, 0x96,
0x41, 0x01, 0x01, 0x0b, 0x39, 0x59, 0x00, 0x49, 0x41, 0x59, 0x54, 0x0d,
0x41, 0x01, 0x01, 0x09, 0x39, 0x24, 0x00, 0x09, 0x41, 0x66, 0x9e, 0x67,
0x41, 0x01, 0x01, 0x09, 0x44, 0x1b, 0x00, 0x09, 0x46, 0x03, 0x78, 0x0d,
0x41, 0x01, 0x01, 0x09, 0x46, 0x18, 0x00, 0x09, 0x06, 0x18, 0x25, 0x99,
0x41, 0x01, 0x01, 0x09, 0x45, 0x2b, 0x00, 0x09, 0x47, 0x69, 0xd3, 0xc5,
0x41, 0x01, 0x01, 0x09, 0x05, 0x34, 0x00, 0x09, 0x45, 0x34, 0x35, 0x79,
0x41, 0x01, 0x01, 0x09, 0x44, 0x59, 0x00, 0x09, 0x08, 0x59, 0x6e, 0x0a,
0x41, 0x01, 0x01, 0x49, 0x46, 0x64, 0x00, 0x0b, 0x48, 0x64, 0xa4, 0x60,
0x41, 0x01, 0x01, 0x09, 0x08, 0x62, 0x00, 0x09, 0x52, 0x62, 0x03, 0x5a,
0x41, 0x01, 0x01, 0x19, 0x48, 0x67, 0x00, 0x01, 0x50, 0x67, 0x70, 0xa8
};
#endregion
// TODO: Enable the following only if reading from a drive directly
/*
internal static byte LibCryptDrive(string[] args)
{
byte offset = 0;
string path = $"\\\\.\\{args[0][0]}:";
byte i;
byte[] sub = new byte[12], buffer = new byte[BUFFER_LEN], buffer2352 = new byte[23520], buffer2 = new byte[BUFFER_LEN], buffer3 = new byte[BUFFER_LEN], buffer4 = new byte[BUFFER_LEN];
byte[] status;
ushort crc;
uint sector, sector_start, sector_end, a, lcsectors = 0, todo = 9300, done = 0;
if (args.Length != 1 || (args.Length == 1 && (args[0][1] != 0 && (args[0][1] != ':' || args[0][2] != 0))))
{
Console.WriteLine("LibCrypt drive detector");
Console.WriteLine("nUsage: psxt001z.exe --libcryptdrv <drive letter>");
return 0;
}
Stream hDevice;
try
{
hDevice = File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
}
catch (Exception ex)
{
Console.WriteLine("Can't open device!");
return 0;
}
Stream f;
try
{
f = File.Open(F_NAME, FileMode.Open, FileAccess.Write);
}
catch (Exception ex)
{
Console.WriteLine($"Can't open file {F_NAME}!");
return 0;
}
byte[] status1 = new byte[4650];
byte[] status2 = new byte[4650];
// Offset detection
Console.WriteLine("Determining offset...\r");
ScsiPassThroughDirect SRB = new ScsiPassThroughDirect();
ReadSub(buffer, 0, f, offset, hDevice, SRB);
switch (buffer[8])
{
case 0x01:
offset = (byte)(75 - btoi(buffer[9]));
break;
case 0x02:
offset = (byte)(-btoi(buffer[9]));
break;
default:
Console.WriteLine("Can't determine offset!");
Console.WriteLine(BitConverter.ToString(buffer).Replace('-', ' '));
return 0;
}
sub[0] = buffer[0];
sub[1] = 0x01;
sub[2] = 0x01;
sub[6] = 0x00;
Console.WriteLine($"Subchannels offset correction: {offset}");
// Section 1) 02:58:00 - 03:69:74 -- status1
// Section 2) 08:58:00 - 09:69:74 -- status2
// Step 1
for (i = 0; i < CYCLES * 3; i++)
{
if (todo == 0)
goto end;
if (i % 3 == 0)
{
sector_start = 13350;
sector_end = 18000;
status = status1;
}
else if (i % 3 == 1)
{
sector_start = 40350;
sector_end = 45000;
status = status2;
}
else
{
Console.WriteLine($"Left: {todo:4} / Flushing cache... \r");
ClearCache(buffer2352, f, offset, hDevice, SRB);
continue;
}
for (sector = sector_start; sector < sector_end; sector++)
{
if (status[sector - sector_start] != 0)
continue;
ReadSub(buffer, sector, f, offset, hDevice, SRB);
Console.WriteLine("Left: %4u / Sector %u... \r", todo, sector);
// generating q-channel
sub[3] = itob((byte)(sector / 60 / 75));
sub[4] = itob((byte)((sector / 75) % 60));
sub[5] = itob((byte)(sector % 75));
sub[7] = itob((byte)((sector + 150) / 60 / 75));
sub[8] = itob((byte)(((sector + 150) / 75) % 60));
sub[9] = itob((byte)((sector + 150) % 75));
crc = CRC16.Calculate(sub, 0, 10);
sub[10] = (byte)(crc >> 8);
sub[11] = (byte)(crc & 0xFF);
if (sub.SequenceEqual(buffer.Take(12)))
{
status[sector - sector_start] = 1;
todo--;
done++;
}
}
}
// Step 2
for (i = 0; i < 2; i++)
{
if (i == 0)
{
sector_start = 13350;
sector_end = 18000;
status = status1;
}
else
{
sector_start = 40350;
sector_end = 45000;
status = status2;
}
for (sector = sector_start; sector < sector_end; sector++)
{
if (status[sector - sector_start] != 0)
continue;
ReadSub(buffer, sector, f, offset, hDevice, SRB);
Console.WriteLine($"Left: {todo:4} / Sector {sector}... \r");
// generating q-channel
sub[3] = itob((byte)(sector / 60 / 75));
sub[4] = itob((byte)((sector / 75) % 60));
sub[5] = itob((byte)(sector % 75));
sub[7] = itob((byte)((sector + 150) / 60 / 75));
sub[8] = itob((byte)(((sector + 150) / 75) % 60));
sub[9] = itob((byte)((sector + 150) % 75));
crc = CRC16.Calculate(sub, 0, 10);
sub[10] = (byte)(crc >> 8);
sub[11] = (byte)(crc ^ 0xFF);
if (sub.SequenceEqual(buffer.Take(12)))
{
Console.WriteLine($"Left: {todo:4} / Sector {sector}: flushing cache... \r");
do
{
ReadSub(buffer, sector, f, offset, hDevice, SRB);
ClearCache(buffer2352, f, offset, hDevice, SRB);
ReadSub(buffer2, sector, f, offset, hDevice, SRB);
ClearCache(buffer2352, f, offset, hDevice, SRB);
ReadSub(buffer3, sector, f, offset, hDevice, SRB);
ClearCache(buffer2352, f, offset, hDevice, SRB);
} while (!buffer.SequenceEqual(buffer2) || !buffer.SequenceEqual(buffer3));
//} while (!matrix(buffer, buffer2, buffer3, buffer4, BUFFER_LEN));
if (buffer.SequenceEqual(sub))
{
byte[] buf = Encoding.ASCII.GetBytes($"MSF: {sub[7]:2x}:{sub[8]:2x}:{sub[9]:2x} Q-Data: {BitConverter.ToString(buffer.Take(12).ToArray()).Replace('-', ' ')}");
f.Write(buf, 0, buf.Length);
lcsectors++;
//fwrite(SRB.SRB_BufPointer, 1, SRB.SRB_BufLen - 4, f);
f.Flush();
}
}
todo--;
done++;
}
}
end:
Console.WriteLine($"Done! \nProtected sectors: {(lcsectors == 0 ? "None" : lcsectors.ToString())}");
f.Close();
return 1;
}
internal static int LibCryptDriveFast(string[] args)
{
Stream f;
Stream hDevice;
ScsiPassThroughDirect SRB;
s8 offset = 0, path[] = "\\\\.\\X:";
u8 buffer[BUFFER_LEN], buffer2352[23520], sub[12], lc1sectors = 0, lc2sectors = 0, othersectors = 0;
u16 crc;
if (argc != 1 || (argc == 1 && (args[0][1] != 0 && (args[0][1] != ':' || args[0][2] != 0))))
{
Console.WriteLine("LibCrypt drive detector (fast)\nUsage: psxt001z.exe --libcryptdrvfast <drive letter>\n");
return 0;
}
path[4] = args[0][0];
if ((hDevice = CreateFile(path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
{
Console.WriteLine("Can't open device!\n");
return 0;
}
if (fopen_s(&f, F_NAME, "wb") != 0)
{
Console.WriteLine("Can\'t open file %s!\n", F_NAME);
return 0;
}
// Offset detection
ReadSub(buffer, 0, f, offset, hDevice, SRB);
//if (buffer[5] != buffer[9]) {
// Console.WriteLine("Error determining offset!\nSector 0: %02x%02x%02x %02x:%02x:%02x %02x %02x:%02x:%02x %02x%02x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11]);
//}
switch (buffer[8])
{
case 0x01:
offset = 75 - btoi(buffer[9]);
break;
case 0x02:
offset = -btoi(buffer[9]);
break;
default:
Console.WriteLine("Can't determine offset!\nSector 0: %02x%02x%02x %02x:%02x:%02x %02x %02x:%02x:%02x %02x%02x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11]);
return 0;
}
Console.WriteLine("Subchannels offset correction: %d\n", offset);
sub[0] = buffer[0];
sub[1] = 0x01;
sub[2] = 0x01;
sub[6] = 0x00;
for (int i = 0; i < LIBCRYPT_NUM_SECTORS; i++)
{
Console.WriteLine("\nReading sector %u... ", lc_addresses[i]);
ReadSub(buffer, lc_addresses[i], f, offset, hDevice, SRB);
// generating q-channel
sub[3] = itob(lc_addresses[i] / 60 / 75);
sub[4] = itob((lc_addresses[i] / 75) % 60);
sub[5] = itob(lc_addresses[i] % 75);
sub[7] = itob((lc_addresses[i] + 150) / 60 / 75);
sub[8] = itob(((lc_addresses[i] + 150) / 75) % 60);
sub[9] = itob((lc_addresses[i] + 150) % 75);
crc = crc16(sub, 10);
sub[10] = HIbyte(crc);
sub[11] = LObyte(crc);
for (int a = 1; a <= READ_TIMES; a++)
{
if (!memcmp(sub, buffer, 12))
{
Console.WriteLine("original sector");
break;
}
else if (!memcmp(lc1_sectors_contents + (12 * i), buffer, 12))
{
Console.WriteLine("LibCrypt, LC1 sector");
fConsole.WriteLine(f, "MSF: %02x:%02x:%02x Q-Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", sub[7], sub[8], sub[9], buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11]);
lc1sectors++;
break;
}
else
{
if (a < READ_TIMES)
{
ClearCache(buffer2352, 0, offset, hDevice, SRB);
continue;
}
else
{
Console.WriteLine("unknown");
fConsole.WriteLine(f, "MSF: %02x:%02x:%02x Q-Data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", sub[7], sub[8], sub[9], buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7], buffer[8], buffer[9], buffer[10], buffer[11]);
othersectors++;
}
}
}
}
Console.WriteLine("\n\nOriginal sectors: %u", LIBCRYPT_NUM_SECTORS - lc1sectors - lc2sectors - othersectors);
Console.WriteLine("\nLC1 sectors: %u", lc1sectors);
Console.WriteLine("\nLC2 sectors: %u", lc2sectors);
Console.WriteLine("\nOther sectors: %u", othersectors);
fConsole.WriteLine(f, "\nOriginal sectors: %u", LIBCRYPT_NUM_SECTORS - lc1sectors - lc2sectors - othersectors);
fConsole.WriteLine(f, "\nLC1 sectors: %u", lc1sectors);
fConsole.WriteLine(f, "\nLC2 sectors: %u", lc2sectors);
fConsole.WriteLine(f, "\nOther sectors: %u", othersectors);
fclose(f);
return 1;
}
internal static void ReadSub(byte[] buffer, uint sector, Stream f, byte offset, Stream hDevice, ScsiPassThroughDirect SRB)
{
uint returned;
ZeroMemory(&SRB, sizeof(ScsiPassThroughDirect));
SRB.Length = sizeof(ScsiPassThroughDirect);
SRB.CDBLength = 12;
SRB.DataIn = SCSI_IOCTL_DATA_IN;
SRB.DataTransferLength = BUFFER_LEN;
SRB.TimeOutValue = 30;
SRB.DataBuffer = buffer;
SRB.CDB[0] = RAW_READ_CMD;
SRB.CDB[2] = HIbyte(HIWORD(sector + offset));
SRB.CDB[3] = LObyte(HIWORD(sector + offset));
SRB.CDB[4] = HIbyte(LOWORD(sector + offset));
SRB.CDB[5] = LObyte(LOWORD(sector + offset));
SRB.CDB[8] = 1;
SRB.CDB[10] = 1;
if (!DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SRB, sizeof(ScsiPassThroughDirect), &SRB, SENSE_SIZE, &returned, 0))
{
Console.WriteLine("\nError reading subchannel data!\n");
if (f != 0)
fConsole.WriteLine(f, "Error reading subchannel data!");
return 0;
}
Deinterleave(buffer);
return;
}
internal static void ClearCache(byte[] buffer, Stream f, byte offset, Stream hDevice, ScsiPassThroughDirect SRB)
{
static uint returned;
for (uint sector = 0; sector < 1000; sector += 10)
{
ZeroMemory(&SRB, sizeof(ScsiPassThroughDirect));
SRB.Length = sizeof(ScsiPassThroughDirect);
SRB.CDBLength = 12;
SRB.DataIn = SCSI_IOCTL_DATA_IN;
SRB.DataTransferLength = 23520;
SRB.TimeOutValue = 30;
SRB.DataBuffer = buffer;
SRB.CDB[0] = RAW_READ_CMD;
SRB.CDB[2] = HIbyte(HIWORD(sector + offset));
SRB.CDB[3] = LObyte(HIWORD(sector + offset));
SRB.CDB[4] = HIbyte(LOWORD(sector + offset));
SRB.CDB[5] = LObyte(LOWORD(sector + offset));
SRB.CDB[8] = 10;
SRB.CDB[9] = 0xF8;
DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SRB, sizeof(ScsiPassThroughDirect), &SRB, SENSE_SIZE, &returned, 0);
if (!DeviceIoControl(hDevice, IOCTL_SCSI_PASS_THROUGH_DIRECT, &SRB, sizeof(ScsiPassThroughDirect), &SRB, SENSE_SIZE, &returned, 0))
{
Console.WriteLine("\nError clearing cache!\n");
if (f != 0)
fConsole.WriteLine(f, "Error clearing cache!");
exit(0);
}
}
return;
}
*/
internal static bool Matrix(byte[] buffer, byte[] buffer2, byte[] buffer3, byte[] buffer4, uint length)
{
for (int i = 0; i < length; i++)
{
if (buffer[i] == buffer2[i])
{
if (buffer[i] == buffer3[i])
continue;
if (buffer[i] == buffer4[i])
continue;
}
else if (buffer[i] == buffer3[i] && buffer[i] == buffer4[i])
{
continue;
}
else if (buffer2[i] == buffer3[i] && buffer2[i] == buffer4[i])
{
continue;
}
return false;
}
return true;
}
internal static void Deinterleave(byte[] buffer)
{
byte[] buffertmp = new byte[12];
for (int i = 0; i < 12; i++)
{
buffertmp[i] |= (byte)((buffer[i * 8] & 0x40) << 1);
buffertmp[i] |= (byte)((buffer[i * 8 + 1] & 0x40));
buffertmp[i] |= (byte)((buffer[i * 8 + 2] & 0x40) >> 1);
buffertmp[i] |= (byte)((buffer[i * 8 + 3] & 0x40) >> 2);
buffertmp[i] |= (byte)((buffer[i * 8 + 4] & 0x40) >> 3);
buffertmp[i] |= (byte)((buffer[i * 8 + 5] & 0x40) >> 4);
buffertmp[i] |= (byte)((buffer[i * 8 + 6] & 0x40) >> 5);
buffertmp[i] |= (byte)((buffer[i * 8 + 7] & 0x40) >> 6);
}
Array.Copy(buffertmp, buffer, 12);
return;
}
internal static bool LibCryptDetect(string subPath, string sbiPath)
{
if (string.IsNullOrWhiteSpace(subPath) || !File.Exists(subPath))
return false;
// Variables
byte[] buffer = new byte[16], sub = new byte[16];//, pregap = 0;
uint sector, psectors = 0, tpos = 0;
// Opening .sub
Stream subfile = File.OpenRead(subPath);
// checking extension
if (Path.GetExtension(subPath).TrimStart('.').ToLowerInvariant() != "sub")
{
Console.WriteLine($"{subPath}: unknown file extension");
return false;
}
// filesize
long size = subfile.Length;
if (size % 96 != 0)
{
Console.WriteLine($"{subfile}: wrong size");
return false;
}
// sbi
Stream sbi = null;
if (sbiPath != null)
{
sbi = File.OpenWrite(sbiPath);
sbi.Write(Encoding.ASCII.GetBytes("SBI\0"), 0, 4);
}
for (sector = 150; sector < ((size / 96) + 150); sector++)
{
subfile.Seek(12, SeekOrigin.Current);
if (subfile.Read(buffer, 0, 12) != 12)
return true;
subfile.Seek(72, SeekOrigin.Current);
// New track
if ((btoi(buffer[1]) == (btoi(sub[1]) + 1)) && (buffer[2] == 0 || buffer[2] == 1))
{
Array.Copy(buffer, sub, 6);
tpos = (uint)((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// New index
else if (btoi(buffer[2]) == (btoi(sub[2]) + 1) && buffer[1] == sub[1])
{
Array.Copy(buffer, 2, sub, 2, 4);
tpos = (uint)((btoi((byte)(buffer[3] * 60)) + btoi(buffer[4])) * 75) + btoi(buffer[5]);
}
// MSF1 [3-5]
else
{
if (sub[2] == 0)
tpos--;
else
tpos++;
sub[3] = itob((byte)(tpos / 60 / 75));
sub[4] = itob((byte)((tpos / 75) % 60));
sub[5] = itob((byte)(tpos % 75));
}
//MSF2 [7-9]
sub[7] = itob((byte)(sector / 60 / 75));
sub[8] = itob((byte)((sector / 75) % 60));
sub[9] = itob((byte)(sector % 75));
// CRC-16 [10-11]
ushort crc = CRC16.Calculate(sub, 0, 10);
sub[10] = (byte)(crc >> 8);
sub[11] = (byte)(crc & 0xFF);
//if (buffer[10] != sub[10] && buffer[11] != sub[11] && (buffer[3] != sub[3] || buffer[7] != sub[7] || buffer[4] != sub[4] || buffer[8] != sub[8] || buffer[5] != sub[5] || buffer[9] != sub[9])) {
//if (buffer[10] != sub[10] || buffer[11] != sub[11] || buffer[3] != sub[3] || buffer[7] != sub[7] || buffer[4] != sub[4] || buffer[8] != sub[8] || buffer[5] != sub[5] || buffer[9] != sub[9]) {
if (!buffer.Take(6).SequenceEqual(sub.Take(6)) || !buffer.Skip(7).Take(5).SequenceEqual(sub.Skip(7).Take(5)))
{
Console.WriteLine($"MSF: {sub[7]:2x}:{sub[8]:2x}:{sub[9]:2x} Q-Data: {buffer[0]:2x}{buffer[1]:2x}{buffer[2]:2x} {buffer[3]:2x}:{buffer[4]:2x}:{buffer[5]:2x} {buffer[6]:2x} {buffer[7]:2x}:{buffer[8]:2x}:{buffer[9]:2x} {buffer[10]:2x}{buffer[11]:2x} xor {crc ^ ((buffer[10] << 8) + buffer[11]):4x} {CRC16.Calculate(buffer, 0, 10) ^ ((buffer[10] << 8) + buffer[11]):4x}");
//Console.WriteLine("\nMSF: %02x:%02x:%02x Q-Data: %02x%02x%02x %02x:%02x:%02x %02x %02x:%02x:%02x %02x%02x", sub[7], sub[8], sub[9], sub[0], sub[1], sub[2], sub[3], sub[4], sub[5], sub[6], sub[7], sub[8], sub[9], sub[10], sub[11]);
if (buffer[3] != sub[3] && buffer[7] != sub[7] && buffer[4] == sub[4] && buffer[8] == sub[8] && buffer[5] == sub[5] && buffer[9] == sub[9])
Console.WriteLine($" P1 xor {buffer[3] ^ sub[3]:2x} {buffer[7] ^ sub[7]:2x}");
else if (buffer[3] == sub[3] && buffer[7] == sub[7] && buffer[4] != sub[4] && buffer[8] != sub[8] && buffer[5] == sub[5] && buffer[9] == sub[9])
Console.WriteLine($" P2 xor {buffer[4] ^ sub[4]:2x} {buffer[8] ^ sub[8]:2x}");
else if (buffer[3] == sub[3] && buffer[7] == sub[7] && buffer[4] == sub[4] && buffer[8] == sub[8] && buffer[5] != sub[5] && buffer[9] != sub[9])
Console.WriteLine($" P3 xor {buffer[5] ^ sub[5]:2x} {buffer[9] ^ sub[9]:2x}");
else
Console.WriteLine(" ?");
Console.WriteLine("\n");
psectors++;
if (sbi != null)
{
sbi.Write(sub, 7, 3);
sbi.Write(new byte[] { 0x01 }, 0, 1);
sbi.Write(buffer, 0, 10);
}
}
}
// }
Console.WriteLine($"Number of modified sectors: {psectors}");
return true;
}
internal static int XorLibCrypt()
{
sbyte b;
byte d;
byte i, a, x;
byte[] sub = new byte[12]
{
0x41, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
ushort crc;
for (i = 0; i < LIBCRYPT_NUM_SECTORS; i++)
{
sub[3] = itob((byte)(lc_addresses[i] / 60 / 75));
sub[4] = itob((byte)((lc_addresses[i] / 75) % 60));
sub[5] = itob((byte)(lc_addresses[i] % 75));
sub[7] = itob((byte)((lc_addresses[i] + 150) / 60 / 75));
sub[8] = itob((byte)(((lc_addresses[i] + 150) / 75) % 60));
sub[9] = itob((byte)((lc_addresses[i] + 150) % 75));
crc = CRC16.Calculate(sub, 0, 10);
sub[10] = (byte)(crc >> 8);
sub[11] = (byte)(crc & 0xFF);
Console.WriteLine($"%u %02x:%02x:%02x", lc_addresses[i], sub[7], sub[8], sub[9]);
Console.WriteLine($" %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x", sub[0], sub[1], sub[2], sub[3], sub[4], sub[5], sub[6], sub[7], sub[8], sub[9], sub[10], sub[11]);
Console.WriteLine($" %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x %02x%02x", lc1_sectors_contents[i * 12], lc1_sectors_contents[(i * 12) + 1], lc1_sectors_contents[(i * 12) + 2], lc1_sectors_contents[(i * 12) + 3], lc1_sectors_contents[(i * 12) + 4], lc1_sectors_contents[(i * 12) + 5], lc1_sectors_contents[(i * 12) + 6], lc1_sectors_contents[(i * 12) + 7], lc1_sectors_contents[(i * 12) + 8], lc1_sectors_contents[(i * 12) + 9], lc1_sectors_contents[(i * 12) + 10], lc1_sectors_contents[(i * 12) + 11]);
d = 0;
for (a = 3; a < 12; a++)
{
x = (byte)(lc1_sectors_contents[(i * 12) + a] ^ sub[a]);
Console.WriteLine($" %x%x%x%x%x%x%x%x", (x >> 7) & 0x1, (x >> 6) & 0x1, (x >> 5) & 0x1, (x >> 4) & 0x1, (x >> 3) & 0x1, (x >> 2) & 0x1, (x >> 1) & 0x1, x & 0x1);
if (x == 0)
continue;
for (b = 7; b >= 0; b--)
{
if (((x >> b) & 0x1) != 0)
{
d = (byte)(d << 1);
d |= (byte)((sub[a] >> b) & 0x1);
}
}
}
Console.WriteLine($" {(d >> 3) & 0x1:x}{(d >> 2) & 0x1:x}{(d >> 1) & 0x1:x}{d & 0x1}");
}
return 1;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,110 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using static psxt001z.Common;
namespace psxt001z
{
public class Scramble
{
private static readonly byte[] sync = new byte[12] { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
public int __main(string[] args)
{
if (args.Length < 2 || args.Length > 3)
{
Console.WriteLine("Syntax: px_p8 [-t] filename");
return 1;
}
int sectors;
if (args.Length == 2 && args[0] == "-t")
{
args[0] = args[1];
sectors = 2352;
}
else
{
sectors = 4704;
}
Stream sector_file;
try
{
sector_file = File.OpenRead(args[1]);
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
return 1;
}
byte[] sector = new byte[sectors];
if (args.Length == 2)
{
uint hex;
for (int i = 0; sector_file.Position < sector_file.Length && i < 3252; i++)
{
byte[] buf = new byte[2];
hex = uint.Parse(Encoding.ASCII.GetString(buf), NumberStyles.HexNumber);
sector[i] = (byte)hex;
}
}
else
{
sector_file.Read(sector, 0, sectors);
}
int offset = MemSearch(sector, sync, sectors, 12);
if (offset == -1)
{
Console.WriteLine("Error searching for sync!");
return 1;
}
Console.WriteLine($"MSF: {sector[offset + 12]:2x}:{sector[offset + 12 + 1]:2x}:{sector[offset + 12 + 2]:2x}");
int shiftRegister = 0x1;
for (int i = 0; i < 3; i++)
{
sector[offset + 12 + i] ^= (byte)(shiftRegister & 0xFF);
for (int j = 0; j < 8; j++)
{
int hibit = ((shiftRegister & 1) ^ ((shiftRegister & 2) >> 1)) << 15;
shiftRegister = (hibit | shiftRegister) >> 1;
}
}
int start_sector = (btoi(sector[offset + 12]) * 60 + btoi(sector[offset + 13])) * 75 + btoi(sector[offset + 14]) - 150;
Console.WriteLine($"MSF: {sector[offset + 12]:2x}:{sector[offset + 12 + 1]:2x}:{sector[offset + 12 + 2]:2x}");
offset -= start_sector * 2352;
Console.WriteLine($"Combined offset: {offset} bytes / {offset / 4} samples");
return 0;
}
/// <summary>
/// Search for a byte array in another
/// </summary>
private int MemSearch(in byte[] buf_where, in byte[] buf_search, int buf_where_len, int buf_search_len)
{
for (int i = 0; i <= buf_where_len - buf_search_len; i++)
{
for (int j = 0; j < buf_search_len; j++)
{
if (buf_where[i + j] != buf_search[j])
break;
if (j + 1 == buf_search_len)
return i;
}
}
return -1;
}
}
}

View File

@@ -1,310 +0,0 @@
using System;
using System.IO;
namespace psxt001z
{
internal class Track
{
#region Properties
/// <summary>
/// Original input path for the track
/// </summary>
private string InputPath { get; set; }
/// <summary>
/// Stream representing the track data
/// </summary>
private Stream InputStream { get; set; }
/// <summary>
/// Output for saving the track data
/// </summary>
private string OutputPath { get; set; }
/// <summary>
/// Starting offset within the file
/// </summary>
private int Start { get; set; }
/// <summary>
/// Size of the input file
/// </summary>
private int Size { get; set; }
/// <summary>
/// CRC-32 of the track data to compare against
/// </summary>
private uint CRC32 { get; set; }
/// <summary>
/// Audio data header
/// </summary>
private byte[] RiffData { get; set; } = new byte[44];
/// <summary>
/// True if the track is audio data
/// </summary>
private bool IsRiff { get; set; }
/// <summary>
/// True if the file is under ~100MB
/// </summary>
private bool SmallFile { get; set; } = false;
/// <summary>
/// True to write out the track data
/// </summary>
private bool SaveTrack { get; set; }
/// <summary>
/// True means '+' or 'p'
/// False means '-' or 'n'
/// Null means neither
/// </summary>
private bool? Mode { get; set; }
/// <summary>
/// Cache for small file data
/// </summary>
private byte[] FileContents { get; set; }
/// <summary>
/// Cached file offset
/// </summary>
private int Offset { get; set; } = 0;
/// <summary>
/// Current file offset
/// </summary>
private int Current { get; set; } = 0;
#endregion
#region Constructor
public Track(string filename, int start, int size, uint crc, bool isRiff = false, bool? mode = null, string output = null)
{
InputPath = filename;
InputStream = File.OpenRead(filename);
OutputPath = output;
Start = start;
Size = size;
CRC32 = crc;
Mode = mode;
IsRiff = isRiff;
SmallFile = Size <= 100_000_000;
SaveTrack = output != null;
Console.WriteLine($"File: {InputPath}\nStart: {Start}\nSize: {Size}\nCRC-32: {CRC32:8x}");
Console.WriteLine();
if (IsRiff)
PopulateRiffData();
if (SmallFile)
CacheFileData();
}
#endregion
#region Functions
public bool FindTrack()
{
// Positive mode
if (Mode == true)
{
if (Current > 20000)
{
Mode = null;
return true;
}
Offset = Current;
Current += 4;
return MatchesCRC();
}
// Negative mode
else if (Mode == false)
{
if (Current > 20000)
{
Mode = null;
return true;
}
Offset = -Current;
Current += 4;
return MatchesCRC();
}
// Neutral mode
else
{
if (Current > 20000)
{
Mode = null;
return true;
}
Offset = Current;
if (MatchesCRC())
{
return true;
}
else
{
Offset = -Current;
Current += 4;
return MatchesCRC();
}
}
}
public bool MatchesCRC()
{
CRC32 calc = new CRC32();
if (SmallFile)
{
if (IsRiff)
calc.ProcessCRC(RiffData, 0, 44);
calc.ProcessCRC(FileContents, (int)(20000 + Offset), (int)Size);
}
else
{
InputStream.Seek(Start + Offset, SeekOrigin.Begin);
if (IsRiff)
calc.ProcessCRC(RiffData, 0, 44);
for (long i = 0; i < Size; i++)
{
byte[] buffer = new byte[1];
if (InputStream.Read(buffer, 0, 1) != 1)
{
buffer[0] = 0x00;
InputStream.Seek(Start + Offset + i + 1, SeekOrigin.Begin);
}
calc.ProcessCRC(buffer, 0, 1);
}
}
Console.Write($"Offset correction {Offset} bytes, {Offset / 4} samples, CRC-32 {calc.m_crc32:8x}");
return (calc.m_crc32 == CRC32);
}
public void Done()
{
if (SmallFile)
FileContents = null;
if (Mode == null)
{
Console.WriteLine();
Console.WriteLine("Can't find offset!");
return;
}
if (SaveTrack)
{
byte[] buffer = new byte[1];
Stream f2 = File.Open(OutputPath, FileMode.Create, FileAccess.ReadWrite);
if (IsRiff)
f2.Write(RiffData, 0, 44);
InputStream.Seek(Start + Offset, SeekOrigin.Begin);
for (long i = 0; i < Size; i++)
{
if (InputStream.Read(buffer, 0, 1) != 1)
{
buffer[0] = 0x00;
InputStream.Seek(Start + Offset + i + 1, SeekOrigin.Begin);
}
f2.Write(buffer, 0, 1);
}
}
Console.WriteLine();
Console.Write("DONE!");
Console.WriteLine();
Console.Write($"Offset correction: {Offset} bytes / {Offset / 4} samples");
}
#endregion
#region Utilities
// TODO: Figure out what this actually does
private void CacheFileData()
{
FileContents = new byte[Size + 40000];
InputStream.Seek(Start - 20000, SeekOrigin.Begin);
for (int i = 0; i < Size + 40000; i++)
{
if (Start + i <= 20000)
InputStream.Seek(Start + i - 20000, SeekOrigin.Begin);
if (InputStream.Read(new byte[1], 0, 1) != 1)
FileContents[i] = 0x00;
}
}
private void PopulateRiffData()
{
RiffData[0] = 0x52;
RiffData[1] = 0x49;
RiffData[2] = 0x46;
RiffData[3] = 0x46;
byte[] temp = BitConverter.GetBytes(Size - 8);
Array.Copy(temp, 0, RiffData, 4, 4);
RiffData[8] = 0x57;
RiffData[9] = 0x41;
RiffData[10] = 0x56;
RiffData[11] = 0x45;
RiffData[12] = 0x66;
RiffData[13] = 0x6D;
RiffData[14] = 0x74;
RiffData[15] = 0x20;
RiffData[16] = 0x10;
RiffData[17] = 0x00;
RiffData[18] = 0x00;
RiffData[19] = 0x00;
RiffData[20] = 0x01;
RiffData[21] = 0x00;
RiffData[22] = 0x02;
RiffData[23] = 0x00;
RiffData[24] = 0x44;
RiffData[25] = 0xAC;
RiffData[26] = 0x00;
RiffData[27] = 0x00;
RiffData[28] = 0x10;
RiffData[29] = 0xB1;
RiffData[30] = 0x02;
RiffData[31] = 0x00;
RiffData[32] = 0x04;
RiffData[33] = 0x00;
RiffData[34] = 0x10;
RiffData[35] = 0x00;
RiffData[36] = 0x64;
RiffData[37] = 0x61;
RiffData[38] = 0x74;
RiffData[39] = 0x61;
temp = BitConverter.GetBytes(Size - 44);
Array.Copy(temp, 0, RiffData, 40, 4);
Size -= 44;
}
#endregion
}
}

View File

@@ -1,22 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Version>0.21-beta1</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- Package Properties -->
<Authors>Matt Nadareski;Dremora</Authors>
<Product>BurnOutSharp</Product>
<Copyright>Copyright (c)2013 Dremora, Copyright (c)2018-2023 Matt Nadareski</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<RepositoryUrl>https://github.com/mnadareski/BurnOutSharp</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
</Project>