Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Confuser.CLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static int Main(string[] args) {
bool quiet = false;
bool dumpRequested = false;
string dumpPath = null;
string inputMap = null;
int verbosity = 0;
string outDir = null;
string snKeyPath = null;
Expand Down Expand Up @@ -65,6 +66,9 @@ static int Main(string[] args) {
}, {
"dump:", "write a diagnostic report (optionally to the given file).",
value => { dumpRequested = true; if (!string.IsNullOrEmpty(value)) dumpPath = value; }
}, {
"map=", "reuse names from a previous symbol map for consistent re-obfuscation.",
value => { inputMap = value; }
}
};

Expand Down Expand Up @@ -147,6 +151,9 @@ static int Main(string[] args) {
parameters.Project = proj;
}

if (inputMap != null && parameters.Project != null)
parameters.Project.InputSymbolMap = inputMap;

int retVal = RunProject(parameters, quiet, verbosity, dumpRequested, dumpPath);

if (NeedPause() && !noPause) {
Expand Down Expand Up @@ -284,6 +291,7 @@ static void PrintUsage() {
WriteLine(" -v|verbose : increase verbosity (-v debug, -vv trace).");
WriteLine(" -q|quiet : only show warnings and errors.");
WriteLine(" -dump : write a diagnostic report (-dump=<file> for a custom path).");
WriteLine(" -map : reuse names from a previous symbol map for consistent re-obfuscation.");
}

static void WriteLineWithColor(ConsoleColor color, string txt) {
Expand Down
1 change: 1 addition & 0 deletions Confuser.Core/Project/ConfuserPrj.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<xs:attribute name="baseDir" type="xs:string" use="required" />
<xs:attribute name="seed" type="xs:string" use="optional" />
<xs:attribute name="debug" type="xs:boolean" default="false" />
<xs:attribute name="inputSymbolMap" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:schema>
20 changes: 20 additions & 0 deletions Confuser.Core/Project/ConfuserProject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,14 @@ public ConfuserProject() {
/// <value><c>true</c> if debug symbols are generated; otherwise, <c>false</c>.</value>
public bool Debug { get; set; }

/// <summary>
/// Gets or sets the path to a symbol map from a previous obfuscation run. When set, the
/// renamer reuses the obfuscated names recorded in that map, so re-obfuscation produces
/// consistent names across builds (e.g. to patch already-deployed obfuscated assemblies).
/// </summary>
/// <value>The path to the input symbol map, or <c>null</c> to generate fresh names.</value>
public string InputSymbolMap { get; set; }

/// <summary>
/// Gets or sets the output directory.
/// </summary>
Expand Down Expand Up @@ -594,6 +602,12 @@ public XmlDocument Save() {
elem.Attributes.Append(debugAttr);
}

if (InputSymbolMap != null) {
XmlAttribute mapAttr = xmlDoc.CreateAttribute("inputSymbolMap");
mapAttr.Value = InputSymbolMap;
elem.Attributes.Append(mapAttr);
}

foreach (Rule i in Rules)
elem.AppendChild(i.Save(xmlDoc));

Expand Down Expand Up @@ -655,6 +669,11 @@ public void Load(XmlDocument doc, string baseDirRoot = null) {
else
Debug = false;

if (docElem.Attributes["inputSymbolMap"] != null)
InputSymbolMap = docElem.Attributes["inputSymbolMap"].Value.NullIfEmpty();
else
InputSymbolMap = null;

Packer = null;
Clear();
ProbePaths.Clear();
Expand Down Expand Up @@ -724,6 +743,7 @@ public ConfuserProject Clone() {
var ret = new ConfuserProject();
ret.Seed = Seed;
ret.Debug = Debug;
ret.InputSymbolMap = InputSymbolMap;
ret.OutputDirectory = OutputDirectory;
ret.BaseDirectory = BaseDirectory;
ret.Packer = Packer == null ? null : Packer.Clone();
Expand Down
60 changes: 59 additions & 1 deletion Confuser.Renamer/NameService.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Confuser.Core;
using Confuser.Core.Services;
using Confuser.Renamer.Analyzers;
using Confuser.Renamer.Properties;
using dnlib.DotNet;
using Microsoft.Extensions.Logging;

namespace Confuser.Renamer {
public interface INameService {
Expand Down Expand Up @@ -67,13 +69,15 @@ internal class NameService : INameService {
readonly Dictionary<string, string> _originalToObfuscatedNameMap = new Dictionary<string, string>();
readonly Dictionary<string, string> _obfuscatedToOriginalNameMap = new Dictionary<string, string>();
readonly Dictionary<string, string> _prefixesMap = new Dictionary<string, string>();
readonly bool hasInputMap;
internal ReversibleRenamer reversibleRenamer;

public NameService(ConfuserContext context) {
this.context = context;
storage = new VTableStorage(context.Logger);
random = context.Registry.GetService<IRandomService>().GetRandomGenerator(NameProtection._FullId);
nameSeed = random.NextBytes(20);
hasInputMap = LoadInputSymbolMap();

Renamers = new List<IRenamer> {
new InterReferenceAnalyzer(),
Expand All @@ -89,6 +93,57 @@ public NameService(ConfuserContext context) {

public IList<IRenamer> Renamers { get; private set; }

/// <summary>
/// Loads the project's input symbol map (if any) so previously assigned obfuscated names
/// are reused, giving consistent names across re-obfuscation runs. The file uses the same
/// "{obfuscated}\t{original}" format as the exported <c>symbols.map</c>.
/// </summary>
/// <returns><c>true</c> if a non-empty map was loaded; otherwise <c>false</c>.</returns>
bool LoadInputSymbolMap() {
var mapPath = context.Project.InputSymbolMap;
if (string.IsNullOrEmpty(mapPath))
return false;

try {
if (!Path.IsPathRooted(mapPath))
mapPath = Path.Combine(context.BaseDirectory, mapPath);

if (!File.Exists(mapPath)) {
context.Logger.LogWarning("Input symbol map not found: '{0}'. Names will be generated fresh.", mapPath);
return false;
}

int count = 0;
foreach (var line in File.ReadAllLines(mapPath)) {
if (string.IsNullOrWhiteSpace(line))
continue;

int tab = line.IndexOf('\t');
if (tab <= 0)
continue;

var obfuscated = line.Substring(0, tab);
var original = line.Substring(tab + 1);

// The map is "{obfuscated}\t{original}"; reuse looks up original -> obfuscated.
if (!_obfuscatedToOriginalNameMap.ContainsKey(obfuscated))
_obfuscatedToOriginalNameMap[obfuscated] = original;
if (!_originalToObfuscatedNameMap.ContainsKey(original)) {
_originalToObfuscatedNameMap[original] = obfuscated;
count++;
}
}

context.Logger.LogInformation(
"Loaded {0} name mappings from input symbol map for consistent re-obfuscation.", count);
return count > 0;
}
catch (Exception ex) {
context.Logger.LogWarning(ex, "Failed to load input symbol map. Names will be generated fresh.");
return false;
}
}

public VTableStorage GetVTables() {
return storage;
}
Expand Down Expand Up @@ -255,7 +310,10 @@ public string ObfuscateName(string format, string name, RenameMode mode, bool pr
hash = Utils.SHA1(hash);
}

if (mode == RenameMode.Decodable || mode == RenameMode.Sequential) {
// Decodable/Sequential always record the mapping (they need it to be reversible).
// When an input symbol map is in use, record every mode so newly-generated names are
// reused on the next run and the exported map stays complete and chainable.
if (mode == RenameMode.Decodable || mode == RenameMode.Sequential || hasInputMap) {
_obfuscatedToOriginalNameMap.Add(newName, name);
_originalToObfuscatedNameMap.Add(name, newName);
}
Expand Down
15 changes: 15 additions & 0 deletions Confuser2.sln
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Confuser.Analyzers.Test", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AntiDebug.Test", "Tests\AntiDebug.Test\AntiDebug.Test.csproj", "{47197200-B8CB-400A-B1BD-84975FEC8C28}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SymbolMapReuse.Test", "Tests\SymbolMapReuse.Test\SymbolMapReuse.Test.csproj", "{591069EF-617C-4284-A968-5DB55BE1E1EF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1385,6 +1387,18 @@ Global
{47197200-B8CB-400A-B1BD-84975FEC8C28}.Release|x64.Build.0 = Release|Any CPU
{47197200-B8CB-400A-B1BD-84975FEC8C28}.Release|x86.ActiveCfg = Release|Any CPU
{47197200-B8CB-400A-B1BD-84975FEC8C28}.Release|x86.Build.0 = Release|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Debug|x64.ActiveCfg = Debug|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Debug|x64.Build.0 = Debug|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Debug|x86.ActiveCfg = Debug|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Debug|x86.Build.0 = Debug|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Release|Any CPU.Build.0 = Release|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Release|x64.ActiveCfg = Release|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Release|x64.Build.0 = Release|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Release|x86.ActiveCfg = Release|Any CPU
{591069EF-617C-4284-A968-5DB55BE1E1EF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1478,6 +1492,7 @@ Global
{4458415A-0F5E-4136-B723-7A67955D6047} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{1B22CAAE-FC4A-478D-BD68-D29A3081F938} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{47197200-B8CB-400A-B1BD-84975FEC8C28} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{591069EF-617C-4284-A968-5DB55BE1E1EF} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0D937D9E-E04B-4A68-B639-D4260473A388}
Expand Down
5 changes: 5 additions & 0 deletions ConfuserEx/ViewModel/Project/ProjectVM.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ public bool Debug {
set { SetProperty(proj.Debug != value, val => proj.Debug = val, value, "Debug"); }
}

public string InputSymbolMap {
get { return proj.InputSymbolMap; }
set { SetProperty(proj.InputSymbolMap != value, val => proj.InputSymbolMap = val, value, "InputSymbolMap"); }
}

public string BaseDirectory {
get { return proj.BaseDirectory; }
set { SetProperty(proj.BaseDirectory != value, val => proj.BaseDirectory = val, value, "BaseDirectory"); }
Expand Down
31 changes: 25 additions & 6 deletions ConfuserEx/Views/ProjectTabAdvancedView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,34 @@
<ColumnDefinition Width="36px" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="36px" />
<RowDefinition Height="36px" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<Label Grid.Row="0" Grid.Column="0" Content="Probe Paths :" Margin="5" VerticalAlignment="Center" />
<ListBox Grid.Row="1" Grid.Column="0" Margin="5" x:Name="ProbePaths" ItemsSource="{Binding ProbePaths}"
<Grid Grid.Row="0" Grid.ColumnSpan="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120px" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="36px" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="Input Symbol Map :" Margin="5" HorizontalContentAlignment="Right"
VerticalContentAlignment="Center" />
<TextBox Grid.Column="1" Margin="5" VerticalContentAlignment="Center"
Text="{Binding InputSymbolMap, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
local:Skin.EmptyPrompt="Reuse a previous symbols.map for consistent re-obfuscation"
local:FileDragDrop.Command="{x:Static local:FileDragDrop.FileCmd}" />
<Button Grid.Column="2" Margin="5" VerticalAlignment="Center" Height="26" x:Name="ChooseSymbolMap">
<TextBlock FontSize="14px" FontFamily="{DynamicResource FontAwesome}" Text="&#xf141;" Height="10px"
TextOptions.TextRenderingMode="GrayScale" />
</Button>
</Grid>

<Label Grid.Row="1" Grid.Column="0" Content="Probe Paths :" Margin="5" VerticalAlignment="Center" />
<ListBox Grid.Row="2" Grid.Column="0" Margin="5" x:Name="ProbePaths" ItemsSource="{Binding ProbePaths}"
local:FileDragDrop.Command="{x:Static local:FileDragDrop.DirectoryCmd}"
ScrollViewer.CanContentScroll="False" />
<StackPanel Grid.Row="1" Grid.Column="1">
<StackPanel Grid.Row="2" Grid.Column="1">
<Button Height="26" Margin="5" DockPanel.Dock="Top" x:Name="AddProbe">
<TextBlock FontSize="14px" FontFamily="{DynamicResource FontAwesome}" Text="&#xf067;" Height="12px"
TextOptions.TextRenderingMode="GrayScale" />
Expand All @@ -31,11 +50,11 @@
</Button>
</StackPanel>

<Label Grid.Row="0" Grid.Column="2" Content="Plugins :" Margin="5" VerticalAlignment="Center" />
<ListBox Grid.Row="1" Grid.Column="2" Margin="5" x:Name="PluginPaths" ItemsSource="{Binding Plugins}"
<Label Grid.Row="1" Grid.Column="2" Content="Plugins :" Margin="5" VerticalAlignment="Center" />
<ListBox Grid.Row="2" Grid.Column="2" Margin="5" x:Name="PluginPaths" ItemsSource="{Binding Plugins}"
local:FileDragDrop.Command="{x:Static local:FileDragDrop.FileCmd}"
ScrollViewer.CanContentScroll="False" />
<StackPanel Grid.Row="1" Grid.Column="3">
<StackPanel Grid.Row="2" Grid.Column="3">
<Button Height="26" Margin="5" DockPanel.Dock="Top" x:Name="AddPlugin">
<TextBlock FontSize="14px" FontFamily="{DynamicResource FontAwesome}" Text="&#xf067;" Height="12px"
TextOptions.TextRenderingMode="GrayScale" />
Expand Down
7 changes: 7 additions & 0 deletions ConfuserEx/Views/ProjectTabAdvancedView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ public ProjectTabAdvancedView(ProjectVM project) {
public override void OnApplyTemplate() {
base.OnApplyTemplate();

ChooseSymbolMap.Command = new RelayCommand(() => {
var ofd = new VistaOpenFileDialog();
ofd.Filter = "Symbol map (*.map)|*.map|All Files (*.*)|*.*";
if (ofd.ShowDialog() ?? false)
project.InputSymbolMap = ofd.FileName;
});

AddPlugin.Command = new RelayCommand(() => {
var ofd = new VistaOpenFileDialog();
ofd.Filter = ".NET assemblies (*.exe, *.dll)|*.exe;*.dll|All Files (*.*)|*.*";
Expand Down
13 changes: 13 additions & 0 deletions Tests/SymbolMapReuse.Test/SymbolMapReuse.Test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net462</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Confuser.UnitTest\Confuser.UnitTest.csproj" />
<ProjectReference Include="..\AntiTamper\AntiTamper.csproj" />
</ItemGroup>

</Project>
Loading