using System; using System.Reflection; using Mono.Cecil; using Mono.Cecil.Cil; namespace dtdfixer { class MainClass { public static void Main (string[] args) { ModuleDefinition module = ModuleDefinition.ReadModule ("Assembly-CSharp.dll"); TypeDefinition type = module.GetType ("GameManager"); if (isPatched (type)) { Console.WriteLine("Assembly already patched"); return; } markTypePatched (module, type); telnetPatch (module); connectLogPatch (module); executionLogPatch (module); publicCommandPermissionsPatch (module); playerDataPatch (module); module.Write ("Assembly-CSharp.dll"); Console.WriteLine ("Done"); } private static void playerDataPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("GameManager"); addHook (type, "SavePlayerData", true, 2, true, typeof(PlayerDataStuff).GetMethod ("GM_SavePlayerData")); } private static void publicCommandPermissionsPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("AdminTools"); replaceMethod (type, "GetAllowedCommandsList", true, 1, typeof(AdminToolsStuff).GetMethod ("GetAllowedCommandsList")); } private static void connectLogPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("GameManager"); addHook (type, "RequestToSpawnPlayer", true, 5, true, typeof(AllocsLogFunctions).GetMethod ("RequestToSpawnPlayer")); } private static void executionLogPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("ConsoleSdtd"); addHook (type, "ExecuteCmdFromClient", true, 3, false, typeof(AllocsLogFunctions).GetMethod ("ExecuteCmdFromClient")); } private static void telnetPatch (ModuleDefinition module) { TypeDefinition type = module.GetType ("NetTelnetServer"); replaceMethod (type, ".ctor", false, 1, typeof(AllocsNetTelnetServer).GetMethod ("init")); replaceMethod (type, "Disconnect", false, 0, typeof(AllocsNetTelnetServer).GetMethod ("Disconnect")); replaceMethod (type, "SetConsole", false, 1, typeof(AllocsNetTelnetServer).GetMethod ("SetConsole")); replaceMethod (type, "WriteToClient", false, 1, typeof(AllocsNetTelnetServer).GetMethod ("WriteToClient")); } private static void markTypePatched (ModuleDefinition module, TypeDefinition type) { type.Fields.Add (new FieldDefinition ("AllocsPatch", Mono.Cecil.FieldAttributes.Private | Mono.Cecil.FieldAttributes.SpecialName, module.Import (typeof(int)))); } private static void addHook (TypeDefinition type, string methodName, bool addThisRef, int opCount, bool atEnd, MethodBase targetMethod) { foreach (MethodDefinition method in type.Methods) { if (method.Name.Equals (methodName)) { Console.WriteLine ("Patching " + methodName); var il = method.Body.GetILProcessor (); var call = il.Create (OpCodes.Call, method.Module.Import (targetMethod)); if (atEnd) { int insBefore = method.Body.Instructions.Count; if (addThisRef) il.Append (il.Create (OpCodes.Ldarg, 0)); for (int op = 0; op < opCount; op++) { il.Append (il.Create (OpCodes.Ldarg, op + 1)); } il.Append (call); il.Remove (method.Body.Instructions [insBefore - 1]); il.Append (il.Create (OpCodes.Ret)); } else { var i = 0; if (addThisRef) il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, 0)); for (int op = 0; op < opCount; op++) { il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, op + 1)); } il.InsertBefore (method.Body.Instructions [i++], call); } } } } private static void replaceMethod (TypeDefinition type, string methodName, bool addThisRef, int opCount, MethodBase targetMethod) { foreach (MethodDefinition method in type.Methods) { if (method.Name.Equals (methodName)) { Console.WriteLine ("Patching " + methodName); var il = method.Body.GetILProcessor (); var call = il.Create (OpCodes.Call, method.Module.Import (targetMethod)); var i = 0; if (addThisRef) il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, 0)); for (int op = 0; op < opCount; op++) { il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ldarg, op + 1)); } il.InsertBefore (method.Body.Instructions [i++], call); il.InsertBefore (method.Body.Instructions [i++], il.Create (OpCodes.Ret)); } } } private static bool isPatched (TypeDefinition type) { foreach (FieldDefinition fd in type.Fields) { if (fd.Name.Equals ("AllocsPatch")) { Console.WriteLine ("\"" + type.Name + "\" is already patched, skipping"); return true; } } Console.WriteLine ("Patching \"" + type.Name + "\""); return false; } } }