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:
Ivan Kochurkin 2021-07-02 12:33:05 +03:00 коммит произвёл GitHub
Родитель 949a998c5d
Коммит a69820a4b9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
21 изменённых файлов: 664 добавлений и 281 удалений

Просмотреть файл

@ -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;
}
}
}