Skip to content

Instantly share code, notes, and snippets.

@PathogenDavid
Last active April 10, 2018 10:08
Show Gist options
  • Save PathogenDavid/28c52c6a90fcc4c28a9d66981c92ba5d to your computer and use it in GitHub Desktop.
Save PathogenDavid/28c52c6a90fcc4c28a9d66981c92ba5d to your computer and use it in GitHub Desktop.
Evil Fody weaver for force writing readonly fields with test program to be weaved by it.
using Fody;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System.Collections.Generic;
using System.Linq;
namespace Evil.Fody
{
public class ModuleWeaver : BaseModuleWeaver
{
public override void Execute()
{
TypeDefinition programType = ModuleDefinition.Types.First(t => t.Name == "Program");
FieldDefinition lolField = programType.Fields.First(f => f.Name == "<Lol>k__BackingField");
FieldDefinition lelField = programType.Fields.First(f => f.Name == "Lel");
MethodDefinition evilConstructor = programType.Methods.First(m => m.Name == ".ctor" && m.Parameters.Count == 0);
MethodDefinition evilMethod = programType.Methods.First(m => m.Name == "Evil");
evilMethod.Body.Instructions.Clear();
ILProcessor processor = evilMethod.Body.GetILProcessor();
processor.Emit(OpCodes.Nop);
#if true
// This produces verification error 0x80131884
// [IL]: Error: [... : ForceWriteReadonly.Program::Evil][offset 0x0000000A]
// Cannot change initonly field outside its .ctor.(Error: 0x80131884)
processor.Emit(OpCodes.Ldarg_0);
processor.Emit(OpCodes.Ldarg_0);
processor.Emit(OpCodes.Ldfld, lelField);
processor.Emit(OpCodes.Ldc_I4_1);
processor.Emit(OpCodes.Add);
processor.Emit(OpCodes.Stfld, lelField);
processor.Emit(OpCodes.Ldarg_0);
processor.Emit(OpCodes.Ldarg_0);
processor.Emit(OpCodes.Ldfld, lolField);
processor.Emit(OpCodes.Ldc_I4_1);
processor.Emit(OpCodes.Add);
processor.Emit(OpCodes.Stfld, lolField);
#else
// This produces verification error 0x801318BF
// [IL]: Error: [... : ForceWriteReadonly.Program::Evil][offset 0x00000002][found ref ('this' ptr) 'ForceWriteReadonly.Program']
// Call to .ctor only allowed to initialize this pointer from within a .ctor. Try newobj.(Error: 0x801318BF)
processor.Emit(OpCodes.Ldarg_0);
processor.Emit(OpCodes.Call, evilConstructor);
#endif
processor.Emit(OpCodes.Ret);
}
public override IEnumerable<string> GetAssembliesForScanning()
{
yield break;
}
}
}
using System;
namespace ForceWriteReadonly
{
class Program
{
public int Lol { get; }
public readonly int Lel;
public Program(int x, int y)
{
Lol = x;
Lel = y;
}
// Evil constructor for alternate method
private Program()
{
Lol++;
Lel++;
}
public void Evil()
{
//Lol++;
//Lel++;
}
public override string ToString()
=> $"{Lol}, {Lel}";
static void Main(string[] args)
{
Program p = new Program(100, 200);
Console.WriteLine(p);
p.Evil();
Console.WriteLine(p);
p.Evil();
Console.WriteLine(p);
p.Evil();
Console.WriteLine(p);
Console.WriteLine("Done.");
Console.ReadLine();
}
}
}
@PathogenDavid
Copy link
Author

Here's the output of the weaved program:

100, 200
101, 201
102, 202
103, 203
Done.

@PathogenDavid
Copy link
Author

Also maybe worth pointing out that I've tested this in .NET Framework as well as .NET Core using Fody 3.0.3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment