Example #1
0
            /// <summary>
            /// Injects a CALL instruction into the given <see cref="ILRef"/>. If <paramref name="insert"/> is false, it will replace the target instruction.
            /// If <paramref name="insert"/> is true, then it will insert the new instruction and push forward the instructions at
            /// and after the given <see cref="ILRef"/>
            /// </summary>
            public ILRef InjectHook(ILRef target, MethodBase hook, bool insert = true)
            {
                if (target == null)
                {
                    throw new ArgumentNullException("target");
                }
                if (hook == null)
                {
                    throw new ArgumentNullException("hook");
                }
                if (!target.Valid)
                {
                    throw new InvalidOperationException("Cannot use an invalid ILRef!");
                }
                int             targetIndex = target.Index;
                CodeInstruction targetInsn  = GetInsn(target);

                if (insert)
                {
                    ShiftInsns(target, 1);
                }
                Insns[targetIndex] = new CodeInstruction(hook.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, hook);
                Insns[targetIndex].labels.AddRange(targetInsn.labels);
                targetInsn.labels.Clear();
                UpdateMetadata();
                return(insert ? GetRefByIndex(targetIndex) : target);
            }
Example #2
0
            /// <summary>
            /// Injects an instruction into the given <see cref="ILRef"/>. If <paramref name="insert"/> is false, it will replace the target instruction.
            /// If <paramref name="insert"/> is true, then it will insert the new instruction and push forward the instructions at
            /// and after the given <see cref="ILRef"/>
            /// </summary>
            public ILRef InjectInsn(ILRef target, CodeInstruction insn, bool insert = true)
            {
                if (target == null)
                {
                    throw new ArgumentNullException("target");
                }
                if (insn == null)
                {
                    throw new ArgumentNullException("insn");
                }
                if (!target.Valid)
                {
                    throw new InvalidOperationException("Cannot use an invalid ILRef!");
                }
                int             targetIndex = target.Index;
                CodeInstruction targetInsn  = GetInsn(target);

                insn.labels.AddRange(targetInsn.labels);
                targetInsn.labels.Clear();
                if (insert)
                {
                    ShiftInsns(target, 1);
                }
                Insns[targetIndex] = new CodeInstruction(insn);
                UpdateMetadata();
                return(insert ? GetRefByIndex(targetIndex) : target);
            }
Example #3
0
            /// <summary>
            /// Injects an elseif structure onto the end of a specified if block specified by the <see cref="ILRef"/> that is targeting a conditional branch instruction.
            /// The returned <see cref="ILRef"/>s will point to NOPs you can use and/or replace.
            /// </summary>
            public void InjectElseIf(ILRef ifBranch, OpCode conditionCode, out ILRef conditionBlock, out ILRef codeBlock)
            {
                if (ifBranch == null)
                {
                    throw new ArgumentNullException("ifBranch");
                }
                if (!ifBranch.Valid)
                {
                    throw new InvalidOperationException("Cannot use an invalid ILRef!");
                }
                CodeInstruction brCode = GetInsn(ifBranch);

                if (brCode.opcode.FlowControl != FlowControl.Cond_Branch)
                {
                    throw new InvalidOperationException("ifBranch must point to a conditional branch instruction!");
                }
                Label exitLabel      = (Label)brCode.operand;
                Label conditionLabel = ILGen.DefineLabel();

                brCode.operand = conditionLabel;
                ILRef exitRef = FindRefByLabel(exitLabel);

                InjectInsn(exitRef, new CodeInstruction(OpCodes.Br, exitLabel), true);
                CodeInstruction conditionInsn = new CodeInstruction(conditionCode, exitLabel);

                conditionBlock = InjectInsn(exitRef, new CodeInstruction(OpCodes.Nop), true);
                GetInsn(conditionBlock).labels.Add(conditionLabel);
                InjectInsn(exitRef, conditionInsn, true);
                codeBlock = InjectInsn(exitRef, new CodeInstruction(OpCodes.Nop), true);
                UpdateMetadata();
            }
Example #4
0
 /// <summary>
 /// Dumps the instructions of this <see cref="CILProcessor"/> as a string,
 /// optionally with a given starting <see cref="ILRef"/> and count of instructions to print.
 /// lines are seperated by the \n character.
 /// </summary>
 public string DumpInstructions(ILRef start, int count = int.MaxValue)
 {
     if (!start.Valid)
     {
         throw new InvalidOperationException("Cannot use an invalid ILRef!");
     }
     return(DumpInstructions(start?.Index ?? 0, count));
 }
            /// <summary>
            /// Finds the last instruction that has the given opcode.
            /// </summary>
            public ILRef FindLastRefByOpCode(OpCode code, ILRef startRef)
            {
                if (code == null)
                {
                    throw new ArgumentNullException("code");
                }
                int index = Insns.FindLastIndex(startRef.Index, x => x?.opcode == code);

                return(index >= 0 ? GetRefByIndex(index) : null);
            }
            /// <summary>
            /// Finds the last instruction that matches the given instruction's opcode and operand.
            /// Ignores the instruction's labels and exception blocks.
            /// </summary>
            public ILRef FindLastRefByInsn(CodeInstruction insn, ILRef startRef)
            {
                if (insn == null)
                {
                    throw new ArgumentNullException("insn");
                }
                bool hasToString = insn.operand != null && !(insn.operand is Label) && insn.operand.GetType().GetMethods().Any(m => m.Name == "ToString" && m.GetParameters().Length == 0 && m.DeclaringType != typeof(object));
                int  index       = Insns.FindLastIndex(startRef.Index, x => x?.opcode == insn.opcode && (insn.operand == null || (hasToString ? x?.operand?.ToString() == insn.operand?.ToString() : x?.operand is Label xLab && insn.operand is Label insnLab ? xLab == insnLab : x?.operand == insn.operand)));

                return(index >= 0 ? GetRefByIndex(index) : null);
            }
            /// <summary>
            /// Finds the last instruction block that matches the given instructions' opcodes and operands.
            /// Ignores the instruction's labels and exception blocks.
            /// The <see cref="ILRef"/> points to the first instruction in the block.
            /// </summary>
            public ILRef FindLastRefByInsns(CodeInstruction[] searchInsns, ILRef startRef)
            {
                if (searchInsns == null)
                {
                    throw new ArgumentNullException("searchInsns");
                }
                EqualityComparison <CodeInstruction>[] comparers = searchInsns.Select(x => x == null ? (a, b) => true : x.operand == null ? (a, b) => a?.opcode == b?.opcode : !(x.operand is Label) && x.operand.GetType().GetMethods().Any(m => m.Name == "ToString" && m.GetParameters().Length == 0 && m.DeclaringType != typeof(object)) ? (a, b) => a?.opcode == b?.opcode && a?.operand?.ToString() == b?.operand?.ToString() : (EqualityComparison <CodeInstruction>)((a, b) => a?.opcode == b?.opcode && (a?.operand is Label aLab && b?.operand is Label bLab ? aLab == bLab : a?.operand == b?.operand))).ToArray();
                int index = Insns.LastIndexOfSublist(searchInsns.ToList(), startRef.Index, comparers);

                return(index >= 0 ? GetRefByIndex(index) : null);
            }
            /// <summary>
            /// Marks a label at the target instruction, for use in branch instructions.
            /// </summary>
            public Label MarkLabel(ILRef target)
            {
                Label           l    = ILGen.DefineLabel();
                CodeInstruction insn = GetInsn(target);

                if (insn.labels == null)
                {
                    insn.labels = new List <Label>();
                }
                insn.labels.Add(l);
                return(l);
            }
