Example #1
0
        internal DllField(FieldDefinition f)
        {
            LayoutOffset  = f.Offset;
            DeclaringType = DllTypeRef.From(f.DeclaringType);
            Type          = DllTypeRef.From(f.FieldType);
            Name          = f.Name;
            Offset        = -1;
            if (f.HasCustomAttributes)
            {
                foreach (var ca in f.CustomAttributes)
                {
                    if (ca.AttributeType.Name == "FieldOffsetAttribute")
                    {
                        if (ca.Fields.Count > 0)
                        {
                            Offset = Convert.ToInt32(ca.Fields.FirstOrDefault().Argument.Value as string, 16);
                        }
                    }
                    else
                    {
                        // Ignore the DummyDll attributes
                        var atr = new DllAttribute(ca);
                        if (!string.IsNullOrEmpty(atr.Name))
                        {
                            Attributes.Add(atr);
                        }
                    }
                }
            }

            Specifiers.AddRange(DllSpecifierHelpers.From(f));

            This     = f;
            Constant = f.Constant;
        }
 internal DllProperty(PropertyDefinition p)
 {
     DeclaringType = DllTypeRef.From(p.DeclaringType);
     Type          = DllTypeRef.From(p.PropertyType);
     Name          = p.Name;
     GetMethod     = p.GetMethod != null;
     SetMethod     = p.SetMethod != null;
     if (p.HasCustomAttributes)
     {
         Attributes.AddRange(p.CustomAttributes.Select(ca => new DllAttribute(ca)).Where(a => !string.IsNullOrEmpty(a.Name)));
     }
     Specifiers.AddRange(DllSpecifierHelpers.From(p));
 }
Example #3
0
        private ITypeData?Resolve(DllTypeRef typeRef)
        {
            // Generic parameters can never "Resolve"
            if (typeRef.IsGenericParameter)
            {
                return(null);
            }
            // TODO: Resolve only among our types that we actually plan on serializing
            // Basically, check it against our whitelist/blacklist
            ITypeData ret;

            if (typeRef.IsGenericInstance)
            {
                // This is a generic instance. We want to convert this instance to a generic type that we have already created in _types
                var def   = typeRef.This.Resolve();
                var check = DllTypeRef.From(def);
                // Try to get our Generic Definition out of _types
                if (!_types.TryGetValue(check, out ret))
                {
                    // This should never happen. All generic definitions should already be resolved.
                    throw new InvalidOperationException($"Generic instance: {typeRef} (definition: {check}) cannot map to any type in _types!");
                }
                return(ret);
            }

            if (!_types.TryGetValue(typeRef, out ret))
            {
                var def = typeRef.This.Resolve();
                if (def != null)
                {
                    ret = new DllTypeData(def, _config);
                    if (!_types.ContainsKey(ret.This))
                    {
                        Console.Error.WriteLine($"Too late to add {def} to Types!");
                    }
                    else
                    {
                        Console.Error.WriteLine($"{typeRef} already existed in _types?! Matching item: {_types[ret.This].This}");
                        ret = _types[ret.This];
                    }
                }
                else
                {
                    throw new InvalidOperationException($"Non-generic-parameter {typeRef} cannot be resolved!");
                }
            }
            return(ret);
        }
        internal DllTypeData(TypeDefinition def, DllConfig config)
        {
            _config = config;
            foreach (var i in def.Interfaces)
            {
                ImplementingInterfaces.Add(DllTypeRef.From(i.InterfaceType));
            }

            This = DllTypeRef.From(def);
            Type = def.IsEnum ? TypeEnum.Enum : (def.IsInterface ? TypeEnum.Interface : (def.IsValueType ? TypeEnum.Struct : TypeEnum.Class));
            Info = new TypeInfo
            {
                Refness = def.IsValueType ? Refness.ValueType : Refness.ReferenceType
            };

            if (def.BaseType != null)
            {
                Parent = DllTypeRef.From(def.BaseType);
            }

            // TODO: Parse this eventually
            TypeDefIndex = -1;

            if (_config.ParseTypeAttributes && def.HasCustomAttributes)
            {
                Attributes.AddRange(def.CustomAttributes.Select(ca => new DllAttribute(ca)).Where(a => !string.IsNullOrEmpty(a.Name)));
            }
            Layout = (ITypeData.LayoutKind)(def.Attributes & TypeAttributes.LayoutMask);
            if (_config.ParseTypeFields)
            {
                InstanceFields.AddRange(def.Fields.Where(f => !f.IsStatic).Select(f => new DllField(f)));
                StaticFields.AddRange(def.Fields.Where(f => f.IsStatic).Select(f => new DllField(f)));
            }
            if (_config.ParseTypeProperties)
            {
                Properties.AddRange(def.Properties.Select(p => new DllProperty(p)));
            }
            if (_config.ParseTypeMethods)
            {
                var mappedBaseMethods = new HashSet <MethodDefinition>();
                var methods           = def.Methods.Select(m => DllMethod.From(m, ref mappedBaseMethods)).ToList();
                // It's important that Foo.IBar.func() goes after func() (if present)
                Methods.AddRange(methods.Where(m => m.ImplementedFrom is null));
                Methods.AddRange(methods.Where(m => m.ImplementedFrom != null));
            }
        }
        internal DllField(FieldDefinition f, TypeDefinition info)
        {
            LayoutOffset  = f.Offset;
            DeclaringType = DllTypeRef.From(f.DeclaringType);
            Type          = DllTypeRef.From(f.FieldType);
            Name          = f.Name;
            Offset        = -1;
            if (f.HasCustomAttributes)
            {
                foreach (var ca in f.CustomAttributes)
                {
                    if (ca.AttributeType.Name == "FieldOffsetAttribute" || ca.AttributeType.Name == "StaticFieldOffsetAttribute")
                    {
                        if (ca.Fields.Count > 0)
                        {
                            Offset = Convert.ToInt32(ca.Fields.FirstOrDefault().Argument.Value as string, 16);
                        }
                        //if (info.IsEnum)
                        //    // Because Il2CppInspector is bad and emits 0x10 for fields on enums. I seriously don't know why.
                        //    Offset -= 0x10;
                    }
                    else
                    {
                        // Ignore the DummyDll attributes
                        var atr = new DllAttribute(ca);
                        if (!string.IsNullOrEmpty(atr.Name))
                        {
                            Attributes.Add(atr);
                        }
                    }
                }
            }

            Specifiers.AddRange(DllSpecifierHelpers.From(f));

            This     = f;
            Constant = f.Constant;
        }
