コード例 #1
0
ファイル: Simplifier.cs プロジェクト: vaginessa/Probfuscator
        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="Instruction"></typeparam>
        /// <param name="instruction"></param>
        /// <param name="mappings"></param>
        /// <param name="canonicalizer"></param>
        /// <returns></returns>
        internal static Instruction SimplifyUnary <Instruction>(Instruction instruction, ValueMappings <Instruction> mappings, ExpressionCanonicalizer <Instruction> canonicalizer)
            where Instruction : Microsoft.Cci.Analysis.Instruction, new()
        {
            Contract.Requires(instruction != null);
            Contract.Requires(mappings != null);
            Contract.Requires(canonicalizer != null);
            Contract.Ensures(Contract.Result <Instruction>() != null);

            var operation = instruction.Operation;

            Contract.Assume(instruction.Operand1 is Instruction);
            var operand1            = (Instruction)instruction.Operand1;
            var operand             = Simplify(operand1, mappings, canonicalizer);
            var compileTimeConstant = mappings.GetCompileTimeConstantValueFor(operand);

            if (compileTimeConstant != null)
            {
                var constantResult = Evaluator.Evaluate(instruction.Operation, compileTimeConstant);
                if (constantResult != null)
                {
                    return(canonicalizer.GetAsCanonicalizedLoadConstant(constantResult, instruction));
                }
            }

            switch (operation.OperationCode)
            {
            case OperationCode.Neg:
                if (operand.Operation.OperationCode == OperationCode.Neg)
                {
                    Contract.Assume(operand.Operand1 is Instruction);
                    return((Instruction)operand.Operand1);
                }
                //TODO: if the operand is a binary operation with arithmetic operands where one of them is a Neg
                //distribute the neg over the binary operation, if doing so is safe w.r.t. overflow.
                break;

            case OperationCode.Not:
                var simplerInverse = TryToGetSimplerLogicalInverse(operand);
                if (simplerInverse != null)
                {
                    return(simplerInverse);
                }
                if (operand != operand1)
                {
                    var operation1 = operand1.Operation;
                    switch (operation1.OperationCode)
                    {
                    case OperationCode.Bne_Un:
                    case OperationCode.Bne_Un_S:
                    case OperationCode.Beq:
                    case OperationCode.Beq_S:
                        OperationCode newOpcode = GetInverse(operation1.OperationCode, operand1.Type.TypeCode == PrimitiveTypeCode.Float32 || operand1.Type.TypeCode == PrimitiveTypeCode.Float64);
                        return(new Instruction()
                        {
                            Operation = new Operation()
                            {
                                OperationCode = newOpcode, Offset = operation.Offset, Location = operation.Location
                            },
                            Operand1 = operand1.Operand1,
                            Operand2 = operand1.Operand2
                        });
                    }
                }
                return(new Instruction()
                {
                    Operation = operation, Operand1 = operand
                });
            }
            return(instruction);
        }
