MSIL检查

发布于 2024-08-24 13:57:16 字数 108 浏览 0 评论 0原文

我有一些字节格式的 MSIL(反射的 GetMethodBody() 的结果),我想对其进行一些分析。我想在 MSIL 中找到使用 new 运算符创建的所有类。关于如何以编程方式做到这一点有什么想法吗?

I have some MSIL in byte format (result of reflection's GetMethodBody()) that I'd like to analyze a bit. I'd like to find all classes created with the new operator in the MSIL. Any ideas on how to do that programmatically?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夕色琉璃 2024-08-31 13:57:16

我最终在这里使用了 MSIL 解析器: http:// /blogs.msdn.com/zelmalki/archive/2008/12/11/msil-parser.aspx,稍微修改源代码以适用于 ConstructorInfo 以及 MethodInfo(从反射器返回的结果)。

它将给出操作列表,以及操作码和参数。操作码是一个枚举,可以根据该值解释参数。参数是二进制形式,需要使用MethodInfo.Module.Resolve*()来获取实际的参数值。

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace AspnetReflection
{
    public class MsilReader
    {
        static readonly Dictionary<short, OpCode> _instructionLookup;
        static readonly object _syncObject = new object();
        readonly BinaryReader _methodReader;
        MsilInstruction _current;
        Module _module; // Need to resolve method, type tokens etc


        static MsilReader()
        {
            if (_instructionLookup == null)
            {
                lock (_syncObject)
                {
                    if (_instructionLookup == null)
                    {
                        _instructionLookup = GetLookupTable();
                    }
                }
            }
        }

        public MsilReader(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentException("method");
            }

            _module = method.Module;
            _methodReader = new BinaryReader(new MemoryStream(method.GetMethodBody().GetILAsByteArray()));
        }

        public MsilReader(ConstructorInfo contructor)
        {
            if (contructor == null)
            {
                throw new ArgumentException("contructor");
            }

            _module = contructor.Module;
            _methodReader = new BinaryReader(new MemoryStream(contructor.GetMethodBody().GetILAsByteArray()));
        }

        public MsilInstruction Current
        {
            get { return _current; }
        }


        public bool Read()
        {
            if (_methodReader.BaseStream.Length == _methodReader.BaseStream.Position)
            {
                return false;
            }

            int instructionValue;

            if (_methodReader.BaseStream.Length - 1 == _methodReader.BaseStream.Position)
            {
                instructionValue = _methodReader.ReadByte();
            }
            else
            {
                instructionValue = _methodReader.ReadUInt16();

                if ((instructionValue & OpCodes.Prefix1.Value) != OpCodes.Prefix1.Value)
                {
                    instructionValue &= 0xff;
                    _methodReader.BaseStream.Position--;
                }
                else
                {
                    instructionValue = ((0xFF00 & instructionValue) >> 8) |
                                       ((0xFF & instructionValue) << 8);
                }
            }

            OpCode code;

            if (!_instructionLookup.TryGetValue((short) instructionValue, out code))
            {
                throw new InvalidProgramException();
            }

            int dataSize = GetSize(code.OperandType);

            var data = new byte[dataSize];

            _methodReader.Read(data, 0, dataSize);

            _current = new MsilInstruction(code, data);

            return true;
        }

        static int GetSize(OperandType opType)
        {
            int size = 0;

            switch (opType)
            {
                case OperandType.InlineNone:
                    return 0;
                case OperandType.ShortInlineBrTarget:
                case OperandType.ShortInlineI:
                case OperandType.ShortInlineVar:
                    return 1;

                case OperandType.InlineVar:
                    return 2;

                case OperandType.InlineBrTarget:
                case OperandType.InlineField:
                case OperandType.InlineI:
                case OperandType.InlineMethod:
                case OperandType.InlineSig:
                case OperandType.InlineString:
                case OperandType.InlineSwitch:
                case OperandType.InlineTok:
                case OperandType.InlineType:
                case OperandType.ShortInlineR:
                    return 4;
                case OperandType.InlineI8:

                case OperandType.InlineR:


                    return 8;

                default:

                    return 0;
            }
        }


        static Dictionary<short, OpCode> GetLookupTable()
        {
            var lookupTable = new Dictionary<short, OpCode>();

            FieldInfo[] fields = typeof (OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);

            foreach (FieldInfo field in fields)
            {
                var code = (OpCode) field.GetValue(null);

                lookupTable.Add(code.Value, code);
            }

            return lookupTable;
        }
    }


    public struct MsilInstruction
    {
        public readonly byte[] Data;
        public readonly OpCode Instruction;

        public MsilInstruction(OpCode code, byte[] data)
        {
            Instruction = code;

            Data = data;
        }


        public override string ToString()
        {
            var builder = new StringBuilder();

            builder.Append(Instruction.Name + " ");

            if (Data != null && Data.Length > 0)
            {
                builder.Append("0x");

                foreach (byte b in Data)
                {
                    builder.Append(b.ToString("x2"));
                }
            }

            return builder.ToString();
        }
    }
}

