Beispiel #1
0
        private static void SerializeImageToDisk(
            DevirtualisationOptions options,
            DevirtualisationContext context,
            ModuleDefinition module,
            string fileName)
        {
            var imageBuilder = new ManagedPEImageBuilder();

            var result = imageBuilder.CreateImage(module);

            if (result.DiagnosticBag.IsFatal)
            {
                throw new AggregateException(result.DiagnosticBag.Exceptions);
            }

            foreach (var error in result.DiagnosticBag.Exceptions)
            {
                context.Logger.Error(Tag, error.Message);
            }

            var fileBuilder = new ManagedPEFileBuilder();
            var file        = fileBuilder.CreateFile(result.ConstructedImage);

            file.Write(Path.Combine(options.OutputOptions.RootDirectory, fileName));
        }
Beispiel #2
0
        private ModuleDefinition ResolveRuntimeModule(DevirtualisationOptions options, ModuleDefinition targetModule)
        {
            ModuleDefinition runtimeModule = null;

            if (options.AutoDetectRuntimeFile)
            {
                Logger.Debug(Tag, "Attempting to autodetect location of the runtime library...");
                var runtimeAssemblies = targetModule.AssemblyReferences
                                        .Where(r => RuntimeAssemblyNames.Contains(r.Name))
                                        .ToArray();

                switch (runtimeAssemblies.Length)
                {
                case 0:
                    // No assembly references detected, default to embedded.
                    Logger.Debug(Tag, "No references found to a runtime library.");
                    options.RuntimeFile = options.InputFile;
                    break;

                case 1:
                    // A single assembly reference with a known KoiVM runtime library name was found.
                    Logger.Debug(Tag, $"Reference to runtime library detected ({runtimeAssemblies[0].Name}).");
                    options.RuntimeFile =
                        Path.Combine(Path.GetDirectoryName(options.InputFile), runtimeAssemblies[0].Name + ".dll");
                    break;

                default:
                    // Multiple assembly references with a known KoiVM runtime library name were found.
                    // Report to the user that they have to choose which one to use.
                    throw new DevirtualisationException(
                              "Multiple runtime assembly reference detected. "
                              + "Please specify the location of the runtime assembly to use in the devirtualizer options.");
                }
            }

            if (options.RuntimeIsEmbedded)
            {
                // Runtime is embedded into the assembly, so they share the same metadata image.
                Logger.Log(Tag, "Runtime is embedded in the target assembly.");
                runtimeModule = targetModule;
            }
            else if (options.RuntimeFile != null)
            {
                // Resolve runtime library.
                Logger.Log(Tag, $"Opening external runtime library located at {options.RuntimeFile}...");

                string runtimePath = Path.IsPathRooted(options.RuntimeFile)
                    ? options.RuntimeFile
                    : Path.Combine(Path.GetDirectoryName(options.InputFile), options.RuntimeFile);
                runtimeModule = ModuleDefinition.FromFile(runtimePath);
            }
            else
            {
                throw new DevirtualisationException(
                          "Failed to resolve runtime library. This could be a bug in the initial scanning phase. "
                          + "Try specifying the location of the runtime assembly in the devirtualizer options.");
            }

            return(runtimeModule);
        }