Example #6
0
        internal DllData(string dir, DllConfig config)
        {
            _config = config;
            _dir    = dir;
            AddSearchDirectory(dir);
            _metadataResolver = new MetadataResolver(this);
            _readerParams     = new ReaderParameters(ReadingMode.Immediate)
            {
                AssemblyResolver = this,
                MetadataResolver = _metadataResolver
            };

            var modules = new List <ModuleDefinition>();

            foreach (var file in Directory.GetFiles(dir))
            {
                if (file.EndsWith(".dll") && !_config.BlacklistDlls.Contains(file))
                {
                    var assemb = AssemblyDefinition.ReadAssembly(file, _readerParams);
                    foreach (var module in assemb.Modules)
                    {
                        modules.Add(module);
                    }
                }
            }

            Queue <TypeDefinition> frontier = new Queue <TypeDefinition>();

            modules.ForEach(m => m.Types.ToList().ForEach(t =>
            {
                if (_config.ParseTypes && !_config.BlacklistTypes.Contains(t.Name))
                {
                    frontier.Enqueue(t);
                }
            }));

            while (frontier.Count > 0)
            {
                var t = frontier.Dequeue();
                if (t.Name.StartsWith("<") && t.Namespace.Length == 0 && t.DeclaringType is null)
                {
                    if (!t.Name.StartsWith("<Module>") && !t.Name.StartsWith("<PrivateImplementationDetails>"))
                    {
                        Console.Error.WriteLine($"Skipping TypeDefinition {t}");
                    }
                    continue;
                }

                var dllRef = DllTypeRef.From(t);
                if (!_types.ContainsKey(dllRef))
                {
                    var type = new DllTypeData(t, _config);
                    if (dllRef.DeclaringType != null)
                    {
                        _types[dllRef.DeclaringType].NestedTypes.AddOrThrow(type);
                    }
                    foreach (var nested in t.NestedTypes)
                    {
                        frontier.Enqueue(nested);
                    }
                    _types.Add(dllRef, type);
                }
                else
                {
                    Console.Error.WriteLine($"{dllRef} already in _types! Matching item: {_types[dllRef].This}");
                }
            }

            int total = DllTypeRef.Hits + DllTypeRef.Misses;

            Console.WriteLine($"{nameof(DllTypeRef)} cache hits: {DllTypeRef.Hits} / {total} = {100.0f * DllTypeRef.Hits / total}");
            // Ignore images for now.
        }
