Exemplo n.º 1
0
        public void TestAppModelQueries()
        {
            // Arrange
            // We're currently in IlCppTests\bin\Debug\netcoreapp3.0 or similar
            var testPath = Path.GetFullPath(Directory.GetCurrentDirectory() + @"\..\..\..\TestBinaries\ArraysAndPointers-ARM64");

            // Act
            var inspectors = Il2CppInspector.LoadFromFile(testPath + @"\ArraysAndPointers-ARM64.so", testPath + @"\global-metadata.dat");
            var model      = new TypeModel(inspectors[0]);
            var app        = new AppModel(model).Build();

            // Assert

            // Check VTable offset is accurate
            Assert.AreEqual(0x130, app.GetVTableOffset());

            // BufferedStream.Flush()
            Assert.AreEqual(11, app.GetVTableIndexFromClassOffset(0x1E0));

            var vtable = model.GetType("System.IO.BufferedStream").GetVTable();

            Assert.AreEqual("get_CanWrite", vtable[app.GetVTableIndexFromClassOffset(0x1E0)].Name);

            var method = app.Methods.Values.First(m => m.MethodCodeAddress == 0x7C94D4);

            Assert.AreEqual("Flush", method.Method.Name);
            Assert.AreEqual("System.IO.BufferedStream", method.Method.DeclaringType.FullName);
        }
