public bool Matches(SearchMask mask) { if (!string.IsNullOrWhiteSpace(mask.Assembly) && !string.IsNullOrWhiteSpace(Assembly) && !Assembly.WildcardMatch(mask.Assembly, ignoreCase: true)) { return(false); } if (!string.IsNullOrWhiteSpace(mask.Namespace) && !string.IsNullOrWhiteSpace(Namespace) && !Namespace.WildcardMatch(mask.Namespace, ignoreCase: true)) { return(false); } if (!string.IsNullOrWhiteSpace(mask.Type) && !string.IsNullOrWhiteSpace(Type) && !Type.WildcardMatch(mask.Type, ignoreCase: true)) { return(false); } if (!string.IsNullOrWhiteSpace(mask.Opcode) && !string.IsNullOrWhiteSpace(Opcode) && !Opcode.WildcardMatch(mask.Opcode, ignoreCase: true)) { return(false); } if (!string.IsNullOrWhiteSpace(mask.Argument) && !string.IsNullOrWhiteSpace(Argument) && !Argument.WildcardMatch(mask.Argument, ignoreCase: true)) { return(false); } return(true); }
internal static int Replace(IsleOptions opts) { var term = new SearchMask(opts.Term); var files = GetAssemblyFiles(opts.WorkDir).ToArray(); log.Info($"Found {files.Length} files!"); var resolv = new DefaultAssemblyResolver(); resolv.AddSearchDirectory(opts.WorkDir); var rparam = new ReaderParameters { AssemblyResolver = resolv }; var wparam = new WriterParameters(); foreach (var file in files) { using (var stream = IntoMemory(file)) { var tuples = FindInstructions(stream, rparam, term).ToArray(); if (tuples.Length < 1) { continue; } bool isDirty = false; var byMethod = tuples.GroupBy(t => t.Item1.Method).ToArray(); foreach (var tuple in byMethod) { var meth = tuple.Key; var instrs = tuple.Select(t => t.Item2).ToArray(); Console.WriteLine(meth); var proc = meth.Body.GetILProcessor(); foreach (var instr in instrs) { Console.WriteLine($" {instr}"); Type type; var patch = CreateOperation(proc, opts.Patch, out type); Console.Write($" > {patch} (y/n)? "); var ask = Console.ReadLine(); if (!ask.Equals("y", StringComparison.InvariantCultureIgnoreCase)) { continue; } proc.Replace(instr, patch); log.InfoFormat(" added '{0}'!", CopyTypeRef(type.Assembly, opts.WorkDir)); isDirty = true; } } if (!isDirty) { continue; } var ass = tuples.First().Item1.Method.Module.Assembly; ass.Write(file, wparam); log.InfoFormat($"Replaced something in '{ass}'!"); } } return(0); }
internal static IEnumerable <Tuple <MethodBody, Instruction> > FindInstructions(Stream stream, ReaderParameters rparam, params SearchMask[] terms) { var ass = AssemblyDefinition.ReadAssembly(stream, rparam); var assMask = new SearchMask { Assembly = ass.Name.Name }; var assMatched = terms.Where(t => t.Matches(assMask)).ToArray(); if (assMatched.Length < 1) { yield break; } var types = ass.GetAllTypes(); foreach (var type in types) { var subMask = new SearchMask { Assembly = assMask.Assembly, Namespace = type.Namespace }; if (subMask.Namespace.Length < 1) { subMask.Namespace = "-"; } var subMatched = assMatched.Where(t => t.Matches(subMask)).ToArray(); if (subMatched.Length < 1) { continue; } subMask.Type = type.Name; subMatched = subMatched.Where(t => t.Matches(subMask)).ToArray(); if (subMatched.Length < 1) { continue; } foreach (var meth in type.Methods) { if (!meth.HasBody) { continue; } var instrs = meth.Body.Instructions; foreach (var instr in instrs) { var instrMask = new SearchMask { Assembly = assMask.Assembly, Namespace = type.Namespace, Type = type.Name, Opcode = instr.OpCode.Name, Argument = instr.Operand?.ToString() }; var opMatched = subMatched.Where(t => t.Matches(instrMask)).ToArray(); if (opMatched.Length < 1) { continue; } yield return(Tuple.Create(meth.Body, instr)); } } } }