public void ReadSmallMethodBody()
        {
            var assembly = WindowsAssembly.FromFile(typeof(Class1).Assembly.Location);
            var header   = assembly.NetDirectory.MetadataHeader;

            var methodToken = new MetadataToken((uint)typeof(Class1).GetMethod("MyMethod").MetadataToken);
            var methodRow   = header.GetStream <TableStream>().GetTable <MethodDefinitionTable>()[(int)(methodToken.Rid - 1)];

            Assert.IsType <CilRawSmallMethodBody>(methodRow.Column1);

            var image  = header.LockMetadata();
            var method = image.Assembly.Modules[0].TopLevelTypes.First(x => x.Name == "Class1").Methods
                         .First(x => x.Name == "MyMethod");

            var body = method.CilMethodBody;

            Assert.NotNull(body);
            Assert.False(body.IsFat);
            Assert.False(body.InitLocals);
            Assert.Equal(0, body.ExceptionHandlers.Count);
            Assert.Null(body.Signature);

            var instructions = body.Instructions;

            Assert.Contains(instructions, x => x.OpCode.Code == CilCode.Ldstr);
            Assert.Contains(instructions, x => x.OpCode.Code == CilCode.Call);
            Assert.Contains(instructions, x => x.OpCode.Code == CilCode.Ret);
        }
        public void ExtensionMethodTest()
        {
            var sourceAssembly = WindowsAssembly.FromFile(typeof(StaticClass).Assembly.Location);
            var sourceImage    = sourceAssembly.NetDirectory.MetadataHeader.LockMetadata();

            var assembly = NetAssemblyFactory.CreateAssembly("SomeAssembly", false);
            var header   = assembly.NetDirectory.MetadataHeader;
            var image    = header.LockMetadata();
            var importer = new ReferenceImporter(image);
            var cloner   = new MemberCloner(image);

            var staticClass = sourceImage.Assembly.Modules[0].TopLevelTypes.First(x => x.Name == "StaticClass");
            var clonedType  = cloner.CloneType(staticClass);

            var main = new MethodDefinition("Main", MethodAttributes.Public | MethodAttributes.Static,
                                            new MethodSignature(image.TypeSystem.Void));

            main.CilMethodBody = new CilMethodBody(main);
            var instructions = main.CilMethodBody.Instructions;

            instructions.Add(CilInstruction.Create(CilOpCodes.Ldc_I4_1));
            instructions.Add(CilInstruction.Create(CilOpCodes.Call,
                                                   clonedType.Methods.First(x => x.Name == "SomeExtension")));
            instructions.Add(CilInstruction.Create(CilOpCodes.Call,
                                                   importer.ImportMethod(typeof(Console).GetMethod("WriteLine", new[] { typeof(int) }))));
            instructions.Add(CilInstruction.Create(CilOpCodes.Ret));

            image.Assembly.Modules[0].TopLevelTypes.Add(clonedType);
            image.Assembly.Modules[0].TopLevelTypes[0].Methods.Add(main);
            image.ManagedEntrypoint = main;

            header.UnlockMetadata();

            _context.VerifyOutput(assembly, "4");
        }
Exemple #3
0
        static VmHelperGenerator()
        {
            var assembly = WindowsAssembly.FromFile(typeof(VmHelper).Assembly.Location);
            var image    = assembly.NetDirectory.MetadataHeader.LockMetadata();

            VmHelperType = image.Assembly.Modules[0].TopLevelTypes.First(x => x.Name == nameof(VmHelper));
        }
