void ICustomCodeGenerator.GenerateAssembly(MethodHook methodHook, string path)
        {
            if (methodHook == null)
            {
                throw new ArgumentNullException("methodHook");
            }
            if (!methodHook.RunCustomCode)
            {
                throw new ArgumentException("RunCustomCode should be set in order to generate custom code");
            }

            StringBuilder customCode = new StringBuilder();
            foreach (string ns in m_referencedNamespaces)
            {
                customCode.AppendLine(String.Format("using {0};", ns));
            }
            customCode.AppendLine();

            customCode.AppendLine(String.Format("namespace {0}", CustomNamespace));
            customCode.AppendLine("{");

            string name = GetName(methodHook);
            string className = String.Format("{0}_{1}", name, "Class");
            customCode.AppendLine(String.Format("public class {0}", className));
            customCode.AppendLine("{");

            string returnType = GetReturnType(methodHook);
            string methodName = String.Format("{0}_{1}", name, "Hook");
            var parameters = methodHook.Method.Parameters.Cast<ParameterDefinition>().Select(
                p => "ref " + p.ParameterType.Name + " " + p.Name
                );
            string parametersString = String.Join(", ", parameters);
            customCode.AppendLine(String.Format("public {0} {1}({2})", returnType, methodName, parametersString));
            customCode.AppendLine("{");

            customCode.AppendLine(methodHook.Code);

            // method
            customCode.AppendLine("}");
            // class
            customCode.AppendLine("}");
            // namespace
            customCode.AppendLine("}");

            GenerateAssembly(methodHook, customCode.ToString(), path);
        }