I ended up using the MSIL parser here: http://blogs.msdn.com/zelmalki/archive/2008/12/11/msil-parser.aspx, with the source slightly modified to work on ConstructorInfo as well as MethodInfo (results returned from reflector).

It will give a list of operations, with the opcode and parameters. The opcode is an enum, based on that value the parameters can be interpreted. The parameters are in binary form, need to used MethodInfo.Module.Resolve*() to get the actual parameter values.

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace AspnetReflection
{
    public class MsilReader
    {
        static readonly Dictionary<short, OpCode> _instructionLookup;
        static readonly object _syncObject = new object();
        readonly BinaryReader _methodReader;
        MsilInstruction _current;
        Module _module; // Need to resolve method, type tokens etc


        static MsilReader()
        {
            if (_instructionLookup == null)
            {
                lock (_syncObject)
                {
                    if (_instructionLookup == null)
                    {
                        _instructionLookup = GetLookupTable();
                    }
                }
            }
        }

        public MsilReader(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentException("method");
            }

            _module = method.Module;
            _methodReader = new BinaryReader(new MemoryStream(method.GetMethodBody().GetILAsByteArray()));
        }

        public MsilReader(ConstructorInfo contructor)
        {
            if (contructor == null)
            {
                throw new ArgumentException("contructor");
            }

            _module = contructor.Module;
            _methodReader = new BinaryReader(new MemoryStream(contructor.GetMethodBody().GetILAsByteArray()));
        }

        public MsilInstruction Current
        {
            get { return _current; }
        }


        public bool Read()
        {
            if (_methodReader.BaseStream.Length == _methodReader.BaseStream.Position)
            {
                return false;
            }

            int instructionValue;

            if (_methodReader.BaseStream.Length - 1 == _methodReader.BaseStream.Position)
            {
                instructionValue = _methodReader.ReadByte();
            }
            else
            {
                instructionValue = _methodReader.ReadUInt16();

                if ((instructionValue & OpCodes.Prefix1.Value) != OpCodes.Prefix1.Value)
                {
                    instructionValue &= 0xff;
                    _methodReader.BaseStream.Position--;
                }
                else
                {
                    instructionValue = ((0xFF00 & instructionValue) >> 8) |
                                       ((0xFF & instructionValue) << 8);
                }
            }

            OpCode code;

            if (!_instructionLookup.TryGetValue((short) instructionValue, out code))
            {
                throw new InvalidProgramException();
            }

            int dataSize = GetSize(code.OperandType);

            var data = new byte[dataSize];

            _methodReader.Read(data, 0, dataSize);

            _current = new MsilInstruction(code, data);

            return true;
        }

        static int GetSize(OperandType opType)
        {
            int size = 0;

            switch (opType)
            {
                case OperandType.InlineNone:
                    return 0;
                case OperandType.ShortInlineBrTarget:
                case OperandType.ShortInlineI:
                case OperandType.ShortInlineVar:
                    return 1;

                case OperandType.InlineVar:
                    return 2;

                case OperandType.InlineBrTarget:
                case OperandType.InlineField:
                case OperandType.InlineI:
                case OperandType.InlineMethod:
                case OperandType.InlineSig:
                case OperandType.InlineString:
                case OperandType.InlineSwitch:
                case OperandType.InlineTok:
                case OperandType.InlineType:
                case OperandType.ShortInlineR:
                    return 4;
                case OperandType.InlineI8:

                case OperandType.InlineR:


                    return 8;

                default:

                    return 0;
            }
        }


        static Dictionary<short, OpCode> GetLookupTable()
        {
            var lookupTable = new Dictionary<short, OpCode>();

            FieldInfo[] fields = typeof (OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);

            foreach (FieldInfo field in fields)
            {
                var code = (OpCode) field.GetValue(null);

                lookupTable.Add(code.Value, code);
            }

            return lookupTable;
        }
    }


    public struct MsilInstruction
    {
        public readonly byte[] Data;
        public readonly OpCode Instruction;

        public MsilInstruction(OpCode code, byte[] data)
        {
            Instruction = code;

            Data = data;
        }


        public override string ToString()
        {
            var builder = new StringBuilder();

            builder.Append(Instruction.Name + " ");

            if (Data != null && Data.Length > 0)
            {
                builder.Append("0x");

                foreach (byte b in Data)
                {
                    builder.Append(b.ToString("x2"));
                }
            }

            return builder.ToString();
        }
    }
}
甜是你 2024-08-31 13:57:16

