问题描述
我要分析一些字节格式的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?
推荐答案
我最终在这里使用MSIL解析器:,对源代码进行了稍微修改,使其可以在ConstructorInfo和MethodInfo(从反射器返回的结果)上运行。
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).
操作列表,以及操作码和参数。操作码是一个枚举,基于该值可以解释参数。参数为二进制形式,需要使用MethodInfo.Module.Resolve *()来获取实际的参数值。
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();
}
}
}
这篇关于MSIL检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!