Файлы ELF в Linux: какой байт будет отличаться для статических и динамических программ ELF?
Я работаю с linux elf файлами.
Я хочу определить, является ли данная эльфийская программа статически связанной (полная статическая ссылка, ldd
говорит "not a dynamic executable
") или динамически связаны. ELF для встроенного Linux, поэтому я не могу просто запустить его или использовать ldd
полезность.
Я хочу сделать это полностью в моей программе, читая и проверяя некоторые байты. Я не хочу зависеть от file
утилита или на libelf, binutils и т. д.
Какие байты будут другими?
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;
}