Beispiel #1
0
        /// <summary>
        ///     Directly adds a raw segment from an NE file segment
        /// </summary>
        /// <param name="segment"></param>
        public void AddSegment(Segment segment)
        {
            //Get Address for this Segment
            var segmentMemory = new byte[0x10000];

            //Add the data to memory and record the segment offset in memory
            Array.Copy(segment.Data, 0, segmentMemory, 0, segment.Data.Length);
            _memorySegments.Add(segment.Ordinal, segmentMemory);

            if (segment.Flags.Contains(EnumSegmentFlags.Code))
            {
                //Decode the Segment
                var instructionList = new InstructionList();
                var codeReader      = new ByteArrayCodeReader(segment.Data);
                var decoder         = Decoder.Create(16, codeReader);
                decoder.IP = 0x0;

                while (decoder.IP < (ulong)segment.Data.Length)
                {
                    decoder.Decode(out instructionList.AllocUninitializedElement());
                }

                _decompiledSegments.Add(segment.Ordinal, new Dictionary <ushort, Instruction>());
                foreach (var i in instructionList)
                {
                    _decompiledSegments[segment.Ordinal].Add(i.IP16, i);
                }
            }

            _segments[segment.Ordinal] = segment;
        }
Beispiel #2
0
        private static void DecodeMethod(IntPtr ptr, uint size, StringBuilder builder, Formatter formatter)
        {
            // You can also pass in a hex string, eg. "90 91 929394", or you can use your own CodeReader
            // reading data from a file or memory etc.
            var codeReader = new UnmanagedCodeReader(ptr, size);
            var decoder    = Decoder.Create(IntPtr.Size * 8, codeReader);

            decoder.IP = (ulong)ptr.ToInt64();
            ulong endRip = decoder.IP + (uint)size;

            // This list is faster than List<Instruction> since it uses refs to the Instructions
            // instead of copying them (each Instruction is 32 bytes in size). It has a ref indexer,
            // and a ref iterator. Add() uses 'in' (ref readonly).
            var instructions = new InstructionList();

            while (decoder.IP < endRip)
            {
                // The method allocates an uninitialized element at the end of the list and
                // returns a reference to it which is initialized by Decode().
                decoder.Decode(out instructions.AllocUninitializedElement());
            }

            var output = new StringOutput();

            // Use InstructionList's ref iterator (C# 7.3) to prevent copying 32 bytes every iteration
            foreach (ref var instr in instructions)
            {
                // Don't use instr.ToString(), it allocates more, uses masm syntax and default options
                formatter.Format(in instr, output);
                builder.AppendLine($"{instr.IP:X16} {output.ToStringAndReset()}");
            }
        }
Beispiel #3
0
        private void Disassemble(ITextOutput output, ReadyToRunReader reader, ReadyToRunMethod readyToRunMethod, RuntimeFunction runtimeFunction, int bitness, ulong address)
        {
            WriteCommentLine(output, readyToRunMethod.SignatureString);
            byte[] codeBytes = new byte[runtimeFunction.Size];
            for (int i = 0; i < runtimeFunction.Size; i++)
            {
                codeBytes[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i];
            }

            // TODO: Decorate the disassembly with Unwind, GC and debug info
            var codeReader = new ByteArrayCodeReader(codeBytes);
            var decoder    = Decoder.Create(bitness, codeReader);

            decoder.IP = address;
            ulong endRip = decoder.IP + (uint)codeBytes.Length;

            var instructions = new InstructionList();

            while (decoder.IP < endRip)
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
            }

            string    disassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(null);
            Formatter formatter         = null;

            if (disassemblyFormat.Equals(ReadyToRunOptions.intel))
            {
                formatter = new NasmFormatter();
            }
            else
            {
                Debug.Assert(disassemblyFormat.Equals(ReadyToRunOptions.gas));
                formatter = new GasFormatter();
            }
            formatter.Options.DigitSeparator        = "`";
            formatter.Options.FirstOperandCharIndex = 10;
            var tempOutput = new StringBuilderFormatterOutput();

            foreach (var instr in instructions)
            {
                int byteBaseIndex = (int)(instr.IP - address);
                formatter.Format(instr, tempOutput);
                output.Write(instr.IP.ToString("X16"));
                output.Write(" ");
                int instrLen = instr.ByteLength;
                for (int i = 0; i < instrLen; i++)
                {
                    output.Write(codeBytes[byteBaseIndex + i].ToString("X2"));
                }
                int missingBytes = 10 - instrLen;
                for (int i = 0; i < missingBytes; i++)
                {
                    output.Write("  ");
                }
                output.Write(" ");
                output.WriteLine(tempOutput.ToStringAndReset());
            }
            output.WriteLine();
        }
