mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Update package1 and package2 readers to use SharedRef<T>
This commit is contained in:
parent
2370f76c62
commit
0a8fb8a5c0
6 changed files with 163 additions and 144 deletions
|
@ -13,33 +13,38 @@ namespace LibHac.Boot
|
|||
/// <summary>
|
||||
/// Parses a package2 file and opens the payloads within.
|
||||
/// </summary>
|
||||
public class Package2StorageReader
|
||||
public class Package2StorageReader : IDisposable
|
||||
{
|
||||
private const int KernelPayloadIndex = 0;
|
||||
private const int IniPayloadIndex = 1;
|
||||
|
||||
private IStorage _storage;
|
||||
private SharedRef<IStorage> _storage;
|
||||
private Package2Header _header;
|
||||
private KeySet _keySet;
|
||||
private Crypto.AesKey _key;
|
||||
|
||||
public ref readonly Package2Header Header => ref _header;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_storage.Destroy();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the <see cref="Package2StorageReader"/>.
|
||||
/// </summary>
|
||||
/// <param name="keySet">The keyset to use for decrypting the package.</param>
|
||||
/// <param name="storage">An <see cref="IStorage"/> of the encrypted package2.</param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
public Result Initialize(KeySet keySet, IStorage storage)
|
||||
public Result Initialize(KeySet keySet, in SharedRef<IStorage> storage)
|
||||
{
|
||||
Result rc = storage.Read(0, SpanHelpers.AsByteSpan(ref _header));
|
||||
Result rc = storage.Get.Read(0, SpanHelpers.AsByteSpan(ref _header));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
_key = keySet.Package2Keys[_header.Meta.KeyGeneration];
|
||||
DecryptHeader(_key, ref _header.Meta, ref _header.Meta);
|
||||
|
||||
_storage = storage;
|
||||
_storage.SetByCopy(in storage);
|
||||
_keySet = keySet;
|
||||
return Result.Success;
|
||||
}
|
||||
|
@ -47,14 +52,12 @@ namespace LibHac.Boot
|
|||
/// <summary>
|
||||
/// Opens a decrypted <see cref="IStorage"/> of one of the payloads in the package.
|
||||
/// </summary>
|
||||
/// <param name="payloadStorage">If the method returns successfully, contains an <see cref="IStorage"/>
|
||||
/// <param name="outPayloadStorage">If the method returns successfully, contains an <see cref="IStorage"/>
|
||||
/// of the specified payload.</param>
|
||||
/// <param name="index">The index of the payload to get. Must me less than <see cref="Package2Header.PayloadCount"/></param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
public Result OpenPayload(out IStorage payloadStorage, int index)
|
||||
public Result OpenPayload(ref UniqueRef<IStorage> outPayloadStorage, int index)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out payloadStorage);
|
||||
|
||||
if ((uint)index >= Package2Header.PayloadCount)
|
||||
return ResultLibHac.ArgumentOutOfRange.Log();
|
||||
|
||||
|
@ -65,53 +68,52 @@ namespace LibHac.Boot
|
|||
|
||||
if (size == 0)
|
||||
{
|
||||
payloadStorage = payloadSubStorage;
|
||||
outPayloadStorage.Reset(payloadSubStorage);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
byte[] iv = _header.Meta.PayloadIvs[index].Bytes.ToArray();
|
||||
payloadStorage = new CachedStorage(new Aes128CtrStorage(payloadSubStorage, _key.DataRo.ToArray(), iv, true), 0x4000, 1, true);
|
||||
outPayloadStorage.Reset(new CachedStorage(new Aes128CtrStorage(payloadSubStorage, _key.DataRo.ToArray(), iv, true), 0x4000, 1, true));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an <see cref="IStorage"/> of the kernel payload.
|
||||
/// </summary>
|
||||
/// <param name="kernelStorage">If the method returns successfully, contains an <see cref="IStorage"/>
|
||||
/// <param name="outKernelStorage">If the method returns successfully, contains an <see cref="IStorage"/>
|
||||
/// of the kernel payload.</param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
public Result OpenKernel(out IStorage kernelStorage)
|
||||
public Result OpenKernel(ref UniqueRef<IStorage> outKernelStorage)
|
||||
{
|
||||
return OpenPayload(out kernelStorage, KernelPayloadIndex);
|
||||
return OpenPayload(ref outKernelStorage, KernelPayloadIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an <see cref="IStorage"/> of the initial process binary. If the binary is embedded in
|
||||
/// the kernel, this method will attempt to locate and return the embedded binary.
|
||||
/// </summary>
|
||||
/// <param name="iniStorage">If the method returns successfully, contains an <see cref="IStorage"/>
|
||||
/// <param name="outIniStorage">If the method returns successfully, contains an <see cref="IStorage"/>
|
||||
/// of the initial process binary.</param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
public Result OpenIni(out IStorage iniStorage)
|
||||
public Result OpenIni(ref UniqueRef<IStorage> outIniStorage)
|
||||
{
|
||||
if (HasIniPayload())
|
||||
{
|
||||
return OpenPayload(out iniStorage, IniPayloadIndex);
|
||||
return OpenPayload(ref outIniStorage, IniPayloadIndex);
|
||||
}
|
||||
|
||||
// Ini is embedded in the kernel
|
||||
UnsafeHelpers.SkipParamInit(out iniStorage);
|
||||
|
||||
Result rc = OpenKernel(out IStorage kernelStorage);
|
||||
using var kernelStorage = new UniqueRef<IStorage>();
|
||||
Result rc = OpenKernel(ref kernelStorage.Ref());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!IniExtract.TryGetIni1Offset(out int offset, out int size, kernelStorage))
|
||||
if (!IniExtract.TryGetIni1Offset(out int offset, out int size, kernelStorage.Get))
|
||||
{
|
||||
// Unable to find the ini. Could be a new, unsupported layout.
|
||||
return ResultLibHac.NotImplemented.Log();
|
||||
}
|
||||
|
||||
iniStorage = new SubStorage(kernelStorage, offset, size);
|
||||
outIniStorage.Reset(new SubStorage(kernelStorage.Release(), offset, size));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -140,7 +142,7 @@ namespace LibHac.Boot
|
|||
Unsafe.SkipInit(out Package2Meta meta);
|
||||
Span<byte> metaBytes = SpanHelpers.AsByteSpan(ref meta);
|
||||
|
||||
Result rc = _storage.Read(Package2Header.SignatureSize, metaBytes);
|
||||
Result rc = _storage.Get.Read(Package2Header.SignatureSize, metaBytes);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return _header.VerifySignature(_keySet.Package2SigningKeyParams.Modulus, metaBytes);
|
||||
|
@ -209,10 +211,10 @@ namespace LibHac.Boot
|
|||
/// <summary>
|
||||
/// Opens a decrypted <see cref="IStorage"/> of the entire package.
|
||||
/// </summary>
|
||||
/// <param name="packageStorage">If the method returns successfully, contains a decrypted
|
||||
/// <param name="outPackageStorage">If the method returns successfully, contains a decrypted
|
||||
/// <see cref="IStorage"/> of the package.</param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
public Result OpenDecryptedPackage(out IStorage packageStorage)
|
||||
public Result OpenDecryptedPackage(ref UniqueRef<IStorage> outPackageStorage)
|
||||
{
|
||||
var storages = new List<IStorage>(4);
|
||||
|
||||
|
@ -239,17 +241,14 @@ namespace LibHac.Boot
|
|||
if (_header.Meta.PayloadSizes[i] == 0)
|
||||
continue;
|
||||
|
||||
Result rc = OpenPayload(out IStorage payloadStorage, i);
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out packageStorage);
|
||||
return rc;
|
||||
}
|
||||
using var payloadStorage = new UniqueRef<IStorage>();
|
||||
Result rc = OpenPayload(ref payloadStorage.Ref(), i);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
storages.Add(payloadStorage);
|
||||
storages.Add(payloadStorage.Release());
|
||||
}
|
||||
|
||||
packageStorage = new ConcatenationStorage(storages, true);
|
||||
outPackageStorage.Reset(new ConcatenationStorage(storages, true));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
|
@ -6,32 +7,37 @@ using LibHac.Fs;
|
|||
|
||||
namespace LibHac.Kernel
|
||||
{
|
||||
public class InitialProcessBinaryReader
|
||||
public class InitialProcessBinaryReader : IDisposable
|
||||
{
|
||||
internal const uint ExpectedMagic = 0x31494E49; // INI1
|
||||
private const int MaxProcessCount = 80;
|
||||
|
||||
private IStorage _storage;
|
||||
private SharedRef<IStorage> _storage;
|
||||
private IniHeader _header;
|
||||
private (int offset, int size)[] _offsets;
|
||||
|
||||
public ref readonly IniHeader Header => ref _header;
|
||||
public int ProcessCount => _header.ProcessCount;
|
||||
|
||||
public Result Initialize(IStorage binaryStorage)
|
||||
public void Dispose()
|
||||
{
|
||||
if (binaryStorage is null)
|
||||
_storage.Destroy();
|
||||
}
|
||||
|
||||
public Result Initialize(in SharedRef<IStorage> binaryStorage)
|
||||
{
|
||||
if (!binaryStorage.HasValue)
|
||||
return ResultLibHac.NullArgument.Log();
|
||||
|
||||
// Verify there's enough data to read the header
|
||||
Result rc = binaryStorage.GetSize(out long iniSize);
|
||||
Result rc = binaryStorage.Get.GetSize(out long iniSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (iniSize < Unsafe.SizeOf<IniHeader>())
|
||||
return ResultLibHac.InvalidIniFileSize.Log();
|
||||
|
||||
// Read the INI file header and validate some of its values.
|
||||
rc = binaryStorage.Read(0, SpanHelpers.AsByteSpan(ref _header));
|
||||
rc = binaryStorage.Get.Read(0, SpanHelpers.AsByteSpan(ref _header));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (_header.Magic != ExpectedMagic)
|
||||
|
@ -45,36 +51,40 @@ namespace LibHac.Kernel
|
|||
rc = GetKipOffsets(out _offsets, binaryStorage, _header.ProcessCount);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
_storage = binaryStorage;
|
||||
_storage.SetByCopy(in binaryStorage);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenKipStorage(out IStorage storage, int index)
|
||||
public Result OpenKipStorage(ref UniqueRef<IStorage> outStorage, int index)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out storage);
|
||||
|
||||
if ((uint)index >= _header.ProcessCount)
|
||||
return ResultLibHac.ArgumentOutOfRange.Log();
|
||||
|
||||
(int offset, int size) range = _offsets[index];
|
||||
storage = new SubStorage(_storage, range.offset, range.size);
|
||||
outStorage.Reset(new SubStorage(in _storage, range.offset, range.size));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private static Result GetKipOffsets(out (int offset, int size)[] kipOffsets, IStorage iniStorage,
|
||||
private static Result GetKipOffsets(out (int offset, int size)[] kipOffsets, in SharedRef<IStorage> iniStorage,
|
||||
int processCount)
|
||||
{
|
||||
Assert.SdkRequiresLessEqual(processCount, MaxProcessCount);
|
||||
|
||||
UnsafeHelpers.SkipParamInit(out kipOffsets);
|
||||
|
||||
Result rc = iniStorage.Get.GetSize(out long iniStorageSize);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
var offsets = new (int offset, int size)[processCount];
|
||||
int offset = Unsafe.SizeOf<IniHeader>();
|
||||
var kipReader = new KipReader();
|
||||
using var kipReader = new KipReader();
|
||||
|
||||
for (int i = 0; i < processCount; i++)
|
||||
{
|
||||
Result rc = kipReader.Initialize(new SubStorage(iniStorage, offset, int.MaxValue));
|
||||
using var kipStorage =
|
||||
new SharedRef<IStorage>(new SubStorage(in iniStorage, offset, iniStorageSize - offset));
|
||||
|
||||
rc = kipReader.Initialize(in kipStorage);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
int kipSize = kipReader.GetFileSize();
|
||||
|
|
|
@ -8,9 +8,9 @@ using LibHac.Fs;
|
|||
|
||||
namespace LibHac.Kernel
|
||||
{
|
||||
public class KipReader
|
||||
public class KipReader : IDisposable
|
||||
{
|
||||
private IStorage KipStorage { get; set; }
|
||||
private SharedRef<IStorage> _kipStorage;
|
||||
|
||||
private KipHeader _header;
|
||||
|
||||
|
@ -34,48 +34,51 @@ namespace LibHac.Kernel
|
|||
public int AffinityMask => _header.AffinityMask;
|
||||
public int StackSize => _header.StackSize;
|
||||
|
||||
public Result Initialize(IStorage kipData)
|
||||
public void Dispose()
|
||||
{
|
||||
if (kipData is null)
|
||||
_kipStorage.Destroy();
|
||||
}
|
||||
|
||||
public Result Initialize(in SharedRef<IStorage> kipData)
|
||||
{
|
||||
if (!kipData.HasValue)
|
||||
return ResultLibHac.NullArgument.Log();
|
||||
|
||||
// Verify there's enough data to read the header
|
||||
Result rc = kipData.GetSize(out long kipSize);
|
||||
Result rc = kipData.Get.GetSize(out long kipSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (kipSize < Unsafe.SizeOf<KipHeader>())
|
||||
return ResultLibHac.InvalidKipFileSize.Log();
|
||||
|
||||
rc = kipData.Read(0, SpanHelpers.AsByteSpan(ref _header));
|
||||
rc = kipData.Get.Read(0, SpanHelpers.AsByteSpan(ref _header));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (!_header.IsValid)
|
||||
return ResultLibHac.InvalidKipMagic.Log();
|
||||
|
||||
KipStorage = kipData;
|
||||
_kipStorage.SetByCopy(in kipData);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw input KIP file.
|
||||
/// </summary>
|
||||
/// <param name="kipData">If the operation returns successfully, an <see cref="IStorage"/>
|
||||
/// <param name="outKipData">If the operation returns successfully, an <see cref="IStorage"/>
|
||||
/// containing the KIP data.</param>
|
||||
/// <returns>The <see cref="Result"/> of the operation.</returns>
|
||||
public Result GetRawData(out IStorage kipData)
|
||||
public Result GetRawData(ref UniqueRef<IStorage> outKipData)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out kipData);
|
||||
|
||||
int kipFileSize = GetFileSize();
|
||||
|
||||
Result rc = KipStorage.GetSize(out long inputFileSize);
|
||||
Result rc = _kipStorage.Get.GetSize(out long inputFileSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Verify the input KIP file isn't truncated
|
||||
if (inputFileSize < kipFileSize)
|
||||
return ResultLibHac.InvalidKipFileSize.Log();
|
||||
|
||||
kipData = new SubStorage(KipStorage, 0, kipFileSize);
|
||||
outKipData.Reset(new SubStorage(in _kipStorage, 0, kipFileSize));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
@ -149,14 +152,14 @@ namespace LibHac.Kernel
|
|||
int offset = CalculateSegmentOffset((int)segment);
|
||||
|
||||
// Verify the segment offset is in-range
|
||||
rc = KipStorage.GetSize(out long kipSize);
|
||||
rc = _kipStorage.Get.GetSize(out long kipSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (kipSize < offset + segmentHeader.FileSize)
|
||||
return ResultLibHac.InvalidKipFileSize.Log();
|
||||
|
||||
// Read the segment data.
|
||||
rc = KipStorage.Read(offset, buffer.Slice(0, segmentHeader.FileSize));
|
||||
rc = _kipStorage.Get.Read(offset, buffer.Slice(0, segmentHeader.FileSize));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Decompress if necessary.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Kernel;
|
||||
|
@ -200,8 +201,10 @@ namespace LibHac
|
|||
|
||||
for (int i = 0; i < KipCount; i++)
|
||||
{
|
||||
using var sharedStorage = new SharedRef<IStorage>(Storage.Slice(offset));
|
||||
|
||||
Kips[i] = new KipReader();
|
||||
Kips[i].Initialize(Storage.Slice(offset)).ThrowIfFailure();
|
||||
Kips[i].Initialize(in sharedStorage).ThrowIfFailure();
|
||||
|
||||
offset += Kips[i].GetFileSize();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.IO;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Kernel;
|
||||
|
@ -9,50 +10,50 @@ namespace hactoolnet
|
|||
{
|
||||
public static void ProcessKip1(Context ctx)
|
||||
{
|
||||
using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
|
||||
using var file = new SharedRef<IStorage>(new LocalStorage(ctx.Options.InFile, FileAccess.Read));
|
||||
|
||||
using var kip = new KipReader();
|
||||
kip.Initialize(in file).ThrowIfFailure();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ctx.Options.UncompressedOut))
|
||||
{
|
||||
var kip = new KipReader();
|
||||
kip.Initialize(file).ThrowIfFailure();
|
||||
byte[] uncompressed = new byte[kip.GetUncompressedSize()];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ctx.Options.UncompressedOut))
|
||||
{
|
||||
byte[] uncompressed = new byte[kip.GetUncompressedSize()];
|
||||
kip.ReadUncompressedKip(uncompressed).ThrowIfFailure();
|
||||
|
||||
kip.ReadUncompressedKip(uncompressed).ThrowIfFailure();
|
||||
|
||||
File.WriteAllBytes(ctx.Options.UncompressedOut, uncompressed);
|
||||
}
|
||||
File.WriteAllBytes(ctx.Options.UncompressedOut, uncompressed);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ProcessIni1(Context ctx)
|
||||
{
|
||||
using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
|
||||
{
|
||||
string outDir = ctx.Options.OutDir;
|
||||
using var file = new SharedRef<IStorage>(new LocalStorage(ctx.Options.InFile, FileAccess.Read));
|
||||
|
||||
if (outDir != null)
|
||||
{
|
||||
ExtractIni1(file, outDir);
|
||||
}
|
||||
string outDir = ctx.Options.OutDir;
|
||||
|
||||
if (outDir != null)
|
||||
{
|
||||
ExtractIni1(in file, outDir);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExtractIni1(IStorage iniStorage, string outDir)
|
||||
public static void ExtractIni1(in SharedRef<IStorage> iniStorage, string outDir)
|
||||
{
|
||||
var ini1 = new InitialProcessBinaryReader();
|
||||
using var ini1 = new InitialProcessBinaryReader();
|
||||
ini1.Initialize(iniStorage).ThrowIfFailure();
|
||||
|
||||
Directory.CreateDirectory(outDir);
|
||||
var kipReader = new KipReader();
|
||||
using var kipReader = new KipReader();
|
||||
|
||||
for (int i = 0; i < ini1.ProcessCount; i++)
|
||||
{
|
||||
ini1.OpenKipStorage(out IStorage kipStorage, i).ThrowIfFailure();
|
||||
using var kipStorage = new UniqueRef<IStorage>();
|
||||
ini1.OpenKipStorage(ref kipStorage.Ref(), i).ThrowIfFailure();
|
||||
|
||||
kipReader.Initialize(kipStorage).ThrowIfFailure();
|
||||
using SharedRef<IStorage> sharedKipStorage = SharedRef<IStorage>.Create(ref kipStorage.Ref());
|
||||
kipReader.Initialize(in sharedKipStorage).ThrowIfFailure();
|
||||
|
||||
kipStorage.WriteAllBytes(System.IO.Path.Combine(outDir, $"{kipReader.Name.ToString()}.kip1"));
|
||||
sharedKipStorage.Get.WriteAllBytes(System.IO.Path.Combine(outDir, $"{kipReader.Name.ToString()}.kip1"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,43 +15,42 @@ namespace hactoolnet
|
|||
{
|
||||
public static void ProcessPk11(Context ctx)
|
||||
{
|
||||
using (var file = new SharedRef<IStorage>(new LocalStorage(ctx.Options.InFile, FileAccess.Read)))
|
||||
using var file = new SharedRef<IStorage>(new LocalStorage(ctx.Options.InFile, FileAccess.Read));
|
||||
|
||||
var package1 = new LibHac.Boot.Package1();
|
||||
package1.Initialize(ctx.KeySet, in file).ThrowIfFailure();
|
||||
|
||||
ctx.Logger.LogMessage(package1.Print());
|
||||
|
||||
string outDir = ctx.Options.OutDir;
|
||||
|
||||
if (package1.IsDecrypted && outDir != null)
|
||||
{
|
||||
var package1 = new LibHac.Boot.Package1();
|
||||
package1.Initialize(ctx.KeySet, in file).ThrowIfFailure();
|
||||
Directory.CreateDirectory(outDir);
|
||||
|
||||
ctx.Logger.LogMessage(package1.Print());
|
||||
IStorage decryptedStorage = package1.OpenDecryptedPackage1Storage();
|
||||
|
||||
string outDir = ctx.Options.OutDir;
|
||||
WriteFile(decryptedStorage, "Decrypted.bin");
|
||||
WriteFile(package1.OpenWarmBootStorage(), "Warmboot.bin");
|
||||
WriteFile(package1.OpenNxBootloaderStorage(), "NX_Bootloader.bin");
|
||||
WriteFile(package1.OpenSecureMonitorStorage(), "Secure_Monitor.bin");
|
||||
|
||||
if (package1.IsDecrypted && outDir != null)
|
||||
if (package1.IsMariko)
|
||||
{
|
||||
Directory.CreateDirectory(outDir);
|
||||
WriteFile(package1.OpenDecryptedWarmBootStorage(), "Warmboot_Decrypted.bin");
|
||||
|
||||
IStorage decryptedStorage = package1.OpenDecryptedPackage1Storage();
|
||||
var marikoOemLoader = new SubStorage(decryptedStorage, Unsafe.SizeOf<Package1MarikoOemHeader>(),
|
||||
package1.MarikoOemHeader.Size);
|
||||
|
||||
WriteFile(decryptedStorage, "Decrypted.bin");
|
||||
WriteFile(package1.OpenWarmBootStorage(), "Warmboot.bin");
|
||||
WriteFile(package1.OpenNxBootloaderStorage(), "NX_Bootloader.bin");
|
||||
WriteFile(package1.OpenSecureMonitorStorage(), "Secure_Monitor.bin");
|
||||
|
||||
if (package1.IsMariko)
|
||||
{
|
||||
WriteFile(package1.OpenDecryptedWarmBootStorage(), "Warmboot_Decrypted.bin");
|
||||
|
||||
var marikoOemLoader = new SubStorage(decryptedStorage, Unsafe.SizeOf<Package1MarikoOemHeader>(),
|
||||
package1.MarikoOemHeader.Size);
|
||||
|
||||
WriteFile(marikoOemLoader, "Mariko_OEM_Bootloader.bin");
|
||||
}
|
||||
WriteFile(marikoOemLoader, "Mariko_OEM_Bootloader.bin");
|
||||
}
|
||||
}
|
||||
|
||||
void WriteFile(IStorage storage, string filename)
|
||||
{
|
||||
string path = Path.Combine(outDir, filename);
|
||||
ctx.Logger.LogMessage($"Writing {path}...");
|
||||
storage.WriteAllBytes(path, ctx.Logger);
|
||||
}
|
||||
void WriteFile(IStorage storage, string filename)
|
||||
{
|
||||
string path = Path.Combine(outDir, filename);
|
||||
ctx.Logger.LogMessage($"Writing {path}...");
|
||||
storage.WriteAllBytes(path, ctx.Logger);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,43 +104,47 @@ namespace hactoolnet
|
|||
|
||||
public static void ProcessPk21(Context ctx)
|
||||
{
|
||||
using (var file = new CachedStorage(new LocalStorage(ctx.Options.InFile, FileAccess.Read), 0x4000, 4, false))
|
||||
using var file = new SharedRef<IStorage>(new CachedStorage(new LocalStorage(ctx.Options.InFile, FileAccess.Read), 0x4000, 4, false));
|
||||
|
||||
using var package2 = new Package2StorageReader();
|
||||
package2.Initialize(ctx.KeySet, in file).ThrowIfFailure();
|
||||
|
||||
ctx.Logger.LogMessage(package2.Print());
|
||||
|
||||
string outDir = ctx.Options.OutDir;
|
||||
string iniDir = ctx.Options.Ini1OutDir;
|
||||
|
||||
if (iniDir == null && ctx.Options.ExtractIni1)
|
||||
{
|
||||
var package2 = new Package2StorageReader();
|
||||
package2.Initialize(ctx.KeySet, file).ThrowIfFailure();
|
||||
iniDir = Path.Combine(outDir, "INI1");
|
||||
}
|
||||
|
||||
ctx.Logger.LogMessage(package2.Print());
|
||||
if (outDir != null)
|
||||
{
|
||||
Directory.CreateDirectory(outDir);
|
||||
|
||||
string outDir = ctx.Options.OutDir;
|
||||
string iniDir = ctx.Options.Ini1OutDir;
|
||||
using var kernelStorage = new UniqueRef<IStorage>();
|
||||
package2.OpenPayload(ref kernelStorage.Ref(), 0).ThrowIfFailure();
|
||||
kernelStorage.Get.WriteAllBytes(Path.Combine(outDir, "Kernel.bin"), ctx.Logger);
|
||||
|
||||
if (iniDir == null && ctx.Options.ExtractIni1)
|
||||
{
|
||||
iniDir = Path.Combine(outDir, "INI1");
|
||||
}
|
||||
using var ini1Storage = new UniqueRef<IStorage>();
|
||||
package2.OpenIni(ref ini1Storage.Ref()).ThrowIfFailure();
|
||||
ini1Storage.Get.WriteAllBytes(Path.Combine(outDir, "INI1.bin"), ctx.Logger);
|
||||
|
||||
if (outDir != null)
|
||||
{
|
||||
Directory.CreateDirectory(outDir);
|
||||
using var decPackageStorage = new UniqueRef<IStorage>();
|
||||
package2.OpenDecryptedPackage(ref decPackageStorage.Ref()).ThrowIfFailure();
|
||||
decPackageStorage.Get.WriteAllBytes(Path.Combine(outDir, "Decrypted.bin"), ctx.Logger);
|
||||
}
|
||||
|
||||
package2.OpenPayload(out IStorage kernelStorage, 0).ThrowIfFailure();
|
||||
kernelStorage.WriteAllBytes(Path.Combine(outDir, "Kernel.bin"), ctx.Logger);
|
||||
if (iniDir != null)
|
||||
{
|
||||
Directory.CreateDirectory(iniDir);
|
||||
|
||||
package2.OpenIni(out IStorage ini1Storage).ThrowIfFailure();
|
||||
ini1Storage.WriteAllBytes(Path.Combine(outDir, "INI1.bin"), ctx.Logger);
|
||||
using var ini1Storage = new UniqueRef<IStorage>();
|
||||
package2.OpenIni(ref ini1Storage.Ref()).ThrowIfFailure();
|
||||
|
||||
package2.OpenDecryptedPackage(out IStorage decPackageStorage).ThrowIfFailure();
|
||||
decPackageStorage.WriteAllBytes(Path.Combine(outDir, "Decrypted.bin"), ctx.Logger);
|
||||
}
|
||||
|
||||
if (iniDir != null)
|
||||
{
|
||||
Directory.CreateDirectory(iniDir);
|
||||
|
||||
package2.OpenIni(out IStorage ini1Storage).ThrowIfFailure();
|
||||
|
||||
ProcessKip.ExtractIni1(ini1Storage, iniDir);
|
||||
}
|
||||
using SharedRef<IStorage> sharedIni1Storage = SharedRef<IStorage>.Create(ref ini1Storage.Ref());
|
||||
ProcessKip.ExtractIni1(in sharedIni1Storage, iniDir);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue