Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用Mono Cecil更改字段值?_C#_Field_Mono.cecil - Fatal编程技术网

C# 如何使用Mono Cecil更改字段值?

C# 如何使用Mono Cecil更改字段值?,c#,field,mono.cecil,C#,Field,Mono.cecil,我有一个C#程序,它有一个类: public class Test { internal const string a = "some value"; private DateTime b = new DateTime(); } 如何使用Mono Cecil更改其初始值,使其看起来像这样: public class Test { internal const string a = "test"; private DateT

我有一个C#程序,它有一个类:

public class Test
{
    internal const string a = "some value";
    private DateTime b = new DateTime();
}
如何使用Mono Cecil更改其初始值,使其看起来像这样:

public class Test
{
    internal const string a = "test";
    private DateTime b = DateTime.MaxValue;
}
现在我只有下面的框架代码,我不知道如何修改字段

void Main()
{
    var input = @"C:\my_projects\a.exe";
    var asm = AssemblyDefinition.ReadAssembly(input);
    foreach (ModuleDefinition module in asm.Modules)
    {
        foreach (TypeDefinition type in module.GetTypes())
        {

            foreach (var field in type.Fields)
            {
                if (field.Name == "a")
                {

                }

                else if (field.Name == "b")
                {

                }

            }
        }
    }
    asm.Write(@"c:\my_projects\b.exe");
}
免责声明

非常脆弱的代码

对于常数,需要设置
fld.constant
属性

例如,C#编译器将在构造函数中发出初始化代码,因此您需要找到加载将存储在字段中的值的指令并替换它

using System.IO;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace x
{
    class Program
    {
        public const string ConstValue = "old";
        public int instanceField = 1;

        static void Main(string[] args)
        {
            var o = new Program();
            if (o.instanceField == 1)
            {
                using var a = AssemblyDefinition.ReadAssembly(typeof(Program).Assembly.Location);
                var t = a.MainModule.Types.Single(ct => ct.Name == "Program");

                var constant = t.Fields.First(f => f.Name == "ConstValue");
                constant.Constant = "new value";

                var ctor = t.Methods.Single(m => m.IsConstructor);
                System.Console.WriteLine(ctor);
                var il = ctor.Body.GetILProcessor();

                var inst = il.Body.Instructions.First();
                while (inst != null)
                {
                    System.Console.WriteLine($"Checking {inst}");
                    if (inst.OpCode == OpCodes.Stfld && ((FieldReference) inst.Operand).Name == "instanceField")
                    {
                        // notice that this is very fragile. For this specific
                        // case I'd say it is safe but depending on how you
                        // initialize the field the instruction that loads 
                        // the value to be assigned to the field may be located 
                        // several instructions prior to the actual assignment
                        // but you can keep track of the stack state and figure 
                        // out which instruction is pushing the value that
                        // will end up being poped into the field.
                        
                        il.Replace(inst.Previous, il.Create(OpCodes.Ldc_I4, 42));                        
                        System.Console.WriteLine("Found");
                        break;
                    }
                    inst = inst.Next;
                }

                var  p = typeof(Program).Assembly.Location;
                var newBinaryPath =  Path.Combine(Path.GetDirectoryName(p), Path.GetFileNameWithoutExtension(p) + "2" +Path.GetExtension(p));
                a.Write(newBinaryPath);
                System.Console.WriteLine($"New binary writen to {newBinaryPath}");
            }

            System.Console.WriteLine(o.instanceField);

            // Notice that no matter what you do, this will always print the 
            // old value; that happens because the C# compiler will emit the
            // constant at the call site (instead of referencing the field
            // at runtime)
            System.Console.WriteLine(ConstValue);
        }
    }
}