Cacher le nom des fonctions dans exécutable
Bonjour,
j'ai une question au sujet de l'édition de fichier exécutables compilés. Comme vous devez le savoir, il est possible avec des éditeurs hexadécimaux (Strings, voire des outils d'édition de texte actuels comme Notepad++) d' "ouvrir" un programme/fichier exécutable et d'y "lire" des informations de type ASCII (string fixes, messages, noms de fonctions définies dans l'exe). Justement ma question porte sur le nom des fonctions que l'on peut ainsi lire: est-il possible de les masquer/cacher? Vous comprendrez que rien que le nom des fonctions peut renseigner un probable lecteur sur le comportement global d'un programme ou sur une implémentation particulière (en vrac: protocole de transfert utilisé, technique de chiffrage, fonction mathématique implémentée...), chose que je souhaite éviter idéalement.
Je sais que la façon la plus simple consiste à -avant compilation- renommer les fonctions (déclaration et définition) et ainsi de générer un exe plus "obscur" au lecteur potentiel ("LireMotdePasse" deviendrait "LMDP" ou "titi" mais le comportement serait identique), mais je veux éviter ceci pour des raisons de maintenance et de lisibilité du code. Peut-être qu'un traitement de texte particulier avant compilation ou l'utilisation de macros (préprocesseur) pourrait résoudre l'affaire...
Donc, j'attends vos suggestions sur cette affaire et vous remercie à l'avance.
@ailonn, PIC16F877A, olivieram, Yobi's
@ailonn et PIC16F877A: prenons le code d'un petit exécutable
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <stdio.h>
int Fonction_A_Cacher(int);
int main()
{
int i=0;
printf("%d\n", Fonction_A_Cacher(i));
return 0;
}
int Fonction_A_Cacher(int input)
{
printf("salut!\n");
return ++input;
} |
- en compilant ce code sans l'option "-s", la taille de l'exe est de 25KB: on peut retrouver à l'intérieur (édition héxa) plein de données y compris le nom de la fonction "Fonction_A_Cacher".
- en compilant ce code avec l'option "-s" (strip all symbols from binary), la taille de l'exe passe de 25KB à 6KB: on ne retrouve plus grand chose à l'intérieur et le nom de la fonction "Fonction_A_Cacher" est invisible.
Maintenant remplaçons la syntaxe du
Code:
printf("salut!\n");
par
Code:
printf("%s: salut!\n", __func__);
=> la 2ème syntaxe fait appel au preprocesseur qui remplace la variable __func__ par le nom de la fonction en cours (notation très intéressante si l'on veut par exemple retrouver une erreur dans la log ainsi que le nom de la fonction dans laquelle elle se produit).
=> quelque soit l'option de compilation (-s ou pas) le nom de la fonction "Fonction_A_Cacher" est toujours présent (car codé en dur par le préprocesseur).
Personnellement, j'utilise beaucoup la 2ème syntaxe du printf: les noms de mes fonctions se retrouvent codées en dur et visibles même avec Notepad. Le seul moyen de cacher ceci est de:
- ne plus utiliser la variable __func__ et compiler avec l'option -s
- ajouter au début du programme la ligne:
Code:
#define Fonction_A_Cacher FAC
Bien entendu, je choisis l'option #define.
@olivieram: mon code reste complètement clair, commenté et possédant des noms de fonctions/variables intelligents. Les seules choses qui changeront seront:
- on ne verra plus "Fonction_A_Cacher" mais "FAC" lors de l'édition du binaire (remplacement effectué par le preproc avant la compilation, donc sans modification de code et sans altération du fonctionnement du binaire),
- si une erreur survenait dans la fonction "Fonction_A_Cacher", la log indiquerait juste "FAC: erreur" au lieu de "Fonction_A_Cacher: erreur", mais ceci reste compréhensible (pour le développeur) et acceptable (d'un point de vue de la sécurité du processus implémenté).
Il s'agit bien d'une obfuscation basique, sans impact sur le code mais tout en restant nécessaire et suffisante à mon avis dans le cadre de mon projet.
@Yobi's: au lieu de coder ton mdp en dur essaie de créer une boucle sur ton argv[1], genre:
Code:
1 2 3 4 5 6 7 8
| len = strlen(argv[1]);
for (i=0; i<len; ++i)
{
if (i==0) pEncrString[i]=113; //code ascii de 'q'
else if (i==1) pEncrString[i]=119; //code ascii de 'w'
else if (i==2) pEncrString[i]=101; //code ascii de 'e'
//...
} |
Ça sera déjà beaucoup mieux, l'idéal étant de forcer ton prog à toujours recalculer la valeur de chaque lettre du mot de passe (en gros que la valeur de chaque lettre ne soit pas codée en dur mais toujours réévaluée), genre:
Code:
1 2 3 4
| a=10;
...
if (i==0) pEncrString[i]=pow(a, 2)+13;
... |
mais bon, qui sait, il y a peut-être mieux!
En vous remerciant de vos nombreux messages et votre précieuse aide, je vous salue bien.