5

I'm trying to read content of a file into a struct. The struct looks like this:

    typedef struct{
            unsigned char e_ident[EI_NIDENT] ;
            Elf32_Half e_type;
            Elf32_Half e_machine;
            Elf32_Word e_version;
            Elf32_Addr e_entry;
            Elf32_Off e_phoff;
            Elf32_Off e_shoff;
            Elf32_Word e_flags;
            Elf32_Half e_ehsize;
            Elf32_Half e_phentsize;
            Elf32_Half e_phnum;
            Elf32_Half e_shentsize;
            Elf32_Half e_shnum;
            Elf32_Half e_shstrndx;
    } Elf32_Ehdr;
extern Elf32_Ehdr elfH;

It's basically an ELF header file. So, anyways i want to load content of a file into this structure.

The function looks like this.

Elf32_Ehdr elfH;
int load(char* fname){
        FILE* file = fopen(fname,"r");

        if(NULL == file) return 0;

        fread(&elfH, 1, 52, file);

        fclose(file);
        return 1;
}

As it seems it's not working correctly. The content of elfH is not as expected. What might be the problem? Should i

idjuradj
  • 1,355
  • 6
  • 19
  • 31

6 Answers6

2

This is the code I've used to read the header from an ELF executable.

FILE* fp = fopen(fname, "rb");
if(fp == NULL)
{
    printf("failed to load\n");
    exit(1);
}

Elf32_Ehdr hdr;
if (1 != fread(&hdr, sizeof(hdr), 1, fp))
{
    printf("failed to read elf header\n");
    exit(1);
}
// If program doesn't exit, header was read and can be worked with down here.
Isaac Drachman
  • 984
  • 6
  • 8
0

You'll have to add "b" in your file access mode string ("rb") of fopen to do binary data reading. Your hardcoded elf header size may also be not such a good idea as it may be the case that the size of your elf header struct is not exactly 62. sizeof(Elf32_Ehdr) is probably a better way of doing it ...

dragosht
  • 3,237
  • 2
  • 23
  • 32
0

Maybe your problem is that the data in the file is not written in the same endianness as your program expects it to be.

You can verify if this is the case if you compare the expected and the actual values in hex.
E.g. if you expect 0x12345678 but actually get 0x78563412 it is definitely an endianness issue.

For a solution see answer to this problem.

Community
  • 1
  • 1
Curd
  • 12,169
  • 3
  • 35
  • 49
0

C makes rather limited guarantees about how the contents of structs are packed and aligned in memory. It's probably both compiler- and platform-dependent whether the elements of your Elf32_Ehdr structure are in fact contiguous. Since they're all different sizes, I doubt it (if you print out sizeof(Elf32_Ehdr) and compare it to the actual on-disk size of the header, you might see differences).

If you know that the header you're reading is 52 bytes long (as your code suggests), then you need to fread that much, and then do something like (in outline)

#define HDR_SIZE 52
typedef unsigned char byte;
Elf32_Ehdr hdr;

byte buf[HDR_SIZE];

fread(buf, HDR_SIZE, 1, fp);

hdr.e_version = *(Elf32_Word*)&buf[1];
...

(I'm guessing that Elf32_Half is a half-byte, so that e_version is in bytes 1 and 2 (0-offset) of the buffer).

I haven't tested that, but I hope you get the idea.

Then there are bytesex questions for you to worry about...

Norman Gray
  • 11,978
  • 2
  • 33
  • 56
0

As dragosht pointed out, you may need to open the file binary, if you are on some kind of windows machine.

There is also a possibility that you are running into alignment issues. structs can have extra fields automatically inserted to help maintain correct address alignment for performance reasons.

If you are reading a file which was written from the same structure in binary mode, i would not expect to see that issue.

EvilTeach
  • 28,120
  • 21
  • 85
  • 141
  • The overall idea would be that i would create the header myself (i would fill the structure in my program and then i would write it into a file)... then, at some other point in my program i would read it, so the form should be the same. Can i test this with .txt file? For example i have a file with one word containing 52 chars (each char is one byte, so the size would be right 52 bytes). What should be the content of my struct? The main question is, can i test this with text file saved as .bin? – idjuradj Aug 11 '14 at 19:34
  • no. a text file saved with a .bin extension is still a text file. What platform are you running on? – EvilTeach Aug 11 '14 at 20:26
  • I'm running it on Visual Studio 2010, Windows 7. – idjuradj Aug 11 '14 at 21:07
  • One one problem for sure. You must open the file "rb" when reading and "wb" when writing. – EvilTeach Aug 11 '14 at 22:10
  • 1
    I advise writing a test program seperate from your application which defines a test structure, populates it, writes it to a binary file. Then it creates an other structure and reads it from the binary file. then use memcmp on the two structures to see if they are identical. That will give you a place to test to get the technique correct. You will be able to refer to it again when you need refreshed on the technique. – EvilTeach Aug 11 '14 at 22:19
0

The code you have has the fread backwards, which makes the if statement incorrect. fread returns the number if items read. If you give the size arguments backwards, then it will return the number of bytes read. Thus, the solution is to give the two size arguments to fread in the opposite order.

int main(int argc, char ** argv)
{
    printf("Reading %s\n", argv[1]);
    FILE* fp = fopen(argv[1], "rb");
    if(fp == NULL)
    {
            printf("file not opened\n");
            exit(-1);
    }

    Elf32_Ehdr * header = malloc(sizeof(Elf32_Ehdr));
    int value = fread(header, sizeof(Elf32_Ehdr), 1, fp);
    //int value = fread(header, 1, sizeof(Elf32_Ehdr), fp); // incorrect order
    printf("Read %d items\n", value);
    if (value != 1)
    {
            printf("failed to read elf header\n");
            exit(-1);
    }
    printf("Majick %c%c%c%c",header->e_ident[0],header->e_ident[1], header->e_ident[2], header->e_ident[3]);
    fclose(fp);
}
Milhous
  • 14,473
  • 16
  • 63
  • 82