Example #1
0
        protected void HookConstructionRedirectors <T>(CecilContext cecilContext)
        {
            try
            {
                var test  = FarmhandAssemblies.SelectMany(a => a.GetTypes());
                var types = FarmhandAssemblies.SelectMany(a => a.GetTypesWithCustomAttribute(typeof(T).FullName)).ToArray();

                foreach (var asmType in types)
                {
                    try
                    {
                        RedirectConstructorInMethod(cecilContext, asmType);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error setting protections for {asmType.FullName}: \n\t{ex.Message}");
                    }
                }
            }
            catch (System.Reflection.ReflectionTypeLoadException ex)
            {
                Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}\n\t\t{ex.LoaderExceptions[0].Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}");
            }
        }
Example #2
0
        /// <summary>
        ///     Redirects a constructor.
        /// </summary>
        /// <param name="cecilContext">
        ///     The <see cref="CecilContext" />.
        /// </param>
        /// <param name="asmType">
        ///     The type whose constructor to redirect
        /// </param>
        protected override void RedirectConstructorInMethod(CecilContext cecilContext, Type asmType)
        {
            var attributes =
                asmType.GetCustomAttributes(typeof(HookRedirectConstructorFromBaseAttribute), false)
                .ToList()
                .Cast <HookRedirectConstructorFromBaseAttribute>();

            foreach (var attribute in attributes)
            {
                if (attribute.GenericArguments != null && attribute.GenericArguments.Any())
                {
                    CecilHelper.RedirectConstructorFromBase(
                        cecilContext,
                        asmType,
                        attribute.GenericArguments,
                        attribute.Type,
                        attribute.Method,
                        attribute.Parameters);
                }
                else
                {
                    CecilHelper.RedirectConstructorFromBase(
                        cecilContext,
                        asmType,
                        attribute.Type,
                        attribute.Method,
                        attribute.Parameters);
                }
            }
        }
Example #3
0
        protected void HookMakeBaseVirtualCallAlterations <T>(CecilContext cecilContext)
        {
            try
            {
                var methods = FarmhandAssemblies.SelectMany(a => a.GetMethodsWithCustomAttribute(typeof(T).FullName)).ToArray();

                foreach (var asmMethod in methods)
                {
                    try
                    {
                        SetVirtualCallOnMethod(cecilContext, asmMethod);
                    }
                    catch (Exception ex)
                    {
                        if (asmMethod.DeclaringType != null)
                        {
                            Console.WriteLine($"Error setting protections for {asmMethod.DeclaringType.FullName}.{asmMethod.Name}: \n\t{ex.Message}");
                        }
                    }
                }
            }
            catch (System.Reflection.ReflectionTypeLoadException ex)
            {
                Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}\n\t\t{ex.LoaderExceptions[0].Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}");
            }
        }
Example #4
0
        public static void Patch(CecilContext context, string outputPath)
        {
            TerrariaPatcher.context = context;
            memRes = TerrariaPatcher.context.Resolver;

            TerrariaPatcher.context.PrimaryAssembly.Name.Name       = "Prism.Terraria";
            TerrariaPatcher.context.PrimaryAssembly.MainModule.Name = TerrariaPatcher.context.PrimaryAssembly.Name.Name + ".dll";

            FindPlatform();

            Publicify();
            //AddInternalsVisibleToAttr();
            RemoveConsoleWriteLineInWndProcHook();
            Fix1308AssemblyVersion();

            ItemPatcher.Patch();
            NpcPatcher.Patch();
            ProjectilePatcher.Patch();
            PlayerPatcher.Patch();
            MountPatcher.Patch();
            MainPatcher.Patch();
            WorldFilePatcher.Patch();
            // do other stuff here

            // Newtonsoft.Json.dll, Steamworks.NET.dll and Ionic.Zip.CF.dll are required to write the assembly (and FNA and WindowsBase on mono, too)
            TerrariaPatcher.context.PrimaryAssembly.Write(outputPath);

            memRes = null;
            TerrariaPatcher.context = null;
        }
Example #5
0
 protected void HookApiTypeProtectionAlterations <T>(CecilContext cecilContext)
 {
     try
     {
         var types = FarmhandAssemblies.SelectMany(a => a.GetTypesWithCustomAttribute(typeof(T).FullName)).ToArray();
         foreach (var asmType in types)
         {
             try
             {
                 AlterTypeProtections(cecilContext, asmType);
             }
             catch (Exception ex)
             {
                 Console.WriteLine($"Error setting protections for {asmType.FullName}: \n\t{ex.Message}");
             }
         }
     }
     catch (System.Reflection.ReflectionTypeLoadException ex)
     {
         Console.WriteLine($"Error setting type protections: \n\t{ex.Message}\n\t\t{ex.LoaderExceptions[0].Message}");
     }
     catch (Exception ex)
     {
         Console.WriteLine($"Error setting type protections: \n\t{ex.Message}");
     }
 }
Example #6
0
        public static void HookAllGlobalRouteMethods(CecilContext stardewContext)
        {
            var methods = stardewContext.GetMethods().Where(n => n.DeclaringType.Namespace.StartsWith("StardewValley")).ToArray();

            var ilProcessor2 = stardewContext.GetMethodIlProcessor("Farmhand.Test", "TesttttgetNewID");

            ilProcessor2.Body.SimplifyMacros();


            {
                var listenedMethodField = stardewContext.GetFieldDefinition("Farmhand.Events.GlobalRouteManager", "ListenedMethods");
                var ilProcessor         = stardewContext.GetMethodIlProcessor("Farmhand.Events.GlobalRouteManager", ".cctor");
                var loadInt             = ilProcessor.Create(OpCodes.Ldc_I4, methods.Length);
                var setValue            = ilProcessor.Create(OpCodes.Stsfld, listenedMethodField);
                ilProcessor.InsertAfter(ilProcessor.Body.Instructions[ilProcessor.Body.Instructions.Count - 2], loadInt);
                ilProcessor.InsertAfter(loadInt, setValue);
            }

            for (int i = 0; i < methods.Length; ++i)
            {
                //InjectGlobalRoutePreMethod(stardewContext, methods[i].DeclaringType.FullName, methods[i].Name, i);
                InjectGlobalRoutePostMethod(stardewContext, methods[i].DeclaringType.FullName, methods[i].Name, i);
                InjectMappingInformation(stardewContext, methods[i].DeclaringType.FullName, methods[i].Name, i);
            }
        }
