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); }
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); }
// 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 }