Exemplo n.º 1
0
        public static void MakeRefasm(string inputPath, string outputPath, LoggerBase logger, IImportFilter filter = null)
        {
            logger.Debug?.Invoke($"Reading assembly {inputPath}");
            var peReader   = new PEReader(new FileStream(inputPath, FileMode.Open, FileAccess.Read));
            var metaReader = peReader.GetMetadataReader();

            if (!metaReader.IsAssembly)
            {
                throw new Exception("File format is not supported");
            }

            var result = MakeRefasm(metaReader, peReader, logger, filter);

            logger.Debug?.Invoke($"Writing result to {outputPath}");
            if (File.Exists(outputPath))
            {
                File.Delete(outputPath);
            }

            File.WriteAllBytes(outputPath, result);
        }
Exemplo n.º 2
0
        public static byte[] MakeRefasm(MetadataReader metaReader, PEReader peReader, LoggerBase logger, IImportFilter filter = null)
        {
            var metaBuilder = new MetadataBuilder();

            var importer = new MetadataImporter(metaReader, metaBuilder, logger);

            if (filter != null)
            {
                importer.Filter = filter;
                logger.Info?.Invoke("Using custom entity filter");
            }
            else if (importer.IsInternalsVisible())
            {
                importer.Filter = new AllowPublicAndInternals();
                logger.Info?.Invoke("InternalsVisibleTo attributes found, using AllowPublicAndInternals entity filter");
            }
            else
            {
                importer.Filter = new AllowPublic();
                logger.Info?.Invoke("Using AllowPublic entity filter");
            }

            var mvidBlob = importer.Import();

            logger.Debug?.Invoke($"Building reference assembly");

            var metaRootBuilder = new MetadataRootBuilder(metaBuilder, metaReader.MetadataVersion, true);

            var peHeaderBuilder = new PEHeaderBuilder(
                peReader.PEHeaders.CoffHeader.Machine,
                peReader.PEHeaders.PEHeader.SectionAlignment,
                peReader.PEHeaders.PEHeader.FileAlignment,
                peReader.PEHeaders.PEHeader.ImageBase,
                peReader.PEHeaders.PEHeader.MajorLinkerVersion,
                peReader.PEHeaders.PEHeader.MinorLinkerVersion,
                peReader.PEHeaders.PEHeader.MajorOperatingSystemVersion,
                peReader.PEHeaders.PEHeader.MinorOperatingSystemVersion,
                peReader.PEHeaders.PEHeader.MajorImageVersion,
                peReader.PEHeaders.PEHeader.MinorImageVersion,
                peReader.PEHeaders.PEHeader.MajorSubsystemVersion,
                peReader.PEHeaders.PEHeader.MinorSubsystemVersion,
                peReader.PEHeaders.PEHeader.Subsystem,
                peReader.PEHeaders.PEHeader.DllCharacteristics,
                peReader.PEHeaders.CoffHeader.Characteristics,
                peReader.PEHeaders.PEHeader.SizeOfStackReserve,
                peReader.PEHeaders.PEHeader.SizeOfStackCommit,
                peReader.PEHeaders.PEHeader.SizeOfHeapReserve,
                peReader.PEHeaders.PEHeader.SizeOfHeapCommit
                );

            var ilStream = new BlobBuilder();

            var peBuilder = new ManagedPEBuilder(peHeaderBuilder, metaRootBuilder, ilStream,
                                                 deterministicIdProvider: blobs =>
            {
                var hasher = IncrementalHash.CreateHash(HashAlgorithmName.SHA256) ?? throw new Exception("Cannot create hasher");

                foreach (var segment in blobs.Select(b => b.GetBytes()))
                {
                    hasher.AppendData(segment.Array, segment.Offset, segment.Count);
                }

                return(BlobContentId.FromHash(hasher.GetHashAndReset()));
            });

            var blobBuilder = new BlobBuilder();
            var contentId   = peBuilder.Serialize(blobBuilder);

            mvidBlob.CreateWriter().WriteGuid(contentId.Guid);

            return(blobBuilder.ToArray());
        }
Exemplo n.º 3
0
 public MetadataImporter(MetadataReader reader, MetadataBuilder builder, LoggerBase logger) : base(logger)
 {
     _reader  = reader;
     _builder = builder;
 }
