private XElement GetAllInfoMethod(MethodTrace methodTrace) { var result = GetInfoMethod(methodTrace); foreach (var nestedMethod in methodTrace.NestedMethods) { result.Add(GetAllInfoMethod(nestedMethod)); } return(result); }
private XElement GetInfoMethod(MethodTrace methodTrace) { var result = new XElement("method"); result.Add(new XAttribute("name", methodTrace.Metadata.Name)); result.Add(new XAttribute("time", methodTrace.GetExecutionTime())); result.Add(new XAttribute("class", methodTrace.Metadata.ClassName)); result.Add(new XAttribute("params", methodTrace.Metadata.CountParameters)); return(result); }
private void WriteMethodInfo(MethodTrace methodInfo, int nestingLevel = 0) { var nesting = new string('\t', nestingLevel); Console.WriteLine($"{nesting}Method name: {methodInfo.Metadata.Name}; time: {methodInfo.GetExecutionTime()}; " + $" class: {methodInfo.Metadata.ClassName}; params: {methodInfo.Metadata.CountParameters}"); foreach (var nestedMethod in methodInfo.NestedMethods) { WriteMethodInfo(nestedMethod, nestingLevel + 1); } }
/// <summary> /// Replaces the placeholder call in method with actual instruction sequence. /// </summary> /// <param name="method">The methodto process.</param> /// <param name="repl">The function replacing the argument of placeholder call with actual instruction sequence.</param> public static void ReplacePlaceholder(MethodDef method, Func <Instruction[], Instruction[]> repl) { MethodTrace trace = new MethodTrace(method).Trace(); for (int i = 0; i < method.Body.Instructions.Count; i++) { Instruction instr = method.Body.Instructions[i]; if (instr.OpCode == OpCodes.Call) { var operand = (IMethod)instr.Operand; if (operand.DeclaringType.FullName == mutationType && operand.Name == "Placeholder") { var initialLoadInstructions = new List <Instruction>(); var pendingInstructions = new Queue <Instruction>(); pendingInstructions.Enqueue(instr); while (pendingInstructions.Count > 0) { var currentInstr = pendingInstructions.Dequeue(); int[] argIndexes = trace.TraceArguments(currentInstr); if (argIndexes == null) { throw new ArgumentException("Failed to trace placeholder argument."); } if (argIndexes.Length == 0) { initialLoadInstructions.Add(currentInstr); } foreach (int argIndex in argIndexes) { pendingInstructions.Enqueue(method.Body.Instructions[argIndex]); } } var firstArgIndex = initialLoadInstructions.Select(method.Body.Instructions.IndexOf).Min(); Instruction[] arg = method.Body.Instructions.Skip(firstArgIndex).Take(i - firstArgIndex).ToArray(); for (int j = 0; j < arg.Length; j++) { method.Body.Instructions.RemoveAt(firstArgIndex); } method.Body.Instructions.RemoveAt(firstArgIndex); arg = repl(arg); for (int j = arg.Length - 1; j >= 0; j--) { method.Body.Instructions.Insert(firstArgIndex, arg[j]); } return; } } } }
private static XElement FormMethodData(MethodTrace methodTrace) { var result = new XElement("method"); result.Add(new XAttribute("name", methodTrace.name)); result.Add(new XAttribute("time", methodTrace.time)); result.Add(new XAttribute("class", methodTrace.classname)); foreach (MethodTrace nestedMethodTrace in methodTrace._nestedStack) { result.Add(FormMethodData(nestedMethodTrace)); } return(result); }
private string DisplayMethods(MethodTrace mth, int level = 0) { StringBuilder str = new StringBuilder(); string tab = string.Format($"{{0, {level * 4 + 1}}}", string.Empty); str.AppendLine($"{tab}method: {mth.name}"); str.AppendLine($"{tab}class: {mth.classname}"); str.AppendLine($"{tab}time: {mth.time} ms"); foreach (MethodTrace nestedmth in mth._nestedStack) { str.AppendLine(DisplayMethods(nestedmth, level + 1)); } return(str.ToString()); }
private MethodtoJson TransformMethodInfo(MethodTrace methodTrace) { MethodtoJson mth = new MethodtoJson(); mth.name = methodTrace.name; mth.classname = methodTrace.classname; mth.time = methodTrace.time; mth.methods = new List <MethodtoJson>(); foreach (MethodTrace nestedMethodTrace in methodTrace._nestedStack) { MethodtoJson nestedmth = TransformMethodInfo(nestedMethodTrace); if (nestedmth != null) { mth.methods.Add(nestedmth); } } return(mth); }
public void Analyze(ConfuserContext context, INameService service, ProtectionParameters parameters, IDnlibDef def) { if (!(def is MethodDef method) || !method.HasBody) { return; } var logger = context.Logger; var traceService = context.Registry.GetService <ITraceService>(); MethodTrace methodTrace = null; var instructions = method.Body.Instructions; foreach (var instruction in instructions) { if (!IsCreateCallSiteInstruction(instruction)) { continue; } if (methodTrace is null) { methodTrace = traceService.Trace(method); } // CallSite`1.Create(CallSiteBinder) int[] createArguments = methodTrace.TraceArguments(instruction); if (createArguments.Length != 1) { continue; } // Binder.InvokeMember(CSharpBinderFlags, string, IEnumerable<Type>, Type, IEnumerable<CSharpArgumentInfo>) var binderInstruction = instructions[createArguments[0]]; if (IsBinderInvokeMember(binderInstruction)) { HandleBinderInvokeMember(context, method, methodTrace, binderInstruction); } } }
/// <summary> /// Replaces the placeholder call in method with actual instruction sequence. /// </summary> /// <param name="method">The methodto process.</param> /// <param name="repl">The function replacing the argument of placeholder call with actual instruction sequence.</param> public static void ReplacePlaceholder(MethodDef method, Func <Instruction[], Instruction[]> repl) { var trace = new MethodTrace(method).Trace(); for (var i = 0; i < method.Body.Instructions.Count; i++) { var instr = method.Body.Instructions[i]; if (instr.OpCode == OpCodes.Call) { var operand = (IMethod)instr.Operand; if (operand.DeclaringType.FullName == mutationType && operand.Name == "Placeholder") { var argIndexes = trace.TraceArguments(instr); if (argIndexes == null) { throw new ArgumentException("Failed to trace placeholder argument."); } var argIndex = argIndexes[0]; var arg = method.Body.Instructions.Skip(argIndex).Take(i - argIndex).ToArray(); for (var j = 0; j < arg.Length; j++) { method.Body.Instructions.RemoveAt(argIndex); } method.Body.Instructions.RemoveAt(argIndex); arg = repl(arg); for (var j = arg.Length - 1; j >= 0; j--) { method.Body.Instructions.Insert(argIndex, arg[j]); } return; } } } }
public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx) { MethodTrace trace = ctx.Context.Registry.GetService <ITraceService>().Trace(ctx.Method); body.MaxStack += 2; IPredicate predicate = null; if (ctx.Predicate == PredicateType.Normal) { predicate = new NormalPredicate(ctx); } else if (ctx.Predicate == PredicateType.Expression) { predicate = new ExpressionPredicate(ctx); } else if (ctx.Predicate == PredicateType.x86) { predicate = new x86Predicate(ctx); } foreach (InstrBlock block in GetAllBlocks(root)) { LinkedList <Instruction[]> statements = SpiltStatements(block, trace, ctx); // Make sure .ctor is executed before switch if (ctx.Method.IsInstanceConstructor) { var newStatement = new List <Instruction>(); while (statements.First != null) { newStatement.AddRange(statements.First.Value); Instruction lastInstr = statements.First.Value.Last(); statements.RemoveFirst(); if (lastInstr.OpCode == OpCodes.Call && ((IMethod)lastInstr.Operand).Name == ".ctor") { break; } } statements.AddFirst(newStatement.ToArray()); } if (statements.Count < 3) { continue; } int[] key = Enumerable.Range(0, statements.Count).ToArray(); ctx.Random.Shuffle(key); var statementKeys = new Dictionary <Instruction, int>(); LinkedListNode <Instruction[]> current = statements.First; int i = 0; while (current != null) { if (i != 0) { statementKeys[current.Value[0]] = key[i]; } i++; current = current.Next; } var switchInstr = new Instruction(OpCodes.Switch); var switchHdr = new List <Instruction>(); if (predicate != null) { predicate.Init(body); switchHdr.Add(Instruction.CreateLdcI4(predicate.GetSwitchKey(key[1]))); predicate.EmitSwitchLoad(switchHdr); } else { switchHdr.Add(Instruction.CreateLdcI4(key[1])); } switchHdr.Add(switchInstr); ctx.AddJump(switchHdr, statements.Last.Value[0]); ctx.AddJunk(switchHdr); var operands = new Instruction[statements.Count]; current = statements.First; i = 0; while (current.Next != null) { var newStatement = new List <Instruction>(current.Value); if (i != 0) { // Convert to switch bool converted = false; if (newStatement.Last().IsBr()) { // Unconditional var target = (Instruction)newStatement.Last().Operand; int brKey; if (!trace.IsBranchTarget(trace.OffsetToIndexMap(newStatement.Last().Offset)) && statementKeys.TryGetValue(target, out brKey)) { newStatement.RemoveAt(newStatement.Count - 1); newStatement.Add(Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(brKey) : brKey)); ctx.AddJump(newStatement, switchHdr[1]); ctx.AddJunk(newStatement); operands[key[i]] = newStatement[0]; converted = true; } } else if (newStatement.Last().IsConditionalBranch()) { // Conditional var target = (Instruction)newStatement.Last().Operand; int brKey; if (!trace.IsBranchTarget(trace.OffsetToIndexMap(newStatement.Last().Offset)) && statementKeys.TryGetValue(target, out brKey)) { int nextKey = key[i + 1]; OpCode condBr = newStatement.Last().OpCode; newStatement.RemoveAt(newStatement.Count - 1); if (ctx.Random.NextBoolean()) { condBr = InverseBranch(condBr); int tmp = brKey; brKey = nextKey; nextKey = tmp; } Instruction brKeyInstr = Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(brKey) : brKey); Instruction nextKeyInstr = Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(nextKey) : nextKey); Instruction pop = Instruction.Create(OpCodes.Pop); newStatement.Add(Instruction.Create(condBr, brKeyInstr)); newStatement.Add(nextKeyInstr); newStatement.Add(Instruction.Create(OpCodes.Dup)); newStatement.Add(Instruction.Create(OpCodes.Br, pop)); newStatement.Add(brKeyInstr); newStatement.Add(Instruction.Create(OpCodes.Dup)); newStatement.Add(pop); ctx.AddJump(newStatement, switchHdr[1]); ctx.AddJunk(newStatement); operands[key[i]] = newStatement[0]; converted = true; } } if (!converted) { // Normal newStatement.Add(Instruction.CreateLdcI4(predicate != null ? predicate.GetSwitchKey(key[i + 1]) : key[i + 1])); ctx.AddJump(newStatement, switchHdr[1]); ctx.AddJunk(newStatement); operands[key[i]] = newStatement[0]; } } else { operands[key[i]] = switchHdr[0]; } current.Value = newStatement.ToArray(); current = current.Next; i++; } operands[key[i]] = current.Value[0]; switchInstr.Operand = operands; Instruction[] first = statements.First.Value; statements.RemoveFirst(); Instruction[] last = statements.Last.Value; statements.RemoveLast(); List <Instruction[]> newStatements = statements.ToList(); ctx.Random.Shuffle(newStatements); block.Instructions.Clear(); block.Instructions.AddRange(first); block.Instructions.AddRange(switchHdr); foreach (var statement in newStatements) { block.Instructions.AddRange(statement); } block.Instructions.AddRange(last); } }
private static void HandleBinderInvokeMember(ConfuserContext context, MethodDef method, MethodTrace methodTrace, Instruction instruction) { var instructions = method.Body.Instructions; int[] binderArguments = methodTrace.TraceArguments(instruction); if (binderArguments.Length != 5) { return; } var nameInstruction = instructions[binderArguments[1]]; var contextInstruction = instructions[binderArguments[3]]; // Name instruction is expected to contain a string constant - This is the name of the invoked member if (nameInstruction.OpCode.Code != Code.Ldstr) { return; } string boundMemberName = nameInstruction.Operand as string; var ldContextTokenInstruction = contextInstruction; if (IsGetTypeFromHandle(contextInstruction)) { int[] getTypeFromHandleArguments = methodTrace.TraceArguments(contextInstruction); if (getTypeFromHandleArguments.Length == 1) { ldContextTokenInstruction = instructions[getTypeFromHandleArguments[0]]; } } if (ldContextTokenInstruction.OpCode.Code == Code.Ldtoken && ldContextTokenInstruction.Operand is ITypeDefOrRef typeDefOrRef) { // We found the load token of the context parameter. This means we know the type the member is called for. BuildMemberReferences(context, typeDefOrRef, boundMemberName, nameInstruction); } else { context.Logger.WarnFormat( "Failed to resolve type for dynamic invoke member in {0} - blocking all members with name {1} from renaming.", method, boundMemberName); // The type referenced is unknown. To be safe, all methods matching the name need to be blocked from renaming. DisableRenamingForMethods(context, boundMemberName); } }
private void AnalyzeMethod(ConfuserContext context, INameService service, MethodDef method) { var dpRegInstrs = new List <Tuple <bool, Instruction> >(); var routedEvtRegInstrs = new List <Instruction>(); foreach (Instruction instr in method.Body.Instructions) { 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); } } } 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) { 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; } 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 AnalyzeMethod(ConfuserContext context, INameService service, MethodDef method) { var binding = new List <Tuple <bool, Instruction> >(); var dataPropertyName = new List <Instruction>(); foreach (var instr in method.Body.Instructions) { var target = instr.Operand as IMethod; switch (instr.OpCode.Code) { case Code.Call: case Code.Callvirt: Debug.Assert(target != null); if ((target.DeclaringType.FullName == "System.Windows.Forms.ControlBindingsCollection" || target.DeclaringType.FullName == "System.Windows.Forms.BindingsCollection") && target.Name == "Add" && target.MethodSig.Params.Count != 1) { binding.Add(Tuple.Create(true, instr)); } else if (target.DeclaringType.FullName == "System.Windows.Forms.DataGridViewColumn" && target.Name == "set_DataPropertyName" && target.MethodSig.Params.Count == 1) { dataPropertyName.Add(instr); } break; case Code.Newobj: Debug.Assert(target != null); if (target.DeclaringType.FullName == "System.Windows.Forms.Binding" && target.Name.String == ".ctor") { binding.Add(Tuple.Create(false, instr)); } break; } } if (binding.Count == 0 && dataPropertyName.Count == 0) { return; } var traceSrv = context.Registry.GetService <ITraceService>(); MethodTrace trace = traceSrv.Trace(method); bool erred = false; foreach (var instrInfo in binding) { int[] args = trace.TraceArguments(instrInfo.Item2); if (args == null) { if (!erred) { context.Logger.WarnFormat("Failed to extract binding property name in '{0}'.", method.FullName); } erred = true; continue; } var argumentIndex = (instrInfo.Item1 ? 1 : 0); var propertyName = ResolveNameInstruction(method, args, ref argumentIndex); if (propertyName.OpCode.Code != Code.Ldstr) { if (!erred) { context.Logger.WarnFormat("Failed to extract binding property name in '{0}'.", method.FullName); } erred = true; } else { List <PropertyDef> props; if (!properties.TryGetValue((string)propertyName.Operand, out props)) { if (!erred) { context.Logger.WarnFormat("Failed to extract target property in '{0}'.", method.FullName); } erred = true; } else { foreach (var property in props) { service.SetCanRename(property, false); } } } argumentIndex += 2; var dataMember = ResolveNameInstruction(method, args, ref argumentIndex); if (dataMember.OpCode.Code != Code.Ldstr) { if (!erred) { context.Logger.WarnFormat("Failed to extract binding property name in '{0}'.", method.FullName); } erred = true; } else { List <PropertyDef> props; if (!properties.TryGetValue((string)dataMember.Operand, out props)) { if (!erred) { context.Logger.WarnFormat("Failed to extract target property in '{0}'.", method.FullName); } erred = true; } else { foreach (var property in props) { service.SetCanRename(property, false); } } } } foreach (var instrInfo in dataPropertyName) { int[] args = trace.TraceArguments(instrInfo); if (args == null) { if (!erred) { context.Logger.WarnFormat("Failed to extract binding property name in '{0}'.", method.FullName); } erred = true; continue; } var argumentIndex = 1; var propertyName = ResolveNameInstruction(method, args, ref argumentIndex); if (propertyName.OpCode.Code != Code.Ldstr) { if (!erred) { context.Logger.WarnFormat("Failed to extract binding property name in '{0}'.", method.FullName); } erred = true; } else { if (!properties.TryGetValue((string)propertyName.Operand, out var props)) { if (!erred) { context.Logger.WarnFormat("Failed to extract target property in '{0}'.", method.FullName); } erred = true; } else { foreach (var property in props) { service.SetCanRename(property, false); } } } } }
public void Analyze(INameService nameService, ITraceService traceService, IReadOnlyList <ModuleDef> moduleDefs, ILogger logger, MethodDef method) { if (!method.HasBody) { return; } MethodTrace methodTrace = null; MethodTrace GetMethodTrace() { if (methodTrace == null) { methodTrace = traceService.Trace(method); } return(methodTrace); } foreach (var instr in method.Body.Instructions) { if (instr.OpCode.Code == Code.Call && instr.Operand is IMethodDefOrRef calledMethod) { if (calledMethod.DeclaringType.FullName == "System.Type") { Func <TypeDef, IEnumerable <IMemberDef> > getMember = null; if (calledMethod.Name == nameof(Type.GetMethod)) { getMember = t => t.Methods; } else if (calledMethod.Name == nameof(Type.GetField)) { getMember = t => t.Fields; } else if (calledMethod.Name == nameof(Type.GetProperty)) { getMember = t => t.Properties; } else if (calledMethod.Name == nameof(Type.GetEvent)) { getMember = t => t.Events; } else if (calledMethod.Name == nameof(Type.GetMember)) { getMember = t => Enumerable.Empty <IMemberDef>().Concat(t.Methods).Concat(t.Fields).Concat(t.Properties).Concat(t.Events); } if (getMember != null) { var trace = GetMethodTrace(); var arguments = trace.TraceArguments(instr); if (arguments == null) { logger.WarnFormat(Resources.ReflectionAnalyzer_Analyze_TracingArgumentsFailed, calledMethod.FullName, method.FullName); } else if (arguments.Length >= 2) { var types = GetReferencedTypes(method.Body.Instructions[arguments[0]], method, trace); var names = GetReferencedNames(method.Body.Instructions[arguments[1]]); if (!types.Any()) { types = moduleDefs.SelectMany(m => m.GetTypes()).ToArray(); } foreach (var possibleMethod in types.SelectMany(getMember).Where(m => names.Contains(m.Name))) { nameService.SetCanRename(possibleMethod, false); } } } } } } }
/// <summary> /// This method is used to determine the types that are load onto the stack at the referenced instruction. /// In case the method is unable to determine all the types reliable, it will return a empty list. /// </summary> private static IReadOnlyList <TypeDef> GetReferencedTypes(Instruction instruction, MethodDef method, MethodTrace trace) { if (instruction.OpCode.Code == Code.Call && instruction.Operand is IMethodDefOrRef calledMethod) { if (calledMethod.DeclaringType.FullName == "System.Type" && calledMethod.Name == "GetTypeFromHandle") { var arguments = trace.TraceArguments(instruction); if (arguments.Length == 1) { var ldTokenInstr = method.Body.Instructions[arguments[0]]; if (ldTokenInstr.OpCode.Code == Code.Ldtoken && ldTokenInstr.Operand is TypeDef refTypeDef) { return(new List <TypeDef>() { refTypeDef }); } } } } return(new List <TypeDef>()); }
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); if (match.Success) { operand = match.Groups[1].Value; } else if (operand.Contains("/")) { context.Logger.WarnFormat("[WPF] Fail to extract XAML name from '{0}'.", instr.Operand); } var reference = new BAMLStringReference(instr); operand = 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 AnalyzeMethod(ConfuserContext context, INameService service, MethodDef method) { var binding = new List <Tuple <bool, Instruction> >(); foreach (Instruction instr in method.Body.Instructions) { if ((instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt)) { var target = (IMethod)instr.Operand; if ((target.DeclaringType.FullName == "System.Windows.Forms.ControlBindingsCollection" || target.DeclaringType.FullName == "System.Windows.Forms.BindingsCollection") && target.Name == "Add" && target.MethodSig.Params.Count != 1) { binding.Add(Tuple.Create(true, instr)); } else if (target.DeclaringType.FullName == "System.Windows.Forms.Binding" && target.Name.String == ".ctor") { binding.Add(Tuple.Create(false, instr)); } } } if (binding.Count == 0) { return; } ITraceService traceSrv = context.Registry.GetService <ITraceService>(); MethodTrace trace = traceSrv.Trace(method); bool erred = false; foreach (Tuple <bool, Instruction> instrInfo in binding) { int[] args = trace.TraceArguments(instrInfo.Item2); if (args == null) { if (!erred) { context.Logger.LogFormat("WARN: Failed to extract binding property name in '{0}'.", method.FullName); } erred = true; continue; } Instruction propertyName = method.Body.Instructions[args[0 + (instrInfo.Item1 ? 1 : 0)]]; if (propertyName.OpCode.Code != Code.Ldstr) { if (!erred) { context.Logger.LogFormat("WARN: Failed to extract binding property name in '{0}'.", method.FullName); } erred = true; } else { if (!properties.TryGetValue((string)propertyName.Operand, out List <PropertyDef> props)) { if (!erred) { context.Logger.LogFormat("WARN: Failed to extract target property in '{0}'.", method.FullName); } erred = true; } else { foreach (PropertyDef property in props) { service.SetCanRename(property, false); } } } Instruction dataMember = method.Body.Instructions[args[2 + (instrInfo.Item1 ? 1 : 0)]]; if (dataMember.OpCode.Code != Code.Ldstr) { if (!erred) { context.Logger.LogFormat("WARN: Failed to extract binding property name in '{0}'.", method.FullName); } erred = true; } else { if (!properties.TryGetValue((string)dataMember.Operand, out List <PropertyDef> props)) { if (!erred) { context.Logger.LogFormat("WARN: Failed to extract target property in '{0}'.", method.FullName); } erred = true; } else { foreach (PropertyDef property in props) { service.SetCanRename(property, false); } } } } }
// Token: 0x06000044 RID: 68 RVA: 0x00004ED4 File Offset: 0x000030D4 private void AnalyzeMethod(ConfuserContext context, INameService service, MethodDef method) { List <Tuple <bool, Instruction> > dpRegInstrs = new List <Tuple <bool, Instruction> >(); List <Instruction> routedEvtRegInstrs = new List <Instruction>(); foreach (Instruction instr in method.Body.Instructions) { if (instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt) { IMethod regMethod = (IMethod)instr.Operand; if (regMethod.DeclaringType.FullName == "System.Windows.DependencyProperty" && regMethod.Name.String.StartsWith("Register")) { dpRegInstrs.Add(Tuple.Create <bool, Instruction>(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 == OpCodes.Ldstr) { string operand = ((string)instr.Operand).ToUpperInvariant(); if (operand.EndsWith(".BAML") || operand.EndsWith(".XAML")) { Match match = WPFAnalyzer.UriPattern.Match(operand); if (match.Success) { operand = match.Groups[1].Value; } BAMLStringReference reference = new BAMLStringReference(instr); operand = operand.TrimStart(new char[] { '/' }); string baml = operand.Substring(0, operand.Length - 5) + ".BAML"; string xaml = operand.Substring(0, operand.Length - 5) + ".XAML"; this.bamlRefs.AddListEntry(baml, reference); this.bamlRefs.AddListEntry(xaml, reference); } } } if (dpRegInstrs.Count == 0) { return; } ITraceService traceSrv = context.Registry.GetService <ITraceService>(); MethodTrace trace = traceSrv.Trace(method); bool erred = false; foreach (Tuple <bool, Instruction> 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}'.", new object[] { method.FullName }); } erred = true; } else { 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}'.", new object[] { method.FullName }); } erred = true; } else { string name = (string)ldstr.Operand; TypeDef declType = method.DeclaringType; bool found = false; if (instrInfo.Item1) { 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; } } PropertyDef property; 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 accessor2 in property.OtherMethods) { service.SetCanRename(accessor2, false); } } } if (!found) { if (instrInfo.Item1) { context.Logger.WarnFormat("Failed to find the accessors of attached dependency property '{0}' in type '{1}'.", new object[] { name, declType.FullName }); } else { context.Logger.WarnFormat("Failed to find the CLR property of normal dependency property '{0}' in type '{1}'.", new object[] { name, declType.FullName }); } } } } } erred = false; foreach (Instruction instr2 in routedEvtRegInstrs) { int[] args2 = trace.TraceArguments(instr2); if (args2 == null) { if (!erred) { context.Logger.WarnFormat("Failed to extract routed event name in '{0}'.", new object[] { method.FullName }); } erred = true; } else { Instruction ldstr2 = method.Body.Instructions[args2[0]]; if (ldstr2.OpCode.Code != Code.Ldstr) { if (!erred) { context.Logger.WarnFormat("Failed to extract routed event name in '{0}'.", new object[] { method.FullName }); } erred = true; } else { string name2 = (string)ldstr2.Operand; TypeDef declType2 = method.DeclaringType; EventDef eventDef; if ((eventDef = declType2.FindEvent(name2)) == null) { context.Logger.WarnFormat("Failed to find the CLR event of routed event '{0}' in type '{1}'.", new object[] { name2, declType2.FullName }); } else { 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 accessor3 in eventDef.OtherMethods) { service.SetCanRename(accessor3, false); } } } } } } }