Example #1
0
        public void BeginProcessing()
        {
#if DEBUG
            Stopwatch debugStopwatch = new Stopwatch();
            debugStopwatch.Start();

            try
            {
#endif
            if (Processed)
            {
                throw new NameMapperProcessingException("Already processed! This class is a one-time use.");
            }

            // -- BEGIN PROCESSING

            //	 -- Trying to find exactly same methods using entry as a start point.

            var cleanEntry = FindEntryPoint(CleanModule);
            var obfEntry   = FindEntryPoint(ObfModule);

            Message(XConsole.Info("Recursing using entry as a start point."));
            StartRecurseThread(cleanEntry, obfEntry);
            WaitMakeSure();

            //	 --

            //	 -- 1. Getting unique methods from both obf and clean types as two separate lists (NameProcessed, but not IsFullyProcessed)
            //	 -- 2. Comparing unique obf methods to unique clean methods, recursing same methods
            //	 -- 3. IsFullyProcessed = true

            Message(XConsole.Info("Recursing unique methods."));

            int prevCount = -1;

            var procMan = _namableProcessor.Processed;

            while (true)
            {
                foreach (var item in procMan.Types)
                {
                    if (item.IsFullyProcessed)
                    {
                        continue;
                    }

                    var cleanMethods = item.Clean.ScopeType.ResolveTypeDef()?.Methods.Where(x => !x.IsNameObfuscated()).ToList();
                    var obfMethods   = item.Obfuscated.ScopeType.ResolveTypeDef()?.Methods.Where(x => !x.IsEazInternalName()).ToList();

                    if (cleanMethods is null || obfMethods is null)
                    {
                        continue;
                    }

                    List <MethodDef> cleanUniqueMethods = cleanMethods.GetUniqueMethods();
                    List <MethodDef> obfUniqueMethods   = obfMethods.GetUniqueMethods();

                    foreach (var cleanMethod in cleanUniqueMethods)
                    {
                        var obfMethod = obfUniqueMethods.FirstOrDefault(x => AreOpcodesEqual(cleanMethod?.Body?.Instructions, x.Body?.Instructions) == -1);

                        if (obfMethod != null)
                        {
                            StartRecurseThread(cleanMethod, obfMethod);
                        }
                    }

                    item.IsFullyProcessed = true;
                }

                WaitMakeSure();

                int count = procMan.Types.Count;

                if (count == prevCount)
                {
                    break;
                }

                Message(XConsole.Info($"{count - prevCount} new types! Processing..."));

                prevCount = count;
            }

            //   --

            if (DeobfuscateNames)
            {
                //   -- Filling up interfaces

                foreach (var type in procMan.Types)
                {
                    var obfTypeDef = type.Obfuscated.ScopeType.ResolveTypeDef();

                    if (obfTypeDef.HasInterfaces)
                    {
                        var interfaceMethods = obfTypeDef.Interfaces.Where(x => x.Interface.IsFromModule(this)).SelectMany(x => x.Interface.ResolveTypeDef().Methods).Where(x => x.IsNameObfuscated()).ToList();

                        foreach (var method in obfTypeDef.Methods)
                        {
                            if (NamePairs.TryGetValue(method.Name, out string obfName))
                            {
                                var interfaceMethod = interfaceMethods.FirstOrDefault(x => x.Name == obfName);

                                if (interfaceMethod != null)
                                {
                                    interfaceMethod.Name = method.Name;
                                }
                            }
                        }
                    }
                }

                //   --

                //   -- Renaming all names left

                var obfCleanDict = NamePairs.Swap();

                var res = new MemberFinder().FindAll(ObfModule);

                foreach (var meth in res.MethodDefs.Select(x => x.Key).Where(x => x.IsNameObfuscated()))
                {
                    if (obfCleanDict.TryGetValue(meth.Name, out string value))
                    {
                        meth.Name = value;
                    }
                }

                foreach (var type in res.TypeDefs.Select(x => x.Key).Where(x => x.IsNameObfuscated()))
                {
                    if (obfCleanDict.TryGetValue(type.Name, out string value))
                    {
                        type.Name = value;
                    }
                }

                foreach (var field in res.FieldDefs.Select(x => x.Key).Where(x => x.IsNameObfuscated()))
                {
                    if (obfCleanDict.TryGetValue(field.Name, out string value))
                    {
                        field.Name = value;
                    }
                }

                foreach (var genParam in res.GenericParams.Select(x => x.Key).Where(x => x.IsNameObfuscated()))
                {
                    if (obfCleanDict.TryGetValue(genParam.Name, out string value))
                    {
                        genParam.Name = value;
                    }
                }

                //   --
            }

            WaitMakeSure();

            if (_overallErroredMethods > 0)
            {
                Message(XConsole.Warn($"Not all methods are processed! {_overallErroredMethods} left behind."));
            }

            Message(XConsole.Info($"Overall known classes: {procMan.Types.Count}; Fully processed classes: {procMan.Types.Count(x => x.IsFullyProcessed)}"));

            var processedTypesCount = procMan.Types.Count;
            var allTypesCount       = ObfModule.CountTypes(x => !x.IsNameObfuscated());
            var processedPercentage = (float)processedTypesCount / allTypesCount;

            if (processedPercentage < MINIMAL_SUCCESS_PERCENTAGE)
            {
                throw new NameMapperProcessingException($"Processed types percentage: {processedTypesCount}/{allTypesCount} => {processedPercentage * 100}% < {MINIMAL_SUCCESS_PERCENTAGE * 100}% (min), counting as unsuccessful.");
            }

            Processed = true;
#if DEBUG
        }

        catch (Exception ex)
        {
            Message(XConsole.Error(ex.ToString()));
            Console.ReadKey();                     // because debug
        }
        finally
        {
            debugStopwatch.Stop();
            Message(XConsole.Info($"Mapped everything in: {debugStopwatch.ElapsedMilliseconds}ms"));
        }
#endif

            // -- END
        }