Beispiel #4
0
 public void Disassemble()
 {
     while (_decoder.IP < (ulong)_moduleData.Length)
     {
         _decoder.Decode(out Instructions.AllocUninitializedElement());
     }
 }
Beispiel #5
0
        static void Main(string[] args)
        {
            int exampleCodeBitness = 32;

            if (args.Length == 2)
            {
                switch (args[0])
                {
                case "32": { exampleCodeBitness = 32; break; }

                case "64": { exampleCodeBitness = 64; break; }

                default:
                    break;
                }
            }
            else
            {
                Console.Write("Must use arguments: <bit-length[32|64]> <target file path>");
                return;
            }

            string filePath = args[1];

            BinaryReader reader    = new BinaryReader(File.Open(filePath, FileMode.Open));
            var          fileSize  = Convert.ToInt32(new FileInfo(filePath).Length);
            var          codeBytes = reader.ReadBytes(fileSize);

            var sw = Stopwatch.StartNew();

            var codeReader = new ByteArrayCodeReader(codeBytes);
            var decoder    = Decoder.Create(exampleCodeBitness, codeReader);

            decoder.IP = exampleCodeRIP;
            ulong endRip = decoder.IP + (uint)codeBytes.Length;

            var instructions = new InstructionList();

            while (decoder.IP < endRip)
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
            }

            var formatter = new MasmFormatter();

            formatter.Options.DigitSeparator        = "`";
            formatter.Options.FirstOperandCharIndex = 10;
            var output = new StringOutput();

            foreach (ref var instr in instructions)
            {
                formatter.Format(instr, output);
                Console.WriteLine(instr.IP.ToString("X8") + " " + output.ToStringAndReset());
            }

            sw.Stop();
            Console.Error.WriteLine("Total dump time: {0:F} sec.", sw.Elapsed.TotalSeconds);
        }
Beispiel #6
0
        static void ShellcodeDecoder(string shellcode, string RIP, bool x64)
        {
            string[] hexValues = shellcode.Split("\\x").Skip(1).ToArray();
            int      bitness;

            if (x64)
            {
                bitness = 64;
            }
            else
            {
                bitness = 32;
            }
            byte[] code = hexValues
                          .Select(value => Convert.ToByte(value, 16))
                          .ToArray();
            var   codeBytes  = code;
            var   codeReader = new ByteArrayCodeReader(codeBytes);
            var   decoder    = Iced.Intel.Decoder.Create(bitness, codeReader);
            ulong CodeRIP    = Convert.ToUInt64(RIP, 16);

            decoder.IP = CodeRIP;

            ulong endRip = decoder.IP + (uint)codeBytes.Length;

            var instructions = new InstructionList();

            while (decoder.IP < endRip)
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
            }
            var formatter = new NasmFormatter();

            formatter.Options.DigitSeparator        = "";
            formatter.Options.FirstOperandCharIndex = 10;
            var output = new StringBuilderFormatterOutput();

            foreach (ref var instr in instructions)
            {
                formatter.Format(instr, output);
                int instrLen      = instr.ByteLength;
                int byteBaseIndex = (int)(instr.IP - CodeRIP);
                for (int i = 0; i < instrLen; i++)
                {
                    Console.Write(codeBytes[byteBaseIndex + i].ToString("X2"));
                }
                int missingBytes = 10 - instrLen;
                for (int i = 0; i < missingBytes; i++)
                {
                    Console.Write("  ");
                }
                Console.Write(" ");
                Console.WriteLine(output.ToStringAndReset().ToUpper());
            }
        }
