Click here to Skip to main content
15,896,118 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 927.2K   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.Generic;
using Mono.Cecil;
#endregion

namespace Reflexil.Compilation
{
    /// <summary>
    /// VisualBasic code generator
    /// </summary>
    internal class VisualBasicHelper : BaseLanguageHelper
    {

        #region " Constants "
        protected const string NEW_LINE = " _";
        protected const string COMMENT = "' ";
        protected const string REGION_START = "#Region ";
        protected const string REGION_END = "#End Region ";
        #endregion

        #region " Fields "
        private Stack<bool> m_displayconstraintsstack = new Stack<bool>();
        #endregion

        #region " Methods "
        /// <summary>
        /// Constructor. Aliases initialisation.
        /// </summary>
        public VisualBasicHelper()
        {
            m_aliases.Add("System.Object", EVisualBasicKeyword.Object.ToString());
            m_aliases.Add("System.Int16", EVisualBasicKeyword.Short.ToString());
            m_aliases.Add("System.Int32", EVisualBasicKeyword.Integer.ToString());
            m_aliases.Add("System.Int64", EVisualBasicKeyword.Long.ToString());
            m_aliases.Add("System.UInt16", EVisualBasicKeyword.UShort.ToString());
            m_aliases.Add("System.UInt32", EVisualBasicKeyword.UInteger.ToString());
            m_aliases.Add("System.UInt64", EVisualBasicKeyword.ULong.ToString());
            m_aliases.Add("System.Boolean", EVisualBasicKeyword.Boolean.ToString());
            m_aliases.Add("System.Char", EVisualBasicKeyword.Char.ToString());
            m_aliases.Add("System.Decimal", EVisualBasicKeyword.Decimal.ToString());
            m_aliases.Add("System.Double", EVisualBasicKeyword.Double.ToString());
            m_aliases.Add("System.Single", EVisualBasicKeyword.Single.ToString());
            m_aliases.Add("System.String", EVisualBasicKeyword.String.ToString());
            m_aliases.Add("[]", "()");

            m_displayconstraintsstack.Push(false);
        }

        /// <summary>
        /// Write the correct method prefix using a method result type
        /// </summary>
        /// <param name="tref">Method result type reference</param>
        private void HandleSubFunction(TypeReference tref)
        {
            if (tref.FullName == typeof(void).FullName)
            {
                Write(EVisualBasicKeyword.Sub);
            }
            else
            {
                Write(EVisualBasicKeyword.Function);
            }
            Write(SPACE);
        }

        #region " BaseLanguageHelper "
        /// <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 override string GenerateSourceCode(MethodDefinition mdef, List<AssemblyNameReference> references)
        {
            string startNs = Surround(EVisualBasicKeyword.Namespace, ESpaceSurrounder.After);
            string endNs = Surround(EVisualBasicKeyword.End, ESpaceSurrounder.After) + startNs;
            return GenerateSourceCode(mdef, references, startNs, String.Empty, endNs);
        }

        /// <summary>
        /// Replace all keyword in a string
        /// </summary>
        /// <param name="str">Input string</param>
        /// <returns>Result string</returns>
        protected override string HandleKeywords(string str)
        {
            foreach (string keyword in System.Enum.GetNames(typeof(EVisualBasicKeyword)))
            {
                if (str.ToLower() == keyword.ToLower())
                {
                    str = LEFT_BRACKET + str + RIGHT_BRACKET;
                }
            }
            return str;
        }
        #endregion
        
        #region " Writers "
        /// <summary>
        /// Write a method signature to the text buffer
        /// </summary>
        /// <param name="mdef">Method definition</param>
        protected override void WriteMethodSignature(MethodDefinition mdef)
        {
            if (IsUnsafe(mdef))
            {
                WriteComment("This method is 'unsafe' and cannot be used in VB.NET");
                Write(COMMENT);
            }
            mdef.Accept(this);
            if (mdef.ReturnType.ReturnType.FullName != typeof(void).FullName)
            {
                Write(EVisualBasicKeyword.As, ESpaceSurrounder.Both);
                VisitTypeReference(mdef.ReturnType.ReturnType);
            }
        }

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

