A fork of Eusth's IPA
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.9KB

  1. using Mono.Cecil;
  2. using Mono.Cecil.Cil;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. namespace IPA.Patcher
  9. {
  10. class PatchedModule
  11. {
  12. private static readonly string[] ENTRY_TYPES = { "Input", "Display" };
  13. private FileInfo _File;
  14. private ModuleDefinition _Module;
  15. public static PatchedModule Load(string engineFile)
  16. {
  17. return new PatchedModule(engineFile);
  18. }
  19. private PatchedModule(string engineFile)
  20. {
  21. _File = new FileInfo(engineFile);
  22. LoadModules();
  23. }
  24. private void LoadModules()
  25. {
  26. var resolver = new DefaultAssemblyResolver();
  27. resolver.AddSearchDirectory(_File.DirectoryName);
  28. var parameters = new ReaderParameters
  29. {
  30. AssemblyResolver = resolver,
  31. };
  32. _Module = ModuleDefinition.ReadModule(_File.FullName, parameters);
  33. }
  34. public bool IsPatched
  35. {
  36. get
  37. {
  38. foreach (var @ref in _Module.AssemblyReferences)
  39. {
  40. if (@ref.Name == "IllusionInjector") return true;
  41. }
  42. return false;
  43. }
  44. }
  45. public void Patch()
  46. {
  47. // First, let's add the reference
  48. var nameReference = new AssemblyNameReference("IllusionInjector", new Version(1, 0, 0, 0));
  49. var injectorPath = Path.Combine(_File.DirectoryName, "IllusionInjector.dll");
  50. var injector = ModuleDefinition.ReadModule(injectorPath);
  51. _Module.AssemblyReferences.Add(nameReference);
  52. int patched = 0;
  53. foreach(var type in FindEntryTypes())
  54. {
  55. if(PatchType(type, injector))
  56. {
  57. patched++;
  58. }
  59. }
  60. if(patched > 0)
  61. {
  62. _Module.Write(_File.FullName);
  63. } else
  64. {
  65. throw new Exception("Could not find any entry type!");
  66. }
  67. }
  68. private bool PatchType(TypeDefinition targetType, ModuleDefinition injector)
  69. {
  70. var targetMethod = targetType.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic);
  71. if (targetMethod != null)
  72. {
  73. var methodReference = _Module.Import(injector.GetType("IllusionInjector.Injector").Methods.First(m => m.Name == "Inject"));
  74. targetMethod.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, methodReference));
  75. return true;
  76. }
  77. return false;
  78. }
  79. private IEnumerable<TypeDefinition> FindEntryTypes()
  80. {
  81. return _Module.GetTypes().Where(m => ENTRY_TYPES.Contains(m.Name));
  82. }
  83. }
  84. }