static void mergeClassWithAllAncestors(NamespaceTypeDefinition mergeTargetClass, PeReader.DefaultHost host) { List <NamespaceTypeDefinition> ancestorClasses = new List <NamespaceTypeDefinition>(); ancestorClasses.Add(mergeTargetClass); NamespaceTypeDefinition currentClass = mergeTargetClass; NamespaceTypeDefinition ancestorClass = null; while (true) { // get class from which was inherited if (currentClass.BaseClasses.Count() == 1) { // only add base classes of type NamespaceTypeDefinition if (currentClass.BaseClasses.ElementAt(0) as NamespaceTypeDefinition != null) { ancestorClass = (currentClass.BaseClasses.ElementAt(0) as NamespaceTypeDefinition); } // ignore ancestor that are not of type NamespaceTypeDefinition else { break; } } else { throw new ArgumentException("Do not know how to handle multiple inheritance."); } // add ancestor class to list of ancestor classes globalLog.writeLine("Found ancestor: " + ancestorClass.ToString()); ancestorClasses.Add(ancestorClass); currentClass = ancestorClass; } // mrge class with ancenstor (start with the "highest" ancestor) for (int i = (ancestorClasses.Count - 1); i >= 0; i--) { globalLog.writeLine("Merge class \"" + ancestorClasses[i].ToString() + "\" with ancestor"); mergeClassWithAncestor(ancestorClasses[i], host); globalLog.writeLine(""); } }
// adds the given interface to the given class public void addInterface(NamespaceTypeDefinition addTargetClass, ITypeDefinition interfaceToAdd) { // add interface to target class if (addTargetClass.Interfaces != null) { // check if interface is already implemented by class if (addTargetClass.Interfaces.Contains(interfaceToAdd)) { this.logger.writeLine("Class \"" + addTargetClass.ToString() + "\" already implements interface \"" + interfaceToAdd.ToString() + "\""); return; } else { this.logger.writeLine("Add interface \"" + interfaceToAdd.ToString() + "\" to class \"" + addTargetClass.ToString() + "\""); addTargetClass.Interfaces.Add(interfaceToAdd); } } else { List <ITypeReference> interfaceList = new List <ITypeReference>(); interfaceList.Add(interfaceToAdd); addTargetClass.Interfaces = interfaceList; } // copy all attributes from the interface to the target class if (interfaceToAdd.Fields != null) { foreach (FieldDefinition field in interfaceToAdd.Fields) { FieldDefinition copy = new FieldDefinition(); this.helperClass.copyField(copy, field); copy.ContainingTypeDefinition = addTargetClass; // set intern factory of the copied field to the one of the class // (without it, the generated binary file will have strange results like use only the same field) copy.InternFactory = addTargetClass.InternFactory; addTargetClass.Fields.Add(copy); } } // copy all methods from the interface to the target class if (interfaceToAdd.Methods != null) { foreach (IMethodDefinition method in interfaceToAdd.Methods) { // search through all methods in the target class // to see if this method was already added bool foundMethod = false; foreach (IMethodDefinition tempMethod in addTargetClass.Methods) { // skip constructors if (tempMethod.IsConstructor) { continue; } // check if the number of parameters are the same if (tempMethod.ParameterCount == method.ParameterCount) { // check if the parameters have the same type in the same order bool parameterCorrect = true; for (int i = 0; i < method.ParameterCount; i++) { if (method.Parameters.ElementAt(i).Type != tempMethod.Parameters.ElementAt(i).Type) { parameterCorrect = false; break; } } // check if the return type is the same bool returnTypeCorrect = false; if (method.Type.Equals(tempMethod.Type)) { returnTypeCorrect = true; } // check if both methods are static // (c# compiler does not allow static + non-static function with // same signature in same class, but CIL does) bool bothStatic = false; if (method.IsStatic == tempMethod.IsStatic) { bothStatic = true; } // if the parameters and return type are correct => check the name if (parameterCorrect && returnTypeCorrect && bothStatic) { if (method.Name.Equals(tempMethod.Name)) { // if name is the same => method already added foundMethod = true; break; } } } } // skip if method was already added if (foundMethod) { this.logger.writeLine("Method \"" + method.Name.ToString() + "\" already exists"); continue; } this.logger.writeLine("Add method: " + method.Name.ToString()); // copy method MethodDefinition copy = new MethodDefinition(); this.helperClass.copyMethod(copy, method); copy.ContainingTypeDefinition = addTargetClass; // generate random dead code for newly created method ILGenerator ilGenerator = new ILGenerator(host, method); foreach (IOperation tempOperation in CodeGenerator.generateDeadCode(true)) { ilGenerator.Emit(tempOperation.OperationCode, tempOperation.Value); } IMethodBody newBody = new ILGeneratorMethodBody(ilGenerator, true, 8, method, Enumerable <ILocalDefinition> .Empty, Enumerable <ITypeDefinition> .Empty); copy.Body = newBody; // set intern factory of the copied method to the one of the class // (without it, the generated binary file will have strange results like call always the same method) copy.InternFactory = addTargetClass.InternFactory; // set method to not abstract copy.IsAbstract = false; // set method to not external copy.IsExternal = false; // set intern factory of the copied method to the one of the class // (without it, the generating of the binary file will have strange results) copy.InternFactory = addTargetClass.InternFactory; // add method to the class addTargetClass.Methods.Add(copy); } } }
// adds the given interface to the given class public void addInterface(NamespaceTypeDefinition addTargetClass, ITypeDefinition interfaceToAdd) { // add interface to target class if (addTargetClass.Interfaces != null) { // check if interface is already implemented by class if (addTargetClass.Interfaces.Contains(interfaceToAdd)) { this.logger.writeLine("Class \"" + addTargetClass.ToString() + "\" already implements interface \"" + interfaceToAdd.ToString() + "\""); return; } else { this.logger.writeLine("Add interface \"" + interfaceToAdd.ToString() + "\" to class \"" + addTargetClass.ToString() + "\""); addTargetClass.Interfaces.Add(interfaceToAdd); } } else { List<ITypeReference> interfaceList = new List<ITypeReference>(); interfaceList.Add(interfaceToAdd); addTargetClass.Interfaces = interfaceList; } // copy all attributes from the interface to the target class if (interfaceToAdd.Fields != null) { foreach (FieldDefinition field in interfaceToAdd.Fields) { FieldDefinition copy = new FieldDefinition(); this.helperClass.copyField(copy, field); copy.ContainingTypeDefinition = addTargetClass; // set intern factory of the copied field to the one of the class // (without it, the generated binary file will have strange results like use only the same field) copy.InternFactory = addTargetClass.InternFactory; addTargetClass.Fields.Add(copy); } } // copy all methods from the interface to the target class if (interfaceToAdd.Methods != null) { foreach (IMethodDefinition method in interfaceToAdd.Methods) { // search through all methods in the target class // to see if this method was already added bool foundMethod = false; foreach (IMethodDefinition tempMethod in addTargetClass.Methods) { // skip constructors if (tempMethod.IsConstructor) { continue; } // check if the number of parameters are the same if (tempMethod.ParameterCount == method.ParameterCount) { // check if the parameters have the same type in the same order bool parameterCorrect = true; for (int i = 0; i < method.ParameterCount; i++) { if (method.Parameters.ElementAt(i).Type != tempMethod.Parameters.ElementAt(i).Type) { parameterCorrect = false; break; } } // check if the return type is the same bool returnTypeCorrect = false; if (method.Type.Equals(tempMethod.Type)) { returnTypeCorrect = true; } // check if both methods are static // (c# compiler does not allow static + non-static function with // same signature in same class, but CIL does) bool bothStatic = false; if (method.IsStatic == tempMethod.IsStatic) { bothStatic = true; } // if the parameters and return type are correct => check the name if (parameterCorrect && returnTypeCorrect && bothStatic) { if (method.Name.Equals(tempMethod.Name)) { // if name is the same => method already added foundMethod = true; break; } } } } // skip if method was already added if (foundMethod) { this.logger.writeLine("Method \"" + method.Name.ToString() + "\" already exists"); continue; } this.logger.writeLine("Add method: " + method.Name.ToString()); // copy method MethodDefinition copy = new MethodDefinition(); this.helperClass.copyMethod(copy, method); copy.ContainingTypeDefinition = addTargetClass; // generate random dead code for newly created method ILGenerator ilGenerator = new ILGenerator(host, method); foreach (IOperation tempOperation in CodeGenerator.generateDeadCode(true)) { ilGenerator.Emit(tempOperation.OperationCode, tempOperation.Value); } IMethodBody newBody = new ILGeneratorMethodBody(ilGenerator, true, 8, method, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); copy.Body = newBody; // set intern factory of the copied method to the one of the class // (without it, the generated binary file will have strange results like call always the same method) copy.InternFactory = addTargetClass.InternFactory; // set method to not abstract copy.IsAbstract = false; // set method to not external copy.IsExternal = false; // set intern factory of the copied method to the one of the class // (without it, the generating of the binary file will have strange results) copy.InternFactory = addTargetClass.InternFactory; // add method to the class addTargetClass.Methods.Add(copy); } } }
static void Main(string[] args) { String inputFile; String targetFile; String targetNamespace; String targetClass; String targetMethod; int depth; int dimension; int numberValidPaths; int duplicateBasicBlockWeight; int duplicateBasicBlockCorrectionValue; int stateChangeWeight; int stateChangeCorrectionValue; int insertOpaquePredicateWeight; int seed; // Add debugging code into the obfuscated method (dump obfuscation graphs and so on) bool graphTransformerDebug = false; // Should the obfuscated code contain information to trace the control flow? bool basicBlockTrace = false; // When debugging is active, should the whole obfuscation graph be dumped or only the vpaths in it? bool graphOnlyDumpVPaths = true; // The number of random interfaces that are added to the program int numberRandomInterfaces = 100; if (args.Length != 14) { System.Console.WriteLine("Needed parameters: <inputBinary> <outputBinary> <namespace> <class> <method> <depth> <dimension> <numberValidPaths> <duplicateBasicBlockWeight> <duplicateBasicBlockCorrectionValue> <stateChangeWeight> <stateChangeCorrectionValue> <insertOpaquePredicateWeight> <seed>"); return; } else { inputFile = args[0]; targetFile = args[1]; targetNamespace = args[2]; targetClass = args[3]; targetMethod = args[4]; depth = Convert.ToInt32(args[5]); dimension = Convert.ToInt32(args[6]); numberValidPaths = Convert.ToInt32(args[7]); duplicateBasicBlockWeight = Convert.ToInt32(args[8]); duplicateBasicBlockCorrectionValue = Convert.ToInt32(args[9]); stateChangeWeight = Convert.ToInt32(args[10]); stateChangeCorrectionValue = Convert.ToInt32(args[11]); insertOpaquePredicateWeight = Convert.ToInt32(args[12]); seed = Convert.ToInt32(args[13]); } String logDir = Path.GetDirectoryName(targetFile); Log.Log logger = new Log.Log(logDir, "probfuscation_logfile.txt"); System.Console.WriteLine("Obfuscating: " + inputFile); logger.writeLine("Obfuscating: " + inputFile); System.Console.WriteLine("Output file: " + targetFile); logger.writeLine("Output file: " + targetFile); System.Console.WriteLine("Target namespace: " + targetNamespace); logger.writeLine("Target namespace: " + targetNamespace); System.Console.WriteLine("Target class: " + targetClass); logger.writeLine("Target class: " + targetClass); System.Console.WriteLine("Target method: " + targetMethod); logger.writeLine("Target method: " + targetMethod); System.Console.WriteLine("Depth: " + depth); logger.writeLine("Depth: " + depth); System.Console.WriteLine("Dimension: " + dimension); logger.writeLine("Dimension: " + dimension); System.Console.WriteLine("Number of vpaths: " + numberValidPaths); logger.writeLine("Number of vpaths: " + numberValidPaths); System.Console.WriteLine("Basic Block duplication weight: " + duplicateBasicBlockWeight); logger.writeLine("Basic Block duplication weight: " + duplicateBasicBlockWeight); System.Console.WriteLine("Basic Block duplication correction value: " + duplicateBasicBlockCorrectionValue); logger.writeLine("Basic Block duplication correction value: " + duplicateBasicBlockCorrectionValue); System.Console.WriteLine("State change weight: " + stateChangeWeight); logger.writeLine("State change weight: " + stateChangeWeight); System.Console.WriteLine("State change correction value: " + stateChangeCorrectionValue); logger.writeLine("State change correction value: " + stateChangeCorrectionValue); System.Console.WriteLine("Opaque predicate weight: " + insertOpaquePredicateWeight); logger.writeLine("Opaque predicate weight: " + insertOpaquePredicateWeight); System.Console.WriteLine("Seed: " + seed); logger.writeLine("Seed: " + seed); // Seed PRNG for interfaces PRNGRandomInterfaces = new Random(seed); using (var host = new PeReader.DefaultHost()) { IModule /*?*/ module = host.LoadUnitFrom(inputFile) as IModule; if (module == null || module == Dummy.Module || module == Dummy.Assembly) { Console.WriteLine(inputFile + " is not a PE file containing a CLR module or assembly."); return; } module = new MetadataDeepCopier(host).Copy(module); if (module as Assembly == null) { logger.writeLine("File does not have CIL assembly"); return; } // create analyzer object object CfgBuilder analyze = new Cfg.CfgBuilder(module, host, logger); PdbReader /*?*/ pdbReader = null; string pdbFile = Path.ChangeExtension(module.Location, "pdb"); if (File.Exists(pdbFile)) { using (var pdbStream = File.OpenRead(pdbFile)) { pdbReader = new PdbReader(pdbStream, host); } } else { logger.writeLine("Could not load the PDB file for '" + module.Name.Value + "' . Proceeding anyway."); } using (pdbReader) { Microsoft.Cci.ILGenerator.LocalScopeProvider localScopeProvider = null; if (pdbReader != null) { localScopeProvider = new ILGenerator.LocalScopeProvider(pdbReader); } // search the namespace the interface should be added to IUnitNamespace foundNamespace = null; foreach (var tempMember in module.UnitNamespaceRoot.Members) { if ((tempMember as IUnitNamespace) == null) { continue; } IUnitNamespace tempNamespace = (tempMember as IUnitNamespace); if (tempNamespace.ToString() == targetNamespace) { foundNamespace = tempNamespace; break; } } if (foundNamespace == null) { throw new ArgumentException("Not able to find target namespace."); } // add created interface (and implemented methods) to all classes bool classFound = false; foreach (var tempClass in module.GetAllTypes()) { if ((tempClass as NamespaceTypeDefinition) == null || tempClass.IsAbstract) { continue; } NamespaceTypeDefinition foundClass = (tempClass as NamespaceTypeDefinition); if (foundClass.ContainingUnitNamespace.ToString() == "") { continue; } if (foundClass.ToString() != targetNamespace + "." + targetClass) { continue; } classFound = true; Random prng = new Random(); GraphTransformer graphTransformer = new GraphTransformer(module, host, logger, prng, foundNamespace, foundClass, depth, dimension, graphTransformerDebug); graphTransformer.duplicateBasicBlockWeight = duplicateBasicBlockWeight; graphTransformer.duplicateBasicBlockCorrectionValue = duplicateBasicBlockCorrectionValue; graphTransformer.stateChangeWeight = stateChangeWeight; graphTransformer.stateChangeCorrectionValue = stateChangeCorrectionValue; graphTransformer.insertOpaquePredicateWeight = insertOpaquePredicateWeight; graphTransformer.trace = basicBlockTrace; graphTransformer.graphOnlyDumpVPaths = graphOnlyDumpVPaths; graphTransformer.debuggingDumpLocation = logDir; // Add 100 random interfaces to the namespace Helper testHelper = new Helper(module, host, logger); List <NamespaceTypeDefinition> randomInterfaces = new List <NamespaceTypeDefinition>(); for (int i = 0; i < numberRandomInterfaces; i++) { String randName = randomString(20); NamespaceTypeDefinition temp = testHelper.createNewInterface(randName, foundNamespace); randomInterfaces.Add(temp); } InterfaceTransformer interfaceTransformer = new InterfaceTransformer(module, host, logger); foreach (var classToAdd in module.GetAllTypes()) { if ((classToAdd as NamespaceTypeDefinition) == null || classToAdd.IsAbstract || classToAdd.IsInterface || classToAdd.IsEnum || classToAdd.IsDelegate || classToAdd.IsGeneric || classToAdd.IsStruct) { continue; } if (((NamespaceTypeDefinition)classToAdd).ContainingUnitNamespace.ToString() == "") { continue; } /* * // Use this code if you want to add standard interfaces to the target class * interfaceTransformer.addStdInterfacesGivenByFile(@"e:\code\dotnet_standard_interfaces.txt"); * * // add std interfaces to class * if (foundClass != (classToAdd as NamespaceTypeDefinition)) { * foreach (ITypeDefinition temp in interfaceTransformer.getInterfacesList()) { * interfaceTransformer.addInterface((classToAdd as NamespaceTypeDefinition), temp); * } * } */ // Add random interfaces to the classes List <NamespaceTypeDefinition> alreadyAdded = new List <NamespaceTypeDefinition>(); int max = PRNGRandomInterfaces.Next(numberRandomInterfaces); NamespaceTypeDefinition interfaceClass = (classToAdd as NamespaceTypeDefinition); logger.writeLine("Adding " + max + " random interfaces to class \"" + interfaceClass.ToString() + "\""); for (int i = 0; i < max; i++) { NamespaceTypeDefinition randInterface = randomInterfaces.ElementAt(PRNGRandomInterfaces.Next(randomInterfaces.Count)); if (alreadyAdded.Contains(randInterface)) { continue; } alreadyAdded.Add(randInterface); logger.writeLine("Adding interface: \"" + randInterface.ToString() + "\""); // add nodes interface to class if (interfaceClass.Interfaces != null) { interfaceClass.Interfaces.Add(randInterface); } else { interfaceClass.Interfaces = new List <ITypeReference>(); interfaceClass.Interfaces.Add(randInterface); } } logger.writeLine(""); // Add special interface for the obfuscation scheme to the class // (makes sure that all needed attributes and methods are implemented) graphTransformer.addNodeInterfaceToTargetClass((classToAdd as NamespaceTypeDefinition)); } // Prepare obfuscation graph graphTransformer.generateGraph(numberValidPaths); graphTransformer.createGraphMethods(); // Search method to obfuscate MethodDefinition methodToObfu = null; foreach (MethodDefinition tempMethod in foundClass.Methods) { if (tempMethod.Name.ToString() == targetMethod) { methodToObfu = tempMethod; break; } } if (methodToObfu == null) { throw new ArgumentException("Not able to find target method."); } // Obfuscate target method MethodCfg cfg = analyze.buildCfgForMethod(methodToObfu); logger.dumpMethodCfg(cfg, "before"); graphTransformer.addObfuscationToMethod(cfg); analyze.createMethodFromCfg(cfg); logger.dumpMethodCfg(cfg, "after"); break; } if (!classFound) { throw new ArgumentException("Not able to find target class."); } /* * This code can be used if not only one specific method should be obfuscated, * but the whole class. * List<ClassCfg> classCfgList = new List<ClassCfg>(); * foreach (var tempClass in module.GetAllTypes()) { * if ((tempClass as NamespaceTypeDefinition) == null || tempClass.IsAbstract) { || continue; || } || || // create basic blocks || NamespaceTypeDefinition foundClass = (tempClass as NamespaceTypeDefinition); || || logger.writeLine("Create CFG for class \"" + foundClass.Name.ToString() + "\""); || ClassCfg temp = analyze.buildCfgForClass(foundClass); || classCfgList.Add(temp); || logger.writeLine("\n---------------------------------\n"); ||} || ||// transform each function ||NopTransformer transformator = new NopTransformer(module, host, logger); ||foreach (ClassCfg tempClassCfg in classCfgList) { || foreach (MethodCfg tempMethodCfg in tempClassCfg.methodCfgs) { || logger.writeLine("Transform method CFG of \"" + tempMethodCfg.method.ToString() + "\""); || transformator.addNopsToCfg(tempMethodCfg); || logger.writeLine("\n---------------------------------\n"); || } ||} || ||foreach (ClassCfg tempClassCfg in classCfgList) { || logger.writeLine("Create class from CFG for \"" + tempClassCfg.classObj.Name.ToString() + "\""); || analyze.createClassFromCfg(tempClassCfg); || logger.writeLine("\n---------------------------------\n"); ||} */ using (var peStream = File.Create(targetFile)) { using (var pdbWriter = new PdbWriter(Path.ChangeExtension(targetFile, ".pdb"), pdbReader)) { PeWriter.WritePeToStream(module, host, peStream, pdbReader, localScopeProvider, pdbWriter); } } } } }
// this function adds the created iNode interface to the class and also implements all neded functions public void addNodeInterfaceToTargetClass(NamespaceTypeDefinition givenClass) { this.logger.writeLine(""); this.logger.writeLine("Add node interface \"" + this.nodeInterface.ToString() + "\" to class \"" + givenClass.ToString() + "\""); // check if generated interface was already added to target class if (givenClass.Interfaces != null && givenClass.Interfaces.Contains(this.nodeInterface)) { this.logger.writeLine("Class \"" + givenClass.ToString() + "\" already contains node interface \"" + this.nodeInterface.ToString() + "\""); return; } // add nodes interface to class if (givenClass.Interfaces != null) { givenClass.Interfaces.Add(this.nodeInterface); } else { givenClass.Interfaces = new List<ITypeReference>(); givenClass.Interfaces.Add(this.nodeInterface); } // add start pointer field FieldDefinition startPointerField = new FieldDefinition(); startPointerField.IsCompileTimeConstant = false; startPointerField.IsNotSerialized = false; startPointerField.IsReadOnly = false; startPointerField.IsRuntimeSpecial = false; startPointerField.IsSpecialName = false; startPointerField.Type = this.nodeInterface; startPointerField.IsStatic = false; startPointerField.Visibility = TypeMemberVisibility.Public; startPointerField.Name = host.NameTable.GetNameFor("startPointer"); startPointerField.InternFactory = host.InternFactory; startPointerField.ContainingTypeDefinition = givenClass; if (givenClass.Fields != null) { givenClass.Fields.Add(startPointerField); } else { givenClass.Fields = new List<IFieldDefinition>(); givenClass.Fields.Add(startPointerField); } // create getter for the startPointer variable MethodDefinition startPointerGetMethod = this.helperClass.createNewMethod("startPointer_get", givenClass, this.nodeInterface, TypeMemberVisibility.Public, null, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the getter method ILGenerator ilGenerator = new ILGenerator(host, startPointerGetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, startPointerField); ilGenerator.Emit(OperationCode.Ret); IMethodBody body = new ILGeneratorMethodBody(ilGenerator, true, 1, startPointerGetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); startPointerGetMethod.Body = body; // create setter for the startPointer variable List<IParameterDefinition> parameters = new List<IParameterDefinition>(); ParameterDefinition parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Name = host.NameTable.GetNameFor("value"); parameter.Type = this.nodeInterface; parameters.Add(parameter); MethodDefinition startPointerSetMethod = this.helperClass.createNewMethod("startPointer_set", givenClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the setter method ilGenerator = new ILGenerator(host, startPointerSetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stfld, startPointerField); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, startPointerSetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); startPointerSetMethod.Body = body; // add childNodes array field FieldDefinition childNodesField = new FieldDefinition(); childNodesField.IsCompileTimeConstant = false; childNodesField.IsNotSerialized = false; childNodesField.IsReadOnly = false; childNodesField.IsRuntimeSpecial = false; childNodesField.IsSpecialName = false; // create array of node interface type VectorTypeReference nodeInterfaceArrayType = new VectorTypeReference(); nodeInterfaceArrayType.ElementType = this.nodeInterface; nodeInterfaceArrayType.Rank = 1; nodeInterfaceArrayType.IsFrozen = true; nodeInterfaceArrayType.IsValueType = false; nodeInterfaceArrayType.InternFactory = host.InternFactory; childNodesField.Type = nodeInterfaceArrayType; childNodesField.IsStatic = false; childNodesField.Visibility = TypeMemberVisibility.Public; childNodesField.Name = host.NameTable.GetNameFor("childNodes"); childNodesField.InternFactory = host.InternFactory; childNodesField.ContainingTypeDefinition = givenClass; givenClass.Fields.Add(childNodesField); // create getter for the childNodes variable parameters = new List<IParameterDefinition>(); // int parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.host.PlatformType.SystemInt32; parameters.Add(parameter); MethodDefinition childNodesGetMethod = this.helperClass.createNewMethod("childNodes_get", givenClass, this.nodeInterface, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the getter method ilGenerator = new ILGenerator(host, childNodesGetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, childNodesField); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Ldelem_Ref); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, childNodesGetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); childNodesGetMethod.Body = body; // create setter for the childNodes variable parameters = new List<IParameterDefinition>(); // iNode parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameters.Add(parameter); // int parameter parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.host.PlatformType.SystemInt32; parameters.Add(parameter); MethodDefinition childNodesSetMethod = this.helperClass.createNewMethod("childNodes_set", givenClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the setter method ilGenerator = new ILGenerator(host, childNodesSetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, childNodesField); ilGenerator.Emit(OperationCode.Ldarg_2); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stelem_Ref); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, childNodesSetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); childNodesSetMethod.Body = body; // add current node field FieldDefinition currentNodeField = new FieldDefinition(); currentNodeField.IsCompileTimeConstant = false; currentNodeField.IsNotSerialized = false; currentNodeField.IsReadOnly = false; currentNodeField.IsRuntimeSpecial = false; currentNodeField.IsSpecialName = false; currentNodeField.Type = this.nodeInterface; currentNodeField.IsStatic = false; currentNodeField.Visibility = TypeMemberVisibility.Public; currentNodeField.Name = host.NameTable.GetNameFor("currentNode"); currentNodeField.InternFactory = host.InternFactory; currentNodeField.ContainingTypeDefinition = givenClass; givenClass.Fields.Add(currentNodeField); // create getter for the currentNode variable MethodDefinition currentNodeGetMethod = this.helperClass.createNewMethod("currentNode_get", givenClass, this.nodeInterface, TypeMemberVisibility.Public, null, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the getter method ilGenerator = new ILGenerator(host, currentNodeGetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, currentNodeField); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, currentNodeGetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); currentNodeGetMethod.Body = body; // create setter for the currentNode variable parameters = new List<IParameterDefinition>(); parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Name = host.NameTable.GetNameFor("value"); parameter.Type = this.nodeInterface; parameters.Add(parameter); MethodDefinition currentNodeSetMethod = this.helperClass.createNewMethod("currentNode_set", givenClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the setter method ilGenerator = new ILGenerator(host, currentNodeSetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_1); ilGenerator.Emit(OperationCode.Stfld, currentNodeField); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, currentNodeSetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); currentNodeSetMethod.Body = body; // check if debugging is activated // => add graph debugging attributes and methods MethodDefinition objectIdGetMethod = null; FieldDefinition objectIdField = null; if (this.debugging) { this.logger.writeLine("Debugging activated: Adding field for unique object id and getter method"); // add objectId field objectIdField = new FieldDefinition(); objectIdField.IsCompileTimeConstant = false; objectIdField.IsNotSerialized = false; objectIdField.IsReadOnly = false; objectIdField.IsRuntimeSpecial = false; objectIdField.IsSpecialName = false; objectIdField.Type = this.host.PlatformType.SystemString; objectIdField.IsStatic = false; objectIdField.Name = host.NameTable.GetNameFor("DEBUG_objectId"); objectIdField.Visibility = TypeMemberVisibility.Public; objectIdField.InternFactory = host.InternFactory; objectIdField.ContainingTypeDefinition = givenClass; givenClass.Fields.Add(objectIdField); // create getter for the objectId variable objectIdGetMethod = this.helperClass.createNewMethod("DEBUG_objectId_get", givenClass, this.host.PlatformType.SystemString, TypeMemberVisibility.Public, null, CallingConvention.HasThis, false, false, true); // TODO: method name // create a body for the getter method ilGenerator = new ILGenerator(host, objectIdGetMethod); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldfld, objectIdField); ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 1, objectIdGetMethod, Enumerable<ILocalDefinition>.Empty, Enumerable<ITypeDefinition>.Empty); objectIdGetMethod.Body = body; } // add .ctor(iNode) to target class parameters = new List<IParameterDefinition>(); parameter = new ParameterDefinition(); parameter.IsIn = false; parameter.IsOptional = false; parameter.IsOut = false; parameter.Type = this.nodeInterface; parameters.Add(parameter); MethodDefinition nodeConstructor = this.helperClass.createNewMethod(".ctor", givenClass, host.PlatformType.SystemVoid, TypeMemberVisibility.Public, parameters, CallingConvention.HasThis, false, false, false); nodeConstructor.IsSpecialName = true; nodeConstructor.IsHiddenBySignature = true; nodeConstructor.IsRuntimeSpecial = true; // generate node constructor body ilGenerator = new ILGenerator(host, currentNodeSetMethod); // create local variable list List<ILocalDefinition> localVariables = new List<ILocalDefinition>(); // call system.object constructor ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Call, this.helperClass.objectCtor); // initialize childNodes array ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldc_I4, this.graphDimension); ilGenerator.Emit(OperationCode.Newarr, nodeInterfaceArrayType); ilGenerator.Emit(OperationCode.Stfld, childNodesField); // check if debugging is activated // => add code to constructor that generates a unique id for this object if (this.debugging) { this.logger.writeLine("Debugging activated: Adding code to generate unique id to node constructor"); // create local integer variable needed for debugging code LocalDefinition intLocal = new LocalDefinition(); intLocal.IsReference = false; intLocal.IsPinned = false; intLocal.IsModified = false; intLocal.Type = this.host.PlatformType.SystemInt32; intLocal.MethodDefinition = nodeConstructor; localVariables.Add(intLocal); // use the hash code of this instance as unique object id ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Ldarg_0); ilGenerator.Emit(OperationCode.Callvirt, this.helperClass.objectGetHashCode); ilGenerator.Emit(OperationCode.Stloc, intLocal); // cast random integer to string and store in object id ilGenerator.Emit(OperationCode.Ldloca, intLocal); ilGenerator.Emit(OperationCode.Call, this.helperClass.int32ToString); ilGenerator.Emit(OperationCode.Stfld, objectIdField); } ilGenerator.Emit(OperationCode.Ret); body = new ILGeneratorMethodBody(ilGenerator, true, 8, nodeConstructor, localVariables, Enumerable<ITypeDefinition>.Empty); nodeConstructor.Body = body; // add class to the list of possible nodes for the graph PossibleNode tempStruct = new PossibleNode(); tempStruct.nodeConstructor = nodeConstructor; tempStruct.givenClass = givenClass; // for each interface the class implements add it to the according list foreach (ITypeReference interfaceRef in givenClass.Interfaces) { this.logger.writeLine("Add class \"" + givenClass.ToString() + "\" to graph interface list \"" + interfaceRef.ToString() + "\""); // check if a list with this interface already exists // => if it does just add current class to list if (this.graphInterfaces.ContainsKey(interfaceRef)) { List<PossibleNode> tempList = (List<PossibleNode>)this.graphInterfaces[interfaceRef]; tempList.Add(tempStruct); } // if not => add new list for this interface else { List<PossibleNode> tempList = new List<PossibleNode>(); tempList.Add(tempStruct); this.graphInterfaces.Add(interfaceRef, tempList); } } this.logger.writeLine(""); }
static void Main(string[] args) { //String inputFile = @"c:\Users\typ\Documents\Visual Studio 2013\Projects\vererbung\vererbung\bin\Debug\vererbung.exe"; String inputFile = @"e:\dile_v0_2_12_x86\Dile.exe"; globalLog = new Log(@"e:\merge_logfile.txt"); System.Console.WriteLine(inputFile); /* * if (args == null || args.Length == 0) * { * Console.WriteLine("Usage: ILMutator <assembly> [<outputPath>]"); * return; * } */ using (var host = new PeReader.DefaultHost()) { //IModule/*?*/ module = host.LoadUnitFrom(args[0]) as IModule; IModule /*?*/ module = host.LoadUnitFrom(inputFile) as IModule; if (module == null || module == Dummy.Module || module == Dummy.Assembly) { //Console.WriteLine(args[0] + " is not a PE file containing a CLR module or assembly."); Console.WriteLine(inputFile + " is not a PE file containing a CLR module or assembly."); return; } module = new MetadataDeepCopier(host).Copy(module); if (module as Assembly == null) { globalLog.writeLine("File does not have CIL assembly"); return; } PdbReader /*?*/ pdbReader = null; string pdbFile = Path.ChangeExtension(module.Location, "pdb"); if (File.Exists(pdbFile)) { using (var pdbStream = File.OpenRead(pdbFile)) { pdbReader = new PdbReader(pdbStream, host); } } else { globalLog.writeLine("Could not load the PDB file for '" + module.Name.Value + "' . Proceeding anyway."); } using (pdbReader) { Microsoft.Cci.ILGenerator.LocalScopeProvider localScopeProvider = null; if (pdbReader != null) { localScopeProvider = new ILGenerator.LocalScopeProvider(pdbReader); } // AB HIER DER INTERESSANTE PART ZUM MERGEN, DAVOR NUR INIT CRAP // search for class in namespace NamespaceTypeDefinition foundClass = null; foreach (var asdf in module.GetAllTypes()) { //if (asdf.ToString() == "vererbung.Erber") { if (asdf.ToString() == "Dile.Disassemble.Assembly") { foundClass = (asdf as NamespaceTypeDefinition); break; } } if (foundClass == null) { globalLog.writeLine("Class not found!"); return; } // merge class globalLog.writeLine("Merge class \"" + foundClass.ToString() + "\" with all ancestors"); mergeClassWithAllAncestors(foundClass, host); string newName; if (args.Length == 2) { newName = args[1]; //newName = @"e:\dile_v0_2_12_x86\dile_classes.exe"; newName = @"e:\test.exe"; } else { var loc = module.Location; var path = Path.GetDirectoryName(loc) ?? ""; var fileName = Path.GetFileNameWithoutExtension(loc); var ext = Path.GetExtension(loc); newName = Path.Combine(path, fileName + "1" + ext); //newName = @"e:\dile_v0_2_12_x86\dile_classes.exe"; newName = @"e:\test.exe"; } using (var peStream = File.Create(newName)) { using (var pdbWriter = new PdbWriter(Path.ChangeExtension(newName, ".pdb"), pdbReader)) { PeWriter.WritePeToStream(module, host, peStream, pdbReader, localScopeProvider, pdbWriter); } } } } }
static void mergeClassWithAncestor(NamespaceTypeDefinition mergeTargetClass, PeReader.DefaultHost host) { // get class from which was inherited ITypeDefinition ancestorClass = null; INamedEntity ancestorClassName = null; if (mergeTargetClass.BaseClasses.Count == 1) { // TODO // entferne wenn Methode umgeschrieben /* * // ignore inheritance from System.Object * if (mergeTargetClass.BaseClasses[0].ToString() != "System.Object") { * ancestorClass = (mergeTargetClass.BaseClasses[0] as NamespaceTypeDefinition); * } * // return if ancestor class equals System.Object * else { * return; * } */ // check base class is of type NamespaceTypeDefinition if (mergeTargetClass.BaseClasses.ElementAt(0) as NamespaceTypeDefinition != null) { ancestorClass = (mergeTargetClass.BaseClasses.ElementAt(0) as ITypeDefinition); ancestorClassName = (mergeTargetClass.BaseClasses.ElementAt(0) as INamedEntity); } // ignore inheritance from System.Object else if (mergeTargetClass.BaseClasses[0].ToString() == "System.Object") { return; } // check for needed values in base class and its resolved value (for example when base class of type NamespaceTypeReference) else if ((mergeTargetClass.BaseClasses.ElementAt(0).ResolvedType as ITypeDefinition != null) && (mergeTargetClass.BaseClasses.ElementAt(0) as INamedEntity != null)) { // TODO // weiss nicht ob es Sinn macht externe Klassen wie z.B. system.ValueType // in die aktuelle Klasse rein zu mergen => denn Trick mit methoden auf Virtual stellen // damit JIT Compiler unsere Methoden aufruft klappt nicht in dem Fall (da wir die Methoden von System.ValueType nicht umschreiben koennen) //ancestorClass = (mergeTargetClass.BaseClasses[0].ResolvedType as ITypeDefinition); //ancestorClassName = (mergeTargetClass.BaseClasses[0].ResolvedType as INamedEntity); return; } else { throw new ArgumentException("Do not know how to handle base class."); } } else { throw new ArgumentException("Do not know how to handle multiple inheritance."); } // copy all attributes from the ancestor class to the current class if (ancestorClass.Fields != null) { globalLog.writeLine("Copying fileds"); foreach (FieldDefinition field in ancestorClass.Fields) { FieldDefinition copy = new FieldDefinition(); globalLog.writeLine("Copying field: " + field.Name.ToString()); copyField(copy, field); copy.ContainingTypeDefinition = mergeTargetClass; // set intern factory of the copied field to the one of the class // (without it, the generated binary file will have strange results like use only the same field) copy.InternFactory = mergeTargetClass.InternFactory; mergeTargetClass.Fields.Add(copy); } globalLog.writeLine(""); } // list of all constructors of the ancestor class List <MethodDefinition> copiedAncestorConstructors = new List <MethodDefinition>(); // copy methods from the ancestor class to the current class if (ancestorClass.Methods != null) { globalLog.writeLine("Copying methods"); foreach (IMethodDefinition method in ancestorClass.Methods) { globalLog.writeLine("Copying method: " + method.Name.ToString()); // check if the method is a constructor if (method.IsConstructor) { MethodDefinition copiedAncestorConstructor = new MethodDefinition(); copyMethod(copiedAncestorConstructor, method, host); // TODO // name muss noch geaendert werden String tempName = "ctor_" + ancestorClassName.Name.ToString(); copiedAncestorConstructor.Name = host.NameTable.GetNameFor(tempName); // constructor has the "SpecialName" (the name describes the functionality) // and "RTSpecialName" (runtime should check name encoding) flag set // runtime will raise an exception if these flags are set for a copied constructor // which is added as a normal function copiedAncestorConstructor.IsSpecialName = false; copiedAncestorConstructor.IsRuntimeSpecial = false; // TODO: // vielleicht einfach von späterer Schleife machen lassen (sollte jetzt schon gehen, aber noch nicht getestet, // deshalb erst ein mal drin gelassen) // copy constructor and rewrite instructions to use attributes and functions // inside the same class var testIlGenerator = new ILGenerator(host, copiedAncestorConstructor); foreach (var operation in copiedAncestorConstructor.Body.Operations) { switch (operation.OperationCode) { case OperationCode.Call: // HIER NOCH CHECKEN OB ANDERE FUNKTIONEN INNERHALB DES ANCESTORS AUFGERUFEN WERDEN // DIESE MUESSEN UMGELEITET WERDEN /* * Microsoft.Cci.MutableCodeModel.MethodDefinition blah = null; * if (operation.Value is Microsoft.Cci.MutableCodeModel.MethodDefinition) { * blah = (Microsoft.Cci.MutableCodeModel.MethodDefinition)(operation.Value); * NamespaceTypeDefinition test = (NamespaceTypeDefinition)blah.ContainingTypeDefinition; * * if (ancestorClass.Name.Equals(test.Name)) { * System.Console.WriteLine("Ja"); * } * * * } */ testIlGenerator.Emit(operation.OperationCode, operation.Value); break; case OperationCode.Stfld: FieldDefinition attribute = (FieldDefinition)operation.Value; // search for the method attribute that is used in the copied constructor // and replace it with the method attribute from the current class FieldDefinition foundField = null; foreach (FieldDefinition field in mergeTargetClass.Fields) { if (attribute.Name.Equals(field.Name) && attribute.Type.Equals(field.Type)) { foundField = field; break; } } if (foundField == null) { System.Console.WriteLine("Attribute not found"); return; } testIlGenerator.Emit(operation.OperationCode, foundField); break; default: testIlGenerator.Emit(operation.OperationCode, operation.Value); break; } } // create new body List <ILocalDefinition> variableListCopy = new List <ILocalDefinition>(method.Body.LocalVariables); List <ITypeDefinition> privateHelperTypesListCopy = new List <ITypeDefinition>(method.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(testIlGenerator, method.Body.LocalsAreZeroed, method.Body.MaxStack, copiedAncestorConstructor, variableListCopy, privateHelperTypesListCopy); copiedAncestorConstructor.Body = newBody; // set intern factory of the copied constructor to the one of the class // (without it, the generated binary file will have strange results like call always the same method) copiedAncestorConstructor.InternFactory = mergeTargetClass.InternFactory; // add copied constructor to the class copiedAncestorConstructor.ContainingTypeDefinition = mergeTargetClass; copiedAncestorConstructor.Visibility = TypeMemberVisibility.Private; mergeTargetClass.Methods.Add(copiedAncestorConstructor); // add copied ancestor constructor to the list of copied ancestor constructors copiedAncestorConstructors.Add(copiedAncestorConstructor); continue; } else { // copy method MethodDefinition copy = new MethodDefinition(); copyMethod(copy, method, host); copy.ContainingTypeDefinition = mergeTargetClass; // set intern factory of the copied method to the one of the class // (without it, the generating of the binary file will have strange results) copy.InternFactory = mergeTargetClass.InternFactory; // add method to the class if (mergeTargetClass.Methods == null) { mergeTargetClass.Methods = new List <IMethodDefinition>(); } mergeTargetClass.Methods.Add(copy); } } globalLog.writeLine(""); } // rewrite constructors of the class to call the copied constructor instead of // the constructor of the ancestor class // (rewriting methods is handled later) foreach (MethodDefinition method in mergeTargetClass.Methods) { // check if method is a constructor if (method.IsConstructor) { var testIlGenerator = new ILGenerator(host, method); foreach (var operation in method.Body.Operations) { switch (operation.OperationCode) { // only call instructions that call a constructor have to be redirected case OperationCode.Call: MethodDefinition calledMethod = (MethodDefinition)operation.Value; if (calledMethod.IsConstructor) { // TODO hier treten noch Probleme auf, wenn System.Object ist nicht der oberste Ancestor // sondern z.B. System.ValueType // check if the called constructor is not the constructor of System.Object // and if the constructor that is called is not a constructor of THIS class NamespaceTypeDefinition calledMethodNamespace = (NamespaceTypeDefinition)calledMethod.ContainingTypeDefinition; if (calledMethodNamespace.ToString() != "System.Object" && !calledMethodNamespace.Name.Equals(mergeTargetClass.Name)) { // search for the copied constructor that has to be called // (it is searched by parameter types because they always are named the same ".ctor") MethodDefinition copiedConstructorToCall = null; foreach (MethodDefinition copiedAncestorConstructor in copiedAncestorConstructors) { // check if the count of the parameters of the called constructor and the copied constructor are the same if (copiedAncestorConstructor.ParameterCount == calledMethod.ParameterCount) { // check if the parameters have the same type in the same order bool found = true; for (int i = 0; i < calledMethod.ParameterCount; i++) { if (calledMethod.Parameters[i].Type != copiedAncestorConstructor.Parameters[i].Type) { found = false; break; } } if (found) { copiedConstructorToCall = copiedAncestorConstructor; break; } } } if (copiedConstructorToCall == null) { throw new ArgumentException("No copied constructor with the same parameter types in the same order."); } // call copied constructor instead of constructor of the ancestor testIlGenerator.Emit(operation.OperationCode, copiedConstructorToCall); } // just emit if the called constructor is the constructor of System.Object else { testIlGenerator.Emit(operation.OperationCode, operation.Value); } } // just emit operation if no constructor is called // (rewriting methods is handled later) else { testIlGenerator.Emit(operation.OperationCode, operation.Value); } break; // just emit operation if none of the above cases match default: testIlGenerator.Emit(operation.OperationCode, operation.Value); break; } } // create new body List <ILocalDefinition> variableListCopy = new List <ILocalDefinition>(method.Body.LocalVariables); List <ITypeDefinition> privateHelperTypesListCopy = new List <ITypeDefinition>(method.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(testIlGenerator, method.Body.LocalsAreZeroed, method.Body.MaxStack, method, variableListCopy, privateHelperTypesListCopy); method.Body = newBody; } } // rewrite all methods to use local attributes/methods instead of the ones of the ancestor foreach (MethodDefinition method in mergeTargetClass.Methods) { var testIlGenerator = new ILGenerator(host, method); foreach (var operation in method.Body.Operations) { switch (operation.OperationCode) { case OperationCode.Stfld: case OperationCode.Ldfld: // get namespace of attribute FieldDefinition attribute = (FieldDefinition)operation.Value; INamedTypeDefinition attributeNamespace = (INamedTypeDefinition)attribute.ContainingTypeDefinition; // check if namespace of attribute equals the namespace of THIS class // => just emit operation if (mergeTargetClass.Name.Equals(attributeNamespace.Name)) { testIlGenerator.Emit(operation.OperationCode, operation.Value); continue; } // try the namespace of all ancestors of this class to see if it was copied else { // flag that indicates if the operation was emitted during the search loop bool operationEmitted = false; // search through all ancestors to find the namespace of the used attribute NamespaceTypeDefinition tempAncestorClass = mergeTargetClass; while (true) { // get class from which was inherited if (tempAncestorClass.BaseClasses.Count == 1) { // ignore inheritance from System.Object if (tempAncestorClass.BaseClasses[0].ToString() != "System.Object") { tempAncestorClass = (tempAncestorClass.BaseClasses[0] as NamespaceTypeDefinition); } // return if ancestor class equals System.Object else { break; } } else { throw new ArgumentException("Do not know how to handle multiple inheritance."); } // check namespace of used attribute is equal to namespace of ancestor // => change target of operation to THIS class if (tempAncestorClass.Name.Equals(attributeNamespace.Name)) { // search for the method attribute that is used in the copied method // and replace it with the method attribute from the current class FieldDefinition foundField = null; foreach (FieldDefinition field in mergeTargetClass.Fields) { if (attribute.Name.Equals(field.Name) && attribute.Type.Equals(field.Type)) { foundField = field; break; } } if (foundField == null) { throw new ArgumentException("Attribute not found."); } // emit operation and set flag that it was emitted operationEmitted = true; testIlGenerator.Emit(operation.OperationCode, foundField); break; } } // if operation was not emitted yet => emit it if (operationEmitted == false) { testIlGenerator.Emit(operation.OperationCode, operation.Value); } } break; case OperationCode.Call: // just emit if value is of type method reference if (operation.Value is Microsoft.Cci.MutableCodeModel.MethodReference) { testIlGenerator.Emit(operation.OperationCode, operation.Value); continue; } // get namespace of called method MethodDefinition calledMethod = (MethodDefinition)operation.Value; NamespaceTypeDefinition calledMethodNamespace = (NamespaceTypeDefinition)calledMethod.ContainingTypeDefinition; // check if namespace of called method equals the namespace of THIS class // => just emit operation if (mergeTargetClass.Name.Equals(calledMethodNamespace.Name)) { testIlGenerator.Emit(operation.OperationCode, operation.Value); continue; } // try the namespace of all ancestors of this class to see if it was copied else { // flag that indicates if the operation was emitted during the search loop bool operationEmitted = false; // search through all ancestors to find the namespace of the called method NamespaceTypeDefinition tempAncestorClass = mergeTargetClass; while (true) { // get class from which was inherited if (tempAncestorClass.BaseClasses.Count == 1) { // ignore inheritance from System.Object if (tempAncestorClass.BaseClasses[0].ToString() != "System.Object") { tempAncestorClass = (tempAncestorClass.BaseClasses[0] as NamespaceTypeDefinition); } // return if ancestor class equals System.Object else { break; } } else { throw new ArgumentException("Do not know how to handle multiple inheritance."); } // check namespace of called method is equal to namespace of ancestor, if the same // => find copied method in THIS class // => change target of operation to method in THIS class if (tempAncestorClass.Name.Equals(calledMethodNamespace.Name)) { // search through all methods in THISS class and search for the copied one MethodDefinition foundMethod = null; foreach (MethodDefinition newMethod in mergeTargetClass.Methods) { // skip constructors (can not be called from the ancestor) if (newMethod.IsConstructor) { continue; } if (newMethod.ParameterCount == calledMethod.ParameterCount) { // check if the parameters have the same type in the same order bool parameterCorrect = true; for (int i = 0; i < calledMethod.ParameterCount; i++) { if (calledMethod.Parameters[i].Type != newMethod.Parameters[i].Type) { parameterCorrect = false; break; } } // if the parameters are correct => check the name if (parameterCorrect) { if (calledMethod.Name.Equals(newMethod.Name)) { // if name is the same => found method to call foundMethod = newMethod; break; } } } } // check if the method we want to call was found if (foundMethod == null) { throw new ArgumentException("Did not find a method to call."); } // emit operation and set flag that it was emitted operationEmitted = true; testIlGenerator.Emit(operation.OperationCode, foundMethod); break; } } // if operation was not emitted yet => emit it if (operationEmitted == false) { testIlGenerator.Emit(operation.OperationCode, operation.Value); } } break; // just emit operation if none of the above cases match default: testIlGenerator.Emit(operation.OperationCode, operation.Value); break; } } // create new body List <ILocalDefinition> variableListCopy = new List <ILocalDefinition>(method.Body.LocalVariables); List <ITypeDefinition> privateHelperTypesListCopy = new List <ITypeDefinition>(method.Body.PrivateHelperTypes); var newBody = new ILGeneratorMethodBody(testIlGenerator, method.Body.LocalsAreZeroed, method.Body.MaxStack, method, variableListCopy, privateHelperTypesListCopy); method.Body = newBody; } }