add support for relr relocations in nso loader

This commit is contained in:
LukeFZ
2026-03-21 01:30:29 +01:00
parent 3fb00b1b86
commit 8e29293f8e
2 changed files with 95 additions and 1 deletions

View File

@@ -136,6 +136,9 @@ public enum DynamicTag : long
DT_SYMENT = 0xb,
DT_INIT = 0xC,
DT_FINI = 0xD,
DT_SONAME = 0xe,
DT_RPATH = 0xf,
DT_SYMBOLIC = 0x10,
DT_REL = 0x11,
DT_RELSZ = 0x12,
DT_RELENT = 0x13,
@@ -152,11 +155,19 @@ public enum DynamicTag : long
DT_FLAGS = 0x1E,
DT_PREINIT_ARRAY = 0x20,
DT_PREINIT_ARRAYSZ = 0x21,
DT_MAXPOSTAGS = 0x22,
DT_RELRSZ = 0x23,
DT_RELR = 0x24,
DT_RELRENT = 0x25,
DT_LOOS = 0x6000000D,
DT_ANDROID_REL = DT_LOOS + 2,
DT_ANDROID_RELSZ = DT_LOOS + 3,
DT_ANDROID_RELA = DT_LOOS + 4,
DT_ANDROID_RELASZ = DT_LOOS + 5
DT_ANDROID_RELASZ = DT_LOOS + 5,
DT_ANDROID_RELR = 0x6fffe000,
DT_ANDROID_RELRSZ = 0x6fffe001,
DT_ANDROID_RELRENT = 0x6fffe003,
DT_ANDROID_RELRCOUNT = 0x6fffe005,
}
public struct SymbolEntry : IReadable

View File

@@ -8,6 +8,8 @@ using System.Collections.Frozen;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
using VersionedSerialization;
namespace Il2CppInspector;
@@ -84,6 +86,17 @@ internal class ByteArrayBackingBuffer : IDisposable
.ReadPrimitive<T>();
}
public ImmutableArray<T> ReadPrimitiveArray<T>(ulong address, long count) where T : unmanaged
{
Debug.Assert(Initialized);
return IsLittleEndian
? Reader.LittleEndian(Data, TranslateVaToRva(address), new ReaderConfig(Is32Bit))
.ReadPrimitiveArray<T>(count)
: Reader.BigEndian(Data, TranslateVaToRva(address), new ReaderConfig(Is32Bit))
.ReadPrimitiveArray<T>(count);
}
public void WriteNUInt(ulong address, ulong value)
{
var region = Data.Slice(TranslateVaToRva(address), Is32Bit ? sizeof(uint) : sizeof(ulong));
@@ -269,6 +282,13 @@ public class NsoReader : FileFormatStream<NsoReader>
relocationRegions.Add((jmprelAddress, jmprelAddress + size));
}
if (_dynamicEntries.TryGetValue(DynamicTag.DT_RELR, out var relrAddress))
{
var size = _dynamicEntries[DynamicTag.DT_RELRSZ];
ApplyRelrRelocations(relrAddress, size);
relocationRegions.Add((relrAddress, relrAddress + size));
}
_relocationEntryRegions = [.. relocationRegions];
// Clear out relocation sections in memory so searching is faster
@@ -339,6 +359,64 @@ public class NsoReader : FileFormatStream<NsoReader>
return [.. _mappedExecutable.ReadObjectArray<RelaEntry>(ImageBase + rva, checked((int)entryCount), default)
.Select<RelaEntry, (ulong, ulong, long?)>(x => (x.Offset, x.Info, x.Addend))];
}
void ApplyRelrRelocations(ulong address, ulong size)
{
if (Is32Bit)
{
ApplyRelrRelocationsImpl<uint>();
}
else
{
ApplyRelrRelocationsImpl<ulong>();
}
return;
void ApplyRelrRelocationsImpl<T>() where T : unmanaged, IUnsignedNumber<T>, IBinaryNumber<T>
{
Debug.Assert(typeof(T) == typeof(uint) || typeof(T) == typeof(ulong));
var entrySize = _dynamicEntries[DynamicTag.DT_RELRENT];
var entryCount = size / entrySize;
Debug.Assert(entrySize == (uint)Unsafe.SizeOf<T>());
var relrWords = _mappedExecutable.ReadPrimitiveArray<T>(ImageBase + address, checked((int)entryCount));
var baseAddr = 0ul;
for (int i = 0; i < relrWords.Length; i++)
{
var word = ulong.CreateChecked(relrWords[i]);
ulong offset;
if ((word & 1) == 0)
{
offset = word;
var value = ulong.CreateChecked(_mappedExecutable.ReadPrimitive<T>(ImageBase + offset));
_mappedExecutable.WriteNUInt(ImageBase + offset, ImageBase + value);
baseAddr = offset + entrySize;
}
else
{
offset = baseAddr;
while (word != 0)
{
word >>= 1;
if ((word & 1) != 0)
{
var value = ulong.CreateChecked(_mappedExecutable.ReadPrimitive<T>(ImageBase + offset));
_mappedExecutable.WriteNUInt(ImageBase + offset, ImageBase + value);
}
offset += entrySize;
}
baseAddr += (8 * entrySize - 1) * entrySize;
}
}
}
}
}
public override uint[] GetFunctionTable() => [];
@@ -352,6 +430,11 @@ public class NsoReader : FileFormatStream<NsoReader>
}
fileOffset = checked((uint)(uiAddr - ImageBase));
if (fileOffset > Length)
{
return false;
}
return true;
}