ELF Identification
ELF header 資料結構裡的 e_ident 欄位用來判斷檔案是否為ELF格式的欄位,e_ident 欄位是一個陣列資料結構,其長度由 SysV ABI所定義的常數 EI_NIDENT指定。
EI_NIDENT 的值為 16 代表 e_ident 欄位有 16 個元素,SysV ABI 定義了 8 個常數來索引 e_ident 陣列的元素。
表 e_ident[] 索引值定義
Name | Value | 說明 |
EI_MAG0 | 0 | ELF 識別字元 |
EI_MAG1 | 1 | ELF 識別字元 |
EI_MAG2 | 2 | ELF 識別字元 |
EI_MAG3 | 3 | ELF 識別字元 |
EI_CLASS | 4 | 檔案類別 (class) |
EI_DATA | 5 | 資料編碼方式 (Data encoding) |
EI_VERSION | 6 | 檔案版本 |
EI_PAD | 7 | padding bytes 的開頭 |
loader-0.2.c主要的改變在於加入了判斷檔案是否為 ELF 格式的程式碼。要判斷檔案是否為 ELF 格式,必須根據 e_ident[] 裡的識別字元來做判斷:
e_ident[EI_MAG0] 必須等於 ELFMAG0
e_ident[EI_MAG1] 必須等於 ELFMAG1
e_ident[EI_MAG2] 必須等於 ELFMAG2
e_ident[EI_MAG3] 必須等於 ELFMAG3
表 ELF識別字元(magic number)定義
Name | Value | 說明 |
ELFMAG0 | 0x7f | e_ident[EI_MAG0] 之值 |
ELFMAG1 | ‘E’ | e_ident[EI_MAG1] 之值 |
ELFMAG2 | ‘L’ | e_ident[EI_MAG2] 之值 |
ELFMAG3 | ‘F’ | e_ident[EI_MAG3] 之值 |
判斷是否為 ELF 格式
設計一個 elf_ident() 函數來判斷檔案是否為 ELF 格式,其程式碼如下:
int elf_ident(char *ident) { if (*(ident+EI_MAG0) != ELFMAG0) return 0; if (*(ident+EI_MAG1) != ELFMAG1) return 0; if (*(ident+EI_MAG2) != ELFMAG2) return 0; if (*(ident+EI_MAG3) != ELFMAG3) return 0; return -1; }
e_ident[] 裡還存放許多 ELF 的資訊。以下再舉一例,我們新增一個函數 parse_ident() 來分析e_ident[] 的 "CLASS" 資訊:
void parse_ident(char *ident) { printf("ELF Identification\n"); printf(" Class: "); switch (*(ident+EI_CLASS)) { case ELFCLASSNONE: printf("Invalid class\n"); break; case ELFCLASS32: printf("32-bit objects\n"); break; case ELFCLASS64: printf("64-bit objects\n"); break; } }
程式列表:loader-0.2.c
/* * Copyright(c) 2003,2006 * * ELF programming. ver 0.2 * */ #include#include #include #include #include #include int elf_ident(char *ident) { if (*(ident+EI_MAG0) != ELFMAG0) return 0; if (*(ident+EI_MAG1) != ELFMAG1) return 0; if (*(ident+EI_MAG2) != ELFMAG2) return 0; if (*(ident+EI_MAG3) != ELFMAG3) return 0; return -1; } void parse_ident(char *ident) { printf("ELF Identification\n"); printf(" Class: "); switch (*(ident+EI_CLASS)) { case ELFCLASSNONE: printf("Invalid class\n"); break; case ELFCLASS32: printf("32-bit objects\n"); break; case ELFCLASS64: printf("64-bit objects\n"); break; } } void parse_machine(Elf32_Half machine) { printf("Machine: "); switch (machine) { case EM_NONE: printf("No machine\n"); break; case EM_M32: printf("AT&T WE 32100\n"); break; case EM_SPARC: printf("SPARC\n"); break; case EM_386: printf("Intel 80386\n"); break; case EM_68K: printf("Motorola 68000\n"); break; case EM_88K: printf("Motorola 88000\n"); break; case EM_860: printf("Intel 80860\n"); break; case EM_MIPS: printf("MIPS RS3000 Big-Endian\n"); break; default: printf("Unknow\n"); } } int main(int argc, char *argv[]) { int fd; Elf32_Ehdr f_header; if (argc != 2) { printf("Usage: loader [filename]\n"); return -1; } fd = open(argv[1], S_IRUSR); if (fd < 0) { printf("\nfile open error\n"); return -1; } /* Read ELF Header */ read(fd, &f_header, sizeof(Elf32_Ehdr)); /* Parse header information */ if (elf_ident(f_header.e_ident)) { parse_ident(f_header.e_ident); parse_machine(f_header.e_machine); } else { printf("not a ELF binary file\n"); } }