Exemplo n.º 4
0
        public static int Main(string[] args)
        {
            var inputs    = new List <string>();
            var operation = Operation.MakeRefasm;

            var verbosity        = LogLevel.Warning;
            var showHelp         = false;
            var quiet            = false;
            var continueOnErrors = false;

            var fileListAttr = new Dictionary <string, string>();

            var options = new OptionSet
            {
                { "v", "increase verbosity", v => { if (v != null && verbosity > LogLevel.Trace)
                                                    {
                                                        verbosity--;
                                                    }
                  } },
                { "q|quiet", "be quiet", v => quiet = v != null },
                { "h|?|help", "show help", v => showHelp = v != null },
                { "c|continue", "continue on errors", v => continueOnErrors = v != null },

                { "O|outputdir=", "set output directory", v => _outputDir = v },
                { "o|output=", "set output file, for single file only", v => _outputFile = v },

                { "r|refasm", "make reference assembly, default action", v => { if (v != null)
                                                                                {
                                                                                    operation = Operation.MakeRefasm;
                                                                                }
                  } },
                { "w|overwrite", "overwrite source files", v => _overwrite = v != null },

                { "p|public", "drop non-public types even with InternalsVisibleTo", v => _public = v != null },
                { "i|internals", "import public and internal types", v => _internals = v != null },
                { "all", "ignore visibility and import all", v => _all = v != null },

                { "m|mock", "make mock assembly instead of reference assembly", p => _makeMock = p != null },
                { "n|noattr", "omit reference assembly attribute", p => _omitReferenceAssemblyAttr = p != null },

                { "l|list", "make file list xml", v => { if (v != null)
                                                         {
                                                             operation = Operation.MakeXmlList;
                                                         }
                  } },
                { "a|attr=", "add FileList tag attribute", v => AddFileListAttr(v, fileListAttr) },

                { "g|globs", "expand globs internally: ?, *, **", p => _expandGlobs = p != null },

                { "<>", "one or more input files", v => inputs.Add(v) },
            };

            try
            {
                options.Parse(args);
            }
            catch (InvalidOptionException e)
            {
                Console.Error.WriteLine(e.Message);
                return(1);
            }
            catch (Exception e)
            {
                Console.Error.WriteLine($"{e}");
                return(1);
            }

            if (quiet)
            {
                verbosity = LogLevel.None;
            }

            if (showHelp || args.Length == 0)
            {
                var selfName = Path.GetFileName(Environment.GetCommandLineArgs()[0]);

                Console.Out.WriteLine($"Usage: {selfName} [options] <dll> [<**/*.dll> ...]");
                Console.Out.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return(0);
            }

            if (!string.IsNullOrEmpty(_outputFile) && inputs.Count > 1)
            {
                Console.Error.WriteLine("Output file should not be specified for many inputs");
                return(2);
            }

            _logger = new LoggerBase(new VerySimpleLogger(Console.Error, verbosity));

            try
            {
                _logger.Trace?.Invoke($"Program arguments: {string.Join(" ", args)}");

                // Apply input globbing
                var dirCurrent     = new DirectoryInfo(Environment.CurrentDirectory);
                var inputsExpanded = inputs.SelectMany(input => ExpandInput(input, dirCurrent, _logger)).OrderBy(t => t.Path, StringComparer.OrdinalIgnoreCase).ToImmutableArray();

                // Re-check for the second time, after expanding globs
                if (!string.IsNullOrEmpty(_outputFile) && inputs.Count > 1)
                {
                    Console.Error.WriteLine("Output file should not be specified for many inputs");
                    return(2);
                }

                XmlTextWriter xmlWriter = null;

                if (operation == Operation.MakeXmlList)
                {
                    xmlWriter = !string.IsNullOrEmpty(_outputFile)
                        ? new XmlTextWriter(_outputFile, Encoding.UTF8)
                        : new XmlTextWriter(Console.Out);

                    xmlWriter.Formatting = Formatting.Indented;

                    xmlWriter.WriteStartDocument();
                    xmlWriter.WriteStartElement("FileList");

                    foreach (var kv in fileListAttr)
                    {
                        xmlWriter.WriteAttributeString(kv.Key, kv.Value);
                    }
                }

                _logger.Info?.Invoke($"Processing {inputs.Count} assemblies");
                for (var nInput = 0; nInput < inputsExpanded.Length; nInput++)
                {
                    var input = inputsExpanded[nInput];
                    _logger.Info?.Invoke($"Processing {input.Path}");
                    using (_logger.WithLogPrefix($"[{Path.GetFileName(input.RelativeForOutput)}]"))
                    {
                        try
                        {
                            switch (operation)
                            {
                            case Operation.MakeRefasm:
                                MakeRefasm(input);
                                break;

                            case Operation.MakeXmlList:
                                WriteAssemblyToXml(input, xmlWriter);
                                break;

                            default:
                                throw new ArgumentOutOfRangeException();
                            }
                        }
                        catch (InvalidOperationException e)
                        {
                            _logger.Error?.Invoke(e.Message);
                            if (continueOnErrors)
                            {
                                continue;
                            }
                            if (nInput < inputsExpanded.Length - 1) // When doing multiple files, let user know some might be left undone
                            {
                                _logger.Error?.Invoke($"Aborted on first error, {inputsExpanded.Length - nInput + 1:N0} files left unprocessed; pass “--continue” to try them anyway");
                            }
                            return(1);
                        }
                    }
                }

                if (xmlWriter != null)
                {
                    xmlWriter.WriteEndElement();
                    xmlWriter.WriteEndDocument();

                    xmlWriter.Close();
                }

                _logger.Info?.Invoke("All done");
                return(0);
            }
            catch (Exception e)
            {
                _logger.Error?.Invoke($"{e}");
                _logger.Error?.Invoke("ABORTED"); // When doing multiple files, let user know some might be left undone
                return(1);
            }
        }
