From 332d9e0d00222e02eed69d1b4d0960f6d5989642 Mon Sep 17 00:00:00 2001 From: ivan-danilov Date: Wed, 17 Oct 2018 21:53:51 +0300 Subject: [PATCH 1/2] Add InputSymbolMap attribute to ConfuserProject to allow the map for the future runs Sometimes it is necessary to provide a patch for obfuscated software. Having different obfuscation applied to patched version comparing with the released one effectively means the patched version cannot be deployed without replacing every obfuscated assembly. This change makes it possible to provide a symbol map from a previous obfuscation and preserves the renames specified there. --- Confuser.Core/ConfuserContext.cs | 6 ++++++ Confuser.Core/ConfuserEngine.cs | 4 ++++ Confuser.Core/Project/ConfuserPrj.xsd | 1 + Confuser.Core/Project/ConfuserProject.cs | 12 ++++++++++++ Confuser.Renamer/NameService.cs | 22 +++++++++++++++++++++- docs/ProjectFormat.md | 5 +++++ 6 files changed, 49 insertions(+), 1 deletion(-) diff --git a/Confuser.Core/ConfuserContext.cs b/Confuser.Core/ConfuserContext.cs index 56b7c806a..d8265384e 100644 --- a/Confuser.Core/ConfuserContext.cs +++ b/Confuser.Core/ConfuserContext.cs @@ -74,6 +74,12 @@ public ServiceRegistry Registry { /// The output directory. public string OutputDirectory { get; internal set; } + /// + /// Gets the input symbol map (optional). + /// + /// The input symbol map. + public string InputSymbolMap { get; internal set; } + /// /// Gets the packer. /// diff --git a/Confuser.Core/ConfuserEngine.cs b/Confuser.Core/ConfuserEngine.cs index 211da3a56..3e0697cf1 100644 --- a/Confuser.Core/ConfuserEngine.cs +++ b/Confuser.Core/ConfuserEngine.cs @@ -91,6 +91,10 @@ static void RunInternal(ConfuserParameters parameters, CancellationToken token) context.Resolver = asmResolver; context.BaseDirectory = Path.Combine(Environment.CurrentDirectory, parameters.Project.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar); context.OutputDirectory = Path.Combine(parameters.Project.BaseDirectory, parameters.Project.OutputDirectory.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar); + + if (!string.IsNullOrWhiteSpace(parameters.Project.InputSymbolMap)) + context.InputSymbolMap = Path.Combine(parameters.Project.BaseDirectory, parameters.Project.InputSymbolMap); + foreach (string probePath in parameters.Project.ProbePaths) asmResolver.PostSearchPaths.Insert(0, Path.Combine(context.BaseDirectory, probePath)); diff --git a/Confuser.Core/Project/ConfuserPrj.xsd b/Confuser.Core/Project/ConfuserPrj.xsd index bdad775b7..32372d38f 100644 --- a/Confuser.Core/Project/ConfuserPrj.xsd +++ b/Confuser.Core/Project/ConfuserPrj.xsd @@ -68,6 +68,7 @@ + diff --git a/Confuser.Core/Project/ConfuserProject.cs b/Confuser.Core/Project/ConfuserProject.cs index d6307fadd..b2cdad2f1 100644 --- a/Confuser.Core/Project/ConfuserProject.cs +++ b/Confuser.Core/Project/ConfuserProject.cs @@ -449,6 +449,12 @@ public ConfuserProject() { /// The base directory. public string BaseDirectory { get; set; } + /// + /// Gets or sets the input symbol map file. + /// + /// The file with input symbol map. + public string InputSymbolMap { get; set; } + /// /// Gets a list of protection rules that applies globally. /// @@ -556,6 +562,11 @@ public void Load(XmlDocument doc) { else Seed = null; + if (docElem.Attributes["inputSymbolMap"] != null) + InputSymbolMap = docElem.Attributes["inputSymbolMap"].Value.NullIfEmpty(); + else + InputSymbolMap = null; + if (docElem.Attributes["debug"] != null) Debug = bool.Parse(docElem.Attributes["debug"].Value); else @@ -597,6 +608,7 @@ public void Load(XmlDocument doc) { public ConfuserProject Clone() { var ret = new ConfuserProject(); ret.Seed = Seed; + ret.InputSymbolMap = InputSymbolMap; ret.Debug = Debug; ret.OutputDirectory = OutputDirectory; ret.BaseDirectory = BaseDirectory; diff --git a/Confuser.Renamer/NameService.cs b/Confuser.Renamer/NameService.cs index e35402373..16b62f815 100644 --- a/Confuser.Renamer/NameService.cs +++ b/Confuser.Renamer/NameService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using Confuser.Core; @@ -58,6 +59,8 @@ internal class NameService : INameService { public NameService(ConfuserContext context) { this.context = context; + if (context.InputSymbolMap != null) + LoadInputSymbolMap(context.InputSymbolMap); storage = new VTableStorage(context.Logger); random = context.Registry.GetService().GetRandomGenerator(NameProtection._FullId); nameSeed = random.NextBytes(20); @@ -71,6 +74,23 @@ public NameService(ConfuserContext context) { }; } + private void LoadInputSymbolMap(string inputSymbolMapPath) + { + var lineNum = 0; + foreach (var line in File.ReadLines(inputSymbolMapPath)) + { + lineNum++; + if (string.IsNullOrWhiteSpace(line)) continue; + var fields = line.Split('\t'); + if (fields.Length != 2) + throw new FileFormatException(string.Format("Cannot read input symbol map {0}:{1}", inputSymbolMapPath, lineNum)); + var key = fields[0]; + var value = fields[1]; + nameMap2.Add(key, value); + nameMap1.Add(value, key); + } + } + public IList Renamers { get; private set; } public VTableStorage GetVTables() { @@ -227,7 +247,7 @@ public string ObfuscateName(string name, RenameMode mode) { byte[] hash = Utils.Xor(Utils.SHA1(Encoding.UTF8.GetBytes(name)), nameSeed); for (int i = 0; i < 100; i++) { newName = ObfuscateNameInternal(hash, mode); - if (!identifiers.Contains(MakeGenericName(newName, count))) + if (!identifiers.Contains(MakeGenericName(newName, count)) && !nameMap2.ContainsKey(newName)) break; hash = Utils.SHA1(hash); } diff --git a/docs/ProjectFormat.md b/docs/ProjectFormat.md index 0618cce5f..b8b29b432 100644 --- a/docs/ProjectFormat.md +++ b/docs/ProjectFormat.md @@ -27,6 +27,11 @@ The seed of the random generator in protection process. Indicates whether the debug symbols (*.pdb) are generated. Currently unused. +`inputSymbolMap` +Path to symbols map relative to `baseDir`. +It if is set, rename protection will respect name mappings specified there and only generate additional ones as needed. Does not make sense for non-reversible rename modes. +Symbol map file can be taken from previous obfuscation or created manually. Every non-empty line must contain exactly one tab character that separates two values: the first is obfuscated name and the second is original one. No duplications in either original or obfuscated names are allowed. + **Elements:** `rule`: From da68742fecd1863877b6473e3bf4ced739892ac9 Mon Sep 17 00:00:00 2001 From: ivan-danilov Date: Tue, 19 Mar 2019 14:45:29 +0200 Subject: [PATCH 2/2] Revert "Add underscore back to decodable names" This reverts commit ef61ef1f37faa4c75eb5831ab2c7cb323e87b1e3. Not sure why underscores were first added, but it breaks decoding of existing obfuscated stacks with given symbol maps. --- Confuser.Renamer/NameService.cs | 4 ++-- ConfuserEx/StackTraceDecoder.xaml.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Confuser.Renamer/NameService.cs b/Confuser.Renamer/NameService.cs index 16b62f815..37cae7f15 100644 --- a/Confuser.Renamer/NameService.cs +++ b/Confuser.Renamer/NameService.cs @@ -192,10 +192,10 @@ string ObfuscateNameInternal(byte[] hash, RenameMode mode) { return Utils.EncodeString(hash, asciiCharset); case RenameMode.Decodable: IncrementNameId(); - return "_" + Utils.EncodeString(hash, alphaNumCharset); + return Utils.EncodeString(hash, alphaNumCharset); case RenameMode.Sequential: IncrementNameId(); - return "_" + Utils.EncodeString(nameId, alphaNumCharset); + return Utils.EncodeString(nameId, alphaNumCharset); default: throw new NotSupportedException("Rename mode '" + mode + "' is not supported."); diff --git a/ConfuserEx/StackTraceDecoder.xaml.cs b/ConfuserEx/StackTraceDecoder.xaml.cs index 6a7b74cd5..95e4dd4d5 100644 --- a/ConfuserEx/StackTraceDecoder.xaml.cs +++ b/ConfuserEx/StackTraceDecoder.xaml.cs @@ -56,7 +56,7 @@ void ChooseMapPath(object sender, RoutedEventArgs e) { } } - readonly Regex mapSymbolMatcher = new Regex("_[a-zA-Z0-9]+"); + readonly Regex mapSymbolMatcher = new Regex("[a-zA-Z0-9]+"); readonly Regex passSymbolMatcher = new Regex("[a-zA-Z0-9_$]{23,}"); ReversibleRenamer renamer;