Пример #1
0
        protected static string _Format(string message,
                                        IMetadataTokenProvider mtp, IMetadataTokenProvider context)
        {
            if (mtp == null && context == null)
            {
                return(message);
            }

            StringBuilder builder = new StringBuilder(message);

            builder.Append(" ");

            if (mtp != null)
            {
                builder.Append(mtp.ToString());
            }

            if (context != null)
            {
                builder.Append(" ");
            }

            if (context != null)
            {
                builder.Append("(context: ").Append(context.ToString()).Append(")");
            }

            return(builder.ToString());
        }
Пример #2
0
        void CreateTargetDetails(IMetadataTokenProvider target)
        {
            AssemblyDefinition assembly = target.GetAssembly();

            writer.WriteAttributeString("Name", target.ToString());
            writer.WriteAttributeString("Assembly", assembly == null ? AssemblySet : assembly.Name.FullName);
        }
Пример #3
0
        static string GetKey(MethodDefinition caller, MethodDefinition callee, Instruction ins)
        {
            if (callee.IsStatic)
            {
                return(callee.GetFullName());
            }

            IMetadataTokenProvider chain    = callee;
            Instruction            instance = ins.TraceBack(caller);

            StringBuilder sb = new StringBuilder();

            while (instance != null)
            {
                MemberReference mr = (chain as MemberReference);
                if (mr == null)
                {
                    sb.Append(chain.ToString()); // ?? "null")
                }
                else
                {
                    sb.Append(mr.GetFullName());
                }
                sb.Append('.');
                chain = (instance.Operand as IMetadataTokenProvider);
                if (chain == null)
                {
                    sb.Append(instance.GetOperand(caller));
                    break;
                }
                instance = instance.TraceBack(caller);
            }
            if (chain != null)
            {
                sb.Append(chain.ToString());
            }
            return(sb.ToString());
        }
        /// <summary>
        /// Creates the suitable importer for the givem member
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        public MemberImporter CreateImporter(IMetadataTokenProvider member)
        {
            //Switches the token type
            switch (member.MetadataToken.TokenType)
            {
            case TokenType.TypeDef:
                return(new TypeImporter(member, Destination, this));

            case TokenType.Field:
                return(new FieldImporter(member, Destination, this));

            case TokenType.Method:
                return(new MethodImporter(member, Destination, this));

            case TokenType.Property:
                return(new PropertyImporter(member, Destination, this));

            case TokenType.Event:
                return(new EventImporter(member, Destination, this));

            default:
                throw new ArgumentException("Cannot create an importer for " + member.ToString());
            }
        }