Beispiel #7
0
		static InstructionList DecodeAsm(CodeBlock src)
		{
            var dst = new InstructionList();
            var reader = new ByteArrayCodeReader(src.Data);
			var decoder = Decoder.Create(IntPtr.Size * 8, reader);
			decoder.IP = src.Address;			
			while (reader.CanReadByte) 
			{
				ref var instruction = ref dst.AllocUninitializedElement();
				decoder.Decode(out instruction);                
			}
Beispiel #8
0
        private static void Disasm(Stream stream, uint size, TextWriter writer, Formatter formatter = null)
        {
            var buffer = ArrayPool <byte> .Shared.Rent((int)size);

            var startPosition = stream.Position;

            stream.Read(buffer, 0, (int)size);
            stream.Position = startPosition;

            // You can also pass in a hex string, eg. "90 91 929394", or you can use your own CodeReader
            // reading data from a file or memory etc
            var codeReader = new StreamCodeReader(stream, size);
            var decoder    = Decoder.Create(IntPtr.Size * 8, codeReader);

            decoder.IP = (ulong)0;
            ulong endRip = decoder.IP + (uint)size;

            // This list is faster than List<Instruction> since it uses refs to the Instructions
            // instead of copying them (each Instruction is 32 bytes in size). It has a ref indexer,
            // and a ref iterator. Add() uses 'in' (ref readonly).
            var instructions = new InstructionList();

            while (decoder.IP < endRip)
            {
                // The method allocates an uninitialized element at the end of the list and
                // returns a reference to it which is initialized by Decode().
                decoder.Decode(out instructions.AllocUninitializedElement());
            }

            // Formatters: Masm*, Nasm* and Gas* (AT&T)
            if (formatter == null)
            {
                formatter = new NasmFormatter();
                formatter.Options.DigitSeparator        = "";
                formatter.Options.FirstOperandCharIndex = 10;
            }
            var output = new StringBuilderFormatterOutput();

            // Use InstructionList's ref iterator (C# 7.3) to prevent copying 32 bytes every iteration
            foreach (ref var instr in instructions)
            {
                // Don't use instr.ToString(), it allocates more, uses masm syntax and default options
                formatter.Format(instr, output);
                writer.Write($"{instr.IP:X16} ");
                for (int i = 0; i < instr.ByteLength; i++)
                {
                    writer.Write(buffer[(int)instr.IP + i].ToString("X2"));
                }
                writer.Write(new string(' ', 16 * 2 - instr.ByteLength * 2));
                writer.WriteLine($"{output.ToStringAndReset()}");
            }
        }
Beispiel #9
0
        void AllocUninitializedElement_works()
        {
            var instructions = GetInstructions();
            var list         = new InstructionList();

            for (int i = 0; i < instructions.Length; i++)
            {
                list.AllocUninitializedElement() = instructions[i];
                Assert.Equal(i + 1, list.Count);
                Assert.True(i < list.Capacity);
                var listElems = new Instruction[list.Count];
                list.CopyTo(listElems);
                AssertEqual(instructions, listElems, listElems.Length);
            }
        }
Beispiel #10
0
        private static void CreateCodeSegment(ReadOnlySpan <byte> byteCode, ushort segmentOrdinal = 1)
        {
            //Decode the Segment
            var instructionList = new InstructionList();
            var codeReader      = new ByteArrayCodeReader(byteCode.ToArray());
            var decoder         = Decoder.Create(16, codeReader);

            decoder.IP = 0x0;

            while (decoder.IP < (ulong)byteCode.Length)
            {
                decoder.Decode(out instructionList.AllocUninitializedElement());
            }

            CreateCodeSegment(instructionList, segmentOrdinal);
        }
Beispiel #11
0
        public static InstructionList DisassembleBytesNew(bool is32Bit, byte[] bytes, ulong methodBase)
        {
            var codeReader = new ByteArrayCodeReader(bytes);
            var decoder    = Decoder.Create(is32Bit ? 32 : 64, codeReader);

            decoder.IP = methodBase;
            var instructions = new InstructionList();
            var endRip       = decoder.IP + (uint)bytes.Length;

            while (decoder.IP < endRip)
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
            }

            return(instructions);
        }
