Skip to content

Commit b567f03

Browse files
authored
Merge 3974595 into c5b450f
2 parents c5b450f + 3974595 commit b567f03

File tree

8 files changed

+216
-81
lines changed

8 files changed

+216
-81
lines changed

Confuser.Renamer/MessageDeobfuscator.cs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
namespace Confuser.Renamer {
77
public class MessageDeobfuscator {
8-
static readonly Regex MapSymbolMatcher = new Regex("_[a-zA-Z0-9]+");
9-
static readonly Regex PasswordSymbolMatcher = new Regex("[a-zA-Z0-9_$]{23,}");
8+
static readonly Regex MapSymbolRegex = new Regex("_[a-zA-Z0-9]+");
9+
static readonly Regex PasswordSymbolRegex = new Regex("[a-zA-Z0-9_$]{23,}");
1010

1111
readonly Dictionary<string, string> _symbolMap;
1212
readonly ReversibleRenamer _renamer;
@@ -34,32 +34,34 @@ public static MessageDeobfuscator Load(string symbolMapFileName) {
3434

3535
public MessageDeobfuscator(string password) => _renamer = new ReversibleRenamer(password);
3636

37-
public string Deobfuscate(string obfuscatedMessage) {
37+
public string DeobfuscateMessage(string message) {
3838
if (_symbolMap != null) {
39-
return MapSymbolMatcher.Replace(obfuscatedMessage, DecodeSymbolMap);
39+
return MapSymbolRegex.Replace(message, m => DeobfuscateSymbol(m.Value, true));
4040
}
4141

42-
return PasswordSymbolMatcher.Replace(obfuscatedMessage, DecodeSymbolPassword);
42+
return PasswordSymbolRegex.Replace(message, m => DeobfuscateSymbol(m.Value, true));
4343
}
4444

45-
string DecodeSymbolMap(Match match) {
46-
var symbol = match.Value;
47-
if (_symbolMap.TryGetValue(symbol, out string result))
48-
return ExtractShortName(result);
49-
return ExtractShortName(symbol);
50-
}
45+
public string DeobfuscateSymbol(string obfuscatedIdentifier, bool shortName) {
46+
string fullName;
5147

52-
string DecodeSymbolPassword(Match match) {
53-
var sym = match.Value;
54-
try {
55-
return ExtractShortName(_renamer.Decrypt(sym));
48+
if (_symbolMap != null) {
49+
if (!_symbolMap.TryGetValue(obfuscatedIdentifier, out fullName))
50+
fullName = obfuscatedIdentifier;
5651
}
57-
catch {
58-
return sym;
52+
else {
53+
try {
54+
fullName = _renamer.Decrypt(obfuscatedIdentifier);
55+
}
56+
catch {
57+
fullName = obfuscatedIdentifier;
58+
}
5959
}
60+
61+
return shortName ? ExtractShortName(fullName) : fullName;
6062
}
6163

62-
static string ExtractShortName(string fullName) {
64+
public static string ExtractShortName(string fullName) {
6365
const string doubleParen = "::";
6466
int doubleParenIndex = fullName.IndexOf(doubleParen, StringComparison.Ordinal);
6567
if (doubleParenIndex != -1) {

Confuser.Renamer/NameService.cs

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ internal class NameService : INameService {
6262
readonly byte[] nameId = new byte[8];
6363
readonly Dictionary<string, string> _originalToObfuscatedNameMap = new Dictionary<string, string>();
6464
readonly Dictionary<string, string> _obfuscatedToOriginalNameMap = new Dictionary<string, string>();
65+
readonly Dictionary<string, string> _prefixesMap = new Dictionary<string, string>();
6566
internal ReversibleRenamer reversibleRenamer;
6667

6768
public NameService(ConfuserContext context) {
@@ -140,7 +141,7 @@ public void ReduceRenameMode(object obj, RenameMode val) {
140141
if (original < val)
141142
context.Annotations.Set(obj, RenameModeKey, val);
142143
if (val <= RenameMode.Reflection && obj is IDnlibDef dnlibDef) {
143-
string nameWithoutParams = GetSimplifiedFullName(dnlibDef, true);
144+
string nameWithoutParams = ExtractActualName(dnlibDef, true);
144145
SetOriginalName(dnlibDef, nameWithoutParams);
145146
}
146147
}
@@ -282,7 +283,7 @@ public void SetOriginalName(IDnlibDef dnlibDef, string newFullName = null) {
282283
if (dnlibDef is TypeDef typeDef) {
283284
AddReservedIdentifier(typeDef.Namespace);
284285
}
285-
string fullName = newFullName ?? GetSimplifiedFullName(dnlibDef);
286+
string fullName = newFullName ?? ExtractActualName(dnlibDef);
286287
context.Annotations.Set(dnlibDef, OriginalFullNameKey, fullName);
287288
}
288289

@@ -361,50 +362,71 @@ public IList<INameReference> GetReferences(object obj) {
361362
}
362363

363364
public string GetOriginalFullName(IDnlibDef obj) =>
364-
context.Annotations.Get(obj, OriginalFullNameKey, (string)null) ?? GetSimplifiedFullName(obj);
365+
context.Annotations.Get(obj, OriginalFullNameKey, (string)null) ?? ExtractActualName(obj);
365366

366367
public IReadOnlyDictionary<string, string> GetNameMap() => _obfuscatedToOriginalNameMap;
367368

368369
public bool IsRenamed(IDnlibDef def) => context.Annotations.Get(def, IsRenamedKey, !CanRename(def));
369370

370371
public void SetIsRenamed(IDnlibDef def) => context.Annotations.Set(def, IsRenamedKey, true);
371372

372-
string GetSimplifiedFullName(IDnlibDef dnlibDef, bool forceShortNames = false) {
373-
string result;
374-
373+
string ExtractActualName(IDnlibDef dnlibDef, bool forceShortNames = false) {
375374
var shortNames = forceShortNames ||
376375
GetParam(dnlibDef, "shortNames")?.Equals("true", StringComparison.OrdinalIgnoreCase) ==
377376
true;
377+
var renameMode = GetRenameMode(dnlibDef);
378+
379+
if (dnlibDef is TypeDef typeDef) {
380+
return typeDef.DeclaringType != null
381+
? $"{CompressTypeName(typeDef.DeclaringType.FullName, renameMode)}/{dnlibDef.Name}"
382+
: dnlibDef.FullName;
383+
}
384+
378385
if (shortNames) {
379-
result = dnlibDef is MethodDef ? (string)dnlibDef.Name : dnlibDef.FullName;
386+
return dnlibDef.Name;
380387
}
381-
else {
382-
if (dnlibDef is MethodDef methodDef) {
383-
var resultBuilder = new StringBuilder();
384-
resultBuilder.Append(methodDef.DeclaringType2?.FullName);
385-
resultBuilder.Append("::");
386-
resultBuilder.Append(dnlibDef.Name);
387388

389+
var resultBuilder = new StringBuilder();
390+
if (dnlibDef is IMemberDef memberDef) {
391+
var declaringTypeName = CompressTypeName(memberDef.DeclaringType?.FullName ?? "", renameMode);
392+
resultBuilder.Append(declaringTypeName);
393+
resultBuilder.Append("::");
394+
resultBuilder.Append(dnlibDef.Name);
395+
396+
if (memberDef is MethodDef methodDef) {
388397
resultBuilder.Append('(');
389398
if (methodDef.Signature is MethodSig methodSig) {
390399
var methodParams = methodSig.Params;
391400
for (var index = 0; index < methodParams.Count; index++) {
392-
resultBuilder.Append(methodParams[index]);
401+
resultBuilder.Append(CompressTypeName(methodParams[index].ToString(), renameMode));
393402
if (index < methodParams.Count - 1) {
394403
resultBuilder.Append(',');
395404
}
396405
}
397406
}
398-
resultBuilder.Append(')');
399407

400-
result = resultBuilder.ToString();
408+
resultBuilder.Append(')');
401409
}
402-
else {
403-
result = dnlibDef.FullName;
410+
}
411+
412+
return resultBuilder.ToString();
413+
}
414+
415+
string CompressTypeName(string typeName, RenameMode renameMode)
416+
{
417+
if (renameMode == RenameMode.Reversible)
418+
{
419+
if (!_prefixesMap.TryGetValue(typeName, out string prefix))
420+
{
421+
IncrementNameId();
422+
prefix = Utils.EncodeString(nameId, alphaNumCharset);
423+
_prefixesMap.Add(typeName, prefix);
404424
}
425+
426+
return prefix;
405427
}
406428

407-
return result;
429+
return typeName;
408430
}
409431
}
410432
}

Confuser.Renamer/ReversibleRenamer.cs

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,41 @@
55

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

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

17-
static string Base64Encode(byte[] buf) {
18-
return Convert.ToBase64String(buf).Trim('=').Replace('+', '$').Replace('/', '_');
17+
public string Encrypt(string name) {
18+
byte ivId = GetIVId(name);
19+
cipher.IV = GetIV(ivId);
20+
var buf = Encoding.UTF8.GetBytes(name);
21+
22+
using (var ms = new MemoryStream()) {
23+
ms.WriteByte(ivId);
24+
using (var stream = new CryptoStream(ms, cipher.CreateEncryptor(), CryptoStreamMode.Write)) {
25+
stream.Write(buf, 0, buf.Length);
26+
stream.FlushFinalBlock();
27+
return Base64Encode(ms.GetBuffer(), (int)ms.Length);
28+
}
29+
}
1930
}
2031

21-
static byte[] Base64Decode(string str) {
22-
str = str.Replace('$', '+').Replace('_', '/').PadRight((str.Length + 3) & ~3, '=');
23-
return Convert.FromBase64String(str);
32+
public string Decrypt(string name) {
33+
using (var ms = new MemoryStream(Base64Decode(name))) {
34+
byte ivId = (byte)ms.ReadByte();
35+
cipher.IV = GetIV(ivId);
36+
37+
using (var result = new MemoryStream()) {
38+
using (var stream = new CryptoStream(ms, cipher.CreateDecryptor(), CryptoStreamMode.Read))
39+
stream.CopyTo(result);
40+
return Encoding.UTF8.GetString(result.GetBuffer(), 0, (int)result.Length);
41+
}
42+
}
2443
}
2544

2645
byte[] GetIV(byte ivId) {
@@ -37,32 +56,48 @@ byte GetIVId(string str) {
3756
return x;
3857
}
3958

40-
public string Encrypt(string name) {
41-
byte ivId = GetIVId(name);
42-
cipher.IV = GetIV(ivId);
43-
var buf = Encoding.UTF8.GetBytes(name);
59+
static string Base64Encode(byte[] buffer, int length) {
60+
int inputUnpaddedLength = 4 * length / 3;
61+
var outArray = new char[(inputUnpaddedLength + 3) & ~3];
62+
Convert.ToBase64CharArray(buffer, 0, length, outArray, 0);
4463

45-
using (var ms = new MemoryStream()) {
46-
ms.WriteByte(ivId);
47-
using (var stream = new CryptoStream(ms, cipher.CreateEncryptor(), CryptoStreamMode.Write))
48-
stream.Write(buf, 0, buf.Length);
64+
var result = new StringBuilder(inputUnpaddedLength);
65+
foreach (var oldChar in outArray) {
66+
if (oldChar == '=') {
67+
break;
68+
}
4969

50-
buf = ms.ToArray();
51-
return Base64Encode(buf);
70+
result.Append(oldChar == '+'
71+
? '$'
72+
: oldChar == '/'
73+
? '_'
74+
: oldChar);
5275
}
53-
}
5476

55-
public string Decrypt(string name) {
56-
using (var ms = new MemoryStream(Base64Decode(name))) {
57-
byte ivId = (byte)ms.ReadByte();
58-
cipher.IV = GetIV(ivId);
77+
return result.ToString();
78+
}
5979

60-
var result = new MemoryStream();
61-
using (var stream = new CryptoStream(ms, cipher.CreateDecryptor(), CryptoStreamMode.Read))
62-
stream.CopyTo(result);
80+
static byte[] Base64Decode(string str) {
81+
var newLength = (str.Length + 3) & ~3;
82+
var inArray = new char[newLength];
83+
for (int index = 0; index < newLength; index++) {
84+
char newChar;
85+
if (index < str.Length) {
86+
char oldChar = str[index];
87+
newChar = oldChar == '$'
88+
? '+'
89+
: oldChar == '_'
90+
? '/'
91+
: oldChar;
92+
}
93+
else {
94+
newChar = '=';
95+
}
6396

64-
return Encoding.UTF8.GetString(result.ToArray());
97+
inArray[index] = newChar;
6598
}
99+
100+
return Convert.FromBase64CharArray(inArray, 0, inArray.Length);
66101
}
67102
}
68-
}
103+
}

ConfuserEx/StackTraceDecoder.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void Decode_Click(object sender, RoutedEventArgs e) {
4141
}
4242

4343
if (!error) {
44-
stackTrace.Text = _messageDeobfuscator.Deobfuscate(stackTrace.Text);
44+
stackTrace.Text = _messageDeobfuscator.DeobfuscateMessage(stackTrace.Text);
4545
}
4646
}
4747
}

0 commit comments

Comments
 (0)