2

I want to get the Magic Number from a binary file (for example file ELF hava 7f 45 4c 46). I wrote a program to print out the magic number of the file but i get the error zsh: segmentation fault ./magic. How should I fix this?

int main() 
{ 
    //setlocale(LC_ALL, "Russian"); 
    //FILE *fp; 
    //fopen (&fp, "/Documents/OCP/lab1test/lab1call", "rb"); 
    FILE *fp; 
    long fSize; 
    fp = fopen("/Documents/OCP/lab1test/lab1call", "rb"); 
    fseek (fp , 0 , SEEK_END); 
    fSize = ftell (fp);  
    rewind (fp);  
    char *magic_number; 
    magic_number=(char *)malloc(fSize+1); 
    //unsigned char magic_number[4]; 
    fread(magic_number, sizeof(char), 4, fp); 
    printf ("A magic number of your file is:\n");
    //magic_number[4] = '\0'; 
    //for (int i = 0; i < 4; i++) 
    printf ("%02hhx%02hhx%02hhx%02hhx\n ", magic_number[0],magic_number[1], magic_number[2], magic_number[3]);  
    printf("\n"); 
}   
Ivan Ivan
  • 49
  • 3
  • 1
    You dont need so big malloc based on whole size of file. You can malloc only 4 bytes if you are reading only first 4 bytes from file. Imagine that if you are reading file that is smaller than 4 bytes and now you use malloc based on that file size (ex: only 2B), Your pointer get malloced 2B and you are trying to store 4 bytes in fread, that may cause segfault. – T0maas Nov 28 '21 at 22:01
  • Run it in a debugger like gdb (after compiling with the `-g` option to get debugging information in the binary) to see exactly where it's getting the segfault. – Shawn Nov 28 '21 at 22:02
  • Check also if `fp` is not NULL after `fopen` – T0maas Nov 28 '21 at 22:03
  • 2
    `/Documents` does not look like a valid path. Do basic error checking of all function calls, speicificaly `fopen` in this case. – kaylum Nov 28 '21 at 22:05
  • 1
    You can also use simple array `char magic_number[4]` without malloc. – T0maas Nov 28 '21 at 22:05
  • (`gcc -g program.c; gdb ./a.out` then at the gdb prompt, `run`) – Shawn Nov 28 '21 at 22:06
  • Or just use a `uint32_t` or similar. But not all file magic is in the first 4 bytes. It's probably better to use `libmagic`. – Cheatah Nov 28 '21 at 22:18
  • maybe an array of 5 so you can print it directly as a string ? Anyway the solution seams to be a missing `~` in the file path. – Scouarn. Nov 28 '21 at 22:20
  • I recommend simplifying your code more before asking for help. The `fseek`, `ftell`, and `malloc` stuff is not needed if you just want to read 4 bytes from the beginning of the file. The commented out lines are also not needed. See: [mcve]. – David Grayson Nov 28 '21 at 22:39

1 Answers1

2

A few things first:

  1. I doubt that /Documents/OCP/lab1test/lab1call is a valid path on your system. It's usually /home/[USER]/Documents/..., you should double check that. Even better, pass it as an argument to your program so you can do fopen(argv[1], ...) after checking that argc == 2.

  2. You definitely do not need to seek all the way to the end of the file, and you definitely do not need to allocate a buffer the entire size of the file only to read four bytes at the beginning of the file. Simply fread 4 bytes. You can safely declare a 4-byte array on the stack of main.

  3. You must do error checking. Almost every library function in C can fail and return an error. Check the manual page (usually simply type man 3 function_name in your terminal) and see which errors can happen for each function and which is a "good" return value. The section 3 of the manual is for library functions. If you don't have the manual installed you can use an online one like for example manned.org.

With this said, what you're trying to do can be simplified down to:

int main(int argc, char **argv) {
    FILE *fp;
    unsigned char magic[4];

    if (argc != 2) {
        fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
        return 1;
    }

    fp = fopen(argv[1], "rb");
    if (fp == NULL) {
        perror("fopen failed");
        return 1;
    }

    if (fread(magic, 1, 4, fp) != 4) {
        if (feof(fp)) 
            fputs("File is less than 4 bytes\n", stderr);
        else
            fputs("Error reading the file\n", stderr);
        return 1;
    }

    fclose(fp);
    
    puts("The magic number of your file is:");
    printf("%02hhx%02hhx%02hhx%02hhx\n", magic[0], magic[1], magic[2], magic[3]);

    return 0;
}

You can compile and then run your program like this:

./magic path/to/the/file

Beware that if the path contains spaces you will have to enclose it in quotes otherwise it will be interpreted as two different arguments:

./magic 'path/with some/spaces'
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128