Example #7
0
        private DllMethod(MethodDefinition m, ref HashSet <MethodDefinition> mappedBaseMethods)
        {
            cache.Add(m, this);
            This = m;
            // Il2CppName is the MethodDefinition Name (hopefully we don't need to convert it for il2cpp, but we might)
            Il2CppName = m.Name;
            Name       = m.Name;
            Parameters.AddRange(m.Parameters.Select(p => new Parameter(p)));
            Specifiers.AddRange(DllSpecifierHelpers.From(m));
            // This is not necessary: m.GenericParameters.Any(param => !m.DeclaringType.GenericParameters.Contains(param));
            Generic           = m.HasGenericParameters;
            GenericParameters = m.GenericParameters.Select(g => DllTypeRef.From(g)).ToList();

            // This may not always be the case, we could have a special name in which case we have to do some sorcery
            // Grab the special name, grab the type from the special name
            int idxDot = Name.LastIndexOf('.');

            if (idxDot >= 2)
            {
                // Call a utilities function for converting a special name method to a proper base method
                var baseMethod = m.GetSpecialNameBaseMethod(out var iface, idxDot);
                if (baseMethod is null)
                {
                    throw new Exception("Failed to find baseMethod for dotted method name!");
                }
                if (iface is null)
                {
                    throw new Exception("Failed to get iface for dotted method name!");
                }
                if (!mappedBaseMethods.Add(baseMethod))
                {
                    throw new InvalidOperationException($"Base method: {baseMethod} has already been overriden!");
                }
                // Only one base method for special named methods
                BaseMethods.Add(From(baseMethod, ref mappedBaseMethods));
                ImplementedFrom = DllTypeRef.From(iface);
            }
            else
            {
                var baseMethod = m.GetBaseMethod();
                if (baseMethod == m)
                {
                    var baseMethods = m.GetBaseMethods();
                    if (baseMethods.Count > 0)
                    {
                        HidesBase = true;
                    }
                    // We need to check here SPECIFICALLY for a method in our declaring type that shares the same name as us, since we could have the same BaseMethod as it.
                    // If either ourselves or a method of the same safe name (after . prefixes) exists, we need to ensure that only the one with the dots gets the base method
                    // It correctly describes.
                    // Basically, we need to take all our specially named methods on our type that have already been defined and remove them from our current list of baseMethods.
                    // We should only ever have baseMethods of methods that are of methods that we haven't already used yet.
                    if (baseMethods.Count > 0)
                    {
                        foreach (var baseM in mappedBaseMethods)
                        {
                            baseMethods.Remove(baseM);
                        }
                    }
                    foreach (var bm in baseMethods)
                    {
                        BaseMethods.Add(From(bm, ref mappedBaseMethods));
                    }
                }
                else
                {
                    if (!mappedBaseMethods.Add(baseMethod))
                    {
                        throw new InvalidOperationException($"Base method: {baseMethod} has already been overriden!");
                    }
                    BaseMethods.Add(From(baseMethod, ref mappedBaseMethods));
                }
            }
            if (BaseMethods.Count > 0)
            {
                // TODO: This may not be true for generic methods. Should ensure validity for IEnumerator<T> methods
                // This method is an implemented/overriden method.
                // TODO: We need to double check to see if we need multiple ImplementedFroms
                ImplementedFrom = BaseMethods.First().DeclaringType;
                // Add ourselves to our BaseMethod's ImplementingMethods
                foreach (var bm in BaseMethods)
                {
                    bm.ImplementingMethods.Add(this);
                }
            }

            ReturnType    = DllTypeRef.From(m.ReturnType);
            DeclaringType = DllTypeRef.From(m.DeclaringType);
            // This is a very rare condition that we need to handle if it ever happens, but for now just log it
            if (m.HasOverrides)
            {
                Console.WriteLine($"{m}.HasOverrides!!! Overrides: {string.Join(", ", m.Overrides)}");
            }

            RVA    = -1;
            Offset = -1;
            VA     = -1;
            Slot   = -1;
            if (m.HasCustomAttributes)
            {
                foreach (var ca in m.CustomAttributes)
                {
                    if (ca.AttributeType.Name == "AddressAttribute")
                    {
                        if (ca.Fields.Count >= 3)
                        {
                            for (int i = 0; i < ca.Fields.Count; i++)
                            {
                                var f = ca.Fields[i];
                                if (f.Name == "RVA" || f.Name == "Offset" || f.Name == "VA")
                                {
                                    var val = Convert.ToInt32(f.Argument.Value as string, 16);
                                    if (f.Name == "RVA")
                                    {
                                        RVA = val;
                                    }
                                    else if (f.Name == "Offset")
                                    {
                                        Offset = val;
                                    }
                                    else if (f.Name == "VA")
                                    {
                                        VA = val;
                                    }
                                }
                                else if (f.Name == "Slot")
                                {
                                    Slot = Convert.ToInt32(f.Argument.Value as string);
                                }
                            }
                        }
                    }
                    else
                    {
                        // Ignore the DummyDll attributes
                        Attributes.Add(new DllAttribute(ca));
                    }
                }
            }
        }