diff --git a/Il2CppInspector/Il2CppBinaryARM64.cs b/Il2CppInspector/Il2CppBinaryARM64.cs index 06e2ecb..11a1482 100644 --- a/Il2CppInspector/Il2CppBinaryARM64.cs +++ b/Il2CppInspector/Il2CppBinaryARM64.cs @@ -1,6 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Text; +/* + Copyright 2019 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com + + All rights reserved. +*/ namespace Il2CppInspector { @@ -10,14 +12,75 @@ namespace Il2CppInspector public Il2CppBinaryARM64(IFileFormatReader stream, uint codeRegistration, uint metadataRegistration) : base(stream, codeRegistration, metadataRegistration) { } + private (uint reg, ulong page) getAdrp(uint inst, ulong pc) { + if ((inst.Bits(24, 8) & 0b_1000_1111) != 1 << 7) + return (0, 0); + + var addendLo = inst.Bits(29, 2); + var addendHi = inst.Bits(5, 19); + var addend = (addendHi << 14) + (addendLo << 12); + var page = pc & ~((1Lu << 12) - 1); + var reg = inst.Bits(0, 5); + + return (reg, page + addend); + } + + private (uint reg_n, uint reg_d, uint imm) getAdd64(uint inst) { + if (inst.Bits(22, 10) != 0b_1001_0001_00) + return (0, 0, 0); + + var imm = inst.Bits(10, 12); + var reg_n = inst.Bits(5, 5); + var reg_d = inst.Bits(0, 5); + + return (reg_n, reg_d, imm); + } + + private ulong getAddressLoad(IFileFormatReader image, uint loc) { + // Get candidate ADRP Xa, #PAGE instruction + var inst = image.ReadUInt32(loc); + + var adrp = getAdrp(inst, loc); + if (adrp.page == 0) + return 0; + + // Get candidate ADD Xb, Xc, #OFFSET instruction + inst = image.ReadUInt32(); + + var add64 = getAdd64(inst); + if (add64.imm == 0) + return 0; + + // Confirm a == b == c + if (adrp.reg != add64.reg_d || add64.reg_d != add64.reg_n) + return 0; + + return adrp.page + add64.imm; + } + protected override (ulong, ulong) ConsiderCode(IFileFormatReader image, uint loc) { - // Assembly bytes to search for at start of each function - ulong metadataRegistration, codeRegistration; - byte[] buff; + var codeRegistration = getAddressLoad(image, loc); + if (codeRegistration == 0) + return (0, 0); + var metadataRegistration = getAddressLoad(image, loc + 8); + if (metadataRegistration == 0) + return (0, 0); - return (0, 0); + // There should be an Il2CppCodeGenOptions address load after the above two + if (getAddressLoad(image, loc + 16) == 0) + return (0, 0); + + // TODO: Verify loc + 24 is a hard branch (B) + + return (image.GlobalOffset + codeRegistration, image.GlobalOffset + metadataRegistration); } } + + internal static class UIntExtensions + { + // Return count bits starting at bit low of integer x + public static uint Bits(this uint x, int low, int count) => (x >> low) & (uint) ((1 << count) - 1); + } } \ No newline at end of file diff --git a/README.md b/README.md index 8ca50af..ade79bb 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,12 @@ Extract types, methods, properties and fields from Unity IL2CPP binaries. * Supports ELF (Android .so), PE (Windows .exe), Mach-O (Apple iOS/Mac) and Universal Binary (Fat Mach-O) file formats * 64-bit support for Mach-O files -* Supports ARMv7, ARMv7 Thumb T1 and x86 architectures regardless of file format +* Supports ARMv7, ARMv7 Thumb T1, ARMv8 (A64) and x86 architectures regardless of file format * Supports metadata versions 21, 22, 23, 24, 24.1 (Unity 2018.3+) and 24.2 (Unity 2019+) * No manual reverse-engineering required; all data is calculated automatically * Support for classes, methods, fields, properties, enumerations, events, delegates, interfaces, structs and default field values -* Static and dynamic symbol table scanning for ELF binaries if present +* Static symbol table scanning for ELF and Mach-O binaries if present +* Dynamic symbol table scanning for ELF binaries if present * Symbol relocation handling for ELF binaries * **Il2CppInspector** re-usable class library for low-level access to IL2CPP binaries and metadata * **Il2CppReflector** re-usable class library for high-level .NET Reflection-style access to IL2CPP types and data as a tree model