2017-03-12 2 views
0

Je code le programme lite en c de base qui ajoute (ou sous) offset pour chaque octet dans le fichier binaire passé en argument. Ce travail pour tous les autres ELF, mais quand je suis en train de courir:
$ ./a.out a.out 1 (ajouter 0x01 à chaque octets),
fopen() accident avec le message d'erreur « Fichier texte occupé ». J'ai vérifié avec lsof, mais n'est pas ouvert sur le système de fichiers.
Je pensais que lorsqu'un fichier exécutable est en cours d'exécution, une image du fichier est chargée dans la RAM et le fichier est accessible.
Si quelqu'un sait quoi à ce sujet, je vais le prendre! Merci d'avoir pris le temps de me lire!ouvrir un fichier binaire runing

Voici le code:

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

void usage (char *pgr_name); // print usage and exit 
void fatal(char *s); // print s, call perror("") and exit(-1) 

// lite hexdump ([0xff] x16 | ...a...b...c...d) 
void dump (const unsigned char *data_buffer, const unsigned int len); 

int main(int argc, char **argv) { 
    FILE *my, *crypted; 
    void *content; 
    unsigned char *ascii; 
    char output[256] = ""; 
    int i, bytes_read, offset; 

    if (argc < 3) 
     usage(argv[0]); 

    offset = atoi(argv[2]); 
    if (offset < -255 || offset > 0xff) { 
     printf("bad offset\n"); 
     usage(argv[0]); 
    } 

    printf("offset %d\n", offset); 

    // open src 
    if ((my = fopen(argv[1], "rb+")) == NULL) 
     fatal("in opening argv[1]"); 

    // alloc memory for src 
    if ((content = malloc (10000)) == NULL) 
     fatal("in malloc"); 

    // read src 
    bytes_read = fread(content, 1, 9999, my); 
    printf("%d bytes read\n", bytes_read); 

    // for reading easily 
    ascii = (unsigned char *) content; 

    dump(content, bytes_read); 

    // apply offset on each bytes 
    for (i=0; i<bytes_read; i++) 
     ascii[i] = ascii[i] + offset; 
    printf("\n\ntranslation complete\n\n"); 

    dump(content, bytes_read); 

    strncpy(output, argv[1], 250); 
    strcat(output, ".cry"); 

    // open dest 
    if ((crypted = fopen(output, "wb+")) == NULL) 
     fatal("in open crypted"); 

    // write src translated in dest 
    bytes_read = fwrite(content, 1, bytes_read, crypted); 
    printf("%d bytes written\n", bytes_read); 

    // terminate pgrm 
    fclose(crypted); 
    fclose(my); 
    free(content); 

    return 0; 
} 

void fatal(char *s) { 
    if (s) { 
     fprintf(stderr, "[!] Fatal [!] : %s\n", s); 
    } 
    perror(""); 
    exit(-1); 
} 

void usage (char *pgr_name) { 
    printf("Usage : %s <binary input> <offset [-255:255]>\n\n", pgr_name); 
    exit(0); 
} 

void dump (const unsigned char *data_buffer, const unsigned int len) { 
    unsigned char byte; 
    unsigned int i, j; 
    for (i=0; i<len; i++) { 
     byte = data_buffer[i]; 
     printf("%02x ", data_buffer[i]); 
     if (((i%16) == 15) || (i==len-1)) { 
      for (j=0; j < 15-(i%16); j++) 
       printf(" "); 
      printf("| "); 
      for (j=(i-(i%16)); j<=i; j++) { 
       byte = data_buffer[j]; 
       if (byte > 31 && byte < 127) 
        printf("%c", byte); 
       else 
        printf("."); 
      } 
      printf("\n"); 
     } 
    } 
} 
+0

Le fichier est occupé car vous l'exécutez. Une fois qu'il a échoué, alors vous ne l'utilisez plus, donc lsof ne le montrerait pas verrouillé. EDIT TO ADD, le fichier sera occupé pendant toute la durée de la course, pas seulement en mémoire. – racraman

+0

Donc, un exécutable ne peut pas le réécrire sur unix? – ghost

+0

Merci pour la rapidité de la réponse – ghost

Répondre

1

Unix systèmes de fichiers - ceux utilisés dans Unix, BSD, Mac OS, Linux, etc. - comptent sur inodes. Plusieurs noms de fichiers peuvent faire référence au même inode.

Si le nom de fichier est supprimé, mais que l'inode est toujours ouvert dans un ou plusieurs processus, l'inode n'a aucun nom de fichier qui s'y rapporte. Vous pouvez toujours travailler avec le fichier ouvert normalement - l'étendre, par exemple - mais aucun autre processus ne peut l'ouvrir (à moins que vous ne lui fournissiez le descripteur de fichier ouvert d'une façon ou d'une autre). Lorsque les binaires ELF sont exécutés, l'inode sous-jacent est verrouillé par le noyau.

Note: c'est l'inode qui est verrouillé, pas le nom du fichier. En effet, plutôt que de «charger» les données dans la mémoire, la plupart des systèmes ne font que mapper les données. Sous Linux, par exemple, cela signifie que peu importe le nombre de copies d'un exécutable ou d'une bibliothèque dynamique en cours d'exécution, une seule copie du binaire existe en RAM.

En pratique, cela signifie que vous ne pouvez pas modifier un fichier binaire ELF pendant son exécution. Cependant, vous pouvez renommer ou même supprimer le fichier, car c'est l'inode auquel le nom de fichier fait référence et non le nom de fichier qui est verrouillé par le noyau. (Bien sûr, vous pouvez très bien lire les binaires ELF même s'ils sont en cours d'exécution, vous devez juste les ouvrir en lecture seule, car leur ouverture en lecture-écriture échouera car la plupart des systèmes de fichiers Unix ne vérifient que les droits d'accès à l'heure d'ouverture.)

Ce que vous pouvez faire, c'est créer un nouveau fichier; écrire les données modifiées; copier facultativement le propriétaire, le groupe, le mode, l'horodatage du dernier accès et de la dernière modification, et/ou les attributs étendus (xattrs); et enfin renommer ou créer un lien physique entre le nouveau nom de fichier et l'ancien nom de fichier. (Renommer ou hardlinker sur un fichier existant change juste l'inode auquel le nom de fichier existant fait référence et ne viole donc pas le verrouillage inode.)

Ceci a l'avantage supplémentaire que le remplacement (de l'ancien binaire) est atomique. Indépendamment du moment où les autres processus peuvent ouvrir ou exécuter l'ancien binaire, ils verront toujours soit l'ancien inode, soit le nouvel inode, jamais une sorte d'entre-deux.