Exemple #4
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));
        }
        public void CloneParameterReferences()
        {
            var sourceAssembly = WindowsAssembly.FromFile(typeof(SimpleClass).Assembly.Location);
            var sourceImage    = sourceAssembly.NetDirectory.MetadataHeader.LockMetadata();

            var assembly = NetAssemblyFactory.CreateAssembly("SomeAssembly", false);
            var header   = assembly.NetDirectory.MetadataHeader;
            var image    = header.LockMetadata();
            var cloner   = new MemberCloner(image);

            var variablesClass = sourceImage.Assembly.Modules[0].TopLevelTypes.First(x => x.Name == "Variables");
            var clonedClass    = cloner.CloneType(variablesClass);

            image.Assembly.Modules[0].TopLevelTypes.Add(clonedClass);

            foreach (var clonedMethod in clonedClass.Methods.Where(x => x.CilMethodBody != null))
            {
                var body       = clonedMethod.CilMethodBody;
                var parameters = clonedMethod.Signature.Parameters;

                var originalBody       = variablesClass.Methods.First(x => x.Name == clonedMethod.Name).CilMethodBody;
                var originalParameters = originalBody.Method.Signature.Parameters;

                foreach (var instruction in body.Instructions.Where(x =>
                                                                    x.OpCode.OperandType == CilOperandType.InlineArgument ||
                                                                    x.OpCode.OperandType == CilOperandType.ShortInlineArgument))
                {
                    var originalInstruction = originalBody.Instructions.GetByOffset(instruction.Offset);
                    Assert.NotNull(instruction.Operand);
                    Assert.Equal(originalParameters.IndexOf((ParameterSignature)originalInstruction.Operand),
                                 parameters.IndexOf((ParameterSignature)instruction.Operand));
                }
            }
        }
        protected override IList <Subtitle> GetSubtitles()
        {
            var result = new List <Subtitle>();

            var peInfo = WindowsAssembly.FromFile(Path);

            using (var fs = new FileStream(Path, FileMode.Open))
                using (var input = new ExtendedBinaryReader(fs, FileEncoding, Endianness.LittleEndian))
                {
                    var pointerSection      = peInfo.GetSectionByName(PointerSectionName);
                    var pointerSectionStart = pointerSection.Header.PointerToRawData;
                    var pointerCount        = pointerSection.GetPhysicalLength() / 8;

                    var stringsSection     = peInfo.GetSectionByName(StringsSectionName);
                    var stringsSectionBase = (long)(peInfo.NtHeaders.OptionalHeader.ImageBase +
                                                    (stringsSection.Header.VirtualAddress - stringsSection.Header.PointerToRawData));
                    for (var i = 0; i < pointerCount; i++)
                    {
                        input.Seek(pointerSectionStart + i * 8, SeekOrigin.Begin);
                        var value = input.ReadInt64();
                        if (value != 0)
                        {
                            var possibleStringOffset = value - stringsSectionBase;

                            bool allowed;

                            if (AllowedStringOffsets != null)
                            {
                                allowed = AllowedStringOffsets.Any(x =>
                                                                   x.Item1 <= possibleStringOffset && x.Item2 >= possibleStringOffset);
                            }
                            else
                            {
                                allowed = (stringsSection.Header.PointerToRawData <= possibleStringOffset) &&
                                          (possibleStringOffset < (stringsSection.Header.PointerToRawData + stringsSection.Header.SizeOfRawData));
                            }

                            if (allowed)
                            {
                                var exists = result.Any(x => x.Offset == possibleStringOffset);

                                if (!exists)
                                {
                                    var sub = ReadSubtitle(input, possibleStringOffset, false);
                                    sub.PropertyChanged += SubtitlePropertyChanged;

                                    result.Add(sub);
                                }
                            }
                        }
                    }

                    result.Sort();
                }

            LoadChanges(result);

            return(result);
        }
        private static void DebugPatch(string EXE, string CFG, string KeyPath)
        {
            File.Move(EXE, EXE + ".bak");
            byte[]          Executable = File.ReadAllBytes(EXE + ".bak");
            WindowsAssembly Assembly   = WindowsAssembly.FromFile(EXE + ".bak");
            var             Entries    = Assembly.RootResourceDirectory.Entries;

            try {
                UpdateResourceByName(ref Executable, "V_CODE", VCODE, ref Entries);
                UpdateResourceByName(ref Executable, "V_CODE2", VCODE, ref Entries);
                UpdateResourceByName(ref Executable, "KEY_CODE", KEYCODE, ref Entries);
            }
            catch {
                File.Move(EXE + ".bak", EXE);
                Log("Failed to Patch, This is a CT2 Game?");
                return;
            }
            Log("All Resources Patched...");
            File.WriteAllBytes(KeyPath, DBGKEY);
            Log("Debug Key Generated...");

            if (!Patch(ref Executable, Validation, new byte[] { 0xEB }, "BYPASS V1"))
            {
                if (!Patch(ref Executable, Validation2, new byte[] { 0xEB }, "BYPASS V2"))
                {
                    File.Move(EXE + ".bak", EXE);
                    File.Delete(EXE + ".tmp");
                    if (SteamStubPresent(ref Executable))
                    {
                        Log("Failed to Patch, Steam Stub Present in the executable, Remove it before.");
                    }
                    else
                    {
                        Log("Failed to Patch, Unsupported Engine Version");
                    }
                    return;
                }
            }
            File.WriteAllBytes(EXE, Executable);

            string[] XML = File.ReadAllLines(CFG, Encoding.UTF8);
            for (int i = 0; i < XML.Length; i++)
            {
                string Line = XML[i].Trim().ToLower();
                if (Line.Contains("v_code") && !Line.StartsWith("<!--"))
                {
                    XML[i] = "<!-- " + XML[i] + " -->";
                }
            }
            File.WriteAllLines(CFG, XML);
            Log("Successfully patched");

            ConsoleColor bk = Console.ForegroundColor;

            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Atention: To works you need decrypt all Int's Packget and delete the \"startup.xml\" into game save directory.");
            Console.ForegroundColor = bk;
        }
        public void ReadFieldRvaArray()
        {
            var assembly = WindowsAssembly.FromFile(typeof(Class1).Assembly.Location);
            var header   = assembly.NetDirectory.MetadataHeader;

            var fieldInitializer = typeof(Class1).Assembly.GetTypes().SelectMany(x => x.GetFields(BindingFlags.Static | BindingFlags.NonPublic))
                                   .First();
            var fieldToken  = new MetadataToken((uint)fieldInitializer.MetadataToken);
            var fieldRvaRow = header.GetStream <TableStream>().GetTable <FieldRvaTable>()
                              .FindFieldRvaOfField(fieldToken.Rid);

            Assert.Equal(Class1.MyArray, fieldRvaRow.Column1.Data);
        }
