Esempio n. 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"));
        }
Esempio n. 2
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"));
        }