Exemplo n.º 2
0
        public void TestGenericTypes()
        {
            // Arrange
            // We're currently in IlCppTests\bin\Debug\netcoreapp3.0 or similar
            var testPath = Path.GetFullPath(Directory.GetCurrentDirectory() + @"\..\..\..\TestBinaries\GenericTypes");

            // Build model
            var inspectors = Il2CppInspector.LoadFromFile(testPath + @"\GenericTypes.so", testPath + @"\global-metadata.dat");
            var model      = new Il2CppModel(inspectors[0]);

            var asm = model.GetAssembly("GenericTypes.dll");

            // Act
            TypeInfo tDerived     = asm.GetType("Il2CppTests.TestSources.Derived`1");
            TypeInfo tDerivedBase = tDerived.BaseType;

            // TODO: array of Derived<int>
            // TypeInfo tDerivedArray

            TypeInfo tT      = asm.GetType("Il2CppTests.TestSources.Base`2").GenericTypeParameters[0];
            TypeInfo tF      = tDerived.GetField("F").FieldType;
            TypeInfo tNested = asm.GetType("Il2CppTests.TestSources.Derived`1+Nested");

            DisplayGenericType(tDerived, "Derived<V>");
            DisplayGenericType(tDerivedBase, "Base type of Derived<V>");
            //DisplayGenericType(tDerivedArray, "Array of Derived<int>");
            DisplayGenericType(tT, "Type parameter T from Base<T>");
            DisplayGenericType(tF, "Field type, G<Derived<V>>");
            DisplayGenericType(tNested, "Nested type in Derived<V>");

            // Assert
            var checks = new[] {
Exemplo n.º 3
0
        static void Main(string[] args)
        {
            // Command-line usage: dotnet run [<binary-file> [<metadata-file> [<output-file>]]]
            // Defaults to libil2cpp.so or GameAssembly.dll if binary file not specified
            string imageFile = "libil2cpp.so";
            string metaFile  = "global-metadata.dat";
            string outFile   = "types.cs";

            if (args.Length == 0)
            {
                if (!File.Exists(imageFile))
                {
                    imageFile = "GameAssembly.dll";
                }
            }

            if (args.Length >= 1)
            {
                imageFile = args[0];
            }

            if (args.Length >= 2)
            {
                metaFile = args[1];
            }

            if (args.Length >= 3)
            {
                outFile = args[2];
            }

            // Check files
            if (!File.Exists(imageFile))
            {
                Console.Error.WriteLine($"File {imageFile} does not exist");
                Environment.Exit(1);
            }
            if (!File.Exists(metaFile))
            {
                Console.Error.WriteLine($"File {metaFile} does not exist");
                Environment.Exit(1);
            }

            // Analyze data
            var il2cppInspectors = Il2CppInspector.LoadFromFile(imageFile, metaFile);

            if (il2cppInspectors == null)
            {
                Environment.Exit(1);
            }

            // Write output file
            int i = 0;

            foreach (var il2cpp in il2cppInspectors)
            {
                new Il2CppDumper(il2cpp).WriteFile(outFile + (i++ > 0 ? "-" + (i - 1) : ""));
            }
        }
Exemplo n.º 4
0
        // See: IL2CPP/Il2CppInspector.cs
        public void PostProcessPackage(Il2CppInspector.Il2CppInspector package, PluginPostProcessPackageEventInfo data)
        {
            // This is called once per IL2CPP binary after it has been merged with global-metadata.dat
            // and all of the data linked together

            // It contains surrogate properties to everything in Metadata and Il2CppBinary
            // plus all calculated default field values (FieldDefaultValue), default parameter values (ParameterDefaultValue),
            // field offsets (FieldOffsets), custom attribute generators (CustomAttributeGenerators),
            // function addresses (FunctionAddresses) and metadata usages (MetadataUsages) etc.

            // Set data.IsDataModified if you modify the Il2CppInspector
        }
Exemplo n.º 5
0
        public void TestGenericTypes()
        {
            // Arrange
            // We're currently in IlCppTests\bin\Debug\netcoreapp3.0 or similar
            var testPath = Path.GetFullPath(Directory.GetCurrentDirectory() + @"\..\..\..\TestBinaries\GenericTypes");

            // Build model
            var inspectors = Il2CppInspector.LoadFromFile(testPath + @"\GenericTypes.so", testPath + @"\global-metadata.dat");
            var model      = new Il2CppModel(inspectors[0]);

            var asm = model.GetAssembly("GenericTypes.dll");

            // Act
            TypeInfo tBase         = asm.GetType("Il2CppTests.TestSources.Base`2");
            TypeInfo tDerived      = asm.GetType("Il2CppTests.TestSources.Derived`1");
            TypeInfo tDerivedBase  = tDerived.BaseType;
            TypeInfo tDerivedArray = model.GetType("Il2CppTests.TestSources.Derived`1[System.Int32][]");

            TypeInfo tT      = tBase.GenericTypeParameters[0];
            TypeInfo tU      = tBase.GenericTypeParameters[1];
            TypeInfo tF      = tDerived.GetField("F").FieldType;
            TypeInfo tNested = asm.GetType("Il2CppTests.TestSources.Derived`1+Nested");

            TypeInfo   tNG      = asm.GetType("Il2CppTests.TestSources.NonGeneric");
            TypeInfo   tGCWM    = asm.GetType("Il2CppTests.TestSources.GenericClassWithMethods`1");
            TypeInfo   tCGM     = asm.GetType("Il2CppTests.TestSources.CallGenericMethods");
            MethodInfo mGMDINGC = tNG.GetMethod("GenericMethodDefinitionInNonGenericClass");
            MethodInfo mNGMIGC  = tGCWM.GetMethod("NonGenericMethodInGenericClass");
            MethodInfo mNGMIGC2 = tGCWM.GetMethod("NonGenericMethodInGenericClass2");
            MethodInfo mGMDIGC  = tGCWM.GetMethod("GenericMethodDefinitionInGenericClass");
            MethodInfo mGMDIGC2 = tGCWM.GetMethod("GenericMethodDefinitionInGenericClass2");

            MethodBase mGMDINGC_closed = model.GetGenericMethod(
                "Il2CppTests.TestSources.NonGeneric.GenericMethodDefinitionInNonGenericClass", model.GetType("System.Single"));
            MethodBase mGMDIGC_closed = model.GetGenericMethod(
                "Il2CppTests.TestSources.GenericClassWithMethods`1.GenericMethodDefinitionInGenericClass", model.GetType("System.Int32"));
            MethodBase mGMDIGC2_closed = model.GetGenericMethod(
                "Il2CppTests.TestSources.GenericClassWithMethods`1.GenericMethodDefinitionInGenericClass2", model.GetType("System.String"));

            DisplayGenericType(tBase, "Generic type definition Base<T, U>");
            DisplayGenericType(tDerived, "Derived<V>");
            DisplayGenericType(tDerivedBase, "Base type of Derived<V>");
            DisplayGenericType(tDerivedArray, "Array of Derived<int>");
            DisplayGenericType(tT, "Type parameter T from Base<T,U>");
            DisplayGenericType(tU, "Type parameter U from Base<T,U>");
            DisplayGenericType(tF, "Field type, G<Derived<V>>");
            DisplayGenericType(tNested, "Nested type in Derived<V>");

            // Assert
            var typeChecks = new[] {
Exemplo n.º 6
0
        private void runTest(string testPath)
        {
            // Android
            var testFile = testPath + @"\" + Path.GetFileName(testPath) + ".so";

            // Windows
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath) + ".dll";
            }
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\GameAssembly.dll";
            }
            // iOS
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath);
            }
            // Android
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\libil2cpp.so";
            }

            var inspectors = Il2CppInspector.LoadFromFile(testFile, testPath + @"\global-metadata.dat");

            // If null here, there was a problem parsing the files
            if (inspectors == null)
            {
                throw new Exception("Could not understand IL2CPP binary or metadata");
            }

            if (inspectors.Count == 0)
            {
                throw new Exception("Could not find any images in the IL2CPP binary");
            }

            // Dump each image in the binary separately
            int i = 0;

            foreach (var il2cpp in inspectors)
            {
                new CSharpCodeStubs(new Il2CppModel(il2cpp))
                {
                    ExcludedNamespaces = Constants.DefaultExcludedNamespaces,
                    SuppressMetadata   = false,
                    MustCompile        = true
                }
            }
