source: binary-improvements/assembly-patcher/Main.cs@ 128

Last change on this file since 128 was 128, checked in by alloc, 10 years ago

Fixes

File size: 5.3 KB
RevLine 
[73]1using System;
[107]2using System.Collections.Generic;
[73]3using System.Reflection;
4using Mono.Cecil;
5using Mono.Cecil.Cil;
6
7namespace dtdfixer
8{
9 class MainClass
10 {
11 public static void Main (string[] args)
12 {
13 ModuleDefinition module = ModuleDefinition.ReadModule ("Assembly-CSharp.dll");
[93]14
15 TypeDefinition type = module.GetType ("GameManager");
16 if (isPatched (type)) {
[107]17 Console.WriteLine ("Assembly already patched");
[93]18 return;
19 }
20 markTypePatched (module, type);
21
[128]22 mappingPatch (module);
[107]23 consoleOutputPatch (module);
[73]24 telnetPatch (module);
[76]25 connectLogPatch (module);
[84]26 publicCommandPermissionsPatch (module);
[93]27 playerDataPatch (module);
[107]28
[115]29 module.Write ("Assembly-CSharp.patched.dll");
[73]30 Console.WriteLine ("Done");
[107]31
[73]32 }
33
[128]34 private static void mappingPatch (ModuleDefinition module)
35 {
36 TypeDefinition type = module.GetType ("Chunk");
37 addHook (type, "CalcMapColors", true, 0, true, typeof(MapRendering).GetMethod ("RenderSingleChunk"));
38 }
39
[107]40 private static void consoleOutputPatch (ModuleDefinition module)
41 {
42 TypeDefinition type = module.GetType ("ConsoleSdtd");
43 replaceMethod (type, "ExecuteCmdFromClient", true, 3, typeof(ConsoleOutputSeparator).GetMethod ("C_ExecuteCmdFromClient"));
44 addHook (type, "Run", true, 0, true, typeof(ConsoleOutputSeparator).GetMethod ("C_Run"));
45 replaceMethod (type, "SendResult", true, 1, typeof(ConsoleOutputSeparator).GetMethod ("C_SendResult"));
46 }
47
[93]48 private static void playerDataPatch (ModuleDefinition module)
49 {
50 TypeDefinition type = module.GetType ("GameManager");
51 addHook (type, "SavePlayerData", true, 2, true, typeof(PlayerDataStuff).GetMethod ("GM_SavePlayerData"));
[107]52 addHook (type, "Awake", true, 0, true, typeof(CommandExtensions).GetMethod ("InitCommandExtensions"));
[93]53 }
54
[84]55 private static void publicCommandPermissionsPatch (ModuleDefinition module)
56 {
57 TypeDefinition type = module.GetType ("AdminTools");
58 replaceMethod (type, "GetAllowedCommandsList", true, 1, typeof(AdminToolsStuff).GetMethod ("GetAllowedCommandsList"));
59 }
60
[75]61 private static void connectLogPatch (ModuleDefinition module)
62 {
63 TypeDefinition type = module.GetType ("GameManager");
[83]64 addHook (type, "RequestToSpawnPlayer", true, 5, true, typeof(AllocsLogFunctions).GetMethod ("RequestToSpawnPlayer"));
[75]65 }
66
[73]67 private static void telnetPatch (ModuleDefinition module)
68 {
69 TypeDefinition type = module.GetType ("NetTelnetServer");
[84]70 replaceMethod (type, ".ctor", false, 1, typeof(AllocsNetTelnetServer).GetMethod ("init"));
71 replaceMethod (type, "Disconnect", false, 0, typeof(AllocsNetTelnetServer).GetMethod ("Disconnect"));
72 replaceMethod (type, "SetConsole", false, 1, typeof(AllocsNetTelnetServer).GetMethod ("SetConsole"));
73 replaceMethod (type, "WriteToClient", false, 1, typeof(AllocsNetTelnetServer).GetMethod ("WriteToClient"));
[73]74 }
75
76 private static void markTypePatched (ModuleDefinition module, TypeDefinition type)
77 {
78 type.Fields.Add (new FieldDefinition ("AllocsPatch", Mono.Cecil.FieldAttributes.Private | Mono.Cecil.FieldAttributes.SpecialName, module.Import (typeof(int))));
79 }
80
[76]81 private static void addHook (TypeDefinition type, string methodName, bool addThisRef, int opCount, bool atEnd, MethodBase targetMethod)
[73]82 {
83 foreach (MethodDefinition method in type.Methods) {
84 if (method.Name.Equals (methodName)) {
85 var il = method.Body.GetILProcessor ();
86 var call = il.Create (OpCodes.Call, method.Module.Import (targetMethod));
[76]87 if (atEnd) {
88 int insBefore = method.Body.Instructions.Count;
89 if (addThisRef)
90 il.Append (il.Create (OpCodes.Ldarg, 0));
91 for (int op = 0; op < opCount; op++) {
92 il.Append (il.Create (OpCodes.Ldarg, op + 1));
93 }
94 il.Append (call);
95 il.Remove (method.Body.Instructions [insBefore - 1]);
96 il.Append (il.Create (OpCodes.Ret));
97 } else {
98 var i = 0;
99 if (addThisRef)
100 il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, 0));
101 for (int op = 0; op < opCount; op++) {
102 il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, op + 1));
103 }
104 il.InsertBefore (method.Body.Instructions [i++], call);
[73]105 }
[107]106 return;
[75]107 }
108 }
[107]109 Console.WriteLine ("ERROR: Did not find " + type.Name + "." + methodName + "()");
[75]110 }
111
[84]112 private static void replaceMethod (TypeDefinition type, string methodName, bool addThisRef, int opCount, MethodBase targetMethod)
[75]113 {
114 foreach (MethodDefinition method in type.Methods) {
115 if (method.Name.Equals (methodName)) {
116 var il = method.Body.GetILProcessor ();
117 var call = il.Create (OpCodes.Call, method.Module.Import (targetMethod));
118 var i = 0;
[84]119 if (addThisRef)
120 il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, 0));
[75]121 for (int op = 0; op < opCount; op++) {
122 il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, op + 1));
123 }
124 il.InsertBefore (method.Body.Instructions [i++], call);
[73]125 il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ret));
[107]126 return;
[73]127 }
128 }
[107]129 Console.WriteLine ("ERROR: Did not find " + type.Name + "." + methodName + "()");
[73]130 }
131
132 private static bool isPatched (TypeDefinition type)
133 {
134 foreach (FieldDefinition fd in type.Fields) {
135 if (fd.Name.Equals ("AllocsPatch")) {
136 return true;
137 }
138 }
139 return false;
140 }
141 }
142}
Note: See TracBrowser for help on using the repository browser.