Patcher.Patcher.Patch C# (CSharp) Method

Patch() public static method

Inline classes marked as [Patch], copying fields and replacing method implementations. As you can probably guess from the code, this is wholly incomplete and will certainly break and have to be extended in the future.
public static Patch ( string modModulePath ) : void
modModulePath string
return void
        public static void Patch(string modModulePath)
        {
            var baseModule = ModuleDefinition.ReadModule("PatchedTowerFall.exe");

            var modModule = ModuleDefinition.ReadModule(modModulePath);

            Func<TypeReference, bool> patchType = (type) => {
                if (type.Scope == modModule)
                {
                    return type.Resolve().CustomAttributes.Any(attr => attr.AttributeType.FullName == "Patcher.PatchAttribute");
                }
                return false;
            };

            // baseModule won't recognize MemberReferences from modModule without Import(), so recursively translate them.
            // Furthermore, we have to redirect any references to members in [Patch] classes.
            Func<TypeReference, TypeReference> mapType = null;
            mapType = (modType) => {
                if (modType.IsGenericParameter)
                {
                    return modType;
                }
                if (modType.IsArray)
                {
                    var type = mapType(((ArrayType)modType).ElementType);
                    return new ArrayType(type);
                }
                if (patchType(modType))
                    modType = modType.Resolve().BaseType;
                return baseModule.Import(modType);
            };
            Action<MethodReference, MethodReference> mapParams = (modMethod, method) => {
                foreach (var param in modMethod.Parameters)
                    method.Parameters.Add(new ParameterDefinition(mapType(param.ParameterType)));
            };
            Func<MethodReference, MethodReference> mapMethod = (modMethod) => {
                var method = new MethodReference(modMethod.Name, mapType(modMethod.ReturnType), mapType(modMethod.DeclaringType));
                method.HasThis = modMethod.HasThis;
                mapParams(modMethod, method);
                return method as MethodReference;
            };
            Func<MethodDefinition, string, MethodDefinition> cloneMethod = (modMethod, prefix) => {
                var method = new MethodDefinition(prefix + modMethod.Name, modMethod.Attributes, mapType(modMethod.ReturnType));
                mapParams(modMethod, method);
                foreach (var modParam in modMethod.GenericParameters)
                {
                    var param = new GenericParameter(modParam.Owner);
                    method.GenericParameters.Add(param);
                }
                return method;
            };

            MyMInput.PatchModule(baseModule);
            MyMainMenu.PatchModule(baseModule);
            MyMenuButtons.PatchModule(baseModule);
            MyMenuInput.PatchModule(baseModule);
            MyPlayerInput.PatchModule(baseModule);
            MyReadyBanner.PatchModule(baseModule);
            MyRoundLogic.PatchModule(baseModule);
            MySession.PatchModule(baseModule);
            MyTFCommands.PatchModule(baseModule);
            MyTFGame.PatchModule(baseModule);
            MyTeamSelectOverlay.PatchModule(baseModule);
            MyVariant.PatchModule(baseModule);
            MyVersusAwards.PatchModule(baseModule);
            MyVersusRoundResults.PatchModule(baseModule);
            CleanMyVersusMatchResults.CleanModule(baseModule);
            CleanMyVersusPlayerMatchResults.CleanModule(baseModule);
            MyAwardInfo.PatchModule(baseModule);
            VersusPlayerMatchResultsAssembly.PatchModule(baseModule);
            CleanMyVariantPerPlayer.CleanModule(baseModule);

            foreach (TypeDefinition modType in modModule.Types.SelectMany(CecilExtensions.AllNestedTypes))
                if (patchType(modType))
                {
                    var type = baseModule.AllNestedTypes().Single(t => t.FullName == modType.BaseType.FullName);

                    // copy over fields including their custom attributes
                    foreach (var field in modType.Fields)
                        if (field.DeclaringType == modType)
                        {
                            var newField = new FieldDefinition(field.Name, field.Attributes, mapType(field.FieldType));
                            foreach (var attribute in field.CustomAttributes)
                                newField.CustomAttributes.Add(new CustomAttribute(mapMethod(attribute.Constructor), attribute.GetBlob()));
                            type.Fields.Add(newField);
                        }

                    // copy over or replace methods
                    foreach (var method in modType.Methods)
                        if (method.DeclaringType == modType)
                        {
                            var original = type.Methods.SingleOrDefault(m => m.Signature() == method.Signature());
                            MethodDefinition savedMethod = null;
                            if (original == null)
                                type.Methods.Add(original = cloneMethod(method, ""));
                            else {
                                savedMethod = cloneMethod(method, "$original_");
                                savedMethod.Body = original.Body;
                                savedMethod.IsRuntimeSpecialName = false;
                                type.Methods.Add(savedMethod);
                            }
                            original.Body = method.Body;

                            // redirect any references in the body
                            var proc = method.Body.GetILProcessor();
                            var amendments = new List<Action>();
                            foreach (var instr in method.Body.Instructions)
                            {
                                if (instr.Operand is MethodReference)
                                {
                                    var callee = (MethodReference)instr.Operand;
                                    if (callee.Name == "CallRealBase")
                                    {
                                        MethodReference baseMethod;
                                        try {
                                            baseMethod = type.BaseType.Resolve().Methods.Single(m => m.Name == method.Name) as MethodReference;
                                        }
                                        catch
                                        {
                                            baseMethod = ((TypeDefinition)(type.BaseType)).BaseType.Resolve().Methods.Single(m => m.Name == method.Name) as MethodReference;
                                        }
                                        amendments.Add(() => proc.InsertBefore(instr, proc.Create(OpCodes.Ldarg_0)));
                                        amendments.Add(() => proc.Replace(instr, proc.Create(OpCodes.Call, baseMethod)));
                                    }
                                    else {
                                        callee = mapMethod((MethodReference)instr.Operand);
                                        if (callee.FullName == original.FullName)
                                            // replace base calls with ones to $original
                                            instr.Operand = savedMethod;
                                        else
                                            instr.Operand = callee;
                                    }
                                }
                                else if (instr.Operand is FieldReference)
                                {
                                    var field = (FieldReference)instr.Operand;
                                    instr.Operand = new FieldReference(field.Name, mapType(field.FieldType), mapType(field.DeclaringType));
                                }
                                else if (instr.Operand is TypeReference)
                                    instr.Operand = mapType((TypeReference)instr.Operand);
                            }
                            foreach (var var in method.Body.Variables)
                                var.VariableType = mapType(var.VariableType);
                            foreach (var amendment in amendments)
                            {
                                amendment();
                            }
                            method.Body = proc.Body;
                        }
                }
            CleanMyVersusMatchResults.PatchModule(baseModule);
            baseModule.Write("TowerFall8Player.exe");
        }

Usage Example

示例#1
0
        static void Main(string[] args)
        {
            //4032F680BFEE01
            byte[] originalPattern = { 0x40, 0x32, 0xF6, 0x80, 0xBF, 0xEE, 0x01 };
            // 90909080BFEE01
            byte[] patchPattern = { 0x90, 0x90, 0x90, 0x80, 0xBF, 0xEE, 0x01 };

            var patcher = new Patcher(@"Bin64\StarCitizen.exe", originalPattern, patchPattern);

            var result = patcher.Find();

            var patched = patcher.Patch(result);

            Console.WriteLine(patched ? "Patched" : "Original");
        }