Example #9
0
            private void ShiftInsns(ILRef target, int shift)
            {
                if (shift == 0)
                {
                    return;
                }
                int targetIndex = target.Index;

                if (shift > 0)
                {
                    Insns.InsertRange(targetIndex, new CodeInstruction[shift]);
                    UpdateMetadata();
                    foreach (KeyValuePair <int, ILRef> r in ILRefs.Where(x => x.Key >= targetIndex).OrderByDescending(x => x.Key).ToList())
                    {
                        r.Value.Shift(shift);
                        ILRefs[r.Key + shift] = r.Value;
                        ILRefs.Remove(r.Key);
                    }
                }
                else if (target.Index + shift >= 0)
                {
                    Label[] labels = Insns.GetRange(targetIndex + shift, -shift).SelectMany(x => x.labels).ToArray();
                    Insns.RemoveRange(targetIndex + shift, -shift);
                    Insns.TrimExcess();
                    CodeInstruction firstInsn = Insns[targetIndex + shift];
                    foreach (Label label in labels)
                    {
                        firstInsn.labels.Add(label);
                    }
                    UpdateMetadata();
                    foreach (KeyValuePair <int, ILRef> r in ILRefs.Where(x => x.Key >= targetIndex + shift).OrderBy(x => x.Key).ToList())
                    {
                        if (r.Key >= targetIndex)
                        {
                            r.Value.Shift(shift);
                            ILRefs[r.Key + shift] = r.Value;
                            ILRefs.Remove(r.Key);
                        }
                        else
                        {
                            r.Value.Invalidate();
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException("Cannot shift past the bottom of the insn list!");
                }
            }
Example #10
0
            /// <summary>
            /// Injects a set of instructions into the block started by the given <see cref="ILRef"/>. If <paramref name="insert"/> is false, it will replace the target instructions.
            /// If <paramref name="insert"/> is true, then it will insert the new instructions and push forward the instructions at
            /// and after the given <see cref="ILRef"/>
            /// </summary>
            public ILRef InjectInsns(ILRef target, CodeInstruction[] newInsns, bool insert = true)
            {
                if (target == null)
                {
                    throw new ArgumentNullException("target");
                }
                if (newInsns == null)
                {
                    throw new ArgumentNullException("newInsns");
                }
                if (newInsns.Length < 1)
                {
                    throw new ArgumentOutOfRangeException("newInsns");
                }
                if (!target.Valid)
                {
                    throw new InvalidOperationException("Cannot use an invalid ILRef!");
                }
                int             targetIndex = target.Index;
                CodeInstruction targetInsn  = GetInsn(target);

                if (newInsns[0] != null)
                {
                    newInsns[0].labels.AddRange(targetInsn.labels);
                    targetInsn.labels.Clear();
                }
                if (insert)
                {
                    ShiftInsns(target, newInsns.Length);
                }
                if (Insns.Capacity < targetIndex + newInsns.Length)
                {
                    Insns.Capacity = Math.Max(targetIndex + newInsns.Length, (int)Math.Pow(2, Math.Floor(Math.Log(Insns.Capacity, 2) + 1)));
                }
                for (int i = targetIndex; i < targetIndex + newInsns.Length; i++)
                {
                    if (Insns[i] != null)
                    {
                        newInsns[i - targetIndex].labels.AddRange(Insns[i].labels);
                    }
                    Insns[i] = newInsns[i - targetIndex];
                }
                UpdateMetadata();
                return(insert ? GetRefByIndex(targetIndex) : target);
            }
Example #11
0
            /// <summary>
            /// Injects a LDFLD instruction into the given <see cref="ILRef"/>. Will fail to load a non-static field from a static method.
            /// If <paramref name="insert"/> is false, it will replace the target instruction.
            /// If <paramref name="insert"/> is true, then it will insert the new instruction and push forward the instructions at
            /// and after the given <see cref="ILRef"/>
            /// </summary>
            public ILRef InjectLoadField(ILRef target, FieldInfo field, bool insert = true)
            {
                if (target == null)
                {
                    throw new ArgumentNullException("target");
                }
                if (field == null)
                {
                    throw new ArgumentNullException("hook");
                }
                if (!target.Valid)
                {
                    throw new InvalidOperationException("Cannot use an invalid ILRef!");
                }
                int             targetIndex = target.Index;
                CodeInstruction targetInsn  = GetInsn(target);

                if (field.IsStatic)
                {
                    if (insert)
                    {
                        ShiftInsns(target, 1);
                    }
                    Insns[targetIndex] = new CodeInstruction(OpCodes.Ldsfld, field);
                }
                else
                {
                    if (insert)
                    {
                        ShiftInsns(target, 2);
                    }
                    else
                    {
                        ShiftInsns(target, 1);
                    }
                    Insns[targetIndex]     = new CodeInstruction(OpCodes.Ldarg_0);
                    Insns[targetIndex + 1] = new CodeInstruction(OpCodes.Ldfld, field);
                }
                Insns[targetIndex].labels.AddRange(targetInsn.labels);
                targetInsn.labels.Clear();
                UpdateMetadata();
                return(insert ? GetRefByIndex(targetIndex) : target);
            }
Example #12
0
            /// <summary>
            /// Simplifies needlessly complicated conditional branch structures.
            /// </summary>
            public ILRef SimplifyConditionalBranch(ILRef ifBranch)
            {
                if (ifBranch == null)
                {
                    throw new ArgumentNullException("ifBranch");
                }
                if (!ifBranch.Valid)
                {
                    throw new InvalidOperationException("Cannot use an invalid ILRef!");
                }
                CodeInstruction conditionalBranch    = GetInsn(ifBranch);
                CodeInstruction nonconditionalBranch = GetInsn(ifBranch.GetRefByOffset(1));

                if (conditionalBranch.opcode.FlowControl == FlowControl.Cond_Branch && nonconditionalBranch.opcode.FlowControl == FlowControl.Branch &&
                    GetInsn(ifBranch.GetRefByOffset(2)).labels.Contains((Label)conditionalBranch.operand) &&
                    conditionalBranch.opcode != GetReverseConditionalCode(conditionalBranch.opcode))
                {
                    conditionalBranch.opcode  = GetReverseConditionalCode(conditionalBranch.opcode);
                    conditionalBranch.operand = nonconditionalBranch.operand;
                    RemoveInsn(ifBranch.GetRefByOffset(1));
                }
                UpdateMetadata();
                return(ifBranch);
            }
Example #13
0
 /// <summary>
 /// Removes the set of instructions in the block started by the given <see cref="ILRef"/>s.
 /// </summary>
 public void RemoveInsns(ILRef start, ILRef end)
 {
     ShiftInsns(end, end.Index - start.Index + 1);
 }
Example #14
0
 /// <summary>
 /// Removes the set of instructions in the block started by the given <see cref="ILRef"/>.
 /// Accepts values of <paramref name="count"/> higher than the number of instructions.
 /// </summary>
 public void RemoveInsns(ILRef target, int count)
 {
     ShiftInsns(target.GetRefByOffset(count), -count);
 }
Example #15
0
 /// <summary>
 /// Removes the instruction at the given <see cref="ILRef"/>.
 /// </summary>
 public void RemoveInsn(ILRef target)
 {
     RemoveInsns(target, 1);
 }
Example #16
0
 /// <summary>
 /// Returns an <see cref="ILRef"/> for the instruction with its index offset from the given <see cref="ILRef"/>
 /// </summary>
 public ILRef GetRefByOffset(ILRef current, int offset)
 {
     return(GetRefByIndex(current.Index + offset));
 }
Example #17
0
 /// <summary>
 /// Gets the <see cref="CodeInstruction"/> referenced by the given <see cref="ILRef"/>
 /// </summary>
 public CodeInstruction GetInsn(ILRef target)
 {
     return(Insns[target.Index]);
 }