Click here to Skip to main content
15,892,059 members
Articles / Programming Languages / MSIL

Assembly Manipulation and C# / VB.NET Code Injection

Rate me:
Please Sign up or sign in to vote.
4.95/5 (200 votes)
26 Apr 2013MIT5 min read 925.9K   25K   486  
Reflexil is an assembly editor and runs as a plug-in for Reflector or JustDecompile. Reflexil is able to manipulate IL code and save the modified assemblies to disk. Reflexil also supports "on-the-fly" C#/VB.NET code injection.
/*
    Reflexil .NET assembly editor.
    Copyright (C) 2007 Sebastien LEBRETON

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#region " Imports "
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Mono.Cecil;
#endregion

namespace Reflexil.Compilation
{
    /// <summary>
    /// Base class for code generation
    /// </summary>
    internal abstract class BaseLanguageHelper : IReflectionVisitor, ILanguageHelper
    {

        #region " Constants "
        protected const string BASIC_SEPARATOR = ", ";
        protected const string GENERIC_TYPE_TAG = "`";
        protected const string LEFT_PARENTHESIS = "(";
        protected const string RIGHT_PARENTHESIS = ")";
        protected const string LEFT_BRACE = "{";
        protected const string RIGHT_BRACE = "}";
        protected const string LEFT_CHEVRON = "<";
        protected const string RIGHT_CHEVRON = ">";
        protected const string LEFT_BRACKET = "[";
        protected const string RIGHT_BRACKET = "]";
        protected const string REFERENCE_TYPE_TAG = "&";
        protected const string NAMESPACE_SEPARATOR = ".";
        protected const string SPACE = " ";
        protected const string QUOTE = "\"";
        protected string[] DEFAULT_NAMESPACES = { "System", "System.Collections.Generic", "System.Text" };
        #endregion

        #region " Fields "
        private StringBuilder m_identedbuilder = new StringBuilder();
        private int m_identlevel = 0;
        protected Dictionary<string, string> m_aliases = new Dictionary<string, string>();
        protected bool m_fullnamespaces = true;
        #endregion

        #region " Properties "
        protected int IdentLevel
        {
            get
            {
                return m_identlevel;
            }
            set
            {
                m_identlevel = value;
            }
        }
        #endregion

        #region " Methods "

        #region " Abstract "
        /// <summary>
        /// Write a method signature to the text buffer
        /// </summary>
        /// <param name="mdef">Method definition</param>
        protected abstract void WriteMethodSignature(MethodDefinition mdef);

        /// <summary>
        /// Write a method body to the text buffer
        /// </summary>
        /// <param name="mdef">Method definition</param>
        protected abstract void WriteMethodBody(MethodDefinition mdef);

        /// <summary>
        /// Write a type signature to the text buffer
        /// </summary>
        /// <param name="tdef">Type definition</param>
        protected abstract void WriteTypeSignature(TypeDefinition tdef);

        /// <summary>
        /// Write a field to the text buffer
        /// </summary>
        /// <param name="fdef">Field definition</param>
        protected abstract void WriteField(FieldDefinition fdef);

        /// <summary>
        /// Write a comment to the text buffer
        /// </summary>
        /// <param name="comment">Comment</param>
        protected abstract void WriteComment(string comment);

        /// <summary>
        /// Write fields stubs to the text buffer
        /// </summary>
        /// <param name="fields">Fields stubs</param>
        protected abstract void WriteFieldsStubs(FieldDefinitionCollection fields);

        /// <summary>
        /// Write methods stubs to the text buffer
        /// </summary>
        /// <param name="mdef">Method definition to exclude</param>
        /// <param name="methods">Methods definitions</param>
        protected abstract void WriteMethodsStubs(MethodDefinition mdef, MethodDefinitionCollection methods);

        /// <summary>
        /// Write default namespaces to the text buffer
        /// </summary>
        protected abstract void WriteDefaultNamespaces();

        /// <summary>
        /// Write a method's owner type to the text buffer
        /// </summary>
        /// <param name="mdef">Method definition</param>
        protected abstract void WriteType(MethodDefinition mdef);

        /// <summary>
        /// Write referenced assemblies to the text buffer (as a comment)
        /// </summary>
        /// <param name="references">Assembly references</param>
        protected abstract void WriteReferencedAssemblies(List<AssemblyNameReference> references);
        #endregion

        #region " IReflectionVisitor "
        /// <summary>
        /// Visit a type definition
        /// </summary>
        /// <param name="type">Type definition</param>
        public abstract void VisitTypeDefinition(TypeDefinition type);

        /// <summary>
        /// Visit a field definition
        /// </summary>
        /// <param name="field">Field definition</param>
        public abstract void VisitFieldDefinition(FieldDefinition field);

        /// <summary>
        /// Visit a method definition
        /// </summary>
        /// <param name="method">Method definition</param>
        public abstract void VisitMethodDefinition(MethodDefinition method);

        /// <summary>
        /// Visit a type reference
        /// </summary>
        /// <param name="type">Type reference</param>
        public abstract void VisitTypeReference(TypeReference type);

        /// <summary>
        /// Visit a generic parameter collection
        /// </summary>
        /// <param name="genparams">Generic parameter collection</param>
        public abstract void VisitGenericParameterCollection(GenericParameterCollection genparams);

        /// <summary>
        /// Visit a parameter definition
        /// </summary>
        /// <param name="parameter">Parameter definition</param>
        public abstract void VisitParameterDefinition(ParameterDefinition parameter);

        /// <summary>
        /// Visit a parameter definition collection
        /// </summary>
        /// <param name="parameters"></param>
        public abstract void VisitParameterDefinitionCollection(ParameterDefinitionCollection parameters);
        #endregion

        #region " Not Implemented "
        public virtual void VisitCustomAttributeCollection(CustomAttributeCollection customAttrs) { }
        public virtual void VisitSecurityDeclaration(SecurityDeclaration secDecl) { }
        public virtual void VisitCustomAttribute(CustomAttribute customAttr) { }
        public virtual void VisitSecurityDeclarationCollection(SecurityDeclarationCollection secDecls) { }
        public virtual void VisitOverride(MethodReference ov) { }
        public virtual void VisitOverrideCollection(OverrideCollection meth) { }
        public virtual void VisitGenericParameter(GenericParameter genparam) { }
        public virtual void VisitConstructorCollection(ConstructorCollection ctors) { }
        public virtual void VisitEventDefinitionCollection(EventDefinitionCollection events) { }
        public virtual void VisitFieldDefinitionCollection(FieldDefinitionCollection fields) { }
        public virtual void VisitMethodDefinitionCollection(MethodDefinitionCollection methods) { }
        public virtual void VisitNestedTypeCollection(NestedTypeCollection nestedTypes) { }
        public virtual void VisitPropertyDefinitionCollection(PropertyDefinitionCollection properties) { }
        public virtual void VisitTypeDefinitionCollection(TypeDefinitionCollection types) { }
        public virtual void VisitEventDefinition(EventDefinition evt) { }
        public virtual void VisitModuleDefinition(ModuleDefinition @module) { }
        public virtual void VisitNestedType(TypeDefinition nestedType) { }
        public virtual void VisitPropertyDefinition(PropertyDefinition @property) { }
        public virtual void VisitConstructor(MethodDefinition ctor) { }
        public virtual void TerminateModuleDefinition(ModuleDefinition @module) { }
        public virtual void VisitExternType(TypeReference externType) { }
        public virtual void VisitExternTypeCollection(ExternTypeCollection externs) { }
        public virtual void VisitInterface(TypeReference interf) { }
        public virtual void VisitInterfaceCollection(InterfaceCollection interfaces) { }
        public virtual void VisitMemberReference(MemberReference member) { }
        public virtual void VisitMemberReferenceCollection(MemberReferenceCollection members) { }
        public virtual void VisitMarshalSpec(MarshalSpec marshalSpec) { }
        public virtual void VisitTypeReferenceCollection(TypeReferenceCollection refs) { }
        public virtual void VisitPInvokeInfo(PInvokeInfo pinvk) { }
        #endregion

        #region " Text generation "
        /// <summary>
        /// Change ident level and apply modifications to the text buffer
        /// </summary>
        /// <param name="newidentlevel">Ident level</param>
        protected void ReIdent(int newidentlevel)
        {
            UnIdent();
            IdentLevel = newidentlevel;
            Ident();
        }

        /// <summary>
        /// Pre-ident the text buffer
        /// </summary>
        protected void Ident()
        {
            for (int i = 0; i < IdentLevel; i++)
            {
                m_identedbuilder.Append("\t");
            }
        }

        /// <summary>
        /// Unident the pre-idented text buffer
        /// </summary>
        protected void UnIdent()
        {
            for (int i = 0; i < IdentLevel; i++)
            {
                if ((m_identedbuilder.Length > 0) && (m_identedbuilder[m_identedbuilder.Length - 1] == '\t'))
                {
                    m_identedbuilder.Remove(m_identedbuilder.Length - 1, 1);
                }
            }
        }

        /// <summary>
        /// Replace text in the text buffer
        /// </summary>
        /// <param name="oldvalue">string to replace</param>
        /// <param name="newvalue">replacement string</param>
        protected void Replace(string oldvalue, string newvalue)
        {
            m_identedbuilder.Replace(oldvalue, newvalue);
        }

        /// <summary>
        /// Write a new line to the text buffer
        /// </summary>
        protected void WriteLine()
        {
            m_identedbuilder.AppendLine();
            Ident();
        }

        /// <summary>
        /// Write a string and a new line to the text buffer
        /// </summary>
        /// <param name="str">the string to write</param>
        protected void WriteLine(string str)
        {
            Write(str);
            WriteLine();
        }

        /// <summary>
        /// Write a string to the text buffer
        /// </summary>
        /// <param name="str">the string to write</param>
        protected void Write(string str)
        {
            m_identedbuilder.Append(str);
        }

        /// <summary>
        /// Write an item to the text buffer (space surrounding)
        /// </summary>
        /// <param name="item">the item to write</param>
        /// <param name="mode">space surrounding mode</param>
        protected void Write(System.Enum item, ESpaceSurrounder mode)
        {
            m_identedbuilder.Append(Surround(item, mode));
        }

        /// <summary>
        /// Write an enum
        /// </summary>
        /// <param name="item">Item to write</param>
        protected void Write(System.Enum item)
        {
            Write(item.ToString());
        }

        /// <summary>
        /// Write an enum
        /// </summary>
        /// <param name="item">Item to write</param>
        protected void WriteLine(System.Enum item)
        {
            WriteLine(item.ToString());
        }
     
        /// <summary>
        /// Reset the text buffer 
        /// </summary>
        protected void Reset()
        {
            m_identlevel = 0;
            m_identedbuilder.Length = 0;
        }

        /// <summary>
        /// Get the text buffer
        /// </summary>
        /// <returns></returns>
        protected string GetResult()
        {
            return m_identedbuilder.ToString();
        }
        #endregion

        #region " ILanguageHelper "
        /// <summary>
        /// Generate method signature 
        /// </summary>
        /// <param name="mdef">Method definition</param>
        /// <returns>generated source code</returns>
        public virtual string GetMethodSignature(MethodDefinition mdef)
        {
            Reset();
            WriteMethodSignature(mdef);
            return GetResult();
        }

        /// <summary>
        /// Generate method
        /// </summary>
        /// <param name="mdef">Method definition</param>
        /// <returns>generated source code</returns>
        public virtual string GetMethod(MethodDefinition mdef)
        {
            Reset();
            WriteMethodSignature(mdef);
            WriteMethodBody(mdef);
            return GetResult();
        }

        /// <summary>
        /// Generate field
        /// </summary>
        /// <param name="fdef">Field definition</param>
        /// <returns>generated source code</returns>
        public virtual string GetField(FieldDefinition fdef)
        {
            Reset();
            WriteField(fdef);
            return GetResult();
        }

        /// <summary>
        /// Generate type signature
        /// </summary>
        /// <param name="tdef">Type definition</param>
        /// <returns>generated source code</returns>
        public virtual string GetTypeSignature(TypeDefinition tdef)
        {
            Reset();
            WriteTypeSignature(tdef);
            return GetResult();
        }

        /// <summary>
        /// Generate source code from method declaring type. All others
        /// methods are generated as stubs.
        /// </summary>
        /// <param name="mdef">Method definition</param>
        /// <param name="references">Assembly references</param>
        /// <returns>generated source code</returns>
        public abstract string GenerateSourceCode(MethodDefinition mdef, List<AssemblyNameReference> references);
        #endregion

        #region " Writers "
        /// <summary>
        /// Write methods stubs to the text buffer
        /// </summary>
        /// <param name="mdef">Method definition to exclude</param>
        /// <param name="methods">Methods definitions</param>
        /// <param name="rskw">Region start keyword</param>
        /// <param name="rekw">Region end keyword</param>
        protected void WriteMethodsStubs(MethodDefinition mdef, MethodDefinitionCollection methods, string rskw, string rekw)
        {
            Write(rskw);
            WriteLine("\" Methods stubs \"");
            WriteComment("Do not add or update any method. If compilation fails because of a method declaration, comment it");
            foreach (MethodDefinition smdef in methods)
            {
                if (mdef != smdef)
                {
                    WriteMethodSignature(smdef);
                    WriteMethodBody(smdef);
                    WriteLine();
                }
            }
            WriteLine(rekw);
        }

        /// <summary>
        /// Write fields stubs to the text buffer
        /// </summary>
        /// <param name="fields">Fields stubs</param>
        /// <param name="rskw">Region start keyword</param>
        /// <param name="rekw">Region end keyword</param>
        protected void WriteFieldsStubs(FieldDefinitionCollection fields, string rskw, string rekw)
        {
            Write(rskw);
            WriteLine("\" Fields stubs \"");
            WriteComment("Do not add or update any field. If compilation fails because of a field declaration, comment it");
            foreach (FieldDefinition fdef in fields)
            {
                WriteField(fdef);
                WriteLine();
            }
            WriteLine(rekw);
        }

        /// <summary>
        /// Write referenced assemblies to the text buffer (as a comment)
        /// </summary>
        /// <param name="references">Assembly references</param>
        /// <param name="rskw">Region start keyword</param>
        /// <param name="rekw">Region end keyword</param>
        protected void WriteReferencedAssemblies(List<AssemblyNameReference> references, string rskw, string rekw)
        {
            Write(rskw);
            WriteLine("\" Referenced assemblies \"");
            foreach (AssemblyNameReference asmref in references)
            {
                WriteComment(String.Format("- {0} v{1}", asmref.Name, asmref.Version));
            }
            WriteLine(rekw);
        }
        
        /// <summary>
        /// Write a method's owner type to the text buffer
        /// </summary>
        /// <param name="mdef">Method definition</param>
        /// <param name="tkw">Type keyword</param>
        /// <param name="tskw">Type start keyword</param>
        /// <param name="tekw">Type end keywork</param>
        protected void WriteType(MethodDefinition mdef, string tkw, string tskw, string tekw)
        {
            Write(tkw);
            WriteTypeSignature(mdef.DeclaringType as TypeDefinition);
            WriteLine();
            IdentLevel++;
            WriteLine(tskw);

            WriteComment("Limited support!");
            WriteComment("You can only reference methods or fields defined in the class (not in ancestors classes)");
            WriteComment("Fields and methods stubs are needed for compilation purposes only.");
            WriteComment("Reflexil will automaticaly map current type, fields or methods to original references.");
            WriteMethodSignature(mdef);
            WriteMethodBody(mdef);

            WriteLine();
            WriteMethodsStubs(mdef, (mdef.DeclaringType as TypeDefinition).Methods);

            WriteLine();
            WriteFieldsStubs((mdef.DeclaringType as TypeDefinition).Fields);

            ReIdent(IdentLevel - 1);
            WriteLine();
            WriteLine(tekw);
        }
        #endregion

        #region " Helpers "
        /// <summary>
        /// Replace all aliases in a string
        /// </summary>
        /// <param name="str">Input string</param>
        /// <returns>Result string</returns>
        protected string HandleAliases(string str)
        {
            foreach (string alias in m_aliases.Keys)
            {
                str = str.Replace(alias, m_aliases[alias]);
            }
            return str;
        }

        /// <summary>
        /// Replace all keyword in a string
        /// </summary>
        /// <param name="str">Input string</param>
        /// <returns>Result string</returns>
        protected abstract string HandleKeywords(string str);

        /// <summary>
        /// Write a name to the text buffer. Handles aliases and namespaces.
        /// </summary>
        /// <param name="type">Type reference for namespace</param>
        /// <param name="name">The name to write</param>
        protected void HandleTypeName(TypeReference type, string name)
        {
            name = HandleAliases(name);

            if (!m_fullnamespaces)
            {
                name = name.Replace(type.Namespace + NAMESPACE_SEPARATOR, String.Empty);
            }

            Write(name);
        }

        /// <summary>
        /// Visit a collection which contains IReflectionVisitable items, and write it to the text buffer.
        /// </summary>
        /// <param name="start">Collection start keyword</param>
        /// <param name="end">Collection end keyword</param>
        /// <param name="separator">Collection separator</param>
        /// <param name="always">If true write 'collection end keyword' even if collection is empty</param>
        /// <param name="collection">Collection to visit</param>
        protected virtual void VisitVisitableCollection(string start, string end, string separator, bool always, ICollection collection)
        {
            if (always | collection.Count > 0)
            {
                Write(start);
            }

            bool firstloop = true;
            foreach (IReflectionVisitable item in collection)
            {
                if (!firstloop)
                {
                    Write(separator);
                }
                else
                {
                    firstloop = false;
                }
                if (item is TypeDefinition)
                {
                    VisitTypeReference(item as TypeDefinition);
                }
                else
                {
                    item.Accept(this);
                }
            }

            if (always | collection.Count > 0)
            {
                Write(end);
            }
        }

        /// <summary>
        /// Generate source code from method declaring type. All others
        /// methods are generated as stubs.
        /// </summary>
        /// <param name="mdef">Method definition</param>
        /// <param name="references">Assembly references</param>
        /// <param name="nkw">Namespace keyword</param>
        /// <param name="nskw">Namespace start keyword</param>
        /// <param name="nekw">Namespace end keyword</param>
        /// <returns>generated source code</returns>
        protected string GenerateSourceCode(MethodDefinition mdef, List<AssemblyNameReference> references, string nkw, string nskw, string nekw)
        {
            Reset();

            WriteDefaultNamespaces(); WriteLine();
            WriteReferencedAssemblies(references); WriteLine();

            if (mdef.DeclaringType.Namespace != string.Empty)
            {
                Write(nkw);
                WriteLine(mdef.DeclaringType.Namespace);
                IdentLevel++;
                WriteLine(nskw);
            }

            WriteType(mdef);

            if (mdef.DeclaringType.Namespace != string.Empty)
            {
                ReIdent(IdentLevel - 1);
                WriteLine(nekw);
            }

            return GetResult();
        }

        protected string Surround(System.Enum item, ESpaceSurrounder mode)
        {
            string result = item.ToString();
            if (mode != ESpaceSurrounder.After)
            {
                result = SPACE + result;
            }
            if (mode != ESpaceSurrounder.Before)
            {
                result = result + SPACE;
            }
            return result;
        }

        protected bool IsUnsafe(TypeReference source)
        {
            if (source is PointerType)
            {
                return true;
            }
            if (source is TypeSpecification)
            {
                return IsUnsafe((source as TypeSpecification).ElementType);
            }
            return false;
        }

        protected bool IsUnsafe(MethodDefinition source)
        {
            if (IsUnsafe(source.ReturnType.ReturnType))
            {
                return true;
            }
            foreach (ParameterDefinition param in source.Parameters)
            {
                if (IsUnsafe(param.ParameterType))
                {
                    return true;
                }
            }
            return false;
        }
        #endregion

        #endregion

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer (Senior) Microsoft
United States United States
Sebastien Lebreton is a Software Engineer at Microsoft.

He is particularly interested in optimization, reverse engineering and distributed objects technologies.

Comments and Discussions