Search code examples
c#.net-assembly.net-2.0

C# programmatically edit my .NET assembly at runtime


I have a .NET assembly that is built by me but would like to be able rewrite the .DLL with some minor but arbitrary attribute change file at runtime. Specifically I would like to be able to change a property of an attribute of a class so that I can customize the binary depending on the situation.

To illustrate, I want to achieve the effect of editing the assembly being generated from the code

[SomeAttribute("Name")]
public class MyClass{
    ...

such that the new assembly is functionally the same as

[SomeAttribute("Custom Name")]
public class MyClass{
    ...

And this "Custom Name" could be anything (determined at runtime). Is this possible to do at runtime?

The reason why the actual .DLL needs to be modified is because it will get loaded up by a seperate process which cannot determine the runtime information (I do not control this process).

Experimentation so far has shown that it seems to work if the new "Custom Name" is the same length as the original, but not otherwise (even if you edit the preceding byte that specifies the length; presumably there are offsets stored in the file somewhere).

EDIT: Forgot to mention, solution needs to be under the .NET 2 framework as well.


Solution

  • Using the extremely helpful suggestion from @xanatos I have made this solution:

    Under .NET 2, you can install package Mono.Cecil 0.9.6.1.

    The code then is as follows:

    AssemblyDefinition assbDef = AssemblyDefinition.ReadAssembly("x.dll");
    TypeDefinition type = assbDef.MainModule.GetType("NameSpace.MyClass").Resolve();
    foreach (CustomAttribute attr in type.CustomAttributes)
    {
        TypeReference argTypeRef = null;
        int? index = null;
        for (int i = 0; i < attr.ConstructorArguments.Count; i++)
        {
            CustomAttributeArgument arg = attr.ConstructorArguments[i];
    
            string stringValue = arg.Value as string;
            if (stringValue == "Name")
            {
                argTypeRef = arg.Type;
                index = i;
            }
        }
    
        if (index != null)
        {
            attr.ConstructorArguments[(int)index] = new CustomAttributeArgument(argTypeRef, newName);
        }
    }    
    assbDef.Write("y.dll");
    

    Which will search an assembly for any attribute arguments with value "Name" and replace their value with newName.