Пример #1
0
        /**<summary>Get an assembly by name</summary>*/
        public virtual MetadataStream GetAssembly(string name)
        {
            MetadataStream ms;

            if (name == "netstandard")
            {
                name = "mscorlib";
            }

            var simple_name = StripPathAndExtension(name);

            if (cache.TryGetValue(simple_name, out ms))
            {
                return(ms);
            }

            var s = LoadAssembly(name);

            if (s == null)
            {
                return(null);
            }
            PEFile p = new metadata.PEFile();

            ms = p.Parse(s, this);

            cache[simple_name] = ms;
            return(ms);
        }
Пример #2
0
        /**<summary>Get an assembly by name and version</summary>*/
        public virtual MetadataStream GetAssembly(string name,
                                                  int major, int minor, int build, int revision)
        {
            MetadataStream ms;

            var simple_name = StripPathAndExtension(name);

            if (cache.TryGetValue(simple_name, out ms))
            {
                if (ms.MajorVersion == major &&
                    ms.MinorVersion == minor &&
                    ms.BuildVersion == build &&
                    ms.RevisionVersion == revision ||
                    RequireVersionMatch == false ||
                    major == -1)
                {
                    return(ms);
                }
            }

            var s = LoadAssembly(name);

            if (s == null)
            {
                return(null);
            }
            PEFile p = new metadata.PEFile();

            ms = p.Parse(s, this);
            if (ms == null)
            {
                return(null);
            }

            if (ms.MajorVersion == major &&
                ms.MinorVersion == minor &&
                ms.BuildVersion == build &&
                ms.RevisionVersion == revision ||
                RequireVersionMatch == false ||
                major == -1)
            {
                cache[simple_name] = ms;
                return(ms);
            }
            return(null);
        }