Exemple #2
0
 public frmEditHook(MethodHook methodHook)
     : this()
 {
     m_methodHook = methodHook;
     LoadProperties();
 }
        private void PatchMethod(MethodDefinition methodDefinition, TypeDefinition typeDefinition, MethodHook methodHook)
        {
            #if DEBUG
            DumpMethod("dump.txt", methodDefinition);
            #endif

            if (!methodDefinition.HasBody || methodDefinition.IsGetter || methodDefinition.IsSetter)
            {
                return;
            }

            if (methodHook != null && methodHook.RunCustomCode)
            {
                InjectCustomCode(methodDefinition, methodHook);
            }

            if (m_hookProvider.LogMethodNames || (methodHook != null && methodHook.LogMethodName))
            {
                Instruction targetInstruction = LogMethodName(methodDefinition, typeDefinition);
                if (m_hookProvider.LogParameterValues || (methodHook != null && methodHook.LogParameterValues))
                {
                    LogMethodParameters(methodDefinition, targetInstruction);
                }
                if (m_hookProvider.LogReturnValues || (methodHook != null && methodHook.LogReturnValues))
                {
                    LogReturnValue(methodDefinition);
                }
            }

            #if DEBUG
            DumpMethod("dump_changed.txt", methodDefinition);
            #endif
        }
        private void InjectCustomCode(MethodDefinition method, MethodHook methodHook)
        {
            // generate assembly with custom code
            m_codeGenerator.GenerateAssembly(methodHook, Path.GetDirectoryName(m_assemblyPath));

            // load generated assembly
            string assemblyName = methodHook.GetSafeName();
            AssemblyDefinition generatedAssembly = LoadGeneratedAssembly(assemblyName);

            // get method reference with custom code
            string generatedClassName = String.Format("{0}_{1}", assemblyName, "Class");
            var generatedType = generatedAssembly.MainModule.Types.Cast<TypeDefinition>().First(t => t.Name == generatedClassName);
            string generatedMethodName = String.Format("{0}_{1}", assemblyName, "Hook");
            // TODO: take parameter types into account, to resolve methods with the same names
            var generatedMethod = generatedType.Methods.Cast<MethodDefinition>().First(m => m.Name == generatedMethodName);
            MethodReference generatedTypeCtor = null;
            for (int i = 0; i <= generatedType.Constructors.Count; i++)
            {
                if (!generatedType.Constructors[i].HasParameters)
                {
                    generatedTypeCtor = generatedType.Constructors[i];
                    break;
                }
            }
            if (generatedTypeCtor == null)
            {
                throw new InvalidOperationException("Default constructor was not found in generated assembly");
            }

            // inject call
            MethodReference generatedTypeCtorRef = m_assemblyDefinition.MainModule.Import(generatedTypeCtor);
            MethodReference generatedMethodRef = m_assemblyDefinition.MainModule.Import(generatedMethod);

            method.Body.InitLocals = true;

            CilWorker cilWorker = method.Body.CilWorker;

            if (methodHook.HookType == HookType.ReplaceMethod)
            {
                method.Body.Instructions.Clear();
                method.Body.Variables.Clear();
                // return value
                Instruction returnInstruction = cilWorker.Create(OpCodes.Ret);
                cilWorker.Append(returnInstruction);
                InsertCustomCodeCall(method, generatedTypeCtorRef, generatedMethodRef, cilWorker, returnInstruction, true);
            }
            else if ((methodHook.HookType & HookType.OnMethodEnter) == HookType.OnMethodEnter)
            {
                Instruction firstInstruction = method.Body.Instructions[0];
                InsertCustomCodeCall(method, generatedTypeCtorRef, generatedMethodRef, cilWorker, firstInstruction, false);
            }
            else if ((methodHook.HookType & HookType.OnMethodExit) == HookType.OnMethodExit)
            {
                Instruction returnInstruction = method.Body.Instructions[method.Body.Instructions.Count - 1];
                if (returnInstruction.OpCode != OpCodes.Ret)
                {
                    throw new InvalidOperationException(String.Format("Method '{0}' has no valid ret instruction", method.Name));
                }
                InsertCustomCodeCall(method, generatedTypeCtorRef, generatedMethodRef, cilWorker, returnInstruction, false);
            }
        }
        private void GenerateAssembly(MethodHook methodHook, string code, string path)
        {
            var compilerOptions = new Dictionary<string, string>();
            compilerOptions.Add("CompilerVersion", "v4.0");

            CSharpCodeProvider provider = new CSharpCodeProvider(compilerOptions);

            CompilerParameters cp = new CompilerParameters();
            cp.ReferencedAssemblies.Clear();
            cp.ReferencedAssemblies.AddRange(GetReferencedAssemblies());
            cp.GenerateExecutable = false;
            cp.GenerateInMemory = false;
            // do not include standard mscorlib.dll
            cp.CompilerOptions = "/noconfig /nostdlib";
            string dllName = String.Format("{0}.dll", methodHook.GetSafeName());
            cp.OutputAssembly = Path.Combine(path, dllName);

            CompilerResults results = provider.CompileAssemblyFromSource(cp, code);
            if (results.Errors.Count > 0)
            {
                string errors = String.Join(Environment.NewLine, results.Errors.Cast<CompilerError>().Select(e => e.ErrorText));
                throw new InvalidOperationException("Unable to compile custom code: " + Environment.NewLine + errors);
            }
        }
 private string GetReturnType(MethodHook methodHook)
 {
     string returnTypeName = methodHook.Method.ReturnType.ReturnType.FullName;
     return (returnTypeName != "System.Void") ? returnTypeName : "void";
 }
 private string GetName(MethodHook methodHook)
 {
     return methodHook.GetSafeName();
 }
Exemple #8
0
 void IMainView.AddMethod(MethodHook methodHook)
 {
     lbMethods.Items.Add(methodHook);
     lbMethods.SelectedItem = methodHook;
 }
Exemple #9
0
 void IMainView.ShowEditHookForm(MethodHook methodHook)
 {
     using (frmEditHook form = new frmEditHook(methodHook))
     {
         form.ShowDialog();
     }
 }
Exemple #10
0
 private void FillAssemblyMethods(XAPAssembly xapAssembly)
 {
     foreach (var method in xapAssembly.GetMethods())
     {
         var hook = new MethodHook(method)
         {
             LogMethodName = true,
             LogParameterValues = true,
             LogReturnValues = true
         };
         m_hooks.Add(hook);
     }
 }