Exemplo n.º 7
0
        public void TestAppModelQueries()
        {
            // Arrange
            // We're currently in IlCppTests\bin\Debug\netcoreapp3.0 or similar
            var testPath = Path.GetFullPath(Directory.GetCurrentDirectory() + @"\..\..\..\TestBinaries\ArraysAndPointers-ARM64");

            // Act
            var inspectors = Il2CppInspector.LoadFromFile(testPath + @"\ArraysAndPointers-ARM64.so", testPath + @"\global-metadata.dat");
            var model      = new TypeModel(inspectors[0]);
            var app        = new AppModel(model);

            // Assert

            // Check VTable offset is accurate
            // Note: this is for 2020.1 and below; it changed to 0x138 in 2020.2
            Assert.AreEqual(0x130, app.GetVTableOffset());

            // BufferedStream.Flush()
            Assert.AreEqual(11, app.GetVTableIndexFromClassOffset(0x1E0));

            var vtable = model.GetType("System.IO.BufferedStream").GetVTable();

            // Check vtable calculations are correct
            Assert.AreEqual("get_CanWrite", vtable[app.GetVTableIndexFromClassOffset(0x1E0)].Name);

            // Check method lookup is correct
            var method = app.Methods.Values.First(m => m.MethodCodeAddress == 0x7C94D4);

            Assert.AreEqual("Flush", method.Method.Name);
            Assert.AreEqual("System.IO.BufferedStream", method.Method.DeclaringType.FullName);

            // AsyncStateMachineAttribute CAG - 0x3B7C58 - Type from Il2CppType**
            // adrp x9,0xfca000 - ldr x9,[x9, #0x90] - ldr x0,[x9]

            // Check Il2CppType * lookup is correct via AppModel
            var typeRefPtr  = (ulong)app.Image.ReadMappedWord(0xFCA090);
            var typeFromRef = app.Types.Values.First(t => t.TypeRefPtrAddress == typeRefPtr).Type;

            Assert.AreEqual("System.IO.StreamReader+<ReadAsyncInternal>d__65", typeFromRef.FullName);

            // Check Il2CppType * lookup is correct via AddressMap
            var map = app.GetAddressMap();
            var appTypeReference = map[typeRefPtr];

            Assert.AreEqual(typeof(AppTypeReference), appTypeReference.GetType());

            Assert.AreEqual(typeFromRef, ((AppTypeReference)appTypeReference).Type.Type);
            Assert.AreEqual(typeRefPtr, ((AppTypeReference)appTypeReference).Type.TypeRefPtrAddress);
        }
Exemplo n.º 8
0
        // Attempt to load an IL2CPP application package (APK or IPA)
        public async Task <bool> LoadPackageAsync(string packageFile)
        {
            try {
                var streams = Inspector.GetStreamsFromPackage(packageFile);
                if (streams == null)
                {
                    throw new InvalidOperationException("The supplied package is not an APK or IPA file, or does not contain an IL2CPP application");
                }

                return(await LoadMetadataAsync(streams.Value.Metadata) && await LoadBinaryAsync(streams.Value.Binary));
            }
            catch (Exception ex) {
                LastException = ex;
                return(false);
            }
        }
Exemplo n.º 9
0
        // A "package" is the combination of global-metadata.dat, the application binary,
        // and some analysis which links them both together into a single unit, the Il2CppInspector object.

        // This executes after all the low-level processing and analysis of the application is completed,
        // but before any higher-level abstractions are created, such as the .NET type model or C++ application model.

        // Therefore this is a good place to make any final changes to the data that the high level models and output modules will rely on
        // In this case, we are going to acquire all of the string literals that we deferred earlier
        public void PostProcessPackage(Il2CppInspector.Il2CppInspector package, PluginPostProcessPackageEventInfo data)
        {
            // Don't do anything if this isn't for us
            if (!IsOurs)
            {
                return;
            }

            // Tell the user what is happening in case it takes a while
            PluginServices.For(this).StatusUpdate("Decrypting string literals");

            // Calculate the number of string literals
            // This calculation depends on being able to scan MetadataUsages for all of the StringLiteral uses
            // and finding the one with the highest index. The creation of MetadataUsages requires data
            // from both global-metadata.dat and the application binary; this data is merged together
            // when the Il2CppInspector object is initialized, so this is the earliest opportunity we have to examine it
            var stringLiteralCount = package.MetadataUsages.Where(u => u.Type == MetadataUsageType.StringLiteral).Max(u => u.SourceIndex) + 1;

            // Create a delegate which internally is a function pointer to the GetStringLiteralFromIndex function in the DLL
            var pGetStringLiteralFromIndex = (GetStringLiteralFromIndex)
                                             Marshal.GetDelegateForFunctionPointer(ModuleBase + Offsets[game.Value].GetStringLiteralFromIndex, typeof(GetStringLiteralFromIndex));

            var stringLiterals = new List <string>();
            var length         = 0;

            // For each index, call the delegate with the decrypted metadata byte array, index and a pointer as arguments
            // In this case, the function returns an array of UTF8-encoded characters,
            // and populates 'length' with the number of bytes returned
            for (uint index = 0; index < stringLiteralCount; index++)
            {
                var decryptedBytesUnmanaged = pGetStringLiteralFromIndex(metadataBlob, index, ref length);
                var str = new byte[length];
                Marshal.Copy(decryptedBytesUnmanaged, str, 0, length);

                stringLiterals.Add(Encoding.UTF8.GetString(str));
            }

            // If we had used IGetStringLiterals above, we would have set data.StringLiterals,
            // but here we modify the package (the Il2CppInspector object) directly instead
            package.Metadata.StringLiterals = stringLiterals.ToArray();

            // We don't set FullyProcessed so that other plugins can perform further post-processing modifications
            // IsDataModified tells Il2CppInspector that the contents of its internal data structures have been changed
            // Note this is different from IsStreamModified; changing the data in memory
            // does not automatically rewrite the stream.
            data.IsDataModified = true;
        }
Exemplo n.º 10
0
        // Attempt to load an IL2CPP application package (APK or IPA)
        public async Task <bool> LoadPackageAsync(string packageFile)
        {
            try {
                OnStatusUpdate?.Invoke(this, "Extracting package");

                // TODO: Accept multiple APKs
                var streams = Inspector.GetStreamsFromPackage(new string[] { packageFile });
                if (streams == null)
                {
                    throw new InvalidOperationException("The supplied package is not an APK or IPA file, or does not contain an IL2CPP application");
                }

                return(await LoadMetadataAsync(streams.Value.Metadata) && await LoadBinaryAsync(streams.Value.Binary));
            }
            catch (Exception ex) {
                LastException = ex;
                return(false);
            }
        }
Exemplo n.º 11
0
        // Attempt to load an IL2CPP application package (APK or IPA)
        public async Task <bool> LoadPackageAsync(IEnumerable <string> packageFiles)
        {
            try {
                OnStatusUpdate?.Invoke(this, "Extracting package");

                var streams = await Task.Run(() => Inspector.GetStreamsFromPackage(packageFiles));

                if (streams == null)
                {
                    throw new InvalidOperationException("The supplied package is not an APK or IPA file, or does not contain a complete IL2CPP application");
                }

                return(await LoadMetadataAsync(streams.Value.Metadata) && await LoadBinaryAsync(streams.Value.Binary));
            }
            catch (Exception ex) {
                LastException = ex;
                return(false);
            }
        }
Exemplo n.º 12
0
        public void TestNames()
        {
            // Arrange
            // We're currently in IlCppTests\bin\Debug\netcoreapp3.0 or similar
            var testPath = Path.GetFullPath(Directory.GetCurrentDirectory() + @"\..\..\..\TestBinaries\References-ARMv7");

            // Build model
            var inspectors = Il2CppInspector.LoadFromFile(testPath + @"\References-ARMv7.so", testPath + @"\global-metadata.dat");
            var model      = new Il2CppModel(inspectors[0]);

            var asm = model.GetAssembly("References.dll");

            // Act
            var t  = asm.GetType("Il2CppTests.TestSources.Test");
            var m1 = t.GetMethod("MethodWithGenericAndClassRefs");
            var m2 = t.GetMethod("MethodWithInRefOut");
            var p1 = m1.DeclaredParameters;
            var p2 = m2.DeclaredParameters;

            // Assert
            var checks = new[] {
        private void LoadIlAppModel()
        {
            // Lazily create an Il2CppInspector model. Copying the ELF data array is required since the library
            // seems to mess with the data, which crashes the game.
            // TODO: Consider caching the result in a file. This is horribly slow.
            var binaryStream   = new MemoryStream(Data.ToArray());
            var metadataStream = new MemoryStream(Il2CppMetadata);

            var oldOut = Console.Out;

            // Disable Console.WriteLine() since Il2CppInspector logs text
            Console.SetOut(TextWriter.Null);

            try
            {
                // The internal class Il2CppInspector.ElfReader64 can be used to retrieve the offsets of sections
                // in the ELF file. These are relevant since Il2CppInspector saves symbol offsets relative to the
                // code section of the ELF so this offset needs to be considered when editing the ELF.
                var elfReader = CreateAndInitElfReader(binaryStream);
                ReadSectionOffsets(elfReader);

                // Create the inspector manually instead of using Il2CppInspector.LoadFromStream to avoid
                // reading the ELF a second time.
                var metadata  = new Metadata(metadataStream);
                var binary    = Il2CppBinary.Load(elfReader, metadata);
                var inspector = new Il2CppInspector.Il2CppInspector(binary, metadata);

                if (inspector == null)
                {
                    throw new Exception("Couldn't extract Il2Cpp metadata.");
                }

                ilAppModel = new AppModel(new TypeModel(inspector));
            }
            finally
            {
                Console.SetOut(oldOut);
            }
        }
Exemplo n.º 14
0
        private void runTest(string testPath)
        {
            // Android
            var testFile = testPath + @"\" + Path.GetFileName(testPath) + ".so";

            // Windows
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath) + ".dll";
            }
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\GameAssembly.dll";
            }
            // iOS
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath);
            }
            // Android
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\libil2cpp.so";
            }

            var inspectors = Il2CppInspector.LoadFromFile(testFile, testPath + @"\global-metadata.dat");

            // If null here, there was a problem parsing the files
            if (inspectors == null)
            {
                throw new Exception("Could not understand IL2CPP binary or metadata");
            }

            if (inspectors.Count == 0)
            {
                throw new Exception("Could not find any images in the IL2CPP binary");
            }

            // Exclusions

            var excludedNamespaces = new List <string> {
                "System",
                "Mono",
                "Microsoft.Win32",
                "Unity",
                "UnityEditor",
                "UnityEngine",
                "UnityEngineInternal",
                "AOT",
                "JetBrains.Annotations"
            };

            // Dump each image in the binary separately
            int i = 0;

            foreach (var il2cpp in inspectors)
            {
                new CSharpCodeStubs(new Il2CppModel(il2cpp))
                {
                    ExcludedNamespaces = excludedNamespaces,
                    SuppressMetadata   = false,
                    MustCompile        = true
                }
            }
