public void EmulateUntil(Instruction instruction, CilBody body, Instruction starter) { Snapshots.Add(new Snapshot(new Stack<StackEntry>(Stack), new Dictionary<int, LocalEntry>(_locals), instruction, _methodBody, null)); _instructionPointer = starter.GetInstructionIndex(body.Instructions) - 1; Trace(() => _methodBody.Instructions[_instructionPointer] != instruction); }
public static bool FollowsPattern( this Instruction instr, CilBody body, out Instruction ender, List<Predicate<Instruction>> preds, int minPatternSize, out int patternSize) { var curInstr = instr; ender = null; var correct = 0; patternSize = 0; while (curInstr.Next(body) != null && preds.Any(p => p(curInstr.Next(body)))) { curInstr = curInstr.Next(body); correct++; } if (correct >= minPatternSize) { patternSize = correct + 1; ender = curInstr; return true; } return false; }
public void Init(CilBody body) { if (inited) return; xorKey = ctx.Random.NextInt32(); inited = true; }
public void Commit(CilBody body) { foreach (Local i in localMap.Values) { body.InitLocals = true; body.Variables.Add(i); } }
public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx) { body.MaxStack++; foreach (InstrBlock block in GetAllBlocks(root)) { LinkedList<Instruction[]> fragments = SpiltFragments(block, ctx); if (fragments.Count < 4) continue; LinkedListNode<Instruction[]> current = fragments.First; while (current.Next != null) { var newFragment = new List<Instruction>(current.Value); ctx.AddJump(newFragment, current.Next.Value[0]); ctx.AddJunk(newFragment); current.Value = newFragment.ToArray(); current = current.Next; } Instruction[] first = fragments.First.Value; fragments.RemoveFirst(); Instruction[] last = fragments.Last.Value; fragments.RemoveLast(); List<Instruction[]> newFragments = fragments.ToList(); ctx.Random.Shuffle(newFragments); block.Instructions = first .Concat(newFragments.SelectMany(fragment => fragment)) .Concat(last).ToList(); } }
public static IEnumerable<Instruction> FindAllReferences(this Instruction instr, CilBody body) { foreach (var @ref in body.Instructions.Where(x => (x.IsConditionalBranch() || x.IsBr()))) { if ((@ref.Operand as Instruction) == instr) yield return @ref; } }
public void Init(CilBody body) { if (inited) return; stateVar = new Local(ctx.Method.Module.CorLibTypes.Int32); body.Variables.Add(stateVar); body.InitLocals = true; Compile(body); inited = true; }
public static void Run() { // Create a new module. The string passed in is the name of the module, // not the file name. ModuleDef mod = new ModuleDefUser("MyModule.exe"); // It's a console application mod.Kind = ModuleKind.Console; // Add the module to an assembly AssemblyDef asm = new AssemblyDefUser("MyAssembly", new Version(1, 2, 3, 4), null, null); asm.Modules.Add(mod); // Add a .NET resource byte[] resourceData = Encoding.UTF8.GetBytes("Hello, world!"); mod.Resources.Add(new EmbeddedResource("My.Resource", resourceData, ManifestResourceAttributes.Private)); // Add the startup type. It derives from System.Object. TypeDef startUpType = new TypeDefUser("My.Namespace", "Startup", mod.CorLibTypes.Object.TypeDefOrRef); startUpType.Attributes = TypeAttributes.NotPublic | TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.AnsiClass; // Add the type to the module mod.Types.Add(startUpType); // Create the entry point method MethodDef entryPoint = new MethodDefUser("Main", MethodSig.CreateStatic(mod.CorLibTypes.Int32, new SZArraySig(mod.CorLibTypes.String))); entryPoint.Attributes = MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot; entryPoint.ImplAttributes = MethodImplAttributes.IL | MethodImplAttributes.Managed; // Name the 1st argument (argument 0 is the return type) entryPoint.ParamDefs.Add(new ParamDefUser("args", 1)); // Add the method to the startup type startUpType.Methods.Add(entryPoint); // Set module entry point mod.EntryPoint = entryPoint; // Create a TypeRef to System.Console TypeRef consoleRef = new TypeRefUser(mod, "System", "Console", mod.CorLibTypes.AssemblyRef); // Create a method ref to 'System.Void System.Console::WriteLine(System.String)' MemberRef consoleWrite1 = new MemberRefUser(mod, "WriteLine", MethodSig.CreateStatic(mod.CorLibTypes.Void, mod.CorLibTypes.String), consoleRef); // Add a CIL method body to the entry point method CilBody epBody = new CilBody(); entryPoint.Body = epBody; epBody.Instructions.Add(OpCodes.Ldstr.ToInstruction("Hello World!")); epBody.Instructions.Add(OpCodes.Call.ToInstruction(consoleWrite1)); epBody.Instructions.Add(OpCodes.Ldc_I4_0.ToInstruction()); epBody.Instructions.Add(OpCodes.Ret.ToInstruction()); // Save the assembly to a file on disk mod.Write(@"C:\saved-assembly.exe"); }
// This will open the current assembly, add a new class and method to it, // and then save the assembly to disk. public static void Run() { // Open the current module ModuleDefMD mod = ModuleDefMD.Load(typeof(Example2).Module); // Create a new public class that derives from System.Object TypeDef type1 = new TypeDefUser("My.Namespace", "MyType", mod.CorLibTypes.Object.TypeDefOrRef); type1.Attributes = TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.Class | TypeAttributes.AnsiClass; // Make sure to add it to the module or any other type in the module. This is // not a nested type, so add it to mod.Types. mod.Types.Add(type1); // Create a public static System.Int32 field called MyField FieldDef field1 = new FieldDefUser("MyField", new FieldSig(mod.CorLibTypes.Int32), FieldAttributes.Public | FieldAttributes.Static); // Add it to the type we created earlier type1.Fields.Add(field1); // Add a static method that adds both inputs and the static field // and returns the result MethodImplAttributes methImplFlags = MethodImplAttributes.IL | MethodImplAttributes.Managed; MethodAttributes methFlags = MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot; MethodDef meth1 = new MethodDefUser("MyMethod", MethodSig.CreateStatic(mod.CorLibTypes.Int32, mod.CorLibTypes.Int32, mod.CorLibTypes.Int32), methImplFlags, methFlags); type1.Methods.Add(meth1); // Create the CIL method body CilBody body = new CilBody(); meth1.Body = body; // Name the 1st and 2nd args a and b, respectively meth1.ParamDefs.Add(new ParamDefUser("a", 1)); meth1.ParamDefs.Add(new ParamDefUser("b", 2)); // Create a local. We don't really need it but let's add one anyway Local local1 = new Local(mod.CorLibTypes.Int32); body.Variables.Add(local1); // Add the instructions, and use the useless local body.Instructions.Add(OpCodes.Ldarg_0.ToInstruction()); body.Instructions.Add(OpCodes.Ldarg_1.ToInstruction()); body.Instructions.Add(OpCodes.Add.ToInstruction()); body.Instructions.Add(OpCodes.Ldsfld.ToInstruction(field1)); body.Instructions.Add(OpCodes.Add.ToInstruction()); body.Instructions.Add(OpCodes.Stloc.ToInstruction(local1)); body.Instructions.Add(OpCodes.Ldloc.ToInstruction(local1)); body.Instructions.Add(OpCodes.Ret.ToInstruction()); // Save the assembly to a file on disk mod.Write(@"C:\saved-assembly.dll"); }
public void Init(CilBody body) { if (inited) return; encoding = ctx.Context.Annotations.Get<x86Encoding>(ctx.Method.DeclaringType, Encoding, null); if (encoding == null) { encoding = new x86Encoding(); encoding.Compile(ctx); ctx.Context.Annotations.Set(ctx.Method.DeclaringType, Encoding, encoding); } inited = true; }
public CilBodyOptions(CilBody body, RVA rva, FileOffset fileOffset) { this.KeepOldMaxStack = body.KeepOldMaxStack; this.InitLocals = body.InitLocals; this.MaxStack = body.MaxStack; this.LocalVarSigTok = body.LocalVarSigTok; this.RVA = rva; this.FileOffset = fileOffset; this.Instructions.AddRange(body.Instructions); this.ExceptionHandlers.AddRange(body.ExceptionHandlers); this.Locals.AddRange(body.Variables); this.Scope = body.Scope; }
private ControlFlowGraphBuilder(CilBody methodBody) { this.methodBody = methodBody; offsets = methodBody.Instructions.Select(i => i.Offset).ToArray(); hasIncomingJumps = new bool[methodBody.Instructions.Count]; entryPoint = new ControlFlowNode(0, 0, ControlFlowNodeType.EntryPoint); nodes.Add(entryPoint); regularExit = new ControlFlowNode(1, null, ControlFlowNodeType.RegularExit); nodes.Add(regularExit); exceptionalExit = new ControlFlowNode(2, null, ControlFlowNodeType.ExceptionalExit); nodes.Add(exceptionalExit); Debug.Assert(nodes.Count == 3); }
void Compile(RPContext ctx, CilBody body, out Func<int, int> expCompiled, out Expression inverse) { var var = new Variable("{VAR}"); var result = new Variable("{RESULT}"); Expression expression; ctx.DynCipher.GenerateExpressionPair( ctx.Random, new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, ctx.Depth, out expression, out inverse); expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) .GenerateCIL(expression) .Compile<Func<int, int>>(); }
public CilBodyOptions(CilBody body, RVA headerRva, FileOffset headerFileOffset, RVA rva, FileOffset fileOffset) { KeepOldMaxStack = body.KeepOldMaxStack; InitLocals = body.InitLocals; HeaderSize = body.HeaderSize; MaxStack = body.MaxStack; LocalVarSigTok = body.LocalVarSigTok; HeaderRVA = headerRva; HeaderFileOffset = headerFileOffset; RVA = rva; FileOffset = fileOffset; Instructions.AddRange(body.Instructions); ExceptionHandlers.AddRange(body.ExceptionHandlers); Locals.AddRange(body.Variables); Scope = body.Scope; }
public CilBody CopyTo(CilBody body) { body.KeepOldMaxStack = KeepOldMaxStack; body.InitLocals = InitLocals; body.HeaderSize = HeaderSize; body.MaxStack = MaxStack; body.LocalVarSigTok = LocalVarSigTok; body.Instructions.Clear(); body.Instructions.AddRange(Instructions); body.ExceptionHandlers.Clear(); body.ExceptionHandlers.AddRange(ExceptionHandlers); body.Variables.Clear(); body.Variables.AddRange(this.Locals); body.Scope = this.Scope; body.UpdateInstructionOffsets(); return body; }
public ILStructure(CilBody body) : this(ILStructureType.Root, 0, body.GetCodeSize()) { // Build the tree of exception structures: for (int i = 0; i < body.ExceptionHandlers.Count; i++) { ExceptionHandler eh = body.ExceptionHandlers[i]; if (!body.ExceptionHandlers.Take(i).Any(oldEh => oldEh.TryStart == eh.TryStart && oldEh.TryEnd == eh.TryEnd)) AddNestedStructure(new ILStructure(ILStructureType.Try, (int)eh.TryStart.GetOffset(), (int)eh.TryEnd.GetOffset(), eh)); if (eh.HandlerType == ExceptionHandlerType.Filter) AddNestedStructure(new ILStructure(ILStructureType.Filter, (int)eh.FilterStart.GetOffset(), (int)eh.HandlerStart.GetOffset(), eh)); AddNestedStructure(new ILStructure(ILStructureType.Handler, (int)eh.HandlerStart.GetOffset(), eh.HandlerEnd == null ? body.GetCodeSize() : (int)eh.HandlerEnd.GetOffset(), eh)); } // Very simple loop detection: look for backward branches List<KeyValuePair<Instruction, Instruction>> allBranches = FindAllBranches(body); // We go through the branches in reverse so that we find the biggest possible loop boundary first (think loops with "continue;") for (int i = allBranches.Count - 1; i >= 0; i--) { int loopEnd = allBranches[i].Key.GetEndOffset(); int loopStart = (int)allBranches[i].Value.Offset; if (loopStart < loopEnd) { // We found a backward branch. This is a potential loop. // Check that is has only one entry point: Instruction entryPoint = null; // entry point is first instruction in loop if prev inst isn't an unconditional branch Instruction prev = body.GetPrevious(allBranches[i].Value); if (prev != null && !OpCodeInfo.IsUnconditionalBranch(prev.OpCode)) entryPoint = allBranches[i].Value; bool multipleEntryPoints = false; foreach (var pair in allBranches) { if (pair.Key.Offset < loopStart || pair.Key.Offset >= loopEnd) { if (loopStart <= pair.Value.Offset && pair.Value.Offset < loopEnd) { // jump from outside the loop into the loop if (entryPoint == null) entryPoint = pair.Value; else if (pair.Value != entryPoint) multipleEntryPoints = true; } } } if (!multipleEntryPoints) { AddNestedStructure(new ILStructure(ILStructureType.Loop, loopStart, loopEnd, entryPoint)); } } } SortChildren(); }
void Compile(CilBody body) { var var = new Variable("{VAR}"); var result = new Variable("{RESULT}"); ctx.DynCipher.GenerateExpressionPair( ctx.Random, new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, ctx.Depth, out expression, out inverse); expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) .GenerateCIL(expression) .Compile<Func<int, int>>(); invCompiled = new List<Instruction>(); new CodeGen(stateVar, ctx, invCompiled).GenerateCIL(inverse); body.MaxStack += (ushort)ctx.Depth; }
public override void ToBody(CilBody body) { if (Type != BlockType.Normal) { if (Type == BlockType.Try) { Handler.TryStart = GetFirstInstr(); Handler.TryEnd = GetLastInstr(); } else if (Type == BlockType.Filter) { Handler.FilterStart = GetFirstInstr(); } else { Handler.HandlerStart = GetFirstInstr(); Handler.HandlerEnd = GetLastInstr(); } } foreach (BlockBase block in Children) block.ToBody(body); }
public static void WriteTo(this Instruction instruction, MethodDef method, CilBody body, ITextOutput writer) { writer.WriteDefinition(dnlibExtensions.OffsetToString(instruction.Offset), instruction, true); writer.Write(": "); writer.WriteReference(instruction.OpCode.Name, instruction.OpCode, true); if (instruction.Operand != null) { writer.Write(' '); if (instruction.OpCode == OpCodes.Ldtoken) { if (dnlibExtensions.IsMethod(instruction.Operand)) writer.WriteKeyword("method "); else if (dnlibExtensions.IsField(instruction.Operand)) writer.WriteKeyword("field "); } WriteOperand(writer, instruction.Operand); } else if (method != null && body != null) { switch (instruction.OpCode.Code) { case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: writer.WriteComment(" // "); var local = instruction.GetLocal(body.Variables); if (local != null) WriteOperand(writer, local); break; case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: writer.WriteComment(" // "); var arg = instruction.GetParameter(method.Parameters); if (arg != null) WriteOperand(writer, arg); break; } } }
private static CilBody ToCil(MethodDef method, Body body, int index) { CilBody nm = new dnlib.DotNet.Emit.CilBody(); IList <Local> localVariables = method.Body.Variables.Locals; foreach (var localVariableInfo in localVariables) { nm.Variables.Locals.Add(localVariableInfo); } ConvertToDnBody(nm, body, index); foreach (dnlib.DotNet.Emit.Instruction lmao in nm.Instructions) { if (lmao.GetOperand() is TargetDisplOperand) { var t = (TargetDisplOperand)lmao.Operand; if (t.Displacement > 0) { lmao.Operand = nm.Instructions[t.Displacement]; } } } return(nm); }
private void ResolveBody(MethodDef methodDef, MosaMethod.Mutator method, CilBody body, GenericArgumentResolver resolver) { method.LocalVariables.Clear(); int index = 0; foreach (var variable in body.Variables) { method.LocalVariables.Add(new MosaLocal( variable.Name ?? "V_" + index, metadata.Loader.GetType(resolver.Resolve(variable.Type)), variable.Type.IsPinned)); index++; } method.ExceptionBlocks.Clear(); foreach (var eh in body.ExceptionHandlers) { method.ExceptionBlocks.Add(new MosaExceptionHandler( (ExceptionHandlerType)eh.HandlerType, ResolveOffset(body, eh.TryStart), ResolveOffset(body, eh.TryEnd), ResolveOffset(body, eh.HandlerStart), ResolveOffset(body, eh.HandlerEnd), eh.CatchType == null ? null : metadata.Loader.GetType(resolver.Resolve(eh.CatchType.ToTypeSig())), eh.FilterStart == null ? null : (int?)eh.FilterStart.Offset )); } method.MaxStack = methodDef.Body.MaxStack; method.Code.Clear(); for (int i = 0; i < body.Instructions.Count; i++) { method.Code.Add(ResolveInstruction(methodDef, body, i, resolver)); } }
private MosaInstruction ResolveInstruction(MethodDef methodDef, CilBody body, int index, GenericArgumentResolver resolver) { Instruction instruction = body.Instructions[index]; int? prev = index == 0 ? null : (int?)body.Instructions[index - 1].Offset; int? next = index == body.Instructions.Count - 1 ? null : (int?)body.Instructions[index + 1].Offset; object operand = instruction.Operand; // Special case: newarr instructions need to have their operand changed now so that the type is a SZArray if (instruction.OpCode == OpCodes.Newarr) { var typeSig = resolver.Resolve(((ITypeDefOrRef)instruction.Operand).ToTypeSig()); var szArraySig = new SZArraySig(typeSig); operand = metadata.Loader.GetType(szArraySig); } else if (instruction.Operand is ITypeDefOrRef) { operand = ResolveTypeOperand((ITypeDefOrRef)instruction.Operand, resolver); } else if (instruction.Operand is MemberRef) { MemberRef memberRef = (MemberRef)instruction.Operand; if (memberRef.IsFieldRef) operand = ResolveFieldOperand(memberRef, resolver); else operand = ResolveMethodOperand(memberRef, resolver); } else if (instruction.Operand is IField) { operand = ResolveFieldOperand((IField)instruction.Operand, resolver); } else if (instruction.Operand is IMethod) { operand = ResolveMethodOperand((IMethod)instruction.Operand, resolver); } else if (instruction.Operand is Local) { operand = ((Local)instruction.Operand).Index; } else if (instruction.Operand is Parameter) { operand = ((Parameter)instruction.Operand).Index; } else if (instruction.Operand is Instruction) { operand = (int)((Instruction)instruction.Operand).Offset; } else if (instruction.Operand is Instruction[]) { Instruction[] targets = (Instruction[])instruction.Operand; int[] offsets = new int[targets.Length]; for (int i = 0; i < offsets.Length; i++) offsets[i] = (int)targets[i].Offset; operand = offsets; } else if (instruction.Operand is string) { operand = metadata.Cache.GetStringId((string)instruction.Operand); } ushort code = (ushort)instruction.OpCode.Code; if (code > 0xff) // To match compiler's opcode values code = (ushort)(0x100 + (code & 0xff)); return new MosaInstruction((int)instruction.Offset, code, operand, prev, next); }
/// <summary> /// Creates a CIL body. Must be called after <see cref="Read()"/>, and can only be /// called once. /// </summary> /// <returns>A new <see cref="CilBody"/> instance</returns> public CilBody CreateCilBody() { // Set init locals if it's a tiny method or if the init locals bit is set (fat header) bool initLocals = flags == 2 || (flags & 0x10) != 0; var cilBody = new CilBody(initLocals, instructions, exceptionHandlers, locals); cilBody.MaxStack = maxStack; cilBody.LocalVarSigTok = localVarSigTok; instructions = null; exceptionHandlers = null; locals = null; return cilBody; }
private static int ResolveOffset(CilBody body, Instruction instruction) { if (instruction == null) { instruction = body.Instructions[body.Instructions.Count - 1]; return (int)(instruction.Offset + instruction.GetSize()); } else return (int)instruction.Offset; }
void Add(CilBody cb) { if (cb == null) return; Add(cb.Instructions); Add(cb.ExceptionHandlers); Add(cb.Variables); }
/// <summary> /// Updates <paramref name="body"/> with the PDB info (if any) /// </summary> /// <param name="body">Method body</param> /// <param name="rid">Method rid</param> /// <returns>Returns originak <paramref name="body"/> value</returns> CilBody InitializeBodyFromPdb(CilBody body, uint rid) { if (pdbState != null) pdbState.InitializeDontCall(body, rid); return body; }
/// <summary> /// Constructs a successful devirtualize attempt. /// </summary> /// <param name="vmethod">Virtualized method</param> /// <param name="reader">Method body reader</param> /// <param name="body">Devirtualized method body</param> public DevirtualizeAttempt(MethodStub vmethod, VirtualizedMethodBodyReader reader, CilBody body) { this.VirtualizedMethod = vmethod; this.Reader = reader; this.MethodBody = body; }
public Trace(CilBody body, bool hasReturnValue) { RefCount = new Dictionary<uint, int>(); BrRefs = new Dictionary<uint, List<Instruction>>(); BeforeStack = new Dictionary<uint, int>(); AfterStack = new Dictionary<uint, int>(); body.UpdateInstructionOffsets(); foreach (ExceptionHandler eh in body.ExceptionHandlers) { BeforeStack[eh.TryStart.Offset] = 0; BeforeStack[eh.HandlerStart.Offset] = (eh.HandlerType != ExceptionHandlerType.Finally ? 1 : 0); if (eh.FilterStart != null) BeforeStack[eh.FilterStart.Offset] = 1; } int currentStack = 0; for (int i = 0; i < body.Instructions.Count; i++) { var instr = body.Instructions[i]; if (BeforeStack.ContainsKey(instr.Offset)) currentStack = BeforeStack[instr.Offset]; BeforeStack[instr.Offset] = currentStack; instr.UpdateStack(ref currentStack, hasReturnValue); AfterStack[instr.Offset] = currentStack; uint offset; switch (instr.OpCode.FlowControl) { case FlowControl.Branch: offset = ((Instruction)instr.Operand).Offset; if (!BeforeStack.ContainsKey(offset)) BeforeStack[offset] = currentStack; Increment(RefCount, offset); BrRefs.AddListEntry(offset, instr); currentStack = 0; continue; case FlowControl.Call: if (instr.OpCode.Code == Code.Jmp) currentStack = 0; break; case FlowControl.Cond_Branch: if (instr.OpCode.Code == Code.Switch) { foreach (Instruction target in (Instruction[])instr.Operand) { if (!BeforeStack.ContainsKey(target.Offset)) BeforeStack[target.Offset] = currentStack; Increment(RefCount, target.Offset); BrRefs.AddListEntry(target.Offset, instr); } } else { offset = ((Instruction)instr.Operand).Offset; if (!BeforeStack.ContainsKey(offset)) BeforeStack[offset] = currentStack; Increment(RefCount, offset); BrRefs.AddListEntry(offset, instr); } break; case FlowControl.Meta: case FlowControl.Next: case FlowControl.Break: break; case FlowControl.Return: case FlowControl.Throw: continue; default: throw new UnreachableException(); } if (i + 1 < body.Instructions.Count) { offset = body.Instructions[i + 1].Offset; Increment(RefCount, offset); } } }
public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx) { Trace trace = new Trace(body, ctx.Method.ReturnType.RemoveModifiers().ElementType != ElementType.Void); var local = new Local(ctx.Method.Module.CorLibTypes.UInt32); body.Variables.Add(local); body.InitLocals = true; body.MaxStack += 2; IPredicate predicate = null; if (ctx.Predicate == PredicateType.Normal) { predicate = new NormalPredicate(ctx); } else if (ctx.Predicate == PredicateType.Expression) { predicate = new ExpressionPredicate(ctx); } else if (ctx.Predicate == PredicateType.x86) { predicate = new x86Predicate(ctx); } foreach (InstrBlock block in GetAllBlocks(root)) { LinkedList<Instruction[]> statements = SpiltStatements(block, trace, ctx); // Make sure .ctor is executed before switch if (ctx.Method.IsInstanceConstructor) { var newStatement = new List<Instruction>(); while (statements.First != null) { newStatement.AddRange(statements.First.Value); Instruction lastInstr = statements.First.Value.Last(); statements.RemoveFirst(); if (lastInstr.OpCode == OpCodes.Call && ((IMethod)lastInstr.Operand).Name == ".ctor") break; } statements.AddFirst(newStatement.ToArray()); } if (statements.Count < 3) continue; int i; var keyId = Enumerable.Range(0, statements.Count).ToArray(); ctx.Random.Shuffle(keyId); var key = new int[keyId.Length]; for (i = 0; i < key.Length; i++) { var q = ctx.Random.NextInt32() & 0x7fffffff; key[i] = q - q % statements.Count + keyId[i]; } var statementKeys = new Dictionary<Instruction, int>(); LinkedListNode<Instruction[]> current = statements.First; i = 0; while (current != null) { if (i != 0) statementKeys[current.Value[0]] = key[i]; i++; current = current.Next; } var statementLast = new HashSet<Instruction>(statements.Select(st => st.Last())); Func<IList<Instruction>, bool> hasUnknownSource; hasUnknownSource = instrs => instrs.Any(instr => { if (trace.HasMultipleSources(instr.Offset)) return true; List<Instruction> srcs; if (trace.BrRefs.TryGetValue(instr.Offset, out srcs)) { // Target of switch => assume unknown if (srcs.Any(src => src.Operand is Instruction[])) return true; // Not within current instruction block / targeted in first statement if (srcs.Any(src => src.Offset <= statements.First.Value.Last().Offset || src.Offset >= block.Instructions.Last().Offset)) return true; // Not targeted by the last of statements if (srcs.Any(src => statementLast.Contains(src))) return true; } return false; }); var switchInstr = new Instruction(OpCodes.Switch); var switchHdr = new List<Instruction>(); if (predicate != null) { predicate.Init(body); switchHdr.Add(Instruction.CreateLdcI4(predicate.GetSwitchKey(key[1]))); predicate.EmitSwitchLoad(switchHdr); } else { switchHdr.Add(Instruction.CreateLdcI4(key[1])); } switchHdr.Add(Instruction.Create(OpCodes.Dup)); switchHdr.Add(Instruction.Create(OpCodes.Stloc, local)); switchHdr.Add(Instruction.Create(OpCodes.Ldc_I4, statements.Count)); switchHdr.Add(Instruction.Create(OpCodes.Rem_Un)); switchHdr.Add(switchInstr); if (trace.BeforeStack[statements.Last.Value[0].Offset] == 0) { ctx.AddJump(switchHdr, statements.Last.Value[0]); } else { ctx.AddJump(switchHdr, switchHdr[0]); } ctx.AddJunk(switchHdr); var operands = new Instruction[statements.Count]; current = statements.First; i = 0; while (current.Next != null) { var newStatement = new List<Instruction>(current.Value); if (i != 0) { // Convert to switch bool converted = false; if (newStatement.Last().IsBr()) { // Unconditional var target = (Instruction)newStatement.Last().Operand; int brKey; if (!trace.IsBranchTarget(newStatement.Last().Offset) && statementKeys.TryGetValue(target, out brKey)) { if (trace.BeforeStack[target.Offset] == 0) { var targetKey = predicate != null ? predicate.GetSwitchKey(brKey) : brKey; var unkSrc = hasUnknownSource(newStatement); var initialBeforeStack = trace.BeforeStack[newStatement[0].Offset]; newStatement.RemoveAt(newStatement.Count - 1); if (unkSrc || initialBeforeStack != 0) { newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); } else { var thisKey = key[i]; var r = ctx.Random.NextInt32(); newStatement.Add(Instruction.Create(OpCodes.Ldloc, local)); newStatement.Add(Instruction.CreateLdcI4(r)); newStatement.Add(Instruction.Create(OpCodes.Mul)); newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey)); newStatement.Add(Instruction.Create(OpCodes.Xor)); } ctx.AddJump(newStatement, switchHdr[1]); ctx.AddJunk(newStatement); } if (trace.BeforeStack[newStatement[0].Offset] == 0) { operands[keyId[i]] = newStatement[0]; } converted = true; } } else if (newStatement.Last().IsConditionalBranch()) { // Conditional var target = (Instruction)newStatement.Last().Operand; int brKey; if (!trace.IsBranchTarget(newStatement.Last().Offset) && statementKeys.TryGetValue(target, out brKey)) { if (trace.BeforeStack[target.Offset] == 0) { bool unkSrc = hasUnknownSource(newStatement); int nextKey = key[i + 1]; OpCode condBr = newStatement.Last().OpCode; newStatement.RemoveAt(newStatement.Count - 1); if (ctx.Random.NextBoolean()) { condBr = InverseBranch(condBr); int tmp = brKey; brKey = nextKey; nextKey = tmp; } var thisKey = key[i]; int r = 0, xorKey = 0; if (!unkSrc) { r = ctx.Random.NextInt32(); xorKey = thisKey * r; } Instruction brKeyInstr = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(brKey) : brKey)); Instruction nextKeyInstr = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(nextKey) : nextKey)); Instruction pop = Instruction.Create(OpCodes.Pop); newStatement.Add(Instruction.Create(condBr, brKeyInstr)); newStatement.Add(nextKeyInstr); newStatement.Add(Instruction.Create(OpCodes.Dup)); newStatement.Add(Instruction.Create(OpCodes.Br, pop)); newStatement.Add(brKeyInstr); newStatement.Add(Instruction.Create(OpCodes.Dup)); newStatement.Add(pop); if (!unkSrc) { newStatement.Add(Instruction.Create(OpCodes.Ldloc, local)); newStatement.Add(Instruction.CreateLdcI4(r)); newStatement.Add(Instruction.Create(OpCodes.Mul)); newStatement.Add(Instruction.Create(OpCodes.Xor)); } ctx.AddJump(newStatement, switchHdr[1]); ctx.AddJunk(newStatement); converted = true; } if (trace.BeforeStack[newStatement[0].Offset] == 0) { operands[keyId[i]] = newStatement[0]; } } } if (!converted) { // Normal if (newStatement[newStatement.Count - 1].OpCode != OpCodes.Ret) { var nextStatement = current.Next; if (trace.BeforeStack[nextStatement.Value[0].Offset] == 0) { var targetKey = predicate != null ? predicate.GetSwitchKey(key[i + 1]) : key[i + 1]; if (!hasUnknownSource(newStatement) && trace.BeforeStack[newStatement[0].Offset] == 0) { var thisKey = key[i]; var r = ctx.Random.NextInt32(); newStatement.Add(Instruction.Create(OpCodes.Ldloc, local)); newStatement.Add(Instruction.CreateLdcI4(r)); newStatement.Add(Instruction.Create(OpCodes.Mul)); newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey*r) ^ targetKey)); newStatement.Add(Instruction.Create(OpCodes.Xor)); } else { newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); } ctx.AddJump(newStatement, switchHdr[1]); ctx.AddJunk(newStatement); } else { newStatement.Add(Instruction.Create(OpCodes.Br, nextStatement.Value[0])); } } if (trace.BeforeStack[newStatement[0].Offset] == 0) { operands[keyId[i]] = newStatement[0]; } } } else operands[keyId[i]] = switchHdr[0]; current.Value = newStatement.ToArray(); current = current.Next; i++; } if (trace.BeforeStack[current.Value[0].Offset] == 0) { operands[keyId[i]] = current.Value[0]; } for (i = 0; i < operands.Length; i++) { if (operands[i] == null) { operands[i] = switchHdr[0]; } } switchInstr.Operand = operands; Instruction[] first = statements.First.Value; statements.RemoveFirst(); Instruction[] last = statements.Last.Value; statements.RemoveLast(); List<Instruction[]> newStatements = statements.Where(s => trace.BeforeStack[s[0].Offset] == 0).ToList(); ctx.Random.Shuffle(newStatements); List<Instruction[]> newOrderedStatements = statements.Where(s => trace.BeforeStack[s[0].Offset] != 0).ToList(); block.Instructions.Clear(); block.Instructions.AddRange(first); block.Instructions.AddRange(switchHdr); foreach (var statement in newStatements) block.Instructions.AddRange(statement); foreach (var statement in newOrderedStatements) block.Instructions.AddRange(statement); block.Instructions.AddRange(last); } }
/// <summary> /// Finds all branches. Returns list of source offset->target offset mapping. /// Multiple entries for the same source offset are possible (switch statements). /// The result is sorted by source offset. /// </summary> List<KeyValuePair<Instruction, Instruction>> FindAllBranches(CilBody body) { var result = new List<KeyValuePair<Instruction, Instruction>>(); foreach (Instruction inst in body.Instructions) { switch (inst.OpCode.OperandType) { case OperandType.InlineBrTarget: case OperandType.ShortInlineBrTarget: var target = inst.Operand as Instruction; if (target != null) result.Add(new KeyValuePair<Instruction, Instruction>(inst, target)); break; case OperandType.InlineSwitch: var list = inst.Operand as IList<Instruction>; if (list != null) { foreach (Instruction target2 in list) { if (target2 != null) result.Add(new KeyValuePair<Instruction, Instruction>(inst, target2)); } } break; } } return result; }
public DevirtualizeResults Devirtualize(DevirtualizeOptions options, Action<DevirtualizeAttempt> attemptCallback) { var methods = this.Parent.FindMethodStubs(); if (methods.Length == 0) return new DevirtualizeResults(); var attempts = new List<DevirtualizeAttempt>(); foreach (var method in methods) { var reader = new VirtualizedMethodBodyReader(method, this.Logger, this.Parent.Version); Exception exception = null, fixerException = null; try { reader.Read(); // Read method } catch (Exception e) { exception = e; } DevirtualizeAttempt attempt; if (exception == null) { var body = new CilBody( true, reader.Instructions, reader.ExceptionHandlers, reader.Locals ); method.Method.FreeMethodBody(); method.Method.Body = body; // Perform fixes try { PerformFixes(method.Method); } catch (Exception e) { fixerException = e; } if (fixerException == null) { // Inject DevirtualizedAttribute if specified if (options.HasFlag(DevirtualizeOptions.InjectAttributes)) this.Injector.InjectDevirtualized(method.Method); attempt = new DevirtualizeAttempt(method, reader, body); } else attempt = new DevirtualizeAttempt(method, reader, fixerException); } else attempt = new DevirtualizeAttempt(method, reader, exception); // Add attempt to list and fire callback attempts.Add(attempt); if (attemptCallback != null) attemptCallback(attempt); } return new DevirtualizeResults(attempts); }