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