예제 #1
0
        void WriteStructureBody(ILStructure s, HashSet <int> branchTargets, ref BlobReader body)
        {
            bool isFirstInstructionInStructure = true;
            bool prevInstructionWasBranch      = false;
            int  childIndex = 0;

            while (body.RemainingBytes > 0 && body.Offset < s.EndOffset)
            {
                int offset = body.Offset;
                if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset)
                {
                    ILStructure child = s.Children[childIndex++];
                    WriteStructureHeader(child);
                    WriteStructureBody(child, branchTargets, ref body);
                    WriteStructureFooter(child);
                }
                else
                {
                    if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset)))
                    {
                        output.WriteLine();                         // put an empty line after branches, and in front of branch targets
                    }
                    var currentOpCode = ILParser.DecodeOpCode(ref body);
                    body.Offset = offset;                     // reset IL stream
                    WriteInstruction(output, metadata, s.MethodHandle, ref body);
                    prevInstructionWasBranch = currentOpCode.IsBranch() ||
                                               currentOpCode.IsReturn() ||
                                               currentOpCode == ILOpCode.Throw ||
                                               currentOpCode == ILOpCode.Rethrow ||
                                               currentOpCode == ILOpCode.Switch;
                }
                isFirstInstructionInStructure = false;
            }
        }
예제 #2
0
 void WriteRVA(BlobReader blob, int offset, ILOpCode opCode)
 {
     if (ShowRawRVAOffsetAndBytes)
     {
         output.Write("/* ");
         var tmp = blob;
         if (opCode == ILOpCode.Switch)
         {
             tmp.ReadInt32();
         }
         else
         {
             ILParser.SkipOperand(ref tmp, opCode);
         }
         output.Write($"0x{offset:X8} {(ushort)opCode:X2}");
         int appendSpaces = (ushort)opCode > 0xFF ? 14 : 16;
         while (blob.Offset < tmp.Offset)
         {
             output.Write($"{blob.ReadByte():X2}");
             appendSpaces -= 2;
         }
         if (appendSpaces > 0)
         {
             output.Write(new string(' ', appendSpaces));
         }
         output.Write(" */ ");
     }
 }
예제 #3
0
        HashSet <int> GetBranchTargets(BlobReader blob)
        {
            HashSet <int> branchTargets = new HashSet <int>();

            while (blob.RemainingBytes > 0)
            {
                var opCode = ILParser.DecodeOpCode(ref blob);
                if (opCode == ILOpCode.Switch)
                {
                    branchTargets.UnionWith(ILParser.DecodeSwitchTargets(ref blob));
                }
                else if (opCode.IsBranch())
                {
                    branchTargets.Add(ILParser.DecodeBranchTarget(ref blob, opCode));
                }
                else
                {
                    ILParser.SkipOperand(ref blob, opCode);
                }
            }
            return(branchTargets);
        }
