Protéger mes données de configuration dans une dll compilée

Dans ce petit exemple, je vais travailler la réflexion et la configuration sous c#, pour préparer une dll qui peut être utilisé comme une dll de configuration à partir d’un fichier de configuration afin de protéger la configuration.

  • Le besoin

Le besoin est de trouver une solution pour protéger la configuration.
On veut que la configuration se fait par l’administrateur de l’application (après l’installation) et de la protéger pour ne pas être changer par d’autres utilisateurs.

La solution est :

  • l’administrateur peux changer le fichier de configuration
  • l’application compile une dll qui contient les données de configuration et qui va être chargé et utilisé par l’application.
  • L’administrateur peut aussi redémarrer la configuration s’il change la configuration.
  • La récupération des données

la récupération des données est simple, mais pourquoi ne pas avoir la possibilité de recharger le fichier « app.config » en cas de besoin :

je peux utiliser l’objet configurationManger pour le faire:

CC.Nom= System.Configuration.ConfigurationManager.AppSettings["Nom"];
CC.Prenom = System.Configuration.ConfigurationManager.AppSettings["Prenom"];

Mais je préfère considérer mon “app.config” comme un fichier de configuration externe afin de pouvoir le recharger en cas de besoin sans redémarrer mon application :

ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = string.Format("{0}.{1}.{2}",FileConfigName,"exe", "config");
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configMap,ConfigurationUserLevel.None);
ClassConfig CC = new ClassConfig();
System.Configuration.ConfigurationManager.RefreshSection("AppSettings");
CC.Nom= config.AppSettings.Settings["Nom"].Value;
CC.Prenom = config.AppSettings.Settings["Prenom"].Value;
  • La compilation

Dans cette partie :

– les données de configuration sont dans l’objet CC (de type ClassConfig ) qui est définie comme :

public class ClassConfig
    {
        string _Nom = "Nom";
        public string Nom
        {
            get { return _Nom; }
            set { _Nom = value; }
        }
        string _Prenom = "Prenom";
        public string Prenom
        {
            get { return _Prenom; }
            set { _Prenom = value; }
        }
        public override string ToString()
        {
            //string _usings = "using System;using System.Collections.Generic;using System.Text; \n";
            string _className = this.GetType().Name;
            string _nameSpace = this.GetType().Namespace;
            string _Params = "";
            foreach (System.Reflection.PropertyInfo h in this.GetType().GetProperties())
            {
                _Params += "\t private " + h.PropertyType.Name + " " + "_" + h.Name;
                if (Type.GetTypeCode(h.PropertyType) == TypeCode.String)
                    _Params += "= \"" + h.GetValue(this, null).ToString() + "\"; \n";
                else
                    _Params += "= " + h.GetValue(this, null).ToString() + "; \n";
                _Params += " \t public " + h.PropertyType.Name + " " + h.Name + "\n" + "\t { \n\t\t get { return " + "_" + h.Name + "; }\n\t\t set {"+ "_" + h.Name + " = value; }\n \t}\n";
            }
            string codesource = /*_usings + */" namespace " + _nameSpace + "{ \n";
            codesource += " public class " + _className + " { \n";
            codesource += _Params;
            codesource += "}}";
            return codesource;
        }

    }

Qui représente mes données de configuration :

config

C’est pourquoi on a deux propriétés Nom et Prenom dans la définition de ma classe.

  • la récupération du code source de ma classe

J’ai redéfini la fonction Tostring pour avoir la définition de ma classe en code csharp pour que je puisque le compiler par la suite.

L’idée n’est claire, je m’explique .

exemple :

Pour les valeurs de mes données de configurations (Nom=azstar;Prenom=abdo) la fonction va me générer un classe de définition:

namespace ClassConfig
{

public class ClassConfig
    {
        string _Nom = "azstar";
        public string Nom
        {
            get { return _Nom; }
            set { _Nom = value; }
        }
        string _Prenom = "abdo";
        public string Prenom
        {
            get { return _Prenom; }
            set { _Prenom = value; }
        }
     }
}

La fonction ToString va me générer le code source de la classe avec mes données de configuration dedans (je me limite aux propriétés ).

Au premier temps je récupère le nom de la classe et le Namespace

string _className = this.GetType().Name;
string _nameSpace = this.GetType().Namespace;

Pour faire :

string codesource = /*_usings + */" namespace " + _nameSpace + "{ \n";
codesource += " public class " + _className + " { \n";

Donc jusque-là je doit avoir :

namespace ClassConfig
{
    public class ClassConfig    {

Ensuite je me lance à récupérer les propriétés

foreach (System.Reflection.PropertyInfo h in this.GetType().GetProperties())
{}

pour chaque propriété je vais avoir un code semblable à ça :

string _Nom = "azstar";//la valeur de la propriété
 public string Nom
{
 get { return _Nom; }
   set { _Nom = value; }
 }

Et finalement je vais avoir le code total de ma classe.Je ne sais pas est ce qu’ il existe une fonction qui génère le code facilement dans framework? mais je n’ai pas cherché!.

Donc à ce stade on a le code source de ma classe avec les valeurs des données de configuration (ToString est appelé depuis mon objet CC qui contient mes données de configuration).

