Dans une tentative de falsification de mon exécutable avec du hachage, j'ai rencontré un comportement de compilateur inattendu et inconnu.

J'ai cette idée de calculer une valeur de hachage simple de mon programme en ajoutant simplement tous les octets du binaire et en utilisant le reste de ce total divisé par 256 comme valeur de hachage.

J'ai pensé que si dans mon programme j'avais un littéral de chaîne de "0000" et que le hachage que je calcule avec l'algorithme ci-dessus donne par exemple 163, que je pourrais obtenir 164 en remplaçant l'un des "0" par un "1" . Cependant, les résultats que j'obtiens sont loin de cela. En remplaçant un seul caractère par une seule valeur, j'obtiens un résultat de hachage totalement différent. Pour cet exemple, le 163 pourrait devenir 84, ce qui me laisse perplexe.

Ma fonction pour calculer le hachage est assez simple mais la voici quand même.

int calcHash(const char *filename) {
    int hash = 0;
    int c;
    FILE *fh = fopen(filename, "r");

    if (!fh)
        return -1;

    while((c = fgetc(fh)) != EOF)
        hash = (hash + c) % 256;

    fclose(fh);

    return hash;
}

Et je l'appelle depuis main() avec cette instruction.

int hash = calcHash(argv[0]);

Que se passe-t-il exactement pendant la compilation ? Quoi qu'il en soit, je peux obtenir des valeurs de hachage plus prévisibles?

Peut-être que cela n'arrive pas avec tous les compilateurs. Je suis juste totalement déconcerté par ce comportement inattendu.

J'utilise gcc sur Ubuntu.

0
Hexmind 17 févr. 2020 à 03:44

1 réponse

Meilleure réponse

C'est un problème plus difficile qu'il n'y paraît, en plus d'être une idée pire qu'il n'y paraît - je ne saurais trop le recommander.

J'ai travaillé sur un système client où ils ont fait cela, et c'était aussi pénible qu'on l'a suggéré, alors j'ai fini par faire une ingénierie inverse pour écrire mon propre utilitaire de re-scellement afin que je puisse éditer le fichu fichier et appliquer le nouveau hachage. Et ces changements étaient toujours à l'avantage du fournisseur de logiciels et de ses clients, pour ne jamais le voler ou quoi que ce soit.

Mais dans tous les cas, pour autant que je me souvienne, cela a fonctionné en incluant certaines zones de données dans le code :

char tamper_marker_1[] = "SOME MAGIC STRING";
int  fileSize;
unsigned checksum;
char endmarker[] = "OTHER MAGIC STRING";

Le programme externe d'application du sceau ouvrirait le .exe et trouverait la chaîne magique, qui mènerait à la zone de données ci-dessus, et remplirait le fileSize et le checksum de toutes les données autre que dans la zone d'information sur les sceaux.

L'exécutable testerait la falsification en s'ouvrant en tant que fichier et en effectuant les mêmes vérifications.

Sous Windows, vous pouvez utiliser GetModuleFilename() pour trouver le chemin complet de l'exécutable, et sous Linux, vous pouvez ouvrir /proc/12345/exe (où 12345 est votre ID de processus) qui est un lien symbolique vers le programme et donc le même chose.

Je ne sais pas si je contribue à rendre le monde pire en décrivant cela, mais SO est pour les questions et réponses, et peut-être qu'il y a un besoin légitime. S'il vous plaît, ne le faites pas à moins que vous n'y soyez vraiment obligé.

EDIT : Vous pourriez souligner que très peu de gens se donneront la peine que j'ai fait de l'ingénierie inverse, mais je soulignerai que tout ce dont vous avez besoin est une personne pour créer l'outil de re-scellement et le libérer , et tout votre travail intelligent est pour rien.

EDIT2 : Comme je pense à cela, s'il ne s'agit que d'un programme, vous n'auriez pas à faire de l'ingénierie inverse de l'algorithme - vous auriez juste à pouvoir le désassembler pour annuler le test.

0
Steve Friedl 17 févr. 2020 à 02:15