Example #1
0
        public static void Apply(ModuleDefinition module, Logger logger)
        {
            int stat_obfCall = 0, stat_nullField = 0, stat_duppop = 0, stat_obfSwitch = 0, stat_obfIf = 0, stat_obfClasses = 0;

            //not as fancy as it could be; the alternate way would be checking the field's names (always 1 uppercase letter) but that method could more easily get outdated
            Dictionary <FieldDefinition, FieldRemoveInfo> suspectFields = new Dictionary <FieldDefinition, FieldRemoveInfo>();

            List <MethodDefinition> decryptMethods = new List <MethodDefinition>();

            MethodDefinition[] mdefs = HelperClass.findMembers <MethodDefinition>(module, null, true);
            for (int methodIndex = 0; methodIndex < mdefs.Length; methodIndex++)
            {
                MethodDefinition mdef = mdefs[methodIndex];
                if (mdef.HasBody)
                {
                    MethodBody mdefBody = mdef.Body;
                    for (int i = 0; i < mdefBody.Instructions.Count; i++)
                    {
                        Instruction instr = mdefBody.Instructions[i];
                        if (instr.OpCode == OpCodes.Call)
                        {
                            MethodReference  mref         = (MethodReference)instr.Operand;
                            MethodDefinition targetMethod = mref.Resolve();
                            //indicates that this is a method by the obfuscator that replaces single operations from other methods
                            if (targetMethod != null &&
                                targetMethod.IsStatic && targetMethod.DeclaringType.Namespace.Equals("A") &&
                                targetMethod.Body.Instructions.Count < 10 &&
                                targetMethod.DeclaringType.Methods.Count == 1 && targetMethod.DeclaringType.Fields.Count == 0)
                            {
                                //logger.Info(targetMethod.DeclaringType.FullName + "::" + targetMethod.Name + " -> " + mdef.DeclaringType.FullName + "::" + mdef.Name + " (@" + i + ")");
                                MethodBody targetBody = targetMethod.Body;
                                targetBody.SimplifyMacros();
                                bool canPatch = (targetBody.Instructions.Count > targetMethod.Parameters.Count) && !targetBody.HasVariables;
                                if (canPatch)
                                {
                                    for (int k = 0; k < targetMethod.Parameters.Count; k++)
                                    {
                                        if (targetBody.Instructions[k].OpCode != OpCodes.Ldarg || ((ParameterDefinition)targetBody.Instructions[k].Operand).Index != k)
                                        {
                                            canPatch = false;
                                            break;
                                        }
                                    }
                                    if (canPatch)
                                    {
                                        for (int k = targetMethod.Parameters.Count; k < targetBody.Instructions.Count; k++)
                                        {
                                            if (targetBody.Instructions[k].Operand is ParameterDefinition)
                                            {
                                                canPatch = false;
                                                break;
                                            }
                                        }
                                    }
                                }
                                if (!canPatch)
                                {
                                    logger.Warning("Cannot reimport the instructions from " + targetMethod.FullName + " (not yet supported)!");
                                    continue;
                                }
                                ILProcessor        proc = mdefBody.GetILProcessor();
                                List <Instruction> targetInstructions = new List <Instruction>(targetBody.Instructions.Count - targetMethod.Parameters.Count);
                                int _k = 0; Instruction before = instr;
                                //create nop instructions to simplify creating jumps (the instruction and the operand will be changed afterwards)
                                for (int k = targetMethod.Parameters.Count; k < targetBody.Instructions.Count; k++, _k++)
                                {
                                    Instruction nopInstr = proc.Create(OpCodes.Nop);
                                    targetInstructions.Add(nopInstr);
                                    HelperClass.SafeInsertAfter(proc, before, nopInstr);
                                    //proc.InsertAfter(before, nopInstr);
                                    before = nopInstr;
                                }
                                _k = 0;
                                for (int k = targetMethod.Parameters.Count; k < targetBody.Instructions.Count; k++, _k++)
                                {
                                    Instruction curInstr = targetBody.Instructions[k];
                                    switch (curInstr.OpCode.Code)
                                    {
                                    case Mono.Cecil.Cil.Code.Ret:                                            //OpCodes.Ret.Code:
                                        HelperClass.SafeRemove(proc, targetInstructions[_k]);
                                        //proc.Remove(targetInstructions[_k]);
                                        targetInstructions.RemoveAt(_k);
                                        break;

                                    default:
                                        targetInstructions[_k].OpCode = curInstr.OpCode;
                                        if (curInstr.Operand is Instruction)
                                        {
                                            Instruction targetedInstruction = (Instruction)curInstr.Operand;
                                            int         instrIndex = -1; int targetInstrIndex = -1;
                                            for (int l = targetMethod.Parameters.Count; l < targetBody.Instructions.Count; l++)
                                            {
                                                if (targetBody.Instructions[l].Equals(targetedInstruction))
                                                {
                                                    instrIndex       = l;
                                                    targetInstrIndex = l - targetMethod.Parameters.Count;
                                                    break;
                                                }
                                            }
                                            if (instrIndex == -1)
                                            {
                                                throw new Exception("Unable to find the target of instruction #" + k + " in " + targetMethod.FullName + "!");
                                            }
                                            if (targetBody.Instructions[instrIndex].OpCode == OpCodes.Ret)
                                            {
                                                targetInstructions[_k].Operand = targetInstructions[targetInstructions.Count - 1].Next;
                                            }
                                            else
                                            {
                                                targetInstructions[_k].Operand = targetInstructions[targetInstrIndex];
                                            }
                                        }
                                        else if (curInstr.Operand is Instruction[])
                                        {
                                            Instruction[] oldTargetList   = (Instruction[])curInstr.Operand;
                                            Instruction[] newInstructions = new Instruction[oldTargetList.Length];
                                            for (int l = 0; l < oldTargetList.Length; l++)
                                            {
                                                Instruction targetedInstruction = oldTargetList[l];
                                                int         instrIndex = -1; int targetInstrIndex = -1;
                                                for (int m = targetMethod.Parameters.Count; m < targetBody.Instructions.Count; m++)
                                                {
                                                    if (targetBody.Instructions[l].Equals(targetedInstruction))
                                                    {
                                                        instrIndex       = l;
                                                        targetInstrIndex = l - targetMethod.Parameters.Count;
                                                        break;
                                                    }
                                                }
                                                if (instrIndex == -1)
                                                {
                                                    throw new Exception("Unable to find the target of instruction #" + k + " in " + targetMethod.FullName + "!");
                                                }
                                                if (targetBody.Instructions[instrIndex].OpCode == OpCodes.Ret)
                                                {
                                                    newInstructions[l] = targetInstructions[targetInstructions.Count - 1].Next;
                                                }
                                                else
                                                {
                                                    newInstructions[l] = targetInstructions[targetInstrIndex];
                                                }
                                            }
                                            targetInstructions[_k].Operand = newInstructions;
                                        }
                                        else if (curInstr.Operand is MethodReference)
                                        {
                                            targetInstructions[_k].Operand = curInstr.Operand;                                                    //module.Import(((MethodReference)curInstr.Operand).Resolve());
                                        }
                                        else if (curInstr.Operand is FieldReference)
                                        {
                                            targetInstructions[_k].Operand = curInstr.Operand;                                                    //module.Import(((FieldReference)curInstr.Operand).Resolve());
                                        }
                                        else if (curInstr.Operand is TypeReference)
                                        {
                                            targetInstructions[_k].Operand = curInstr.Operand;                                                    //module.Import(((TypeReference)curInstr.Operand).Resolve());
                                        }
                                        else if (curInstr.Operand is IMetadataTokenProvider)
                                        {
                                            throw new Exception("Unsupported operand type IMetadataTokenProvider in " + targetMethod.FullName + "!");
                                            //IMetadataTokenProvider provider = (IMetadataTokenProvider)curInstr.Operand;
                                            //string name = provider.MetadataToken.ToString();
                                            //targetInstructions[_k].Operand = null;//module.Import(((TypeReference)curInstr.Operand).Resolve());
                                        }
                                        else
                                        {
                                            targetInstructions[_k].Operand = curInstr.Operand;
                                        }
                                        break;
                                    }
                                }

                                HelperClass.PatchInstructionReferences(mdefBody, instr, (targetInstructions.Count > 0) ? targetInstructions[0] : instr.Next);
                                HelperClass.SafeRemove(proc, instr);
                                i--;

                                stat_obfCall++;
                            }
                        }
                        else if (instr.OpCode == OpCodes.Ldsfld)
                        {
                            //remove fields generated by the obfuscator that always are null
                            FieldReference  fref        = (FieldReference)instr.Operand;
                            FieldDefinition targetField = fref.Resolve();
                            if (targetField != null && targetField.DeclaringType.Namespace.Equals("A") && targetField.IsAssembly)
                            {
                                if (targetField.DeclaringType.Fields.Count == 1 && targetField.DeclaringType.Methods.Count == 0)
                                {
                                    if (!suspectFields.ContainsKey(targetField))
                                    {
                                        FieldRemoveInfo fieldInfo = new FieldRemoveInfo();
                                        suspectFields.Add(targetField, fieldInfo);
                                    }
                                    suspectFields[targetField].references.Add(new InstructionIdentifier(mdefBody, instr));
                                }
                            }
                        }
                        else if (instr.OpCode == OpCodes.Stsfld)
                        {
                            //make sure the fields to remove really are not written to (doesn't work for structs whose members are altered)
                            FieldReference  fref        = (FieldReference)instr.Operand;
                            FieldDefinition targetField = fref.Resolve();
                            if (targetField != null && targetField.DeclaringType.Namespace.Equals("A") && targetField.IsAssembly)
                            {
                                if (targetField.DeclaringType.Fields.Count == 1 && targetField.DeclaringType.Methods.Count == 0)
                                {
                                    if (!suspectFields.ContainsKey(targetField))
                                    {
                                        FieldRemoveInfo fieldInfo = new FieldRemoveInfo();
                                        suspectFields.Add(targetField, fieldInfo);
                                    }
                                    suspectFields[targetField].shouldRemove = false;
                                }
                            }
                        }
                        else if ((instr.OpCode == OpCodes.Dup) && ((i + 1) < mdefBody.Instructions.Count) && (mdefBody.Instructions[i + 1].OpCode == OpCodes.Pop))
                        {
                            ILProcessor proc = mdefBody.GetILProcessor();
                            HelperClass.PatchInstructionReferences(mdefBody, instr, mdefBody.Instructions[i + 2]);
                            HelperClass.SafeRemove(proc, mdefBody.Instructions[i + 1]);
                            HelperClass.SafeRemove(proc, instr);
                            i--;
                            stat_duppop++;
                        }
                        else if (i > 0 &&
                                 (instr.OpCode == OpCodes.Switch) &&
                                 ((Instruction[])instr.Operand).Length == 1 && ((Instruction[])instr.Operand)[0] == mdefBody.Instructions[i - 1])
                        {
                            Instruction ldInstr = mdefBody.Instructions[i - 1];
                            HelperClass.PatchInstructionReferences(mdefBody, ldInstr, mdefBody.Instructions[i + 1]);
                            ILProcessor proc = mdefBody.GetILProcessor();
                            HelperClass.SafeRemove(proc, mdefBody.Instructions[i - 1]);
                            HelperClass.SafeRemove(proc, instr);
                            i -= 2;
                            stat_obfSwitch++;
                        }
                        else if ((instr.OpCode == OpCodes.Ldc_I4_1) && ((i + 4) < mdefBody.Instructions.Count) &&
                                 (mdefBody.Instructions[i + 1].OpCode.Code == Code.Brtrue_S) &&
                                 (mdefBody.Instructions[i + 2].OpCode.Code == Code.Ldtoken) &&
                                 (mdefBody.Instructions[i + 3].OpCode.Code == Code.Pop)
                                 )
                        {
                            Instruction ldInstr = mdefBody.Instructions[i - 1];
                            HelperClass.PatchInstructionReferences(mdefBody, instr, mdefBody.Instructions[i + 4]);
                            ILProcessor proc = mdefBody.GetILProcessor();
                            for (int k = 0; k < 4; k++)
                            {
                                HelperClass.SafeRemove(proc, mdefBody.Instructions[i]);
                            }
                            i--;
                            stat_obfIf++;
                        }
                    }
                }
                if ((methodIndex % (mdefs.Length / 10)) == 0 && methodIndex > 0)
                {
                    logger.KeyInfo("Removed garbage from method #" + (methodIndex + 1) + ".");
                }
            }
            foreach (FieldRemoveInfo info in suspectFields.Values)
            {
                if (info.shouldRemove)
                {
                    foreach (InstructionIdentifier ident in info.references)
                    {
                        ILProcessor proc     = ident.body.GetILProcessor();
                        Instruction newInstr = proc.Create(OpCodes.Ldnull);
                        HelperClass.PatchInstructionReferences(ident.body, ident.instr, newInstr);
                        HelperClass.SafeInsertAfter(proc, ident.instr, newInstr);
                        HelperClass.SafeRemove(proc, ident.instr);
                        stat_nullField++;
                    }
                }
            }
            List <TypeDefinition> referencedTypes = new List <TypeDefinition>();

            for (int methodIndex = 0; methodIndex < mdefs.Length; methodIndex++)
            {
                MethodDefinition mdef = mdefs[methodIndex];
                if (mdef.HasBody)
                {
                    MethodBody mdefBody = mdef.Body;
                    for (int k = 0; k < mdefBody.Instructions.Count; k++)
                    {
                        Instruction instr = mdefBody.Instructions[k];
                        if (instr.Operand is MethodReference)
                        {
                            MethodDefinition targetMethod = ((MethodReference)instr.Operand).Resolve();
                            if (targetMethod != null)
                            {
                                referencedTypes.Add(targetMethod.DeclaringType);
                            }
                        }
                        else if (instr.Operand is FieldReference)
                        {
                            FieldDefinition targetField = ((FieldReference)instr.Operand).Resolve();
                            if (targetField != null)
                            {
                                referencedTypes.Add(targetField.DeclaringType);
                            }
                        }
                        else if (instr.Operand is TypeReference)
                        {
                            TypeDefinition targetType = ((TypeReference)instr.Operand).Resolve();
                            if (targetType != null)
                            {
                                referencedTypes.Add(targetType);
                            }
                        }
                    }
                }
            }
            for (int i = module.Types.Count - 1; i >= 0; i--)
            {
                TypeDefinition tdef = module.Types[i];
                if (tdef.Namespace.Equals("A") && !tdef.IsEnum && !tdef.Name.Equals("AssemblyInfoAttribute"))
                {
                    if (!referencedTypes.Contains(tdef))
                    {
                        module.Types.RemoveAt(i);
                        stat_obfClasses++;
                    }
                }
            }
            logger.KeyInfo("Removed " +
                           stat_obfCall + " extracted method calls, " +
                           stat_nullField + " always null fields, " +
                           stat_duppop + " senseless dup/pop, " +
                           stat_obfSwitch + " senseless switches, " +
                           stat_obfIf + " senseless conditions, " +
                           stat_obfClasses + " obfuscator classes.");
        }
Example #2
0
        public static void Apply(ModuleDefinition module, Logger logger)
        {
            //AppDomain currentDomain = AppDomain.CurrentDomain;
            //currentDomain.AssemblyResolve += new ResolveEventHandler(LoadFromSameFolder);
            Assembly assembly = Assembly.LoadFrom(Deobfuscator.sourceAssemblyPath.path + Path.DirectorySeparatorChar + Deobfuscator.sourceAssemblyPath.filename);

            Module target = assembly.GetModules()[0];

            logger.KeyInfo("Looking for string decryption calls...");
            int decryptStats = 0;
            List <MethodDefinition> decryptMethods = new List <MethodDefinition>();

            MethodDefinition[] mdefs = HelperClass.findMembers <MethodDefinition>(module, null, true);
            for (int __i = 0; __i < mdefs.Length; __i++)
            {
                MethodDefinition mdef = mdefs[__i];
                if (mdef.HasBody)
                {
                    Mono.Cecil.Cil.MethodBody mdefBody = mdef.Body;
                    for (int i = 0; i < (mdefBody.Instructions.Count - 1); i++)
                    {
                        Instruction instr1 = mdefBody.Instructions[i];
                        Instruction instr2 = mdefBody.Instructions[i + 1];
                        if (loadIntegerCodes.ContainsKey(instr1.OpCode.Code) &&
                            (instr2.OpCode == OpCodes.Call))
                        {
                            int key = loadIntegerCodes[instr1.OpCode.Code](instr1.Operand);                            //(int)instr1.Operand;
                            MethodDefinition targetMethod = ((MethodReference)instr2.Operand).Resolve();
                            if (targetMethod != null && targetMethod.IsStatic &&
                                targetMethod.Parameters.Count == 1 && targetMethod.ReturnType.FullName.Equals("System.String") &&
                                targetMethod.HasBody && targetMethod.Body.Instructions.Count > 5 && targetMethod.Body.Instructions[4].OpCode == OpCodes.Ldelem_U1)
                            {
                                Type       decryptorType   = null;
                                MethodInfo decryptorMethod = null;
                                try
                                {
                                    decryptorType   = target.GetType(targetMethod.DeclaringType.FullName);
                                    decryptorMethod = decryptorType.GetMethod(targetMethod.Name, BindingFlags.Static | BindingFlags.NonPublic);
                                    string      decrypted = (string)decryptorMethod.Invoke(null, new object[] { key });
                                    Instruction newInstr;
                                    ILProcessor proc = mdefBody.GetILProcessor();
                                    HelperClass.SafeInsertBefore(proc, instr1, (newInstr = mdefBody.GetILProcessor().Create(OpCodes.Ldstr, decrypted)));
                                    //mdefBody.GetILProcessor().InsertBefore(instr1, (newInstr = mdefBody.GetILProcessor().Create(OpCodes.Ldstr, decrypted)));
                                    HelperClass.PatchInstructionReferences(mdefBody, instr1, newInstr);
                                    for (int _i = 0; _i < 2; _i++)
                                    {
                                        HelperClass.SafeRemove(proc, mdefBody.Instructions[i + 1]);
                                    }
                                    //mdefBody.Instructions.RemoveAt(i+1);
                                    if (!decryptMethods.Contains(targetMethod))
                                    {
                                        decryptMethods.Add(targetMethod);
                                    }

                                    //logger.Info(decrypted);
                                    //i++;
                                    decryptStats++;
                                }
                                catch (Exception e)
                                {
                                    logger.Warning("Unable to decrypt " + targetMethod.Name + " (" + key + ") :\r\n" + e.ToString());
                                    continue;
                                }
                            }
                        }
                    }
                }
                if ((__i % (mdefs.Length / 10)) == 0 && __i > 0)
                {
                    logger.KeyInfo("Decrypted strings from method #" + (__i + 1) + ".");
                }
            }
            for (int i = 0; i < decryptMethods.Count; i++)
            {
                MethodDefinition mdef = decryptMethods[i];
                //module.Types.Remove(mdef.DeclaringType);
                mdef.DeclaringType.Name = "decryptor" + i;
                mdef.Name = "Decrypt";
            }
            logger.KeyInfo("Finished decrypting " + decryptStats + " strings!");
        }