示例#1
0
        public bool PatchAssembly()
        {
            try
            {
                MessageIntegration.Info("CSCli is searching for calls to replace. Assemblyname: " + _assembly.FullName);

                var module = _assembly.MainModule;
                foreach (var type in module.Types)
                {
                    ProcessType(type);
                }

                MessageIntegration.Info(String.Format("CSCli processed {0} types.", module.Types.Count));
                MessageIntegration.Info(String.Format("CSCli replaced {0} method-calls by Calli-instruction.", _replacedCallsCount));
                MessageIntegration.Info(String.Format("Cleaning up assembly. {0} types to remove from assembly.", _typesToRemove.Count));

                foreach (var typeToRemove in _typesToRemove)
                {
                    module.Types.Remove(typeToRemove);
                }
            }
            catch (Exception ex)
            {
                MessageIntegration.WriteError("Unknown error: " + ex.ToString());
                return(false);
            }

            return(true);
        }
示例#2
0
        private void ProcessMethod(MethodDefinition method)
        {
            if (method.HasBody)
            {
                ILProcessor ilProcessor = method.Body.GetILProcessor();

                //process every instruction of the methods body
                for (int n = 0; n < ilProcessor.Body.Instructions.Count; n++) //foreach won't work because iterator length is bigger than count??
                {
                    var instruction = ilProcessor.Body.Instructions[n];

                    //check whether the instruction is a call to a method
                    if (instruction.OpCode.Code == Code.Call && instruction.Operand is MethodReference)
                    {
                        //get the called method
                        MethodReference methodDescription = (MethodReference)instruction.Operand;
                        //get the attributes of the called method
                        var attributes = GetAttributes(methodDescription.Resolve());

                        //check whether the called method is marked with the given calli attribute
                        if (attributes.Contains(_calliAttributeName))
                        {
                            MessageIntegration.Info("Patching [{0}] @ [{1}].", method.ToString(), instruction.ToString());
                            if (!method.Name.EndsWith("Native"))
                            {
                                MessageIntegration.Info(String.Format("CallI-Comimport Methodnames should end with a \"Native\". Method: \"{0}\".", method.FullName));
                            }

                            //create a callsite for the calli instruction using stdcall calling convention
                            var callSite = new CallSite(methodDescription.ReturnType)
                            {
                                CallingConvention = MethodCallingConvention.StdCall
                            };

                            //iterate through every parameter of the original method-call
                            for (int j = 0; j < methodDescription.Parameters.Count - 1; j++) //foreach won't work because iterator length is bigger than count??
                            {
                                var p = methodDescription.Parameters[j];
                                if (p.ParameterType.FullName == "System.Boolean")
                                {
                                    MessageIntegration.WriteWarning("Native bool has a size of 4 bytes. Make sure to use a 16bit Integer for \"VARIANT_BOOL\" and a 32bit Integer for \"BOOL\".", "CI0001");
                                }

                                //append every parameter of the method-call to the callsite of the calli instruction
                                callSite.Parameters.Add(p);
                            }

                            //create a calli-instruction including the just built callSite
                            var calliInstruction = ilProcessor.Create(OpCodes.Calli, callSite);
                            //replace the method-call by the calli-instruction
                            ilProcessor.Replace(instruction, calliInstruction);

                            _replacedCallsCount++;
                        }
                    }
                }
            }
        }
示例#3
0
        private static void Main(string[] args)
        {
            string calliAttributeName      = "CalliAttribute";
            string removeTypeAttributeName = "RemoveTypeAttribute";
            string filename = null;
            string pdbfile  = null;

            MessageIntegration.Info("CSCli started.");
            MessageIntegration.Info("CSCli was copied from http://www.codeproject.com/Articles/644130/NET-COM-Interop-using-Postbuild.");
            MessageIntegration.Info(String.Empty); //new line

            MessageIntegration.Info(String.Format("CSCli-Argments: [{0}].", String.Concat(args.Select(x => x + " ")).Trim()));

            /*
             * Parse parameters
             */
            foreach (var a in args)
            {
                if (a.StartsWith("-file:"))
                {
                    filename = a.Substring("-file:".Length);
                    MessageIntegration.Info("Filename: " + filename);
                }
                else if (a.StartsWith("-c:"))
                {
                    calliAttributeName = a.Substring("-c:".Length);
                }
                else if (a.StartsWith("-r:"))
                {
                    removeTypeAttributeName = a.Substring("-r:".Length);
                }
                else if (a.StartsWith("-pdb:"))
                {
                    pdbfile = a.Substring("-pdb:".Length);
                }
                else
                {
                    MessageIntegration.WriteWarning(String.Format("Unknown parameter: \"{0}\".", a));
                }
            }

            /*
             * Load and process assembly
             */
            if (!File.Exists(filename))
            {
                MessageIntegration.WriteError(String.Format("Could not find file \"{0}\".", filename));
                Environment.Exit(-1);
            }

            WriterParameters wp = new WriterParameters();
            ReaderParameters rp = new ReaderParameters();

            var strongNameKey = Path.ChangeExtension(filename, "snk");

            if (File.Exists(strongNameKey))
            {
                MessageIntegration.Info("Signing with Key : " + strongNameKey);
                wp.StrongNameKeyPair = new StrongNameKeyPair(File.OpenRead(strongNameKey));
            }

            //check whether the pdbfile has been passed through application parameters
            if (pdbfile == null)
            {
                //if not use the default pdbfilepath by changing the extension of the assembly to .pdb
                pdbfile = Path.ChangeExtension(filename, "pdb");
            }

            //check whether the original pdb-file exists
            bool generatePdb = File.Exists(pdbfile);

            //if the original pdb-file exists -> prepare for rewriting the symbols file
            wp.WriteSymbols = generatePdb;
            rp.ReadSymbols  = generatePdb;

            if (rp.ReadSymbols)
            {
                rp.SymbolReaderProvider = new PdbReaderProvider();
            }

            MessageIntegration.Info("Generating pdb: " + generatePdb.ToString());

            //open assembly
            var assembly = AssemblyDefinition.ReadAssembly(filename, rp);

            //add the directory assembly directory as search directory to resolve referenced assemblies
            ((BaseAssemblyResolver)assembly.MainModule.AssemblyResolver).AddSearchDirectory(Path.GetDirectoryName(filename));

            //path the assembly
            AssemblyPatcher patcher = new AssemblyPatcher(assembly, calliAttributeName, removeTypeAttributeName);

            if (patcher.PatchAssembly())
            {
                try
                {
                    //if the assembly was patched successfully -> replace the old assembly file with the new, patched assembly file
                    //the symbols file will be created automatically
                    File.Delete(filename);
                    assembly.Write(filename, wp);
                }
                catch (Exception ex)
                {
                    MessageIntegration.WriteError("Creating new assembly failed: " + ex.ToString());
                    Environment.Exit(-1);
                }

                MessageIntegration.Info(String.Format("CSCli patched assembly \"{0}\" successfully.", Path.GetFileName(filename)));
                Environment.Exit(0);
            }
            else
            {
                MessageIntegration.WriteError(String.Format("\"{0}\" could not be patched.", filename));
                Environment.Exit(-1);
            }
        }