Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

fix WPF relative resource renaming #551

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions Confuser.Renamer/Analyzers/WPFAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,14 @@
var decodedName = HttpUtility.UrlDecode(doc.DocumentName);
var encodedName = doc.DocumentName;
if (bamlRefs.TryGetValue(decodedName, out var references)) {
var decodedDirectory = decodedName.Substring(0, decodedName.LastIndexOf('/') + 1);
var encodedDirectory = encodedName.Substring(0, encodedName.LastIndexOf('/') + 1);
var decodedLastSlash = decodedName.LastIndexOf('/') + 1;
var encodedLastSlash = encodedName.LastIndexOf("/") + 1;

var decodedDirectory = decodedName.Substring(0, decodedLastSlash);
var encodedDirectory = encodedName.Substring(0, encodedLastSlash);

var decodedFileName = decodedName.Substring(decodedLastSlash);
var encodedFileName = encodedName.Substring(encodedLastSlash);

var fileName = service.RandomName(renameMode).ToLowerInvariant();
if (decodedName.EndsWith(".BAML", StringComparison.OrdinalIgnoreCase))
Expand All @@ -78,8 +84,8 @@

if (renameOk) {
foreach (var bamlRef in references) {
bamlRef.Rename(module, decodedName, decodedNewName);
bamlRef.Rename(module, encodedName, encodedNewName);
bamlRef.Rename(module, decodedFileName, fileName);
bamlRef.Rename(module, encodedFileName, fileName);
}
doc.DocumentName = encodedNewName;
}
Expand Down Expand Up @@ -139,180 +145,180 @@
}