Пример #5
0
        private void PatchAssembly(Action <byte[]> callback)
        {
            if (isPatching)
            {
                Interface.Oxide.LogWarning("Already patching plugin assembly: {0} (ignoring)", PluginNames.ToSentence());
                //RemoteLogger.Warning($"Already patching plugin assembly: {PluginNames.ToSentence()}");
                return;
            }

            float startedAt = Interface.Oxide.Now;

            isPatching = true;
            ThreadPool.QueueUserWorkItem(_ =>
            {
                try
                {
                    AssemblyDefinition definition;
                    using (MemoryStream stream = new MemoryStream(RawAssembly))
                    {
                        definition = AssemblyDefinition.ReadAssembly(stream);
                    }

                    ConstructorInfo exceptionConstructor = typeof(UnauthorizedAccessException).GetConstructor(new[] { typeof(string) });
                    MethodReference securityException    = definition.MainModule.Import(exceptionConstructor);

                    Action <TypeDefinition> patchModuleType = null;
                    patchModuleType = type =>
                    {
                        foreach (MethodDefinition method in type.Methods)
                        {
                            bool changedMethod = false;

                            if (method.Body == null)
                            {
                                if (method.HasPInvokeInfo && CSharpExtension.SandboxEnabled)
                                {
                                    method.Attributes &= ~MethodAttributes.PInvokeImpl;
                                    MethodBody body    = new MethodBody(method);
                                    body.Instructions.Add(Instruction.Create(OpCodes.Ldstr, "PInvoke access is restricted, you are not allowed to use PInvoke"));
                                    body.Instructions.Add(Instruction.Create(OpCodes.Newobj, securityException));
                                    body.Instructions.Add(Instruction.Create(OpCodes.Throw));
                                    method.Body = body;
                                }
                            }
                            else
                            {
                                bool replacedMethod = false;
                                foreach (VariableDefinition variable in method.Body.Variables)
                                {
                                    if (!IsNamespaceBlacklisted(variable.VariableType.FullName))
                                    {
                                        continue;
                                    }

                                    MethodBody body = new MethodBody(method);
                                    body.Instructions.Add(Instruction.Create(OpCodes.Ldstr, $"System access is restricted, you are not allowed to use {variable.VariableType.FullName}"));
                                    body.Instructions.Add(Instruction.Create(OpCodes.Newobj, securityException));
                                    body.Instructions.Add(Instruction.Create(OpCodes.Throw));
                                    method.Body    = body;
                                    replacedMethod = true;
                                    break;
                                }
                                if (replacedMethod)
                                {
                                    continue;
                                }

                                References::Mono.Collections.Generic.Collection <Instruction> instructions = method.Body.Instructions;
                                ILProcessor ilProcessor = method.Body.GetILProcessor();
                                Instruction first       = instructions.First();

                                int i = 0;
                                while (i < instructions.Count && !changedMethod)
                                {
                                    Instruction instruction = instructions[i];
                                    if (instruction.OpCode == OpCodes.Ldtoken)
                                    {
                                        IMetadataTokenProvider operand = instruction.Operand as IMetadataTokenProvider;
                                        string token = operand?.ToString();
                                        if (IsNamespaceBlacklisted(token))
                                        {
                                            ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Ldstr, $"System access is restricted, you are not allowed to use {token}"));
                                            ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Newobj, securityException));
                                            ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Throw));
                                            changedMethod = true;
                                        }
                                    }
                                    else if (instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Calli || instruction.OpCode == OpCodes.Callvirt || instruction.OpCode == OpCodes.Ldftn || instruction.OpCode == OpCodes.Newobj)
                                    {
                                        MethodReference methodCall = instruction.Operand as MethodReference;
                                        string fullNamespace       = methodCall?.DeclaringType.FullName;

                                        if ((fullNamespace == "System.Type" && methodCall.Name == "GetType") || IsNamespaceBlacklisted(fullNamespace))
                                        {
                                            ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Ldstr, $"System access is restricted, you are not allowed to use {fullNamespace}"));
                                            ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Newobj, securityException));
                                            ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Throw));
                                            changedMethod = true;
                                        }
                                    }
                                    else if (instruction.OpCode == OpCodes.Ldfld)
                                    {
                                        FieldReference fieldType = instruction.Operand as FieldReference;
                                        string fullNamespace     = fieldType?.FieldType.FullName;
                                        if (IsNamespaceBlacklisted(fullNamespace))
                                        {
                                            ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Ldstr, $"System access is restricted, you are not allowed to use {fullNamespace}"));
                                            ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Newobj, securityException));
                                            ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Throw));
                                            changedMethod = true;
                                        }
                                    }
                                    i++;
                                }
                            }

                            if (changedMethod)
                            {
                                method.Body?.OptimizeMacros();

                                /*//Interface.Oxide.LogDebug("Updating {0} instruction offsets: {1}", instructions.Count, method.FullName);
                                 * int curoffset = 0;
                                 * for (var i = 0; i < instructions.Count; i++)
                                 * {
                                 *  var instruction = instructions[i];
                                 *  instruction.Previous = (i == 0) ? null : instructions[i - 1];
                                 *  instruction.Next = (i == instructions.Count - 1) ? null : instructions[i + 1];
                                 *  instruction.Offset = curoffset;
                                 *  curoffset += instruction.GetSize();
                                 *  //Interface.Oxide.LogDebug("    {0}", instruction.ToString());
                                 * }*/
                            }
                        }
                        foreach (TypeDefinition nestedType in type.NestedTypes)
                        {
                            patchModuleType(nestedType);
                        }
                    };

                    foreach (TypeDefinition type in definition.MainModule.Types)
                    {
                        patchModuleType(type);

                        if (IsCompilerGenerated(type))
                        {
                            continue;
                        }

                        if (type.Namespace == "Oxide.Plugins")
                        {
                            if (PluginNames.Contains(type.Name))
                            {
                                MethodDefinition constructor =
                                    type.Methods.FirstOrDefault(
                                        m => !m.IsStatic && m.IsConstructor && !m.HasParameters && !m.IsPublic);
                                if (constructor != null)
                                {
                                    CompilablePlugin plugin = CompilablePlugins.SingleOrDefault(p => p.Name == type.Name);
                                    if (plugin != null)
                                    {
                                        plugin.CompilerErrors = "Primary constructor in main class must be public";
                                    }
                                }
                                else
                                {
                                    new DirectCallMethod(definition.MainModule, type);
                                }
                            }
                            else
                            {
                                Interface.Oxide.LogWarning(PluginNames.Length == 1
                                    ? $"{PluginNames[0]} has polluted the global namespace by defining {type.Name}"
                                    : $"A plugin has polluted the global namespace by defining {type.Name}");
                                //RemoteLogger.Info($"A plugin has polluted the global namespace by defining {type.Name}: {PluginNames.ToSentence()}");
                            }
                        }
                        else if (type.FullName != "<Module>")
                        {
                            if (!PluginNames.Any(plugin => type.FullName.StartsWith($"Oxide.Plugins.{plugin}")))
                            {
                                Interface.Oxide.LogWarning(PluginNames.Length == 1
                                    ? $"{PluginNames[0]} has polluted the global namespace by defining {type.FullName}"
                                    : $"A plugin has polluted the global namespace by defining {type.FullName}");
                            }
                        }
                    }

                    // TODO: Why is there no error on boot using this?
                    foreach (TypeDefinition type in definition.MainModule.Types)
                    {
                        if (type.Namespace != "Oxide.Plugins" || !PluginNames.Contains(type.Name))
                        {
                            continue;
                        }

                        foreach (MethodDefinition m in type.Methods.Where(m => !m.IsStatic && !m.HasGenericParameters && !m.ReturnType.IsGenericParameter && !m.IsSetter && !m.IsGetter))
                        {
                            foreach (ParameterDefinition parameter in m.Parameters)
                            {
                                foreach (CustomAttribute attribute in parameter.CustomAttributes)
                                {
                                    //Interface.Oxide.LogInfo($"{m.FullName} - {parameter.Name} - {attribute.Constructor.FullName}");
                                }
                            }
                        }
                    }

                    using (MemoryStream stream = new MemoryStream())
                    {
                        definition.Write(stream);
                        PatchedAssembly = stream.ToArray();
                    }

                    Interface.Oxide.NextTick(() =>
                    {
                        isPatching = false;
                        //Interface.Oxide.LogDebug("Patching {0} assembly took {1:0.00} ms", ScriptName, Interface.Oxide.Now - startedAt);
                        callback(PatchedAssembly);
                    });
                }
                catch (Exception ex)
                {
                    Interface.Oxide.NextTick(() =>
                    {
                        isPatching = false;
                        Interface.Oxide.LogException($"Exception while patching: {PluginNames.ToSentence()}", ex);
                        //RemoteLogger.Exception($"Exception while patching: {PluginNames.ToSentence()}", ex);
                        callback(null);
                    });
                }
            });
        }