Beispiel #12
0
        protected void CreateCodeSegment(ReadOnlySpan <byte> byteCode, ushort segmentOrdinal = 1)
        {
            //Decode the Segment
            var instructionList = new InstructionList();
            var codeReader      = new ByteArrayCodeReader(byteCode.ToArray());
            var decoder         = Decoder.Create(16, codeReader);

            decoder.IP = 0x0;

            while (decoder.IP < (ulong)byteCode.Length)
            {
                decoder.Decode(out instructionList.AllocUninitializedElement());
            }

            mbbsEmuMemoryCore.AddSegment(segmentOrdinal, instructionList);
        }
Beispiel #13
0
        private CodeByte Disamexe(string fileexe)
        {
            progressBar1.Maximum = 100;
            CodeByte codeByte = new CodeByte();

            int exampleCodeBitness;
            var peHeader = new PeNet.PeFile(fileexe);

            if (peHeader.Is64Bit)
            {
                exampleCodeBitness = 64;
            }
            else
            {
                exampleCodeBitness = 32;
            }

            FileStream   input  = new FileStream(fileexe, FileMode.Open, FileAccess.Read);
            BinaryReader reader = new BinaryReader(input);

            reader.ReadBytes((int)peHeader.ImageSectionHeaders[0].PointerToRawData);
            byte[] buffer = reader.ReadBytes((int)peHeader.ImageSectionHeaders[0].SizeOfRawData);
            input.Close();

            ulong exampleCodeRIP = peHeader.ImageNtHeaders.OptionalHeader.ImageBase + peHeader.ImageSectionHeaders[0].VirtualAddress;
            var   codeBytes      = buffer;
            var   codeReader     = new ByteArrayCodeReader(codeBytes);
            var   decoder        = Iced.Intel.Decoder.Create(exampleCodeBitness, codeReader);

            decoder.IP = exampleCodeRIP;
            ulong endRip       = decoder.IP + (uint)codeBytes.Length;
            var   instructions = new InstructionList();

            while (decoder.IP < endRip)
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
                if (decoder.IP % PROGRESS_MODULO == 0)
                {
                    progressBar1.Value = (int)(decoder.IP * 100 / endRip);
                }
            }
            codeByte.instructions = instructions;
            codeByte.hexcode      = buffer;
            codeByte.CodeRIP      = exampleCodeRIP;

            return(codeByte);
        }
Beispiel #14
0
        /// <summary>
        /// Returns a set of instructions represented by the prologue this type was instantiated with.
        /// </summary>
        private IList <Instruction> DecodePrologue()
        {
            var codeReader = new ByteArrayCodeReader(_bytes);
            var decoder    = Decoder.Create(_bitness, codeReader);

            decoder.IP = _originalFunctionAddress;
            ulong endRip = decoder.IP + (uint)_bytes.Length;

            var instructions = new InstructionList();

            while (decoder.IP < endRip)
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
            }

            return(instructions);
        }
Beispiel #15
0
        public static void Main(string[] args)
        {
            var code   = File.ReadAllBytes(args[0]);
            var reader = new ByteArrayCodeReader(code);

            var decoder = Decoder.Create(64, reader);

            decoder.InstructionPointer = 0x00007FFAC46ACDA4;

            var end          = decoder.InstructionPointer + (uint)code.Length;
            var instructions = new InstructionList();

            while (decoder.InstructionPointer < end)
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
            }
        }