コード例 #2
0
ファイル: Simplifier.cs プロジェクト: vaginessa/Probfuscator
        /// <summary>
        /// Uses Arithmetic and Boolean laws to simplify expressions.
        /// </summary>
        /// <typeparam name="Instruction"></typeparam>
        /// <param name="instruction"></param>
        /// <param name="mappings"></param>
        /// <param name="canonicalizer"></param>
        /// <returns></returns>
        internal static Instruction SimplifyBinary <Instruction>(Instruction instruction, ValueMappings <Instruction> mappings, ExpressionCanonicalizer <Instruction> canonicalizer)
            where Instruction : Microsoft.Cci.Analysis.Instruction, new()
        {
            Contract.Requires(instruction != null);
            Contract.Requires(mappings != null);
            Contract.Requires(canonicalizer != null);
            Contract.Ensures(Contract.Result <Instruction>() != null);

            var operation = instruction.Operation;

            Contract.Assume(instruction.Operand1 is Instruction);
            var operand1 = (Instruction)instruction.Operand1;

            Contract.Assume(instruction.Operand2 is Instruction);
            var operand2 = (Instruction)instruction.Operand2;
            IMetadataConstant constantResult = null;
            var compileTimeConstant1         = mappings.GetCompileTimeConstantValueFor(operand1);
            var compileTimeConstant2         = mappings.GetCompileTimeConstantValueFor(operand2);

            if (compileTimeConstant1 != null)
            {
                if (compileTimeConstant2 != null)
                {
                    constantResult = Evaluator.Evaluate(instruction.Operation, compileTimeConstant1, compileTimeConstant2);
                }
                else
                {
                    constantResult = Evaluator.Evaluate(instruction.Operation, compileTimeConstant1, operand2, mappings);
                }
            }
            else if (compileTimeConstant2 != null)
            {
                constantResult = Evaluator.Evaluate(instruction.Operation, operand1, compileTimeConstant2, mappings);
            }
            else
            {
                constantResult = Evaluator.Evaluate(instruction.Operation, operand1, operand2, mappings);
            }
            if (constantResult != null)
            {
                return(canonicalizer.GetAsCanonicalizedLoadConstant(constantResult, instruction));
            }

            //If we get here, the instruction does not simplify to a constant, but it could still simplify to a simpler expression.
            bool operand1IsZero     = compileTimeConstant1 != null && MetadataExpressionHelper.IsIntegralZero(compileTimeConstant1);
            bool operand1IsOne      = compileTimeConstant1 != null && (operand1IsZero ? false : MetadataExpressionHelper.IsIntegralOne(compileTimeConstant1));
            bool operand1IsMinusOne = compileTimeConstant1 != null && ((operand1IsZero || operand1IsOne) ? false : MetadataExpressionHelper.IsIntegralMinusOne(compileTimeConstant1));
            bool operand2IsZero     = compileTimeConstant2 != null && MetadataExpressionHelper.IsIntegralZero(compileTimeConstant2);
            bool operand2IsOne      = compileTimeConstant2 != null && (operand1IsZero ? false : MetadataExpressionHelper.IsIntegralOne(compileTimeConstant2));
            bool operand2IsMinusOne = compileTimeConstant2 != null && ((operand2IsZero || operand2IsOne) ? false : MetadataExpressionHelper.IsIntegralMinusOne(compileTimeConstant2));

            operand1 = Simplify(operand1, mappings, canonicalizer);
            operand2 = Simplify(operand2, mappings, canonicalizer);

            switch (operation.OperationCode)
            {
            case OperationCode.Add:
            case OperationCode.Add_Ovf:
            case OperationCode.Add_Ovf_Un:
                if (operand1IsZero)
                {
                    return(operand2);
                }
                if (operand2IsZero)
                {
                    return(operand1);
                }
                //TODO: factor out common mults/divs/etc (subject to overflow checks).
                break;

            case OperationCode.And:
                if (operand1IsZero)
                {
                    return(operand1);
                }
                if (operand2IsZero)
                {
                    return(operand2);
                }
                if (operand1IsMinusOne)
                {
                    return(operand2);
                }
                if (operand2IsMinusOne)
                {
                    return(operand1);
                }
                if (operand1.Operation.OperationCode == OperationCode.Not && operand2.Operation.OperationCode == OperationCode.Not)
                {
                    var opnd11 = operand1.Operand1 as Instruction;
                    var opnd21 = operand2.Operand1 as Instruction;
                    Contract.Assume(opnd11 != null && opnd21 != null);
                    var or = new Operation()
                    {
                        OperationCode = OperationCode.Or, Location = operation.Location, Offset = operation.Offset
                    };
                    var orInst = new Instruction()
                    {
                        Operation = or, Operand1 = opnd11, Operand2 = opnd21, Type = instruction.Type
                    };
                    var not = new Operation {
                        OperationCode = OperationCode.Not, Location = operation.Location, Offset = operation.Offset
                    };
                    return(new Instruction()
                    {
                        Operation = not, Operand1 = orInst, Type = instruction.Type
                    });
                }
                break;

            case OperationCode.Ceq:
                //If one of the operands is const 0 and the other is a boolean expression, invert the boolean expression
                if (operand2IsZero && operand1.Type.TypeCode == PrimitiveTypeCode.Boolean)
                {
                    var not = new Operation()
                    {
                        Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Not
                    };
                    instruction = new Instruction()
                    {
                        Operation = not, Operand1 = operand1, Type = instruction.Type
                    };
                    return(SimplifyUnary(instruction, mappings, canonicalizer));
                }
                else if (operand1IsZero && operand2.Type.TypeCode == PrimitiveTypeCode.Boolean)
                {
                    var not = new Operation()
                    {
                        Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Not
                    };
                    instruction = new Instruction()
                    {
                        Operation = not, Operand1 = operand2, Type = instruction.Type
                    };
                    return(SimplifyUnary(instruction, mappings, canonicalizer));
                }
                else
                {
                    operation = new Operation()
                    {
                        Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Beq
                    };
                }
                break;

            case OperationCode.Cgt:
                operation = new Operation()
                {
                    Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Bgt
                };
                break;

            case OperationCode.Cgt_Un:
                operation = new Operation()
                {
                    Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Bgt_Un
                };
                break;

            case OperationCode.Clt:
                operation = new Operation()
                {
                    Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Blt
                };
                break;

            case OperationCode.Clt_Un:
                operation = new Operation()
                {
                    Location = instruction.Operation.Location, Offset = instruction.Operation.Offset, OperationCode = OperationCode.Blt_Un
                };
                break;

            case OperationCode.Div:
            case OperationCode.Div_Un:
                if (operand2IsOne)
                {
                    return(operand1);
                }
                break;

            case OperationCode.Mul:
            case OperationCode.Mul_Ovf:
            case OperationCode.Mul_Ovf_Un:
                if (operand1IsOne)
                {
                    return(operand2);
                }
                if (operand2IsOne)
                {
                    return(operand1);
                }
                break;

            case OperationCode.Or:
                if (operand1IsZero)
                {
                    return(operand2);
                }
                if (operand2IsZero)
                {
                    return(operand1);
                }
                if (operand1.Operation.OperationCode == OperationCode.Not && operand2.Operation.OperationCode == OperationCode.Not)
                {
                    var opnd11 = operand1.Operand1 as Instruction;
                    var opnd21 = operand2.Operand1 as Instruction;
                    Contract.Assume(opnd11 != null && opnd21 != null);
                    var and = new Operation()
                    {
                        OperationCode = OperationCode.And, Location = operation.Location, Offset = operation.Offset
                    };
                    var andInst = new Instruction()
                    {
                        Operation = and, Operand1 = opnd11, Operand2 = opnd21, Type = instruction.Type
                    };
                    var not = new Operation {
                        OperationCode = OperationCode.Not, Location = operation.Location, Offset = operation.Offset
                    };
                    return(new Instruction()
                    {
                        Operation = not, Operand1 = andInst, Type = instruction.Type
                    });
                }
                if (operand1.Operand1 == operand2.Operand1 && operand1.Operand2 == operand2.Operand2 &&
                    operand1.Operation.OperationCode != operand2.Operation.OperationCode && operand2.Operand1 != null &&
                    operand1.Operation.OperationCode == GetInverse(operand2.Operation.OperationCode,
                                                                   operand2.Operand1.Type.TypeCode == PrimitiveTypeCode.Float32 || operand2.Operand1.Type.TypeCode == PrimitiveTypeCode.Float64))
                {
                    return(canonicalizer.GetAsCanonicalizedLoadConstant(new MetadataConstant()
                    {
                        Value = true, Type = instruction.Type
                    }, instruction));
                }
                break;

            case OperationCode.Rem:
            case OperationCode.Rem_Un:
                break;

            case OperationCode.Shl:
            case OperationCode.Shr:
            case OperationCode.Shr_Un:
                if (operand2IsZero)
                {
                    return(operand1);
                }
                break;

            case OperationCode.Sub:
            case OperationCode.Sub_Ovf:
            case OperationCode.Sub_Ovf_Un:
                if (operand2IsZero)
                {
                    return(operand1);
                }
                break;

            case OperationCode.Xor:
                break;

            case OperationCode.Beq:
            case OperationCode.Beq_S:
                if (operand1IsZero && operand2.Type.TypeCode == PrimitiveTypeCode.Boolean)
                {
                    var operand2inv = TryToGetSimplerLogicalInverse(operand2);
                    if (operand2inv != null)
                    {
                        return(operand2inv);
                    }
                }
                else if (operand2IsZero && operand1.Type.TypeCode == PrimitiveTypeCode.Boolean)
                {
                    var operand1inv = TryToGetSimplerLogicalInverse(operand1);
                    if (operand1inv != null)
                    {
                        return(operand1inv);
                    }
                }
                goto case OperationCode.Bge_S;

            case OperationCode.Bne_Un:
            case OperationCode.Bne_Un_S:
                if (operand1IsZero && operand2.Type.TypeCode == PrimitiveTypeCode.Boolean)
                {
                    return(operand2);
                }
                if (operand2IsZero && operand1.Type.TypeCode == PrimitiveTypeCode.Boolean)
                {
                    return(operand1);
                }
                goto case OperationCode.Bge_S;

            case OperationCode.Bge_S:
            case OperationCode.Bge_Un_S:
            case OperationCode.Bgt_S:
            case OperationCode.Bgt_Un_S:
            case OperationCode.Ble_S:
            case OperationCode.Ble_Un_S:
            case OperationCode.Blt_S:
            case OperationCode.Blt_Un_S:
                operation = new Operation()
                {
                    Location      = operation.Location, Offset = operation.Offset,
                    OperationCode = LongVersionOf(operation.OperationCode), Value = operation.Value
                };
                break;
            }
            if (operation != instruction.Operation || operand1 != instruction.Operand1 || operand2 != instruction.Operand2)
            {
                return new Instruction()
                       {
                           Operation = operation, Operand1 = operand1, Operand2 = operand2, Type = instruction.Type
                       }
            }
            ;
            return(instruction);
        }