Пример #6
0
		void CreateTargetDetails (IMetadataTokenProvider target)
		{
			AssemblyDefinition assembly = target.GetAssembly ();

			writer.WriteAttributeString ("Name", target.ToString ());
			writer.WriteAttributeString ("Assembly", assembly == null ? AssemblySet : assembly.Name.FullName);
		}
Пример #7
0
		private void ResolveMethod (IMetadataTokenProvider method)
		{
			HashSet<string> rules;

			string m = method.ToString ();
			m = m.Substring (m.IndexOf (' ') + 1);

			if (targets.TryGetValue (m, out rules))
				Add (method, rules);
		}
Пример #8
0
 /// <summary>
 /// Creates the suitable importer for the givem member
 /// </summary>
 /// <param name="member"></param>
 /// <returns></returns>
 public MemberImporter CreateImporter(IMetadataTokenProvider member)
 {
     //Switches the token type
     switch (member.MetadataToken.TokenType)
     {
         case TokenType.TypeDef:
             return new TypeImporter(member, Destination, this);
         case TokenType.Field:
             return new FieldImporter(member, Destination, this);
         case TokenType.Method:
             return new MethodImporter(member, Destination, this);
         case TokenType.Property:
             return new PropertyImporter(member, Destination, this);
         case TokenType.Event:
             return new EventImporter(member, Destination, this);
         default:
             throw new ArgumentException("Cannot create an importer for " + member.ToString());
     }
 }
        private void PatchAssembly(Action <byte[]> callback)
        {
            Action action1 = null;

            if (this.isPatching)
            {
                Interface.Oxide.LogWarning("Already patching plugin assembly: {0} (ignoring)", new object[] { this.PluginNames.ToSentence <string>() });
                return;
            }
            float now = Interface.Oxide.Now;

            this.isPatching = true;
            ThreadPool.QueueUserWorkItem((object _) => {
                AssemblyDefinition assemblyDefinition;
                try
                {
                    using (MemoryStream memoryStream = new MemoryStream(this.RawAssembly))
                    {
                        assemblyDefinition = AssemblyDefinition.ReadAssembly(memoryStream);
                    }
                    ConstructorInfo constructor      = typeof(UnauthorizedAccessException).GetConstructor(new Type[] { typeof(string) });
                    MethodReference methodReference1 = assemblyDefinition.MainModule.Import(constructor);
                    Action <TypeDefinition> methods  = null;
                    methods = (TypeDefinition type) => {
                        string fullName;
                        string str;
                        foreach (MethodDefinition method in type.Methods)
                        {
                            bool flag = false;
                            if (method.Body != null)
                            {
                                bool flag1 = false;
                                foreach (VariableDefinition variable in method.Body.Variables)
                                {
                                    if (!CompiledAssembly.IsNamespaceBlacklisted(variable.VariableType.FullName))
                                    {
                                        continue;
                                    }
                                    Mono.Cecil.Cil.MethodBody methodBody = new Mono.Cecil.Cil.MethodBody(method);
                                    methodBody.Instructions.Add(Instruction.Create(OpCodes.Ldstr, string.Concat("System access is restricted, you are not allowed to use ", variable.VariableType.FullName)));
                                    methodBody.Instructions.Add(Instruction.Create(OpCodes.Newobj, methodReference1));
                                    methodBody.Instructions.Add(Instruction.Create(OpCodes.Throw));
                                    method.Body = methodBody;
                                    flag1       = true;
                                    break;
                                }
                                if (flag1)
                                {
                                    continue;
                                }
                                Collection <Instruction> instructions = method.Body.Instructions;
                                ILProcessor lProcessor  = method.Body.GetILProcessor();
                                Instruction instruction = instructions.First <Instruction>();
                                for (int i = 0; i < instructions.Count && !flag; i++)
                                {
                                    Instruction item = instructions[i];
                                    if (item.OpCode == OpCodes.Ldtoken)
                                    {
                                        IMetadataTokenProvider operand = item.Operand as IMetadataTokenProvider;
                                        str         = (operand != null ? operand.ToString() : null);
                                        string str1 = str;
                                        if (CompiledAssembly.IsNamespaceBlacklisted(str1))
                                        {
                                            lProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Ldstr, string.Concat("System access is restricted, you are not allowed to use ", str1)));
                                            lProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Newobj, methodReference1));
                                            lProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Throw));
                                            flag = true;
                                        }
                                    }
                                    else if (item.OpCode == OpCodes.Call || item.OpCode == OpCodes.Calli || item.OpCode == OpCodes.Callvirt || item.OpCode == OpCodes.Ldftn)
                                    {
                                        MethodReference methodReference = item.Operand as MethodReference;
                                        string str2 = (methodReference != null ? methodReference.DeclaringType.FullName : null);
                                        if (str2 == "System.Type" && methodReference.Name == "GetType" || CompiledAssembly.IsNamespaceBlacklisted(str2))
                                        {
                                            lProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Ldstr, string.Concat("System access is restricted, you are not allowed to use ", str2)));
                                            lProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Newobj, methodReference1));
                                            lProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Throw));
                                            flag = true;
                                        }
                                    }
                                    else if (item.OpCode == OpCodes.Ldfld)
                                    {
                                        FieldReference fieldReference = item.Operand as FieldReference;
                                        fullName    = (fieldReference != null ? fieldReference.FieldType.FullName : null);
                                        string str3 = fullName;
                                        if (CompiledAssembly.IsNamespaceBlacklisted(str3))
                                        {
                                            lProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Ldstr, string.Concat("System access is restricted, you are not allowed to use ", str3)));
                                            lProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Newobj, methodReference1));
                                            lProcessor.InsertBefore(instruction, Instruction.Create(OpCodes.Throw));
                                            flag = true;
                                        }
                                    }
                                }
                            }
                            else if (method.HasPInvokeInfo)
                            {
                                MethodDefinition attributes           = method;
                                attributes.Attributes                 = attributes.Attributes & (Mono.Cecil.MethodAttributes.MemberAccessMask | Mono.Cecil.MethodAttributes.Private | Mono.Cecil.MethodAttributes.FamANDAssem | Mono.Cecil.MethodAttributes.Assembly | Mono.Cecil.MethodAttributes.Family | Mono.Cecil.MethodAttributes.FamORAssem | Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.Static | Mono.Cecil.MethodAttributes.Final | Mono.Cecil.MethodAttributes.Virtual | Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.VtableLayoutMask | Mono.Cecil.MethodAttributes.NewSlot | Mono.Cecil.MethodAttributes.CheckAccessOnOverride | Mono.Cecil.MethodAttributes.Abstract | Mono.Cecil.MethodAttributes.SpecialName | Mono.Cecil.MethodAttributes.UnmanagedExport | Mono.Cecil.MethodAttributes.RTSpecialName | Mono.Cecil.MethodAttributes.HasSecurity | Mono.Cecil.MethodAttributes.RequireSecObject);
                                Mono.Cecil.Cil.MethodBody methodBody1 = new Mono.Cecil.Cil.MethodBody(method);
                                methodBody1.Instructions.Add(Instruction.Create(OpCodes.Ldstr, "PInvoke access is restricted, you are not allowed to use PInvoke"));
                                methodBody1.Instructions.Add(Instruction.Create(OpCodes.Newobj, methodReference1));
                                methodBody1.Instructions.Add(Instruction.Create(OpCodes.Throw));
                                method.Body = methodBody1;
                            }
                            if (!flag)
                            {
                                continue;
                            }
                            Mono.Cecil.Cil.MethodBody body = method.Body;
                            if (body != null)
                            {
                                body.OptimizeMacros();
                            }
                            else
                            {
                            }
                        }
                        foreach (TypeDefinition nestedType in type.NestedTypes)
                        {
                            methods(nestedType);
                        }
                    };
                    foreach (TypeDefinition typeDefinition in assemblyDefinition.MainModule.Types)
                    {
                        methods(typeDefinition);
                        if (this.IsCompilerGenerated(typeDefinition))
                        {
                            continue;
                        }
                        if (typeDefinition.Namespace != "Oxide.Plugins")
                        {
                            if (!(typeDefinition.FullName != "<Module>") || this.PluginNames.Any <string>((string plugin) => typeDefinition.FullName.StartsWith(string.Concat("Oxide.Plugins.", plugin))))
                            {
                                continue;
                            }
                            Interface.Oxide.LogWarning(((int)this.PluginNames.Length == 1 ? string.Concat(this.PluginNames[0], " has polluted the global namespace by defining ", typeDefinition.FullName) : string.Concat("A plugin has polluted the global namespace by defining ", typeDefinition.FullName)), Array.Empty <object>());
                        }
                        else if (!this.PluginNames.Contains <string>(typeDefinition.Name))
                        {
                            Interface.Oxide.LogWarning(((int)this.PluginNames.Length == 1 ? string.Concat(this.PluginNames[0], " has polluted the global namespace by defining ", typeDefinition.Name) : string.Concat("A plugin has polluted the global namespace by defining ", typeDefinition.Name)), Array.Empty <object>());
                        }
                        else
                        {
                            Collection <MethodDefinition> methodDefinitions = typeDefinition.Methods;
                            Func <MethodDefinition, bool> u003cu003e9_204   = CompiledAssembly.< > c.< > 9__20_4;
                            if (u003cu003e9_204 == null)
                            {
                                u003cu003e9_204 = (MethodDefinition m) => {
                                    if (m.IsStatic || !m.IsConstructor || m.HasParameters)
                                    {
                                        return(false);
                                    }
                                    return(!m.IsPublic);
                                };
                                CompiledAssembly.< > c.< > 9__20_4 = u003cu003e9_204;
                            }
                            if (methodDefinitions.FirstOrDefault <MethodDefinition>(u003cu003e9_204) == null)
                            {
                                DirectCallMethod directCallMethod = new DirectCallMethod(assemblyDefinition.MainModule, typeDefinition);
                            }
                            else
                            {
                                CompilablePlugin compilablePlugin = this.CompilablePlugins.SingleOrDefault <CompilablePlugin>((CompilablePlugin p) => p.Name == typeDefinition.Name);
                                if (compilablePlugin == null)
                                {
                                    continue;
                                }
                                compilablePlugin.CompilerErrors = "Primary constructor in main class must be public";
                            }
                        }
                    }
                    foreach (TypeDefinition typeDefinition1 in assemblyDefinition.MainModule.Types)
                    {
                        if (typeDefinition1.Namespace != "Oxide.Plugins" || !this.PluginNames.Contains <string>(typeDefinition1.Name))
                        {
                            continue;
                        }
                        Collection <MethodDefinition> methods1        = typeDefinition1.Methods;
                        Func <MethodDefinition, bool> u003cu003e9_206 = CompiledAssembly.< > c.< > 9__20_6;
                        if (u003cu003e9_206 == null)
                        {
                            u003cu003e9_206 = (MethodDefinition m) => {
                                if (m.IsStatic || m.HasGenericParameters || m.ReturnType.IsGenericParameter || m.IsSetter)
                                {
                                    return(false);
                                }
                                return(!m.IsGetter);
                            };
                            CompiledAssembly.< > c.< > 9__20_6 = u003cu003e9_206;
                        }
                        foreach (MethodDefinition methodDefinition in methods1.Where <MethodDefinition>(u003cu003e9_206))
                        {
                            foreach (ParameterDefinition parameter in methodDefinition.Parameters)
                            {
                                foreach (CustomAttribute customAttribute in parameter.CustomAttributes)
                                {
                                }
                            }
                        }
                    }
                    using (MemoryStream memoryStream1 = new MemoryStream())
                    {
                        assemblyDefinition.Write(memoryStream1);
                        this.PatchedAssembly = memoryStream1.ToArray();
                    }
                    OxideMod oxide       = Interface.Oxide;
                    Action u003cu003e9_2 = action1;
                    if (u003cu003e9_2 == null)
                    {
                        Action u003cu003e4_this = () => {
                            this.isPatching = false;
                            callback(this.PatchedAssembly);
                        };
                        Action action = u003cu003e4_this;
                        action1       = u003cu003e4_this;
                        u003cu003e9_2 = action;
                    }
                    oxide.NextTick(u003cu003e9_2);
                }
                catch (Exception exception1)
                {
                    Exception exception = exception1;
                    Interface.Oxide.NextTick(() => {
                        this.isPatching = false;
                        Interface.Oxide.LogException(string.Concat("Exception while patching: ", this.PluginNames.ToSentence <string>()), exception);
                        callback(null);
                    });
                }
            });
        }
Пример #10
0
 public static string GetParamStr(IMetadataTokenProvider meth)
 => meth.ToString().Split(new[] { '(' }, 2).Last().TrimEnd(')');