Skip to content

Commit 12ab7b9

Browse files
authored
Merge 4aa63d0 into 988b311
2 parents 988b311 + 4aa63d0 commit 12ab7b9

File tree

7 files changed

+123
-54
lines changed

7 files changed

+123
-54
lines changed

Confuser.Core/CoreComponent.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public class CoreComponent : ConfuserComponent {
3737
/// </summary>
3838
public const string _APIStoreId = "Confuser.APIStore";
3939

40+
public const string SymbolsFileName = "symbols.map";
41+
public const string PasswordFileName = "password";
42+
4043
readonly Marker marker;
4144
readonly ConfuserContext _context;
4245

Confuser.Core/Services/RandomService.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,7 @@ internal RandomGenerator(byte[] seed) {
3636
/// <param name="seed">The seed data.</param>
3737
/// <returns>The seed buffer.</returns>
3838
internal static byte[] Seed(string seed) {
39-
byte[] ret;
40-
if (!string.IsNullOrEmpty(seed))
41-
ret = Utils.SHA256(Encoding.UTF8.GetBytes(seed));
42-
else
43-
ret = Utils.SHA256(Guid.NewGuid().ToByteArray());
39+
byte[] ret = Utils.SHA256(!string.IsNullOrEmpty(seed) ? Encoding.UTF8.GetBytes(seed) : Guid.NewGuid().ToByteArray());
4440

4541
for (int i = 0; i < 32; i++) {
4642
ret[i] *= primes[i % primes.Length];
@@ -224,12 +220,15 @@ public void Shuffle<T>(MDTable<T> table) where T : struct {
224220
internal class RandomService : IRandomService {
225221
readonly byte[] seed; //32 bytes
226222

223+
public string SeedString { get; }
224+
227225
/// <summary>
228226
/// Initializes a new instance of the <see cref="RandomService" /> class.
229227
/// </summary>
230228
/// <param name="seed">The project seed.</param>
231229
public RandomService(string seed) {
232-
this.seed = RandomGenerator.Seed(seed);
230+
SeedString = string.IsNullOrEmpty(seed) ? Guid.NewGuid().ToString() : seed;
231+
this.seed = RandomGenerator.Seed(SeedString);
233232
}
234233

235234
/// <inheritdoc />
@@ -255,5 +254,7 @@ public interface IRandomService {
255254
/// <returns>The requested RNG.</returns>
256255
/// <exception cref="System.ArgumentNullException"><paramref name="id" /> is <c>null</c>.</exception>
257256
RandomGenerator GetRandomGenerator(string id);
257+
258+
string SeedString { get; }
258259
}
259260
}

Confuser.Renamer/AnalyzePhase.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
24
using System.Linq;
35
using Confuser.Core;
6+
using Confuser.Core.Services;
47
using Confuser.Renamer.Analyzers;
58
using dnlib.DotNet;
69

@@ -30,6 +33,7 @@ void ParseParameters(IDnlibDef def, ConfuserContext context, NameService service
3033

3134
protected override void Execute(ConfuserContext context, ProtectionParameters parameters) {
3235
var service = (NameService)context.Registry.GetService<INameService>();
36+
3337
context.Logger.Debug("Building VTables & identifier list...");
3438

3539
foreach (ModuleDef moduleDef in parameters.Targets.OfType<ModuleDef>())
@@ -147,9 +151,22 @@ internal void Analyze(NameService service, ConfuserContext context, ProtectionPa
147151
else if (def is EventDef)
148152
Analyze(service, context, parameters, (EventDef)def);
149153
else if (def is ModuleDef) {
150-
var pass = parameters.GetParameter<string>(context, def, "password", null);
151-
if (pass != null)
152-
service.reversibleRenamer = new ReversibleRenamer(pass);
154+
var generatedPassword = parameters.GetParameter<bool>(context, def, "generatePassword");
155+
var password = parameters.GetParameter<string>(context, def, "password");
156+
if (generatedPassword || password != null) {
157+
var reversibleRenamer = service.reversibleRenamer;
158+
if (reversibleRenamer == null) {
159+
if (generatedPassword) {
160+
password = context.Registry.GetService<IRandomService>().SeedString;
161+
}
162+
string dir = context.OutputDirectory;
163+
string path = Path.GetFullPath(Path.Combine(dir, CoreComponent.PasswordFileName));
164+
if (!Directory.Exists(dir))
165+
Directory.CreateDirectory(dir);
166+
File.WriteAllText(path, password);
167+
service.reversibleRenamer = new ReversibleRenamer(password);
168+
}
169+
}
153170
service.SetCanRename(def, false);
154171
}
155172

Confuser.Renamer/NameProtection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ protected override void Execute(ConfuserContext context, ProtectionParameters pa
6161
if (map.Count == 0)
6262
return;
6363

64-
string path = Path.GetFullPath(Path.Combine(context.OutputDirectory, "symbols.map"));
65-
string dir = Path.GetDirectoryName(path);
64+
string dir = context.OutputDirectory;
65+
string path = Path.GetFullPath(Path.Combine(dir, CoreComponent.SymbolsFileName));
6666
if (!Directory.Exists(dir))
6767
Directory.CreateDirectory(dir);
6868

Confuser.Renamer/ReversibleRenamer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55

66
namespace Confuser.Renamer {
77
public class ReversibleRenamer {
8-
readonly RijndaelManaged cipher;
8+
readonly Aes cipher;
99
readonly byte[] key;
1010

1111
public ReversibleRenamer(string password) {
12-
cipher = new RijndaelManaged();
12+
cipher = Aes.Create();
1313
using (var sha = SHA256.Create())
1414
cipher.Key = key = sha.ComputeHash(Encoding.UTF8.GetBytes(password));
1515
}

Tests/Confuser.UnitTest/TestBase.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ protected TestBase(ITestOutputHelper outputHelper) =>
2424
protected Task Run(string inputFileName, string[] expectedOutput, SettingItem<Protection> protection,
2525
string outputDirSuffix = "", Action<string> outputAction = null, SettingItem<Packer> packer = null,
2626
Action<ProjectModule> projectModuleAction = null, Func<string, Task> postProcessAction = null,
27-
string seed = null) =>
27+
string seed = null, bool checkOutput = true) =>
2828

2929
Run(new[] { inputFileName }, expectedOutput, protection, outputDirSuffix, outputAction, packer,
30-
projectModuleAction, postProcessAction, seed);
30+
projectModuleAction, postProcessAction, seed, checkOutput);
3131

3232
protected Task Run(string inputFileName, string[] expectedOutput, IEnumerable<SettingItem<Protection>> protections,
3333
string outputDirSuffix = "", Action<string> outputAction = null, SettingItem<Packer> packer = null,
@@ -39,15 +39,15 @@ protected Task Run(string inputFileName, string[] expectedOutput, IEnumerable<Se
3939
protected Task Run(string[] inputFileNames, string[] expectedOutput, SettingItem<Protection> protection,
4040
string outputDirSuffix = "", Action<string> outputAction = null, SettingItem<Packer> packer = null,
4141
Action<ProjectModule> projectModuleAction = null, Func<string, Task> postProcessAction = null,
42-
string seed = null) {
42+
string seed = null, bool checkOutput = true) {
4343
var protections = (protection is null) ? Enumerable.Empty<SettingItem<Protection>>() : new[] { protection };
44-
return Run(inputFileNames, expectedOutput, protections, outputDirSuffix, outputAction, packer, projectModuleAction, postProcessAction, seed);
44+
return Run(inputFileNames, expectedOutput, protections, outputDirSuffix, outputAction, packer, projectModuleAction, postProcessAction, seed, checkOutput);
4545
}
4646

4747
protected async Task Run(string[] inputFileNames, string[] expectedOutput, IEnumerable<SettingItem<Protection>> protections,
4848
string outputDirSuffix = "", Action<string> outputAction = null, SettingItem<Packer> packer = null,
4949
Action<ProjectModule> projectModuleAction = null, Func<string, Task> postProcessAction = null,
50-
string seed = null) {
50+
string seed = null, bool checkOutput = true) {
5151

5252
var baseDir = Environment.CurrentDirectory;
5353
var outputDir = Path.Combine(baseDir, "obfuscated" + outputDirSuffix);
@@ -120,14 +120,16 @@ protected async Task Run(string[] inputFileNames, string[] expectedOutput, IEnum
120120
using (var process = Process.Start(info)) {
121121
using (var stdout = process.StandardOutput) {
122122
try {
123-
Assert.Equal("START", await stdout.ReadLineAsync());
123+
if (checkOutput) {
124+
Assert.Equal("START", await stdout.ReadLineAsync());
124125

125-
foreach (string line in expectedOutput) {
126-
Assert.Equal(line, await stdout.ReadLineAsync());
127-
}
126+
foreach (string line in expectedOutput) {
127+
Assert.Equal(line, await stdout.ReadLineAsync());
128+
}
128129

129-
Assert.Equal("END", await stdout.ReadLineAsync());
130-
Assert.Empty(await stdout.ReadToEndAsync());
130+
Assert.Equal("END", await stdout.ReadLineAsync());
131+
Assert.Empty(await stdout.ReadToEndAsync());
132+
}
131133
}
132134
catch (XunitException) {
133135
try {

Tests/MessageDeobfuscation.Test/MessageDeobfuscationTest.cs

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ public class MessageDeobfuscationTest : TestBase {
1616
" at MessageDeobfuscation.Class.NestedClass.Method(String )",
1717
" at MessageDeobfuscation.Program.Main()");
1818

19+
const string Password = "password";
20+
const string Seed = "seed";
21+
1922
public MessageDeobfuscationTest(ITestOutputHelper outputHelper) : base(outputHelper) { }
2023

2124
[Theory]
@@ -87,15 +90,53 @@ public static IEnumerable<object[]> RenameModeAndExpectedObfuscatedOutput() =>
8790
}
8891
},
8992
new object[] {
90-
nameof(RenameMode.Sequential),
91-
new[] {
93+
nameof(RenameMode.Sequential), new[] {
9294
"Exception",
9395
" at _g._e._c(String )",
9496
" at _B._f()"
9597
}
9698
}
9799
};
98100

101+
[Fact]
102+
[Trait("Category", "Protection")]
103+
public async Task CheckGeneratedPassword() {
104+
string actualPassword1 = null, actualPassword2 = null;
105+
await RunDeobfuscationWithPassword(true, null, "_0", Array.Empty<string>(),
106+
outputPath => {
107+
actualPassword1 = File.ReadAllText(Path.Combine(outputPath, CoreComponent.PasswordFileName));
108+
Assert.True(Guid.TryParse(actualPassword1, out _));
109+
return Task.Delay(0);
110+
});
111+
await RunDeobfuscationWithPassword(true, null, "_1", Array.Empty<string>(),
112+
outputPath => {
113+
actualPassword2 = File.ReadAllText(Path.Combine(outputPath, CoreComponent.PasswordFileName));
114+
Assert.True(Guid.TryParse(actualPassword2, out _));
115+
return Task.Delay(0);
116+
});
117+
Assert.NotEqual(actualPassword1, actualPassword2);
118+
}
119+
120+
[Fact]
121+
[Trait("Category", "Protection")]
122+
public async Task CheckPasswordDependsOnSeed() {
123+
var expectedObfuscatedOutput = new[] {
124+
"Exception",
125+
" at oZuuchQgRo99FxO43G5kj2LB6aE3b$hsLiIOVL3cn0lg.CN9UQGJKgUbt4OKGBs8_vig.FtV6w7kWA1GcUNTnc2UDptg(String )",
126+
" at EcGxTPKtKIEeZuP3ekjPVhrVKQsiovm5zMkq5xfZbt1V.xvkt0Ir5VfNl8phozRzOvg8()"
127+
};
128+
await RunDeobfuscationWithPassword(true, Seed, "_0", expectedObfuscatedOutput,
129+
outputPath => {
130+
Assert.Equal(Seed, File.ReadAllText(Path.Combine(outputPath, CoreComponent.PasswordFileName)));
131+
return Task.Delay(0);
132+
});
133+
await RunDeobfuscationWithPassword(true, Seed, "_1", expectedObfuscatedOutput,
134+
outputPath => {
135+
Assert.Equal(Seed, File.ReadAllText(Path.Combine(outputPath, CoreComponent.PasswordFileName)));
136+
return Task.Delay(0);
137+
});
138+
}
139+
99140
[Fact]
100141
[Trait("Category", "Protection")]
101142
[Trait("Protection", "rename")]
@@ -105,36 +146,41 @@ public async Task MessageDeobfuscationWithPassword() {
105146
" at oQmpV$y2k2b9P3d6GP1cxGPuRtKaNIZvZcKpZXSfKFG8.CE8t0VDPQk9$jgv1XuRwt1k.FhsPrCLqIAaPKe7abGklvY4(String )",
106147
" at EbUjRcrC76NnA7RJlhQffrfp$vMGHdDfqtVFtWrAOPyD.xgIw9voebB21PlxPFA_hs60()"
107148
};
108-
string password = "password";
109-
await Run(
110-
"MessageDeobfuscation.exe",
111-
expectedObfuscatedOutput,
112-
new SettingItem<Protection>("rename") {
113-
["mode"] = "reversible",
114-
["password"] = password,
115-
["renPdb"] = "true"
116-
},
117-
"Password",
118-
postProcessAction: outputPath => {
119-
var deobfuscator = new MessageDeobfuscator(password);
120-
var deobfuscatedMessage = deobfuscator.DeobfuscateMessage(string.Join(Environment.NewLine, expectedObfuscatedOutput));
149+
await RunDeobfuscationWithPassword(false, null, "", expectedObfuscatedOutput, outputPath => {
150+
var deobfuscator = new MessageDeobfuscator(Password);
151+
var deobfuscatedMessage =
152+
deobfuscator.DeobfuscateMessage(string.Join(Environment.NewLine, expectedObfuscatedOutput));
121153

122-
void CheckName(string expectedName, string obfuscatedName) {
123-
var name = deobfuscator.DeobfuscateSymbol(obfuscatedName, true);
124-
Assert.Equal(expectedName, name);
125-
}
154+
void CheckName(string expectedName, string obfuscatedName) {
155+
var name = deobfuscator.DeobfuscateSymbol(obfuscatedName, true);
156+
Assert.Equal(expectedName, name);
157+
}
126158

127-
CheckName("MessageDeobfuscation.Class", "oQmpV$y2k2b9P3d6GP1cxGPuRtKaNIZvZcKpZXSfKFG8");
128-
CheckName("NestedClass", "CE8t0VDPQk9$jgv1XuRwt1k");
129-
CheckName("Method", "jevJU4p4yNrAYGqN7GkRWaI");
130-
CheckName("Field", "3IS4xsnUsvDQZop6e4WmNVw");
131-
CheckName("Property", "917VMBMNYHd0kfnnNkgeJ10");
132-
CheckName("Event", "AIyINk7kgFLFc73Md8Nu8Z0");
159+
CheckName("MessageDeobfuscation.Class", "oQmpV$y2k2b9P3d6GP1cxGPuRtKaNIZvZcKpZXSfKFG8");
160+
CheckName("NestedClass", "CE8t0VDPQk9$jgv1XuRwt1k");
161+
CheckName("Method", "jevJU4p4yNrAYGqN7GkRWaI");
162+
CheckName("Field", "3IS4xsnUsvDQZop6e4WmNVw");
163+
CheckName("Property", "917VMBMNYHd0kfnnNkgeJ10");
164+
CheckName("Event", "AIyINk7kgFLFc73Md8Nu8Z0");
133165

134-
Assert.Equal(_expectedDeobfuscatedOutput, deobfuscatedMessage);
135-
return Task.Delay(0);
136-
}
137-
);
166+
Assert.Equal(_expectedDeobfuscatedOutput, deobfuscatedMessage);
167+
return Task.Delay(0);
168+
});
138169
}
170+
171+
async Task RunDeobfuscationWithPassword(bool generatePassword, string seed, string suffix,
172+
string[] expectedObfuscatedOutput, Func<string, Task> postProcessAction) => await Run(
173+
"MessageDeobfuscation.exe",
174+
expectedObfuscatedOutput,
175+
new SettingItem<Protection>("rename") {
176+
["mode"] = "reversible",
177+
["password"] = Password,
178+
["generatePassword"] = generatePassword.ToString()
179+
},
180+
$"Password_{(generatePassword ? $"Random{(seed != null ? "_Seed" : "")}{suffix}" : $"Hardcoded{suffix}")}",
181+
checkOutput: !generatePassword || seed != null,
182+
seed: seed,
183+
postProcessAction: postProcessAction
184+
);
139185
}
140186
}

0 commit comments

Comments
 (0)