Exemplo n.º 5
0
        public static int Main(string[] args)
        {
            var inputs    = new List <string>();
            var operation = Operation.MakeRefasm;

            var verbosity        = LogLevel.Warning;
            var showHelp         = false;
            var quiet            = false;
            var continueOnErrors = false;

            var fileListAttr = new Dictionary <string, string>();

            var options = new OptionSet
            {
                { "v", "increase verbosity", v => { if (v != null && verbosity > LogLevel.Trace)
                                                    {
                                                        verbosity--;
                                                    }
                  } },
                { "q|quiet", "be quiet", v => quiet = v != null },
                { "h|help", "show help", v => showHelp = v != null },
                { "c|continue", "continue on errors", v => continueOnErrors = v != null },

                { "O|outputdir=", "set output directory", v => _outputDir = v },
                { "o|output=", "set output file, for single file only", v => _outputFile = v },

                { "r|refasm", "make reference assembly, default action", v => { if (v != null)
                                                                                {
                                                                                    operation = Operation.MakeRefasm;
                                                                                }
                  } },
                { "w|overwrite", "overwrite source files", v => _overwrite = v != null },

                { "l|list", "make file list xml", v => { if (v != null)
                                                         {
                                                             operation = Operation.MakeXmlList;
                                                         }
                  } },
                { "a|attr=", "add FileList tag attribute", v => AddFileListAttr(v, fileListAttr) },

                { "<>", v => inputs.Add(v) },
            };

            try
            {
                options.Parse(args);
            }
            catch (InvalidOptionException e)
            {
                Console.Error.WriteLine(e.Message);
                return(1);
            }
            catch (Exception e)
            {
                Console.Error.WriteLine($"{e}");
                return(1);
            }

            if (quiet)
            {
                verbosity = LogLevel.None;
            }

            if (showHelp)
            {
                var selfName = Path.GetFileName(Environment.GetCommandLineArgs()[0]);

                Console.Out.WriteLine($"Usage: {selfName} [options] <dll> [<dll> ...]");
                Console.Out.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return(0);
            }

            if (!string.IsNullOrEmpty(_outputFile) && inputs.Count > 1)
            {
                Console.Error.WriteLine("Output file should not be specified for many inputs");
                return(2);
            }

            _logger = new LoggerBase(new VerySimpleLogger(Console.Error, verbosity));

            try
            {
                if (!Directory.Exists(_outputDir))
                {
                    Directory.CreateDirectory(_outputDir);
                }

                _logger.Trace?.Invoke($"Program arguments: {string.Join(" ", args)}");

                XmlTextWriter xmlWriter = null;

                if (operation == Operation.MakeXmlList)
                {
                    xmlWriter = !string.IsNullOrEmpty(_outputFile)
                        ? new XmlTextWriter(_outputFile, Encoding.UTF8)
                        : new XmlTextWriter(Console.Out);

                    xmlWriter.Formatting = Formatting.Indented;

                    xmlWriter.WriteStartDocument();
                    xmlWriter.WriteStartElement("FileList");

                    foreach (var(key, value) in fileListAttr)
                    {
                        xmlWriter.WriteAttributeString(key, value);
                    }

                    inputs.Sort();
                }

                _logger.Info?.Invoke($"Processing {inputs.Count} assemblies");
                foreach (var input in inputs)
                {
                    _logger.Info?.Invoke($"Processing {input}");
                    using (_logger.WithLogPrefix($"[{Path.GetFileName(input)}]"))
                    {
                        MetadataReader metaReader;

                        PEReader peReader;
                        try
                        {
                            _logger.Debug?.Invoke($"Reading assembly {input}");
                            peReader   = new PEReader(new FileStream(input, FileMode.Open));
                            metaReader = peReader.GetMetadataReader();

                            if (!metaReader.IsAssembly)
                            {
                                _logger.Warning?.Invoke($"Dll has no assembly: {input}");
                            }
                        }
                        catch (InvalidOperationException e)
                        {
                            _logger.Error?.Invoke(e.Message);
                            if (continueOnErrors)
                            {
                                continue;
                            }
                            return(1);
                        }

                        switch (operation)
                        {
                        case Operation.MakeRefasm:
                            MakeRefasm(metaReader, peReader, input);
                            break;

                        case Operation.MakeXmlList:
                            WriteAssemblyToXml(metaReader, xmlWriter);
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                }

                if (xmlWriter != null)
                {
                    xmlWriter.WriteEndElement();
                    xmlWriter.WriteEndDocument();

                    xmlWriter.Close();
                }

                _logger.Info?.Invoke("All done");
                return(0);
            }
            catch (Exception e)
            {
                _logger.Error?.Invoke($"{e}");
                return(1);
            }
        }
Exemplo n.º 6
0
 public MetadataImporter(MetadataReader reader, MetadataBuilder builder, BlobBuilder ilStream, LoggerBase logger) : base(logger)
 {
     _reader   = reader;
     _builder  = builder;
     _ilStream = ilStream;
 }