Example #1
0
        public static void Disassemble(ManualLogSource logSource, IntPtr memoryPtr, int size)
        {
            var data = new byte[size];

            Marshal.Copy(memoryPtr, data, 0, size);

            var formatter  = new NasmFormatter();
            var output     = new StringOutput();
            var codeReader = new ByteArrayCodeReader(data);
            var decoder    = Decoder.Create(64, codeReader);

            decoder.IP = (ulong)memoryPtr.ToInt64();
            while (codeReader.CanReadByte)
            {
                decoder.Decode(out var instr);
                formatter.Format(instr, output);
                logSource.LogDebug($"{instr.IP:X16} {output.ToStringAndReset()}");

                if (instr.Code == Code.Jmp_rm64 && instr.Immediate32 == 0
                    ) // && instr.IsIPRelativeMemoryOperand && instr.IPRelativeMemoryAddress = 6
                {
                    var address = new byte[8];

                    for (var i = 0; i < 8; i++)
                    {
                        address[i] = (byte)codeReader.ReadByte();
                    }

                    logSource.LogDebug($"{instr.IP + (ulong) instr.Length:X16} db 0x{BitConverter.ToUInt64(address, 0):X16}");
                    decoder.IP += 8;
                }
            }
        }
Example #2
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();
        }
Example #3
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());
            }
        }
Example #4
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()}");
            }
        }
Example #5
0
        /// <summary>
        /// Disassemble the method.
        /// </summary>
        /// <param name="method">A method to disassemble</param>
        /// <param name="builder">The builder to receive the method ASM</param>
        /// <param name="formatter">A Iced Formatter to use instead of the default <see cref="NasmFormatter"/></param>
        public static void ToAsm(this MethodInfo method, StringBuilder builder, Formatter formatter = null)
        {
            if (method == null)
            {
                throw new ArgumentNullException(nameof(method));
            }

            using (var dataTarget = DataTarget.AttachToProcess(Process.GetCurrentProcess().Id, false))
            {
                var clrVersion = dataTarget.ClrVersions.First();
                var runtime    = clrVersion.CreateRuntime();
                dataTarget.DataReader.FlushCachedData();

                // Make sure the method is being Jitted
                RuntimeHelpers.PrepareMethod(method.MethodHandle);

                // Get the handle from clrmd
                var clrmdMethodHandle = runtime.GetMethodByHandle((ulong)method.MethodHandle.Value.ToInt64());

                if ((clrmdMethodHandle?.NativeCode ?? 0) == 0)
                {
                    throw new InvalidOperationException($"Unable to disassemble method `{method}`");
                }

                //var check = clrmdMethodHandle.NativeCode;
                //var offsets = clrmdMethodHandle.ILOffsetMap;

                var codePtr  = clrmdMethodHandle.HotColdInfo.HotStart;
                var codeSize = clrmdMethodHandle.HotColdInfo.HotSize;

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

                // Disassemble with Iced
                DecodeMethod(new IntPtr((long)codePtr), codeSize, builder, formatter);
            }
        }
Example #6
0
        private static void DecodeMethod(IntPtr ptr, uint size, StringBuilder builder, Formatter formatter = null)
        {
            // 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());
            }

            // 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(in instr, output);
                builder.AppendLine($"{instr.IP:X16} {output.ToStringAndReset()}");
            }
        }
Example #7
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();
        }
Example #8
0
        public void TrampolineTest(int bitness)
        {
            byte[] exampleCode =
            {
                0x48, 0x89, 0x5C, 0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x55, 0x57, 0x41, 0x56, 0x48, 0x8D,
                0xAC, 0x24, 0x00, 0xFF, 0xFF, 0xFF, 0x48, 0x81, 0xEC, 0x00, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x05,
                0x18, 0x57, 0x0A, 0x00, 0x48, 0x33, 0xC4, 0x48, 0x89, 0x85, 0xF0, 0x00, 0x00, 0x00, 0x4C, 0x8B,
                0x05, 0x2F, 0x24, 0x0A, 0x00, 0x48, 0x8D, 0x05, 0x78, 0x7C, 0x04, 0x00, 0x33, 0xFF
            };

            var exampleCodePointer    = Marshal.AllocHGlobal(80);
            var trampolineCodePointer = Marshal.AllocHGlobal(80);

            Marshal.Copy(exampleCode, 0, exampleCodePointer, exampleCode.Length);


            void Disassemble(byte[] data, ulong ip)
            {
                var formatter  = new NasmFormatter();
                var output     = new StringOutput();
                var codeReader = new ByteArrayCodeReader(data);
                var decoder    = Decoder.Create(bitness, codeReader);

                decoder.IP = ip;
                while (codeReader.CanReadByte)
                {
                    decoder.Decode(out var instr);
                    formatter.Format(instr, output);
                    Console.WriteLine($"{instr.IP:X16} {output.ToStringAndReset()}");
                }

                Console.WriteLine();
            }

            Console.WriteLine("Original:");
            Console.WriteLine();


            Disassemble(exampleCode, (ulong)exampleCodePointer.ToInt64());

            DetourGenerator.CreateTrampolineFromFunction(exampleCodePointer, out var trampolineLength, out _);

            Console.WriteLine("Modified:");
            Console.WriteLine();


            Marshal.Copy(exampleCodePointer, exampleCode, 0, exampleCode.Length);
            Disassemble(exampleCode, (ulong)exampleCodePointer.ToInt64());


            Console.WriteLine();
            Console.WriteLine("Trampoline:");
            Console.WriteLine();

            var trampolineArray = new byte[trampolineLength];

            Marshal.Copy(trampolineCodePointer, trampolineArray, 0, trampolineLength);

            Disassemble(trampolineArray, (ulong)trampolineCodePointer.ToInt64());


            Marshal.FreeHGlobal(exampleCodePointer);
            Marshal.FreeHGlobal(trampolineCodePointer);

            Assert.IsFalse(false);
        }
Example #9
0
        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();
        }