diff --git a/Il2CppDumper/Attributes/ArrayLengthAttribute.cs b/Il2CppDumper/Attributes/ArrayLengthAttribute.cs new file mode 100644 index 0000000..1955df5 --- /dev/null +++ b/Il2CppDumper/Attributes/ArrayLengthAttribute.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Il2CppDumper +{ + [AttributeUsage(AttributeTargets.Field)] + class ArrayLengthAttribute : Attribute + { + public int Length { get; set; } + } +} diff --git a/Il2CppDumper/ExecutableFormats/Elf.cs b/Il2CppDumper/ExecutableFormats/Elf.cs index e760d4e..1220a91 100644 --- a/Il2CppDumper/ExecutableFormats/Elf.cs +++ b/Il2CppDumper/ExecutableFormats/Elf.cs @@ -27,29 +27,7 @@ namespace Il2CppDumper public Elf(Stream stream, float version, long maxMetadataUsages) : base(stream, version, maxMetadataUsages) { is32Bit = true; - elfHeader = new Elf32_Ehdr(); - elfHeader.ei_mag = ReadUInt32(); - elfHeader.ei_class = ReadByte(); - elfHeader.ei_data = ReadByte(); - elfHeader.ei_version = ReadByte(); - elfHeader.ei_osabi = ReadByte(); - elfHeader.ei_abiversion = ReadByte(); - elfHeader.ei_pad = ReadBytes(7); - elfHeader.e_type = ReadUInt16(); - elfHeader.e_machine = ReadUInt16(); - if (elfHeader.e_machine != EM_ARM && elfHeader.e_machine != EM_386) - throw new Exception("ERROR: Unsupported machines."); - elfHeader.e_version = ReadUInt32(); - elfHeader.e_entry = ReadUInt32(); - elfHeader.e_phoff = ReadUInt32(); - elfHeader.e_shoff = ReadUInt32(); - elfHeader.e_flags = ReadUInt32(); - elfHeader.e_ehsize = ReadUInt16(); - elfHeader.e_phentsize = ReadUInt16(); - elfHeader.e_phnum = ReadUInt16(); - elfHeader.e_shentsize = ReadUInt16(); - elfHeader.e_shnum = ReadUInt16(); - elfHeader.e_shtrndx = ReadUInt16(); + elfHeader = ReadClass(); programSegment = ReadClassArray(elfHeader.e_phoff, elfHeader.e_phnum); try { diff --git a/Il2CppDumper/ExecutableFormats/Elf64.cs b/Il2CppDumper/ExecutableFormats/Elf64.cs index bb50071..7a5c756 100644 --- a/Il2CppDumper/ExecutableFormats/Elf64.cs +++ b/Il2CppDumper/ExecutableFormats/Elf64.cs @@ -18,27 +18,7 @@ namespace Il2CppDumper public Elf64(Stream stream, float version, long maxMetadataUsages) : base(stream, version, maxMetadataUsages) { - elfHeader = new Elf64_Ehdr(); - elfHeader.ei_mag = ReadUInt32(); - elfHeader.ei_class = ReadByte(); - elfHeader.ei_data = ReadByte(); - elfHeader.ei_version = ReadByte(); - elfHeader.ei_osabi = ReadByte(); - elfHeader.ei_abiversion = ReadByte(); - elfHeader.ei_pad = ReadBytes(7); - elfHeader.e_type = ReadUInt16(); - elfHeader.e_machine = ReadUInt16(); - elfHeader.e_version = ReadUInt32(); - elfHeader.e_entry = ReadUInt64(); - elfHeader.e_phoff = ReadUInt64(); - elfHeader.e_shoff = ReadUInt64(); - elfHeader.e_flags = ReadUInt32(); - elfHeader.e_ehsize = ReadUInt16(); - elfHeader.e_phentsize = ReadUInt16(); - elfHeader.e_phnum = ReadUInt16(); - elfHeader.e_shentsize = ReadUInt16(); - elfHeader.e_shnum = ReadUInt16(); - elfHeader.e_shtrndx = ReadUInt16(); + elfHeader = ReadClass(); programSegment = ReadClassArray(elfHeader.e_phoff, elfHeader.e_phnum); try { diff --git a/Il2CppDumper/ExecutableFormats/Elf64Class.cs b/Il2CppDumper/ExecutableFormats/Elf64Class.cs index 5c8db82..328c0ba 100644 --- a/Il2CppDumper/ExecutableFormats/Elf64Class.cs +++ b/Il2CppDumper/ExecutableFormats/Elf64Class.cs @@ -13,6 +13,7 @@ namespace Il2CppDumper public byte ei_version; public byte ei_osabi; public byte ei_abiversion; + [ArrayLength(Length = 7)] public byte[] ei_pad; public ushort e_type; public ushort e_machine; diff --git a/Il2CppDumper/ExecutableFormats/ElfClass.cs b/Il2CppDumper/ExecutableFormats/ElfClass.cs index 5ed845a..a9f9eca 100644 --- a/Il2CppDumper/ExecutableFormats/ElfClass.cs +++ b/Il2CppDumper/ExecutableFormats/ElfClass.cs @@ -14,6 +14,7 @@ namespace Il2CppDumper public byte ei_version; public byte ei_osabi; public byte ei_abiversion; + [ArrayLength(Length = 7)] public byte[] ei_pad; public ushort e_type; public ushort e_machine; diff --git a/Il2CppDumper/ExecutableFormats/PE.cs b/Il2CppDumper/ExecutableFormats/PE.cs index ca0a067..2233dda 100644 --- a/Il2CppDumper/ExecutableFormats/PE.cs +++ b/Il2CppDumper/ExecutableFormats/PE.cs @@ -13,52 +13,40 @@ namespace Il2CppDumper public PE(Stream stream, float version, long maxMetadataUsages) : base(stream, version, maxMetadataUsages) { - if (ReadUInt16() != 0x5A4D)//e_magic - throw new Exception("ERROR: Invalid PE file"); - Position = 0x3C;//e_lfanew - Position = ReadUInt32(); - if (ReadUInt32() != 0x00004550)//Signature - throw new Exception("ERROR: Invalid PE file"); + var dosHeader = ReadClass(); + if (dosHeader.Magic != 0x5A4D) + { + throw new InvalidDataException("ERROR: Invalid PE file"); + } + Position = dosHeader.Lfanew; + if (ReadUInt32() != 0x4550u) //Signature + { + throw new InvalidDataException("ERROR: Invalid PE file"); + } var fileHeader = ReadClass(); - if (fileHeader.Machine == 0x014c)//Intel 386 + var pos = Position; + if (fileHeader.Machine == 0x14c) //Intel 386 { is32Bit = true; var optionalHeader = ReadClass(); - optionalHeader.DataDirectory = ReadClassArray(optionalHeader.NumberOfRvaAndSizes); imageBase = optionalHeader.ImageBase; } - else if (fileHeader.Machine == 0x8664)//AMD64 + else if (fileHeader.Machine == 0x8664) //AMD64 { var optionalHeader = ReadClass(); - optionalHeader.DataDirectory = ReadClassArray(optionalHeader.NumberOfRvaAndSizes); imageBase = optionalHeader.ImageBase; } else { - throw new Exception("ERROR: Unsupported machine."); - } - sections = new SectionHeader[fileHeader.NumberOfSections]; - for (int i = 0; i < fileHeader.NumberOfSections; i++) - { - sections[i] = new SectionHeader - { - Name = Encoding.UTF8.GetString(ReadBytes(8)).Trim('\0'), - VirtualSize = ReadUInt32(), - VirtualAddress = ReadUInt32(), - SizeOfRawData = ReadUInt32(), - PointerToRawData = ReadUInt32(), - PointerToRelocations = ReadUInt32(), - PointerToLinenumbers = ReadUInt32(), - NumberOfRelocations = ReadUInt16(), - NumberOfLinenumbers = ReadUInt16(), - Characteristics = ReadUInt32() - }; + throw new NotSupportedException("ERROR: Unsupported machine."); } + Position = pos + fileHeader.SizeOfOptionalHeader; + sections = ReadClassArray(fileHeader.NumberOfSections); } - public override ulong MapVATR(ulong uiAddr) + public override ulong MapVATR(ulong absAddr) { - var addr = uiAddr - imageBase; + var addr = absAddr - imageBase; var section = sections.First(x => addr >= x.VirtualAddress && addr <= x.VirtualAddress + x.VirtualSize); return addr - (section.VirtualAddress - section.PointerToRawData); } diff --git a/Il2CppDumper/ExecutableFormats/PEClass.cs b/Il2CppDumper/ExecutableFormats/PEClass.cs index 94fcbee..7bc95ff 100644 --- a/Il2CppDumper/ExecutableFormats/PEClass.cs +++ b/Il2CppDumper/ExecutableFormats/PEClass.cs @@ -5,6 +5,31 @@ using System.Text; namespace Il2CppDumper { + public class DosHeader + { + public ushort Magic; + public ushort Cblp; + public ushort Cp; + public ushort Crlc; + public ushort Cparhdr; + public ushort Minalloc; + public ushort Maxalloc; + public ushort Ss; + public ushort Sp; + public ushort Csum; + public ushort Ip; + public ushort Cs; + public ushort Lfarlc; + public ushort Ovno; + [ArrayLength(Length = 4)] + public ushort[] Res; + public ushort Oemid; + public ushort Oeminfo; + [ArrayLength(Length = 10)] + public ushort[] Res2; + public uint Lfanew; + } + public class FileHeader { public ushort Machine; @@ -48,7 +73,7 @@ namespace Il2CppDumper public uint SizeOfHeapCommit; public uint LoaderFlags; public uint NumberOfRvaAndSizes; - public DataDirectory[] DataDirectory { get; set; } + //public DataDirectory[] DataDirectory; } public class OptionalHeader64 @@ -82,18 +107,19 @@ namespace Il2CppDumper public ulong SizeOfHeapCommit; public uint LoaderFlags; public uint NumberOfRvaAndSizes; - public DataDirectory[] DataDirectory { get; set; } + //public DataDirectory[] DataDirectory; } - public class DataDirectory + /*public class DataDirectory { public uint VirtualAddress; public uint Size; - } + }*/ public class SectionHeader { - public string Name; + [ArrayLength(Length = 8)] + public byte[] Name; public uint VirtualSize; public uint VirtualAddress; public uint SizeOfRawData; @@ -104,4 +130,12 @@ namespace Il2CppDumper public ushort NumberOfLinenumbers; public uint Characteristics; } + + [Flags] + public enum SectionCharacteristics : uint + { + IMAGE_SCN_MEM_EXECUTE = 0x20000000, + IMAGE_SCN_MEM_READ = 0x40000000, + IMAGE_SCN_MEM_WRITE = 0x80000000 + } } diff --git a/Il2CppDumper/IO/BinaryStream.cs b/Il2CppDumper/IO/BinaryStream.cs index f6ed2f8..8004c14 100644 --- a/Il2CppDumper/IO/BinaryStream.cs +++ b/Il2CppDumper/IO/BinaryStream.cs @@ -14,7 +14,8 @@ namespace Il2CppDumper private BinaryReader reader; private BinaryWriter writer; private MethodInfo readClass; - private Dictionary readClassCache = new Dictionary(); + private MethodInfo readClassArray; + private Dictionary genericMethodCache = new Dictionary(); private Dictionary attributeCache = new Dictionary(); public BinaryStream(Stream input) @@ -23,6 +24,7 @@ namespace Il2CppDumper reader = new BinaryReader(stream, Encoding.UTF8, true); writer = new BinaryWriter(stream, Encoding.UTF8, true); readClass = GetType().GetMethod("ReadClass", Type.EmptyTypes); + readClassArray = GetType().GetMethod("ReadClassArray", new[] { typeof(long) }); } public bool ReadBoolean() => reader.ReadBoolean(); @@ -101,7 +103,7 @@ namespace Il2CppDumper case "UInt64": return ReadUInt64(); default: - return null; + throw new NotSupportedException(); } } @@ -127,7 +129,7 @@ namespace Il2CppDumper { if (Attribute.IsDefined(i, typeof(VersionAttribute))) { - versionAttribute = (VersionAttribute)Attribute.GetCustomAttribute(i, typeof(VersionAttribute)); + versionAttribute = i.GetCustomAttribute(); attributeCache.Add(i, versionAttribute); } } @@ -140,16 +142,24 @@ namespace Il2CppDumper { i.SetValue(t, ReadPrimitive(i.FieldType)); } + else if (i.FieldType.IsArray) + { + var arrayLengthAttribute = i.GetCustomAttribute(); + if (!genericMethodCache.TryGetValue(i.FieldType, out var methodInfo)) + { + methodInfo = readClassArray.MakeGenericMethod(i.FieldType.GetElementType()); + genericMethodCache.Add(i.FieldType, methodInfo); + } + i.SetValue(t, methodInfo.Invoke(this, new object[] { arrayLengthAttribute.Length })); + } else { - if (!readClassCache.TryGetValue(i.FieldType, out var methodInfo)) + if (!genericMethodCache.TryGetValue(i.FieldType, out var methodInfo)) { methodInfo = readClass.MakeGenericMethod(i.FieldType); - readClassCache.Add(i.FieldType, methodInfo); + genericMethodCache.Add(i.FieldType, methodInfo); } - var value = methodInfo.Invoke(this, null); - i.SetValue(t, value); - break; + i.SetValue(t, methodInfo.Invoke(this, null)); } } return t; diff --git a/Il2CppDumper/Il2CppDumper.csproj b/Il2CppDumper/Il2CppDumper.csproj index af9f6ec..f76dac0 100644 --- a/Il2CppDumper/Il2CppDumper.csproj +++ b/Il2CppDumper/Il2CppDumper.csproj @@ -51,6 +51,7 @@ + diff --git a/Il2CppDumper/Outputs/Il2CppDecompiler.cs b/Il2CppDumper/Outputs/Il2CppDecompiler.cs index 921f077..00adaf7 100644 --- a/Il2CppDumper/Outputs/Il2CppDecompiler.cs +++ b/Il2CppDumper/Outputs/Il2CppDecompiler.cs @@ -514,7 +514,6 @@ namespace Il2CppDumper var pointer = metadata.GetDefaultValueFromIndex(dataIndex); var defaultValueType = il2Cpp.types[typeIndex]; metadata.Position = pointer; - value = null; switch (defaultValueType.type) { case Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN: