public ulong GetAdress(AppModel model)
        {
            if (model == null)
            {
                return(0x0);
            }

            AddressMap map    = model.GetAddressMap();
            ulong      adress = map.Where(k => k.Value is AppMethod).FirstOrDefault(m => ((AppMethod)m.Value).Method == ((MethodBase)Il2CppMethod)).Key;

            return(adress);
        }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
0
        // See: Model/AppModel.cs
        // See: Model/*.cs
        // See: Cpp/CppTypeCollection.cs
        // See: Cpp/CppType.cs
        // See: Cpp/CppField.cs
        // See: Il2CppTests/TestAppModelQueries.cs
        // See: Il2CppTests/CppTypeDeclarations.cs
        public void PostProcessAppModel(AppModel appModel, PluginPostProcessAppModelEventInfo data)
        {
            // This is only called if the user generates a C++ application model from a .NET type model
            // The bundled CLI and GUI do this automatically if it is required for the selected outputs

            // The application model provides a C-oriented model of the IL2CPP application;
            // lower level than using the .NET type model but higher level than the IL2CPP structures

            // Note that you should change the .NET type model, NOT the application model, if you want
            // changes to propagate to all outputs because all outputs including the application model
            // are derived from the .NET type model

            // Changing the application model will only change outputs that depend on it, eg.
            // C++ scaffolding project, IDA script output etc.

            // You can access the underlying components:
            var typeModel   = appModel.TypeModel;
            var package     = appModel.Package;
            var binary      = appModel.Package.Binary;
            var binaryImage = appModel.Package.BinaryImage;
            var metadata    = appModel.Package.Metadata;

            // AppModels are targeted towards a specific compiler type and a specific version of Unity
            // SourceCompiler, TargetCompiler, UnityVersion, UnityHeaders

            // AppModel provides a composite mapping of .NET methods to C++ functions,
            // and .NET types to C++ types using MultiKeyDictionary

            var vector3 = typeModel.GetType("UnityEngine.Vector3");

            // See: Model/AppType.cs
            // CppType, CppValueType, Type, TypeClassAddress, TypeRefPtrAddress, Name etc.
            var appType = appModel.Types[vector3];

            // See: Model/AppMethod.cs
            // CppFnPtrType, Method, MethodInfoPtrAddress, MethodCodeAddress etc.
            var appMethod = appModel.Methods[vector3.GetMethod("Scale")];

            // Example: Get the C++ struct for Vector3
            var v3struct = appType.CppValueType; // null for .NET reference types

            /*  Vector3 C++ struct:
             *  struct Vector3 {
             *      float x;
             *      float y;
             *      float z;
             *  }; */
            Console.WriteLine("Vector3 C++ struct:");
            Console.WriteLine(v3struct.ToString());

            // Example: Get the C++ class for Vector3, derived from Il2CppObject
            var v3class = appType.CppType;

            /*  Vector3 C++ class:
             *  struct Vector3__Boxed {
             *      struct Vector3__Class *klass;
             *      MonitorData *monitor;
             *      struct Vector3 fields;
             *  }; */
            Console.WriteLine("Vector3 C++ class:");
            Console.WriteLine(v3class.ToString());

            // Example: Get the C++ function pointer type for a method
            var scaleFnPtrType = appMethod.CppFnPtrType;

            /* Vector3.Scale C++ function: Vector3 Vector3_Scale(void * this, Vector3 a, Vector3 b, MethodInfo * method) */
            Console.WriteLine("Vector3.Scale C++ function: " + scaleFnPtrType.ToSignatureString());

            // You can also retrieve composite types from the same dictionaries
            // via their C++ class types or function pointer types, if you want to
            // go back to the .NET type model
            var appType2   = appModel.Types[v3class];
            var appMethod2 = appModel.Methods[scaleFnPtrType];

            if (appType != appType2 || appMethod != appMethod2)
            {
                throw new Exception("This will never happen");
            }

            // Get detailed information about a type
            // We can use a type directly from appModel.Types, or inspect a method:
            var scaleReturnType = scaleFnPtrType.ReturnType;
            var argType         = scaleFnPtrType.Arguments[1].Type as CppComplexType; // Note: Arguments[0] == this pointer

            /* Vector3: 12 bytes; 0-byte aligned */
            Console.WriteLine($"{argType.Name}: {argType.SizeBytes} bytes; {argType.AlignmentBytes}-byte aligned");

            // Get every field in a class or struct

            /*  x, offset 00 bytes, length 4 bytes, type float
             *  y, offset 04 bytes, length 4 bytes, type float
             *  z, offset 08 bytes, length 4 bytes, type float */
            foreach (var field in argType)
            {
                Console.WriteLine($"{field.Name}, offset {field.OffsetBytes:x2} bytes, length {field.SizeBytes} bytes, type {field.Type.Name}");
            }

            // Many other ways to access fields
            var fieldByByteOffset = argType[4][0]; // will get Vector3.y field
            var fieldByName       = argType["y"];

            if (fieldByName != fieldByByteOffset)
            {
                throw new Exception("This will never happen");
            }

            // Get any C++ type in the AppModel by name
            var typeDefType = appModel.CppTypeCollection.GetComplexType("Il2CppTypeDefinition");

            // You can also add types and methods to the AppModel
            // Examples are not shown here; browse AppModel.cs and CppTypeCollection.cs for details

            // You can generate an address map from the AppModel (Note: slow)
            // This is an IDictionary<ulong, object> which maps every address in an IL2CPP binary to its contents
            // as elements from the AppModel, for example function addresses will yield an AppMethod allowing you
            // to access both the C++ and .NET methods for the same function

            // This feature is currently highly experimental
            // See: Model/AddressMap.cs for example contents
            var map = appModel.GetAddressMap();

            // Set data.IsDataModified if you modify the AppModel
        }