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

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

fixes

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