예제 #4
0
        protected virtual void WriteInstruction(ITextOutput output, MetadataReader metadata, MethodDefinitionHandle methodDefinition, ref BlobReader blob)
        {
            int offset = blob.Offset;

            if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count)
            {
                var sp = sequencePoints[nextSequencePointIndex];
                if (sp.Offset <= offset)
                {
                    output.Write("// sequence point: ");
                    if (sp.Offset != offset)
                    {
                        output.Write("!! at " + DisassemblerHelpers.OffsetToString(sp.Offset) + " !!");
                    }
                    if (sp.IsHidden)
                    {
                        output.WriteLine("hidden");
                    }
                    else
                    {
                        output.WriteLine($"(line {sp.StartLine}, col {sp.StartColumn}) to (line {sp.EndLine}, col {sp.EndColumn}) in {sp.DocumentUrl}");
                    }
                    nextSequencePointIndex++;
                }
            }
            ILOpCode opCode = ILParser.DecodeOpCode(ref blob);

            output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true);
            output.Write(": ");
            if (opCode.IsDefined())
            {
                output.WriteReference(new OpCodeInfo(opCode, opCode.GetDisplayName()));
                switch (opCode.GetOperandType())
                {
                case OperandType.BrTarget:
                case OperandType.ShortBrTarget:
                    output.Write(' ');
                    int targetOffset = ILParser.DecodeBranchTarget(ref blob, opCode);
                    output.WriteLocalReference($"IL_{targetOffset:x4}", targetOffset);
                    break;

                case OperandType.Field:
                case OperandType.Method:
                case OperandType.Sig:
                case OperandType.Type:
                    output.Write(' ');
                    int          metadataToken = blob.ReadInt32();
                    EntityHandle?handle        = MetadataTokenHelpers.TryAsEntityHandle(metadataToken);
                    try {
                        handle?.WriteTo(module, output, genericContext);
                    } catch (BadImageFormatException) {
                        handle = null;
                    }
                    WriteMetadataToken(handle, metadataToken, spaceBefore: true);
                    break;

                case OperandType.Tok:
                    output.Write(' ');
                    metadataToken = blob.ReadInt32();
                    handle        = MetadataTokenHelpers.TryAsEntityHandle(metadataToken);
                    switch (handle?.Kind)
                    {
                    case HandleKind.MemberReference:
                        switch (metadata.GetMemberReference((MemberReferenceHandle)handle).GetKind())
                        {
                        case MemberReferenceKind.Method:
                            output.Write("method ");
                            break;

                        case MemberReferenceKind.Field:
                            output.Write("field ");
                            break;
                        }
                        break;

                    case HandleKind.FieldDefinition:
                        output.Write("field ");
                        break;

                    case HandleKind.MethodDefinition:
                        output.Write("method ");
                        break;
                    }
                    try {
                        handle?.WriteTo(module, output, genericContext);
                    } catch (BadImageFormatException) {
                        handle = null;
                    }
                    WriteMetadataToken(handle, metadataToken, spaceBefore: true);
                    break;

                case OperandType.ShortI:
                    output.Write(' ');
                    DisassemblerHelpers.WriteOperand(output, blob.ReadSByte());
                    break;

                case OperandType.I:
                    output.Write(' ');
                    DisassemblerHelpers.WriteOperand(output, blob.ReadInt32());
                    break;

                case OperandType.I8:
                    output.Write(' ');
                    DisassemblerHelpers.WriteOperand(output, blob.ReadInt64());
                    break;

                case OperandType.ShortR:
                    output.Write(' ');
                    DisassemblerHelpers.WriteOperand(output, blob.ReadSingle());
                    break;

                case OperandType.R:
                    output.Write(' ');
                    DisassemblerHelpers.WriteOperand(output, blob.ReadDouble());
                    break;

                case OperandType.String:
                    metadataToken = blob.ReadInt32();
                    output.Write(' ');
                    UserStringHandle?userString;
                    string           text;
                    try {
                        userString = MetadataTokens.UserStringHandle(metadataToken);
                        text       = metadata.GetUserString(userString.Value);
                    } catch (BadImageFormatException) {
                        userString = null;
                        text       = null;
                    }
                    if (userString != null)
                    {
                        DisassemblerHelpers.WriteOperand(output, text);
                    }
                    WriteMetadataToken(userString, metadataToken, spaceBefore: true);
                    break;

                case OperandType.Switch:
                    int[] targets = ILParser.DecodeSwitchTargets(ref blob);
                    output.Write(" (");
                    for (int i = 0; i < targets.Length; i++)
                    {
                        if (i > 0)
                        {
                            output.Write(", ");
                        }
                        output.WriteLocalReference($"IL_{targets[i]:x4}", targets[i]);
                    }
                    output.Write(")");
                    break;

                case OperandType.Variable:
                    output.Write(' ');
                    int index = blob.ReadUInt16();
                    if (opCode == ILOpCode.Ldloc || opCode == ILOpCode.Ldloca || opCode == ILOpCode.Stloc)
                    {
                        DisassemblerHelpers.WriteVariableReference(output, metadata, methodDefinition, index);
                    }
                    else
                    {
                        DisassemblerHelpers.WriteParameterReference(output, metadata, methodDefinition, index);
                    }
                    break;

                case OperandType.ShortVariable:
                    output.Write(' ');
                    index = blob.ReadByte();
                    if (opCode == ILOpCode.Ldloc_s || opCode == ILOpCode.Ldloca_s || opCode == ILOpCode.Stloc_s)
                    {
                        DisassemblerHelpers.WriteVariableReference(output, metadata, methodDefinition, index);
                    }
                    else
                    {
                        DisassemblerHelpers.WriteParameterReference(output, metadata, methodDefinition, index);
                    }
                    break;
                }
            }
            else
            {
                ushort opCodeValue = (ushort)opCode;
                if (opCodeValue > 0xFF)
                {
                    // split 16-bit value into two emitbyte directives
                    output.WriteLine($".emitbyte 0x{(byte)(opCodeValue >> 8):x}");
                    // add label
                    output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset + 1), offset + 1, isDefinition: true);
                    output.Write(": ");
                    output.Write($".emitbyte 0x{(byte)(opCodeValue & 0xFF):x}");
                }
                else
                {
                    output.Write($".emitbyte 0x{(byte)opCodeValue:x}");
                }
            }
            output.WriteLine();
        }
