예제 #1
0
        async internal Task <Dictionary <string, object> > ApplyPatch(JObject data, ProgressDelegate progressDelegate, CoreDelegates coreDelegates)
        {
            AssemblyDefinition    assembly   = null;
            EntryPointDefinitions sourceDefs = null;
            string tempFile = string.Empty;

            try {
                PatchConfig config      = new PatchConfig((JObject)data["patchConfig"]);
                EntryPoint  sourcePoint = config.SourceEntryPoint as EntryPoint;
                if (!File.Exists(sourcePoint.AssemblyPath))
                {
                    throw new FileNotFoundException($"{sourcePoint.AssemblyPath} does not exist");
                }

                sourceDefs = sourcePoint.GetDefinitions() as EntryPointDefinitions;
                if (!sourceDefs.IsEntryPointValid)
                {
                    throw new EntryPointNotFoundException($"Unable to find {sourcePoint.AssemblyPath}_{sourcePoint.ToString ()} source entry point. Expected format is Namespace.className::methodName");
                }

                string dataPath = await coreDelegates.context.GetDataPath();

                string VMLPath = await coreDelegates.context.GetModLoaderPath();

                foreach (EntryPoint point in config.TargetEntryPoints)
                {
                    if (!File.Exists(point.AssemblyPath))
                    {
                        throw new FileNotFoundException($"{point.AssemblyPath} does not exist");
                    }
                    // TODO: Might have to change this to only use the entry point's dependency path.
                    //  More testing is needed.
                    string [] assemblyResolverPaths = (dataPath != VMLPath)
                        ? new string [] { point.DependencyPath, dataPath, VMLPath }
                        : new string [] { point.DependencyPath, dataPath };

                    m_resolver = new MissingAssemblyResolver(assemblyResolverPaths);

                    tempFile = Util.GetTempFile(point.AssemblyPath);
                    using (assembly = AssemblyDefinition.ReadAssembly(tempFile,
                                                                      new ReaderParameters {
                        AssemblyResolver = m_resolver
                    })) {
                        if (IsInjected(assembly, config.SourceEntryPoint, point))
                        {
                            throw new EntryPointInjectedException($"{point.AssemblyPath}_{point.ToString ()} is already injected");
                        }

                        TypeDefinition   typeDef = assembly.MainModule.GetType(point.TypeName);
                        MethodDefinition methDef = typeDef.Methods.First(x => x.Name == point.MethodName);

                        ILProcessor ilProcessor = methDef.Body.GetILProcessor();
                        if (sourcePoint.ExpandoObjectData != string.Empty)
                        {
                            ilProcessor.InsertBefore(methDef.Body.Instructions [0], Instruction.Create(OpCodes.Ldstr, sourcePoint.ExpandoObjectData));
                            ilProcessor.InsertBefore(methDef.Body.Instructions [1], Instruction.Create(OpCodes.Call, methDef.Module.ImportReference(sourceDefs.MethodDef)));
                        }
                        else
                        {
                            ilProcessor.InsertBefore(methDef.Body.Instructions [0], Instruction.Create(OpCodes.Call, methDef.Module.ImportReference(sourceDefs.MethodDef)));
                        }

                        assembly.Write(point.AssemblyPath);
                    }

                    Util.Dispose(ref assembly);
                    Util.DeleteTemp(tempFile);
                    tempFile = string.Empty;
                }

                Util.Dispose(ref sourceDefs);
            } catch (Exception exc) {
                Util.Dispose(ref assembly);
                Util.Dispose(ref sourceDefs);

                if (tempFile != string.Empty)
                {
                    Util.DeleteTemp(tempFile);
                    tempFile = string.Empty;
                }

                return(PatchHelper.CreatePatchResult(false, exc.Message));
            }

            return(PatchHelper.CreatePatchResult(true, "Patch Applied"));
        }
