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 }
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); } } }); }