public void Patch() { System.Reflection.Assembly ownAssembly = System.Reflection.Assembly.GetCallingAssembly(); Stream xmlStream = ownAssembly.GetManifestResourceStream("SKPatcher.xmlpatchers.xml"); XmlDocument xml = new XmlDocument(); xml.Load(xmlStream); XmlElement document = xml.DocumentElement; XmlNode[] hookNodes = document.ChildNodes.Items("hook"); foreach (XmlNode hookNode in hookNodes) { if (hookNode.Attributes["type"] == null || hookNode.Attributes["name"] == null || hookNode.Attributes["insertAt"] == null) { logger.Error("Error in xmlpatchers.xml : Unable to find one of the necessary attributes!"); break; } if (hookNode.Attributes["type"].Value.ToLower().Equals("event")) { string eventName = hookNode.Attributes["name"].Value; bool isCancellable = (hookNode.Attributes["cancellable"] != null) && (hookNode.Attributes["cancellable"].Value.ToLower().Equals("true")); int insertAt; if (!Int32.TryParse(hookNode.Attributes["insertAt"].Value, out insertAt)) { logger.Error("Error in xmlpatchers.xml : Unable to parse the insertAt value!"); continue; } XmlNode typeNode = hookNode.ChildNodes.Item("type"); XmlNode methodNode = hookNode.ChildNodes.Item("method"); XmlNode parametersNode = hookNode.ChildNodes.Item("parameters"); if (typeNode == null || methodNode == null || parametersNode == null) { logger.Error("Error in xmlpatchers.xml : ChildNodes missing for event (name = \"" + eventName + "\")!"); continue; } string typeName = typeNode.Attributes["name"].Value; XmlAttribute methodName = methodNode.Attributes["name"]; XmlAttribute methodParameters = methodNode.Attributes["parameters"]; XmlAttribute methodReturn = methodNode.Attributes["return"]; TypeDefinition targetType = module.GetType(typeName); if (targetType == null) { logger.Error("Error in xmlpatchers.xml : Unable to find type \"" + typeName + "\"!"); continue; } //I don't always use 'var' but when I do, it would be odd not to. var methodComparers = new List <HelperClass.GenericFuncContainer <MethodDefinition, bool> >(3); if (methodName != null) { methodComparers.Add(HelperClass.MemberNameComparer <MethodDefinition>(methodName.Value)); } if (methodParameters != null) { methodComparers.Add(HelperClass.MethodParametersComparer(methodParameters.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))); } if (methodReturn != null) { methodComparers.Add(HelperClass.MethodReturnTypeComparer(methodReturn.Value)); } methodComparers.Add(new HelperClass.GenericFuncContainer <MethodDefinition, bool>(method => Matches(method, methodNode))); MethodDefinition targetMethod = HelperClass.findMember <MethodDefinition>(module, targetType, false, methodComparers.ToArray()); int parameterId = (isCancellable ? 0 : -1); if (targetMethod != null) { MethodBody body = targetMethod.Body; ILProcessor proc = body.GetILProcessor(); List <Instruction[]> argLoaders = new List <Instruction[]>(parametersNode.ChildNodes.Count + (isCancellable ? 1 : 0)); if (isCancellable) { argLoaders.Add(new Instruction[] { proc.Create(OpCodes.Ldc_I4_0), proc.Create(OpCodes.Box, module.Import(mscorlibModule.GetType("System.Boolean"))) }); } List <Instruction[]> argWriters = new List <Instruction[]>(parametersNode.ChildNodes.Count); if (isCancellable) { Instruction[] cancelInstr = new Instruction[8]; cancelInstr[0] = proc.Create(OpCodes.Dup); cancelInstr[1] = proc.Create(OpCodes.Ldc_I4_0); cancelInstr[2] = proc.Create(OpCodes.Ldelem_Ref); cancelInstr[3] = proc.Create(OpCodes.Unbox_Any, module.Import(mscorlibModule.GetType("System.Boolean"))); cancelInstr[5] = proc.Create(OpCodes.Pop); cancelInstr[6] = proc.Create(OpCodes.Ret); cancelInstr[7] = proc.Create(OpCodes.Nop); cancelInstr[4] = proc.Create(OpCodes.Brfalse, cancelInstr[7]); argWriters.Add(cancelInstr); } foreach (XmlNode parNode in parametersNode.ChildNodes.Items("parameter")) { parameterId++; XmlAttribute _typeAttr = parNode.Attributes["type"]; string parType = (_typeAttr == null) ? "System.Object" : _typeAttr.Value; TypeDefinition parTypeDef = findType(parType); if (parTypeDef == null) { logger.Error("Error in xmlpatchers.xml : Unable to find type \"" + parType + "\"!"); continue; } bool isCustom = parNode.Attributes.ValueOf("isCustom").ToLower().Equals("true"); XmlNode loadNode = parNode.ChildNodes.Item("load"); XmlNode writeNode = parNode.ChildNodes.Item("write"); if (loadNode != null) { List <Instruction> loadInstr = new List <Instruction>(ParseInstructions(loadNode, proc)); if (parTypeDef.IsValueType) { loadInstr.Add(proc.Create(OpCodes.Box, module.Import(parTypeDef))); } argLoaders.Add(loadInstr.ToArray()); } if (writeNode != null) { List <Instruction> writeInstr = new List <Instruction> (); if (!isCustom) { writeInstr.Add(proc.Create(OpCodes.Dup)); writeInstr.Add(proc.Create(OpCodes.Ldc_I4, parameterId)); writeInstr.Add(proc.Create(OpCodes.Ldelem_Ref)); if (parTypeDef.IsValueType) { writeInstr.Add(proc.Create(OpCodes.Unbox_Any, module.Import(parTypeDef))); } else { writeInstr.Add(proc.Create(OpCodes.Castclass, module.Import(parTypeDef))); } } writeInstr.AddRange(ParseInstructions(writeNode, proc)); argWriters.Add(writeInstr.ToArray()); } } List <Instruction> hook = HookHelper.Instance.prepareEventHook(targetMethod, eventName, argLoaders.ToArray()); for (int i = 0; i < argWriters.Count; i++) { hook.AddRange(argWriters[i]); } hook.Add(proc.Create(OpCodes.Pop)); HookHelper.insertAt(body, insertAt, hook.ToArray()); } } } }
public void Patch() { HelperClass.SetLogger(null); //HelperClass.OnError would otherwise show errors if a NetPackage class doesn't override Process,Read or Write TypeDefinition[] netPackageTypes = HelperClass.findTypes(module, HelperClass.CombinedComparer <MethodDefinition>( HelperClass.MemberNameComparer <MethodDefinition>("GetPackageType"), HelperClass.MethodReturnTypeComparer("PackageType"), HelperClass.MethodNegAttributeComparer(MethodAttributes.Abstract)) ); if (netPackageTypes == null || netPackageTypes.Length == 0) { logger.Error("Unable to find any NetPackage classes!"); return; } foreach (TypeDefinition curPackageType in netPackageTypes) { MethodDefinition processMethod = HelperClass.findMember <MethodDefinition>(module, curPackageType, false, HelperClass.MemberNameComparer <MethodDefinition>("Process"), HelperClass.MethodReturnTypeComparer("System.Void"), HelperClass.MethodParametersComparer("World", "INetConnectionCallbacks")); if (processMethod != null) { MethodBody body = processMethod.Body; if (body != null) { ILProcessor proc = body.GetILProcessor(); List <Instruction> eventHook = HookHelper.Instance.prepareEventHook(processMethod, "ProcessPacketEvent", new Instruction[][] { new Instruction[] { proc.Create(OpCodes.Ldarg_0), }, new Instruction[] { proc.Create(OpCodes.Ldc_I4_0), proc.Create(OpCodes.Box, module.Import(mscorlibModule.GetType("System.Boolean"))), }, new Instruction[] { proc.Create(OpCodes.Ldarg_1), }, new Instruction[] { proc.Create(OpCodes.Ldarg_2), }, } ); eventHook.Add(proc.Create(OpCodes.Ldc_I4_1)); eventHook.Add(proc.Create(OpCodes.Ldelem_Ref)); eventHook.Add(proc.Create(OpCodes.Unbox_Any, module.Import(mscorlibModule.GetType("System.Boolean")))); eventHook.Add(proc.Create(OpCodes.Brfalse, body.Instructions[0])); eventHook.Add(proc.Create(OpCodes.Ret)); HookHelper.insertAt(body, 0, eventHook.ToArray()); } } MethodDefinition readMethod = HelperClass.findMember <MethodDefinition>(module, curPackageType, false, HelperClass.MemberNameComparer <MethodDefinition>("Read"), HelperClass.MethodReturnTypeComparer("System.Void"), HelperClass.MethodParametersComparer("System.IO.BinaryReader")); if (readMethod != null) { MethodBody body = readMethod.Body; if (body != null) { ILProcessor proc = body.GetILProcessor(); List <Instruction> eventHook = HookHelper.Instance.prepareEventHook(readMethod, "ReadPacketFromBufEvent", new Instruction[][] { new Instruction[] { proc.Create(OpCodes.Ldarg_0), }, } ); eventHook.Add(proc.Create(OpCodes.Pop)); HookHelper.insertAt(body, body.Instructions.Count - 1, eventHook.ToArray()); } } MethodDefinition writeMethod = HelperClass.findMember <MethodDefinition>(module, curPackageType, false, HelperClass.MemberNameComparer <MethodDefinition>("Write"), HelperClass.MethodReturnTypeComparer("System.Void"), HelperClass.MethodParametersComparer("System.IO.BinaryWriter")); if (writeMethod != null) { MethodBody body = writeMethod.Body; if (body != null) { ILProcessor proc = body.GetILProcessor(); List <Instruction> eventHook = HookHelper.Instance.prepareEventHook(writeMethod, "WritePacketToBufEvent", new Instruction[][] { new Instruction[] { proc.Create(OpCodes.Ldarg_0), }, new Instruction[] { proc.Create(OpCodes.Ldc_I4_0), proc.Create(OpCodes.Box, module.Import(mscorlibModule.GetType("System.Boolean"))), }, } ); eventHook.Add(proc.Create(OpCodes.Ldc_I4_1)); eventHook.Add(proc.Create(OpCodes.Ldelem_Ref)); eventHook.Add(proc.Create(OpCodes.Unbox_Any, module.Import(mscorlibModule.GetType("System.Boolean")))); eventHook.Add(proc.Create(OpCodes.Brfalse, body.Instructions[0])); eventHook.Add(proc.Create(OpCodes.Ret)); HookHelper.insertAt(body, 0, eventHook.ToArray()); } } } }