Created
September 2, 2010 18:37
-
-
Save kumpera/562697 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Mono.Cecil; | |
using Mono.Cecil.Cil; | |
public class Driver { | |
public static void Main () { | |
new Weaver ("sample.exe").Weave (); | |
} | |
} | |
public class Weaver { | |
AssemblyDefinition ad; | |
ModuleDefinition module; | |
public Weaver (string str) { | |
this.ad = AssemblyDefinition.ReadAssembly ("sample.exe"); | |
this.module = ad.MainModule; | |
} | |
public void Weave () { | |
foreach (var type in module.Types) | |
ProcessType (type); | |
ad.Write ("res.exe"); | |
Console.WriteLine ("done"); | |
} | |
void ProcessType (TypeDefinition type) { | |
Console.WriteLine ("\n\n------ {0}--------", type); | |
foreach (var method in type.Methods) | |
ProcessMethod (method); | |
} | |
void ProcessMethod (MethodDefinition method) { | |
Console.WriteLine ("\n**{0}", method); | |
if (!method.HasBody) | |
return; | |
var processor = method.Body.GetILProcessor(); | |
var ins = method.Body.Instructions [0]; | |
for (; ins != null; ins = ins.Next) { | |
//Console.WriteLine("\t{0}", ins.GetType ()); | |
switch (ins.OpCode.FlowControl) { | |
case FlowControl.Call: | |
MethodReference mr = (MethodReference)ins.Operand; | |
Console.WriteLine ("ref: {0}", mr); | |
if (IsInteresting (mr)) | |
RecordOp (method, processor, ins); | |
break; | |
} | |
} | |
} | |
void RecordOp (MethodDefinition method, ILProcessor processor, Instruction ins) { | |
Console.WriteLine ("recording {0}", ins); | |
MethodReference mr = (MethodReference)ins.Operand; | |
var mparams = mr.Parameters; | |
//1 save args | |
VariableDefinition[] vars = new VariableDefinition [mparams.Count]; | |
for (int i = mparams.Count - 1; i >= 0; --i) { | |
var param = mparams [i]; | |
VariableDefinition local = vars [i] = new VariableDefinition (param.ParameterType); | |
method.Body.Variables.Add (local); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Stloc, local)); | |
} | |
var paramArr = new VariableDefinition (module.Import (typeof (object[]))); | |
method.Body.Variables.Add (paramArr); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Ldc_I4, mparams.Count)); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Newarr, module.Import (typeof (object[])))); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Stloc, paramArr)); | |
for (int i = 0; i < mparams.Count; ++i) { | |
processor.InsertBefore (ins, processor.Create (OpCodes.Ldloc, paramArr)); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Ldc_I4, i)); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Ldloc, vars [i])); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Box, vars [i].VariableType)); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Stelem_Ref)); | |
} | |
VariableDefinition thisVal = null; | |
if (ins.OpCode != OpCodes.Newobj && mr.HasThis) { | |
thisVal = new VariableDefinition (mr.DeclaringType); | |
method.Body.Variables.Add (thisVal); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Stloc, thisVal)); | |
processor.InsertBefore (ins, processor.Create (OpCodes.Ldloc, thisVal)); | |
} | |
for (int i = 0; i < mparams.Count; ++i) { | |
processor.InsertBefore (ins, processor.Create (OpCodes.Ldloc, vars [i])); | |
} | |
//2 - save result | |
Instruction lastIns = ins; | |
VariableDefinition retVal = null; | |
if (!IsVoid (mr.ReturnType) || ins.OpCode == OpCodes.Newobj) { | |
retVal = new VariableDefinition (ins.OpCode == OpCodes.Newobj ? mr.DeclaringType : mr.ReturnType); | |
method.Body.Variables.Add (retVal); | |
processor.InsertAfter (ins, lastIns = processor.Create (OpCodes.Stloc, retVal)); | |
} | |
//3 log | |
if (ins.OpCode == OpCodes.Newobj) { | |
var trace = typeof (Tracer).GetMethod ("TraceNewObject"); | |
var m = module.Import (trace); | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Ldloc, retVal)); | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Ldloc, paramArr)); | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Call, m)); | |
} else { | |
//public static void TraceCall (object me, string name, object ret, object[] args) { | |
var trace = typeof (Tracer).GetMethod ("TraceCall"); | |
var m = module.Import (trace); | |
if (thisVal != null) | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Ldloc, thisVal)); | |
else | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Ldnull)); | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Ldstr, mr.Name)); | |
if (retVal != null) | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Ldloc, retVal)); | |
else | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Ldnull)); | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Ldloc, paramArr)); | |
processor.InsertAfter (lastIns, lastIns = processor.Create (OpCodes.Call, m)); | |
} | |
//4 - restore result | |
if (!IsVoid (mr.ReturnType) || ins.OpCode == OpCodes.Newobj) { | |
processor.InsertAfter (lastIns, processor.Create (OpCodes.Ldloc, retVal)); | |
} | |
} | |
bool IsVoid (TypeReference type) { | |
return type.Namespace == "System" && type.Name == "Void"; | |
} | |
bool IsInteresting (MethodReference method) { | |
if (method.DeclaringType.Scope.Name != "mscorlib") | |
return false; | |
/*if (IsInteresting (method.DeclaringType)) | |
Console.WriteLine ("\ttarget"); | |
if (IsInteresting (method.ReturnType)) | |
Console.WriteLine ("\treturn"); | |
foreach (var p in method.Parameters) { | |
if (IsInteresting (p.ParameterType)) | |
Console.WriteLine ("\tparam {0}", p.Index); | |
}*/ | |
if (IsInteresting (method.DeclaringType)) | |
return true; | |
if (IsInteresting (method.ReturnType)) | |
return true; | |
foreach (var p in method.Parameters) { | |
if (IsInteresting (p.ParameterType)) | |
return true; | |
} | |
return false; | |
} | |
bool IsInteresting (TypeReference type) { | |
if (type.Namespace == "System.Reflection" || type.Namespace == "System.Reflection.Emit") | |
return true; | |
if (type.Namespace == "System" && type.Name == "Type") | |
return true; | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment