Renaming fixes and improvements (#305)
* Remove ParseGenericName, MakeGenericName methods since they don't affect renaming process * Make signatures SetOriginalName, SetOriginalNamespace, GetOriginalName, GetOriginalNamespace more concrete * Rename nameMap1 -> _originalToObfuscatedNameMap, nameMap2 -> _obfuscatedToOriginalNameMap; check if newName exists in _obfuscatedToOriginalNameMap when newName is being generated * Use full names during renaming both for type definitions and members; use original full names everywhere; fix #296, fix #293 * Fix renaming for the case when method in base type implements an interface method for a derived type, add GetSimplifiedFullName method * Add MethodOverloading.Test.csproj, MethodOverloading.csproj and MethodOverloading test * Reduce number of allocations in Utils and NameService, remove not used methods * Add MessageDeobfuscator with tests, fix StackTraceDecoder * Clean up RenamePhase, extract RenameGenericParameters * Rewrite symbols.map file instead of appending * Revert "Reduce number of allocations in Utils and NameService, remove not used methods" (except of not used methods removing) This reverts commit d045e6fa248a227297d2b2b15e837afc6b68309c. * Remove [Flags] modifier from RenameMode * Add `shortNames` parameter that disabled by default, extend MethodOverloading test * Trim namespaces if `shortNames` parameter is activated, extend MethodOverloading test (add postProcessAction action) * Misc fixes * Restore functionality related to generic parameters, add `preserveGenericParams` that is disabled by default, extend test * Fix bugs after rebasing * Try fix issues by CodeFactor * Add tests with virtual methods * Ignore method parameters during renaming if reflection or dynamic is used * Simplify GetSimplifiedFullName in NameService, move ExtractShortName from NameService to MessageDeobfuscator * Use `forceShortNames` instead of `withoutParams` during renaming if dynamic or reflection is used
This commit is contained in:
Родитель
949a998c5d
Коммит
a69820a4b9
|
@ -145,8 +145,8 @@ namespace Confuser.Core {
|
|||
for (int i = 1; i < buff.Length; i++) {
|
||||
current = (current << 8) + buff[i];
|
||||
while (current >= charset.Length) {
|
||||
ret.Append(charset[current % charset.Length]);
|
||||
current /= charset.Length;
|
||||
current = Math.DivRem(current, charset.Length, out int remainder);
|
||||
ret.Append(charset[remainder]);
|
||||
}
|
||||
}
|
||||
if (current != 0)
|
||||
|
@ -154,38 +154,6 @@ namespace Confuser.Core {
|
|||
return ret.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new string in which all occurrences of a specified string in
|
||||
/// <paramref name="str" /> are replaced with another specified string.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> equivalent to <paramref name="str" /> but with all instances of
|
||||
/// <paramref name="oldValue" />
|
||||
/// replaced with <paramref name="newValue" />.
|
||||
/// </returns>
|
||||
/// <param name="str">A string to do the replace in. </param>
|
||||
/// <param name="oldValue">A string to be replaced. </param>
|
||||
/// <param name="newValue">A string to replace all occurrences of <paramref name="oldValue" />. </param>
|
||||
/// <param name="comparison">One of the <see cref="StringComparison" /> values. </param>
|
||||
/// <remarks>Adopted from http://stackoverflow.com/a/244933 </remarks>
|
||||
public static string Replace(this string str, string oldValue, string newValue, StringComparison comparison) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int previousIndex = 0;
|
||||
int index = str.IndexOf(oldValue, comparison);
|
||||
while (index != -1) {
|
||||
sb.Append(str.Substring(previousIndex, index - previousIndex));
|
||||
sb.Append(newValue);
|
||||
index += oldValue.Length;
|
||||
previousIndex = index;
|
||||
index = str.IndexOf(oldValue, index, comparison);
|
||||
}
|
||||
sb.Append(str.Substring(previousIndex));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Encode the buffer to a hexadecimal string.
|
||||
/// </summary>
|
||||
|
@ -208,12 +176,17 @@ namespace Confuser.Core {
|
|||
/// <param name="self">The list to remove from.</param>
|
||||
/// <param name="match">The predicate that defines the conditions of the elements to remove.</param>
|
||||
/// <returns><paramref name="self" /> for method chaining.</returns>
|
||||
public static IList<T> RemoveWhere<T>(this IList<T> self, Predicate<T> match) {
|
||||
public static void RemoveWhere<T>(this IList<T> self, Predicate<T> match) {
|
||||
if (self is List<T> list) {
|
||||
list.RemoveAll(match);
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch to slow algorithm
|
||||
for (int i = self.Count - 1; i >= 0; i--) {
|
||||
if (match(self[i]))
|
||||
self.RemoveAt(i);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -121,7 +121,7 @@ namespace Confuser.Protections {
|
|||
}
|
||||
}
|
||||
if (ren) {
|
||||
member.Name = name.ObfuscateName(member.Name, RenameMode.Unicode);
|
||||
member.Name = name.ObfuscateName(member, RenameMode.Unicode);
|
||||
name.SetCanRename(member, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,17 +34,15 @@ namespace Confuser.Renamer {
|
|||
foreach (IDnlibDef def in parameters.Targets.WithProgress(context.Logger)) {
|
||||
ParseParameters(def, context, service, parameters);
|
||||
|
||||
if (def is ModuleDef) {
|
||||
var module = (ModuleDef)def;
|
||||
foreach (Resource res in module.Resources)
|
||||
service.SetOriginalName(res, res.Name);
|
||||
if (def is ModuleDef module) {
|
||||
foreach (var res in module.Resources)
|
||||
service.AddReservedIdentifier(res.Name);
|
||||
}
|
||||
else
|
||||
service.SetOriginalName(def, def.Name);
|
||||
service.SetOriginalName(def);
|
||||
|
||||
if (def is TypeDef) {
|
||||
service.GetVTables().GetVTable((TypeDef)def);
|
||||
service.SetOriginalNamespace(def, ((TypeDef)def).Namespace);
|
||||
if (def is TypeDef typeDef) {
|
||||
service.GetVTables().GetVTable(typeDef);
|
||||
}
|
||||
context.CheckCancellation();
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ namespace Confuser.Renamer.Analyzers {
|
|||
// derived type. If the base type/interface is not in our control, we should
|
||||
// not rename the methods.
|
||||
bool baseUnderCtrl = modules.Contains(slot.MethodDef.DeclaringType.Module as ModuleDefMD);
|
||||
bool ifaceUnderCtrl = modules.Contains(slot.Overrides.MethodDef.DeclaringType.Module as ModuleDefMD);
|
||||
if ((!baseUnderCtrl && ifaceUnderCtrl) || !service.CanRename(slot.MethodDef)) {
|
||||
bool interfaceUnderCtrl = modules.Contains(slot.Overrides.MethodDef.DeclaringType.Module as ModuleDefMD);
|
||||
if (!baseUnderCtrl && interfaceUnderCtrl || !service.CanRename(slot.MethodDef)) {
|
||||
service.SetCanRename(slot.Overrides.MethodDef, false);
|
||||
}
|
||||
else if (baseUnderCtrl && !ifaceUnderCtrl || !service.CanRename(slot.Overrides.MethodDef)) {
|
||||
else if ((baseUnderCtrl && !interfaceUnderCtrl) || (!service.CanRename(slot.Overrides.MethodDef))) {
|
||||
service.SetCanRename(slot.MethodDef, false);
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,17 @@ namespace Confuser.Renamer.Analyzers {
|
|||
SetupOverwriteReferences(service, modules, slot, type);
|
||||
//CreateOverrideReference(service, slot.MethodDef, slot.Overrides.MethodDef);
|
||||
}
|
||||
|
||||
// For the case when method in base type implements an interface method for a derived type
|
||||
// do not consider method parameters to make method name the same in base type, derived type and interface
|
||||
var methodDef = slot.MethodDef;
|
||||
var typeDef = type.BaseType?.ResolveTypeDef();
|
||||
var baseMethod = typeDef?.FindMethod(methodDef.Name, methodDef.Signature as MethodSig);
|
||||
if (baseMethod != null) {
|
||||
string unifiedName = service.GetOriginalFullName(slot.Overrides.MethodDef);
|
||||
service.SetOriginalName(slot.MethodDef, unifiedName);
|
||||
service.SetOriginalName(baseMethod, unifiedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +226,7 @@ namespace Confuser.Renamer.Analyzers {
|
|||
unprocessed.Enqueue(slot.Overrides.MethodDef);
|
||||
slotsExists = true;
|
||||
}
|
||||
|
||||
|
||||
if (!slotsExists && method != currentMethod)
|
||||
yield return currentMethod;
|
||||
}
|
||||
|
@ -335,7 +346,7 @@ namespace Confuser.Renamer.Analyzers {
|
|||
|
||||
var targetMethodSig = targetMethod.MethodSig;
|
||||
var overrideMethodSig = methodOverride.MethodDeclaration.MethodSig;
|
||||
|
||||
|
||||
targetMethodSig = ResolveGenericSignature(targetMethod, targetMethodSig);
|
||||
overrideMethodSig = ResolveGenericSignature(methodOverride.MethodDeclaration, overrideMethodSig);
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Confuser.Renamer {
|
||||
public class MessageDeobfuscator {
|
||||
static readonly Regex MapSymbolMatcher = new Regex("_[a-zA-Z0-9]+");
|
||||
static readonly Regex PasswordSymbolMatcher = new Regex("[a-zA-Z0-9_$]{23,}");
|
||||
|
||||
readonly Dictionary<string, string> _symbolMap;
|
||||
readonly ReversibleRenamer _renamer;
|
||||
|
||||
public static MessageDeobfuscator Load(string symbolMapFileName) {
|
||||
if (symbolMapFileName is null)
|
||||
throw new ArgumentNullException(nameof(symbolMapFileName));
|
||||
|
||||
var symbolMap = new Dictionary<string, string>();
|
||||
using (var reader = new StreamReader(File.OpenRead(symbolMapFileName))) {
|
||||
var line = reader.ReadLine();
|
||||
while (line != null) {
|
||||
int tabIndex = line.IndexOf('\t');
|
||||
if (tabIndex == -1)
|
||||
throw new FileFormatException();
|
||||
symbolMap.Add(line.Substring(0, tabIndex), line.Substring(tabIndex + 1));
|
||||
line = reader.ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
return new MessageDeobfuscator(symbolMap);
|
||||
}
|
||||
|
||||
public MessageDeobfuscator(Dictionary<string, string> map) => _symbolMap = map ?? throw new ArgumentNullException(nameof(map));
|
||||
|
||||
public MessageDeobfuscator(string password) => _renamer = new ReversibleRenamer(password);
|
||||
|
||||
public string Deobfuscate(string obfuscatedMessage) {
|
||||
if (_symbolMap != null) {
|
||||
return MapSymbolMatcher.Replace(obfuscatedMessage, DecodeSymbolMap);
|
||||
}
|
||||
|
||||
return PasswordSymbolMatcher.Replace(obfuscatedMessage, DecodeSymbolPassword);
|
||||
}
|
||||
|
||||
string DecodeSymbolMap(Match match) {
|
||||
var symbol = match.Value;
|
||||
if (_symbolMap.TryGetValue(symbol, out string result))
|
||||
return ExtractShortName(result);
|
||||
return ExtractShortName(symbol);
|
||||
}
|
||||
|
||||
string DecodeSymbolPassword(Match match) {
|
||||
var sym = match.Value;
|
||||
try {
|
||||
return ExtractShortName(_renamer.Decrypt(sym));
|
||||
}
|
||||
catch {
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
|
||||
static string ExtractShortName(string fullName) {
|
||||
const string doubleParen = "::";
|
||||
int doubleParenIndex = fullName.IndexOf(doubleParen, StringComparison.Ordinal);
|
||||
if (doubleParenIndex != -1) {
|
||||
int resultStringStartIndex = doubleParenIndex + doubleParen.Length;
|
||||
int parenIndex = fullName.IndexOf('(', doubleParenIndex);
|
||||
return fullName.Substring(resultStringStartIndex,
|
||||
(parenIndex == -1 ? fullName.Length : parenIndex) - resultStringStartIndex);
|
||||
}
|
||||
|
||||
int slashIndex = fullName.IndexOf('/');
|
||||
if (slashIndex != -1) {
|
||||
return fullName.Substring(slashIndex + 1);
|
||||
}
|
||||
|
||||
return fullName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -66,11 +66,11 @@ namespace Confuser.Renamer {
|
|||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
using (var writer = new StreamWriter(File.OpenWrite(path))) {
|
||||
using (var writer = new StreamWriter(File.Create(path))) {
|
||||
foreach (var entry in map)
|
||||
writer.WriteLine("{0}\t{1}", entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace Confuser.Renamer {
|
|||
void ReduceRenameMode(object obj, RenameMode val);
|
||||
|
||||
string ObfuscateName(string name, RenameMode mode);
|
||||
string ObfuscateName(IDnlibDef name, RenameMode mode);
|
||||
string RandomName();
|
||||
string RandomName(RenameMode mode);
|
||||
|
||||
|
@ -34,10 +35,8 @@ namespace Confuser.Renamer {
|
|||
void AddReference<T>(T obj, INameReference<T> reference);
|
||||
IList<INameReference> GetReferences(object obj);
|
||||
|
||||
void SetOriginalName(object obj, string name);
|
||||
void SetOriginalNamespace(object obj, string ns);
|
||||
string GetOriginalName(object obj);
|
||||
string GetOriginalNamespace(object obj);
|
||||
void SetOriginalName(IDnlibDef obj, string fullName = null);
|
||||
string GetOriginalFullName(IDnlibDef obj);
|
||||
|
||||
bool IsRenamed(IDnlibDef def);
|
||||
void SetIsRenamed(IDnlibDef def);
|
||||
|
@ -49,8 +48,7 @@ namespace Confuser.Renamer {
|
|||
static readonly object CanRenameKey = new object();
|
||||
static readonly object RenameModeKey = new object();
|
||||
static readonly object ReferencesKey = new object();
|
||||
static readonly object OriginalNameKey = new object();
|
||||
static readonly object OriginalNamespaceKey = new object();
|
||||
static readonly object OriginalFullNameKey = new object();
|
||||
static readonly object IsRenamedKey = new object();
|
||||
|
||||
readonly ConfuserContext context;
|
||||
|
@ -60,9 +58,10 @@ namespace Confuser.Renamer {
|
|||
AnalyzePhase analyze;
|
||||
|
||||
readonly HashSet<string> identifiers = new HashSet<string>();
|
||||
|
||||
readonly byte[] nameId = new byte[8];
|
||||
readonly Dictionary<string, string> nameMap1 = new Dictionary<string, string>();
|
||||
readonly Dictionary<string, string> nameMap2 = new Dictionary<string, string>();
|
||||
readonly Dictionary<string, string> _originalToObfuscatedNameMap = new Dictionary<string, string>();
|
||||
readonly Dictionary<string, string> _obfuscatedToOriginalNameMap = new Dictionary<string, string>();
|
||||
internal ReversibleRenamer reversibleRenamer;
|
||||
|
||||
public NameService(ConfuserContext context) {
|
||||
|
@ -121,8 +120,9 @@ namespace Confuser.Renamer {
|
|||
var param = ProtectionParameters.GetParameters(context, def);
|
||||
if (param == null)
|
||||
return null;
|
||||
Dictionary<string, string> nameParam;
|
||||
if (!param.TryGetValue(analyze.Parent, out nameParam))
|
||||
if (analyze == null)
|
||||
analyze = context.Pipeline.FindPhase<AnalyzePhase>();
|
||||
if (!param.TryGetValue(analyze.Parent, out var nameParam))
|
||||
return null;
|
||||
return nameParam.GetValueOrDefault(name);
|
||||
}
|
||||
|
@ -139,6 +139,10 @@ namespace Confuser.Renamer {
|
|||
RenameMode original = GetRenameMode(obj);
|
||||
if (original < val)
|
||||
context.Annotations.Set(obj, RenameModeKey, val);
|
||||
if (val <= RenameMode.Reflection && obj is IDnlibDef dnlibDef) {
|
||||
string nameWithoutParams = GetSimplifiedFullName(dnlibDef, true);
|
||||
SetOriginalName(dnlibDef, nameWithoutParams);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddReference<T>(T obj, INameReference<T> reference) {
|
||||
|
@ -149,21 +153,13 @@ namespace Confuser.Renamer {
|
|||
if (analyze == null)
|
||||
analyze = context.Pipeline.FindPhase<AnalyzePhase>();
|
||||
|
||||
SetOriginalName(def, def.Name);
|
||||
if (def is TypeDef) {
|
||||
GetVTables().GetVTable((TypeDef)def);
|
||||
SetOriginalNamespace(def, ((TypeDef)def).Namespace);
|
||||
SetOriginalName(def);
|
||||
if (def is TypeDef typeDef) {
|
||||
GetVTables().GetVTable(typeDef);
|
||||
}
|
||||
analyze.Analyze(this, context, ProtectionParameters.Empty, def, true);
|
||||
}
|
||||
|
||||
public void SetNameId(uint id) {
|
||||
for (int i = nameId.Length - 1; i >= 0; i--) {
|
||||
nameId[i] = (byte)(id & 0xff);
|
||||
id >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void IncrementNameId() {
|
||||
for (int i = nameId.Length - 1; i >= 0; i--) {
|
||||
nameId[i]++;
|
||||
|
@ -191,82 +187,86 @@ namespace Confuser.Renamer {
|
|||
IncrementNameId();
|
||||
return "_" + Utils.EncodeString(nameId, alphaNumCharset);
|
||||
default:
|
||||
|
||||
throw new NotSupportedException("Rename mode '" + mode + "' is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
string ParseGenericName(string name, out int? count) {
|
||||
if (name.LastIndexOf('`') != -1) {
|
||||
int index = name.LastIndexOf('`');
|
||||
int c;
|
||||
if (int.TryParse(name.Substring(index + 1), out c)) {
|
||||
string ParseGenericName(string name, out int count) {
|
||||
int graveIndex = name.LastIndexOf('`');
|
||||
if (graveIndex != -1) {
|
||||
if (int.TryParse(name.Substring(graveIndex + 1), out int c)) {
|
||||
count = c;
|
||||
return name.Substring(0, index);
|
||||
return name.Substring(0, graveIndex);
|
||||
}
|
||||
}
|
||||
count = null;
|
||||
count = 0;
|
||||
return name;
|
||||
}
|
||||
|
||||
string MakeGenericName(string name, int? count) {
|
||||
if (count == null)
|
||||
return name;
|
||||
else
|
||||
return string.Format("{0}`{1}", name, count.Value);
|
||||
string MakeGenericName(string name, int count) => count == 0 ? name : $"{name}`{count}";
|
||||
|
||||
public string ObfuscateName(string name, RenameMode mode) => ObfuscateName(null, name, mode, false);
|
||||
|
||||
public string ObfuscateName(IDnlibDef dnlibDef, RenameMode mode) {
|
||||
var originalFullName = GetOriginalFullName(dnlibDef);
|
||||
bool preserveGenericParams = GetParam(dnlibDef, "preserveGenericParams")
|
||||
?.Equals("true", StringComparison.OrdinalIgnoreCase) == true;
|
||||
return ObfuscateName(null, originalFullName, mode, preserveGenericParams);
|
||||
}
|
||||
|
||||
public string ObfuscateName(string name, RenameMode mode) => ObfuscateName(null, name, mode);
|
||||
public string ObfuscateName(string format, string name, RenameMode mode, bool preserveGenericParams = false) {
|
||||
int genericParamsCount = 0;
|
||||
if (preserveGenericParams) {
|
||||
name = ParseGenericName(name, out genericParamsCount);
|
||||
}
|
||||
|
||||
public string ObfuscateName(string format, string name, RenameMode mode) {
|
||||
string newName = null;
|
||||
name = ParseGenericName(name, out var count);
|
||||
string newName;
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
if (string.IsNullOrEmpty(name) || mode == RenameMode.Empty)
|
||||
return string.Empty;
|
||||
|
||||
if (mode == RenameMode.Empty)
|
||||
return "";
|
||||
if (mode == RenameMode.Debug || mode == RenameMode.Retain) {
|
||||
if (mode == RenameMode.Debug || mode == RenameMode.Retain)
|
||||
{
|
||||
// When flattening there are issues, in case there is a . in the name of the assembly.
|
||||
newName = MakeGenericName(name.Replace('.', '_'), count);
|
||||
return mode == RenameMode.Debug ? "_" + newName : newName;
|
||||
newName = name.Replace('.', '_');
|
||||
newName = mode == RenameMode.Debug ? "_" + newName : newName;
|
||||
}
|
||||
if (mode == RenameMode.Reversible) {
|
||||
else if (mode == RenameMode.Reversible)
|
||||
{
|
||||
if (reversibleRenamer == null)
|
||||
throw new ArgumentException("Password not provided for reversible renaming.");
|
||||
newName = reversibleRenamer.Encrypt(name);
|
||||
return MakeGenericName(newName, count);
|
||||
}
|
||||
else if (!_originalToObfuscatedNameMap.TryGetValue(name, out newName))
|
||||
{
|
||||
byte[] hash = Utils.Xor(Utils.SHA1(Encoding.UTF8.GetBytes(name)), nameSeed);
|
||||
while (true) {
|
||||
newName = ObfuscateNameInternal(hash, mode);
|
||||
|
||||
if (nameMap1.ContainsKey(name))
|
||||
return MakeGenericName(nameMap1[name], count);
|
||||
try {
|
||||
if (!(format is null))
|
||||
newName = string.Format(CultureInfo.InvariantCulture, format, newName);
|
||||
}
|
||||
catch (FormatException ex) {
|
||||
throw new ArgumentException(
|
||||
string.Format(CultureInfo.InvariantCulture,
|
||||
Resources.NameService_ObfuscateName_InvalidFormat, format),
|
||||
nameof(format), ex);
|
||||
}
|
||||
|
||||
byte[] hash = Utils.Xor(Utils.SHA1(Encoding.UTF8.GetBytes(name)), nameSeed);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
newName = ObfuscateNameInternal(hash, mode);
|
||||
|
||||
try {
|
||||
if (!(format is null))
|
||||
newName = string.Format(CultureInfo.InvariantCulture, format, newName);
|
||||
if (!identifiers.Contains(MakeGenericName(newName, genericParamsCount))
|
||||
&& !_obfuscatedToOriginalNameMap.ContainsKey(newName))
|
||||
break;
|
||||
hash = Utils.SHA1(hash);
|
||||
}
|
||||
catch (FormatException ex) {
|
||||
throw new ArgumentException(
|
||||
string.Format(CultureInfo.InvariantCulture, Resources.NameService_ObfuscateName_InvalidFormat, format),
|
||||
nameof(format), ex);
|
||||
|
||||
if (mode == RenameMode.Decodable || mode == RenameMode.Sequential) {
|
||||
_obfuscatedToOriginalNameMap.Add(newName, name);
|
||||
_originalToObfuscatedNameMap.Add(name, newName);
|
||||
}
|
||||
|
||||
if (!identifiers.Contains(MakeGenericName(newName, count)))
|
||||
break;
|
||||
hash = Utils.SHA1(hash);
|
||||
}
|
||||
|
||||
if ((mode & RenameMode.Decodable) != 0) {
|
||||
nameMap2[newName] = name;
|
||||
nameMap1[name] = newName;
|
||||
}
|
||||
|
||||
return MakeGenericName(newName, count);
|
||||
return MakeGenericName(newName, genericParamsCount);
|
||||
}
|
||||
|
||||
public string RandomName() {
|
||||
|
@ -277,15 +277,16 @@ namespace Confuser.Renamer {
|
|||
return ObfuscateName(Utils.ToHexString(random.NextBytes(16)), mode);
|
||||
}
|
||||
|
||||
public void SetOriginalName(object obj, string name) {
|
||||
identifiers.Add(name);
|
||||
context.Annotations.Set(obj, OriginalNameKey, name);
|
||||
public void SetOriginalName(IDnlibDef dnlibDef, string newFullName = null) {
|
||||
AddReservedIdentifier(dnlibDef.Name);
|
||||
if (dnlibDef is TypeDef typeDef) {
|
||||
AddReservedIdentifier(typeDef.Namespace);
|
||||
}
|
||||
string fullName = newFullName ?? GetSimplifiedFullName(dnlibDef);
|
||||
context.Annotations.Set(dnlibDef, OriginalFullNameKey, fullName);
|
||||
}
|
||||
|
||||
public void SetOriginalNamespace(object obj, string ns) {
|
||||
identifiers.Add(ns);
|
||||
context.Annotations.Set(obj, OriginalNamespaceKey, ns);
|
||||
}
|
||||
public void AddReservedIdentifier(string id) => identifiers.Add(id);
|
||||
|
||||
public void RegisterRenamer(IRenamer renamer) {
|
||||
Renamers.Add(renamer);
|
||||
|
@ -359,20 +360,51 @@ namespace Confuser.Renamer {
|
|||
return context.Annotations.GetLazy(obj, ReferencesKey, key => new List<INameReference>());
|
||||
}
|
||||
|
||||
public string GetOriginalName(object obj) {
|
||||
return context.Annotations.Get(obj, OriginalNameKey, "");
|
||||
}
|
||||
public string GetOriginalFullName(IDnlibDef obj) =>
|
||||
context.Annotations.Get(obj, OriginalFullNameKey, (string)null) ?? GetSimplifiedFullName(obj);
|
||||
|
||||
public string GetOriginalNamespace(object obj) {
|
||||
return context.Annotations.Get(obj, OriginalNamespaceKey, "");
|
||||
}
|
||||
|
||||
public ICollection<KeyValuePair<string, string>> GetNameMap() {
|
||||
return nameMap2;
|
||||
}
|
||||
public IReadOnlyDictionary<string, string> GetNameMap() => _obfuscatedToOriginalNameMap;
|
||||
|
||||
public bool IsRenamed(IDnlibDef def) => context.Annotations.Get(def, IsRenamedKey, !CanRename(def));
|
||||
|
||||
public void SetIsRenamed(IDnlibDef def) => context.Annotations.Set(def, IsRenamedKey, true);
|
||||
|
||||
string GetSimplifiedFullName(IDnlibDef dnlibDef, bool forceShortNames = false) {
|
||||
string result;
|
||||
|
||||
var shortNames = forceShortNames ||
|
||||
GetParam(dnlibDef, "shortNames")?.Equals("true", StringComparison.OrdinalIgnoreCase) ==
|
||||
true;
|
||||
if (shortNames) {
|
||||
result = dnlibDef.Name;
|
||||
}
|
||||
else {
|
||||
if (dnlibDef is MethodDef methodDef) {
|
||||
var resultBuilder = new StringBuilder();
|
||||
resultBuilder.Append(methodDef.DeclaringType2?.FullName);
|
||||
resultBuilder.Append("::");
|
||||
resultBuilder.Append(dnlibDef.Name);
|
||||
|
||||
resultBuilder.Append('(');
|
||||
if (methodDef.Signature is MethodSig methodSig) {
|
||||
var methodParams = methodSig.Params;
|
||||
for (var index = 0; index < methodParams.Count; index++) {
|
||||
resultBuilder.Append(methodParams[index]);
|
||||
if (index < methodParams.Count - 1) {
|
||||
resultBuilder.Append(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
resultBuilder.Append(')');
|
||||
|
||||
result = resultBuilder.ToString();
|
||||
}
|
||||
else {
|
||||
result = dnlibDef.FullName;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,48 +6,13 @@ namespace Confuser.Renamer {
|
|||
internal static StringBuilder AppendDescription(this StringBuilder builder, IDnlibDef def, INameService nameService) {
|
||||
if (nameService is null)
|
||||
return builder.AppendHashedIdentifier("Name", def.FullName);
|
||||
|
||||
builder.Append("Original Name").Append(": ");
|
||||
|
||||
switch (def) {
|
||||
case TypeDef typeDef:
|
||||
builder.AppendTypeName(typeDef, nameService);
|
||||
break;
|
||||
case IMemberDef memberDef:
|
||||
builder.AppendTypeName(memberDef.DeclaringType, nameService)
|
||||
.Append("::")
|
||||
.AppendOriginalName(memberDef, nameService);
|
||||
break;
|
||||
default:
|
||||
builder.AppendOriginalName(def, nameService);
|
||||
break;
|
||||
}
|
||||
builder.Append("Original Name").Append(": ");
|
||||
builder.Append(nameService.GetOriginalFullName(def));
|
||||
builder.Append("; ");
|
||||
return builder.AppendHashedIdentifier("Name", def.FullName);
|
||||
}
|
||||
|
||||
private static StringBuilder AppendTypeName(this StringBuilder builder, TypeDef typeDef, INameService nameService) {
|
||||
var originalNamespace = nameService.GetOriginalNamespace(typeDef);
|
||||
var originalName = nameService.GetOriginalName(typeDef);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(originalNamespace))
|
||||
originalNamespace = typeDef.Namespace;
|
||||
if (string.IsNullOrWhiteSpace(originalName))
|
||||
originalName = typeDef.Name;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(originalNamespace))
|
||||
builder.Append(originalNamespace).Append(".");
|
||||
|
||||
return builder.Append(originalName);
|
||||
}
|
||||
|
||||
private static StringBuilder AppendOriginalName(this StringBuilder builder, IDnlibDef def, INameService nameService) {
|
||||
var originalName = nameService.GetOriginalName(def);
|
||||
if (string.IsNullOrWhiteSpace(originalName))
|
||||
originalName = def.Name;
|
||||
return builder.Append(originalName);
|
||||
}
|
||||
|
||||
internal static StringBuilder AppendReferencedDef(this StringBuilder builder, IDnlibDef def, INameService nameService) {
|
||||
switch (def) {
|
||||
case EventDef eventDef:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Confuser.Core;
|
||||
|
@ -7,24 +6,20 @@ using dnlib.DotNet;
|
|||
using dnlib.DotNet.Pdb;
|
||||
|
||||
namespace Confuser.Renamer {
|
||||
internal class RenamePhase : ProtectionPhase {
|
||||
class RenamePhase : ProtectionPhase {
|
||||
public RenamePhase(NameProtection parent)
|
||||
: base(parent) { }
|
||||
|
||||
public override ProtectionTargets Targets {
|
||||
get { return ProtectionTargets.AllDefinitions; }
|
||||
}
|
||||
public override ProtectionTargets Targets => ProtectionTargets.AllDefinitions;
|
||||
|
||||
public override string Name {
|
||||
get { return "Renaming"; }
|
||||
}
|
||||
public override string Name => "Renaming";
|
||||
|
||||
protected override void Execute(ConfuserContext context, ProtectionParameters parameters) {
|
||||
var service = (NameService)context.Registry.GetService<INameService>();
|
||||
|
||||
context.Logger.Debug("Renaming...");
|
||||
foreach (IRenamer renamer in service.Renamers) {
|
||||
foreach (IDnlibDef def in parameters.Targets)
|
||||
foreach (var renamer in service.Renamers) {
|
||||
foreach (var def in parameters.Targets)
|
||||
renamer.PreRename(context, service, parameters, def);
|
||||
context.CheckCancellation();
|
||||
}
|
||||
|
@ -32,21 +27,20 @@ namespace Confuser.Renamer {
|
|||
var targets = parameters.Targets.ToList();
|
||||
service.GetRandom().Shuffle(targets);
|
||||
var pdbDocs = new HashSet<string>();
|
||||
foreach (IDnlibDef def in GetTargetsWithDelay(targets, context, service).WithProgress(targets.Count, context.Logger)) {
|
||||
if (def is ModuleDef && parameters.GetParameter(context, def, "rickroll", false))
|
||||
RickRoller.CommenceRickroll(context, (ModuleDef)def);
|
||||
foreach (var def in GetTargetsWithDelay(targets, context, service).WithProgress(targets.Count, context.Logger)) {
|
||||
if (def is ModuleDef moduleDef && parameters.GetParameter(context, moduleDef, "rickroll", false))
|
||||
RickRoller.CommenceRickroll(context, moduleDef);
|
||||
|
||||
bool canRename = service.CanRename(def);
|
||||
RenameMode mode = service.GetRenameMode(def);
|
||||
var mode = service.GetRenameMode(def);
|
||||
|
||||
if (def is MethodDef) {
|
||||
var method = (MethodDef)def;
|
||||
if ((canRename || method.IsConstructor) && parameters.GetParameter(context, def, "renameArgs", true)) {
|
||||
foreach (ParamDef param in ((MethodDef)def).ParamDefs)
|
||||
if (def is MethodDef method) {
|
||||
if ((canRename || method.IsConstructor) && parameters.GetParameter(context, method, "renameArgs", true)) {
|
||||
foreach (var param in method.ParamDefs)
|
||||
param.Name = null;
|
||||
}
|
||||
|
||||
if (parameters.GetParameter(context, def, "renPdb", false) && method.HasBody) {
|
||||
if (parameters.GetParameter(context, method, "renPdb", false) && method.HasBody) {
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
if (instr.SequencePoint != null && !pdbDocs.Contains(instr.SequencePoint.Document.Url)) {
|
||||
instr.SequencePoint.Document.Url = service.ObfuscateName(instr.SequencePoint.Document.Url, mode);
|
||||
|
@ -68,33 +62,28 @@ namespace Confuser.Renamer {
|
|||
|
||||
service.SetIsRenamed(def);
|
||||
|
||||
IList<INameReference> references = service.GetReferences(def);
|
||||
var references = service.GetReferences(def);
|
||||
bool cancel = references.Any(r => r.ShouldCancelRename);
|
||||
if (cancel)
|
||||
continue;
|
||||
|
||||
if (def is TypeDef) {
|
||||
var typeDef = (TypeDef)def;
|
||||
if (parameters.GetParameter(context, def, "flatten", true)) {
|
||||
typeDef.Name = service.ObfuscateName(typeDef.FullName, mode);
|
||||
if (def is TypeDef typeDef) {
|
||||
if (parameters.GetParameter(context, typeDef, "flatten", true)) {
|
||||
typeDef.Namespace = "";
|
||||
}
|
||||
else {
|
||||
var nsFormat = parameters.GetParameter(context, def, "nsFormat", "{0}");
|
||||
var nsFormat = parameters.GetParameter(context, typeDef, "nsFormat", "{0}");
|
||||
typeDef.Namespace = service.ObfuscateName(nsFormat, typeDef.Namespace, mode);
|
||||
typeDef.Name = service.ObfuscateName(typeDef.Name, mode);
|
||||
}
|
||||
foreach (var param in typeDef.GenericParameters)
|
||||
param.Name = ((char)(param.Number + 1)).ToString();
|
||||
typeDef.Name = service.ObfuscateName(typeDef, mode);
|
||||
RenameGenericParameters(typeDef.GenericParameters);
|
||||
}
|
||||
else if (def is MethodDef) {
|
||||
foreach (var param in ((MethodDef)def).GenericParameters)
|
||||
param.Name = ((char)(param.Number + 1)).ToString();
|
||||
|
||||
def.Name = service.ObfuscateName(def.Name, mode);
|
||||
else if (def is MethodDef methodDef) {
|
||||
methodDef.Name = service.ObfuscateName(methodDef, mode);
|
||||
RenameGenericParameters(methodDef.GenericParameters);
|
||||
}
|
||||
else
|
||||
def.Name = service.ObfuscateName(def.Name, mode);
|
||||
def.Name = service.ObfuscateName(def, mode);
|
||||
|
||||
int updatedReferences = -1;
|
||||
do {
|
||||
|
@ -119,7 +108,13 @@ namespace Confuser.Renamer {
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<IDnlibDef> GetTargetsWithDelay(IList<IDnlibDef> definitions, ConfuserContext context, INameService service) {
|
||||
static void RenameGenericParameters(IList<GenericParam> genericParams)
|
||||
{
|
||||
foreach (var param in genericParams)
|
||||
param.Name = ((char) (param.Number + 1)).ToString();
|
||||
}
|
||||
|
||||
static IEnumerable<IDnlibDef> GetTargetsWithDelay(IList<IDnlibDef> definitions, ConfuserContext context, INameService service) {
|
||||
var delayedItems = new List<IDnlibDef>();
|
||||
var currentList = definitions;
|
||||
var lastCount = -1;
|
||||
|
|
|
@ -125,6 +125,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "345_RenameDynamicParameter"
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "345_RenameDynamicParameter.Test", "Tests\345_RenameDynamicParameter.Test\345_RenameDynamicParameter.Test.csproj", "{0C8F49D8-BD68-420A-907D-031B83737C50}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MethodOverloading", "Tests\MethodOverloading\MethodOverloading.csproj", "{A5B912EC-D588-401C-A84F-D01F98142B9E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MethodOverloading.Test", "Tests\MethodOverloading.Test\MethodOverloading.Test.csproj", "{E17B7339-C788-4DBE-B382-3AEDB024073D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessageDeobfuscation", "Tests\MessageDeobfuscation\MessageDeobfuscation.csproj", "{F2378C48-D441-49E7-B094-1E8642A7E7C0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessageDeobfuscation.Test", "Tests\MessageDeobfuscation.Test\MessageDeobfuscation.Test.csproj", "{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -783,6 +791,54 @@ Global
|
|||
{0C8F49D8-BD68-420A-907D-031B83737C50}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0C8F49D8-BD68-420A-907D-031B83737C50}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0C8F49D8-BD68-420A-907D-031B83737C50}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -834,6 +890,10 @@ Global
|
|||
{EC62CE1D-ADD7-419A-84A9-D6A04E866197} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
|
||||
{DAE3997B-D51B-4D9F-9F11-2EBC6FDDF57C} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
|
||||
{0C8F49D8-BD68-420A-907D-031B83737C50} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
|
||||
{A5B912EC-D588-401C-A84F-D01F98142B9E} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
|
||||
{E17B7339-C788-4DBE-B382-3AEDB024073D} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
|
||||
{F2378C48-D441-49E7-B094-1E8642A7E7C0} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
|
||||
{5E9715AB-CAF7-4FFF-8E14-A8727891DA93} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0D937D9E-E04B-4A68-B639-D4260473A388}
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
TextOptions.TextRenderingMode="GrayScale" />
|
||||
</Button>
|
||||
<TextBox x:Name="PathBox" Grid.Row="1" Grid.Column="1" Margin="5" VerticalContentAlignment="Center"
|
||||
TextChanged="PathBox_TextChanged"
|
||||
local:FileDragDrop.Command="{x:Static local:FileDragDrop.FileCmd}" />
|
||||
</DockPanel>
|
||||
<DockPanel Grid.Row="0" Grid.Column="1" Visibility="{Binding IsChecked, ElementName=optPass, Converter={x:Static local:BoolToVisibilityConverter.Instance}}">
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Confuser.Core;
|
||||
using System.Windows;
|
||||
using Confuser.Renamer;
|
||||
using Ookii.Dialogs.Wpf;
|
||||
|
||||
|
@ -12,41 +6,10 @@ namespace ConfuserEx {
|
|||
/// <summary>
|
||||
/// Interaction logic for StackTraceDecoder.xaml
|
||||
/// </summary>
|
||||
public partial class StackTraceDecoder : Window {
|
||||
public StackTraceDecoder() {
|
||||
InitializeComponent();
|
||||
}
|
||||
public partial class StackTraceDecoder {
|
||||
MessageDeobfuscator _messageDeobfuscator;
|
||||
|
||||
readonly Dictionary<string, string> symMap = new Dictionary<string, string>();
|
||||
|
||||
void PathBox_TextChanged(object sender, TextChangedEventArgs e) {
|
||||
if (File.Exists(PathBox.Text))
|
||||
LoadSymMap(PathBox.Text);
|
||||
}
|
||||
|
||||
void LoadSymMap(string path) {
|
||||
string shortPath = path;
|
||||
if (path.Length > 35)
|
||||
shortPath = "..." + path.Substring(path.Length - 35, 35);
|
||||
|
||||
try {
|
||||
symMap.Clear();
|
||||
using (var reader = new StreamReader(File.OpenRead(path))) {
|
||||
var line = reader.ReadLine();
|
||||
while (line != null) {
|
||||
int tabIndex = line.IndexOf('\t');
|
||||
if (tabIndex == -1)
|
||||
throw new FileFormatException();
|
||||
symMap.Add(line.Substring(0, tabIndex), line.Substring(tabIndex + 1));
|
||||
line = reader.ReadLine();
|
||||
}
|
||||
}
|
||||
status.Content = "Loaded symbol map from '" + shortPath + "' successfully.";
|
||||
}
|
||||
catch {
|
||||
status.Content = "Failed to load symbol map from '" + shortPath + "'.";
|
||||
}
|
||||
}
|
||||
public StackTraceDecoder() => InitializeComponent();
|
||||
|
||||
void ChooseMapPath(object sender, RoutedEventArgs e) {
|
||||
var ofd = new VistaOpenFileDialog();
|
||||
|
@ -56,32 +19,29 @@ namespace ConfuserEx {
|
|||
}
|
||||
}
|
||||
|
||||
readonly Regex mapSymbolMatcher = new Regex("_[a-zA-Z0-9]+");
|
||||
readonly Regex passSymbolMatcher = new Regex("[a-zA-Z0-9_$]{23,}");
|
||||
ReversibleRenamer renamer;
|
||||
|
||||
void Decode_Click(object sender, RoutedEventArgs e) {
|
||||
var trace = stackTrace.Text;
|
||||
if (optSym.IsChecked ?? true)
|
||||
stackTrace.Text = mapSymbolMatcher.Replace(trace, DecodeSymbolMap);
|
||||
bool error = false;
|
||||
if (optSym.IsChecked ?? true) {
|
||||
var path = PathBox.Text.Trim(' ', '"');
|
||||
string shortPath = path;
|
||||
if (path.Length > 35)
|
||||
shortPath = "..." + path.Substring(path.Length - 35, 35);
|
||||
|
||||
try {
|
||||
_messageDeobfuscator = MessageDeobfuscator.Load(path);
|
||||
status.Content = "Loaded symbol map from '" + shortPath + "' successfully.";
|
||||
}
|
||||
catch {
|
||||
status.Content = "Failed to load symbol map from '" + shortPath + "'.";
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
renamer = new ReversibleRenamer(PassBox.Password);
|
||||
stackTrace.Text = passSymbolMatcher.Replace(trace, DecodeSymbolPass);
|
||||
_messageDeobfuscator = new MessageDeobfuscator(PassBox.Password);
|
||||
}
|
||||
}
|
||||
|
||||
string DecodeSymbolMap(Match match) {
|
||||
var sym = match.Value;
|
||||
return symMap.GetValueOrDefault(sym, sym);
|
||||
}
|
||||
|
||||
string DecodeSymbolPass(Match match) {
|
||||
var sym = match.Value;
|
||||
try {
|
||||
return renamer.Decrypt(sym);
|
||||
}
|
||||
catch {
|
||||
return sym;
|
||||
if (!error) {
|
||||
stackTrace.Text = _messageDeobfuscator.Deobfuscate(stackTrace.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,11 @@ namespace Confuser.UnitTest {
|
|||
|
||||
protected Task Run(string inputFileName, string[] expectedOutput, SettingItem<Protection> protection,
|
||||
string outputDirSuffix = "", Action<string> outputAction = null, SettingItem<Packer> packer = null,
|
||||
Action<ProjectModule> projectModuleAction = null, Func<string, Task> postProcessAction = null) =>
|
||||
Action<ProjectModule> projectModuleAction = null, Func<string, Task> postProcessAction = null,
|
||||
string seed = null) =>
|
||||
|
||||
Run(new[] { inputFileName }, expectedOutput, protection, outputDirSuffix, outputAction, packer,
|
||||
projectModuleAction, postProcessAction);
|
||||
projectModuleAction, postProcessAction, seed);
|
||||
|
||||
protected Task Run(string inputFileName, string[] expectedOutput, IEnumerable<SettingItem<Protection>> protections,
|
||||
string outputDirSuffix = "", Action<string> outputAction = null, SettingItem<Packer> packer = null,
|
||||
|
@ -37,14 +38,16 @@ namespace Confuser.UnitTest {
|
|||
|
||||
protected Task Run(string[] inputFileNames, string[] expectedOutput, SettingItem<Protection> protection,
|
||||
string outputDirSuffix = "", Action<string> outputAction = null, SettingItem<Packer> packer = null,
|
||||
Action<ProjectModule> projectModuleAction = null, Func<string, Task> postProcessAction = null) {
|
||||
Action<ProjectModule> projectModuleAction = null, Func<string, Task> postProcessAction = null,
|
||||
string seed = null) {
|
||||
var protections = (protection is null) ? Enumerable.Empty<SettingItem<Protection>>() : new[] { protection };
|
||||
return Run(inputFileNames, expectedOutput, protections, outputDirSuffix, outputAction, packer, projectModuleAction, postProcessAction);
|
||||
return Run(inputFileNames, expectedOutput, protections, outputDirSuffix, outputAction, packer, projectModuleAction, postProcessAction, seed);
|
||||
}
|
||||
|
||||
protected async Task Run(string[] inputFileNames, string[] expectedOutput, IEnumerable<SettingItem<Protection>> protections,
|
||||
string outputDirSuffix = "", Action<string> outputAction = null, SettingItem<Packer> packer = null,
|
||||
Action<ProjectModule> projectModuleAction = null, Func<string, Task> postProcessAction = null) {
|
||||
Action<ProjectModule> projectModuleAction = null, Func<string, Task> postProcessAction = null,
|
||||
string seed = null) {
|
||||
|
||||
var baseDir = Environment.CurrentDirectory;
|
||||
var outputDir = Path.Combine(baseDir, "obfuscated" + outputDirSuffix);
|
||||
|
@ -58,7 +61,8 @@ namespace Confuser.UnitTest {
|
|||
var proj = new ConfuserProject {
|
||||
BaseDirectory = baseDir,
|
||||
OutputDirectory = outputDir,
|
||||
Packer = packer
|
||||
Packer = packer,
|
||||
Seed = seed
|
||||
};
|
||||
|
||||
foreach (string name in inputFileNames) {
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net461</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<RootNamespace>MessageDeobfuscation.Test</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Confuser.UnitTest\Confuser.UnitTest.csproj" />
|
||||
<ProjectReference Include="..\MessageDeobfuscation\MessageDeobfuscation.csproj" />
|
||||
<ProjectReference Include="..\MethodOverloading\MethodOverloading.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Confuser.Core;
|
||||
using Confuser.Core.Project;
|
||||
using Confuser.Renamer;
|
||||
using Confuser.UnitTest;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace MessageDeobfuscation.Test {
|
||||
public class MessageDeobfuscationTest : TestBase {
|
||||
readonly string _expectedDeobfuscatedOutput = String.Join(Environment.NewLine,
|
||||
"Exception",
|
||||
" at MessageDeobfuscation.Class.NestedClass.Method(String )",
|
||||
" at MessageDeobfuscation.Program.Main()");
|
||||
|
||||
public MessageDeobfuscationTest(ITestOutputHelper outputHelper) : base(outputHelper) { }
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", "Protection")]
|
||||
[Trait("Protection", "rename")]
|
||||
public async Task MessageDeobfuscationWithSymbolsMap() {
|
||||
var expectedObfuscatedOutput = new[] {
|
||||
"Exception",
|
||||
" at _OokpKOmal5JNZMPvSAFgHLHjBke._tc5CFDIJ2J9Fx3ehd3sgjTMAxCaA._8Tq88jpv7mEXkEMavg6AaMFsXJt(String )",
|
||||
" at _ykdLsBmsKGrd6fxeEseqJs8XlpP._tfvbqapfg44suL8taZVvOKM4AoG()"
|
||||
};
|
||||
await Run(
|
||||
"MessageDeobfuscation.exe",
|
||||
expectedObfuscatedOutput,
|
||||
new SettingItem<Protection>("rename") {["mode"] = "decodable"},
|
||||
"SymbolsMap",
|
||||
seed: "1234",
|
||||
postProcessAction: outputPath => {
|
||||
var messageDeobfuscator = MessageDeobfuscator.Load(Path.Combine(outputPath, "symbols.map"));
|
||||
var deobfuscated = messageDeobfuscator.Deobfuscate(string.Join(Environment.NewLine, expectedObfuscatedOutput));
|
||||
Assert.Equal(_expectedDeobfuscatedOutput, deobfuscated);
|
||||
return Task.Delay(0);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", "Protection")]
|
||||
[Trait("Protection", "rename")]
|
||||
public async Task MessageDeobfuscationWithPassword() {
|
||||
var expectedObfuscatedOutput = new[] {
|
||||
"Exception",
|
||||
" at oQmpV$y2k2b9P3d6GP1cxGPuRtKaNIZvZcKpZXSfKFG8.V1M$X52eDxP6ElgdFrRDlF0KSZU31AmQaiXXgzyoeJJ4KV64JBpi0Bh25Xdje$vCxw.fUHV$KyBiFTUH0$GNDHVx6XvtlZWHnzVgRO9N2M$jw5ysYWJWaUSMQYtPDT$wa$6MarZQoNxnbR_9cn$A2XXvRY(String )",
|
||||
" at EbUjRcrC76NnA7RJlhQffrfp$vMGHdDfqtVFtWrAOPyD.swzvaIVl3W8yDi8Ii3P1j_V9JC8eVu2JgvNNjeVDYc4bOHH37cCBf0_3URE_8UcWPQ()"
|
||||
};
|
||||
string password = "password";
|
||||
await Run(
|
||||
"MessageDeobfuscation.exe",
|
||||
expectedObfuscatedOutput,
|
||||
new SettingItem<Protection>("rename") {["mode"] = "reversible", ["password"] = password},
|
||||
"Password",
|
||||
postProcessAction: outputPath => {
|
||||
var messageDeobfuscator = new MessageDeobfuscator(password);
|
||||
var deobfuscated = messageDeobfuscator.Deobfuscate(string.Join(Environment.NewLine, expectedObfuscatedOutput));
|
||||
Assert.Equal(_expectedDeobfuscatedOutput, deobfuscated);
|
||||
return Task.Delay(0);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net461</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<RootNamespace>MessageDeobfuscation</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
|
||||
namespace MessageDeobfuscation {
|
||||
class Class {
|
||||
public class NestedClass {
|
||||
internal string Method(string param) {
|
||||
throw new Exception($"Exception");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Program {
|
||||
public static int Main() {
|
||||
Console.WriteLine("START");
|
||||
try {
|
||||
new Class.NestedClass().Method("param");
|
||||
}
|
||||
catch (Exception e) {
|
||||
Console.WriteLine(e.Message);
|
||||
Console.WriteLine(e.StackTrace);
|
||||
}
|
||||
Console.WriteLine("END");
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net461</TargetFramework>
|
||||
<RootNamespace>MethodOverloading.Test</RootNamespace>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Confuser.UnitTest\Confuser.UnitTest.csproj" />
|
||||
<ProjectReference Include="..\MethodOverloading\MethodOverloading.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,77 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Confuser.Core;
|
||||
using Confuser.Core.Project;
|
||||
using Confuser.UnitTest;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace MethodOverloading.Test {
|
||||
public class MethodOverloadingTest : TestBase {
|
||||
public MethodOverloadingTest(ITestOutputHelper outputHelper) : base(outputHelper) { }
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(MethodOverloadingData))]
|
||||
[Trait("Category", "Protection")]
|
||||
[Trait("Protection", "rename")]
|
||||
[Trait("Issue", "https://github.com/mkaring/ConfuserEx/issues/230")]
|
||||
public async Task MethodOverloading(bool shortNames, bool preserveGenericParams) =>
|
||||
await Run(
|
||||
"MethodOverloading.exe",
|
||||
new [] {
|
||||
"1",
|
||||
"Hello world",
|
||||
"object",
|
||||
"2",
|
||||
"test",
|
||||
"5",
|
||||
"class",
|
||||
"class2",
|
||||
"class3",
|
||||
"class4",
|
||||
"class5",
|
||||
"BaseClassVirtualMethod",
|
||||
"ClassVirtualMethod",
|
||||
"ClassVirtualMethod"
|
||||
},
|
||||
new SettingItem<Protection>("rename") {
|
||||
["mode"] = "decodable",
|
||||
["shortNames"] = shortNames.ToString().ToLowerInvariant(),
|
||||
["preserveGenericParams"] = preserveGenericParams.ToString().ToLowerInvariant()
|
||||
},
|
||||
(shortNames ? "_shortnames" : "_fullnames") + (preserveGenericParams ? "_preserveGenericParams" : ""),
|
||||
seed: "seed",
|
||||
postProcessAction: outputPath => {
|
||||
var symbolsPath = Path.Combine(outputPath, "symbols.map");
|
||||
var symbols = File.ReadAllLines(symbolsPath).Select(line => {
|
||||
var parts = line.Split('\t');
|
||||
return new KeyValuePair<string, string>(parts[0], parts[1]);
|
||||
}).ToDictionary(keyValue => keyValue.Key, keyValue => keyValue.Value);
|
||||
|
||||
if (shortNames) {
|
||||
Assert.Equal("Class", symbols["_OatkF4GhWlgOakbgdlaLpqEglhm"]);
|
||||
Assert.Equal("NestedClass", symbols["_GYHfKMUMLLO9oVLM117IvfCdmUC"]);
|
||||
Assert.Equal("OverloadedMethod", symbols["_phF8iy7Y79cwt3EaAFmJzW2bGch"]);
|
||||
}
|
||||
else {
|
||||
Assert.Equal("MethodOverloading.Class", symbols["_iyWU2GdYVZxajP8BQlt8KKTy6qQ"]);
|
||||
Assert.Equal("MethodOverloading.Program/NestedClass", symbols["_CZIbNVHU7wPJyGhgOcTnIUsFtC0"]);
|
||||
Assert.Equal("MethodOverloading.Program::OverloadedMethod(System.Object[])", symbols["_LzCBuBOSn49xbtKNsjuJxQZPIEW"]);
|
||||
Assert.Equal("MethodOverloading.Program::OverloadedMethod(System.String)", symbols["_ywSbkiShk8k3qj7bBrEWEUfs9Km"]);
|
||||
}
|
||||
|
||||
return Task.Delay(0);
|
||||
}
|
||||
);
|
||||
|
||||
public static IEnumerable<object[]> MethodOverloadingData() {
|
||||
foreach (var shortNames in new[] {false, true}) {
|
||||
foreach (var preserveGenericParams in new[] {false, true}) {
|
||||
yield return new object[] {shortNames, preserveGenericParams};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net461</TargetFramework>
|
||||
<RootNamespace>MethodOverloading</RootNamespace>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
|
||||
namespace MethodOverloading {
|
||||
public interface IInterface {
|
||||
string Method(string param);
|
||||
}
|
||||
|
||||
public class BaseClass {
|
||||
public string Method(string param) => param;
|
||||
|
||||
public virtual string VirtualMethod() => "BaseClassVirtualMethod";
|
||||
}
|
||||
|
||||
public class Class : BaseClass, IInterface {
|
||||
public override string VirtualMethod() => "ClassVirtualMethod";
|
||||
}
|
||||
|
||||
public interface IInterface2<Result> {
|
||||
string Method2(Result param);
|
||||
}
|
||||
|
||||
public class BaseClass2 {
|
||||
public string Method2(string param) => param;
|
||||
}
|
||||
|
||||
public class Class2 : BaseClass2, IInterface2<string> {
|
||||
}
|
||||
|
||||
public class Class3 {
|
||||
public string Method3(string param) => "class3";
|
||||
}
|
||||
|
||||
public class Class4 {
|
||||
public string Method3(string param) => "class4";
|
||||
}
|
||||
|
||||
public interface Interface5 {
|
||||
string Method5(string param);
|
||||
}
|
||||
|
||||
public class BaseClass5<T> {
|
||||
public virtual T Method5(T param) => param;
|
||||
}
|
||||
|
||||
public class Class5 : BaseClass5<string>, Interface5 {
|
||||
}
|
||||
|
||||
public class Program {
|
||||
public class NestedClass {
|
||||
public override string ToString() => "test";
|
||||
}
|
||||
|
||||
public static int OverloadedMethod(int param) => param;
|
||||
|
||||
public static string OverloadedMethod(string param) => param;
|
||||
|
||||
public static object OverloadedMethod(object[] objects) => objects[0];
|
||||
|
||||
public static object OverloadedMethod(bool cond, float param1, double param2) => cond ? param1 : param2;
|
||||
|
||||
public static NestedClass OverloadedMethod(NestedClass nestedClass) => nestedClass;
|
||||
|
||||
public static T OverloadedMethod<T>(T param) => param;
|
||||
|
||||
static int Main(string[] args) {
|
||||
Console.WriteLine("START");
|
||||
Console.WriteLine(OverloadedMethod(1));
|
||||
Console.WriteLine(OverloadedMethod("Hello world"));
|
||||
Console.WriteLine(OverloadedMethod(new object[] { "object" }));
|
||||
Console.WriteLine(OverloadedMethod(false, 1.0f, 2.0));
|
||||
Console.WriteLine(OverloadedMethod(new NestedClass()));
|
||||
Console.WriteLine(OverloadedMethod((byte)5));
|
||||
Console.WriteLine(new Class().Method("class"));
|
||||
Console.WriteLine(new Class2().Method2("class2"));
|
||||
Console.WriteLine(new Class3().Method3("class3"));
|
||||
Console.WriteLine(new Class4().Method3("class4"));
|
||||
Console.WriteLine(new Class5().Method5("class5"));
|
||||
Console.WriteLine(new BaseClass().VirtualMethod());
|
||||
BaseClass baseClass = new Class();
|
||||
Console.WriteLine(baseClass.VirtualMethod());
|
||||
Console.WriteLine(new Class().VirtualMethod());
|
||||
Console.WriteLine("END");
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче