示例#1
0
        public void TestMethod5()
        {
            var originalClass = typeof(Class5);

            Assert.IsNotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method5");

            Assert.IsNotNull(originalMethod);

            var patchClass = typeof(Class5Patch);
            var prefix     = patchClass.GetMethod("Prefix");

            Assert.IsNotNull(prefix);
            var postfix = patchClass.GetMethod("Postfix");

            Assert.IsNotNull(postfix);

            Class5Patch.ResetTest();

            var instance = new Harmony("test");

            Assert.IsNotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.IsNotNull(patcher);
            patcher.AddPrefix(prefix);
            patcher.AddPostfix(postfix);
            patcher.Patch();

            (new Class5()).Method5("foo");
            Assert.IsTrue(Class5Patch.prefixed, "Prefix was not executed");
            Assert.IsTrue(Class5Patch.postfixed, "Prefix was not executed");
        }
示例#2
0
        public void TestPatchUnpatch()
        {
            var originalClass = typeof(Class9);

            Assert.IsNotNull(originalClass);
            var originalMethod = originalClass.GetMethod("ToString");

            Assert.IsNotNull(originalMethod);

            var patchClass = typeof(Class9Patch);
            var prefix     = patchClass.GetMethod("Prefix");

            Assert.IsNotNull(prefix);
            var postfix = patchClass.GetMethod("Postfix");

            Assert.IsNotNull(postfix);

            var instance = new Harmony("test");

            Assert.IsNotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.IsNotNull(patcher);
            patcher.AddPrefix(prefix);
            patcher.AddPostfix(postfix);
            patcher.Patch();

            var instanceB = new Harmony("test");

            Assert.IsNotNull(instanceB);

            instanceB.UnpatchAll("test");
        }
示例#3
0
        public void Test_InjectingBaseClassField()
        {
            var testInstance = new InjectFieldSubClass();

            testInstance.Method("foo");
            Assert.AreEqual("foo", testInstance.TestValue);

            var originalClass = testInstance.GetType();

            Assert.NotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method");

            Assert.NotNull(originalMethod);

            var patchClass = typeof(InjectFieldSubClass_Patch);
            var postfix    = patchClass.GetMethod("Postfix");

            Assert.NotNull(postfix);

            var instance = new Harmony("test");

            Assert.NotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.NotNull(patcher);
            _ = patcher.AddPostfix(postfix);
            Assert.NotNull(patcher);

            _ = patcher.Patch();

            testInstance.Method("bar");
            Assert.AreEqual("patched", testInstance.TestValue);
        }
示例#4
0
        public void TestMethod0()
        {
            var originalClass = typeof(Class0);

            Assert.IsNotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method0");

            Assert.IsNotNull(originalMethod);

            var patchClass = typeof(Class0Patch);
            var postfix    = patchClass.GetMethod("Postfix");

            Assert.IsNotNull(postfix);

            var instance = new Harmony("test");

            Assert.IsNotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.IsNotNull(patcher);
            patcher.AddPostfix(postfix);
            patcher.Patch();

            var result = new Class0().Method0();

            Assert.AreEqual("patched", result);
        }
示例#5
0
        public void Test_Method7()
        {
            var originalClass = typeof(Class7);

            Assert.NotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method7");

            Assert.NotNull(originalMethod);

            var patchClass = typeof(Class7Patch);
            var postfix    = patchClass.GetMethod("Postfix");

            Assert.NotNull(postfix);

            var instance = new Harmony("test");

            Assert.NotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.NotNull(patcher);
            _ = patcher.AddPostfix(postfix);

            _ = patcher.Patch();

            var instance7 = new Class7();
            var result    = instance7.Method7("parameter");

            Assert.AreEqual("parameter", instance7.state1);
            Assert.AreEqual(10, result.a);
            Assert.AreEqual(20, result.b);
        }
示例#6
0
        public void TestMethod10()
        {
            var originalClass = typeof(Class10);

            Assert.IsNotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method10");

            Assert.IsNotNull(originalMethod);

            var patchClass = typeof(Class10Patch);
            var postfix    = patchClass.GetMethod("Postfix");

            Assert.IsNotNull(postfix);

            var instance = new Harmony("test");

            Assert.IsNotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.IsNotNull(patcher);
            patcher.AddPostfix(postfix);
            patcher.Patch();

            new Class10().Method10();
            Assert.IsTrue(Class10Patch.postfixed);
            Assert.IsTrue(Class10Patch.originalResult);
        }
示例#7
0
        public void Test_Method8()
        {
            var originalClass = typeof(Class8);

            Assert.NotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method8");

            Assert.NotNull(originalMethod);

            var patchClass = typeof(Class8Patch);
            var postfix    = patchClass.GetMethod("Postfix");

            Assert.NotNull(postfix);

            var instance = new Harmony("test");

            Assert.NotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.NotNull(patcher);
            _ = patcher.AddPostfix(postfix);
            Assert.NotNull(patcher);

            _ = patcher.Patch();

            var result = Class8.Method8("patched");

            Assert.True(Class8.mainRun);
            Assert.AreEqual(10, result.a);
            Assert.AreEqual(20, result.b);
        }
示例#8
0
 public static ProcessorInfo Create(Harmony instance, MethodBase original)
 {
     return(new ProcessorInfo {
         instance = instance,
         original = original,
         processor = instance.CreateProcessor(original)
     });
 }
示例#9
0
        public void TestMethod1()
        {
            var originalClass = typeof(Class1);

            Assert.IsNotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method1");

            Assert.IsNotNull(originalMethod);

            var patchClass = typeof(Class1Patch);
            var prefix     = patchClass.GetMethod("Prefix");
            var postfix    = patchClass.GetMethod("Postfix");
            var transpiler = patchClass.GetMethod("Transpiler");

            Assert.IsNotNull(prefix);
            Assert.IsNotNull(postfix);
            Assert.IsNotNull(transpiler);

            Class1Patch.ResetTest();

            var instance = new Harmony("test");

            Assert.IsNotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.IsNotNull(patcher);
            patcher.AddPrefix(prefix);
            patcher.AddPostfix(postfix);
            patcher.AddTranspiler(transpiler);

            var originalMethodStartPre = Memory.GetMethodStart(originalMethod, out _);

            patcher.Patch();
            var originalMethodStartPost = Memory.GetMethodStart(originalMethod, out _);

            Assert.AreEqual(originalMethodStartPre, originalMethodStartPost);
            unsafe
            {
                var patchedCode = *(byte *)originalMethodStartPre;
                if (IntPtr.Size == sizeof(long))
                {
                    Assert.IsTrue(patchedCode == 0x48);
                }
                else
                {
                    Assert.IsTrue(patchedCode == 0x68);
                }
            }

            Class1.Method1();
            Assert.IsTrue(Class1Patch.prefixed, "Prefix was not executed");
            Assert.IsTrue(Class1Patch.originalExecuted, "Original was not executed");
            Assert.IsTrue(Class1Patch.postfixed, "Postfix was not executed");
        }
示例#10
0
        public static void Patch()
        {
            var testMethod   = TestContext.CurrentContext.Test.Name;
            var parts        = testMethod.Split('_');
            var originalType = AccessTools.TypeByName("HarmonyLibTests.Assets." + parts[1]);
            var patchType    = AccessTools.TypeByName("HarmonyLibTests.Assets." + parts[2]);

            Assert.NotNull(originalType, nameof(originalType));
            var originalMethod = originalType.GetMethod("Method");

            Assert.NotNull(originalMethod, nameof(originalMethod));

            Assert.NotNull(patchType, nameof(patchType));
            var finalizer = patchType.GetMethod("Finalizer");

            Assert.NotNull(finalizer, nameof(finalizer));

            var instance = new Harmony("finalizer-test");

            instance.UnpatchAll("finalizer-test");
            var patcher = instance.CreateProcessor(originalMethod);

            Assert.NotNull(patcher, nameof(patcher));
            _ = patcher.AddFinalizer(finalizer);
            _ = patcher.Patch();

            var trv = Traverse.Create(patchType);

            _ = trv.Field("finalized").SetValue(false);
            _ = trv.Field("exception").SetValue(new NullReferenceException("replace-me"));

            var obj      = Activator.CreateInstance(originalType);
            var m_method = AccessTools.Method(originalType, "Method");

            Assert.NotNull(m_method, nameof(m_method));
            info = new Dictionary <string, object>();
            try
            {
                if (m_method.ReturnType == typeof(void))
                {
                    _ = m_method.Invoke(obj, null);
                }
                else
                {
                    info["result"] = m_method.Invoke(obj, new object[0]);
                }
                info["outerexception"] = null;
            }
            catch (TargetInvocationException e)
            {
                info["outerexception"] = e.InnerException;
            }
            trv.Fields().ForEach(name => info[name] = trv.Field(name).GetValue());
            Assert.True((bool)info["finalized"], "Finalizer not called");
        }
示例#11
0
        public void Test_GenericsOriginalMethod()
        {
            var originalMethod = typeof(Class13 <int>).GetMethod(nameof(Class13 <int> .Add));

            Assert.NotNull(originalMethod);

            var patchClass = typeof(Class13Patch);
            var prefix     = patchClass.GetMethod("Prefix");

            Assert.NotNull(prefix);

            var list1 = new Class13 <int> {
                1, 2, 3
            };

            list1.Add(1000);
            var e1 = list1.GetEnumerator();

            _ = e1.MoveNext();
            _ = e1.MoveNext();
            _ = e1.MoveNext();
            _ = e1.MoveNext();
            Assert.AreEqual(1000, e1.Current);

            var instance = new Harmony("test");

            Assert.NotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.NotNull(patcher);
            _ = patcher.AddPrefix(prefix);
            _ = patcher.Patch();

            Class13Patch.method = null;
            Class13Patch.result = 0;

            var list2 = new Class13 <int> {
                1, 2, 3
            };

            list2.Add(1000);
            var e2 = list2.GetEnumerator();

            _ = e2.MoveNext();
            _ = e2.MoveNext();
            _ = e2.MoveNext();
            _ = e2.MoveNext();
            Assert.AreEqual(999, e2.Current);

            Assert.AreEqual(1000, Class13Patch.result);
            Assert.AreEqual(originalMethod, Class13Patch.method);
        }
示例#12
0
        public override void LoadPlugin()
        {
            base.LoadPlugin();
            HarmonyInstance = new Harmony("PlayerIPPatch");
            Logger.Log("Player IP Patch by ShimmyMySherbet (great job nelson!)");
            Logger.Log("Patching IP Methods...");
            MethodInfo     PatchBase = typeof(SteamGameServerNetworking).GetMethod("GetP2PSessionState");
            PatchProcessor Processor = HarmonyInstance.CreateProcessor(PatchBase);

            Processor.AddPostfix(new HarmonyMethod(typeof(PlayerIPPatch).GetMethod("PostFixObj")));
            Processor.Patch();
            Logger.Log("Patched!");
        }
示例#13
0
        public override void LoadPlugin()
        {
            base.LoadPlugin();
            Harmony = new Harmony("PluginPerformanceProfiler");
            MethodInfo EStart  = typeof(PluginPerformanceProfiler).GetMethod("OnExcecuteStart", BindingFlags.Public | BindingFlags.Static);
            MethodInfo EEnd    = typeof(PluginPerformanceProfiler).GetMethod("OnExcecuteEnd", BindingFlags.Public | BindingFlags.Static);
            MethodInfo E       = typeof(RocketCommandManager).GetMethod("Execute", BindingFlags.Instance | BindingFlags.Public);
            var        patcher = Harmony.CreateProcessor(E);

            patcher.AddPrefix(EStart);
            patcher.AddPostfix(EEnd);
            patcher.Patch();
            Console.WriteLine("Patched!");
        }
示例#14
0
        /// <summary>
        /// Initializes the RPCDetectorCore.
        /// </summary>
        public static void Init(Harmony harmony, RPCDetectorPlugin instance)
        {
            instance.m_Logger.LogInformation("Loading RPCDetectorCore...");
            Plugin = instance;
            Logger = new RPCLogger();
            Dictionary <MethodInfo, MethodInfo> patchMappings = new Dictionary <MethodInfo, MethodInfo>();

            foreach (MethodInfo patchMethod in typeof(RPCDetectorCore).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).Where(x => Attribute.IsDefined(x, typeof(MPatch))))
            {
                var patchParameters = patchMethod.GetParameters().ToList();

                patchParameters.RemoveAll(x => x.Name.StartsWith("__"));

                foreach (MethodInfo BaseMethod in typeof(SteamChannel).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
                {
                    var baseParameters = BaseMethod.GetParameters();
                    if (patchMethod.Name.Equals(BaseMethod.Name, StringComparison.InvariantCultureIgnoreCase) && patchParameters.Count == baseParameters.Length)
                    {
                        bool equal = true;
                        for (int i = 0; i < baseParameters.Length; i++)
                        {
                            if (patchParameters[i].ParameterType != baseParameters[i].ParameterType)
                            {
                                equal = false;
                            }
                        }

                        if (equal && !patchMappings.ContainsKey(patchMethod))
                        {
                            patchMappings.Add(patchMethod, BaseMethod);
                        }
                    }
                }
            }

            foreach (var patchMapping in patchMappings)
            {
                harmony.CreateProcessor(patchMapping.Value)
                .AddPrefix(patchMapping.Key)
                .Patch();
            }
            lock (Logger)
                Logger.CallReceived += Logger_CallReceived;
            Plugin.m_Logger.Log(LogLevel.Information, "RPCDetectorCore loaded; Created {0} patches.", patchMappings.Count);
        }
示例#15
0
        public void Test_GenericStructReturnTypes()
        {
            var originalClass = typeof(MyList <>).MakeGenericType(typeof(int));

            Assert.NotNull(originalClass);
            var originalMethod = originalClass.GetMethod("GetEnumerator");

            Assert.NotNull(originalMethod);

            var patchClass = typeof(TestGenericStructReturnTypes_Patch);
            var postfix    = patchClass.GetMethod("Postfix");

            Assert.NotNull(postfix);

            var instance = new Harmony("test");

            Assert.NotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.NotNull(patcher);
            _ = patcher.AddPostfix(postfix);
            _ = patcher.Patch();

            var list = new MyList <int> {
                list = new List <int>()
                {
                    1, 2, 3
                }
            };

            var enumerator = list.GetEnumerator();
            var result     = new List <int>();

            while (enumerator.MoveNext())
            {
                result.Add(enumerator.Current);
            }

            Assert.AreEqual(3, result.Count);
            Assert.AreEqual(result[0], 100);
            Assert.AreEqual(result[1], 200);
            Assert.AreEqual(result[2], 300);
        }
示例#16
0
        public void Test_Method2()
        {
            var originalClass = typeof(Class2);

            Assert.NotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method2");

            Assert.NotNull(originalMethod);

            var patchClass = typeof(Class2Patch);
            var prefix     = patchClass.GetMethod("Prefix");
            var postfix    = patchClass.GetMethod("Postfix");
            var transpiler = patchClass.GetMethod("Transpiler");

            Assert.NotNull(prefix);
            Assert.NotNull(postfix);
            Assert.NotNull(transpiler);

            Class2Patch.ResetTest();

            var instance = new Harmony("test");

            Assert.NotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.NotNull(patcher);
            _ = patcher.AddPrefix(prefix);
            _ = patcher.AddPostfix(postfix);
            _ = patcher.AddTranspiler(transpiler);

            var originalMethodStartPre = Memory.GetMethodStart(originalMethod, out _);

            _ = patcher.Patch();
            var originalMethodStartPost = Memory.GetMethodStart(originalMethod, out _);

            Assert.AreEqual(originalMethodStartPre, originalMethodStartPost);

            new Class2().Method2();
            Assert.True(Class2Patch.prefixed, "Prefix was not executed");
            Assert.True(Class2Patch.originalExecuted, "Original was not executed");
            Assert.True(Class2Patch.postfixed, "Postfix was not executed");
        }
示例#17
0
        public void Test_ReverseTranspilerPatching()
        {
            var class0 = new Class0Reverse();

            var result1 = class0.Method("al-gin-Ori", 123);

            Assert.AreEqual("Original123Prolog", result1);

            var originalClass = typeof(Class0Reverse);

            Assert.IsNotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method");

            Assert.IsNotNull(originalMethod);

            var patchClass = typeof(Class0ReversePatch);
            var postfix    = patchClass.GetMethod("Postfix");

            Assert.IsNotNull(postfix);

            //Harmony.DEBUG = true;
            var instance = new Harmony("test");

            Assert.IsNotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            _ = patcher.AddPostfix(new HarmonyMethod(postfix));
            _ = patcher.Patch();

            var standin = new HarmonyMethod(patchClass.GetMethod("StringOperation"));

            Assert.IsNotNull(standin);
            Assert.IsNotNull(standin.method);

            var reversePatcher = instance.CreateReversePatcher(originalMethod, standin);

            _ = reversePatcher.Patch();

            var result2 = class0.Method("al-gin-Ori", 456);

            Assert.AreEqual("EpilogOriginal", result2);
        }
示例#18
0
        public void Test_Method6()
        {
            var originalClass = typeof(Class6);

            Assert.NotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method6");

            Assert.NotNull(originalMethod);

            var patchClass = typeof(Class6Patch);
            var prefix     = patchClass.GetMethod("Prefix");

            Assert.NotNull(prefix);

            var instance = new Harmony("test");

            Assert.NotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.NotNull(patcher);
            _ = patcher.AddPrefix(prefix);
            Assert.NotNull(patcher);

            _ = patcher.Patch();

            var instance6 = new Class6
            {
                someFloat  = 999,
                someString = "original",
                someStruct = new Class6Struct()
                {
                    d1 = 1, d2 = 2, d3 = 3
                }
            };
            var res = instance6.Method6();

            Assert.AreEqual(res[0], 123);
            Assert.AreEqual(res[1], "patched");
            Assert.AreEqual(((Class6Struct)res[2]).d1, 10.0);
        }
示例#19
0
        public void Test_Method4()
        {
            var originalClass = typeof(Class4);

            Assert.NotNull(originalClass);
            var originalMethod = originalClass.GetMethod("Method4");

            Assert.NotNull(originalMethod);

            var patchClass = typeof(Class4Patch);
            var prefix     = patchClass.GetMethod("Prefix");

            Assert.NotNull(prefix);

            Class4Patch.ResetTest();

            var instance = new Harmony("test");

            Assert.NotNull(instance);

            var patcher = instance.CreateProcessor(originalMethod);

            Assert.NotNull(patcher);
            _ = patcher.AddPrefix(prefix);

            var originalMethodStartPre = Memory.GetMethodStart(originalMethod, out _);

            _ = patcher.Patch();
            var originalMethodStartPost = Memory.GetMethodStart(originalMethod, out _);

            Assert.AreEqual(originalMethodStartPre, originalMethodStartPost);

            (new Class4()).Method4("foo");
            Assert.True(Class4Patch.prefixed, "Prefix was not executed");
            Assert.True(Class4Patch.originalExecuted, "Original was not executed");
            Assert.AreEqual(Class4Patch.senderValue, "foo");
        }
        public override void LoadPlugin()
        {
            base.LoadPlugin();
            HarmonyInstance = new Harmony("uEssentialsAntiTrack");
            try
            {
                AssemblyRef asm = AssemblyRef.Load("UEssentials");
                if (asm == null)
                {
                    throw new FileNotFoundException();
                }
                Type anylitics = asm.GetType("Essentials.Misc.Analytics");

                if (anylitics != null)
                {
                    MethodInfo sendAnylticicsEvent = anylitics.GetMethod("SendEvent", BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                    if (sendAnylticicsEvent != null)
                    {
                        HarmonyInstance.CreateProcessor(sendAnylticicsEvent).AddPrefix(typeof(AntiTracker).GetMethod("BlockMethod")).Patch();
                        Logger.Log("uEssentials analytics blocked.");
                    }
                    else
                    {
                        Logger.Log("Failed to find Analytics SendEvent Method.");
                    }
                }
                else
                {
                    Logger.Log("Failed to find Analytics Type.");
                }
            }
            catch (FileNotFoundException)
            {
                Logger.Log("uEssentials is not installed.");
            }
        }
示例#21
0
        public void AttemptRemoveHarmonyModPatch(Harmony h)
        {
            /* Needs to run after Harmony is OnEnabled() */

            testName = "TEST/" +
                       "API/ACL3/" +
                       typeof(HarmonyHelper).Assembly.GetName().Name + " " +
                       typeof(HarmonyHelper).Assembly.GetName().Version;

            PatchProcessor processor       = null;
            MethodInfo     prohibitedPatch = null;

            try
            {
                var        targetName = "SetEntry";
                MethodInfo target     = typeof(PackageEntry).GetMethod(targetName,
                                                                       BindingFlags.Instance |
                                                                       BindingFlags.Static |
                                                                       BindingFlags.Public |
                                                                       BindingFlags.NonPublic);
                if (target == null)
                {
                    throw new TestFailed($"Target fn ({targetName}) was not found.");
                }
                processor = h.CreateProcessor(target);
                if (processor == null)
                {
                    UnityEngine.Debug.Log($"[{testName}] INFO - Processor=null. BAD");
                    throw new TestFailed($"Failed to create processor.");
                }

                var patches = Harmony.GetPatchInfo(target);

                if (patches == null)
                {
                    throw new TestFailed($"Failed to get '{target}' patches.");
                }

                if (patches.Prefixes != null)
                {
                    UnityEngine.Debug.Log($"[{testName}] INFO - found {patches.Prefixes.Count} prefix patches to {targetName}");
                }
                if (patches.Postfixes != null)
                {
                    UnityEngine.Debug.Log($"[{testName}] INFO - found {patches.Postfixes.Count} postfix patches to {targetName}");
                }
                if (patches.Transpilers != null)
                {
                    UnityEngine.Debug.Log($"[{testName}] INFO - found {patches.Transpilers.Count} transpiler patches to {targetName}");
                }
                if (patches.Finalizers != null)
                {
                    UnityEngine.Debug.Log($"[{testName}] INFO - found {patches.Finalizers.Count} finalizer patches to {targetName}");
                }

                patches.Postfixes.Do((p) => UnityEngine.Debug.Log($"[{testName}] INFO - found patch to {targetName} = {p.PatchMethod.Name} by {p.owner}"));

                bool found = false;
                patches.Postfixes.DoIf((p) => p.owner.Contains("org.ohmi.harmony"),
                                       (p) => {
                    found = true;
                    processor.Unpatch(p.PatchMethod);
                });

                if (!found)
                {
                    throw new TestFailed($"Mod's patch to {targetName} not found.");
                }

                throw new TestFailed("Removing a Mod's patch did not throw HarmonyModACLException");
            }
            catch (TestFailed ex)
            {
                UnityEngine.Debug.Log($"[{testName}] ERROR : {ex.Message}. BAD");
                throw ex;
            }
            catch (Exception ex)
            {
                if (ex.GetType().Name != "HarmonyModACLException")
                {
                    throw new TestFailed($"Unpatching the mod failed but not because of ACL: {ex.Message}", ex);
                }
                UnityEngine.Debug.Log($"[{testName}] INFO - Attempting to unpatch the mod was blocked ({ex.Message}). OK.");
            }
        }
示例#22
0
        public void AttemptProhibitedPatch(Harmony h)
        {
            testName = "TEST/" +
                       "API/ACL2/" +
                       typeof(HarmonyHelper).Assembly.GetName().Name + " " +
                       typeof(HarmonyHelper).Assembly.GetName().Version;

            PatchProcessor processor       = null;
            MethodInfo     prohibitedPatch = null;

            try
            {
                var        targetName = "CompareTo";
                MethodInfo target     = typeof(Patch).GetMethod(targetName,
                                                                BindingFlags.Instance |
                                                                BindingFlags.Static |
                                                                BindingFlags.Public |
                                                                BindingFlags.NonPublic);
                if (target == null)
                {
                    throw new TestFailed($"Target fn ({targetName}) was not found.");
                }
                processor = h.CreateProcessor(target);
                if (processor == null)
                {
                    UnityEngine.Debug.Log($"[{testName}] INFO - Processor=null. BAD");
                    throw new TestFailed($"Failed to create processor.");
                }

                prohibitedPatch = typeof(ACLPatchDefinitions).GetMethod("ProhibitedPatch",
                                                                        BindingFlags.Instance |
                                                                        BindingFlags.Static |
                                                                        BindingFlags.Public |
                                                                        BindingFlags.NonPublic);
                if (prohibitedPatch == null)
                {
                    throw new TestFailed("Patch fn (ProhibitedPatch) was not found.");
                }

                processor.AddPostfix(prohibitedPatch);
                processor.Patch();
                throw new TestFailed("Installing a prohibited patch did not throw HarmonyModACLException");
            }
            catch (TestFailed ex)
            {
                UnityEngine.Debug.Log($"[{testName}] ERROR : {ex.Message}. BAD");
                throw ex;
            }
            catch (Exception ex)
            {
                if (ex.GetType().Name != "HarmonyModACLException")
                {
                    throw new TestFailed($"Installing a prohibited patch failed but not because of ACL: {ex.Message}");
                }
                UnityEngine.Debug.Log($"[{testName}] INFO - Attempting to install a prohibited patch was blocked ({ex.Message}). OK.");
            }
            finally
            {
                if (processor != null && prohibitedPatch != null)
                {
                    try
                    {
                        processor.Unpatch(prohibitedPatch);
                    }
                    catch (Exception ex)
                    {
                        if (ex.GetType().Name != "HarmonyModACLException")
                        {
                            throw new TestFailed($"Uninstalling a prohibited patch failed but not because of ACL: {ex.Message}");
                        }
                        UnityEngine.Debug.Log($"[{testName}] INFO - Attempting to remove a prohibited patch was blocked ({ex.Message}). OK.");
                    }
                }
                else
                {
                    throw new TestFailed($"Prohibited patch test is broken. processor={processor != null} patch={prohibitedPatch != null}");
                }
            }
        }
示例#23
0
        public static void Install(Harmony harmony, object vanilla, Type vanillaInterfaceType)
        {
            Instance = Activator.CreateInstance <TInstance>();

            var vanillaImplType   = vanilla.GetType();
            var fullInterfaceType = typeof(TService);

            Log.Debug.PrintLine($"Installing {Instance.GetType()} -> {fullInterfaceType} -> {vanillaImplType} -> {vanillaInterfaceType}");

            var stubs   = new List <MethodBase>();
            var patches = new Dictionary <MethodBase, ServicePatch>();

            foreach (var method in typeof(TInstance).GetMethods(InstanceBinding))
            {
                var replace = method.GetCustomAttribute <HarmonyReplaceAttribute>();
                if (replace != null)
                {
                    var patch  = GetPatch();
                    int stubId = stubs.Count;

                    var interfaceMethod = patch.GetImplementedInterface(vanillaInterfaceType);
                    if (interfaceMethod != null)
                    {
                        stubs.Add(interfaceMethod);
                    }
                    else
                    {
                        //This is not method from vanilla interface
                        var extendedInterfaceMethod = patch.Target.FindMatchingMethod(fullInterfaceType.GetAllInterfaceMethods(), false);
                        if (extendedInterfaceMethod != null)
                        {
                            //We can proxy it via extended interface
                            stubs.Add(extendedInterfaceMethod);
                        }
                        else
                        {
                            //Or don't proxy it at all if there is no match in extended interface either
                            stubId = -1;
                        }
                    }

                    patch.VanillaReplace(method, stubId);
                    continue;
                }

                //TODO: Fix for `Vanilla` call
                var prefix = method.GetCustomAttribute <HarmonyPrefix>();
                if (prefix != null)
                {
                    GetPatch().Patch.AddPrefix(new HarmonyMethod(method));
                    continue;
                }

                var postfix = method.GetCustomAttribute <HarmonyPostfix>();
                if (postfix != null)
                {
                    GetPatch().Patch.AddPostfix(new HarmonyMethod(method));
                    continue;
                }

                var finalizer = method.GetCustomAttribute <HarmonyFinalizer>();
                if (finalizer != null)
                {
                    GetPatch().Patch.AddFinalizer(new HarmonyMethod(method));
                    continue;
                }

                ServicePatch GetPatch()
                {
                    var target = method.FindMatchingMethod(vanillaImplType.GetMethods(InstanceBinding), true, IsTypeMatching);

                    //Path real implementation, not V-table stub
                    target = target.GetDeclaredMember();

                    if (patches.TryGetValue(target, out var patch) == false)
                    {
                        patch = new ServicePatch(target, harmony.CreateProcessor(target));
                        patches.Add(target, patch);
                    }

                    return(patch);

                    bool IsTypeMatching(Type real, Type general)
                    {
                        if (real == general)
                        {
                            return(true);
                        }

                        if (real.IsClass && general == typeof(object))
                        {
                            return(true);
                        }

                        if (real.IsByRef && (general == typeof(IntPtr) || general == typeof(void *)))
                        {
                            return(true);
                        }

                        return(false);
                    }
                }
            }

            foreach (var(_, patch) in patches)
            {
                patch.Patch.Patch();
            }

            if (stubs.Count > 0 || vanillaInterfaceType != fullInterfaceType)
            {
                StubIndirections = new bool[stubs.Count];

                var proxy = PatchHelpers.CreateDynamicType($"{fullInterfaceType.Name}_Proxy");
                proxy.SetParent(typeof(object));
                proxy.AddInterfaceImplementation(fullInterfaceType);

                var stubsField      = AccessTools.Field(typeof(CreativeService <TInstance, TService>), "StubIndirections");
                var vanillaInstance = proxy.DefineField("__Vanilla", vanillaImplType, FieldAttributes.Public | FieldAttributes.InitOnly);

                var proxyDelegates         = new List <(Delegate Delegate, FieldInfo Field)>();
                var vanillaMethods         = vanillaInterfaceType.GetAllInterfaceMethods().ToHashSet();
                var declaredVanillaMethods = vanillaImplType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

                foreach (var method in fullInterfaceType.GetAllInterfaceMethods())
                {
                    var args        = method.GetParameters();
                    var proxyMethod = proxy.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual);
                    proxyMethod.SetReturnType(method.ReturnType);
                    proxyMethod.SetParameters(args.Select(x => x.ParameterType).ToArray());
                    proxy.DefineMethodOverride(proxyMethod, method);

                    var IL = proxyMethod.GetILGenerator();

                    var stubId = stubs.IndexOf(method);
                    if (stubId >= 0)
                    {
                        //Set stub mark
                        IL.Emit(OpCodes.Ldsfld, stubsField);
                        IL.Emit(OpCodes.Ldc_I4, stubId);
                        IL.Emit(OpCodes.Ldc_I4_1);
                        IL.Emit(OpCodes.Stelem_I1);
                    }

                    MethodInfo directCallTarget = null;
                    var        isInterfaceCall  = vanillaMethods.Contains(method);

                    if (isInterfaceCall == false)
                    {
                        directCallTarget = method.FindMatchingMethod(declaredVanillaMethods, true);

                        if (directCallTarget.IsAssemblyPublic() == false)
                        {
                            //Note: Nasty hack follows!
                            //Dynamic type has to follow all visibility rules normal assembly would so it can't call private methods directly
                            //Runtime delegates can reflect, call and expose private members, but can't instantiate interface
                            //=> Call proxy delegate inside proxy type to expose private method via public interface. We need to go deeper :)
                            var delegateType  = DelegateCreator.NewDelegateType(directCallTarget, unboundInstanceCall: true);
                            var proxyDelegate = Delegate.CreateDelegate(delegateType, directCallTarget);

                            var fieldName     = $"__ProxyDelegate_{directCallTarget.Name}_{proxyDelegates.Count}";
                            var delegateField = proxy.DefineField(fieldName, delegateType, FieldAttributes.Private | FieldAttributes.InitOnly);

                            IL.Emit(OpCodes.Ldarg_0); //This
                            IL.Emit(OpCodes.Ldfld, delegateField);

                            proxyDelegates.Add((proxyDelegate, delegateField));
                            directCallTarget = delegateType.GetMethod("Invoke");
                        }
                    }

                    if (directCallTarget == null || directCallTarget.IsStatic == false)
                    {
                        IL.Emit(OpCodes.Ldarg_0); //This
                        IL.Emit(OpCodes.Ldfld, vanillaInstance);
                    }

                    var argCount = args.Length;
                    for (int i = 1; i <= argCount; i++)
                    {
                        IL.Emit(OpCodes.Ldarg, i);
                    }

                    if (isInterfaceCall)
                    {
                        IL.Emit(OpCodes.Callvirt, method);
                    }
                    else
                    {
                        IL.Emit(OpCodes.Call, directCallTarget);
                    }

                    IL.Emit(OpCodes.Ret);
                }

                var ctorArgTypes = new[] { vanillaImplType }.Concat(proxyDelegates.Select(x => x.Field.FieldType));
                var ctor         = proxy.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctorArgTypes.ToArray());
                var cIL          = ctor.GetILGenerator();
                cIL.Emit(OpCodes.Ldarg_0);
                cIL.Emit(OpCodes.Call, proxy.BaseType.GetConstructor(Type.EmptyTypes));
                cIL.Emit(OpCodes.Ldarg_0);
                cIL.Emit(OpCodes.Ldarg_1);
                cIL.Emit(OpCodes.Stfld, vanillaInstance);

                for (int i = 0; i < proxyDelegates.Count; i++)
                {
                    cIL.Emit(OpCodes.Ldarg_0);
                    cIL.Emit(OpCodes.Ldarg, i + 2);
                    cIL.Emit(OpCodes.Stfld, proxyDelegates[i].Field);
                }

                cIL.Emit(OpCodes.Ret);

                var ctorArgs = new object[] { vanilla }.Concat(proxyDelegates.Select(x => x.Delegate));
                Instance.Vanilla = (TService)Activator.CreateInstance(proxy.CreateType(), ctorArgs.ToArray());
            }
            else
            {
                Instance.Vanilla = (TService)vanilla;
            }

            foreach (var property in typeof(TInstance).GetProperties(InstanceBinding | BindingFlags.Static))
            {
                if (property.HasAttribute <HarmonyPropertyAttribute>())
                {
                    property.InjectVanillaData(vanillaImplType, harmony);
                }
            }
        }