public override void Mangle(ICFMangleContext context, Block.Regular block) { var fragments = context.SplitFragments(block); if (fragments.Count < 4) { return; } var current = fragments.First; while (current.Next != null) { var newFragment = new CilFragment(current.Value); context.AddJump(newFragment, current.Next.Value.First, true); current.Value = newFragment; current = current.Next; } var first = fragments.First.Value; fragments.RemoveFirst(); var last = fragments.Last.Value; fragments.RemoveLast(); var newFragments = fragments.ToList(); newFragments.Shuffle(Mangler.Rng); block.Fragment.Reset(first .Concat(newFragments.SelectMany(fragment => fragment)) .Concat(last)); }
public override void EmitSwitchLoad(CilFragment instrs) { instrs.Add(Instruction.Create(OpCodes.Stloc, _stateVar)); foreach (var instr in _invCompiled) { instrs.Add(instr.Clone()); } }
public ILEmitter(ModuleDef targetModule, Importer?importer = null, CilFragment fragment = null) { TargetModule = targetModule; _importer = importer ?? new Importer(targetModule); _mainFragment = fragment ?? new CilFragment(); _tempLocals = new TempLocals(); _insertions = new Dictionary <Instruction, List <Insertion> >(); _insertionsStack = new Stack <Insertion>(); }
public LinkedList <CilFragment> SplitFragments(Block.Regular block) { var statements = new LinkedList <CilFragment>(); var currentStatement = new CilFragment(); var requiredInstr = new HashSet <Instruction>(); var i = 0; var instr = block.Fragment.Instructions[i]; var fi = RootBlock.FlowInfo.Info; while (instr != null) { fi.TryGetValue(instr, out var info); i++; var next = i < block.Fragment.Instructions.Count ? block.Fragment.Instructions[i] : null; currentStatement.Add(instr); var shouldSpilt = next != null && fi.TryGetValue(next, out var ni) && ni.RefCount > 1; switch (instr.OpCode.FlowControl) { case FlowControl.Branch: case FlowControl.Cond_Branch: case FlowControl.Return: case FlowControl.Throw: shouldSpilt = true; if (info.DepthAfter != 0) { if (instr.Operand is Instruction) { requiredInstr.Add((Instruction)instr.Operand); } else if (instr.Operand is Instruction[]) { foreach (var target in (Instruction[])instr.Operand) { requiredInstr.Add(target); } } } break; } requiredInstr.Remove(instr); if ((instr.OpCode.OpCodeType != OpCodeType.Prefix && info.DepthAfter == 0 && requiredInstr.Count == 0) && (shouldSpilt || Mangler.Options.Intensity > Mangler.Rng.NextDouble())) { statements.AddLast(currentStatement); currentStatement = new CilFragment(); } instr = next; } if (!currentStatement.IsEmpty) { statements.AddLast(currentStatement); } return(statements); }
public void AddJump(CilFragment instrs, Instruction target, bool stackEmpty) { if (stackEmpty) { instrs.Add(Instruction.Create(OpCodes.Ldc_I4_0)); instrs.Add(Instruction.Create(OpCodes.Brfalse, target)); } else { instrs.Add(Instruction.Create(OpCodes.Br, target)); } }
internal CilBodyBuilding(IContext context, TypeMapping typeMapping, MethodDef source, MethodDef target, Importer importer, IReadOnlyDictionary <Instruction, Instruction> instructionMap) : base(context) { TypeMapping = typeMapping; Source = source; Target = target; Importer = importer; Locals = new List <Local>(); ExceptionHandlers = new List <ExceptionHandler>(); Fragment = new CilFragment(); _instrMap = instructionMap; }
public Insertion(ILEmitter emitter, Instruction i, int replace, bool before) { _emitter = emitter; _instruction = i; if (!emitter._insertions.TryGetValue(i, out var l)) { emitter._insertions.Add(i, l = new List <Insertion>()); } l.Add(this); emitter._insertionsStack.Push(this); Before = before; Replace = replace; Fragment = new CilFragment(); }
public Expr(ICFMangleContext ctx) : base(ctx) { _invCompiled = new CilFragment(); _stateVar = new Local(ctx.Method.Module.CorLibTypes.Int32); var body = ctx.Method.Body; body.Variables.Add(_stateVar); body.InitLocals = true; var nm = new IntGenerator(ctx.Mangler.Rng, ctx.Mangler.Options.MaxMangleIterations); var codec = nm.Generate(); codec.ParameterResolver = p => p == nm.Argument ? _stateVar : null; _codec = codec; var emitter = DnextFactory.NewILEmitter(ctx.Method.Module, ctx.Importer, _invCompiled); codec.EmitDemangler(emitter); }
public static IILEmitter NewILEmitter(ModuleDef targetModule, Importer?importer = null, CilFragment fragment = null) => new ILEmitter(targetModule, importer, fragment);
public override void EmitSwitchLoad(CilFragment instrs) { instrs.Add(Instruction.Create(OpCodes.Ldc_I4, _xorKey)); instrs.Add(Instruction.Create(OpCodes.Xor)); }
public abstract void EmitSwitchLoad(CilFragment instrs);
public void Mangle(Block.Regular block) { var rng = _switch.Mangler.Rng; var fi = _context.RootBlock.FlowInfo.Info; var fragments = _context.SplitFragments(block); if (fragments.Count < 3) { return; } int i; var keyId = Enumerable.Range(0, fragments.Count).ToArray(); keyId.Shuffle(rng); var key = new int[keyId.Length]; for (i = 0; i < key.Length; i++) { var q = rng.NextInt32() & 0x7fffffff; key[i] = q - q % fragments.Count + keyId[i]; } var statementKeys = new Dictionary <Instruction, int>(); var current = fragments.First; i = 0; while (current != null) { if (i != 0) { statementKeys[current.Value.First] = key[i]; } i++; current = current.Next; } var lastInstructions = new HashSet <Instruction>(fragments.Select(f => f.Last())); var blockInstructions = new HashSet <Instruction>(block.Fragment); var firstFragmentInstructions = new HashSet <Instruction>(fragments.First()); bool HasUnknownSource(IEnumerable <Instruction> instrs) => instrs.Any(instr => { //return true; fi.TryGetValue(instr, out var info); if (info.RefCount > 1) { return(true); } Debug.Assert(info.RefCount == 1); var srcs = info.ReferencedBy; if (srcs.Count == 0) { return(false); } Debug.Assert(srcs.Count == 1); var src = srcs[0]; return // Target of switch => assume unknown (src.OpCode.Code == Code.Switch // Operand is Instruction[] // Not targeted by the last of statements || lastInstructions.Contains(src) // Not within current instruction block / targeted in first statement // || src.Offset <= fragments.First.Value.Last().Offset || src.Offset >= block.Fragment.Last().Offset || !blockInstructions.Contains(src) || firstFragmentInstructions.Contains(src)); }); var switchInstr = new Instruction(OpCodes.Switch); var switchHdr = new CilFragment(); if (_predicate != null) { 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, fragments.Count)); switchHdr.Add(Instruction.Create(OpCodes.Rem_Un)); switchHdr.Add(switchInstr); _context.AddJump(switchHdr, fragments.Last.Value.First, true); var switchHdrSecond = switchHdr.Instructions[1]; var operands = new Instruction[fragments.Count]; current = fragments.First; i = 0; while (current.Next != null) { var newFragment = new CilFragment(current.Value); if (i != 0) { var lastInstr = newFragment.Last(); // Convert to switch var converted = false; fi.TryGetValue(lastInstr, out var info); if (lastInstr.IsBr()) { // Unconditional var target = (Instruction)lastInstr.Operand; if (info.ReferencedBy.Count == 0 && statementKeys.TryGetValue(target, out var brKey)) { var targetKey = _predicate?.GetSwitchKey(brKey) ?? brKey; var unkSrc = HasUnknownSource(newFragment); newFragment.Instructions.RemoveAt(newFragment.Instructions.Count - 1); if (unkSrc) { newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); } else { var thisKey = key[i]; var r = rng.NextInt32(); newFragment.Add(Instruction.Create(OpCodes.Ldloc, _local)); newFragment.Add(Instruction.CreateLdcI4(r)); newFragment.Add(Instruction.Create(OpCodes.Mul)); newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey)); newFragment.Add(Instruction.Create(OpCodes.Xor)); } _context.AddJump(newFragment, switchHdrSecond, false); operands[keyId[i]] = newFragment.First; converted = true; } } else if (lastInstr.IsConditionalBranch()) { // Conditional var target = (Instruction)lastInstr.Operand; if (info.ReferencedBy.Count == 0 && statementKeys.TryGetValue(target, out var brKey)) { var unkSrc = HasUnknownSource(newFragment); var nextKey = key[i + 1]; var condBr = newFragment.Last().OpCode; newFragment.Instructions.RemoveAt(newFragment.Instructions.Count - 1); if (rng.NextBoolean()) { condBr = DnextFactory.InverseBranch(condBr); var tmp = brKey; brKey = nextKey; nextKey = tmp; } var thisKey = key[i]; int r = 0, xorKey = 0; if (!unkSrc) { r = rng.NextInt32(); xorKey = thisKey * r; } var brKeyInstr = Instruction.CreateLdcI4(xorKey ^ (_predicate?.GetSwitchKey(brKey) ?? brKey)); var nextKeyInstr = Instruction.CreateLdcI4(xorKey ^ (_predicate?.GetSwitchKey(nextKey) ?? nextKey)); var pop = Instruction.Create(OpCodes.Pop); newFragment.Add(Instruction.Create(condBr, brKeyInstr)); newFragment.Add(nextKeyInstr); newFragment.Add(Instruction.Create(OpCodes.Dup)); newFragment.Add(Instruction.Create(OpCodes.Br, pop)); newFragment.Add(brKeyInstr); newFragment.Add(Instruction.Create(OpCodes.Dup)); newFragment.Add(pop); if (!unkSrc) { newFragment.Add(Instruction.Create(OpCodes.Ldloc, _local)); newFragment.Add(Instruction.CreateLdcI4(r)); newFragment.Add(Instruction.Create(OpCodes.Mul)); newFragment.Add(Instruction.Create(OpCodes.Xor)); } _context.AddJump(newFragment, switchHdrSecond, false); operands[keyId[i]] = newFragment.First; converted = true; } } if (!converted) { // Normal var targetKey = _predicate?.GetSwitchKey(key[i + 1]) ?? key[i + 1]; if (!HasUnknownSource(newFragment)) { var thisKey = key[i]; var r = rng.NextInt32(); newFragment.Add(Instruction.Create(OpCodes.Ldloc, _local)); newFragment.Add(Instruction.CreateLdcI4(r)); newFragment.Add(Instruction.Create(OpCodes.Mul)); newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey)); newFragment.Add(Instruction.Create(OpCodes.Xor)); } else { newFragment.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); } _context.AddJump(newFragment, switchHdrSecond, false); operands[keyId[i]] = newFragment.First; } } else { operands[keyId[i]] = switchHdr.First; } current.Value = newFragment; current = current.Next; i++; } operands[keyId[i]] = current.Value.First; switchInstr.Operand = operands; var first = fragments.First.Value; fragments.RemoveFirst(); var last = fragments.Last.Value; fragments.RemoveLast(); var newStatements = fragments.ToList(); newStatements.Shuffle(rng); block.Fragment.Reset(first.Concat(switchHdr).Concat(newStatements.SelectMany(s => s)).Concat(last)); }