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

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

A11 preps

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