Exemple #9
0
        /// <summary>
        ///     Initializes PEReader using the filepath of a PE to read
        /// </summary>
        /// <param name="fileName">Full File-Path of PE</param>
        public PEReader(string fileName)
        {
            log = new Logger(Environment.UserInteractive ? LoggerType.Console_File : LoggerType.File,
                             "Assembly.PEReader");

            log.Log(LogType.Normal, "PE read using File-load...");

            try
            {
                wasm = WindowsAssembly.FromFile(fileName);
            }
            catch (Exception ex)
            {
                log.Log(ex, "Exception on loading {0}", Path.GetFileName(fileName));
            }
        }
Exemple #10
0
        public void Load(string path, long baseAddr)
        {
            BaseAddress = baseAddr;
            asm         = WindowsAssembly.FromFile(path);
            entryMethod = this.CreateMethodFromRVA(asm.NtHeaders.OptionalHeader.AddressOfEntrypoint);
            methods[entryMethod.Address] = entryMethod;
            entryMethod.Initialize();

            while (pendingAddresses.Count > 0)
            {
                var emu = pendingAddresses.GetEnumerator();
                emu.MoveNext();
                long addr   = emu.Current;
                var  method = this.CreateMethodFromAddress(addr);
                methods[addr] = method;
                method.Initialize();
                pendingAddresses.Remove(addr);
            }
        }
