diff --git a/Obfuscar/Helpers/TypeReferenceExtensions.cs b/Obfuscar/Helpers/TypeReferenceExtensions.cs index 79a13d1b..cab31a12 100644 --- a/Obfuscar/Helpers/TypeReferenceExtensions.cs +++ b/Obfuscar/Helpers/TypeReferenceExtensions.cs @@ -68,10 +68,10 @@ public static string GetGenericName(this TypeReference type) for (int i = 0; i < type.GenericParameters.Count; i++) { GenericParameter genericName = type.GenericParameters[i]; - genericName.Name = nameMaker.UniqueName(i); + genericName.Name = nameMaker.UniqueName(i, null, genericName.Name); } - type.GetElementType().Name = nameMaker.UniqueName(type.GenericParameters.Count); + type.GetElementType().Name = nameMaker.UniqueName(type.GenericParameters.Count, null, type.Name); return type.Name; } } diff --git a/Obfuscar/NameGroup.cs b/Obfuscar/NameGroup.cs index 9eb7a30a..c2144722 100644 --- a/Obfuscar/NameGroup.cs +++ b/Obfuscar/NameGroup.cs @@ -37,13 +37,13 @@ class NameGroup : IEnumerable HashSet names = new HashSet(); - public string GetNext() + public string GetNext(string originalName) { int index = _random.Next(20); string name; for (;;) { - name = NameMaker.Instance.UniqueName(index++); + name = NameMaker.Instance.UniqueName(index++, null, originalName); if (!names.Contains(name)) return name; } @@ -72,14 +72,14 @@ public void Remove(string name) names.Remove(name); } - public static string GetNext(IEnumerable groups) + public static string GetNext(IEnumerable groups, string originalName) { int index = 0; string name; for (;;) { - name = NameMaker.Instance.UniqueName(index++); + name = NameMaker.Instance.UniqueName(index++, null, originalName); bool contained = false; foreach (NameGroup group in groups) diff --git a/Obfuscar/NameMaker.cs b/Obfuscar/NameMaker.cs index afa58544..b75b8dcc 100644 --- a/Obfuscar/NameMaker.cs +++ b/Obfuscar/NameMaker.cs @@ -26,6 +26,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace Obfuscar @@ -74,6 +75,9 @@ internal NameMaker() koreanChars = new string(chars.ToArray()); UseKoreanChars = false; + + // inherit global debug model obfuscation settings + UseDebugVersionNames = Instance?.UseDebugVersionNames ?? false; // null possible when we create first Instance } private void ShuffleArray(IList list, Random rnd) @@ -117,16 +121,20 @@ public bool UseKoreanChars } } - public string UniqueName(int index) - { - return UniqueName(index, null); - } + /// + /// Try to keep it readable for debug purposes (obfuscate/rename it but keep names similar to what was before obfuscation) + /// + public bool UseDebugVersionNames { get; set; } - public string UniqueName(int index, string sep) + public string UniqueName(int index, string sep, string originalName) { + var postfix = string.IsNullOrEmpty(originalName) || !UseDebugVersionNames + ? string.Empty + : "_" + originalName.Split('.', '>').Last(); + // optimization for simple case if (index < numUniqueChars) - return uniqueChars[index].ToString(); + return uniqueChars[index].ToString() + postfix; Stack stack = new Stack(); @@ -147,22 +155,22 @@ public string UniqueName(int index, string sep) builder.Append(stack.Pop()); } - return builder.ToString(); + return builder.ToString() + postfix; } - public string UniqueNestedTypeName(int index) + public string UniqueNestedTypeName(int index, string originalName) { - return UniqueName(index, null); + return UniqueName(index, null, originalName); } - public string UniqueTypeName(int index) + public string UniqueTypeName(int index, string originalName) { - return UniqueName(index % numUniqueChars, "."); + return UniqueName(index % numUniqueChars, ".", originalName); } - public string UniqueNamespace(int index) + public string UniqueNamespace(int index, string originalName) { - return UniqueName(index / numUniqueChars, "."); + return UniqueName(index / numUniqueChars, ".", originalName); } } } diff --git a/Obfuscar/Obfuscator.cs b/Obfuscar/Obfuscator.cs index d2d3a4e2..c9132320 100644 --- a/Obfuscar/Obfuscator.cs +++ b/Obfuscar/Obfuscator.cs @@ -252,6 +252,8 @@ private void LoadFromReader(XDocument reader, string projectFileDirectory) NameMaker.Instance.UseUnicodeChars = true; if (Project.Settings.UseKoreanNames) NameMaker.Instance.UseKoreanChars = true; + if (Project.Settings.UseDebugVersionNames) + NameMaker.Instance.UseDebugVersionNames = true; LogOutput("Loading assemblies..."); LogOutput("Extra framework folders: "); @@ -521,8 +523,8 @@ private void ProcessField(FieldDefinition field, TypeKey typeKey, Dictionary @@ -689,19 +691,19 @@ public void RenameTypes(HashSet namesInXaml) if (type.IsNested) { ns = ""; - name = NameMaker.Instance.UniqueNestedTypeName(type.DeclaringType.NestedTypes.IndexOf(type)); + name = NameMaker.Instance.UniqueNestedTypeName(type.DeclaringType.NestedTypes.IndexOf(type), type.Name); } else { if (Project.Settings.ReuseNames) { - name = NameMaker.Instance.UniqueTypeName(typeIndex); - ns = NameMaker.Instance.UniqueNamespace(typeIndex); + name = NameMaker.Instance.UniqueTypeName(typeIndex, type.Name); + ns = NameMaker.Instance.UniqueNamespace(typeIndex, type.Name); } else { - name = NameMaker.Instance.UniqueName(_uniqueTypeNameIndex); - ns = NameMaker.Instance.UniqueNamespace(_uniqueTypeNameIndex); + name = NameMaker.Instance.UniqueName(_uniqueTypeNameIndex, null, type.Name); + ns = NameMaker.Instance.UniqueNamespace(_uniqueTypeNameIndex, type.Name); _uniqueTypeNameIndex++; } } @@ -939,7 +941,8 @@ public void RenameProperties(HashSet allTypeNamesRelatedToNpcOrInXaml) { //only rename property to avoid method getter issues var propKey = new PropertyKey(typeKey, prop); - var newName = NameMaker.Instance.UniqueName(Project.Settings.ReuseNames ? index++ : _uniqueMemberNameIndex++); + var newName = NameMaker.Instance.UniqueName( + Project.Settings.ReuseNames ? index++ : _uniqueMemberNameIndex++, null, prop.Name); RenameProperty(info, propKey, prop, newName); } } @@ -1002,7 +1005,8 @@ private int ProcessProperty(TypeKey typeKey, PropertyDefinition prop, AssemblyIn else if (prop.CustomAttributes.Count > 0) { // If a property has custom attributes we don't remove the property but rename it instead. - var newName = NameMaker.Instance.UniqueName(Project.Settings.ReuseNames ? index++ : _uniqueMemberNameIndex++); + var newName = NameMaker.Instance.UniqueName(Project.Settings.ReuseNames ? index++ : _uniqueMemberNameIndex++, + null, prop.Name); RenameProperty(info, propKey, prop, newName); } else @@ -1301,7 +1305,7 @@ private void RenameVirtualMethod(Dictionary sigNames, MethodDefini NameGroup nameGroup = GetNameGroup(sigNames, sig); - string newName = nameGroup.GetNext(); + string newName = nameGroup.GetNext(method.Name); // make sure the name groups is updated nameGroup.Add(newName); @@ -1821,7 +1825,7 @@ public void ProcessStrings(MethodDefinition method, MethodDefinition individualStringMethodDefinition; if (!_methodByString.TryGetValue(str, out individualStringMethodDefinition)) { - string methodName = NameMaker.Instance.UniqueName(_nameIndex++); + string methodName = NameMaker.Instance.UniqueName(_nameIndex++, null, "StringReplacedWithCall"); // Add the string to the data array byte[] stringBytes = Encoding.UTF8.GetBytes(str); diff --git a/Obfuscar/Settings.cs b/Obfuscar/Settings.cs index f17a165e..7fcbba2a 100644 --- a/Obfuscar/Settings.cs +++ b/Obfuscar/Settings.cs @@ -46,6 +46,7 @@ public Settings(Variables vars) ReuseNames = XmlConvert.ToBoolean(vars.GetValue("ReuseNames", "true")); UseUnicodeNames = XmlConvert.ToBoolean(vars.GetValue("UseUnicodeNames", "false")); UseKoreanNames = XmlConvert.ToBoolean(vars.GetValue("UseKoreanNames", "false")); + UseDebugVersionNames = XmlConvert.ToBoolean(vars.GetValue("UseDebugVersionNames", "false")); HideStrings = XmlConvert.ToBoolean(vars.GetValue("HideStrings", "true")); Optimize = XmlConvert.ToBoolean(vars.GetValue("OptimizeMethods", "true")); SuppressIldasm = XmlConvert.ToBoolean(vars.GetValue("SuppressIldasm", "true")); @@ -98,6 +99,11 @@ public Settings(Variables vars) public bool UseKoreanNames { get; } + /// + /// Try to keep it readable for debug purposes (obfuscate/rename it but keep names similar to what was before obfuscation) + /// + public bool UseDebugVersionNames { get; } + public bool AbortOnInconsistentState { get; } public bool LogRecoveredInconsistentState { get; }