根据ELF文件的结构进行解析
- 打开并判断是不是ELF64位二进制文件
读取后记得重置文件指针到开头。
int is_elf_64(FILE* fp)
{
char buf[16];
int nread = fread(buf, 1, 16, fp);
fseek(fp, 0, SEEK_SET);
if (nread < 16) {
return 1;
}
if (strncmp(buf, ELFMAG, SELFMAG)) {
return 1;
}
if (buf[EI_CLASS] != ELFCLASS64) {
return 1;
}
return 0;
}
FILE* felf = fopen(argv[1], "r");
if (!felf) {
printf("open %s failed.\n", argv[1]);
return 1;
}
if (is_elf_64(felf)) {
printf("file type mismatch.\n");
return 1;
}
- 读取ELF文件头
Elf64_Ehdr m_elf;
fread(&m_elf, 1, sizeof(m_elf), felf);
- 读取所有段结构
Elf64_Shdr arSection[m_elf.e_shnum];
fseek(felf, m_elf.e_shoff, SEEK_SET);
fread(&arSection[0], 1, (m_elf.e_shnum * m_elf.e_shentsize), felf);
- 读取段名字索引
char arSectionNames[arSection[m_elf.e_shstrndx].sh_size];
fseek(felf, arSection[m_elf.e_shstrndx].sh_offset, SEEK_SET);
fread(&arSectionNames, 1, sizeof(arSectionNames), felf);
- 读取段结构和段名字
SectionMap m_mpSections[m_elf.e_shnum];
for (Elf64_Half i = 0; i < m_elf.e_shnum; i++) {
m_mpSections[i].name = &arSectionNames[0] + arSection[i].sh_name;
m_mpSections[i].shdr = arSection[i];
}
- 输出相关信息
const char findSectionName[] = ".dynstr";
// 遍历每一个段
for (Elf64_Half i = 0; i < m_elf.e_shnum; i++) {
// 输出每个段的名字
printf("section name :%s\n", m_mpSections[i].name);
// 输出“.dynstr”段的内容
if (!strcmp(m_mpSections[i].name, findSectionName)) {
unsigned char content[m_mpSections[i].shdr.sh_size];
fseek(felf, m_mpSections[i].shdr.sh_offset, SEEK_SET);
fread(content, 1, m_mpSections[i].shdr.sh_size, felf);
for (Elf64_Xword j = 0; j < m_mpSections[i].shdr.sh_size; ++j)
printf("%c", content[j]);
// printf("%02x", content[i]);对于非字符内容,应该输出十六机制。
}
}
完整代码
#include <elf.h>
#include <stdio.h>
#include <string.h>
typedef struct {
char* name;
Elf64_Shdr shdr;
} SectionMap;
/**
* 判断是否是ELF64文件。
*/
int is_elf_64(FILE* fp)
{
char buf[16];
int nread = fread(buf, 1, 16, fp);
fseek(fp, 0, SEEK_SET);
if (nread < 16) {
return 1;
}
if (strncmp(buf, ELFMAG, SELFMAG)) {
return 1;
}
if (buf[EI_CLASS] != ELFCLASS64) {
return 1;
}
return 0;
}
int main(int argc, char const* argv[])
{
if (argc != 2) {
printf("usage : %s elf_file\n", argv[0]);
return 1;
}
FILE* felf = fopen(argv[1], "r");
if (!felf) {
printf("open %s failed.\n", argv[1]);
return 1;
}
if (is_elf_64(felf)) {
printf("file type mismatch.\n");
return 1;
}
// 1 读取elf头文件
Elf64_Ehdr m_elf;
fread(&m_elf, 1, sizeof(m_elf), felf);
// 2 读取所有段结构
Elf64_Shdr arSection[m_elf.e_shnum];
fseek(felf, m_elf.e_shoff, SEEK_SET);
fread(&arSection[0], 1, (m_elf.e_shnum * m_elf.e_shentsize), felf);
// 3 读取段名字索引
char arSectionNames[arSection[m_elf.e_shstrndx].sh_size];
fseek(felf, arSection[m_elf.e_shstrndx].sh_offset, SEEK_SET);
fread(&arSectionNames, 1, sizeof(arSectionNames), felf);
// 4 读取段结构和段名字
SectionMap m_mpSections[m_elf.e_shnum];
for (Elf64_Half i = 0; i < m_elf.e_shnum; i++) {
m_mpSections[i].name = &arSectionNames[0] + arSection[i].sh_name;
m_mpSections[i].shdr = arSection[i];
}
const char findSectionName[] = ".dynstr";
// 遍历每一个段
for (Elf64_Half i = 0; i < m_elf.e_shnum; i++) {
// 输出每个段的名字
printf("section name :%s\n", m_mpSections[i].name);
// 输出“.dynstr”段的内容
if (!strcmp(m_mpSections[i].name, findSectionName)) {
unsigned char content[m_mpSections[i].shdr.sh_size];
fseek(felf, m_mpSections[i].shdr.sh_offset, SEEK_SET);
fread(content, 1, m_mpSections[i].shdr.sh_size, felf);
for (Elf64_Xword j = 0; j < m_mpSections[i].shdr.sh_size; ++j)
printf("%c", content[j]);
// printf("%02x", content[i]);对于非字符内容,应该输出十六机制。
}
}
printf("\n");
fclose(felf);
return 0;
}
运行
$ g++ main.cc
$ ./a.out ./a.out
section name :
section name :.interp
section name :.note.gnu.property
section name :.note.gnu.build-id
section name :.note.ABI-tag
section name :.gnu.hash
section name :.dynsym
section name :.dynstr
libc.so.6fopenstrncmpputs__stack_chk_failputcharprintffseekfclosefread__cxa_finalizestrcmp__libc_start_mainGLIBC_2.4GLIBC_2.2.5_ITM_deregisterTMCloneTable__gmon_start___ITM_registerTMCloneTablesection name :.gnu.version
section name :.gnu.version_r
section name :.rela.dyn
section name :.rela.plt
section name :.init
section name :.plt
section name :.plt.got
section name :.plt.sec
section name :.text
section name :.fini
section name :.rodata
section name :.eh_frame_hdr
section name :.eh_frame
section name :.init_array
section name :.fini_array
section name :.dynamic
section name :.got
section name :.data
section name :.bss
section name :.comment
section name :.symtab
section name :.strtab
section name :.shstrtab