Exemplo n.º 15
0
 public static PluginPostProcessPackageEventInfo PostProcessPackage(Il2CppInspector package)
 => PluginManager.Try <ILoadPipeline, PluginPostProcessPackageEventInfo>((p, e) => p.PostProcessPackage(package, e));
Exemplo n.º 16
0
 public Il2CppDumper(Il2CppInspector proc)
 {
     model = new Il2CppReflector(proc);
 }
Exemplo n.º 17
0
        private void runTest(string testPath)
        {
            // Android
            var testFile = testPath + @"\" + Path.GetFileName(testPath) + ".so";

            // Windows
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath) + ".dll";
            }
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\GameAssembly.dll";
            }
            // iOS
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath);
            }
            // Android
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\libil2cpp.so";
            }

            var inspectors = Il2CppInspector.LoadFromFile(testFile, testPath + @"\global-metadata.dat");

            // If null here, there was a problem parsing the files
            if (inspectors == null)
            {
                throw new Exception("Could not understand IL2CPP binary or metadata");
            }

            if (inspectors.Count == 0)
            {
                throw new Exception("Could not find any images in the IL2CPP binary");
            }

            // Dump each image in the binary separately
            int i = 0;

            foreach (var il2cpp in inspectors)
            {
                var model      = new Il2CppModel(il2cpp);
                var nameSuffix = i++ > 0 ? "-" + (i - 1) : "";

                new CSharpCodeStubs(model)
                {
                    ExcludedNamespaces = Constants.DefaultExcludedNamespaces,
                    SuppressMetadata   = false,
                    MustCompile        = true
                }.WriteSingleFile(testPath + $@"\test-result{nameSuffix}.cs");

                new IDAPythonScript(model)
                .WriteScriptToFile(testPath + $@"\test-ida-result{nameSuffix}.py");

                new CppScaffolding(model)
                .WriteCppToFile(testPath + $@"\test-result{nameSuffix}.h");
            }

            // Compare test result with expected result
            for (i = 0; i < inspectors.Count; i++)
            {
                var expected = File.ReadAllLines(testPath + @"\..\..\TestExpectedResults\" + Path.GetFileName(testPath) + (i > 0 ? "-" + i : "") + ".cs");
                var actual   = File.ReadAllLines(testPath + @"\test-result" + (i > 0 ? "-" + i : "") + ".cs");

                // Get rid of blank lines and trim the remaining lines
                expected = (from l in expected where !string.IsNullOrWhiteSpace(l) select l.Trim()).ToArray();
                actual   = (from l in actual where !string.IsNullOrWhiteSpace(l) select l.Trim()).ToArray();

                CollectionAssert.AreEqual(expected, actual);
            }
        }