void AnalyzeMethod(ConfuserContext context, INameService service, MethodDef method) {
var dpRegInstrs = new List<Tuple<bool, Instruction>>();
var routedEvtRegInstrs = new List<Instruction>();
for (int i = 0; i < method.Body.Instructions.Count; i++) {
Instruction instr = method.Body.Instructions[i];
if ((instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt)) {
var regMethod = (IMethod)instr.Operand;

if (regMethod.DeclaringType.FullName == "System.Windows.DependencyProperty" &&
regMethod.Name.String.StartsWith("Register")) {
dpRegInstrs.Add(Tuple.Create(regMethod.Name.String.StartsWith("RegisterAttached"), instr));
}
else if (regMethod.DeclaringType.FullName == "System.Windows.EventManager" &&
regMethod.Name.String == "RegisterRoutedEvent") {
routedEvtRegInstrs.Add(instr);
}
}
else if (instr.OpCode.Code == Code.Newobj) {
var methodRef = (IMethod)instr.Operand;

if (methodRef.DeclaringType.FullName == "System.Windows.Data.PropertyGroupDescription" &&
methodRef.Name == ".ctor" && i - 1 >= 0 && method.Body.Instructions[i - 1].OpCode.Code == Code.Ldstr) {
foreach (var property in analyzer.LookupProperty((string)method.Body.Instructions[i - 1].Operand))
service.SetCanRename(property, false);
}
}
else if (instr.OpCode == OpCodes.Ldstr) {
var operand = ((string)instr.Operand).ToUpperInvariant();
if (operand.EndsWith(".BAML") || operand.EndsWith(".XAML")) {
var match = UriPattern.Match(operand);
var refModule = method.Module;
if (match.Success) {
var resourceAssemblyName = match.Groups[1].Success ? match.Groups[1].Value : string.Empty;
// Check if the expression contains a resource name (group 1)
// If it does, check if it is this assembly.
if (!string.IsNullOrWhiteSpace(resourceAssemblyName) &&
!resourceAssemblyName.Equals(method.Module.Assembly.Name.String, StringComparison.OrdinalIgnoreCase)) {
// Let's see if we can find this assembly.
refModule = context.Modules.FirstOrDefault(m =>
resourceAssemblyName.Equals(m.Assembly.Name.String,
StringComparison.OrdinalIgnoreCase));

if (refModule == null) {
// This resource points to an assembly that is not part of the obfuscation.
// Leave it alone!
return;
}
}
operand = match.Groups[2].Value;
}
else if (operand.Contains("/"))
context.Logger.WarnFormat("Fail to extract XAML name from '{0}'.", instr.Operand);

var reference = new BAMLStringReference(refModule, instr);
operand = WebUtility.UrlDecode(operand.TrimStart('/'));
var baml = operand.Substring(0, operand.Length - 5) + ".BAML";
var xaml = operand.Substring(0, operand.Length - 5) + ".XAML";
bamlRefs.AddListEntry(baml, reference);
bamlRefs.AddListEntry(xaml, reference);
}
}
}

if (dpRegInstrs.Count == 0)
return;

var traceSrv = context.Registry.GetService<ITraceService>();
MethodTrace trace = traceSrv.Trace(method);

bool erred = false;
foreach (var instrInfo in dpRegInstrs) {
int[] args = trace.TraceArguments(instrInfo.Item2);
if (args == null) {
if (!erred)
context.Logger.WarnFormat("Failed to extract dependency property name in '{0}'.", method.FullName);
erred = true;
continue;
}
Instruction ldstr = method.Body.Instructions[args[0]];
if (ldstr.OpCode.Code != Code.Ldstr) {
if (!erred)
context.Logger.WarnFormat("Failed to extract dependency property name in '{0}'.", method.FullName);
erred = true;
continue;
}

var name = (string)ldstr.Operand;
TypeDef declType = method.DeclaringType;
bool found = false;
if (instrInfo.Item1) // Attached DP
{
MethodDef accessor;
if ((accessor = declType.FindMethod("Get" + name)) != null && accessor.IsStatic) {
service.SetCanRename(accessor, false);
found = true;
}
if ((accessor = declType.FindMethod("Set" + name)) != null && accessor.IsStatic) {
service.SetCanRename(accessor, false);
found = true;
}
}

// Normal DP
// Find CLR property for attached DP as well, because it seems attached DP can be use as normal DP as well.
PropertyDef property = null;
if ((property = declType.FindProperty(name)) != null) {
service.SetCanRename(property, false);

found = true;
if (property.GetMethod != null)
service.SetCanRename(property.GetMethod, false);

if (property.SetMethod != null)
service.SetCanRename(property.SetMethod, false);

if (property.HasOtherMethods) {
foreach (MethodDef accessor in property.OtherMethods)
service.SetCanRename(accessor, false);
}
}
if (!found) {
if (instrInfo.Item1)
context.Logger.WarnFormat("Failed to find the accessors of attached dependency property '{0}' in type '{1}'.",
name, declType.FullName);
else
context.Logger.WarnFormat("Failed to find the CLR property of normal dependency property '{0}' in type '{1}'.",
name, declType.FullName);
}
}

erred = false;
foreach (Instruction instr in routedEvtRegInstrs) {
int[] args = trace.TraceArguments(instr);
if (args == null) {
if (!erred)
context.Logger.WarnFormat("Failed to extract routed event name in '{0}'.", method.FullName);
erred = true;
continue;
}
Instruction ldstr = method.Body.Instructions[args[0]];
if (ldstr.OpCode.Code != Code.Ldstr) {
if (!erred)
context.Logger.WarnFormat("Failed to extract routed event name in '{0}'.", method.FullName);
erred = true;
continue;
}

var name = (string)ldstr.Operand;
TypeDef declType = method.DeclaringType;

EventDef eventDef = null;
if ((eventDef = declType.FindEvent(name)) == null) {
context.Logger.WarnFormat("Failed to find the CLR event of routed event '{0}' in type '{1}'.",
name, declType.FullName);
continue;
}
service.SetCanRename(eventDef, false);

if (eventDef.AddMethod != null)
service.SetCanRename(eventDef.AddMethod, false);

if (eventDef.RemoveMethod != null)
service.SetCanRename(eventDef.RemoveMethod, false);

if (eventDef.InvokeMethod != null)
service.SetCanRename(eventDef.InvokeMethod, false);

if (eventDef.HasOtherMethods) {
foreach (MethodDef accessor in eventDef.OtherMethods)
service.SetCanRename(accessor, false);
}
}
}

void AnalyzeResources(ConfuserContext context, INameService service, ModuleDefMD module) {

Check notice on line 321 in Confuser.Renamer/Analyzers/WPFAnalyzer.cs

View check run for this annotation

codefactor.io / CodeFactor

Confuser.Renamer/Analyzers/WPFAnalyzer.cs#L148-L321

Complex Method
if (analyzer == null) {
analyzer = new BAMLAnalyzer(context, service);
analyzer.AnalyzeElement += AnalyzeBAMLElement;
Expand Down