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); }
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()); }
public MetadataImporter(MetadataReader reader, MetadataBuilder builder, LoggerBase logger) : base(logger) { _reader = reader; _builder = builder; }
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); } }
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); } }
public MetadataImporter(MetadataReader reader, MetadataBuilder builder, BlobBuilder ilStream, LoggerBase logger) : base(logger) { _reader = reader; _builder = builder; _ilStream = ilStream; }