Пример #1
0
        /// <summary>
        /// This method starts from an API call instruction and goes backward to locate the instruction that
        /// pushes the "this" object into stack. We insert out instrumentation patch at that point so that
        /// the interception method can access the "this" object. After the interception method ends, we
        /// push the "this" object to stack again so that the original API call can continue.
        /// </summary>
        /// <param name="callInstruction">Instruction that calls the API.</param>
        /// <returns>The instruction that pushes the "this" object into stack.</returns>
        private Instruction LocateLoadThisInstruction(Instruction callInstruction)
        {
            Tuple <int, int> poppedPushed = MSILHelper.GetStackTransition(callInstruction);
            int toPop = poppedPushed.Item1;

            Instruction current = callInstruction.Previous;

            while (toPop > 1)
            {
                poppedPushed = MSILHelper.GetStackTransition(current);
                toPop       += poppedPushed.Item1;
                toPop       -= poppedPushed.Item2;
                current      = current.Previous;
            }

            return(current);
        }
Пример #2
0
        private bool InstrumentMethodCallInstruction(MethodDefinition method, Instruction instruction)
        {
            var methodName = $"{method.DeclaringType.FullName}::{method.Name}";
            var processor  = method.Body.GetILProcessor();

            var calleeRef  = (MethodReference)instruction.Operand;
            var calleeName = $"{calleeRef.DeclaringType.FullName}::{calleeRef.Name}";

            if (Constants.MethodPrefixBlackList.Any(x => calleeName.StartsWith(x)))
            {
                return(false);
            }

            if (calleeRef.DeclaringType.IsValueType)
            {
                return(false); // method in struct
            }

            var patchTarget = instruction;
            var isValueType = false;

            if (patchTarget.Previous != null && patchTarget.Previous.OpCode == OpCodes.Constrained)
            {
                patchTarget = patchTarget.Previous;
                if (patchTarget.Operand is GenericInstanceType)
                {
                    isValueType |= ((GenericInstanceType)patchTarget.Operand).IsValueType;
                }
                else if (patchTarget.Operand is TypeReference)
                {
                    var typeRef = (TypeReference)patchTarget.Operand;
                    isValueType |= typeRef.IsValueType;
                }
            }

            if (isValueType)
            {
                return(false); // method in struct
            }

            var                signature      = calleeRef.GetResolvedMethodSignature();
            var                isNewObj       = instruction.OpCode == OpCodes.Newobj;
            Instruction        patchStart     = null;
            VariableDefinition instanceVarDef = null;

            if (!isNewObj && calleeRef.HasThis)
            {
                instanceVarDef = new VariableDefinition(method.Module.TypeSystem.Object);
                method.Body.Variables.Add(instanceVarDef);

                var loadThisInstruction = MSILHelper.LocateLoadThisInstruction(processor, instruction);
                if (loadThisInstruction == null)
                {
                    return(false);
                }

                var patch1 = new List <Instruction>()
                {
                    processor.Create(OpCodes.Dup),
                    processor.Create(OpCodes.Stloc, instanceVarDef),
                };
                processor.InsertAfter(loadThisInstruction, patch1);
                patchStart = patch1[0];
            }

            VariableDefinition contextVarDef    = null;
            var afterMethodCallbackWillBeCalled = calleeRef.Name.Equals("Dispose");

            if (afterMethodCallbackWillBeCalled)
            {
                contextVarDef = new VariableDefinition(method.Module.TypeSystem.Object);
                method.Body.Variables.Add(contextVarDef);
            }

            var patch = this.GetPatchForBeforeMethodCall(
                processor,
                instanceVarDef,
                methodName,
                calleeRef,
                instruction.Offset,
                isValueType,
                contextVarDef);

            if (patchStart == null)
            {
                patchStart = patch[0];
            }

            processor.InsertBefore(patchTarget, patch);
            method.UpdateInstructionReferences(patchTarget, patchStart, true);

            /*
             * if (contextVarDef != null)
             * {
             *  patch = this.GetPatchForAfterMethodCall(processor, contextVarDef);
             *  processor.InsertAfter(instruction, patch);
             * }
             */
            return(true);
        }
Пример #3
0
        public static Instruction LocateLoadThisInstruction(ILProcessor ilProcessor, Instruction callInstruction)
        {
            Dictionary <Instruction, int> stackSize = new Dictionary <Instruction, int>();

            Tuple <int, int> poppedPushed = MSILHelper.GetStackTransition(callInstruction);
            int toPop = poppedPushed.Item1;

            stackSize[callInstruction] = toPop;

            if (callInstruction.Previous == null)
            {
                ilProcessor.InsertBefore(callInstruction, ilProcessor.Create(OpCodes.Nop));
            }

            Instruction current = callInstruction.Previous;

            // fail if there current is a branch instruction
            if (current.OpCode.FlowControl != FlowControl.Next)
            {
                return(null);
            }

            while (toPop > 1)
            {
                if (IsStackEmptyingInstruction(current))
                {
                    Instruction branchSrc;
                    Instruction branchDst;
                    GetNextBranchDestinationInstruction(current, callInstruction, out branchSrc, out branchDst);
                    if (branchDst != null)
                    {
                        current = branchSrc;
                        toPop   = stackSize[branchDst];
                    }
                }

                poppedPushed       = MSILHelper.GetStackTransition(current);
                toPop             += poppedPushed.Item1;
                toPop             -= poppedPushed.Item2;
                stackSize[current] = toPop;

                if (current.Previous == null)
                {
                    ilProcessor.InsertBefore(current, ilProcessor.Create(OpCodes.Nop));
                }

                current = current.Previous;

                // fail if there current is a branch instruction
                if (current.OpCode.FlowControl != FlowControl.Next)
                {
                    return(null);
                }
            }

            if (current.OpCode == OpCodes.Constrained)
            {
                current = current.Previous;

                // fail if there current is a branch instruction
                if (current.OpCode.FlowControl != FlowControl.Next)
                {
                    return(null);
                }
            }

            return(current);
        }