Cannot set the base class of a type with Mono Cecil

戏子无情 提交于 2019-12-11 20:01:51

问题


I am trying to use Mono Cecil to manipulate a DLL. What I want to do is to set the base type of some classes to System.MarshalByRefObject from mscorlib.dll. I am using the following code.

var assembly = AssemblyDefinition.ReadAssembly(inputtarget);
var types = assembly.MainModule.Types;
var myTypesToChange = types.Where(...).Select(t => t);
var baseType = AssemblyDefinition.ReadAssembly(@"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll").MainModule.Types.Where(t => t.Name.Contains("MarshalByRefObject")).Select(t => t).First();
foreach (var myType in myTypesToChange)
{
    myType.BaseType = baseType;
}
assembly.Write(outputtarget);

In the output the base type is not set!

When I am setting the BaseType to a TypeReference selected from the existing assembly, it is setting the base type correctly.

I believe that what I do is very similar to the way it is done as suggested in this reply to a comment about the Code Project article "Reweaving IL code with Mono.Cecil":

"Yes, you can rewrite the base type of any class:"

var assembly = AssemblyDefinition.ReadAssembly(AssemblyPath); 
var mainModule = assembly.MainModule;

var companyType = mainModule.Types.First(t => t.Name == "Company");
var ownerType = mainModule.Types.First(t => t.Name == "Owner");

ownerType.BaseType = companyType;
assembly.Write(AssemblyPath);

This should be easy! What I am doing wrong?


回答1:


The problem is that assembly metadata is not taken into account. Each assembly has metadata which contains information related to assembly references and type usages.

What you have to do is to import the MarshalByRefObject type in mainModule:

var assembly = assemblyDef.AssemblyDefinition;
var types = assembly.MainModule.Types;
var myTypesToChange = types.Select(t => t);
var baseType = AssemblyDefinition.ReadAssembly(@"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll").MainModule.Types.Where(t => t.Name.Contains("MarshalByRefObject")).Select(t => t).First();
foreach (var myType in myTypesToChange)
{
    myType.BaseType = mainModule.Import(baseType);
}

Besides the metadata is extended, CIL code of the constructors have to be changed to invoke a constructor of the new base class instead of the original.

Finally, a suggestion. I think TypeReference for MarshalByRefObject can be extracted in a more elegant manner:

var baseType = mainModule.Import(typeof (MarshalByRefObject));
for (...)
{
    myType.BaseType = baseType;
}


来源:https://stackoverflow.com/questions/27401118/cannot-set-the-base-class-of-a-type-with-mono-cecil

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!