Exemplo n.º 18
0
        private static int Run(Options options)
        {
            // Banner
            var asmInfo = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetEntryAssembly().Location);

            Console.WriteLine(asmInfo.ProductName);
            Console.WriteLine("Version " + asmInfo.ProductVersion);
            Console.WriteLine(asmInfo.LegalCopyright);
            Console.WriteLine("");

            // Check excluded namespaces
            if (options.ExcludedNamespaces.Count() == 1 && options.ExcludedNamespaces.First().ToLower() == "none")
            {
                options.ExcludedNamespaces = new List <string>();
            }

            // Check files
            if (!File.Exists(options.BinaryFile))
            {
                Console.Error.WriteLine($"File {options.BinaryFile} does not exist");
                return(1);
            }
            if (!File.Exists(options.MetadataFile))
            {
                Console.Error.WriteLine($"File {options.MetadataFile} does not exist");
                return(1);
            }

            // Creating a Visual Studio solution requires Unity assembly references
            var unityPath           = string.Empty;
            var unityAssembliesPath = string.Empty;

            if (options.CreateSolution)
            {
                unityPath           = FindPath(options.UnityPath);
                unityAssembliesPath = FindPath(options.UnityAssembliesPath);

                if (!Directory.Exists(unityPath))
                {
                    Console.Error.WriteLine($"Unity path {unityPath} does not exist");
                    return(1);
                }
                if (!File.Exists(unityPath + @"\Editor\Data\Managed\UnityEditor.dll"))
                {
                    Console.Error.WriteLine($"No Unity installation found at {unityPath}");
                    return(1);
                }
                if (!Directory.Exists(unityAssembliesPath))
                {
                    Console.Error.WriteLine($"Unity assemblies path {unityAssembliesPath} does not exist");
                    return(1);
                }
                if (!File.Exists(unityAssembliesPath + @"\UnityEngine.UI.dll"))
                {
                    Console.Error.WriteLine($"No Unity assemblies found at {unityAssembliesPath}");
                    return(1);
                }

                Console.WriteLine("Using Unity editor at " + unityPath);
                Console.WriteLine("Using Unity assemblies at " + unityAssembliesPath);
            }

            // Analyze data
            List <Il2CppInspector> il2cppInspectors;

            using (var il2cppTimer = new Benchmark("Analyze IL2CPP data"))
                il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFile, options.MetadataFile);

            if (il2cppInspectors == null)
            {
                Environment.Exit(1);
            }

            // Write output file
            int i = 0;

            foreach (var il2cpp in il2cppInspectors)
            {
                // Create model
                Il2CppModel model;
                using (var modelTimer = new Benchmark("Create type model"))
                    model = new Il2CppModel(il2cpp);

                // C# signatures output
                using (var signaturesDumperTimer = new Benchmark("Generate C# code")) {
                    var writer = new Il2CppCSharpDumper(model)
                    {
                        ExcludedNamespaces = options.ExcludedNamespaces.ToList(),
                        SuppressMetadata   = options.SuppressMetadata,
                        MustCompile        = options.MustCompile
                    };

                    var imageSuffix = i++ > 0 ? "-" + (i - 1) : "";

                    var csOut = options.CSharpOutPath;
                    if (csOut.ToLower().EndsWith(".cs"))
                    {
                        csOut = csOut.Insert(csOut.Length - 3, imageSuffix);
                    }
                    else
                    {
                        csOut += imageSuffix;
                    }

                    if (options.CreateSolution)
                    {
                        writer.WriteSolution(csOut, unityPath, unityAssembliesPath);
                    }

                    else
                    {
                        switch (options.LayoutSchema.ToLower(), options.SortOrder.ToLower())
                        {
Exemplo n.º 19
0
        private static int Run(Options options)
        {
            // Check excluded namespaces
            if (options.ExcludedNamespaces.Count() == 1 && options.ExcludedNamespaces.First().ToLower() == "none")
            {
                options.ExcludedNamespaces = new List <string>();
            }

            // Check files
            if (!File.Exists(options.BinaryFile))
            {
                Console.Error.WriteLine($"File {options.BinaryFile} does not exist");
                return(1);
            }
            if (!File.Exists(options.MetadataFile))
            {
                Console.Error.WriteLine($"File {options.MetadataFile} does not exist");
                return(1);
            }

            // Analyze data
            List <Il2CppInspector> il2cppInspectors;

            using (var timer = new Benchmark("Analyze IL2CPP data"))
                il2cppInspectors = Il2CppInspector.LoadFromFile(options.BinaryFile, options.MetadataFile);

            if (il2cppInspectors == null)
            {
                Environment.Exit(1);
            }

            // Write output file
            int i = 0;

            foreach (var il2cpp in il2cppInspectors)
            {
                // Create model
                Il2CppModel model;
                using (var timer1 = new Benchmark("Create type model"))
                    model = new Il2CppModel(il2cpp);

                // C# signatures output
                using var timer2 = new Benchmark("Generate C# code");

                var writer = new Il2CppCSharpDumper(model)
                {
                    ExcludedNamespaces = options.ExcludedNamespaces.ToList(),
                    SuppressMetadata   = options.SuppressMetadata,
                    MustCompile        = options.MustCompile
                };

                var imageSuffix = i++ > 0 ? "-" + (i - 1) : "";

                var csOut = options.CSharpOutPath;
                if (csOut.ToLower().EndsWith(".cs"))
                {
                    csOut = csOut.Insert(csOut.Length - 3, imageSuffix);
                }
                else
                {
                    csOut += imageSuffix;
                }

                switch (options.LayoutSchema.ToLower(), options.SortOrder.ToLower())
                {
Exemplo n.º 20
0
        private void runTest(string testPath)
        {
            // Android
            var testFile = testPath + @"\" + Path.GetFileName(testPath) + ".so";

            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\libil2cpp.so";
            }
            // Windows
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath) + ".dll";
            }
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\GameAssembly.dll";
            }
            // iOS
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath);
            }

            var inspectors = Il2CppInspector.LoadFromFile(testFile, testPath + @"\global-metadata.dat");

            // If null here, there was a problem parsing the files
            if (inspectors == null)
            {
                throw new Exception("Could not understand IL2CPP binary or metadata");
            }

            if (inspectors.Count == 0)
            {
                throw new Exception("Could not find any images in the IL2CPP binary");
            }

            // Dump each image in the binary separately
            int i = 0;

            foreach (var il2cpp in inspectors)
            {
                var model      = new TypeModel(il2cpp);
                var appModel   = new AppModel(model, makeDefaultBuild: false).Build(compiler: CppCompilerType.MSVC);
                var nameSuffix = i++ > 0 ? "-" + (i - 1) : "";

                new CSharpCodeStubs(model)
                {
                    ExcludedNamespaces = Constants.DefaultExcludedNamespaces,
                    SuppressMetadata   = false,
                    MustCompile        = true
                }.WriteSingleFile(testPath + $@"\test-result{nameSuffix}.cs");

                new JSONMetadata(appModel)
                .Write(testPath + $@"\test-result{nameSuffix}.json");

                new CppScaffolding(appModel)
                .Write(testPath + $@"\test-cpp-result{nameSuffix}");

                new PythonScript(appModel)
                .WriteScriptToFile(testPath + $@"\test-ida{nameSuffix}.py", "IDA",
                                   testPath + $@"\test-cpp-result{nameSuffix}\appdata\il2cpp-types.h",
                                   testPath + $@"\test-result{nameSuffix}.json");
            }

            // Compare test results with expected results
            for (i = 0; i < inspectors.Count; i++)
            {
                var suffix = (i > 0 ? "-" + i : "");

                compareFiles(testPath, suffix + ".cs", $"test-result{suffix}.cs");
                compareFiles(testPath, suffix + ".json", $"test-result{suffix}.json");
                compareFiles(testPath, suffix + ".h", $@"test-cpp-result{suffix}\appdata\il2cpp-types.h");
            }
        }
Exemplo n.º 21
0
        // Test runner
        private async Task runTest(string testPath, LoadOptions loadOptions = null)
        {
            // Android
            var testFile = testPath + @"\" + Path.GetFileName(testPath) + ".so";

            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\libil2cpp.so";
            }
            // Windows
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath) + ".dll";
            }
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\GameAssembly.dll";
            }
            // iOS
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath);
            }
            // Linux process map
            if (!File.Exists(testFile))
            {
                testFile = Directory.GetFiles(testPath, "*-maps.txt").FirstOrDefault();
            }
            // XAPK (selects latest version assuming lexical order)
            if (testFile == null)
            {
                testFile = Directory.GetFiles(testPath, "*.xapk").LastOrDefault();
            }
            // APK (selects latest version assuming lexical order) (prefer XAPKs)
            if (testFile == null)
            {
                testFile = Directory.GetFiles(testPath, "*.apk").LastOrDefault();
            }

            // Set load options
            if (loadOptions == null)
            {
                loadOptions = new LoadOptions();
            }

            loadOptions.BinaryFilePath = testFile;

            // Load core plugins
            PluginManager.Reload(testPath + @"\..\plugins", coreOnly: true);

            // Set up additional plugins - place desired plugins in 'plugins' sub-folder of test folder
            try {
                PluginManager.Reload(testPath + @"\plugins", reset: false);
            } catch (DirectoryNotFoundException) { }

            // Handlers for debugging output
            PluginManager.StatusHandler += (s, e) => {
                Console.WriteLine("Plugin " + e.Plugin.Name + ": " + e.Text);
            };

            PluginManager.ErrorHandler += (s, e) => {
                Assert.Fail($"{e.Error.Plugin.Name} throw an exception during {e.Error.Operation}: {e.Error.Exception.Message}.", e);
            };

            // Get plugin options - place desired options in <plugins-id>.options.txt for each plugin in test folder
            // in the format "key=value", one per line
            // Use %TESTDIR% to refer to the directory containing the test files
            foreach (var plugin in PluginManager.AvailablePlugins)
            {
                Console.WriteLine("Using plugin: " + plugin.Name);

                // Enable plugin
                var ourPlugin = PluginManager.Plugins[plugin.Id];
                ourPlugin.Enabled = true;

                // Look for options
                var optionsFile = $@"{testPath}\{plugin.Id}-options.txt";
                if (File.Exists(optionsFile))
                {
                    var options = File.ReadAllLines(optionsFile);

                    // Parse options
                    foreach (var option in options)
                    {
                        var kv = option.Split('=', 2);
                        if (kv.Length == 2)
                        {
                            var key   = kv[0].Trim();
                            var value = kv[1].Trim().Replace("%TESTDIR%", testPath);

                            Console.WriteLine($"Setting option: {key} = {value}");

                            // Null default values must be castable to object
                            ourPlugin.Plugin.Options.Single(o => o.Name == key).SetFromString(value);
                        }
                    }
                }
                PluginManager.OptionsChanged(plugin);
            }

            List <Il2CppInspector> inspectors;

            using (new Benchmark("Load IL2CPP metadata and binary"))
                try {
                    inspectors = Il2CppInspector.LoadFromFile(testFile, testPath + @"\global-metadata.dat", loadOptions);
                } catch (FileNotFoundException) {
                    inspectors = Il2CppInspector.LoadFromPackage(new[] { testFile }, loadOptions);
                }

            // If null here, there was a problem parsing the files
            if (inspectors == null)
            {
                throw new Exception("Could not understand IL2CPP binary or metadata");
            }

            if (inspectors.Count == 0)
            {
                throw new Exception("Could not find any images in the IL2CPP binary");
            }

            // End if we were only testing file load
            if (!GenerateCpp && !GenerateCS && !GenerateDLL && !GenerateJSON && !GeneratePython)
            {
                return;
            }

            // Dump each image in the binary separately
            var imageTasks = inspectors.Select((il2cpp, i) => Task.Run(async() =>
            {
                TypeModel model;
                using (new Benchmark("Create .NET type model"))
                    model = new TypeModel(il2cpp);

                Task <AppModel> appModelTask = null;
                if (GenerateCpp || GenerateJSON || GeneratePython)
                {
                    appModelTask = Task.Run(() => {
                        using (new Benchmark("Create application model"))
                            return(new AppModel(model, makeDefaultBuild: false).Build(compiler: CppCompilerType.MSVC));
                    });
                }

                var nameSuffix    = i++ > 0 ? "-" + (i - 1) : "";
                var generateTasks = new List <Task>();
                var compareTasks  = new List <Task>();

                if (GenerateCS)
                {
                    generateTasks.Add(Task.Run(() => {
                        using (new Benchmark("Create C# code stubs"))
                            new CSharpCodeStubs(model)
                            {
                                ExcludedNamespaces = Constants.DefaultExcludedNamespaces,
                                SuppressMetadata   = false,
                                MustCompile        = true
                            }.WriteSingleFile(testPath + $@"\test-result{nameSuffix}.cs");

                        compareTasks.Add(Task.Run(() => compareFiles(testPath, nameSuffix + ".cs", $"test-result{nameSuffix}.cs")));
                    }));
                }

                if (GenerateDLL)
                {
                    generateTasks.Add(Task.Run(() => {
                        using (new Benchmark("Create .NET assembly shims"))
                            new AssemblyShims(model).Write(testPath + $@"\test-dll-result{nameSuffix}");

                        compareTasks.Add(Task.Run(() => compareBinaryFiles(testPath + $@"\test-dll-result{nameSuffix}",
                                                                           testPath + @"\..\..\TestExpectedResults\dll-" + Path.GetFileName(testPath) + nameSuffix)));
                    }));
                }

                AppModel appModel = null;
                if (appModelTask != null)
                {
                    appModel = await appModelTask;
                }

                if (GenerateJSON || GeneratePython)
                {
                    generateTasks.Add(Task.Run(() => {
                        using (new Benchmark("Create JSON metadata"))
                            new JSONMetadata(appModel)
                            .Write(testPath + $@"\test-result{nameSuffix}.json");

                        compareTasks.Add(Task.Run(() => compareFiles(testPath, nameSuffix + ".json", $"test-result{nameSuffix}.json")));
                    }));
                }

                if (GenerateCpp || GeneratePython)
                {
                    generateTasks.Add(Task.Run(() => {
                        using (new Benchmark("Create C++ scaffolding"))
                            new CppScaffolding(appModel)
                            .Write(testPath + $@"\test-cpp-result{nameSuffix}");

                        compareTasks.Add(Task.Run(() => compareFiles(testPath, nameSuffix + ".h", $@"test-cpp-result{nameSuffix}\appdata\il2cpp-types.h")));
                    }));
                }

                if (GeneratePython)
                {
                    generateTasks.Add(Task.Run(() => {
                        var python = new PythonScript(appModel);
                        foreach (var target in PythonScript.GetAvailableTargets())
                        {
                            python.WriteScriptToFile(testPath + $@"\test-{target.ToLower()}{nameSuffix}.py", target,
                                                     testPath + $@"\test-cpp-result{nameSuffix}\appdata\il2cpp-types.h",
                                                     testPath + $@"\test-result{nameSuffix}.json");
                        }
                    }));
                }

                await Task.WhenAll(generateTasks);
                await Task.WhenAll(compareTasks);
            }));
            await Task.WhenAll(imageTasks);
        }