Beispiel #16
0
        private void CreateCodeSegment(ReadOnlySpan <byte> byteCode, ushort segmentOrdinal = 0x1000)
        {
            if (realModeMemoryCore != null)
            {
                realModeMemoryCore.SetArray(segmentOrdinal, 0, byteCode);
                return;
            }

            //Decode the Segment
            var instructionList = new InstructionList();
            var codeReader      = new ByteArrayCodeReader(byteCode.ToArray());
            var decoder         = Decoder.Create(16, codeReader);

            decoder.IP = 0x0;

            while (decoder.IP < (ulong)byteCode.Length)
            {
                decoder.Decode(out instructionList.AllocUninitializedElement());
            }

            CreateCodeSegment(instructionList, segmentOrdinal);
        }
        private void DisassembleAndWriteSimpleMethod(JitWriteContext context, MethodBase method)
        {
            var handle = method.MethodHandle;

            RuntimeHelpers.PrepareMethod(handle);

            var clrMethod = context.Runtime.GetMethodByHandle((ulong)handle.Value.ToInt64());
            var regions   = FindNonEmptyHotColdInfo(clrMethod);

            if (clrMethod is null || regions is null)
            {
                context.Runtime.Flush();
                clrMethod = context.Runtime.GetMethodByHandle((ulong)handle.Value.ToInt64());
                regions   = FindNonEmptyHotColdInfo(clrMethod);
            }

            if (clrMethod is null || regions is null)
            {
                var address = (ulong)handle.GetFunctionPointer().ToInt64();
                clrMethod = context.Runtime.GetMethodByAddress(address);
                regions   = FindNonEmptyHotColdInfo(clrMethod);
            }

            var writer = context.Writer;

            if (clrMethod is not null)
            {
                writer.WriteLine();
                writer.WriteLine(clrMethod.GetFullSignature());
            }
            else
            {
                WriteSignatureFromReflection(context, method);
            }

            if (regions is null)
            {
                if (method.IsGenericMethod || (method.DeclaringType?.IsGenericType ?? false))
                {
                    writer.WriteLine("    ; Failed to find HotColdInfo for generic method (reference types?).");
                    return;
                }
                writer.WriteLine("    ; Failed to find HotColdRegions.");
                return;
            }

            var methodAddress = regions.HotStart;
            var methodLength  = regions.HotSize;

            var reader  = new MemoryCodeReader(new IntPtr(unchecked ((long)methodAddress)), methodLength);
            var decoder = Decoder.Create(MapArchitectureToBitness(context.Runtime.DataTarget.Architecture), reader);

            var instructions = new InstructionList();

            decoder.IP = methodAddress;
            while (decoder.IP < (methodAddress + methodLength))
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
            }

            var resolver  = new JitAsmSymbolResolver(context.Runtime, methodAddress, methodLength);
            var formatter = new IntelFormatter(FormatterOptions, resolver);
            var output    = new StringOutput();

            foreach (ref var instruction in instructions)
            {
                formatter.Format(instruction, output);

                writer.Write("    L");
                writer.Write((instruction.IP - methodAddress).ToString("x4"));
                writer.Write(": ");
                writer.WriteLine(output.ToStringAndReset());
            }
        }
