mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Support opening the INI1 from a v17.0.0+ kernel
This commit is contained in:
parent
c03e4d3f71
commit
ae9ea9b7f6
1 changed files with 62 additions and 31 deletions
|
@ -26,42 +26,73 @@ public static class IniExtract
|
||||||
|
|
||||||
uint kernelSize = (uint)kernelSizeLong;
|
uint kernelSize = (uint)kernelSizeLong;
|
||||||
|
|
||||||
using (var array = new RentedArray<byte>(0x1000 + Unsafe.SizeOf<KernelMap>()))
|
// .crt0 is located at the start of the kernel pre-17.0.0
|
||||||
{
|
// 17.0.0+ kernels start with a "b crt0" branch instruction followed by 0x7FC of zeros
|
||||||
// The kernel map should be in the first 0x1000 bytes
|
// The kernel map in this case will contain offsets relative to itself rather than to the start of the kernel
|
||||||
if (kernelStorage.Read(0, array.Span).IsFailure())
|
int crt0Offset = 0;
|
||||||
return false;
|
bool isMapAddressRelativeToItself = false;
|
||||||
|
|
||||||
ref byte start = ref array.Span[0];
|
// Check if the first 4 bytes of the kernel is a branch instruction, and get the target if it is
|
||||||
|
ulong inst = 0;
|
||||||
// Search every 4 bytes for a valid kernel map
|
if (kernelStorage.Read(0, SpanHelpers.AsByteSpan(ref inst)).IsFailure())
|
||||||
for (int i = 0; i < 0x1000; i += sizeof(int))
|
|
||||||
{
|
|
||||||
ref KernelMap map = ref Unsafe.As<byte, KernelMap>(ref Unsafe.Add(ref start, i));
|
|
||||||
|
|
||||||
if (IsValidKernelMap(in map, kernelSize))
|
|
||||||
{
|
|
||||||
// Verify the ini header at the offset in the found map
|
|
||||||
var header = new InitialProcessBinaryReader.IniHeader();
|
|
||||||
|
|
||||||
if (kernelStorage.Read(map.Ini1StartOffset, SpanHelpers.AsByteSpan(ref header)).IsFailure())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (header.Magic != InitialProcessBinaryReader.ExpectedMagic)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
offset = (int)map.Ini1StartOffset;
|
|
||||||
size = header.Size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if ((inst & 0xFFFFFFFFFF000000) == 0x0000000014000000)
|
||||||
|
{
|
||||||
|
crt0Offset = (int)((inst & 0x00FFFFFF) << 2);
|
||||||
|
isMapAddressRelativeToItself = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using var array = new RentedArray<byte>(0x1000 + Unsafe.SizeOf<KernelMap>());
|
||||||
|
if (kernelStorage.Read(crt0Offset, array.Span).IsFailure())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ref byte start = ref MemoryMarshal.GetReference(array.Span);
|
||||||
|
|
||||||
|
// Search every 4 bytes for a valid kernel map
|
||||||
|
for (int i = 0; i < 0x1000 - Unsafe.SizeOf<KernelMap>(); i += sizeof(int))
|
||||||
|
{
|
||||||
|
ref KernelMap map = ref Unsafe.As<byte, KernelMap>(ref Unsafe.Add(ref start, i));
|
||||||
|
uint mapOffsetAdjustment = isMapAddressRelativeToItself ? (uint)(crt0Offset + i) : 0;
|
||||||
|
|
||||||
|
if (IsValidKernelMap(in map, kernelSize, mapOffsetAdjustment))
|
||||||
|
{
|
||||||
|
// Verify the ini header at the offset in the found map
|
||||||
|
var header = new InitialProcessBinaryReader.IniHeader();
|
||||||
|
|
||||||
|
if (kernelStorage.Read(map.Ini1StartOffset + mapOffsetAdjustment, SpanHelpers.AsByteSpan(ref header)).IsFailure())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (header.Magic != InitialProcessBinaryReader.ExpectedMagic)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
offset = (int)(map.Ini1StartOffset + mapOffsetAdjustment);
|
||||||
|
size = header.Size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsValidKernelMap(in KernelMap map, uint maxSize)
|
private static bool IsValidKernelMap(in KernelMap rawMap, uint maxSize, uint adj)
|
||||||
{
|
{
|
||||||
|
KernelMap adjustedMap = rawMap;
|
||||||
|
adjustedMap.TextStartOffset += adj;
|
||||||
|
adjustedMap.TextEndOffset += adj;
|
||||||
|
adjustedMap.RodataStartOffset += adj;
|
||||||
|
adjustedMap.RodataEndOffset += adj;
|
||||||
|
adjustedMap.DataStartOffset += adj;
|
||||||
|
adjustedMap.DataEndOffset += adj;
|
||||||
|
adjustedMap.BssStartOffset += adj;
|
||||||
|
adjustedMap.BssEndOffset += adj;
|
||||||
|
adjustedMap.Ini1StartOffset += adj;
|
||||||
|
adjustedMap.DynamicOffset += adj;
|
||||||
|
adjustedMap.InitArrayStartOffset += adj;
|
||||||
|
adjustedMap.InitArrayStartOffset += adj;
|
||||||
|
|
||||||
|
ref KernelMap map = ref adjustedMap;
|
||||||
|
|
||||||
if (map.TextStartOffset != 0) return false;
|
if (map.TextStartOffset != 0) return false;
|
||||||
if (map.TextStartOffset >= map.TextEndOffset) return false;
|
if (map.TextStartOffset >= map.TextEndOffset) return false;
|
||||||
if ((map.TextEndOffset & 0xFFF) != 0) return false;
|
if ((map.TextEndOffset & 0xFFF) != 0) return false;
|
||||||
|
|
Loading…
Reference in a new issue