예제 #2
0
        async internal Task <Dictionary <string, object> > RemovePatch(JObject data, ProgressDelegate progressDelegate, CoreDelegates coreDelegates)
        {
            AssemblyDefinition    assembly   = null;
            EntryPointDefinitions sourceDefs = null;
            string tempFile = string.Empty;

            // This should rarely be used when deploying VML as Vortex itself would remove the
            //  the assemblies when the user decides to purge.
            try {
                PatchConfig config      = new PatchConfig((JObject)data ["patchConfig"]);
                EntryPoint  sourcePoint = config.SourceEntryPoint as EntryPoint;
                if (!File.Exists(sourcePoint.AssemblyPath))
                {
                    throw new FileNotFoundException($"{sourcePoint.AssemblyPath} does not exist");
                }

                sourceDefs = sourcePoint.GetDefinitions() as EntryPointDefinitions;
                if (!sourceDefs.IsEntryPointValid)
                {
                    throw new EntryPointNotFoundException($"Unable to find {sourcePoint.AssemblyPath}_{sourcePoint.ToString ()} source entry point. Expected format is Namespace.className::methodName");
                }

                string dataPath = await coreDelegates.context.GetDataPath();

                string VMLPath = await coreDelegates.context.GetModLoaderPath();

                foreach (EntryPoint point in config.TargetEntryPoints)
                {
                    if (!File.Exists(point.AssemblyPath))
                    {
                        throw new FileNotFoundException($"{point.AssemblyPath} does not exist");
                    }

                    // TODO: Might have to change this to only use the entry point's dependency path.
                    //  More testing is needed.
                    string [] assemblyResolverPaths = (dataPath != VMLPath)
                        ? new string [] { point.DependencyPath, dataPath, VMLPath }
                        : new string [] { point.DependencyPath, dataPath };

                    m_resolver = new MissingAssemblyResolver(assemblyResolverPaths);

                    tempFile = Util.GetTempFile(point.AssemblyPath);
                    using (assembly = AssemblyDefinition.ReadAssembly(tempFile,
                                                                      new ReaderParameters {
                        ReadWrite = true, AssemblyResolver = m_resolver
                    })) {
                        // If the assembly is not injected - there's nothing to remove.
                        //  This shouldn't be treated as an error although we do break
                        //  out using an exception.
                        if (!IsInjected(assembly, sourcePoint, point))
                        {
                            throw new EntryPointInjectedException($"{point.AssemblyPath}_{point.ToString()} is not injected.");
                        }

                        TypeDefinition   typeDef = assembly.MainModule.GetType(point.TypeName);
                        MethodDefinition methDef = typeDef.Methods.First(x => x.Name == point.MethodName);

                        var instructions = methDef.Body.Instructions
                                           .Where(instr => instr.OpCode == OpCodes.Call)
                                           .ToArray();
                        Instruction patchInstr = instructions.FirstOrDefault(instr =>
                                                                             instr.Operand.ToString().Contains(point.ToString()));

                        methDef.Body.Instructions.Remove(patchInstr);

                        assembly.Write(point.AssemblyPath);
                    }

                    Util.Dispose(ref assembly);
                    Util.DeleteTemp(tempFile);
                    tempFile = string.Empty;
                }
                Util.Dispose(ref sourceDefs);
            } catch (Exception exc) {
                Util.Dispose(ref assembly);
                Util.Dispose(ref sourceDefs);

                if (tempFile != string.Empty)
                {
                    Util.DeleteTemp(tempFile);
                    tempFile = string.Empty;
                }

                return(PatchHelper.CreatePatchResult(false, exc.Message));
            }

            return(PatchHelper.CreatePatchResult(true, "Patch removed successfully"));
        }
예제 #3
0
        async internal Task <Dictionary <string, object> > IsPatchApplicable(JObject data, ProgressDelegate progressDelegate, CoreDelegates coreDelegates)
        {
            AssemblyDefinition    assembly   = null;
            EntryPointDefinitions sourceDefs = null;
            EntryPointDefinitions targetDefs = null;
            string tempFile = string.Empty;

            try {
                PatchConfig config      = new PatchConfig((JObject)data["patchConfig"]);
                EntryPoint  sourcePoint = config.SourceEntryPoint as EntryPoint;
                if (!File.Exists(sourcePoint.AssemblyPath))
                {
                    throw new FileNotFoundException($"{sourcePoint.AssemblyPath} does not exist");
                }

                sourceDefs = sourcePoint.GetDefinitions() as EntryPointDefinitions;
                if (!sourceDefs.IsEntryPointValid)
                {
                    throw new EntryPointNotFoundException($"Unable to find {sourcePoint.AssemblyPath}_{sourcePoint.ToString ()} target entry point. Expected format is Namespace.className::methodName");
                }

                string dataPath = await coreDelegates.context.GetDataPath();

                string VMLPath = await coreDelegates.context.GetModLoaderPath();

                foreach (EntryPoint point in config.TargetEntryPoints)
                {
                    if (!File.Exists(point.AssemblyPath))
                    {
                        throw new FileNotFoundException($"{point.AssemblyPath} does not exist");
                    }

                    // TODO: Might have to change this to only use the entry point's dependency path.
                    //  More testing is needed.
                    string [] assemblyResolverPaths = (dataPath != VMLPath)
                        ? new string [] { point.DependencyPath, dataPath, VMLPath }
                        : new string [] { point.DependencyPath, dataPath };

                    targetDefs = point.GetDefinitions() as EntryPointDefinitions;
                    if (!targetDefs.IsEntryPointValid)
                    {
                        throw new EntryPointNotFoundException($"Unable to find {point.AssemblyPath}{point.ToString ()} target entry point. Expected format is Namespace.className::methodName");
                    }

                    m_resolver = new MissingAssemblyResolver(assemblyResolverPaths);

                    tempFile = Util.GetTempFile(point.AssemblyPath);
                    using (assembly = AssemblyDefinition.ReadAssembly(tempFile,
                                                                      new ReaderParameters {
                        AssemblyResolver = m_resolver
                    })) {
                        if (IsInjected(assembly, config.SourceEntryPoint, point))
                        {
                            throw new EntryPointInjectedException($"{point.AssemblyPath}_{point.ToString()} is already injected");
                        }
                    }

                    Util.Dispose(ref assembly);
                    Util.Dispose(ref targetDefs);
                    Util.DeleteTemp(tempFile);
                    tempFile = string.Empty;
                }
            } catch (Exception exc) {
                Util.Dispose(ref assembly);
                Util.Dispose(ref sourceDefs);
                Util.Dispose(ref targetDefs);

                if (tempFile != string.Empty)
                {
                    Util.DeleteTemp(tempFile);
                    tempFile = string.Empty;
                }

                return(PatchHelper.CreatePatchResult(false, exc.Message));
            }

            return(PatchHelper.CreatePatchResult(true, "Patch is applicable"));
        }