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 GetName(MethodHook methodHook) { return(methodHook.GetSafeName()); }
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); } }