How about using ldd.c from & mu; Clibc ? It should be pretty easy to strip any unwanted dependencies / checks if you want. I think this is a more sensible approach than trying to figure out all the corner cases when reading man 5 elf , although FWIW seems to just check the PT_INTERP program PT_INTERP , as you suspect in the comments.
Update: There are a few more checks. I tried to extract the appropriate parts, but I canβt be sure that I missed something to test myself. The code checks 32-bit and 64-bit ELF x86 files. It involves a little continental architecture.
#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; }
source share