Example #2
0
        private void StartRecurseThread(MethodDef cleanMethod, MethodDef obfMethod)
        {
            Interlocked.Increment(ref _inWork);

            ThreadPool.QueueUserWorkItem(state =>
            {
                var lockTaken = false;

                try
                {
                    if (cleanMethod is null || obfMethod is null)
                    {
                        return;
                    }

                    Monitor.Enter(obfMethod, ref lockTaken);                     // clean is used in OperandProcessors.ProcessMethod, hardcoded but that's important

                    if (lockTaken)
                    {
                        var result = _namableProcessor.ProcessMethod(cleanMethod, obfMethod);

                        if (cleanMethod.DeclaringType.IsEazInternalNameRecursive())
                        {
                            return;
                        }

                        if (result == ProcessResult.Ok)
                        {
                            var cleanInstrs = cleanMethod.Body?.Instructions;
                            var obfInstrs   = obfMethod.Body?.Instructions;

                            if (!cleanMethod.HasBody || !obfMethod.HasBody)
                            {
                                return;
                            }

                            // ReSharper disable PossibleNullReferenceException
                            if (cleanInstrs.Count != obfInstrs.Count)
                            {
                                Message(XConsole.Error($"Instruction count differs ({cleanMethod.GetMethodName()}). {cleanInstrs.Count} (clean) {obfInstrs.Count} (obf)."));
                                return;
                            }

                            var idx = AreOpcodesEqual(cleanInstrs, obfInstrs);

                            if (idx > -1)
                            {
                                Message(XConsole.Error($"Instructions differ ({cleanMethod.GetMethodName()}).") + Environment.NewLine +
                                        "-*- Clean instructions:" + Environment.NewLine +
                                        PrintInstructions(cleanInstrs, idx) + Environment.NewLine +
                                        "-*- Obfuscated instructions:" + Environment.NewLine +
                                        PrintInstructions(obfInstrs, idx));
                                return;
                            }

                            for (int i = 0; i < cleanInstrs.Count; i++)
                            {
                                object cleanOperand = cleanInstrs[i].Operand;
                                object obfOperand   = obfInstrs[i].Operand;

                                if (cleanOperand is null || obfOperand is null)
                                {
                                    continue;
                                }

                                if (cleanOperand.GetType() != obfOperand.GetType())
                                {
                                    continue;
                                }

                                if (cleanOperand is IMethodDefOrRef)
                                {
                                    StartRecurseThread(cleanOperand as IMethodDefOrRef, obfOperand as IMethodDefOrRef);
                                }
                                else if (cleanOperand is IType)
                                {
                                    _namableProcessor.ProcessType(cleanOperand as IType, obfOperand as IType);
                                }
                                else if (cleanOperand is FieldDef)
                                {
                                    _namableProcessor.ProcessField(cleanOperand as FieldDef, obfOperand as FieldDef);
                                }
                            }
                        }
                        else if (result.IsError())
                        {
                            Message(XConsole.Error($"An error occurred while trying to process method ({cleanMethod.GetMethodName()}). Result code: {result}."));
                            _overallErroredMethods++;
                        }
                    }
                }
                catch (Exception e)
                {
                    Message(XConsole.Error($"An exception occurred while trying to process method ({cleanMethod.GetMethodName()}). Details:\n{e}"));
                }
                finally
                {
                    Interlocked.Decrement(ref _inWork);

                    if (lockTaken)
                    {
                        Monitor.Exit(obfMethod);
                    }
                }
            });
        }