Файлы Linux ELF: какой байт будет отличаться для статических и динамических программ ELF?

Я работаю с файлами linux elf.

Я хочу определить, связана ли данная эльфийская программа статически (полная статическая ссылка, ldd говорит "not a dynamic executable") или динамически связана. ELF предназначен для встроенного Linux, поэтому я не могу просто запустить его или использовать утилиту ldd.

Я хочу сделать это полностью в своей программе, прочитав и проверив несколько байтов. Я хочу не зависеть от утилиты file или от libelf, binutils и т.д.

Какие байты будут отличаться?


person osgx    schedule 04.09.2011    source источник
comment
Я думаю, вам нужно искать ДИНАМИЧЕСКИЙ заголовок программы   -  person Johannes Schaub - litb    schedule 04.09.2011


Ответы (1)


Как насчет использования ldd.c из Clibc? Если хотите, должно быть довольно легко удалить любые нежелательные зависимости/проверки. Я думаю, что это более разумный подход, чем пытаться выяснить все угловые случаи из чтения man 5 elf, хотя FWIW выглядит просто как проверка заголовка программы PT_INTERP, как вы подозреваете в комментариях.

Обновление: есть еще несколько проверок. Я попытался извлечь соответствующие части, но не уверен, что что-то пропустил, так что проверьте сами. Код проверяет 32-битные и 64-битные файлы x86 ELF. Он предполагает архитектуру с прямым порядком байтов.

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <inttypes.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

#include <elf.h>

int main(int argc, char* argv[])
{
    const char* fname = argv[0];
    if (argc >= 2) fname = argv[1];

    int fd;
    struct stat st;
    void *mapping;

    if ((fd = open(fname, O_RDONLY)) == -1) {
        perror(fname);
        return 1;
    }

    if (fstat(fd, &st)) {
        perror("fstat");
        close(fd);
        return 1;
    }

    if ((mapping = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return 1;
    }
    const Elf32_Ehdr* eh = mapping;

    if (st.st_size < (off_t)sizeof(Elf32_Ehdr) ||
        eh->e_ident[EI_MAG0] != ELFMAG0 || 
        eh->e_ident[EI_MAG1] != ELFMAG1 || 
        eh->e_ident[EI_MAG2] != ELFMAG2 || 
        eh->e_ident[EI_MAG3] != ELFMAG3 ||
        eh->e_ident[EI_VERSION] != EV_CURRENT) {
        printf("Not a valid ELF file\n");
        return 0;
    }

    if (eh->e_type != ET_EXEC && eh->e_type != ET_DYN) {
        printf("Not executable or shared object\n");
        return 0;
    }

    int is_dynamic = 0;

    // change as appropriate, but remember that byteswapping might be needed in some cases
    if (eh->e_ident[EI_CLASS] == ELFCLASS32 && eh->e_ident[EI_DATA] == ELFDATA2LSB && eh->e_machine == EM_386) {
        uint16_t ph_cnt;
        for (ph_cnt = 0; ph_cnt < eh->e_phnum; ph_cnt++) {
            const Elf32_Phdr* ph = (const Elf32_Phdr*)((const uint8_t*)mapping + eh->e_phoff + ph_cnt * eh->e_phentsize);
            if (ph->p_type == PT_DYNAMIC || ph->p_type == PT_INTERP) {
                is_dynamic = 1;
            }
        }
    } else if (eh->e_ident[EI_CLASS] == ELFCLASS64 && eh->e_ident[EI_DATA] == ELFDATA2LSB && eh->e_machine == EM_X86_64) {
        const Elf64_Ehdr* eh = mapping;
        uint16_t ph_cnt;
        for (ph_cnt = 0; ph_cnt < eh->e_phnum; ph_cnt++) {
            const Elf64_Phdr* ph = (const Elf64_Phdr*)((const uint8_t*)mapping + eh->e_phoff + ph_cnt * eh->e_phentsize);
            if (ph->p_type == PT_DYNAMIC || ph->p_type == PT_INTERP) {
                is_dynamic = 1;
            }
        }
    } else {
        printf("Unsupported architecture\n");
        return 0;
    }

    munmap(mapping, st.st_size);
    close(fd);
    printf("%s: %sdynamic\n", fname, is_dynamic?"":"not ");
    return 0;
}
person user786653    schedule 04.09.2011
comment
Это кажется хорошим. Это почти не зависит от внешних инструментов. - person osgx; 04.09.2011
comment
Это достаточно большой блок кода, очевидно полученный из чего-то существующего, и я думаю, вы должны указать, какая лицензия, по вашему мнению, будет применяться. - person Chris Stratton; 04.09.2011
comment
@Chris Stratton: часть mmap взята из моего комментария от 27 августа 8:59, остальное следовало из чтения man 5 elf. Проверки были вдохновлены чтением связанного исходного кода ldd, поэтому я согласен оставить его GPLv2 как uClibc. - person user786653; 04.09.2011
comment
Крис Страттон, я не буду копировать код, я просто хочу узнать идею и название полей. И код, размещенный б/у, является его собственным, и это CC-BY. Я упомяну его имя в коде, если скопирую этот код. - person osgx; 05.09.2011