Exemple #11
0
        private void CreateExeFile(string outputFile)
        {
            var peInfo = WindowsAssembly.FromFile(Path);

            using (var inputFs = new FileStream(Path, FileMode.Open))
                using (var input = new ExtendedBinaryReader(inputFs, FileEncoding, Endianness.LittleEndian))
                    using (var outputFs = new FileStream(outputFile, FileMode.Create))
                    {
                        var output         = new BinaryStreamWriter(outputFs);
                        var writingContext = new WritingContext(peInfo, new BinaryStreamWriter(outputFs));

                        var dosHeader = input.ReadBytes((int)peInfo.NtHeaders.StartOffset);
                        output.WriteBytes(dosHeader);

                        var ntHeader = peInfo.NtHeaders;
                        ntHeader.FileHeader.NumberOfSections++;
                        ntHeader.OptionalHeader.SizeOfImage += 0x00010000;

                        ntHeader.Write(writingContext);

                        var newSection = CreateTFSection(peInfo.SectionHeaders[peInfo.SectionHeaders.Count - 1], ntHeader.OptionalHeader.FileAlignment,
                                                         ntHeader.OptionalHeader.SectionAlignment);
                        peInfo.SectionHeaders.Add(newSection);

                        foreach (var section in peInfo.SectionHeaders)
                        {
                            section.Write(writingContext);
                        }

                        foreach (var section in peInfo.SectionHeaders)
                        {
                            input.Seek(section.PointerToRawData, SeekOrigin.Begin);
                            outputFs.Seek(section.PointerToRawData, SeekOrigin.Begin);

                            var data = input.ReadBytes((int)section.SizeOfRawData);
                            output.WriteBytes(data);
                        }

                        var bytes = new byte[0x00010000];
                        output.WriteBytes(bytes);
                    }
        }
        public void CircularReferenceTest()
        {
            var sourceAssembly = WindowsAssembly.FromFile(typeof(SimpleClass).Assembly.Location);
            var sourceImage    = sourceAssembly.NetDirectory.MetadataHeader.LockMetadata();

            var assembly = NetAssemblyFactory.CreateAssembly("SomeAssembly", false);
            var header   = assembly.NetDirectory.MetadataHeader;
            var image    = header.LockMetadata();
            var cloner   = new MemberCloner(image);

            var classA = sourceImage.Assembly.Modules[0].TopLevelTypes.First(x => x.Name == "ClassA");
            var classB = sourceImage.Assembly.Modules[0].TopLevelTypes.First(x => x.Name == "ClassB");

            var clonedTypes = cloner.CloneTypes(new[] { classA, classB });

            foreach (var type in clonedTypes)
            {
                image.Assembly.Modules[0].TopLevelTypes.Add(type);
            }

            var main = new MethodDefinition("Main", MethodAttributes.Public | MethodAttributes.Static,
                                            new MethodSignature(image.TypeSystem.Void));

            main.CilMethodBody = new CilMethodBody(main);

            main.CilMethodBody.Instructions.AddRange(new[]
            {
                CilInstruction.Create(CilOpCodes.Newobj, clonedTypes[0].Methods.First(x => x.Name == ".ctor")),
                CilInstruction.Create(CilOpCodes.Newobj, clonedTypes[1].Methods.First(x => x.Name == ".ctor")),
                CilInstruction.Create(CilOpCodes.Call, clonedTypes[0].Methods.First(x => x.Name == "Test")),
                CilInstruction.Create(CilOpCodes.Ret)
            });

            image.Assembly.Modules[0].TopLevelTypes[0].Methods.Add(main);
            image.ManagedEntrypoint = main;

            header.UnlockMetadata();

            _context.VerifyOutput(assembly, "MyPropertyA: MyPropertyB");
        }
        private void RebuildSubtitles(string outputFile)
        {
            var data = GetSubtitles();

            if (data.Any(x => x.Text != x.Translation))
            {
                CreateExeFile(outputFile);

                var peInfo = WindowsAssembly.FromFile(outputFile);

                using (var inputFs = new FileStream(Path, FileMode.Open))
                    using (var input = new ExtendedBinaryReader(inputFs, FileEncoding))
                        using (var outputFs = new FileStream(outputFile, FileMode.Open))
                            using (var output = new ExtendedBinaryWriter(outputFs, FileEncoding))
                            {
                                var pointerSection      = peInfo.GetSectionByName(PointerSectionName);
                                var pointerSectionStart = pointerSection.Header.PointerToRawData;
                                var pointerCount        = pointerSection.GetPhysicalLength() / 8;

                                var stringsSection     = peInfo.GetSectionByName(StringsSectionName);
                                var stringsSectionBase = (long)(peInfo.NtHeaders.OptionalHeader.ImageBase +
                                                                (stringsSection.Header.VirtualAddress -
                                                                 stringsSection.Header.PointerToRawData));

                                var translationSection     = peInfo.GetSectionByName(".trad\0\0\0");
                                var translationSectionBase = (long)(peInfo.NtHeaders.OptionalHeader.ImageBase +
                                                                    (translationSection.Header.VirtualAddress -
                                                                     translationSection.Header.PointerToRawData));

                                var used = new Dictionary <long, long>();

                                var outputOffset = (long)translationSection.Header.PointerToRawData;

                                for (var i = 0; i < pointerCount; i++)
                                {
                                    input.Seek(pointerSectionStart + i * 8, SeekOrigin.Begin);
                                    output.Seek(pointerSectionStart + i * 8, SeekOrigin.Begin);

                                    var value = input.ReadInt64();
                                    if (value != 0)
                                    {
                                        var possibleStringOffset = value - stringsSectionBase;

                                        bool allowed;
                                        if (AllowedStringOffsets != null)
                                        {
                                            allowed = AllowedStringOffsets.Any(x =>
                                                                               x.Item1 <= possibleStringOffset && x.Item2 >= possibleStringOffset);
                                        }
                                        else
                                        {
                                            allowed = (stringsSection.Header.PointerToRawData <= possibleStringOffset) &&
                                                      (possibleStringOffset < (stringsSection.Header.PointerToRawData + stringsSection.Header.SizeOfRawData));
                                        }

                                        if (allowed)
                                        {
                                            var exists = used.ContainsKey(possibleStringOffset);

                                            if (exists)
                                            {
                                                output.Write(used[possibleStringOffset]);
                                            }
                                            else
                                            {
                                                var newOffset = outputOffset + translationSectionBase;
                                                output.Write(newOffset);
                                                used[possibleStringOffset] = newOffset;

                                                outputOffset = WriteSubtitle(output, data, possibleStringOffset, outputOffset);
                                            }
                                        }
                                    }
                                }
                            }
            }
        }
Exemple #14
0
        private MetadataImage ResolveRuntimeImage(DevirtualisationOptions options, MetadataImage image)
        {
            MetadataImage runtimeImage = null;

            if (options.AutoDetectRuntimeFile)
            {
                Logger.Debug(Tag, "Attempting to autodetect location of the runtime library...");
                var runtimeAssemblies = image.Assembly.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.");
                runtimeImage = image;
            }
            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);
                var runtimeAssembly = WindowsAssembly.FromFile(runtimePath);
                runtimeImage = runtimeAssembly.NetDirectory.MetadataHeader.LockMetadata();
            }
            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(runtimeImage);
        }