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`: