Posted March 10, 20169 yr Today I wrote a small class that assists with patching .NET binaries. using System; using System.IO; using dnlib.DotNet; using dnlib.DotNet.Emit; namespace MyNamespace { class Patcher { public delegate bool PatchStrategy(AssemblyDef asm); private static bool patchMethodReturnBool(AssemblyDef asm, string classPath, string methodName, bool returnValue, int numArguments = 0) { var method = findMethod(asm, classPath, methodName); if (method != null && method.Parameters.Count == numArguments) { //patch instructions var instructions = method.Body.Instructions; if (returnValue) instructions.Insert(0, OpCodes.Ldc_I4_1.ToInstruction()); //true else instructions.Insert(0, OpCodes.Ldc_I4_0.ToInstruction()); //false instructions.Insert(1, OpCodes.Ret.ToInstruction()); return true; } return false; } private static MethodDef findMethod(TypeDef type, string methodName) { if (type != null) { foreach (var method in type.Methods) { if (method.Name == methodName) return method; } } return null; } private static MethodDef findMethod(AssemblyDef asm, string classPath, string methodName) { return findMethod(findType(asm, classPath), methodName); } private static TypeDef findType(AssemblyDef asm, string classPath) { foreach (var module in asm.Modules) { foreach (var type in module.Types) { if (type.FullName == classPath) return type; } } return null; } public static bool PatchAssembly(string path, ref string error, PatchStrategy patcher) { var bakpath = path + ".bak"; try { //handle backup if (!File.Exists(bakpath)) File.Copy(path, bakpath); else File.Copy(bakpath, path, true); } catch (Exception x) { error = x.ToString(); return false; } try { DateTime creationTime = File.GetCreationTime(path); //load module var module = ModuleDefMD.Load(File.ReadAllBytes(path)); //execute patching strategy if (!patcher(module.Assembly)) return false; //write assembly if (module.IsILOnly) module.Write(path); else module.NativeWrite(path); //restore file date File.SetLastWriteTime(path, creationTime); File.SetCreationTime(path, creationTime); return true; } catch (Exception x) { File.Copy(bakpath, path, true); error = x.ToString(); } return false; } } } For every patch you write a strategy like this: public static bool PatchRegistrationCheck(AssemblyDef asm) { string classPath = "MyNamespace.MyClass"; /* * public bool IsRegistered(RegistrationData rd) * { * return true; * } */ if (!patchMethodReturnBool(asm, classPath, "IsRegistered", true, 2)) //2 parameters (this + rd) throw new Exception("MyClass.IsRegistered not patched!"); return true; } Then you call it like this: Patcher.PatchAssembly(filePath, Patcher.PatchRegistrationCheck); Hope it will be useful for some of you. Greetings Edited March 10, 20169 yr by Mr. eXoDia
Create an account or sign in to comment