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"); }
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)); }
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); }
/// <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)); } }
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); } }
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); } } } } } } }
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); }