Program.cs 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. using System;
  2. using Mono.Cecil;
  3. using Mono.Cecil.Cil;
  4. class P {
  5. static int Main(string[] a) {
  6. string src = a[0], dst = a[1];
  7. var m = ModuleDefinition.ReadModule(src);
  8. var tsAppDomain = new TypeReference("System", "AppDomain", m, m.TypeSystem.CoreLibrary, false);
  9. var getCurrentDomain = new MethodReference("get_CurrentDomain", tsAppDomain, tsAppDomain){ HasThis = false };
  10. var getBaseDir = new MethodReference("get_BaseDirectory", m.TypeSystem.String, tsAppDomain){ HasThis = true };
  11. var mGetCurrent = m.ImportReference(getCurrentDomain);
  12. var mGetBase = m.ImportReference(getBaseDir);
  13. int patched = 0;
  14. foreach (var t in m.GetTypes())
  15. foreach (var meth in t.Methods) {
  16. if (!meth.HasBody) continue;
  17. var il = meth.Body.Instructions;
  18. for (int i = 1; i < il.Count; i++) {
  19. var ins = il[i];
  20. if (ins.OpCode == OpCodes.Call && ins.Operand is MethodReference mr
  21. && mr.Name == "initialize" && mr.DeclaringType.Name == "Entry"
  22. && mr.Parameters.Count == 2 && il[i-1].OpCode == OpCodes.Ldnull) {
  23. // assumes the ldnull is not a branch or handler target; Replace
  24. // does not retarget operands pointing at the removed instruction
  25. var proc = meth.Body.GetILProcessor();
  26. var ldnull = il[i-1];
  27. var call1 = proc.Create(OpCodes.Call, mGetCurrent);
  28. var call2 = proc.Create(OpCodes.Callvirt, mGetBase);
  29. proc.Replace(ldnull, call1);
  30. proc.InsertAfter(call1, call2);
  31. patched++;
  32. Console.WriteLine($"Patched {t.FullName}.{meth.Name}: ldnull -> AppDomain.CurrentDomain.BaseDirectory");
  33. }
  34. }
  35. }
  36. if (patched == 0) { Console.WriteLine("No patch site found"); return 2; }
  37. m.Write(dst);
  38. Console.WriteLine($"Wrote {dst}, patched={patched}");
  39. return 0;
  40. }
  41. }