Example #7
0
        // this build file patches Terraria.exe so the Prism assembly can use that as a reference.
        // this program is invoked from the project file, this just executes everything in Prism.Injector.dll.
        // the project is referenced from the main Prism project, so Terraria.exe will be patched before Prism is built.
        static void Main(string[] args)
        {
            // writing to stderr cancels the MSBuild build process (I think)
            if (args.Length != 2)
                Console.Error.WriteLine("Incorrect usage, two arguments required: Terraria.exe path and output assembly path.");

            if (!File.Exists(args[0]))
            {
                Console.Error.WriteLine("Terraria.exe not found. (full path: \"" + args[0] + "\")");
                // the file is added in the .gitignore (and so is the patched file)
                Console.Error.WriteLine("In order to build Prism, one must provide their own Terraria.exe file and put it in the References subdirectory.");
            }

            var c = new CecilContext(args[0]);

            var d = Path.GetDirectoryName(args[1]);
            if (!Directory.Exists(d))
                Directory.CreateDirectory(d);

            // this will stop the build process if the patcher fails, because a reference in Prism.csproj will be missing
            if (File.Exists(args[1]))
                File.Delete(args[1]);

            try
            {
                Patcher.Patch(c, args[1]);
            }
            catch (Exception e)
            {
                Console.Error.WriteLine("Something went wrong while patching " + Path.GetFileName(args[0]) + ".");
                Console.Error.WriteLine(e);
            }
        }
Example #8
0
        public static void AlterProtectionOnType(CecilContext stardewContext, bool isPublic, string typeName)
        {
            var type = stardewContext.GetTypeDefinition(typeName);

            type.IsPublic    = isPublic;
            type.IsNotPublic = !isPublic;
        }
Example #9
0
        public static void RedirectConstructorFromBase(CecilContext stardewContext, Type asmType, string type, string method)
        {
            var test = stardewContext.GetTypeDefinition("StardewValley.SaveGame");

            var newConstructor = asmType.GetConstructor(new Type[] { });

            if (asmType.BaseType == null)
            {
                return;
            }
            var oldConstructor = asmType.BaseType.GetConstructor(new Type[] { });

            if (newConstructor == null)
            {
                return;
            }
            var newConstructorReference = stardewContext.GetMethodDefinition(asmType.FullName, newConstructor.Name);

            if (oldConstructor == null)
            {
                return;
            }
            var oldConstructorReference = stardewContext.GetMethodDefinition(asmType.BaseType.FullName, oldConstructor.Name);

            ILProcessor ilProcessor  = stardewContext.GetMethodIlProcessor(type, method);
            var         instructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Newobj && n.Operand == oldConstructorReference).ToList();

            foreach (var instruction in instructions)
            {
                ilProcessor.Replace(instruction, ilProcessor.Create(OpCodes.Newobj, newConstructorReference));
            }
        }
Example #10
0
        //static void FixNewtonsoftJsonReferenceVersion()
        //{
        //    foreach (var ar in c.PrimaryAssembly.MainModule.AssemblyReferences)
        //        if (ar.Name == "Newtonsoft.Json" && ar.Version == V7_0_0_0)
        //            ar.Version = V4_5_0_0;
        //}
        public static void Patch(CecilContext context, string outputPath)
        {
            c = context;
            r = c.Resolver;

            c.PrimaryAssembly.Name.Name = "Prism.Terraria";
            c.PrimaryAssembly.MainModule.Name = c.PrimaryAssembly.Name.Name + ".dll";

            Publicify();
            //AddInternalsVisibleToAttr();
            //FixNewtonsoftJsonReferenceVersion();

            ItemPatcher      .Patch();
            NpcPatcher       .Patch();
            ProjectilePatcher.Patch();
            PlayerPatcher    .Patch();
            MainPatcher      .Patch();
            // do other stuff here

            // Newtonsoft.Json.dll, Steamworks.NET.dll and Ionic.Zip.CF.dll are required to write the assembly (and FNA and WindowsBase on mono, too)
            c.PrimaryAssembly.Write(outputPath);

            r = null;
            c = null;
        }
Example #11
0
 private static void InjectMethod <TParam, TThis, TInput, TLocal>(CecilContext stardewContext, ILProcessor ilProcessor, IEnumerable <Instruction> targets, MethodReference method, bool isExit = false)
 {
     foreach (var target in targets.ToList())
     {
         InjectMethod <TParam, TThis, TInput, TLocal>(stardewContext, ilProcessor, target, method, isExit);
     }
 }