  • la compilation de code source

Pour cette partie je n’ai que utilisé un code que j’ai trouvé dans msdn pour compiler mon code source :

public static bool CompileDLL(String source, string AssemblyName,out string message)
        {
            message = "";
         
            CodeDomProvider provider = null;
            bool compileOk = false;
            provider = new Microsoft.CSharp.CSharpCodeProvider();
            if (provider != null)
            {
                // Format the DLL file name.
                String DLLName = String.Format(@"{0}.dll",AssemblyName);
                CompilerParameters cp = new CompilerParameters();
                // Generate an DLL
                cp.GenerateExecutable = false;
                // Specify the assembly file name to generate.
                cp.OutputAssembly = DLLName;
                // Save the assembly as a physical file.
                cp.GenerateInMemory = false;
                // Set whether to treat all warnings as errors.
                cp.TreatWarningsAsErrors = false;
                CompilerResults cr = provider.CompileAssemblyFromSource(cp, source);
                if (cr.Errors.Count > 0)
                {
                    // Display compilation errors.
                    message = string.Format("Errors building {0} into {1}", AssemblyName, cr.PathToAssembly);
                    // Console.WriteLine("Errors building {0} into {1}", sourceName, cr.PathToAssembly);
                    foreach (CompilerError ce in cr.Errors)
                    {
                        /*Console.WriteLine("  {0}", ce.ToString());
                        Console.WriteLine();*/

                        message += string.Format(" {0}", ce.ToString()) + "\n";
                    }
                }
                else
                {
                    // Display a successful compilation message.
                    // Console.WriteLine("Source {0} built into {1} successfully.",  sourceName, cr.PathToAssembly);
                    message += string.Format("Source {0} built into {1} successfully.", AssemblyName, cr.PathToAssembly);
                }
                // Return the results of the compilation.
                if (cr.Errors.Count > 0)
                {
                    compileOk = false;
                }
                else
                {
                    compileOk = true;
                }
            }
            return compileOk;
        }

Ce code me générer une DLL ( cp.GenerateExecutable = false;) que je vais l’utiliser dans mon application comme source de configuration.

Enfin j’ai une dll qui contient la définition de ma classe et qui contient les valeurs de mes données de configuration. l’étape suivante c’est de charger mes données dans l’application.

  • La Chargement de la dll et la récupération des données de la configuration.

Pour charger ma dll automatiquement je dois passer par un assembly et faire :

byte[] bytes = System.IO.File.ReadAllBytes("ClassConfig2.Dll");
Assembly a = Assembly.Load(bytes);
// Get the type to use.
Type myType = a.GetType("ClassConfig.ClassConfig");
 // Create an instance.
object obj = Activator.CreateInstance(myType);

Avec GetType je peux récupérer le type de ma classe qui est définie automatiquement par un code source généré.

 Type myType = a.GetType("ClassConfig");

Par la suite je peux instancier un objet de ma classe sans passer par le constructeur avec

  object obj = Activator.CreateInstance(myType);

Et avoir un objet qui contient mes données de configuration.

Le type de ma classe n’est pas reconnu dans l’application donc il faut passer par une classe qui a la même structure que mon objet que je l’ai nommé aussi ClassConfig.

ClassConfig config = newClassConfig();

J’ai créé une fonction pour parcourir mon obj pour le copier dans mon objet config

private static object CopieObjectInobject(object obj1, object obj2)
        {
            foreach (System.Reflection.PropertyInfo obj1h in obj1.GetType().GetProperties())
            {
                foreach (System.Reflection.PropertyInfo obj2h in obj2.GetType().GetProperties())
                {
                    if (obj1h.Name == obj2h.Name)
                    {
                        obj1h.SetValue(obj1, obj2h.GetValue(obj2, null), null);
                        break;
                    }
                }
            }
            return obj1;
        }

NB: Pour récupérer mes données depuis mon objet obj , je peux aussi les stocker dans un dictionnary.
Il pourra y’ avoir plusieurs méthodes pour faire ça sans passer par une classe !!.

Enfin j’ai un objet reconnu dans mon application et qui contient toutes mes données de configuration. Je peux si besoin de recharger mon “app.config”(un autre fichier text ,xml ou un autre source) dans ma classe et avoir la dll qui contient les données et je peux aussi protéger cette fonctionnalité, pour qu elle soit utiliser seulement par l’administrateur de mon application; ou bien faire plus , générer la dll lors de l’installation de l’application.

Finalement,même si que les données sont à l’intérieur de la dll ; je ne peux pas dire qu’ ils sont sécurisés car je peux par un simple réflecteur, désassembler la dll et avoir les données même si elles sont obfusquées.

Voir le code source

Laisser un commentaire