// Generate the C structure for virtual function calls in a given type (the VTable)
        private CppComplexType GenerateVTableStruct(TypeInfo ti)
        {
            MethodBase[] vtable;
            if (ti.IsInterface)
            {
                /* Interface vtables are just all of the interface methods.
                 * You might have to type a local variable manually as an
                 * interface vtable during an interface call, but the result
                 * should display the correct method name (with a computed
                 * InterfaceOffset added).
                 */
                vtable = ti.DeclaredMethods.ToArray();
            }
            else
            {
                vtable = ti.GetVTable();
            }
            var name  = TypeNamer.GetName(ti);
            var namer = CreateNamespace().MakeNamer <int>((i) => vtable[i]?.Name?.ToCIdentifier() ?? "__unknown");

            // Il2Cpp switched to `VirtualInvokeData *vtable` in Unity 5.3.6.
            // Previous versions used `MethodInfo **vtable`.
            // TODO: Consider adding function types. This considerably increases the script size
            // but can significantly help with reverse-engineering certain binaries.
            var vtableStruct = types.Struct(name + "__VTable");

            if (UnityVersion.CompareTo("5.3.6") < 0)
            {
                for (int i = 0; i < vtable.Length; i++)
                {
                    types.AddField(vtableStruct, namer.GetName(i), "MethodInfo *");
                }
            }
            else
            {
                for (int i = 0; i < vtable.Length; i++)
                {
                    types.AddField(vtableStruct, namer.GetName(i), "VirtualInvokeData");
                }
            }
            return(vtableStruct);
        }
Esempio n. 2
0
 private static void CompareTo(UnityVersion l, UnityVersion r, int result)
 {
     if (!ReferenceEquals(l, null))
     {
         Assert.AreEqual(Math.Sign(l.CompareTo(r)), Math.Sign(result));
     }
     if (!ReferenceEquals(r, null))
     {
         Assert.AreEqual(Math.Sign(r.CompareTo(l)), -Math.Sign(result));
     }
 }
Esempio n. 3
0
        // Generate a C declaration for a method
        private string GenerateMethodDeclaration(MethodBase method, string name, TypeInfo declaringType)
        {
            string retType;

            if (method is MethodInfo mi)
            {
                retType = mi.ReturnType.FullName == "System.Void" ? "void" : AsCType(mi.ReturnType);
            }
            else
            {
                retType = "void";
            }

            var paramNs = CreateNamespace();

            paramNs.ReserveName("method");
            var paramNamer = paramNs.MakeNamer <ParameterInfo>((pi) => pi.Name == "" ? "arg" : pi.Name.ToCIdentifier());

            var paramList = new List <string>();

            // Figure out the "this" param
            if (method.IsStatic)
            {
                // In older versions, static methods took a dummy this parameter
                if (UnityVersion.CompareTo("2018.3.0") < 0)
                {
                    paramList.Add("void *this");
                }
            }
            else
            {
                if (declaringType.IsValueType)
                {
                    // Methods for structs take the boxed object as the this param
                    paramList.Add($"struct {TypeNamer.GetName(declaringType)}__Boxed * this");
                }
                else
                {
                    paramList.Add($"{AsCType(declaringType)} this");
                }
            }

            foreach (var pi in method.DeclaredParameters)
            {
                paramList.Add($"{AsCType(pi.ParameterType)} {paramNamer.GetName(pi)}");
            }

            paramList.Add($"struct MethodInfo *method");

            return($"{retType} {name}({string.Join(", ", paramList)})");
        }
Esempio n. 4
0
        // Generate the overall Il2CppClass-shaped structure for the given type
        private void GenerateTypeStruct(StringBuilder csrc, TypeInfo ti)
        {
            var name = TypeNamer.GetName(ti);

            GenerateVTableStruct(csrc, ti);

            csrc.Append($"struct {name}__StaticFields {{\n");
            var namer = CreateNamespace().MakeNamer <FieldInfo>((field) => field.Name.ToCIdentifier());

            foreach (var field in ti.DeclaredFields)
            {
                if (field.IsLiteral || !field.IsStatic)
                {
                    continue;
                }
                csrc.Append($"  {AsCType(field.FieldType)} {namer.GetName(field)};\n");
            }
            csrc.Append($"}};\n");

            /* TODO: type the rgctx_data */
            if (UnityVersion.CompareTo("5.5.0") < 0)
            {
                csrc.Append(
                    $"struct {name}__Class {{\n" +
                    $"  struct Il2CppClass_0 _0;\n" +
                    $"  struct {name}__VTable *vtable;\n" +
                    $"  Il2CppRuntimeInterfaceOffsetPair *interfaceOffsets;\n" +
                    $"  struct {name}__StaticFields *static_fields;\n" +
                    $"  const Il2CppRGCTXData *rgctx_data;\n" +
                    $"  struct Il2CppClass_1 _1;\n" +
                    $"}};\n");
            }
            else
            {
                csrc.Append(
                    $"struct {name}__Class {{\n" +
                    $"  struct Il2CppClass_0 _0;\n" +
                    $"  Il2CppRuntimeInterfaceOffsetPair *interfaceOffsets;\n" +
                    $"  struct {name}__StaticFields *static_fields;\n" +
                    $"  const Il2CppRGCTXData *rgctx_data;\n" +
                    $"  struct Il2CppClass_1 _1;\n" +
                    $"  struct {name}__VTable vtable;\n" +
                    $"}};\n");
            }
        }
Esempio n. 5
0
 // Determine if this range contains the specified version
 public bool Contains(UnityVersion version) => version.CompareTo(Min) >= 0 && (Max == null || version.CompareTo(Max) <= 0);