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);
            }
        }
示例#2
0
        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 string GetName(MethodHook methodHook)
 {
     return methodHook.GetSafeName();
 }