Beispiel #18
0
        private void Disassemble(PEFile currentFile, ITextOutput output, ReadyToRunReader reader, ReadyToRunMethod readyToRunMethod, RuntimeFunction runtimeFunction, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10)
        {
            // TODO: Decorate the disassembly with GCInfo
            WriteCommentLine(output, readyToRunMethod.SignatureString);

            Dictionary <ulong, UnwindCode> unwindInfo = null;

            if (ReadyToRunOptions.GetIsShowUnwindInfo(null) && bitness == 64)
            {
                unwindInfo = WriteUnwindInfo(runtimeFunction, output);
            }

            bool isShowDebugInfo = ReadyToRunOptions.GetIsShowDebugInfo(null);
            Dictionary <VarLocType, HashSet <ValueTuple <DebugInfo, NativeVarInfo> > > debugInfo = null;

            if (isShowDebugInfo)
            {
                debugInfo = WriteDebugInfo(readyToRunMethod, output);
            }

            byte[] codeBytes = new byte[runtimeFunction.Size];
            for (int i = 0; i < runtimeFunction.Size; i++)
            {
                codeBytes[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i];
            }

            var codeReader = new ByteArrayCodeReader(codeBytes);
            var decoder    = Decoder.Create(bitness, codeReader);

            decoder.IP = address;
            ulong endRip = decoder.IP + (uint)codeBytes.Length;

            var instructions = new InstructionList();

            while (decoder.IP < endRip)
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
            }

            string    disassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(null);
            Formatter formatter         = null;

            if (disassemblyFormat.Equals(ReadyToRunOptions.intel))
            {
                formatter = new NasmFormatter();
            }
            else
            {
                Debug.Assert(disassemblyFormat.Equals(ReadyToRunOptions.gas));
                formatter = new GasFormatter();
            }
            formatter.Options.DigitSeparator        = "`";
            formatter.Options.FirstOperandCharIndex = 10;
            var   tempOutput  = new StringOutput();
            ulong baseInstrIP = instructions[0].IP;

            foreach (var instr in instructions)
            {
                int byteBaseIndex = (int)(instr.IP - address);
                if (isShowDebugInfo && runtimeFunction.DebugInfo != null)
                {
                    foreach (var bound in runtimeFunction.DebugInfo.BoundsList)
                    {
                        if (bound.NativeOffset == byteBaseIndex)
                        {
                            if (bound.ILOffset == (uint)DebugInfoBoundsType.Prolog)
                            {
                                WriteCommentLine(output, "Prolog");
                            }
                            else if (bound.ILOffset == (uint)DebugInfoBoundsType.Epilog)
                            {
                                WriteCommentLine(output, "Epilog");
                            }
                            else
                            {
                                WriteCommentLine(output, $"IL_{bound.ILOffset:x4}");
                            }
                        }
                    }
                }
                formatter.Format(instr, tempOutput);
                output.Write(instr.IP.ToString("X16"));
                output.Write(" ");
                int instrLen = instr.Length;
                for (int i = 0; i < instrLen; i++)
                {
                    output.Write(codeBytes[byteBaseIndex + i].ToString("X2"));
                }
                int missingBytes = 10 - instrLen;
                for (int i = 0; i < missingBytes; i++)
                {
                    output.Write("  ");
                }
                output.Write(" ");
                output.Write(tempOutput.ToStringAndReset());
                DecorateUnwindInfo(output, unwindInfo, baseInstrIP, instr);
                DecorateDebugInfo(output, instr, debugInfo, baseInstrIP);
                DecorateCallSite(currentFile, output, reader, showMetadataTokens, showMetadataTokensInBase10, instr);
            }
            output.WriteLine();
        }
        private void Disassemble(PEFile currentFile, ITextOutput output, ReadyToRunReader reader, ReadyToRunMethod readyToRunMethod, RuntimeFunction runtimeFunction, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10)
        {
            WriteCommentLine(output, readyToRunMethod.SignatureString);
            byte[] codeBytes = new byte[runtimeFunction.Size];
            for (int i = 0; i < runtimeFunction.Size; i++)
            {
                codeBytes[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i];
            }

            // TODO: Decorate the disassembly with Unwind, GC and debug info
            var codeReader = new ByteArrayCodeReader(codeBytes);
            var decoder    = Decoder.Create(bitness, codeReader);

            decoder.IP = address;
            ulong endRip = decoder.IP + (uint)codeBytes.Length;

            var instructions = new InstructionList();

            while (decoder.IP < endRip)
            {
                decoder.Decode(out instructions.AllocUninitializedElement());
            }

            string    disassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(null);
            Formatter formatter         = null;

            if (disassemblyFormat.Equals(ReadyToRunOptions.intel))
            {
                formatter = new NasmFormatter();
            }
            else
            {
                Debug.Assert(disassemblyFormat.Equals(ReadyToRunOptions.gas));
                formatter = new GasFormatter();
            }
            formatter.Options.DigitSeparator        = "`";
            formatter.Options.FirstOperandCharIndex = 10;
            var tempOutput = new StringOutput();

            foreach (var instr in instructions)
            {
                int byteBaseIndex = (int)(instr.IP - address);
                if (runtimeFunction.DebugInfo != null)
                {
                    foreach (var bound in runtimeFunction.DebugInfo.BoundsList)
                    {
                        if (bound.NativeOffset == byteBaseIndex)
                        {
                            if (bound.ILOffset == (uint)DebugInfoBoundsType.Prolog)
                            {
                                WriteCommentLine(output, "Prolog");
                            }
                            else if (bound.ILOffset == (uint)DebugInfoBoundsType.Epilog)
                            {
                                WriteCommentLine(output, "Epilog");
                            }
                            else
                            {
                                WriteCommentLine(output, $"IL_{bound.ILOffset:x4}");
                            }
                        }
                    }
                }
                formatter.Format(instr, tempOutput);
                output.Write(instr.IP.ToString("X16"));
                output.Write(" ");
                int instrLen = instr.Length;
                for (int i = 0; i < instrLen; i++)
                {
                    output.Write(codeBytes[byteBaseIndex + i].ToString("X2"));
                }
                int missingBytes = 10 - instrLen;
                for (int i = 0; i < missingBytes; i++)
                {
                    output.Write("  ");
                }
                output.Write(" ");
                output.Write(tempOutput.ToStringAndReset());
                int importCellAddress = (int)instr.IPRelativeMemoryAddress;
                if (instr.IsCallNearIndirect && reader.ImportCellNames.ContainsKey(importCellAddress))
                {
                    output.Write(" ; ");
                    ReadyToRunSignature signature = reader.ImportSignatures[(int)instr.IPRelativeMemoryAddress];
                    switch (signature)
                    {
                    case MethodDefEntrySignature methodDefSignature:
                        var methodDefToken = MetadataTokens.EntityHandle(unchecked ((int)methodDefSignature.MethodDefToken));
                        if (showMetadataTokens)
                        {
                            if (showMetadataTokensInBase10)
                            {
                                output.WriteReference(currentFile, methodDefToken, $"({MetadataTokens.GetToken(methodDefToken)}) ", "metadata");
                            }
                            else
                            {
                                output.WriteReference(currentFile, methodDefToken, $"({MetadataTokens.GetToken(methodDefToken):X8}) ", "metadata");
                            }
                        }
                        methodDefToken.WriteTo(currentFile, output, Decompiler.Metadata.GenericContext.Empty);
                        break;

                    case MethodRefEntrySignature methodRefSignature:
                        var methodRefToken = MetadataTokens.EntityHandle(unchecked ((int)methodRefSignature.MethodRefToken));
                        if (showMetadataTokens)
                        {
                            if (showMetadataTokensInBase10)
                            {
                                output.WriteReference(currentFile, methodRefToken, $"({MetadataTokens.GetToken(methodRefToken)}) ", "metadata");
                            }
                            else
                            {
                                output.WriteReference(currentFile, methodRefToken, $"({MetadataTokens.GetToken(methodRefToken):X8}) ", "metadata");
                            }
                        }
                        methodRefToken.WriteTo(currentFile, output, Decompiler.Metadata.GenericContext.Empty);
                        break;

                    default:
                        output.WriteLine(reader.ImportCellNames[importCellAddress]);
                        break;
                    }
                    output.WriteLine();
                }
                else
                {
                    output.WriteLine();
                }
            }
            output.WriteLine();
        }