private void ExtendInternal() { var methodBody = MethodBody.Read(dynamicMethod, false); bool output = true; if(output) Debug.WriteLine(""); if(output) Debug.WriteLine("Initial methodBody of DynamicMethod"); if(output) Debug.WriteLine(methodBody); var methodContainsCycles = CycleFinderWithoutRecursion.HasCycle(methodBody.Instructions.ToArray()); if(output) Debug.WriteLine("Contains cycles: " + methodContainsCycles + "\n"); if(!methodContainsCycles && methodBody.Instructions.Count < 50) { Debug.WriteLine(dynamicMethod + " too simple to be traced"); return; } AddLocalVariables(methodBody); int functionId; MethodBaseTracingInstaller.AddMethod(dynamicMethod, out functionId); ModifyMethodBody(methodBody, functionId); methodBody.WriteToDynamicMethod(dynamicMethod, Math.Max(methodBody.MaxStack, 3)); if(output) Debug.WriteLine(""); if(output) Debug.WriteLine("Changed methodBody of DynamicMethod"); if(output) Debug.WriteLine(methodBody); }
private void ModifyMethodBody(MethodBody methodBody, int functionId) { MethodBaseTracingInstaller.ReplaceRetInstructions(methodBody.Instructions, hasReturnType, resultLocalIndex); var ticksReaderSignature = typeof(MethodBaseTracingInstaller).Module.ResolveSignature(typeof(MethodBaseTracingInstaller).GetMethod("TemplateForTicksSignature", BindingFlags.Public | BindingFlags.Static).MetadataToken); var methodStartedSignature = typeof(TracingAnalyzer).Module.ResolveSignature(typeof(TracingAnalyzer).GetMethod("MethodStarted", BindingFlags.Public | BindingFlags.Static).MetadataToken); var methodFinishedSignature = typeof(TracingAnalyzer).Module.ResolveSignature(typeof(TracingAnalyzer).GetMethod("MethodFinished", BindingFlags.Public | BindingFlags.Static).MetadataToken); int startIndex = 0; methodBody.Instructions.Insert(startIndex++, Instruction.Create(IntPtr.Size == 4 ? OpCodes.Ldc_I4 : OpCodes.Ldc_I8, IntPtr.Size == 4 ? (int)ticksReaderAddress : (long)ticksReaderAddress)); methodBody.Instructions.Insert(startIndex++, Instruction.Create(OpCodes.Calli, ticksReaderSignature)); methodBody.Instructions.Insert(startIndex++, Instruction.Create(OpCodes.Stloc, ticksLocalIndex)); methodBody.Instructions.Insert(startIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)functionId)); // [ ourMethod, functionId ] methodBody.Instructions.Insert(startIndex++, Instruction.Create(IntPtr.Size == 4 ? OpCodes.Ldc_I4 : OpCodes.Ldc_I8, IntPtr.Size == 4 ? (int)methodStartedAddress : (long)methodStartedAddress)); // [ ourMethod, functionId, funcAddr ] methodBody.Instructions.Insert(startIndex++, Instruction.Create(OpCodes.Calli, methodStartedSignature)); // [] var tryStartInstruction = methodBody.Instructions[startIndex]; Instruction tryEndInstruction; Instruction finallyStartInstruction; methodBody.Instructions.Insert(methodBody.Instructions.Count, finallyStartInstruction = tryEndInstruction = Instruction.Create(OpCodes.Ldc_I4, (int)functionId)); // [ functionId ] methodBody.Instructions.Insert(methodBody.Instructions.Count, Instruction.Create(IntPtr.Size == 4 ? OpCodes.Ldc_I4 : OpCodes.Ldc_I8, IntPtr.Size == 4 ? (int)ticksReaderAddress : (long)ticksReaderAddress)); // [ functionId, funcAddr ] methodBody.Instructions.Insert(methodBody.Instructions.Count, Instruction.Create(OpCodes.Calli, ticksReaderSignature)); // [ functionId, ticks ] methodBody.Instructions.Insert(methodBody.Instructions.Count, Instruction.Create(OpCodes.Ldloc, ticksLocalIndex)); // [ functionId, ticks, startTicks ] methodBody.Instructions.Insert(methodBody.Instructions.Count, Instruction.Create(OpCodes.Sub)); // [ functionId, elapsed ] methodBody.Instructions.Insert(methodBody.Instructions.Count, Instruction.Create(IntPtr.Size == 4 ? OpCodes.Ldc_I4 : OpCodes.Ldc_I8, IntPtr.Size == 4 ? (int)methodFinishedAddress : (long)methodFinishedAddress)); // [ functionId, elapsed, profilerOverhead , funcAddr ] methodBody.Instructions.Insert(methodBody.Instructions.Count, Instruction.Create(OpCodes.Calli, methodFinishedSignature)); // [] Instruction endFinallyInstruction; methodBody.Instructions.Insert(methodBody.Instructions.Count, endFinallyInstruction = Instruction.Create(OpCodes.Endfinally)); Instruction finallyEndInstruction; if(resultLocalIndex >= 0) { methodBody.Instructions.Insert(methodBody.Instructions.Count, finallyEndInstruction = Instruction.Create(OpCodes.Ldloc, resultLocalIndex)); methodBody.Instructions.Insert(methodBody.Instructions.Count, Instruction.Create(OpCodes.Ret)); } else methodBody.Instructions.Insert(methodBody.Instructions.Count, finallyEndInstruction = Instruction.Create(OpCodes.Ret)); ExceptionHandler newException = new ExceptionHandler(ExceptionHandlerType.Finally); newException.TryStart = tryStartInstruction; newException.TryEnd = tryEndInstruction; newException.HandlerStart = finallyStartInstruction; newException.HandlerEnd = finallyEndInstruction; methodBody.Instructions.Insert(methodBody.Instructions.IndexOf(tryEndInstruction), Instruction.Create(OpCodes.Leave, finallyEndInstruction)); methodBody.ExceptionHandlers.Add(newException); }
private void AddLocalVariables(MethodBody methodBody) { var rawSignature = methodBody.MethodSignature; var methodSignature = new SignatureReader(rawSignature).ReadAndParseMethodSignature(); if(hasReturnType) resultLocalIndex = methodBody.AddLocalVariable(methodSignature.ReturnTypeSignature).LocalIndex; ticksLocalIndex = methodBody.AddLocalVariable(typeof(long)).LocalIndex; }
public static byte *InstallTracing( [MarshalAs(UnmanagedType.LPWStr)] string assemblyName, [MarshalAs(UnmanagedType.LPWStr)] string moduleName, UIntPtr moduleId, uint methodToken, byte *rawMethodBody, [MarshalAs(UnmanagedType.FunctionPtr)] MethodBodyAllocator allocateForMethodBody) { var assembly = AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == assemblyName); var module = assembly.GetModules().First(m => !m.Assembly.IsDynamic && m.FullyQualifiedName == moduleName); var method = module.ResolveMethod((int)methodToken); if (method.IsConstructor) { return(null); } var methodBody = MethodBody.Read(rawMethodBody, module, new MetadataToken(methodToken), false); if (methodBody.Instructions.Count < 20) { return(null); } var curMethodId = Interlocked.Increment(ref methodId) - 1; methods[curMethodId] = $"TRACING: {Format(method)}"; methodBody.Instructions.Insert(0, Instruction.Create(OpCodes.Ldc_I4, curMethodId)); if (IntPtr.Size == 4) { methodBody.Instructions.Insert(1, Instruction.Create(OpCodes.Ldc_I4, debugOutputAddress.ToInt32())); } else { methodBody.Instructions.Insert(1, Instruction.Create(OpCodes.Ldc_I8, debugOutputAddress.ToInt64())); } methodBody.Instructions.Insert(2, Instruction.Create(OpCodes.Calli, signatureTokenBuilder(moduleId, debugOutputSignature))); var methodBytes = methodBody.GetFullMethodBody(sig => signatureTokenBuilder(moduleId, sig), Math.Max(methodBody.MaxStack, 2)); var newMethodBody = allocateForMethodBody(moduleId, (uint)methodBytes.Length); Marshal.Copy(methodBytes, 0, (IntPtr)newMethodBody, methodBytes.Length); return(newMethodBody); }
private static Func <T, TResult> Clone(Func <T, TResult> func) { var body = MethodBody.Read(func.Method, true); foreach (var instruction in body.Instructions) { switch (instruction.OpCode.Code) { case Code.Ldarg_0: throw new InvalidOperationException(String.Format("Method '{0}' has different signature", Formatter.Format(func.Method))); case Code.Ldarg_1: instruction.OpCode = OpCodes.Ldarg_0; break; case Code.Ldarg_2: instruction.OpCode = OpCodes.Ldarg_1; break; } } return(body.CreateDelegate <Func <T, TResult> >()); }
public static void Main(string[] args) { var method = typeof(FileStream).GetMethod("Init", BindingFlags.Instance | BindingFlags.NonPublic); var body = MethodBody.Read(method, true); body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldarg_1)); var debugWriteLineMethod = typeof(Debug).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string) }, null); body.Instructions.Insert(1, Instruction.Create(OpCodes.Call, debugWriteLineMethod)); Console.WriteLine(body); var parameterTypes = new [] { method.DeclaringType }.Concat(method.GetParameters().Select(p => p.ParameterType)).ToArray(); var del = body.CreateDelegate(method.ReturnType, parameterTypes); Action unhook; if (!MethodUtil.HookMethod(method, del.Method, out unhook)) { throw new InvalidOperationException("Unable to hook method"); } File.WriteAllText(@"c:\temp\test.txt", "test"); using (var mock = new Mock <int, int[]>(x => DataReader.Read(x))) { //mock.Set(MockedMethod); mock.Set(x => { if (x == 42) { return new[] { 1, 4, 7, 8 } } ; throw new InvalidOperationException(); }); var dataProcessor = new DataProcessor(); Assert.AreEqual(5, dataProcessor.FindAverage(42)); } }
public static void HookDevenv() { var method = typeof(FileStream).GetMethod("Init", BindingFlags.Instance | BindingFlags.NonPublic); var body = MethodBody.Read(method, true); body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldstr, "TRACING: ")); body.Instructions.Insert(1, Instruction.Create(OpCodes.Ldarg_1)); var stringConcatMethod = typeof(string).GetMethod("Concat", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(string) }, null); body.Instructions.Insert(2, Instruction.Create(OpCodes.Call, stringConcatMethod)); var debugWriteLineMethod = typeof(Debug).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string) }, null); body.Instructions.Insert(3, Instruction.Create(OpCodes.Call, debugWriteLineMethod)); var parameterTypes = new[] { method.DeclaringType }.Concat(method.GetParameters().Select(p => p.ParameterType)).ToArray(); del = body.CreateDelegate(method.ReturnType, parameterTypes); Action unhook; if (!MethodUtil.HookMethod(method, del.Method, out unhook)) { Debug.WriteLine("Unable to hook method"); } }
public static void HookMinesweeper() { var assembly = GetAssembly("Minesweeper"); var form1 = GetType(assembly, "Minesweeper.Form1"); var mouseDownMethod = GetPrivateMethod(form1, "Form1_MouseDown"); var mouseMoveMethod = GetPrivateMethod(form1, "Form1_MouseMove"); var gameStartedField = GetPrivateField(form1, "gameStarted"); var fieldField = GetPrivateField(form1, "field"); var getMethod = GetPublicMethod(fieldField.FieldType, "Get"); var cellType = GetType(assembly, "Minesweeper.Cell"); var cellTypeProp = GetPublicProperty(cellType, "Type"); var cellTypeGetter = cellTypeProp.GetGetMethod(); var cellHasMineProp = GetPublicProperty(cellType, "HasMine"); var cellHasMineGetter = cellHasMineProp.GetGetMethod(); var flagMineMethod = GetPrivateMethod(form1, "FlagMine"); var openNeighboursMethod = GetPrivateMethod(form1, "OpenNeighbours"); var mouseMoveBody = MethodBody.Read(mouseMoveMethod, true); var instructions = mouseMoveBody.Instructions; instructions.Clear(); mouseMoveBody.AddLocalVariable(typeof(int)); mouseMoveBody.AddLocalVariable(typeof(int)); var lastInstr = Instruction.Create(OpCodes.Nop); var mouseDownBody = MethodBody.Read(mouseDownMethod, true); for (int i = 0; i < 44; ++i) { var instruction = mouseDownBody.Instructions[i]; if (i == 42) { instruction.Operand = lastInstr; } instructions.Add(instruction); } instructions.Add(lastInstr); mouseMoveBody.AddLocalVariable(cellType); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Ldfld, gameStartedField)); var gameStartedInstr = Instruction.Create(OpCodes.Nop); instructions.Add(Instruction.Create(OpCodes.Brtrue, gameStartedInstr)); instructions.Add(Instruction.Create(OpCodes.Ret)); instructions.Add(gameStartedInstr); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Ldfld, fieldField)); instructions.Add(Instruction.Create(OpCodes.Ldloc_0)); instructions.Add(Instruction.Create(OpCodes.Ldloc_1)); instructions.Add(Instruction.Create(OpCodes.Callvirt, getMethod)); instructions.Add(Instruction.Create(OpCodes.Stloc_2)); instructions.Add(Instruction.Create(OpCodes.Ldloc_2)); instructions.Add(Instruction.Create(OpCodes.Call, cellTypeGetter)); var cellUnopenedInstr = Instruction.Create(OpCodes.Nop); instructions.Add(Instruction.Create(OpCodes.Brfalse, cellUnopenedInstr)); instructions.Add(Instruction.Create(OpCodes.Ret)); instructions.Add(cellUnopenedInstr); var hasMineInstr = Instruction.Create(OpCodes.Nop); instructions.Add(Instruction.Create(OpCodes.Ldloc_2)); instructions.Add(Instruction.Create(OpCodes.Call, cellHasMineGetter)); instructions.Add(Instruction.Create(OpCodes.Brtrue, hasMineInstr)); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Ldloc_0)); instructions.Add(Instruction.Create(OpCodes.Ldloc_1)); instructions.Add(Instruction.Create(OpCodes.Call, openNeighboursMethod)); instructions.Add(Instruction.Create(OpCodes.Ret)); instructions.Add(hasMineInstr); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Ldloc_0)); instructions.Add(Instruction.Create(OpCodes.Ldloc_1)); instructions.Add(Instruction.Create(OpCodes.Call, flagMineMethod)); instructions.Add(Instruction.Create(OpCodes.Ret)); var parameterTypes = new[] { mouseMoveMethod.DeclaringType }.Concat(mouseMoveMethod.GetParameters().Select(p => p.ParameterType)).ToArray(); del = mouseMoveBody.CreateDelegate(mouseMoveMethod.ReturnType, parameterTypes); Action unhook; if (!MethodUtil.HookMethod(mouseMoveMethod, del.Method, out unhook)) { Debug.WriteLine("Unable to hook MouseMove"); } }
public static void Hook() { var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName.StartsWith("JetBrains.ReSharper.NewRefactorings")); if (assembly == null) { Debug.WriteLine("Assembly 'JetBrains.ReSharper.NewRefactorings' is not found"); return; } var type = assembly.GetType("JetBrains.ReSharper.Refactorings.Rename.Impl.InlineRenameWorkflow"); if (type == null) { Debug.WriteLine("Type 'JetBrains.ReSharper.Refactorings.Rename.Impl.InlineRenameWorkflow' is not found"); return; } var preExecute = type.GetMethod("PreExecute", BindingFlags.Instance | BindingFlags.Public); if (preExecute == null) { Debug.WriteLine("Method 'JetBrains.ReSharper.Refactorings.Rename.Impl.InlineRenameWorkflow.PreExecute' is not found"); return; } var body = MethodBody.Read(preExecute, true); //body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldstr, "ZZZ")); //var debugWriteLineMethod = typeof(Debug).GetMethod("WriteLine", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string) }, null); //body.Instructions.Insert(1, Instruction.Create(OpCodes.Call, debugWriteLineMethod)); var startInstr = body.Instructions.FirstOrDefault(instr => instr.OpCode == OpCodes.Ldstr && (string)instr.Operand == "name"); if (startInstr == null) { Debug.WriteLine("Instruction ldstr 'name' is not found"); return; } var startInstrIndex = body.Instructions.IndexOf(startInstr); var nextInstr = body.Instructions[startInstrIndex + 1]; if (nextInstr.OpCode != OpCodes.Ldloc_S) { Debug.WriteLine("Instruction ldloc.s is not found"); return; } var locIndex = (int)nextInstr.Operand; var zassembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName.StartsWith("JetBrains.ReSharper.Feature.Services")); if (zassembly == null) { Debug.WriteLine("Assembly 'JetBrains.ReSharper.Feature.Services' is not found"); return; } var NameSuggestionsExpression_t = zassembly.GetType("JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots.NameSuggestionsExpression"); if (NameSuggestionsExpression_t == null) { Debug.WriteLine("Type 'JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots.NameSuggestionsExpression' is not found"); return; } var constructor = NameSuggestionsExpression_t.GetConstructor(new [] { typeof(ICollection <string>) }); if (constructor == null) { Debug.WriteLine("Method 'JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots.NameSuggestionsExpression.ctor' is not found"); return; } body.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Ldc_I4_1)); body.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Newarr, typeof(string))); body.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Dup)); body.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Ldc_I4_0)); body.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Ldstr, "zzz")); body.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Stelem_Ref)); body.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Newobj, constructor)); body.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Stloc_S, locIndex)); var parameterTypes = new[] { preExecute.DeclaringType }.Concat(preExecute.GetParameters().Select(p => p.ParameterType)).ToArray(); del = body.CreateDelegate(preExecute.ReturnType, parameterTypes); Action unhook; if (!MethodUtil.HookMethod(preExecute, del.Method, out unhook)) { Debug.WriteLine("Unable to hook PreExecute"); } //var createAndExecute = type.GetMethod("CreateAndExecuteHotspotSession", BindingFlags.Instance | BindingFlags.NonPublic); //if (createAndExecute == null) //{ // Debug.WriteLine("Method 'JetBrains.ReSharper.Refactorings.Rename.Impl.InlineRenameWorkflow.CreateAndExecuteHotspotSession' is not found"); // return; //} //var body2 = MethodBody.Read(createAndExecute, true); //var hotspotSession = zassembly.GetType("JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots.HotspotSession"); //if (hotspotSession == null) //{ // Debug.WriteLine("Type 'JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots.HotspotSession' is not found"); // return; //} //var execute = hotspotSession.GetMethod("Execute", BindingFlags.Instance | BindingFlags.Public); //if (execute == null) //{ // Debug.WriteLine("Method 'JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots.HotspotSession.Execute' is not found"); // return; //} //var startSession = hotspotSession.GetMethod("StartSession", BindingFlags.Instance | BindingFlags.NonPublic); //if (startSession == null) //{ // Debug.WriteLine("Method 'JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots.HotspotSession.StartSession' is not found"); // return; //} //var endSession = hotspotSession.GetMethod("EndSession", BindingFlags.Instance | BindingFlags.Public); //if (endSession == null) //{ // Debug.WriteLine("Method 'JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots.HotspotSession.EndSession' is not found"); // return; //} //var zinstr = body2.Instructions.FirstOrDefault(instr => instr.OpCode == OpCodes.Callvirt && (MethodInfo)instr.Operand == execute); //if(zinstr == null) //{ // Debug.WriteLine("Instruction callvirt HotspotSession.Execute is not found"); // return; //} //startInstrIndex = body2.Instructions.IndexOf(zinstr) - 1; ////body2.Instructions[startInstrIndex] = Instruction.Create(OpCodes.Dup); //body2.Instructions[++startInstrIndex] = Instruction.Create(OpCodes.Call, startSession); //body2.Instructions[++startInstrIndex] = Instruction.Create(OpCodes.Nop); ////body2.Instructions[++startInstrIndex] = Instruction.Create(OpCodes.Ldc_I4_2); ////body2.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Callvirt, endSession)); ////body2.Instructions[startInstrIndex] = Instruction.Create(OpCodes.Pop); ////body2.Instructions[++startInstrIndex] = Instruction.Create(OpCodes.Nop); ////body2.Instructions[++startInstrIndex] = Instruction.Create(OpCodes.Nop); ////body2.Instructions.Insert(++startInstrIndex, Instruction.Create(OpCodes.Callvirt, endSession)); ////var count = body2.Instructions.Count; ////for(int i = 0; i < count; ++i) //// body2.Instructions.RemoveAt(0); ////body2.Instructions.Insert(0, Instruction.Create(OpCodes.Ret)); ////body2.ExceptionHandlers.Clear(); //body2.Seal(); //Debug.WriteLine(body2); //var parameterTypes2 = new[] { createAndExecute.DeclaringType }.Concat(createAndExecute.GetParameters().Select(p => p.ParameterType)).ToArray(); //del2 = body2.CreateDelegate(createAndExecute.ReturnType, parameterTypes2); //Action unhook2; //if(!MethodUtil.HookMethod(createAndExecute, del2.Method, out unhook2)) // Debug.WriteLine("Unable to hook CreateAndExecute"); }
public void Read(MethodBody body) { this.body = body; ReadCode(); }
public static void Read(byte[] buffer, Func <MetadataToken, object> tokenResolver, bool resolveTokens, MethodBody body) { fixed(byte *b = &buffer[0]) new ILCodeReader(b, buffer.Length, tokenResolver, resolveTokens).Read(body); }