Example #12
0
        /// <summary>
        ///     Patches the game's executable.
        /// </summary>
        /// <param name="path">Game's executable Path</param>
        public override void PatchStardew(string path = null)
        {
            path = path ?? PatcherConstants.StardewExe;
            Assembly.LoadFrom(path);

            var repackOutput = this.GetAssemblyPath(PatcherConstants.PassOnePackageResult);

            this.InjectFarmhandCoreClasses(
                repackOutput,
                path,
                PatcherConstants.FarmhandDll,
                PatcherConstants.JsonLibrary,
                PatcherConstants.MonoCecilLibrary,
                PatcherConstants.MonoCecilRocksLibrary);

            var cecilContext = new CecilContext(repackOutput, true);

            this.FarmhandAssemblies.Add(Assembly.LoadFrom(this.GetAssemblyPath(PatcherConstants.FarmhandDll)));

            this.HookApiEvents(cecilContext);
            this.HookOutputableApiEvents(cecilContext);
            this.HookApiFieldProtectionAlterations <HookAlterBaseFieldProtectionAttribute>(cecilContext);
            this.HookApiTypeProtectionAlterations <HookAlterProtectionAttribute>(cecilContext);
            this.HookApiVirtualAlterations <HookForceVirtualBaseAttribute>(cecilContext);
            this.HookMakeBaseVirtualCallAlterations <HookMakeBaseVirtualCallAttribute>(cecilContext);
            this.HookConstructionRedirectors <HookRedirectConstructorFromBaseAttribute>(cecilContext);
            this.HookConstructionToMethodRedirectors(cecilContext);

            Console.WriteLine("First Pass Installation Completed");

            cecilContext.WriteAssembly(this.GetAssemblyPath(PatcherConstants.PassOneFarmhandExe), true);
        }
        public override void PatchStardew(string path = null)
        {
            InjectFarmhandCoreClasses(PatcherConstants.PassTwoPackageResult, PatcherConstants.PassOneFarmhandExe, PatcherConstants.FarmhandUiDll, PatcherConstants.FarmhandGameDll, PatcherConstants.FarmhandCharacterDll);
            var cecilContext = new CecilContext(PatcherConstants.PassTwoPackageResult, true);

            FarmhandAssemblies.Add(Assembly.LoadFrom(PatcherConstants.FarmhandUiDll));
            FarmhandAssemblies.Add(Assembly.LoadFrom(PatcherConstants.FarmhandGameDll));
            FarmhandAssemblies.Add(Assembly.LoadFrom(PatcherConstants.FarmhandCharacterDll));

            HookApiEvents(cecilContext);
            HookOutputableApiEvents(cecilContext);
            HookApiFieldProtectionAlterations <HookAlterBaseFieldProtectionAttribute>(cecilContext);
            HookApiTypeProtectionAlterations <HookAlterProtectionAttribute>(cecilContext);
            HookApiVirtualAlterations <HookForceVirtualBaseAttribute>(cecilContext);
            HookMakeBaseVirtualCallAlterations <HookMakeBaseVirtualCallAttribute>(cecilContext);
            HookConstructionRedirectors <HookRedirectConstructorFromBaseAttribute>(cecilContext);
            HookConstructionToMethodRedirectors(cecilContext);

            HookGlobalRouting(cecilContext);

            Console.WriteLine("Second Pass Installation Completed");

            path = path ?? PatcherConstants.FarmhandExe;
            cecilContext.WriteAssembly(path, true);
        }
Example #14
0
        public static void Patch(CecilContext context, string outputPath)
        {
            TerrariaPatcher.context = context;
            memRes = TerrariaPatcher.context.Resolver;

            TerrariaPatcher.context.PrimaryAssembly.Name.Name = "Prism.Terraria";
            TerrariaPatcher.context.PrimaryAssembly.MainModule.Name = TerrariaPatcher.context.PrimaryAssembly.Name.Name + ".dll";

            FindPlatform();

            Publicify();
            //AddInternalsVisibleToAttr();
            RemoveConsoleWriteLineInWndProcHook();
            Fix1308AssemblyVersion();

            ItemPatcher      .Patch();
            NpcPatcher       .Patch();
            ProjectilePatcher.Patch();
            PlayerPatcher    .Patch();
            MountPatcher     .Patch();
            MainPatcher      .Patch();
            WorldFilePatcher .Patch();
            // do other stuff here

            // Newtonsoft.Json.dll, Steamworks.NET.dll and Ionic.Zip.CF.dll are required to write the assembly (and FNA and WindowsBase on mono, too)
            TerrariaPatcher.context.PrimaryAssembly.Write(outputPath);

            memRes = null;
            TerrariaPatcher.context = null;
        }
Example #15
0
        protected void HookApiVirtualAlterations <T>(CecilContext cecilContext)
        {
            try
            {
                var types = FarmhandAssemblies.SelectMany(a => a.GetTypesWithCustomAttribute(typeof(T).FullName)).ToArray();

                foreach (var asmType in types)
                {
                    try
                    {
                        if (asmType.BaseType != null)
                        {
                            CecilHelper.SetVirtualOnBaseMethods(cecilContext, asmType.BaseType.FullName ?? asmType.BaseType.Namespace + "." + asmType.BaseType.Name);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error setting protections for {asmType.FullName}: \n\t{ex.Message}");
                    }
                }
            }
            catch (System.Reflection.ReflectionTypeLoadException ex)
            {
                Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}\n\t\t{ex.LoaderExceptions[0].Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}");
            }
        }
Example #16
0
        public static void InjectEntryMethod <TParam, TThis, TInput, TLocal>(CecilContext stardewContext, string injecteeType, string injecteeMethod,
                                                                             string injectedType, string injectedMethod)
        {
            var methodDefinition = stardewContext.GetMethodDefinition(injectedType, injectedMethod);
            var ilProcessor      = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);

            InjectMethod <TParam, TThis, TInput, TLocal>(ilProcessor, ilProcessor.Body.Instructions.First(), methodDefinition, false, methodDefinition.ReturnType != null && methodDefinition.ReturnType.FullName == typeof(bool).FullName);
        }
Example #17
0
        public static void InjectExitMethod <TParam, TThis, TInput, TLocal>(CecilContext stardewContext, string injecteeType, string injecteeMethod,
                                                                            string injectedType, string injectedMethod)
        {
            var methodDefinition = stardewContext.GetMethodDefinition(injectedType, injectedMethod);
            var ilProcessor      = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);

            InjectMethod <TParam, TThis, TInput, TLocal>(ilProcessor, ilProcessor.Body.Instructions.Where(i => i.OpCode == OpCodes.Ret), methodDefinition, true);
        }
Example #18
0
        public static void HookAllGlobalRouteMethods(CecilContext cecilContext)
        {
            var methods = cecilContext.GetMethods().Where(n => n.DeclaringType.Namespace.StartsWith("StardewValley"));

            foreach (var method in methods)
            {
                InjectGlobalRouteMethod(cecilContext, method.DeclaringType.FullName, method.Name);
            }
        }
        protected override void RedirectConstructorInMethod(CecilContext cecilContext, Type asmType)
        {
            var attributes = asmType.GetCustomAttributes(typeof(HookRedirectConstructorFromBaseAttribute), false).ToList().Cast <HookRedirectConstructorFromBaseAttribute>();

            foreach (var attribute in attributes)
            {
                CecilHelper.RedirectConstructorFromBase(cecilContext, asmType, attribute.Type, attribute.Method);
            }
        }
        protected override void AlterTypeProtections(CecilContext context, Type type)
        {
            var attributeValue = type.GetCustomAttributes(typeof(HookAlterProtectionAttribute), false).First() as HookAlterProtectionAttribute;

            if (type.BaseType != null)
            {
                CecilHelper.AlterProtectionOnType(context, attributeValue != null && attributeValue.Protection == LowestProtection.Public, attributeValue.ClassName);
            }
        }
        protected override void HookConstructionToMethodRedirectors(CecilContext cecilContext)
        {
            var methods = FarmhandAssemblies.SelectMany(a => a.GetTypes())
                          .SelectMany(t => t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
                          .Where(m => m.GetCustomAttributes(typeof(HookRedirectConstructorToMethodAttribute), false).Any())
                          .ToArray();

            foreach (var method in methods)
            {
                // Check if this method has any properties that would immediately disqualify it from using this hook
                if (method.ReturnType == typeof(void))
                {
                    Logging.Log.Warning($"{method.Name} in {method.DeclaringType.FullName} cannot be used in a hook because it does not return a value!");
                    continue;
                }
                if (!method.IsStatic)
                {
                    Logging.Log.Warning($"{method.Name} in {method.DeclaringType.FullName} cannot be used in a hook because it is not static!");
                    continue;
                }

                // Get the type that the method returns
                var typeName = method.ReturnType.FullName;
                // Get the name of the method
                var methodName = method.Name;
                // Get the type name of the method
                var methodDeclaringType = method.DeclaringType.FullName;
                // Get an array of parameters that the method returns
                var    methodParameterInfo = method.GetParameters();
                Type[] methodParamters     = new Type[methodParameterInfo.Length];
                for (int i = 0; i < methodParamters.Length; i++)
                {
                    methodParamters[i] = methodParameterInfo[i].ParameterType;
                }

                // Get all the hooks for this method
                var hookAttributes = method.GetCustomAttributes(typeof(HookRedirectConstructorToMethodAttribute), false).Cast <HookRedirectConstructorToMethodAttribute>();

                foreach (var hook in hookAttributes)
                {
                    // Get the type name that contains the method we're hooking in
                    var hookTypeName = hook.Type;
                    // Get the name of the method we're hooking in
                    var hookMethodName = hook.Method;
                    try
                    {
                        CecilHelper.RedirectConstructorToMethod(cecilContext, method.ReturnType, hookTypeName, hookMethodName, methodDeclaringType, methodName, methodParamters);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Failed to Inject {typeName}.{methodName} into {hookTypeName}.{hookMethodName}\n\t{ex.Message}");
                        throw ex;
                    }
                }
            }
        }
Example #22
0
        public static MethodDefinition[] GetMethods(this TypeDefinition type, CecilContext context, string name, MethodFlags flags = MethodFlags.All, params Type         [] arguments)
        {
            return GetMethods(type, name, flags, arguments.Select(t =>
            {
                if (context.Comparer.AssemblyEquals(type.Module.Assembly, t.Assembly))
                    return context.Resolver.GetType(t);

                return context.PrimaryAssembly.MainModule.Import(t);
            }).ToArray());
        }
Example #23
0
        internal static void Patch()
        {
            c = TerrariaPatcher.c;
            r = TerrariaPatcher.r;

            ts = c.PrimaryAssembly.MainModule.TypeSystem;
            player_t = r.GetType("Terraria.Player");

            RemoveBuggyPlayerLoading();
        }
Example #24
0
        public static void RedirectConstructorFromBase(CecilContext stardewContext, Type asmType, string type, string method, Type[] parameters)
        {
            string parametersString = "";

            for (int i = 0; i < parameters.Length; i++)
            {
                if (parameters[i].FullName.Contains("`"))
                {
                    parametersString += ConvertGenericTypeFullNameToGenericTypeParameterFormat(parameters[i].FullName);
                }
                else
                {
                    parametersString += parameters[i].FullName;
                }

                if (i != parameters.Length - 1)
                {
                    parametersString += ",";
                }
            }

            var newConstructor = asmType.GetConstructor(parameters);

            if (asmType.BaseType == null)
            {
                return;
            }
            var oldConstructor = asmType.BaseType.GetConstructor(parameters);

            if (newConstructor == null)
            {
                return;
            }
            // Build a FullName version of newConstructor.Name
            string newConstructorFullName  = "System.Void " + asmType.FullName + "::.ctor" + "(" + parametersString + ")";
            var    newConstructorReference = stardewContext.GetMethodDefinitionFullName(asmType.FullName, newConstructorFullName);

            if (oldConstructor == null)
            {
                return;
            }
            // Build a FullName version of oldConstructor.Name
            string oldConstructorFullName  = "System.Void " + asmType.BaseType.FullName + "::.ctor" + "(" + parametersString + ")";
            var    oldConstructorReference = stardewContext.GetMethodDefinitionFullName(asmType.BaseType.FullName ?? asmType.BaseType.Namespace + "." + asmType.BaseType.Name, oldConstructorFullName);


            ILProcessor ilProcessor = stardewContext.GetMethodIlProcessor(type, method);

            var instructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Newobj && n.Operand == oldConstructorReference).ToList();

            foreach (var instruction in instructions)
            {
                ilProcessor.Replace(instruction, ilProcessor.Create(OpCodes.Newobj, newConstructorReference));
            }
        }
Example #25
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes = TerrariaPatcher.memRes;

            typeSys = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_Proj = memRes.GetType("Terraria.Projectile");

            WrapMethods();
            AddFieldForBHandler();
        }
Example #26
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes  = TerrariaPatcher.memRes;

            typeSys = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_WorldFile = memRes.GetType("Terraria.IO.WorldFile");

            InjectSaveHook();
            InjectLoadHook();
        }
Example #27
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes  = TerrariaPatcher.memRes;

            typeSys           = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_WorldFile = memRes.GetType("Terraria.IO.WorldFile");

            InjectSaveHook();
            InjectLoadHook();
        }
Example #28
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes  = TerrariaPatcher.memRes;

            typeSys      = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_Proj = memRes.GetType("Terraria.Projectile");

            WrapMethods();
            AddFieldForBHandler();
        }
Example #29
0
 private void HookGlobalRouting(CecilContext cecilContext)
 {
     if (!this.Options.DisableGrm)
     {
         CecilHelper.HookAllGlobalRouteMethods(cecilContext);
     }
     else
     {
         Console.WriteLine("Skipping GRM injection");
     }
 }
        private void HookOutputableApiEvents(CecilContext cecilContext)
        {
            try
            {
                var methods = FarmhandAssemblies.SelectMany(a => a.GetTypes())
                              .SelectMany(t => t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
                              .Where(m => m.GetCustomAttributes(typeof(HookReturnableAttribute), false).Any())
                              .ToArray();

                foreach (var method in methods)
                {
                    if (method.DeclaringType == null)
                    {
                        continue;
                    }

                    var typeName       = method.DeclaringType.FullName;
                    var methodName     = method.Name;
                    var hookAttributes = method.GetCustomAttributes(typeof(HookReturnableAttribute), false).Cast <HookReturnableAttribute>();

                    foreach (var hook in hookAttributes)
                    {
                        var hookTypeName   = hook.Type;
                        var hookMethodName = hook.Method;
                        try
                        {
                            switch (hook.HookType)
                            {
                            case HookType.Entry:
                                CecilHelper.InjectReturnableEntryMethod <ParameterBindAttribute, ThisBindAttribute, InputBindAttribute, LocalBindAttribute,
                                                                         UseOutputBindAttribute, MethodOutputBindAttribute>
                                    (cecilContext, hookTypeName, hookMethodName, typeName, methodName); break;

                            case HookType.Exit:
                                CecilHelper.InjectReturnableExitMethod <ParameterBindAttribute, ThisBindAttribute, InputBindAttribute, LocalBindAttribute,
                                                                        UseOutputBindAttribute, MethodOutputBindAttribute>
                                    (cecilContext, hookTypeName, hookMethodName, typeName, methodName); break;

                            default:
                                throw new Exception("Unknown HookType");
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"Failed to Inject {typeName}.{methodName} into {hookTypeName}.{hookMethodName}\n\t{ex.Message}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
Example #31
0
        internal static void Patch()
        {
            c = TerrariaPatcher.c;
            r = TerrariaPatcher.r;

            ts = c.PrimaryAssembly.MainModule.TypeSystem;
            npc_t = r.GetType("Terraria.NPC");

            WrapSetDefaults();
            AddFieldForBHandler();
        }
        protected override void SetVirtualCallOnMethod(CecilContext cecilContext, MethodInfo asmMethod)
        {
            var attributes = asmMethod.GetCustomAttributes(typeof(HookMakeBaseVirtualCallAttribute), false).ToList().Cast <HookMakeBaseVirtualCallAttribute>();

            foreach (var attribute in attributes.Where(attribute => asmMethod.DeclaringType?.BaseType != null))
            {
                if (asmMethod.DeclaringType?.BaseType != null)
                {
                    CecilHelper.SetVirtualCallOnMethod(cecilContext, asmMethod.DeclaringType.BaseType.FullName, asmMethod.Name, attribute.Type, attribute.Method);
                }
            }
        }
Example #33
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes = TerrariaPatcher.memRes;

            typeSys = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_Item = memRes.GetType("Terraria.Item");

            WrapSetDefaults();
            AddFieldForBHandler();
            AddFieldForSound();
        }
Example #34
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes  = TerrariaPatcher.memRes;

            typeSys      = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_Item = memRes.GetType("Terraria.Item");

            WrapSetDefaults();
            AddFieldForBHandler();
            AddFieldForSound();
        }
Example #35
0
        public static void SetVirtualCallOnMethod(CecilContext cecilContext, string fullName, string name, string type, string method)
        {
            MethodDefinition methodDefinition = cecilContext.GetMethodDefinition(fullName, name);
            ILProcessor      ilProcessor      = cecilContext.GetMethodIlProcessor(type, method);

            var instructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Call && n.Operand == methodDefinition).ToList();

            foreach (var instruction in instructions)
            {
                ilProcessor.Replace(instruction, ilProcessor.Create(OpCodes.Callvirt, methodDefinition));
            }
        }
Example #36
0
        internal static void Patch()
        {
            c = TerrariaPatcher.c;
            r = TerrariaPatcher.r;

            ts = c.PrimaryAssembly.MainModule.TypeSystem;
            main_t = r.GetType("Terraria.Main");

            RemoveNetModeCheckFromChat();
            RemoveVanillaNpcDrawLimitation();
            InsertMusicHook();
        }
Example #37
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes = TerrariaPatcher.memRes;

            typeSys = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_Mount = memRes.GetType("Terraria.Mount");

            WrapMethods();
            AddFieldForBHandler();
            Remove_FromFields();
            RemoveTypeLimitations();
        }
Example #38
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes  = TerrariaPatcher.memRes;

            typeSys       = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_Mount = memRes.GetType("Terraria.Mount");

            WrapMethods();
            AddFieldForBHandler();
            Remove_FromFields();
            RemoveTypeLimitations();
        }
Example #39
0
        public static void ReplaceAllMethodRefs(CecilContext c, MethodReference tar, MethodReference @new)
        {
            foreach (TypeDefinition t in c.PrimaryAssembly.MainModule.Types)
                foreach (MethodDefinition m in t.Methods)
                {
                    if (!m.HasBody) // abstract, runtime & external, etc
                        continue;

                    foreach (Instruction i in m.Body.Instructions)
                        if (i.Operand == tar)
                            i.Operand = @new;
                }
        }
Example #40
0
        public static void AlterProtectionOnTypeMembers(CecilContext stardewContext, bool @public, string typeName)
        {
            var type = stardewContext.GetTypeDefinition(typeName);

            if (type.HasMethods)
            {
                foreach (MethodDefinition method in type.Methods)
                {
                    if (!@public)
                    {
                        if (method.IsPrivate)
                        {
                            method.IsPrivate = false;
                            method.IsFamily  = true;
                        }
                    }
                    else
                    {
                        if (method.IsPrivate || method.IsFamily)
                        {
                            method.IsPrivate = false;
                            method.IsPublic  = false;
                        }
                    }
                }
            }

            if (type.HasFields)
            {
                foreach (FieldDefinition field in type.Fields)
                {
                    if (!@public)
                    {
                        if (field.IsPrivate)
                        {
                            field.IsPrivate = false;
                            field.IsFamily  = true;
                        }
                    }
                    else
                    {
                        if (field.IsPrivate || field.IsFamily)
                        {
                            field.IsPrivate = false;
                            field.IsPublic  = false;
                        }
                    }
                }
            }
        }
Example #41
0
        public static void RedirectConstructorToMethod(CecilContext stardewContext, Type asmType, string type, string method, string methodType, string methodName, Type[] parameters)
        {
            // Get a single string containing the full names of all parameters, comma separated
            string parametersString = "";

            for (int i = 0; i < parameters.Length; i++)
            {
                parametersString += parameters[i].FullName;
                if (i != parameters.Length - 1)
                {
                    parametersString += ",";
                }
            }

            if (asmType == null)
            {
                return;
            }
            var oldConstructor = asmType.GetConstructor(parameters);

            if (oldConstructor == null)
            {
                return;
            }
            // Build a FullName version of oldConstructor.Name
            string oldConstructorFullName  = "System.Void " + asmType.FullName + "::.ctor" + "(" + parametersString + ")";
            var    oldConstructorReference = stardewContext.GetMethodDefinitionFullName(asmType.FullName ?? asmType.Namespace + "." + asmType.Name, oldConstructorFullName);

            // Build a FullName version of the new method
            string methodFullName = $"{asmType} {methodType}::{methodName}({parametersString})";
            var    newMethod      = stardewContext.GetMethodDefinitionFullName(methodType, methodFullName);

            if (newMethod == null)
            {
                return;
            }

            ILProcessor ilProcessor = stardewContext.GetMethodIlProcessor(type, method);

            var instructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Newobj && n.Operand == oldConstructorReference).ToList();

            foreach (var instruction in instructions)
            {
                ilProcessor.Body.SimplifyMacros();
                ilProcessor.Replace(instruction, ilProcessor.Call(newMethod));
                ilProcessor.Body.OptimizeMacros();
            }
        }
Example #42
0
        /// <summary>
        /// Replaces all method references with the specified reference within the specified context.
        /// </summary>
        /// <param name="context">The current <see cref="CecilContext"/>.</param>
        /// <param name="targetRef">The <see cref="MethodReference"/> to replace.</param>
        /// <param name="newRef">The <see cref="MethodReference"/> to replace targetRef with.</param>
        /// <param name="exitRecursion">Excludes recursive method calls from the replacement operation (may have undesired consequences with recursive methods).</param>
        public static void ReplaceAllMethodRefs(this MethodReference targetRef, MethodReference newRef, CecilContext context, bool exitRecursion = true)
        {
            foreach (TypeDefinition tDef in context.PrimaryAssembly.MainModule.Types)
                foreach (MethodDefinition mDef in tDef.Methods)
                {
                    if (!mDef.HasBody) // abstract, runtime & external, etc
                        continue;

                    if (exitRecursion && mDef == newRef) // may have undesired consequences with recursive methods
                        continue;

                    foreach (Instruction i in mDef.Body.Instructions)
                        if (i.Operand == targetRef)
                            i.Operand = newRef;
                }
        }
Example #43
0
        public static TypeDefinition CreateDelegate(this CecilContext context, string @namespace, string name, TypeReference returnType, out MethodDefinition invoke, params TypeReference[] parameters)
        {
            var cResolver = context.Resolver;
            var typeSys   = context.PrimaryAssembly.MainModule.TypeSystem;

            var delegateType = new TypeDefinition(@namespace, name, TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Sealed, cResolver.ReferenceOf(typeof(MulticastDelegate)));

            var ctor = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, typeSys.Void);

            ctor.IsRuntime = true;
            ctor.Parameters.Add(new ParameterDefinition("object", 0, typeSys.Object));
            ctor.Parameters.Add(new ParameterDefinition("method", 0, typeSys.IntPtr));

            delegateType.Methods.Add(ctor);

            invoke           = new MethodDefinition("Invoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, returnType);
            invoke.IsRuntime = true;
            for (int i = 0; i < parameters.Length; i++)
            {
                invoke.Parameters.Add(new ParameterDefinition("arg" + i, 0, parameters[i]));
            }

            delegateType.Methods.Add(invoke);

            var beginInvoke = new MethodDefinition("BeginInvoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, cResolver.ReferenceOf(typeof(IAsyncResult)));

            beginInvoke.IsRuntime = true;
            for (int i = 0; i < parameters.Length; i++)
            {
                beginInvoke.Parameters.Add(new ParameterDefinition("arg" + i, 0, parameters[i]));
            }
            beginInvoke.Parameters.Add(new ParameterDefinition("callback", 0, cResolver.ReferenceOf(typeof(AsyncCallback))));
            beginInvoke.Parameters.Add(new ParameterDefinition("object", 0, typeSys.Object));

            delegateType.Methods.Add(beginInvoke);

            var endInvoke = new MethodDefinition("EndInvoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, typeSys.Void);

            endInvoke.IsRuntime = true;
            endInvoke.Parameters.Add(new ParameterDefinition("result", 0, cResolver.ReferenceOf(typeof(IAsyncResult))));

            delegateType.Methods.Add(endInvoke);

            context.PrimaryAssembly.MainModule.Types.Add(delegateType);

            return(delegateType);
        }
Example #44
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes  = TerrariaPatcher.memRes;

            typeSys = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_Player = memRes.GetType("Terraria.Player");

            WrapMethods();
            AddFieldForBHandler();
            InsertSaveLoadHooks();
            RemoveBuggyPlayerLoading();
            ReplaceUseSoundCalls();
            FixOnEnterWorldField();
            InjectMidUpdate();
            InitBuffBHandlerArray();
        }
Example #45
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes = TerrariaPatcher.memRes;

            typeSys = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_Main = memRes.GetType("Terraria.Main");

            WrapMethods();
            RemoveVanillaNpcDrawLimitation();
            FixOnEngineLoadField();
            RemoveArmourDrawLimitations();
            AddOnUpdateKeyboardHook();

            //These are causing System.InvalidProgramExceptions so I'm just commenting them out (pls don't remove them)
            //AddIsChatAllowedHook();
            //AddLocalChatHook();
        }
Example #46
0
        internal static void Patch()
        {
            context = TerrariaPatcher.context;
            memRes = TerrariaPatcher.memRes;

            typeSys = context.PrimaryAssembly.MainModule.TypeSystem;
            typeDef_NPC = memRes.GetType("Terraria.NPC" );

            WrapMethods();

            AddFieldForBHandler();
            AddFieldsForAudio();

            InsertInitialize();
            ReplaceSoundHitCalls();
            ReplaceSoundKilledCalls();
            InjectBuffEffectsCall();
            InitBuffBHandlerArray();
        }
Example #47
0
        public static TypeDefinition CreateDelegate(CecilContext c, string ns, string name, TypeReference returnType, out MethodDefinition invoke, params TypeReference[] parameters)
        {
            var r = c.Resolver;
            var ts = c.PrimaryAssembly.MainModule.TypeSystem;

            var ret = new TypeDefinition(ns, name, TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Sealed, r.ReferenceOf(typeof(MulticastDelegate)));

            var ctor = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, ts.Void);
            ctor.IsRuntime = true;
            ctor.Parameters.Add(new ParameterDefinition("object", 0, ts.Object));
            ctor.Parameters.Add(new ParameterDefinition("method", 0, ts.IntPtr));

            ret.Methods.Add(ctor);

            invoke = new MethodDefinition("Invoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, ts.Void);
            invoke.IsRuntime = true;
            for (int i = 0; i < parameters.Length; i++)
                invoke.Parameters.Add(new ParameterDefinition("arg" + i, 0, parameters[i]));

            ret.Methods.Add(invoke);

            var beginInvoke = new MethodDefinition("BeginInvoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, r.ReferenceOf(typeof(IAsyncResult)));
            beginInvoke.IsRuntime = true;
            for (int i = 0; i < parameters.Length; i++)
                beginInvoke.Parameters.Add(new ParameterDefinition("arg" + i, 0, parameters[i]));
            beginInvoke.Parameters.Add(new ParameterDefinition("callback", 0, r.ReferenceOf(typeof(AsyncCallback))));
            beginInvoke.Parameters.Add(new ParameterDefinition("object", 0, ts.Object));

            ret.Methods.Add(beginInvoke);

            var endInvoke = new MethodDefinition("EndInvoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, ts.Void);
            endInvoke.IsRuntime = true;
            endInvoke.Parameters.Add(new ParameterDefinition("result", 0, r.ReferenceOf(typeof(IAsyncResult))));

            ret.Methods.Add(endInvoke);

            c.PrimaryAssembly.MainModule.Types.Add(ret);

            return ret;
        }
Example #48
0
        static int Main(string[] args)
        {
            var toRem = new List<string>();

            try
            {
                if (!ParseRuntimeArgs(args))
                    return 1;

                if (MsBuild)
                    Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

                if (!File.Exists(TerrariaExecutable))
                {
                    Console.WriteLine("Terraria.exe not found. (full path: \"" + Path.GetFullPath(TerrariaExecutable) + "\")");
                    // the file is added in the .gitignore (and so is the patched file)
                    if (MsBuild)
                        Console.WriteLine("In order to build Prism, you must place a copy of your own Terraria.exe file in the '."
                            + Path.DirectorySeparatorChar /* be cross-platform */ + "References' directory.");

                    return 1;
                }

                var d = Path.GetDirectoryName(TerrariaExecutable);

                // just copy the files so the assembly resolving works, they'll be removed when it finished
                if (!MsBuild)
                {
                    var  fs = new[] { "Newtonsoft.Json", "Steamworks.NET", "Ionic.Zip.CF" }.Select(n => Path.Combine(d, n + ".dll"));
                    var ufs = new[] { "WindowsBase"    , "FNA"                            }.Select(n => Path.Combine(d, n + ".dll"));

                    foreach (var s in fs.Concat(IsWindows ? new string[0] : ufs))
                    {
                        var t = Path.Combine(Environment.CurrentDirectory, Path.GetFileName(s));

                        if (File.Exists(s) && !File.Exists(t) /* don't do a useless copy (and worse, remove it afterwards, even when it could be needed later) */)
                        {
                            File.Copy(s, t);
                            toRem.Add(t);
                        }
                    }
                }

                var c = new CecilContext(TerrariaExecutable);

                d = Path.GetDirectoryName(PrismAssembly);
                if (!Directory.Exists(d))
                    Directory.CreateDirectory(d);

                // this will stop the build process if the patcher fails, because a reference in Prism.csproj will be missing
                if (MsBuild && File.Exists(PrismAssembly))
                    File.Delete(PrismAssembly);

                try
                {
                    Console.Write("Patching, please wait... ");

                    Patcher.Patch(c, PrismAssembly);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Something went wrong while patching " + Path.GetFileName(TerrariaExecutable) + ":");
                    Console.WriteLine(e);

                    return 1;
                }

                Console.WriteLine("Patching finished.");

                return 0;
            }
            finally
            {
                if (!MsBuild)
                {
                    Console.WriteLine("Press any key to exit...");
                    Console.ReadKey(true);
                }

                foreach (var s in toRem)
                    File.Delete(s);
            }
        }
Example #49
0
 public static void Load()
 {
     c = new CecilContext("Terraria.exe");
     r = c.Resolver; // this contains a lot of useful methods
 }
Example #50
0
        static void Main(string[] args)
        {
            if (!ParseRuntimeArgs(args))
            {
                return;
            }

            if (!File.Exists(TerrariaExecutable))
            {
                Console.Error.WriteLine("Terraria.exe not found. (full path: \"" + TerrariaExecutable + "\")");
                // the file is added in the .gitignore (and so is the patched file)
                if (VsBuild)
                    Console.Error.WriteLine(@"In order to build Prism, you must place a copy of your own Terraria.exe file in the '.\References' directory.");
            }

            var c = new CecilContext(TerrariaExecutable);

            var d = Path.GetDirectoryName(PrismAssembly);
            if (!Directory.Exists(d))
                Directory.CreateDirectory(d);

            // this will stop the build process if the patcher fails, because a reference in Prism.csproj will be missing
            if (File.Exists(PrismAssembly))
                File.Delete(PrismAssembly);

            try
            {
                Patcher.Patch(c, PrismAssembly);
            }
            catch (Exception e)
            {
                Console.Error.WriteLine("Something went wrong while patching " + Path.GetFileName(TerrariaExecutable) + ".");
                Console.Error.WriteLine(e);
            }
        }
Example #51
0
        /// <summary>
        /// Wraps a method using a fancy delegate. Replaces all references of the method with the wrapped one and creates an "On[MethodName]" hook which passes the method's parent type followed by the type parameters of the original method.
        /// </summary>
        /// <param name="context">The current Cecil context.</param>
        /// <param name="delegateNS">The namespace of the delegate type to create.</param>
        /// <param name="delegateTypeName">The name of the delegate type to create.</param>
        /// <param name="origMethod">The method to wrap.</param>
        public static void Wrap(this MethodDefinition origMethod, CecilContext context, string delegateNS, string delegateTypeName, string fieldName)
        {
            MethodDefinition invokeDelegate;

            SingletonTRArr[0] = origMethod.DeclaringType;

            //If anyone knows a better way to insert one element at the beginning of an array and scoot
            //all the other elements down one index then go ahead and do it lol. I dunno how2array.
            var delegateArgs = (origMethod.IsStatic ? EmptyTRArr : SingletonTRArr).Concat(origMethod.Parameters.Select(p => p.ParameterType)).ToArray();

            var newDelegateType = context.CreateDelegate(delegateNS, delegateTypeName, origMethod.ReturnType, out invokeDelegate, delegateArgs);

            var newMethod = origMethod.ReplaceAndHook(invokeDelegate, origMethod, fieldName);

            origMethod.ReplaceAllMethodRefs(newMethod, context);
        }
Example #52
0
 /// <summary>
 /// Wraps a method using a fancy delegate. Replaces all references of the method with the wrapped one and creates an "On[MethodName]" hook which passes the method's parent type followed by the type parameters of the original method.
 /// </summary>
 /// <param name="context">The current Cecil context.</param>
 /// <param name="origMethod">The method to wrap.</param>
 public static void Wrap(this MethodDefinition method, CecilContext context)
 {
     var delTypeName = DefDelTypeName(method);
     method.Wrap(context, delTypeName[0], delTypeName[1], "P_On" + GetOverloadedName(method));
 }
Example #53
0
 public CecilReflectionComparer(CecilContext context)
 {
     c_wr = new WeakReference(context);
 }
Example #54
0
 public static MethodDefinition GetMethod(this TypeDefinition type, CecilContext context, string name, MethodFlags flags = MethodFlags.All, params Type         [] arguments)
 {
     return GetMethods(type, context, name, flags, arguments).FirstOrDefault();
 }