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

Last change on this file since 142 was 142, checked in by alloc, 6 years ago

Fixes: Fixed #49

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