            IdentLevel++;
            WriteLine();
            if (mdef.ReturnType.ReturnType.FullName != typeof(void).FullName)
            {
                if (isunsafe)
                {
                    Write(COMMENT);
                }
                Write(EVisualBasicKeyword.Return, ESpaceSurrounder.After);
                Write(EVisualBasicKeyword.Nothing);
                WriteLine();
            }
            UnIdent();
            IdentLevel--;
            Ident();
            if (isunsafe)
            {
                Write(COMMENT);
            }
            Write(EVisualBasicKeyword.End, ESpaceSurrounder.After);
            HandleSubFunction(mdef.ReturnType.ReturnType);
            WriteLine();
        }

        /// <summary>
        /// Write a field to the text buffer
        /// </summary>
        /// <param name="fdef">Field definition</param>
        protected override void WriteField(FieldDefinition fdef)
        {
            fdef.Accept(this);
        }

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


            if (tdef.GenericParameters.Count > 0)
            {
                Replace(GENERIC_TYPE_TAG + tdef.GenericParameters.Count, String.Empty);
            }
        }

        /// <summary>
        /// Write a comment to the text buffer
        /// </summary>
        /// <param name="comment">Comment</param>
        protected override void WriteComment(string comment)
        {
            Write(COMMENT);
            WriteLine(comment);
        }

        /// <summary>
        /// Write fields stubs to the text buffer
        /// </summary>
        /// <param name="fields">Fields stubs</param>
        protected override void WriteFieldsStubs(FieldDefinitionCollection fields)
        {
            WriteFieldsStubs(fields, REGION_START, REGION_END);
        }

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

        /// <summary>
        /// Write default namespaces to the text buffer
        /// </summary>
        protected override void WriteDefaultNamespaces()
        {
            Write(EVisualBasicKeyword.Option, ESpaceSurrounder.After);
            Write(EVisualBasicKeyword.Explicit, ESpaceSurrounder.After);
            WriteLine(EVisualBasicKeyword.On);
            Write(EVisualBasicKeyword.Option, ESpaceSurrounder.After);
            Write(EVisualBasicKeyword.Strict, ESpaceSurrounder.After);
            WriteLine(EVisualBasicKeyword.On);
            WriteLine();
            Write(REGION_START);
            WriteLine("\" Imports \"");
            foreach (string item in DEFAULT_NAMESPACES)
            {
                Write(EVisualBasicKeyword.Imports, ESpaceSurrounder.After);
                WriteLine(item);
            }
            WriteLine(REGION_END);
        }

        /// <summary>
        /// Write a method's owner type to the text buffer
        /// </summary>
        /// <param name="mdef">Method definition</param>
        protected override void WriteType(MethodDefinition mdef)
        {
            string startClass = Surround(EVisualBasicKeyword.Class, ESpaceSurrounder.After);
            string endClass = Surround(EVisualBasicKeyword.End, ESpaceSurrounder.After) + startClass;
            WriteType(mdef, startClass, String.Empty, endClass);
        }

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

        #region " IReflectionVisitor "
        /// <summary>
        /// Visit a field definition
        /// </summary>
        /// <param name="field">Field definition</param>
        public override void VisitFieldDefinition(FieldDefinition field)
        {
            Write(EVisualBasicKeyword.Dim, ESpaceSurrounder.After);
            if (field.IsStatic)
            {
                Write(EVisualBasicKeyword.Shared, ESpaceSurrounder.After);
            }
            Write(HandleKeywords(field.Name));
            Write(EVisualBasicKeyword.As, ESpaceSurrounder.Both);
            VisitTypeReference(field.FieldType);
        }

        /// <summary>
        /// Visit a method definition
        /// </summary>
        /// <param name="method">Method definition</param>
        public override void VisitMethodDefinition(MethodDefinition method)
        {
            if (method.IsStatic)
            {
                Write(EVisualBasicKeyword.Shared, ESpaceSurrounder.After);
            }
            HandleSubFunction(method.ReturnType.ReturnType);
            if (method.IsConstructor)
            {
                Write(EVisualBasicKeyword.New);
            }
            else
            {
                Write(HandleKeywords(method.Name));
            }
        }

        /// <summary>
        /// Visit a type definition
        /// </summary>
        /// <param name="type">Type definition</param>
        public override void VisitTypeDefinition(TypeDefinition type)
        {
            HandleTypeName(type, type.Name);
        }

        /// <summary>
        /// Visit a type reference
        /// </summary>
        /// <param name="type">Type reference</param>
        public override void VisitTypeReference(TypeReference type)
        {
            string name = type.Name;

            if (type.Name.EndsWith(REFERENCE_TYPE_TAG))
            {
                name = name.Replace(REFERENCE_TYPE_TAG, String.Empty);
            }
            if (type.Namespace != String.Empty)
            {
                name = type.Namespace + NAMESPACE_SEPARATOR + name;
            }
            if (type is GenericInstanceType)
            {
                GenericInstanceType git = type as GenericInstanceType;
                name = name.Replace(GENERIC_TYPE_TAG + git.GenericArguments.Count, String.Empty);
                HandleTypeName(type, name);
                m_displayconstraintsstack.Push(false);
                VisitVisitableCollection(LEFT_PARENTHESIS + Surround(EVisualBasicKeyword.Of, ESpaceSurrounder.After), RIGHT_PARENTHESIS, BASIC_SEPARATOR, false, git.GenericArguments);
                m_displayconstraintsstack.Pop();
            }
            else
            {
                HandleTypeName(type, name);
            }
            if (m_displayconstraintsstack.Peek() && (type is GenericParameter))
            {
                VisitVisitableCollection(Surround(EVisualBasicKeyword.As, ESpaceSurrounder.Both) + LEFT_BRACE, RIGHT_BRACE, BASIC_SEPARATOR, false, (type as GenericParameter).Constraints);
            }
        }

        /// <summary>
        /// Visit a generic parameter collection
        /// </summary>
        /// <param name="genparams">Generic parameter collection</param>
        public override void VisitGenericParameterCollection(GenericParameterCollection genparams)
        {
            m_displayconstraintsstack.Push(true);
            VisitVisitableCollection(LEFT_PARENTHESIS + Surround(EVisualBasicKeyword.Of, ESpaceSurrounder.After), RIGHT_PARENTHESIS, BASIC_SEPARATOR, false, genparams);
            m_displayconstraintsstack.Pop();
        }

        /// <summary>
        /// Visit a parameter definition collection
        /// </summary>
        /// <param name="parameters"></param>
        public override void VisitParameterDefinitionCollection(ParameterDefinitionCollection parameters)
        {
            VisitVisitableCollection(LEFT_PARENTHESIS, RIGHT_PARENTHESIS, BASIC_SEPARATOR, true, parameters);
        }

        /// <summary>
        /// Visit a parameter definition
        /// </summary>
        /// <param name="parameter">Parameter definition</param>
        public override void VisitParameterDefinition(ParameterDefinition parameter)
        {
            if (parameter.ParameterType.Name.EndsWith(REFERENCE_TYPE_TAG))
            {
                Write(EVisualBasicKeyword.ByRef);
            }
            else
            {
                Write(EVisualBasicKeyword.ByVal);
            }
            Write(SPACE);
            Write(HandleKeywords(parameter.Name));
            Write(EVisualBasicKeyword.As, ESpaceSurrounder.Both);
            VisitTypeReference(parameter.ParameterType);
        }
        #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