예제 #5
0
        public virtual void Disassemble(PEFile module, MethodDefinitionHandle handle)
        {
            this.module      = module ?? throw new ArgumentNullException(nameof(module));
            metadata         = module.Metadata;
            genericContext   = new GenericContext(handle, module);
            signatureDecoder = new DisassemblerSignatureTypeProvider(module, output);
            var methodDefinition = metadata.GetMethodDefinition(handle);

            // start writing IL code
            output.WriteLine("// Method begins at RVA 0x{0:x4}", methodDefinition.RelativeVirtualAddress);
            if (methodDefinition.RelativeVirtualAddress == 0)
            {
                output.WriteLine("// Header size: {0}", 0);
                output.WriteLine("// Code size: {0} (0x{0:x})", 0);
                output.WriteLine(".maxstack {0}", 0);
                output.WriteLine();
                return;
            }
            MethodBodyBlock body;
            BlobReader      bodyBlockReader;

            try
            {
                body            = module.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress);
                bodyBlockReader = module.Reader.GetSectionData(methodDefinition.RelativeVirtualAddress).GetReader();
            }
            catch (BadImageFormatException ex)
            {
                output.WriteLine("// {0}", ex.Message);
                return;
            }
            var blob       = body.GetILReader();
            int headerSize = ILParser.GetHeaderSize(bodyBlockReader);

            output.WriteLine("// Header size: {0}", headerSize);
            output.WriteLine("// Code size: {0} (0x{0:x})", blob.Length);
            output.WriteLine(".maxstack {0}", body.MaxStack);

            var entrypointHandle = MetadataTokens.MethodDefinitionHandle(module.Reader.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress);

            if (handle == entrypointHandle)
            {
                output.WriteLine(".entrypoint");
            }

            DisassembleLocalsBlock(handle, body);
            output.WriteLine();

            sequencePoints         = DebugInfo?.GetSequencePoints(handle) ?? EmptyList <DebugInfo.SequencePoint> .Instance;
            nextSequencePointIndex = 0;
            if (DetectControlStructure && blob.Length > 0)
            {
                blob.Reset();
                HashSet <int> branchTargets = GetBranchTargets(blob);
                blob.Reset();
                WriteStructureBody(new ILStructure(module, handle, genericContext, body), branchTargets, ref blob, methodDefinition.RelativeVirtualAddress + headerSize);
            }
            else
            {
                while (blob.RemainingBytes > 0)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    WriteInstruction(output, metadata, handle, ref blob, methodDefinition.RelativeVirtualAddress);
                }
                WriteExceptionHandlers(module, handle, body);
            }
            sequencePoints = null;
        }