Beispiel #3
0
        private DevirtualisationContext CreateDevirtualisationContext(DevirtualisationOptions options)
        {
            // Open target file.
            Logger.Log(Tag, $"Opening target file {options.InputFile}...");
            var assembly = WindowsAssembly.FromFile(options.InputFile);
            var header   = assembly.NetDirectory?.MetadataHeader;

            if (header == null)
            {
                throw new BadImageFormatException("Assembly does not contain a valid .NET header.");
            }

            // Hook into md stream parser.
            var parser = new KoiVmAwareStreamParser(options.KoiStreamName, Logger);

            if (options.OverrideKoiStreamData)
            {
                string path = Path.IsPathRooted(options.KoiStreamDataFile)
                    ? options.KoiStreamDataFile
                    : Path.Combine(Path.GetDirectoryName(options.InputFile), options.KoiStreamDataFile);

                Logger.Log(Tag, $"Opening external Koi stream data file {path}...");
                parser.ReplacementData = File.ReadAllBytes(path);

                var streamHeader = header.StreamHeaders.FirstOrDefault(h => h.Name == options.KoiStreamName);
                if (streamHeader == null)
                {
                    streamHeader = new MetadataStreamHeader(options.KoiStreamName)
                    {
                        Stream = KoiStream.FromReadingContext(
                            new ReadingContext()
                        {
                            Reader = new MemoryStreamReader(parser.ReplacementData)
                        }, Logger)
                    };
                    header.StreamHeaders.Add(streamHeader);
                }
            }

            header.StreamParser = parser;

            // Ignore invalid / encrypted method bodies when specified.
            if (options.IgnoreInvalidMethodBodies)
            {
                var table = header.GetStream <TableStream>().GetTable <MethodDefinitionTable>();
                table.MethodBodyReader = new DefaultMethodBodyReader {
                    ThrowOnInvalidMethodBody = false
                };
            }

            // Lock image and set custom md resolver.
            var image = header.LockMetadata();

            image.MetadataResolver = new DefaultMetadataResolver(
                new DefaultNetAssemblyResolver(Path.GetDirectoryName(options.InputFile)));

            var runtimeImage = ResolveRuntimeImage(options, image);

            return(new DevirtualisationContext(options, image, runtimeImage, Logger));
        }
Beispiel #4
0
        public void Devirtualise(DevirtualisationOptions options)
        {
            Logger.Log(Tag, "Started devirtualisation.");

            // Create output directory.
            options.OutputOptions.EnsureDirectoriesExist();

            var context = CreateDevirtualisationContext(options);

            // Run pipeline.
            RunPipeline(context);

            // Unlock images.
            Logger.Log(Tag, $"Commiting changes to metadata streams...");
            context.TargetImage.Header.UnlockMetadata();

            bool rebuildRuntimeImage = options.RenameSymbols && !options.RuntimeIsEmbedded;

            if (rebuildRuntimeImage)
            {
                context.RuntimeImage.Header.UnlockMetadata();
            }

            RemoveFinalTraces(options, context);

            // Rebuild.
            Rebuild(options, context, rebuildRuntimeImage);

            Logger.Log(Tag, $"Finished. All fish were caught and served!");
        }
Beispiel #5
0
        private DevirtualisationContext CreateDevirtualisationContext(DevirtualisationOptions options)
        {
            string workingDirectory = Path.GetDirectoryName(options.InputFile);

            // Open target PE.
            Logger.Log(Tag, $"Opening target file {options.InputFile}...");
            var peFile = PEFile.FromFile(options.InputFile);

            // Create #Koi stream aware metadata reader.
            var streamReader = options.OverrideKoiStreamData
                ? new DefaultMetadataStreamReader()
                : (IMetadataStreamReader) new KoiVmAwareStreamReader(options.KoiStreamName, Logger);

            var peImage = PEImage.FromFile(peFile, new PEReaderParameters
            {
                MetadataStreamReader = streamReader
            });

            var metadata = peImage.DotNetDirectory?.Metadata;

            if (metadata is null)
            {
                throw new BadImageFormatException("Assembly does not contain a valid .NET header.");
            }

            // If custom koi stream data was provided, inject it.
            KoiStream koiStream;

            if (!options.OverrideKoiStreamData)
            {
                koiStream = metadata.GetStream <KoiStream>() ?? throw new DevirtualisationException(
                                      "Koi stream was not found in the target PE. This could be because the input file is " +
                                      "not protected with KoiVM, or the metadata stream uses a name that is different " +
                                      "from the one specified in the input parameters.");
            }
            else
            {
                string path = Path.IsPathRooted(options.KoiStreamDataFile)
                    ? options.KoiStreamDataFile
                    : Path.Combine(workingDirectory, options.KoiStreamDataFile);

                Logger.Log(Tag, $"Opening external Koi stream data file {path}...");
                var contents = File.ReadAllBytes(path);

                // Replace original koi stream if it existed.
                koiStream = new KoiStream(options.KoiStreamName, new DataSegment(contents), Logger);
            }

            // Ignore invalid / encrypted method bodies when specified.
            var moduleReadParameters = new ModuleReaderParameters(workingDirectory,
                                                                  options.IgnoreInvalidMD ? (IErrorListener)ThrowErrorListener.Instance : EmptyErrorListener.Instance);

            var module        = ModuleDefinition.FromImage(peImage, moduleReadParameters);
            var runtimeModule = ResolveRuntimeModule(options, module);

            koiStream.ResolutionContext = module;
            return(new DevirtualisationContext(options, module, runtimeModule, koiStream, Logger));
        }