Пример #3
0
        public MetadataStream Parse(DataInterface file, AssemblyLoader al, bool fail_refs = true, bool is_pdb = false)
        {
            var m = new MetadataStream();

            m.al = al;

            long mroot_offset;

            if (is_pdb)
            {
                mroot_offset = 0;
                pdbf         = true;
            }
            else
            {
                pefh = new PE_File_Header();

                uint pefh_start = file.ReadUInt(0x3c) + 4;
                uint pesig      = file.ReadUInt((int)pefh_start - 4);
                System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: PE Signature: " + pesig.ToString("X8"));
                pefh.NumberOfSections = file.ReadUShort((int)pefh_start + 2);
                pefh.Sections         = new SectionHeader[pefh.NumberOfSections];
                TimeSpan t = new TimeSpan(0, 0, (int)(file.ReadUInt((int)pefh_start + 4) & 0x7fffffff));    // csc /deterministic sets top bit - ignore for timestamp purposes
                System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: t: " + ((int)file.ReadUInt((int)pefh_start + 4)).ToString());
                pefh.TimeDateStamp = new DateTime(1970, 1, 1) + t;
                pefh.OptHeaderSize = file.ReadUShort((int)pefh_start + 16);
                if (pefh.OptHeaderSize < 224)
                {
                    throw new Exception("PE optional header too small");
                }
                pefh.Chars = file.ReadUShort((int)pefh_start + 18);
                if ((pefh.Chars & 0x3) != 0x2)
                {
                    System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: Invalid PE file header characteristics: " + pefh.Chars.ToString());
                    System.Diagnostics.Debugger.Break();
                    throw new Exception("Invalid PE file header characteristics");
                }

                int    pe32plusoffset = 0;
                ushort magic          = file.ReadUShort((int)pefh_start + 20);
                if (magic == 0x20b)
                {
                    pe32plusoffset = 16;
                }

                pefh.CliHeader      = new DataDir();
                pefh.CliHeader.RVA  = file.ReadUInt((int)pefh_start + 228 + pe32plusoffset);
                pefh.CliHeader.Size = file.ReadUInt((int)pefh_start + 232 + pe32plusoffset);

                // Read the section headers
                uint sections_start = pefh_start + 20 + pefh.OptHeaderSize;
                for (uint i = 0; i < pefh.NumberOfSections; i++)
                {
                    uint s_start = sections_start + i * 40;
                    pefh.Sections[i] = new SectionHeader();

                    char[] w_str = new char[9];
                    for (int j = 0; j < 8; j++)
                    {
                        w_str[j] = (char)file.ReadByte((int)s_start + j);
                    }
                    w_str[8] = '\0';

                    pefh.Sections[i].Name = new String(w_str);
                    pefh.Sections[i].Name = pefh.Sections[i].Name.Remove(pefh.Sections[i].Name.IndexOf("\0"));
                    System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: section name: " + pefh.Sections[i].Name + "\n");

                    pefh.Sections[i].VSize    = file.ReadUInt((int)s_start + 8);
                    pefh.Sections[i].VAddress = file.ReadUInt((int)s_start + 12);
                    pefh.Sections[i].PSize    = file.ReadUInt((int)s_start + 16);
                    pefh.Sections[i].PAddress = file.ReadUInt((int)s_start + 20);

                    pefh.Sections[i].Chars = file.ReadUInt((int)s_start + 36);
                }

                // Read the Cli header
                if (pefh.CliHeader.RVA == 0)
                {
                    return(null);
                }
                long clih_offset = ResolveRVA(pefh.CliHeader.RVA);


                clih = new Cli_Header();
                clih.Metadata.RVA    = file.ReadUInt((int)clih_offset + 8);
                clih.Metadata.Size   = file.ReadUInt((int)clih_offset + 12);
                clih.EntryPointToken = file.ReadUInt((int)clih_offset + 20);
                clih.Resources.RVA   = file.ReadUInt((int)clih_offset + 24);
                clih.Resources.Size  = file.ReadUInt((int)clih_offset + 28);

                m.entry_point_token = clih.EntryPointToken;

                System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: CLI header parsed");

                // First, read the metadata root
                mroot_offset = ResolveRVA(clih.Metadata.RVA);
            }
            uint sig = file.ReadUInt((int)mroot_offset);

            if (sig != 0x424A5342)
            {
                throw new Exception("Invalid metadata root");
            }
            uint vstr_len = file.ReadUInt((int)mroot_offset + 12);

            m.VersionString = ReadSZ(file, (int)mroot_offset + 16);
            ushort nstr = file.ReadUShort((int)mroot_offset + 16 +
                                          (int)vstr_len + 2);

            int cur_offset = (int)mroot_offset + 16 + (int)vstr_len + 4;

            // Now, read the stream headers
            for (ushort i = 0; i < nstr; i++)
            {
                StreamHeader sh = new StreamHeader();
                sh.Offset     = file.ReadUInt(cur_offset);
                sh.FileOffset = ResolveRVA((is_pdb ? 0 : clih.Metadata.RVA) + sh.Offset);
                sh.Size       = file.ReadUInt(cur_offset + 4);

                cur_offset += 8;
                StringBuilder sb = new StringBuilder();
                while (true)
                {
                    byte strb = file.ReadByte(cur_offset++);
                    if (strb == 0)
                    {
                        break;
                    }
                    else
                    {
                        sb.Append((char)strb);
                    }
                }
                while ((cur_offset & 0x3) != 0)
                {
                    cur_offset++;
                }

                sh.Name = sb.ToString();

                System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: stream name: " + sh.Name);

                sh.di = file.Clone((int)sh.FileOffset);

                if (sh.Name == "#Strings")
                {
                    m.sh_string = sh;
                }
                else if (sh.Name == "#US")
                {
                    m.sh_us = sh;
                }
                else if (sh.Name == "#GUID")
                {
                    m.sh_guid = sh;
                }
                else if (sh.Name == "#Blob")
                {
                    m.sh_blob = sh;
                }
                else if (sh.Name == "#~")
                {
                    m.sh_tables = sh;
                }
                else if (sh.Name == "#Pdb")
                {
                    m.sh_pdb = sh;
                }
                else
                {
                    System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: unknown table \"" + sh.Name + "\"");
                    throw new Exception("Unknown metadata table");
                }
            }

            // Parse tables
            if (m.sh_tables != null)
            {
                var di  = m.sh_tables.di;
                var maj = di.ReadByte(4);
                var min = di.ReadByte(5);
                System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: parsing tables");
                System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: metadata table schema v" + maj.ToString() + "." + min.ToString());

                // Determine size of indices into the heaps
                var heapsizes = di.ReadByte(6);
                if ((heapsizes & 0x1) == 0x1)
                {
                    m.wide_string = true;
                }
                if ((heapsizes & 0x2) == 0x2)
                {
                    m.wide_guid = true;
                }
                if ((heapsizes & 0x4) == 0x4)
                {
                    m.wide_blob = true;
                }

                // Get list of valid tables
                var        valid        = di.ReadULong(8);
                int        valid_count  = 0;
                List <int> valid_tables = new List <int>();
                for (int i = 0; i < 64; i++)
                {
                    if (((valid >> i) & 0x1) == 0x1)
                    {
                        m.valid_tables[i] = true;
                        valid_count++;
                        valid_tables.Add(i);
                    }
                }

                // Get number of rows in each table
                int table_id = 0;
                foreach (var valid_table in valid_tables)
                {
                    m.table_rows[valid_table] = (int)di.ReadUInt(24 + 4 * table_id++);
                }

                // Interpret the schema of each table
                foreach (var valid_table in valid_tables)
                {
                    InterpretSchema(valid_table, m);
                }

                // Determine start offsets of each table
                int offset = 24 + 4 * valid_count;
                foreach (var valid_table in valid_tables)
                {
                    m.table_offsets[valid_table] = offset;
                    offset += m.table_rows[valid_table] * m.table_entry_size[valid_table];
                }
            }

            m.pef  = this;
            m.file = file;

            /* Get this assembly name */
            if (m.table_rows[MetadataStream.tid_Assembly] == 1)
            {
                m.assemblyName = m.GetStringEntry(MetadataStream.tid_Assembly, 1, 7);

                // Handle dotnet coreclr mscorlib having a different name
                if (m.assemblyName == "System.Private.CoreLib")
                {
                    m.assemblyName = "mscorlib";
                }

                System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: current assembly is " + m.assemblyName);
            }

            /* Load up all referenced assemblies */
            m.referenced_assemblies = new MetadataStream[m.table_rows[MetadataStream.tid_AssemblyRef]];
            for (int i = 1; i <= m.table_rows[MetadataStream.tid_AssemblyRef]; i++)
            {
                var ass_name = m.GetStringEntry(MetadataStream.tid_AssemblyRef, i, 6);
                var maj      = (int)m.GetIntEntry(MetadataStream.tid_AssemblyRef, i, 0);
                var min      = (int)m.GetIntEntry(MetadataStream.tid_AssemblyRef, i, 1);
                var build    = (int)m.GetIntEntry(MetadataStream.tid_AssemblyRef, i, 2);
                var rev      = (int)m.GetIntEntry(MetadataStream.tid_AssemblyRef, i, 3);

                if (ass_name == "netstandard")
                {
                    ass_name = "mscorlib";
                    maj      = -1;
                }

                System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: loading referenced assembly " + ass_name);

                if ((m.referenced_assemblies[i - 1] = al.GetAssembly(ass_name, maj, min, build, rev)) == null && fail_refs)
                {
                    var ale = new AssemblyLoadException();
                    ale.ReferencedAssembly = new AssemblyLoadException.ALEAssembly
                    {
                        Name     = ass_name,
                        Major    = maj,
                        Minor    = min,
                        Revision = rev,
                        Build    = build
                    };
                    ale.CurrentAssembly = new AssemblyLoadException.ALEAssembly
                    {
                        Name     = m.AssemblyName,
                        Major    = m.MajorVersion,
                        Minor    = m.MinorVersion,
                        Revision = m.RevisionVersion,
                        Build    = m.BuildVersion
                    };

                    foreach (var la in al.LoadedAssemblies)
                    {
                        var cla = al.GetAssembly(la);

                        var clale = new AssemblyLoadException.ALEAssembly
                        {
                            Name     = cla.AssemblyName,
                            Major    = cla.MajorVersion,
                            Minor    = cla.MinorVersion,
                            Revision = cla.RevisionVersion,
                            Build    = cla.BuildVersion
                        };
                        ale.CurrentlyLoadedAssemblies.Add(clale);
                    }
                    throw ale;
                }
            }

            m.PatchMethodDefOwners();
            m.PatchFieldDefOwners();
            m.PatchFieldRVAs();
            m.PatchClassLayouts();
            m.PatchFieldConstants();
            m.PatchGTypes();
            if (m.assemblyName == "mscorlib")
            {
                m.is_corlib = true;
                m.PatchSimpleTypes();
            }
            m.PatchNestedTypes();
            m.PatchCustomAttrs();

            m.LoadBuiltinTypes();

            System.Diagnostics.Debugger.Log(0, "metadata", "PEFile.Parse: parsing complete");

            /* Load up a .pdb sidecar file if necessary */
            if (m.sh_pdb != null)
            {
                m.pdb = m;
            }
            else
            {
                var fname = file.Name;
                if (fname != null)
                {
                    if (fname.EndsWith(".dll") || fname.EndsWith(".exe"))
                    {
                        fname = fname.Substring(0, fname.Length - 4);
                    }
                    var pdbf = al.LoadAssembly(fname + ".pdb");
                    if (pdbf != null)
                    {
                        var pef = new metadata.PEFile();
                        try
                        {
                            m.pdb = pef.Parse(pdbf, al, true, true);
                        }
                        catch (Exception)
                        {
                            m.pdb = null;
                        }
                    }
                }
            }

            return(m);
        }