这学期Linux的大作业第一部分是解析64位/32位的ELF文件,这里偷了个懒只解析了ELF头、程序头表和节头表;
这里先附上代码占个坑,有时间会来补详细解释;
输入格式为ELF文件名;
程序会同时将三个解析结果打印到控制台并写入同级目录下的result.txt文件中;
#include <stdio.h>
#include <stdlib.h>
#include <elf.h>
#include <string.h>
#define putline puts("-------------------------------------------------------------------------------------------------------------")
int OStype;
FILE *fp;
char *fname;
char strtable[9999];
//----------------------------------------------------------------------------------
//-------------------------------64位分析-------------------------------------------
//----------------------------------------------------------------------------------
void ELF_header_64_parse(Elf64_Ehdr* ehdr) {
fseek(fp, 0, SEEK_SET);
fread(ehdr, sizeof(Elf64_Ehdr), 1, fp);
putline;
puts("ELF头:");
printf("Magic:\t\t\t");
for(int i = 0; i < EI_NIDENT; ++i) printf("%02x ", ehdr->e_ident[i]);
printf("\n类别:\t\t\t");
switch(ehdr->e_type) {
case 0 : printf("未知文件类型\n"); break;
case 1 : printf("可重定位文件\n"); break;
case 2 : printf("可执行文件\n"); break;
case 3 : printf("动态链接库文件\n"); break;
case 4 : printf("Core文件\n"); break;
case 0xff00 : printf("特定处理器文件扩展下边界\n"); break;
case 0xffff : printf("特定处理器文件扩展上边界\n"); break;
}
printf("处理器体系结构:\t\t");
switch(ehdr->e_machine) {
case 0 : printf("未知体系结构\n"); break;
case 1 : printf("AT&T WE 32100\n"); break;
case 2 : printf("SPARC\n"); break;
case 3 : printf("Intel Architecture\n"); break;
case 4 : printf("Motorola 68000\n"); break;
case 5 : printf("Motorola 88000\n"); break;
case 7 : printf("Intel 80860\n"); break;
case 8 : printf("MIPS RS3000 Big-Endian\n"); break;
case 10 : printf("MIPS RS4000 Big-Endian\n"); break;
case 62 : printf("AMD x86-64 architecture\n"); break;
}
printf("version:\t\t");
switch(ehdr->e_version) {
case 0 : printf("非法版本号\n"); break;
case 1 : printf("当前版本号\n"); break;
}
printf("入口虚拟地址:\t\t0x%016x\n", ehdr->e_entry);
printf("程序头表偏移量:\t\t0x%08x\n", ehdr->e_phoff);
printf("节头表偏移量:\t\t0x%08x\n", ehdr->e_shoff);
printf("处理器标志位:\t\t%x\n", ehdr->e_flags);
printf("ELF文件头大小:\t\t%u bytes\n", ehdr->e_ehsize);
printf("程序头标每一表项大小:\t%u bytes\n", ehdr->e_phentsize);
printf("程序头表表项数量:\t%u\n", ehdr->e_phnum);
printf("节头表每一表项大小:\t%u bytes\n", ehdr->e_shentsize);
printf("节头表表项数量:\t\t%u\n", ehdr->e_shnum);
printf("字符串表在节头表中索引:\t%u\n", ehdr->e_shstrndx);
}
void section_header_64_parse(Elf64_Ehdr* ehdr) {
Elf64_Shdr shdr[99];
int count = ehdr->e_shnum; //节头表数量
fseek(fp, ehdr->e_shoff, SEEK_SET);
fread(shdr, sizeof(Elf64_Shdr), count, fp);
fseek(fp, shdr[ehdr->e_shstrndx].sh_offset, SEEK_SET);
fread(strtable, 1, shdr[ehdr->e_shstrndx].sh_size, fp);
putline;
printf("There are %d section headers, starting at offset 0x%04x:\n\n", count, ehdr->e_shoff);
puts("节头表:");
printf("[编号]\t名称\t\t\ 类型\t\t属性\t虚拟地址\t\t偏移量\t\t大小\t\t索引值\t信息\t对齐长度\t表项大小\n");
for(int i = 0; i < count; ++i) {
printf("[%02d]\t%s", i, &strtable[shdr[i].sh_name]);
for(int j = 0; j < 20 - strlen(&strtable[shdr[i].sh_name]); ++j) {
putchar(' ');
}
switch(shdr[i].sh_type) {
case 0 : printf("SHT_NULL\t"); break;
case 1 : printf("SHT_PROGBITS"); break;
case 2 : printf("SHT_SYMTAB\t"); break;
case 3 : printf("SHT_STRTAB\t"); break;
case 4 : printf("SHT_RELA\t"); break;
case 5 : printf("SHT_HASH\t"); break;
case 6 : printf("SHT_DYNAMIC\t"); break;
case 7 : printf("SHT_NOTE\t"); break;
case 8 : printf("SHT_NOBITS\t"); break;
case 9 : printf("SHT_REL\t"); break;
case 10 : printf("SHT_SHLIB\t"); break;
case 11 : printf("SHT_DYNSYM\t"); break;
case 14 : printf("SHT_INIT_ARRAY"); break;
case 15 : printf("SHT_FINI_ARRAY"); break;
case 0x70000000 : printf("SHT_LOPROC"); break;
case 0x7fffffff : printf("SHT_HIPROC"); break;
case 0x80000000 : printf("SHT_LOUSER"); break;
case 0xffffffff : printf("SHT_HIUSER"); break;
case 0x6ffffff6 : printf("SHT_GNU_HASH"); break;
case 0x6fffffff : printf("SHT_GNU_versym"); break;
case 0x6ffffffe : printf("SHT_GNU_verneed"); break;
}
printf("\t0x%x\t", shdr[i].sh_flags);
printf("0x%016x\t", shdr[i].sh_addr);
printf("0x%08x\t", shdr[i].sh_offset);
printf("%4lu bytes\t", shdr[i].sh_size);
printf("%u\t", shdr[i].sh_link);
printf("%u\t", shdr[i].sh_info);
printf("%2lu bytes\t", shdr[i].sh_addralign);
printf("%4x\n", shdr[i].sh_entsize);
}
}
void program_header_64_parse(Elf64_Ehdr* ehdr) {
Elf64_Phdr phdr[99];
fseek(fp, ehdr->e_phoff, SEEK_SET);
int count = ehdr->e_phnum; //程序头表的数量
fread(phdr, sizeof(Elf64_Phdr), count, fp);
putline;
printf("There are %d program headers, starting at offset 0x%04x:\n\n", count, ehdr->e_phoff);
puts("程序头表:");
puts("类型\t\t属性\t偏移量\t\t虚拟地址\t\t物理地址\t\t文件大小\t镜像大小\t对齐长度");
for(int i = 0; i < count; ++i) {
switch(phdr[i].p_type) {
case 0 : printf("PT_NULL\t"); break;
case 1 : printf("PT_LOAD\t"); break;
case 2 : printf("PT_DYNAMIC"); break;
case 3 : printf("PT_INTERP"); break;
case 4 : printf("PT_NOTE\t"); break;
case 5 : printf("PT_SHLIB"); break;
case 6 : printf("PT_PHDR\t"); break;
case 0x6474e550 : printf("GNU_EH_FRAME"); break;
case 0x6474e551 : printf("GNU_STACK"); break;
case 0x6474e552 : printf("GNU_RELRO"); break;
case 0x70000000 : printf("PT_LOPROC"); break;
case 0x7fffffff : printf("PT_HIPROC"); break;
}
putchar('\t');
switch(phdr[i].p_flags) {
case 0 : printf("none"); break;
case 1 : printf("x"); break;
case 2 : printf("w"); break;
case 3 : printf("wx"); break;
case 4 : printf("r"); break;
case 5 : printf("rx"); break;
case 6 : printf("rw"); break;
case 7 : printf("rwx"); break;
}
printf("\t0x%08x", phdr[i].p_offset);
printf("\t0x%016x", phdr[i].p_vaddr);
printf("\t0x%016x", phdr[i].p_paddr);
printf("\t%6u bytes", phdr[i].p_filesz);
printf("\t%6u bytes", phdr[i].p_memsz);
printf("\t%8u bytes", phdr[i].p_align);
putchar('\n');
}
}
//----------------------------------------------------------------------------------
//-----------------------------32位分析---------------------------------------------
//----------------------------------------------------------------------------------
void ELF_header_32_parse(Elf32_Ehdr* ehdr) {
fseek(fp, 0, SEEK_SET);
fread(ehdr, sizeof(Elf32_Ehdr), 1, fp);
putline;
puts("ELF头:");
printf("Magic:\t\t\t");
for(int i = 0; i < EI_NIDENT; ++i) printf("%02x ", ehdr->e_ident[i]);
printf("\n类别:\t\t\t");
switch(ehdr->e_type) {
case 0 : printf("未知文件类型\n"); break;
case 1 : printf("可重定位文件\n"); break;
case 2 : printf("可执行文件\n"); break;
case 3 : printf("动态链接库文件\n"); break;
case 4 : printf("Core文件\n"); break;
case 0xff00 : printf("特定处理器文件扩展下边界\n"); break;
case 0xffff : printf("特定处理器文件扩展上边界\n"); break;
}
printf("处理器体系结构:\t\t");
switch(ehdr->e_machine) {
case 0 : printf("未知体系结构\n"); break;
case 1 : printf("AT&T WE 32100\n"); break;
case 2 : printf("SPARC\n"); break;
case 3 : printf("Intel Architecture\n"); break;
case 4 : printf("Motorola 68000\n"); break;
case 5 : printf("Motorola 88000\n"); break;
case 7 : printf("Intel 80860\n"); break;
case 8 : printf("MIPS RS3000 Big-Endian\n"); break;
case 10 : printf("MIPS RS4000 Big-Endian\n"); break;
case 62 : printf("AMD x86-64 architecture\n"); break;
}
printf("version:\t\t");
switch(ehdr->e_version) {
case 0 : printf("非法版本号\n"); break;
case 1 : printf("当前版本号\n"); break;
}
printf("入口虚拟地址:\t\t0x%08x\n", ehdr->e_entry);
printf("程序头表偏移量:\t\t0x%04x\n", ehdr->e_phoff);
printf("节头表偏移量:\t\t0x%04x\n", ehdr->e_shoff);
printf("处理器标志位:\t\t%x\n", ehdr->e_flags);
printf("ELF文件头大小:\t\t%u bytes\n", ehdr->e_ehsize);
printf("程序头标每一表项大小:\t%u bytes\n", ehdr->e_phentsize);
printf("程序头表表项数量:\t%u\n", ehdr->e_phnum);
printf("节头表每一表项大小:\t%u bytes\n", ehdr->e_shentsize);
printf("节头表表项数量:\t\t%u\n", ehdr->e_shnum);
printf("字符串表在节头表中索引:\t%u\n", ehdr->e_shstrndx);
}
void section_header_32_parse(Elf32_Ehdr* ehdr) {
Elf32_Shdr shdr[99];
int count = ehdr->e_shnum; //节头表数量
fseek(fp, ehdr->e_shoff, SEEK_SET);
fread(shdr, sizeof(Elf32_Shdr), count, fp);
fseek(fp, shdr[ehdr->e_shstrndx].sh_offset, SEEK_SET);
fread(strtable, 1, shdr[ehdr->e_shstrndx].sh_size, fp);
putline;
printf("There are %d section headers, starting at offset 0x%04x:\n\n", count, ehdr->e_shoff);
puts("节头表:");
printf("[编号]\t名称\t\t\ 类型\t\t属性\t虚拟地址\t偏移量\t大小\t\t索引值\t信息\t对齐长度\t表项大小\n");
for(int i = 0; i < count; ++i) {
printf("[%02d]\t%s", i, &strtable[shdr[i].sh_name]);
for(int j = 0; j < 20 - strlen(&strtable[shdr[i].sh_name]); ++j) {
putchar(' ');
}
switch(shdr[i].sh_type) {
case 0 : printf("SHT_NULL\t"); break;
case 1 : printf("SHT_PROGBITS"); break;
case 2 : printf("SHT_SYMTAB\t"); break;
case 3 : printf("SHT_STRTAB\t"); break;
case 4 : printf("SHT_RELA\t"); break;
case 5 : printf("SHT_HASH\t"); break;
case 6 : printf("SHT_DYNAMIC\t"); break;
case 7 : printf("SHT_NOTE\t"); break;
case 8 : printf("SHT_NOBITS\t"); break;
case 9 : printf("SHT_REL\t"); break;
case 10 : printf("SHT_SHLIB\t"); break;
case 11 : printf("SHT_DYNSYM\t"); break;
case 14 : printf("SHT_INIT_ARRAY"); break;
case 15 : printf("SHT_FINI_ARRAY"); break;
case 0x70000000 : printf("SHT_LOPROC"); break;
case 0x7fffffff : printf("SHT_HIPROC"); break;
case 0x80000000 : printf("SHT_LOUSER"); break;
case 0xffffffff : printf("SHT_HIUSER"); break;
case 0x6ffffff6 : printf("SHT_GNU_HASH"); break;
case 0x6fffffff : printf("SHT_GNU_versym"); break;
case 0x6ffffffe : printf("SHT_GNU_verneed"); break;
}
printf("\t0x%x\t", shdr[i].sh_flags);
printf("0x%08x\t", shdr[i].sh_addr);
printf("0x%04x\t", shdr[i].sh_offset);
printf("%4lu bytes\t", shdr[i].sh_size);
printf("%u\t", shdr[i].sh_link);
printf("%u\t", shdr[i].sh_info);
printf("%2lu bytes\t", shdr[i].sh_addralign);
printf("%4x\n", shdr[i].sh_entsize);
}
}
void program_header_32_parse(Elf32_Ehdr* ehdr) {
Elf32_Phdr phdr[99];
fseek(fp, ehdr->e_phoff, SEEK_SET);
int count = ehdr->e_phnum; //程序头表的数量
fread(phdr, sizeof(Elf32_Phdr), count, fp);
putline;
printf("There are %d program headers, starting at offset 0x%04x:\n\n", count, ehdr->e_phoff);
puts("程序头表:");
puts("类型\t\t属性\t偏移量\t虚拟地址\t物理地址\t文件大小\t镜像大小\t对齐长度");
for(int i = 0; i < count; ++i) {
switch(phdr[i].p_type) {
case 0 : printf("PT_NULL\t"); break;
case 1 : printf("PT_LOAD\t"); break;
case 2 : printf("PT_DYNAMIC"); break;
case 3 : printf("PT_INTERP"); break;
case 4 : printf("PT_NOTE\t"); break;
case 5 : printf("PT_SHLIB"); break;
case 6 : printf("PT_PHDR\t"); break;
case 0x6474e550 : printf("GNU_EH_FRAME"); break;
case 0x6474e551 : printf("GNU_STACK"); break;
case 0x6474e552 : printf("GNU_RELRO"); break;
case 0x6474e553 : printf("GNU_PROPERTY"); break;
case 0x70000000 : printf("PT_LOPROC"); break;
case 0x7fffffff : printf("PT_HIPROC"); break;
}
putchar('\t');
switch(phdr[i].p_flags) {
case 0 : printf("none"); break;
case 1 : printf("x"); break;
case 2 : printf("w"); break;
case 3 : printf("wx"); break;
case 4 : printf("r"); break;
case 5 : printf("rx"); break;
case 6 : printf("rw"); break;
case 7 : printf("rwx"); break;
}
printf("\t0x%04x", phdr[i].p_offset);
printf("\t0x%08x", phdr[i].p_vaddr);
printf("\t0x%08x", phdr[i].p_paddr);
printf("\t%4u bytes", phdr[i].p_filesz);
printf("\t%4u bytes", phdr[i].p_memsz);
printf("\t%4u bytes", phdr[i].p_align);
putchar('\n');
}
}
//----------------------------------------------------------------------------------
//-----------------------------main函数---------------------------------------------
//----------------------------------------------------------------------------------
void print64(void (*fun)(Elf64_Ehdr* ehdr)) {
//打印到控制台和txt文件
static Elf64_Ehdr ehdr[1];
freopen("CON", "w", stdout);
fun(ehdr);
freopen("result.txt", "a+", stdout);
fun(ehdr);
freopen("CON", "w", stdout);
}
void print32(void (*fun)(Elf32_Ehdr* ehdr)) {
//打印到控制台和txt文件
static Elf32_Ehdr ehdr[1];
freopen("CON", "w", stdout);
fun(ehdr);
freopen("result.txt", "a+", stdout);
fun(ehdr);
freopen("CON", "w", stdout);
}
int main() {
char str[20];
printf("请输入ELF文件名:\n");
scanf("%s", str);
fname = &str[0];
fp = fopen(fname, "rb");
if(fp == NULL) {
printf("%s not exit\n", fname);
exit(1);
}
memset(str, 0, sizeof(str));
fread(str, 1, 5, fp);
if(str[0] != 0x7f || str[1] != 'E' || str[2] != 'L' || str[3] != 'F') {
printf("%s is not an ELF file\n", fname);
exit(1);
}
OStype = str[4] == 1 ? 32 : 64; //判断elf文件为32位还是64位
printf("魔数检验通过,该文件为%d位ELF文件\n", OStype);
freopen("result.txt", "w", stdout);
printf(""); //清空文件内容
if(OStype == 64) {
print64(ELF_header_64_parse);
print64(section_header_64_parse);
print64(program_header_64_parse);
} else {
print32(ELF_header_32_parse);
print32(section_header_32_parse);
print32(program_header_32_parse);
}
return 0;
}