Как я могу восстановить строковые литералы, используя отражение?

Действительно ли возможно восстановить все ценности строкового литерала от собрания, используя отражение?

Позволяет говорят, что у меня есть этот класс:

public class Example
{
    public void PrintName()
    {
        Debug.Print(@"My name is Dave");
    }
}

Я хотел бы использовать отражение, чтобы получить список последовательностей в применении как последовательность "Меня зовут Дэйв".

Я нашел, как сделать это, если последовательность назначена на переменную, но не для действующей опечатки.

3
nl ja de
I' m боящийся вы can' t. Необходимо было бы разобрать код. Изучить Рослин.
добавлено автор Paul Fleming, источник
Отражение AFAIK can' t делают то, что вы спрашиваете...
добавлено автор Yahia, источник
Там какой-либо путь состоит в том, чтобы овладеть компанией молодых специалистов последовательности, или это полностью скрыто от нас?
добавлено автор Servy, источник
Я никогда не слышал о способности отражения осмотреть тела метода (кроме, возможно, извлечения сырые байты IL), так не могло бы быть возможным.
добавлено автор Zarat, источник

3 ответы

Ниже некоторый быстрый код, который должен работать. Другая вещь, которую можно сделать, прочитана все строковые литералы на собрании, смотря на #US поток метаданных. Я написал некоторый код некоторое время назад, который делает это, я могу вскопать, если вам интересно.

  class Program
    {
        static void Main()
        {
            foreach (string literal in FindLiterals(typeof(Program).GetMethod("TestMethod1", BindingFlags.NonPublic | BindingFlags.Static)))
            {
                Console.WriteLine(literal);
            }

            Console.ReadLine();
        }


        private static IEnumerable FindLiterals(MethodInfo method)
        {
            ILReader reader = new ILReader(method);
            foreach (ILInstruction instruction in reader.Instructions)
            {
                if (instruction.Op == OpCodes.Ldstr)
                {
                    yield return instruction.Data as string;
                }
            }
        }

        private static void TestMethod1()
        {
            Console.WriteLine("Abc");
            Console.WriteLine("123");
        }
    }

    public interface IILReaderProvider
    {
        byte[] GetMethodBody();

        FieldInfo ResolveField(int metadataToken);
        MemberInfo ResolveMember(int metadataToken);

        MethodBase ResolveMethod(int metadataToken);
        byte[] ResolveSignature(int metadataToken);

        string ResolveString(int metadataToken);
        Type ResolveType(int metadataToken);
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ILInstruction
    {
        private readonly OpCode operationCode;//40.  56-64.  The entire structure is very big.  maybe do array lookup for opcode instead.

        private readonly byte[] instructionRawData;

        private readonly object instructionData;

        private readonly int instructionAddress;

        private readonly int index;

        internal ILInstruction(OpCode code, byte[] instructionRawData, int instructionAddress, object instructionData, int index)
        {
            this.operationCode = code;
            this.instructionRawData = instructionRawData;
            this.instructionAddress = instructionAddress;
            this.instructionData = instructionData;
            this.index = index;
        }

        public OpCode Op
        {
            get
            {
                return this.operationCode;
            }
        }

        /// 
        /// Gets the raw data.
        /// 
        public byte[] RawData
        {
            get
            {
                return this.instructionRawData;
            }
        }

        /// 
        /// Gets the data.
        /// 
        public object Data
        {
            get
            {
                return this.instructionData;
            }
        }

        /// 
        /// Gets the address of the instruction.
        /// 
        public int Address
        {
            get
            {
                return this.instructionAddress;
            }
        }

        /// 
        /// Gets the index of the instruction.
        /// 
        /// 
        /// The index of the instruction.
        /// 
        public int InstructionIndex
        {
            get
            {
                return this.index;
            }
        }

        /// 
        /// Gets the value as integer
        /// 
        /// The data value.
        public int DataValue
        {
            get
            {
                int value = 0;
                if (this.Data != null)
                {
                    if (this.Data is byte)
                    {
                        value = (byte)this.Data;
                    }
                    else if (this.Data is short)
                    {
                        value = (short)this.Data;
                    }
                    else if (this.Data is int)
                    {
                        value = (int)this.Data;
                    }
                }

                return value;
            }
        }

        /// 
        /// Gets the length of the instructions and operands.
        /// 
        /// The length.
        public int Length
        {
            get
            {
                return this.Op.Size + (this.RawData == null ? 0 : this.RawData.Length);
            }
        }

        /// 
        /// Returns a  that represents this instance.
        /// 
        /// 
        /// A  that represents this instance.
        /// 
        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.AppendFormat("0x{0:x4} {1,-10}", this.Address, this.Op.Name);

            if (this.Data != null)
            {
                builder.Append(this.Data.ToString());
            }

            if (this.RawData != null && this.RawData.Length > 0)
            {
                builder.Append(" [0x");
                for (int i = this.RawData.Length - 1; i >= 0; i--)
                {
                    builder.Append(this.RawData[i].ToString("x2", CultureInfo.InvariantCulture));
                }

                builder.Append(']');
            }

            return builder.ToString();
        }
    }

    /// 
    /// Reads IL instructions from a byte stream.
    /// 
    /// Allows generated code to be viewed without debugger or enabled debug assemblies.
    public sealed class ILReader
    {
        /// 
        /// The _instruction lookup.
        /// 
        private static readonly Lazy> instructionLookup = new Lazy>(ILReader.GetLookupTable, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);

        /// 
        /// The IL reader provider.
        /// 
        private IILReaderProvider intermediateLanguageProvider;

        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// 
        /// The method.
        /// 
        public ILReader(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            this.intermediateLanguageProvider = ILReader.CreateILReaderProvider(method);
        }

        /// 
        /// Gets the instructions.
        /// 
        /// The instructions.
        public IEnumerable Instructions
        {
            get
            {
                byte[] instructionBytes = this.intermediateLanguageProvider.GetMethodBody();
                int instructionIndex = 0, startAddress;
                for (int position = 0; position < instructionBytes.Length; )
                {
                    startAddress = position;
                    short operationData = instructionBytes[position];
                    if (IsInstructionPrefix(operationData))
                    {
                        operationData = (short)((operationData << 8) | instructionBytes[++position]);
                    }

                    position++;

                    OpCode code;
                    if (!instructionLookup.Value.TryGetValue(operationData, out code))
                    {
                        throw new InvalidProgramException(string.Format("0x{0:X2} is not a valid op code.", operationData));
                    }

                    int dataSize = GetSize(code.OperandType);
                    byte[] data = new byte[dataSize];
                    Buffer.BlockCopy(instructionBytes, position, data, 0, dataSize);
                    object objData = this.GetData(code, data);
                    position += dataSize;

                    if (code.OperandType == OperandType.InlineSwitch)
                    {
                        dataSize = (int)objData;
                        int[] labels = new int[dataSize];
                        for (int index = 0; index < labels.Length; index++)
                        {
                            labels[index] = BitConverter.ToInt32(instructionBytes, position);
                            position += 4;
                        }

                        objData = labels;
                    }

                    yield return new ILInstruction(code, data, startAddress, objData, instructionIndex);
                    instructionIndex++;
                }
            }
        }


        /// 
        /// Creates the IL reader provider.
        /// 
        /// The MethodInfo object that represents the method to read..
        /// 
        /// The ILReader provider.
        /// 
        private static IILReaderProvider CreateILReaderProvider(MethodInfo methodInfo)
        {
            IILReaderProvider reader = DynamicILReaderProvider.Create(methodInfo);
            if (reader != null)
            {
                return reader;
            }

            return new ILReaderProvider(methodInfo);
        }

        /// 
        /// Checks to see if the IL instruction is a prefix indicating the length of the instruction is two bytes long.
        /// 
        /// The IL instruction as a byte.
        /// IL instructions can either be 1 or 2 bytes.
        /// True if this IL instruction is a prefix indicating the instruction is two bytes long.
        private static bool IsInstructionPrefix(short value)
        {
            return ((value & OpCodes.Prefix1.Value) == OpCodes.Prefix1.Value) || ((value & OpCodes.Prefix2.Value) == OpCodes.Prefix2.Value)
                        || ((value & OpCodes.Prefix3.Value) == OpCodes.Prefix3.Value) || ((value & OpCodes.Prefix4.Value) == OpCodes.Prefix4.Value)
                        || ((value & OpCodes.Prefix5.Value) == OpCodes.Prefix5.Value) || ((value & OpCodes.Prefix6.Value) == OpCodes.Prefix6.Value)
                        || ((value & OpCodes.Prefix7.Value) == OpCodes.Prefix7.Value) || ((value & OpCodes.Prefixref.Value) == OpCodes.Prefixref.Value);
        }

        /// 
        /// The get lookup table.
        /// 
        /// 
        /// A dictionary of IL instructions.
        /// 
        private static Dictionary GetLookupTable()
        {
           //Might be better to do an array lookup.  Use a seperate arrary for instructions without a prefix and array for each prefix.
            Dictionary lookupTable = new Dictionary();
            FieldInfo[] fields = typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);
            foreach (FieldInfo field in fields)
            {
                OpCode code = (OpCode)field.GetValue(null);
                lookupTable.Add(code.Value, code);
            }

            return lookupTable;
        }

        /// 
        /// Gets the size of a operand.
        /// 
        /// Defines the type of operand.
        /// The size in bytes of the operand type.
        private static int GetSize(OperandType operandType)
        {
            switch (operandType)
            {
                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;
            }
        }

        private object GetData(OpCode code, byte[] rawData)
        {
            object data = null;
            switch (code.OperandType)
            {
                case OperandType.InlineField:
                    data = this.intermediateLanguageProvider.ResolveField(BitConverter.ToInt32(rawData, 0));
                    break;
                case OperandType.InlineSwitch:
                    data = BitConverter.ToInt32(rawData, 0);

                    break;
                case OperandType.InlineBrTarget:
                case OperandType.InlineI:
                    data = BitConverter.ToInt32(rawData, 0);
                    break;
                case OperandType.InlineI8:
                    data = BitConverter.ToInt64(rawData, 0);
                    break;
                case OperandType.InlineMethod:
                    data = this.intermediateLanguageProvider.ResolveMethod(BitConverter.ToInt32(rawData, 0));
                    break;
                case OperandType.InlineR:
                    data = BitConverter.ToDouble(rawData, 0);
                    break;
                case OperandType.InlineSig:
                    data = this.intermediateLanguageProvider.ResolveSignature(BitConverter.ToInt32(rawData, 0));
                    break;
                case OperandType.InlineString:
                    data = this.intermediateLanguageProvider.ResolveString(BitConverter.ToInt32(rawData, 0));
                    break;
                case OperandType.InlineTok:
                case OperandType.InlineType:
                    data = this.intermediateLanguageProvider.ResolveType(BitConverter.ToInt32(rawData, 0));
                    break;
                case OperandType.InlineVar:
                    data = BitConverter.ToInt16(rawData, 0);
                    break;
                case OperandType.ShortInlineVar:
                case OperandType.ShortInlineI:
                case OperandType.ShortInlineBrTarget:
                    data = rawData[0];
                    break;
                case OperandType.ShortInlineR:
                    data = BitConverter.ToSingle(rawData, 0);
                    break;
            }

            return data;
        }
    }

    internal class DynamicILReaderProvider : IILReaderProvider
    {
        public const int TypeRidPrefix = 0x02000000;

        public const int MethodRidPrefix = 0x06000000;

        public const int FieldRidPrefix = 0x04000000;

        public static readonly Type RuntimeDynamicMethodType;

        private static readonly FieldInfo fileLengthField = typeof(ILGenerator).GetField("m_length", BindingFlags.NonPublic | BindingFlags.Instance);

        private static readonly FieldInfo IntermediateLanguageBytesField = typeof(ILGenerator).GetField("m_ILStream", BindingFlags.NonPublic | BindingFlags.Instance);

        private static readonly MethodInfo bakeByteArrayMethod = typeof(ILGenerator).GetMethod("BakeByteArray", BindingFlags.NonPublic | BindingFlags.Instance);

        private static readonly PropertyInfo dynamicScopeIndexor;

        private static readonly FieldInfo dynamicScopeField;

        private static readonly Type genericMethodInfoType;

        private static readonly FieldInfo genericMethodHandleField;

        private static readonly FieldInfo genericMethodContextField;

        private static readonly Type varArgMethodType;

        private static readonly FieldInfo varArgMethodMethod;

        private static readonly Type genericFieldInfoType;

        private static readonly FieldInfo genericFieldInfoHandle;        

        private static readonly FieldInfo genericFieldInfoContext;

        private static readonly FieldInfo ownerField;

        private object dynamicScope;

        private ILGenerator generator;

        static DynamicILReaderProvider()
        {
            BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
            dynamicScopeIndexor = Type.GetType("System.Reflection.Emit.DynamicScope").GetProperty("Item", bindingFlags);
            dynamicScopeField = Type.GetType("System.Reflection.Emit.DynamicILGenerator").GetField("m_scope", bindingFlags);

            varArgMethodType = Type.GetType("System.Reflection.Emit.VarArgMethod");
            varArgMethodMethod = varArgMethodType.GetField("m_method", bindingFlags);

            genericMethodInfoType = Type.GetType("System.Reflection.Emit.GenericMethodInfo");
            genericMethodHandleField = genericMethodInfoType.GetField("m_methodHandle", bindingFlags);
            genericMethodContextField = genericMethodInfoType.GetField("m_context", bindingFlags);

            genericFieldInfoType = Type.GetType("System.Reflection.Emit.GenericFieldInfo", false);
            if (genericFieldInfoType != null)
            {
                genericFieldInfoHandle = genericFieldInfoType.GetField("m_fieldHandle", bindingFlags);
                genericFieldInfoContext = genericFieldInfoType.GetField("m_context", bindingFlags);
            }
            else
            {
                genericFieldInfoHandle = genericFieldInfoContext = null;
            }

            RuntimeDynamicMethodType = typeof(DynamicMethod).GetNestedType("RTDynamicMethod", BindingFlags.NonPublic);
            ownerField = RuntimeDynamicMethodType.GetField("m_owner", bindingFlags);
        }

        private DynamicILReaderProvider(DynamicMethod method)
        {
            this.Method = method;
            this.generator = method.GetILGenerator();
            this.dynamicScope = dynamicScopeField.GetValue(this.generator);
        }

        public DynamicMethod Method { get; private set; }

        internal object this[int token]
        {
            get
            {
                return dynamicScopeIndexor.GetValue(this.dynamicScope, new object[] { token });
            }
        }

        public static DynamicILReaderProvider Create(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            DynamicMethod dynamicMethod = method as DynamicMethod;
            if (dynamicMethod != null)
            {
                return new DynamicILReaderProvider(dynamicMethod);
            }

            Type methodType = method.GetType();
            if (RuntimeDynamicMethodType.IsAssignableFrom(methodType))
            {
                return new DynamicILReaderProvider(ownerField.GetValue(method) as DynamicMethod);
            }

            return null;
        }

        public byte[] GetMethodBody()
        {
            byte[] data = null;
            ILGenerator ilgen = this.Method.GetILGenerator();

            try
            {
                data = (byte[])bakeByteArrayMethod.Invoke(ilgen, null) ?? new byte[0];
            }
            catch (TargetInvocationException)
            {
                int length = (int)fileLengthField.GetValue(ilgen);
                data = new byte[length];
                Array.Copy((byte[])IntermediateLanguageBytesField.GetValue(ilgen), data, length);
            }

            return data;
        }

        public FieldInfo ResolveField(int metadataToken)
        {
            object tokenValue = this[metadataToken];
            if (tokenValue is RuntimeFieldHandle)
            {
                return FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)tokenValue);
            }

            if (tokenValue.GetType() == DynamicILReaderProvider.genericFieldInfoType)
            {
                return FieldInfo.GetFieldFromHandle(
                    (RuntimeFieldHandle)genericFieldInfoHandle.GetValue(tokenValue),
                    (RuntimeTypeHandle)genericFieldInfoContext.GetValue(tokenValue));
            }

            return null;
        }

        public MemberInfo ResolveMember(int metadataToken)
        {
            if ((metadataToken & TypeRidPrefix) != 0)
            {
                return this.ResolveType(metadataToken);
            }

            if ((metadataToken & MethodRidPrefix) != 0)
            {
                return this.ResolveMethod(metadataToken);
            }

            if ((metadataToken & FieldRidPrefix) != 0)
            {
                return this.ResolveField(metadataToken);
            }

            return null;
        }

        public MethodBase ResolveMethod(int metadataToken)
        {
            object tokenValue = this[metadataToken];
            DynamicMethod dynamicMethod = tokenValue as DynamicMethod;
            if (dynamicMethod != null)
            {
                return dynamicMethod;
            }

            if (tokenValue is RuntimeMethodHandle)
            {
                return MethodBase.GetMethodFromHandle((RuntimeMethodHandle)this[metadataToken]);
            }

            if (tokenValue.GetType() == DynamicILReaderProvider.genericFieldInfoType)
            {
                return MethodBase.GetMethodFromHandle(
                    (RuntimeMethodHandle)genericMethodHandleField.GetValue(tokenValue),
                    (RuntimeTypeHandle)genericMethodContextField.GetValue(tokenValue));
            }

            if (tokenValue.GetType() == DynamicILReaderProvider.varArgMethodType)
            {
                return DynamicILReaderProvider.varArgMethodMethod.GetValue(tokenValue) as MethodInfo;
            }

            return null;
        }

        public byte[] ResolveSignature(int metadataToken)
        {
            return this[metadataToken] as byte[];
        }
        public string ResolveString(int metadataToken)
        {
            return this[metadataToken] as string;
        }

        public Type ResolveType(int metadataToken)
        {
            return Type.GetTypeFromHandle((RuntimeTypeHandle)this[metadataToken]);
        }
    }

    internal class ILReaderProvider : IILReaderProvider
    {
        public ILReaderProvider(MethodInfo method)
        {
            this.Method = method;
            this.MethodBody = method.GetMethodBody();
            this.MethodModule = method.Module;
        }

        public MethodInfo Method { get; private set; }

        public MethodBody MethodBody { get; private set; }

        public Module MethodModule { get; private set; }

        public byte[] GetMethodBody()
        {
            return this.MethodBody.GetILAsByteArray();
        }

        public FieldInfo ResolveField(int metadataToken)
        {
            return this.MethodModule.ResolveField(metadataToken);
        }

        public MemberInfo ResolveMember(int metadataToken)
        {
            return this.MethodModule.ResolveMember(metadataToken);
        }

        public MethodBase ResolveMethod(int metadataToken)
        {
            return this.MethodModule.ResolveMethod(metadataToken);
        }

        public byte[] ResolveSignature(int metadataToken)
        {
            return this.MethodModule.ResolveSignature(metadataToken);
        }

        public string ResolveString(int metadataToken)
        {
            return this.MethodModule.ResolveString(metadataToken);
        }

        public Type ResolveType(int metadataToken)
        {
            return this.MethodModule.ResolveType(metadataToken);
        }
    }
5
добавлено
Это - удивительный ответ.Thank you!!! Я могу изменить последовательность на основе символа метаданных?
добавлено автор rodolk, источник
Ничего себе! Спасибо AbdElRaheim! Я, надо надеяться, получу шанс проверить этот код этим днем.
добавлено автор Dave Nay, источник
Еще раз спасибо. Я смог осуществить ваш код и достигнуть того, что я должен был.
добавлено автор Dave Nay, источник

Я боюсь, что вы не можете. Необходимо было бы разобрать код. Изучить Рослин.

1
добавлено
Хм.... это кажется странным (мне). Последовательности должны быть сохранены на собрании/somewhere/. Возможно, MS просто didn' t обеспечивают доступ к этому посредством отражения.
добавлено автор Dave Nay, источник

Вы могли , но не будете легкими или уберете или опрятный и вероятно будете трудными получить его работающий достоверно.

Можно начать с MethodInfo. GetMethodBody() и затем разбирают двойной IL. Есть некоторые библиотеки там, которые делают это, пробуют Сесил например.

0
добавлено
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot