如何使用Mono.Cecil添加和初始化byte []字段

时间:2013-09-09 01:29:45

标签: .net mono.cecil

我想在byte[]类中添加<Module>类型的字段,并使用Mono.Cecil将其初始化为任意字节数组。以下不起作用。

TypeDefinition moduleClass = ModuleDefinition
    .GetAllTypes()
    .Single(typedef => typedef.Name == "<Module>");

FieldDefinition myBytes = new FieldDefinition("myBytes"
    ,FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.HasFieldRVA
    ,ModuleDefinition.Import(typeof(byte[])));

myBytes.InitialValue = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

moduleClass.Fields.Add(myBytes);

这是ILSpy中的结果(使用“IL”视图)。

.class private auto ansi '<Module>'
{
    // Fields
    .field private static uint8[] myBytes at I_00000000

} // end of class <Module>

当我尝试执行修改后的程序集时,我从程序集'TestApp,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'得到一个TypeLoadException并显示消息“Type'<Module>'有一个字段非法的。“

如果我删除FieldAttributes.HasFieldRVA,我没有错误,但at I_00000000消失,我认为这意味着该字段不会被初始化。

2 个答案:

答案 0 :(得分:1)

为了初始化一个原始值,就像你只想byte初始化一样,filed.InitialValue完美无缺。我不知道为什么它在这里不起作用。也许Jb Evain可以说出来。

请注意,如果您定义s静态字段并设置初始值,那么您设置的是RVA,然后在静态构造函数中,该字段将使用此RVA toekn中存在的数据进行初始化。

因此,为了解决这个问题,我建议你在静态构造函数中自己初始化字段,而不使用RVA。在我的例子中,我初始化一个2字节的字节数组。

var staticConstructorAttributes = 
    Mono.Cecil.MethodAttributes.Private|
    Mono.Cecil.MethodAttributes.HideBySig |
    Mono.Cecil.MethodAttributes.SpecialName |
    Mono.Cecil.MethodAttributes.RTSpecialName |
    Mono.Cecil.MethodAttributes.Static;

MethodDefinition staticConstructor = new MethodDefinition(".cctor", staticConstructorAttributes, module.TypeSystem.Void);
type.Methods.Add(staticConstructor);
type.IsBeforeFieldInit = false;
var il = staticConstructor.Body.GetILProcessor();

il.Emit(OpCodes.Ldc_I4_2); // if your array size is bigger than 4 you need to emit Ldc_I4_S or Ldc_I4
il.Emit(OpCodes.Newarr, module.TypesSystem.Byte); //create a new byte array
il.Emit(OpCodes.Stsfld, myBytesField); //store it in the myBytes static field
il.Emit(OpCodes.Ldsfld, myBytesField); // load the field
il.Emit(OpCodes.Ldc_I4_0); // index
il.Emit(OpCodes.Ldc_I4_0); // value
il.Emit(OpCodes.Stelem_I1); // store the byte value in the given index
il.Emit(OpCodes.Ldsfld, myBytesField);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Stelem_I1);
il.Emit(OpCodes.Ret);

答案 1 :(得分:-1)

您可以为<Module>类创建一个构造函数(静态),并在其中指定值。每当调用类时,将首先初始化构造函数,为您提供值。我个人不确定如何设置初始值,但你可以摆弄一些CIL,或者只是使用导入器将字节从另一个程序集导入到你自己的。

您可以在另一个问题中找到相关示例:Inject Method with Mono.Cecil