您可以查看 FxCop 等工具背后的引擎。它的名称为CCI。或者查看 Mono 中名为 Cecil 的产品,Gendarme 就是基于该产品。它们是为这些(和其他)类型的任务而构建的。

You could take a look at the engine behind tools like FxCop. It's named CCI. Or check out the one from Mono, named Cecil, on which Gendarme is based. They are build for these (and other) kind of tasks.

心房敞 2024-08-31 13:57:16

查看 codeproject 上的这篇文章
http://www.codeproject.com/KB/cs/sdilreader.aspx

使用源代码,您可以将 IL byte[] 放入指令列表中。如果您正在处理 Generic,您可能需要滚动浏览消息并查看我在那篇文章中放置的帖子(Generic 的错误修复),该帖子修复了与使用 Generic 相关的一些错误(仅当您想将 IL 转换为显示文本)。

获得所有 IL 指令后,您所需要做的就是循环遍历它们,并在指令的操作码 (instruction.code) 与 OpCodes.Newobj 或 Newarr 匹配时增加计数。

如果你想对 MSIL 的内部有更多的了解,我强烈推荐 John Gough 的书《Compiling for the .NET CLR》。

Check out this article on codeproject
http://www.codeproject.com/KB/cs/sdilreader.aspx

Use the source code that will give you ability to take the IL byte[] into a list of instructions. If you are dealing with Generic, you may wants to scroll through the messages and check a post that I put in that article (Bug Fix for Generic) that fixed some bugs related to using with Generic (only when you want to turn the IL into display text).

Once you have all the IL Instructions, all you need is to loop through them and increment the count whenever the opcode of the instruction (instruction.code) match up with OpCodes.Newobj or Newarr.

If you want to gain more understanding on the internal of MSIL, I strongly recommend the book "Compiling for the .NET CLR" by John Gough.

家住魔仙堡 2024-08-31 13:57:16

我还发现弗兰克发现的代码非常有用,但它确实有一个问题,即开关操作码未正确处理。

来自 MSDN,操作码后面跟着一个 int32,其中包含跳转表中的项目数以及要跳转到的位置。因此,具有 3 个项目的开关实际上有 16 个数据字节,而不是 4 个。

我正在使用 Ziad Elmalki 的代码 关于该主题的第二篇文章,其中包含 GetData 方法来识别方法调用目标等内容。

我通过更改 GetData 中的处理来更正 switch 操作码的处理,使其看起来更像这样:

    case OperandType.InlineSwitch:
        {
            int numberOfCases = BitConverter.ToInt32(rawData, 0);
            int[] caseAddresses = new int[numberOfCases];
            byte[] caseData = new byte[4];
            for (int i = 0; i < numberOfCases; i++)
            {
                _methodReader.Read(caseData, 0, caseData.Length);
                caseAddresses[i] = BitConverter.ToInt32(caseData, 0);
            }
            data = caseAddresses;
        }
        break;

I've also found the code Frank found to be very useful but it does have one problem, a switch opcode is not processed correctly.

From MSDN, the opcode is followed by an int32 containing the number of items in the jump table and then the positions to jump to. So a switch with 3 items actually has 16 data bytes not 4.

I'm using the code from Ziad Elmalki's second post on the subject that includes a GetData method to identify things like the target of a method call.

I corrected the processing of switch opcodes by changing the handling them in GetData to look more like this:

    case OperandType.InlineSwitch:
        {
            int numberOfCases = BitConverter.ToInt32(rawData, 0);
            int[] caseAddresses = new int[numberOfCases];
            byte[] caseData = new byte[4];
            for (int i = 0; i < numberOfCases; i++)
            {
                _methodReader.Read(caseData, 0, caseData.Length);
                caseAddresses[i] = BitConverter.ToInt32(caseData, 0);
            }
            data = caseAddresses;
        }
        break;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文