Beispiel #6
0
        public DevirtualisationContext(DevirtualisationOptions options, MetadataImage targetImage, MetadataImage runtimeImage, ILogger logger)
        {
            Options      = options ?? throw new ArgumentNullException(nameof(options));
            TargetImage  = targetImage ?? throw new ArgumentNullException(nameof(targetImage));
            RuntimeImage = runtimeImage ?? throw new ArgumentNullException(nameof(runtimeImage));
            Logger       = logger ?? throw new ArgumentNullException(nameof(logger));

            ReferenceImporter = new ReferenceImporter(targetImage);
        }
        public DevirtualisationContext(DevirtualisationOptions options, ModuleDefinition targetModule,
                                       ModuleDefinition runtimeModule, KoiStream koiStream, ILogger logger)
        {
            Options       = options ?? throw new ArgumentNullException(nameof(options));
            TargetModule  = targetModule ?? throw new ArgumentNullException(nameof(targetModule));
            RuntimeModule = runtimeModule ?? throw new ArgumentNullException(nameof(runtimeModule));
            KoiStream     = koiStream ?? throw new ArgumentNullException(nameof(koiStream));
            Logger        = logger ?? throw new ArgumentNullException(nameof(logger));

            ReferenceImporter = new ReferenceImporter(targetModule);
        }
Beispiel #8
0
        private void Rebuild(DevirtualisationOptions options, DevirtualisationContext context)
        {
            bool rebuildRuntimeImage = options.RenameSymbols && !options.RuntimeIsEmbedded;

            Logger.Log(Tag, $"Reassembling image...");
            SerializeImageToDisk(options, context, context.TargetModule, Path.GetFileName(options.InputFile));

            if (rebuildRuntimeImage)
            {
                Logger.Log(Tag, $"Reassembling runtime image...");
                SerializeImageToDisk(options, context, context.RuntimeModule, Path.GetFileName(context.Options.RuntimeFile));
            }
        }
Beispiel #9
0
        private void Rebuild(DevirtualisationOptions options, DevirtualisationContext context, bool rebuildRuntimeImage)
        {
            Logger.Log(Tag, $"Reassembling file...");
            context.TargetAssembly.Write(
                Path.Combine(options.OutputOptions.RootDirectory, Path.GetFileName(options.InputFile)),
                new CompactNetAssemblyBuilder(context.TargetAssembly));

            if (rebuildRuntimeImage)
            {
                context.RuntimeAssembly.Write(
                    Path.Combine(options.OutputOptions.RootDirectory, Path.GetFileName(context.Options.RuntimeFile)),
                    new CompactNetAssemblyBuilder(context.RuntimeAssembly));
            }
        }
Beispiel #10
0
 private void RemoveFinalTraces(DevirtualisationOptions options, DevirtualisationContext context)
 {
     // Remove #koi stream.
     if (!context.AllVirtualisedMethodsRecompiled)
     {
         var header = context.TargetImage.Header;
         Logger.Debug(Tag, "Removing #Koi metadata stream...");
         header.StreamHeaders.Remove(header.GetStream <KoiStream>().StreamHeader);
     }
     else
     {
         Logger.Debug(Tag, "Not removing koi stream as some exports were ignored.");
     }
 }
Beispiel #11
0
        public void Devirtualise(DevirtualisationOptions options)
        {
            Logger.Log(Tag, "Started devirtualisation.");

            // Create output directory.
            options.OutputOptions.EnsureDirectoriesExist();

            var context = CreateDevirtualisationContext(options);

            // Run pipeline.
            RunPipeline(context);

            // Rebuild.
            Rebuild(options, context);

            Logger.Log(Tag, $"Finished. All fish were caught and served!");
        }