private void AffRich(Instruction instruction, RichTextBox richTextBox, StringOutput stringOutput, byte[] buffer, ulong CodeRIP) { const int HEXBYTES_COLUMN_BYTE_LENGTH = 10; var formatter = new MasmFormatter(); formatter.Format(instruction, stringOutput); richTextBox.AppendText(instruction.IP.ToString("X16")); richTextBox.AppendText(" "); int instrLen = instruction.Length; int byteBaseIndex = (int)(instruction.IP - CodeRIP); for (int i = 0; i < instrLen; i++) { richTextBox.AppendText(buffer[byteBaseIndex + i].ToString("X2")); } int missingBytes = HEXBYTES_COLUMN_BYTE_LENGTH - instrLen; for (int i = 0; i < missingBytes; i++) { richTextBox.AppendText(" "); } richTextBox.AppendText(" "); string endasm = stringOutput.ToStringAndReset().PadRight(60); richTextBox.AppendText(endasm + Environment.NewLine); }
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 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()}"); } }
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); }
void FormatMnemonicOptions(string hexBytes, Code code, int bitness, string formattedString, FormatMnemonicOptions options) { var decoder = Decoder.Create(bitness, new ByteArrayCodeReader(hexBytes)); decoder.Decode(out var instruction); Assert.Equal(code, instruction.Code); var formatter = FormatterFactory.Create(); var output = new StringOutput(); formatter.FormatMnemonic(instruction, output, options); var actualFormattedString = output.ToStringAndReset(); #pragma warning disable xUnit2006 // Do not use invalid string equality check // Show the full string without ellipses by using Equal<string>() instead of Equal() Assert.Equal <string>(formattedString, actualFormattedString); #pragma warning restore xUnit2006 // Do not use invalid string equality check }
void DisplInBrackets(string hexBytes, int bitness, string formattedString, Flags flags) { var decoder = Decoder.Create(bitness, new ByteArrayCodeReader(hexBytes)); decoder.IP = bitness switch { 16 => DecoderConstants.DEFAULT_IP16, 32 => DecoderConstants.DEFAULT_IP32, 64 => DecoderConstants.DEFAULT_IP64, _ => throw new InvalidOperationException(), }; decoder.Decode(out var instruction); var resolver = new TestSymbolResolver { tryGetSymbol = (in Instruction instruction, int operand, int instructionOperand, ulong address, int addressSize, out SymbolResult symbol) => { if (instructionOperand == 1 && (flags & Flags.Symbol) != 0) { symbol = new SymbolResult(address, "symbol", FormatterTextKind.Data, (flags & Flags.Signed) != 0 ? SymbolFlags.Signed : SymbolFlags.None); return(true); } symbol = default; return(false); }, }; var formatter = (MasmFormatter)FormatterFactory.Create_Resolver(resolver).formatter; formatter.MasmOptions.SymbolDisplInBrackets = (flags & Flags.SymbolDisplInBrackets) != 0; formatter.MasmOptions.DisplInBrackets = (flags & Flags.DisplInBrackets) != 0; formatter.MasmOptions.RipRelativeAddresses = (flags & Flags.Rip) != 0; formatter.MasmOptions.ShowZeroDisplacements = (flags & Flags.ShowZeroDisplacements) != 0; formatter.MasmOptions.AddDsPrefix32 = (flags & Flags.NoAddDsPrefix32) == 0; var output = new StringOutput(); formatter.Format(instruction, output); var actualFormattedString = output.ToStringAndReset(); #pragma warning disable xUnit2006 // Do not use invalid string equality check // Show the full string without ellipses by using Equal<string>() instead of Equal() Assert.Equal <string>(formattedString, actualFormattedString); #pragma warning restore xUnit2006 // Do not use invalid string equality check }
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()); } }
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 StringOutput(); foreach (var instr in instructions) { int byteBaseIndex = (int)(instr.IP - address); 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.WriteLine(tempOutput.ToStringAndReset()); } output.WriteLine(); }
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(); }