【问题标题】:How can I change field value with Mono Cecil?如何使用 Mono Cecil 更改字段值?
【发布时间】:2021-07-05 02:44:52
【问题描述】:

我有一个 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");
}

【问题讨论】:

    标签: c# field mono.cecil


    【解决方案1】:

    免责声明

    前面的代码很脆弱

    对于常量,只需设置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);
            }
        }
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-20
      • 2012-06-19
      • 2011-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多