gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 15:00:43 25 4
gpt4 key购买 nike

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

最佳答案

Disclaimer

Very brittle code ahead

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

关于c# - 如何使用 Mono Cecil 更改字段值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67017389/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com