3——Linuxバイナリ分析——学習——簡易ELF解析器


第2章の最後に、著者はELF解析器のコードを貼って、私は繰り返しの試みを行って、ELFフォーマットに対する理解を深めました.これは、すべてのsectionヘッダ名と実行可能なプログラム内の仮想アドレス、programヘッダのアドレスを印刷する簡単なreadefです.
理解しやすいように、いくつかの場所で自分の注釈を加えました.例えばmmap()のコメント、line 92の前の3行対e_shstrndxの解釈、そして冒頭の3つの構造体の解釈.
以前「Linuxカーネルを深く理解する」を見たときにmmap()を見たことがありますが、今回はmmap()の具体的な機能を本当に調べてみました.共有メモリがmmap()技術で実現されたとは思わなかった.同じメモリをマッピング(map)すると、同じメモリを操作したり、読み書きしたりすることができ、プロセス間通信を実現することができる.共有メモリのほかにも、メモリとしてハードディスクを割り当てて使用するというより広い応用シーンがあります.
次はコードを貼って、簡単なmain()関数で、少しも複雑ではありません.最初の行のコメントに従ってコンパイルすればいいです.コードに使われている構造体はすべてelfです.hシステムヘッダファイルで定義します.どの完全なlinuxシステムにも存在し、linuxカーネルコードにも存在します.Windows編集を使用する場合はelfをコピーすることをお勧めします.h自分の工事に着く.
/* elfparse.c - gcc elfparse.c -o elfparse */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
    printf("XBter!
"); int fd, i; uint8_t *mem; struct stat st; char *StringTable, *interp; Elf32_Ehdr *ehdr;//ELF file header Elf32_Phdr *phdr;//program header Elf32_Shdr *shdr;//section header if(argc < 2){ printf("Usage: %s
", argv[0]); exit(0); } if((fd = open(argv[1], O_RDONLY)) < 0){ perror("open"); exit(-1); } if(fstat(fd, &st) < 0){ perror("fstat"); exit(-1); } /* Map the executable into memory */ mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if(mem == MAP_FAILED){/*mmap may have many fuctions. I read*/ perror("mmap");/*a blog, share memory, Changing disk to*/ exit(-1);/*memory when memory is not enough may all use*/ }/*mmap(). This is real mapping. This is the blog address: */ /*https://blog.csdn.net/yanerhao/article/details/77829191 */ /** * The initial ELF Header starts at offset 0 * of our mapped memory */ ehdr = (Elf32_Ehdr*)mem; /** * The shdr table and phdr table offsets are * given by e_shoff and e_phoff members of the * ELF32_Ehdr */ phdr = (Elf32_Phdr*)&mem[ehdr->e_phoff]; shdr = (Elf32_Shdr*)&mem[ehdr->e_shoff]; /** * Check to see if the ELF magic (The first 4 bytes) * match up as 0x7f E L F (0x7f 45 4c 46) */ if(mem[0] != 0x7f && strcmp(&mem[1], "ELF")){ fprintf(stderr, "%s is not an ELF file
", argv[1]); exit(-1); } /** * We are only parsing executables with this code * so ET_EXEC marks an executables. */ if(ehdr->e_type != ET_EXEC){ fprintf(stderr, "%s is not an executable
", argv[1]); exit(-1); } printf("Program Entry point: 0x%x
", ehdr->e_entry); /** * We find the string table for the section header * names with e_shstrndx which gives the index of * which section holds the string table. * e_shstrndx is the index of section .shstrtab * .shstrtab holds all sections's name, just a strings * ending with /0. */ StringTable = &mem[shdr[ehdr->e_shstrndx].sh_offset]; /** * Print each section header name and address. * Notice we get the index into the string table * that contains each section header name with * the shdr.sh_name member. */ printf("Section header total:%d list:

", ehdr->e_shnum); for(i = 0; i < ehdr->e_shnum; i++) printf("[%d]%s: 0x%x
", i, &StringTable[shdr[i].sh_name], shdr[i].sh_addr); /** * Print out each segment name, and address. * Except for PT_INTERP we print the path to * the dynamic linker (Interpreter). */ printf("
Program header total:%d list:

", ehdr->e_phnum); for(i = 0; i < ehdr->e_phnum; i++){ // printf("phdr[%d].p_type=%d
", i, phdr[i].p_type); switch(phdr[i].p_type){ case PT_LOAD: /** * We know that text segment starts * at offset 0. And only one other * possible loadable segment exists * which is the data segment. */ if(phdr[i].p_offset == 0) printf("Text segment: 0x%x
", phdr[i].p_vaddr); else printf("Data segment: 0x%x
",phdr[i].p_vaddr); break; case PT_INTERP: interp = strdup((char*)&mem[phdr[i].p_offset]); printf("Interpreter: %s
", interp); break; case PT_NOTE: printf("Note segment: 0x%x
", phdr[i].p_vaddr); break; case PT_DYNAMIC: printf("Dynamic segment: 0x%x
", phdr[i].p_vaddr); break; case PT_PHDR: printf("Phdr segment: 0x%x
", phdr[i].p_vaddr); break; } } exit(0); }