LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1640|回复: 14

俺写的分析elf文件的程序

[复制链接]
发表于 2005-6-14 15:58:25 | 显示全部楼层 |阅读模式
俺这几天正在学习elf文件格式,顺便写了个小程序分析文件格式,总感觉按书上说的不太直观,尽管有一些分析elf文件的工具,比如objdump和readelf,但是自己写个程序分析一下更能理解.这个程序格式可能不太符合标准,俺没有开发过正规的项目所以还请见谅.只是希望能够对学习elf文件格式的sir们有些帮助..
现在只能分析程序头表,节表,串表,和符号表,俺正在学习动态联结的过程(借助理解elf文件的相应结构),还希望懂得这个的sir们给点儿帮助------

  1. /**********************************************************************
  2. * file:elf_file.c
  3. * date:   T六  6月 10 10:19:13 CST 2005
  4. * Author: l1u6uddy
  5. * Last Modified: 6月14 日
  6. *
  7. * Description: 这个程序简单的分析了elf文件的格式;
  8. *
  9. *   
  10. *   
  11. *   
  12. *
  13. * Compile with:
  14. * gcc elf_file.c -o elf_file
  15. * Usage:
  16. *./elf_file a_elf_file_name
  17. ***********************************************************************/
  18. #include <stdio.h>
  19. #include <unistd.h>
  20. #include <sys/mman.h>
  21. #include <sys/stat.h>
  22. #include <sys/types.h>
  23. #include <fcntl.h>
  24. #include <stdio.h>

  25. #define EI_NIDENT 16
  26. #define Elf32_Addr unsigned int
  27. #define Elf32_Half unsigned short
  28. #define Elf32_Off unsigned int
  29. #define Elf32_SWord unsigned int
  30. #define Elf32_Word unsigned int

  31. #define ELF_ST_BIND(x)                ((x) >> 4)
  32. #define ELF_ST_TYPE(x)                (((unsigned int) x) & 0xf)
  33. #define ELF32_ST_BIND(x)        ELF_ST_BIND(x)
  34. #define ELF32_ST_TYPE(x)        ELF_ST_TYPE(x)
  35. #define ELF64_ST_BIND(x)        ELF_ST_BIND(x)
  36. #define ELF64_ST_TYPE(x)        ELF_ST_TYPE(x)

  37. struct  Elf32_Ehd{
  38. unsigned char e_ident[EI_NIDENT];
  39. Elf32_Half e_type;
  40. Elf32_Half e_machine;
  41. Elf32_Word e_version;
  42. Elf32_Addr e_entry;
  43. Elf32_Off e_phoff;
  44. Elf32_Off e_shoff;
  45. Elf32_Word e_flags;
  46. Elf32_Half e_ehsize;
  47. Elf32_Half e_phentsize;
  48. Elf32_Half e_phnum;
  49. Elf32_Half e_shentsize;
  50. Elf32_Half e_shnum;
  51. Elf32_Half e_shstrndx;
  52. };

  53. struct Elf32_Phdr{
  54.   Elf32_Word p_type;
  55.   Elf32_Off p_offset;
  56.   Elf32_Addr p_vaddr;
  57.   Elf32_Addr p_paddr;
  58.   Elf32_Word p_filesz;
  59.   Elf32_Word p_memsz;
  60.   Elf32_Word p_flags;
  61.   Elf32_Word p_align;
  62. };

  63. struct Elf32_Shdr{
  64.   Elf32_Word sh_name;
  65.   Elf32_Word sh_type;
  66.   Elf32_Word sh_flags;
  67.   Elf32_Addr sh_addr;
  68.   Elf32_Off sh_offset;
  69.   Elf32_Word sh_size;
  70.   Elf32_Word sh_link;
  71.   Elf32_Word sh_info;
  72.   Elf32_Word sh_addralign;
  73.   Elf32_Word sh_entsize;
  74. };

  75. typedef struct elf32_sym{
  76.   Elf32_Word        st_name;
  77.   Elf32_Addr        st_value;
  78.   Elf32_Word        st_size;
  79.   unsigned char        st_info;
  80.   unsigned char        st_other;
  81.   Elf32_Half        st_shndx;
  82. } Elf32_Sym;



  83. void print_Phdr_list(FILE* file,Elf32_Half phentsize,Elf32_Half phnum);
  84. void print_Phdr(struct Elf32_Phdr * phdr);
  85. void print_Shdr_list(FILE* file,Elf32_Half shentsize,Elf32_Half shnum);
  86. void print_Shdr(struct Elf32_Shdr * shdr);
  87. void * read_shname_table();
  88. void print_shname( Elf32_Word offset);
  89. void print_Sym( Elf32_Off sym_off,Elf32_Word sym_size );
  90. void print_Sym_element( Elf32_Sym * sym_element);
  91. void print_Sym_element_name( Elf32_Word offset);
  92. struct Elf32_Ehd * ehd;
  93.   void *mapf;
  94.    void * shname_table;
  95.   FILE *fp;
  96. int main(int argc,char* argv[])
  97. {

  98.   int fd;
  99.   void *start;
  100.   int len;

  101.   // struct  Elf32_Ehdr *ehdr;


  102.   
  103.   ehd=(struct Elf32_Ehd *)malloc(sizeof(struct Elf32_Ehd));

  104. fp = fopen(argv[1],"rb");         //// 打开elf格式文件,文件名为file
  105. if(fp == NULL)
  106.   return ;
  107. fseek(fp, 0, SEEK_END);
  108. len = ftell(fp);                  //// 得到文件的大小
  109. if(len <(sizeof(struct Elf32_Ehd)))
  110. {                                 
  111.   printf("File Size too Samll!\n");
  112.   return 0;
  113. }

  114. mapf=mmap(NULL,len,PROT_READ,MAP_PRIVATE,fp,0);

  115. rewind(fp);
  116.   fread(ehd,sizeof(struct Elf32_Ehd) , 1, fp);                  ////* 读取ELF文件头 */

  117. if( (ehd->e_ident[0]== 0x7f)&&( ehd->e_ident[1]== 'E') && (ehd->e_ident[2]== 'L') && (ehd->e_ident[3]== 'F'))
  118. {
  119.    printf("the file is a elf file\n");
  120.    if(ehd->e_type==1)
  121.      printf("可重定位文件\n");
  122.    else
  123.      if(ehd->e_type=2)
  124.        printf("可执行文件\n");
  125.      else
  126.        if(ehd->e_type==3)
  127.          printf("共享目标文件\n");
  128.    

  129.    if(ehd->e_machine==3)
  130.      printf("Intel 80386\n");
  131.    if(ehd->e_version==1)
  132.      printf("当前版本\n");
  133.    
  134.    printf("程序起动的虚拟地址为:%u\n",ehd->e_entry);

  135.    printf("程序头表的以字节为单位的文件偏移为:%u\n",ehd->e_phoff);
  136.    
  137.    printf("e_flags=%x\n",ehd->e_flags);

  138.    printf("该elf文件头字节的长度为:%d\n",ehd->e_ehsize);

  139.    printf("程序头表中一个表项的字节长度为:%d\n",ehd->e_phentsize);

  140.    printf("程序头表中表项的数目为:%d\n",ehd->e_phnum);

  141.    printf("节头的字节长度为:%d\n",ehd->e_shentsize);

  142.    printf("节头表中的表项数目:%d\n",ehd->e_shnum);

  143.    printf("节名串表的索引是%u\n",ehd->e_shstrndx);

  144.    if(ehd->e_phnum!=0)
  145.      {
  146.        //分析程序头表
  147.        fseek(fp,ehd->e_phoff,SEEK_SET);
  148.        print_Phdr_list(fp,ehd->e_phentsize,ehd->e_phnum);   
  149.      }
  150.    
  151.    if(ehd->e_shnum!=0)
  152.      {
  153.        shname_table=read_shname_table();
  154.       //分析节头表

  155.        fseek(fp,ehd->e_shoff,SEEK_SET);
  156.        print_Shdr_list(fp,ehd->e_shentsize,ehd->e_shnum);
  157.      }
  158.    
  159.    

  160. }else
  161.    {
  162.      printf("this file is not a elf file\n");
  163.    }

  164. }

  165. void print_Phdr_list(FILE* file,Elf32_Half phentsize,Elf32_Half phnum)
  166. {
  167.   int i=0;

  168. struct Elf32_Phdr * e_Phdr;
  169.   e_Phdr=(struct Elf32_Phdr *) malloc(sizeof(struct Elf32_Phdr));
  170.   if(phentsize!=sizeof(struct Elf32_Phdr))
  171.       {
  172.      printf("phentsize!=sizeof(struct Elf32_Phdr)\n");
  173.      exit(0);
  174.       }
  175.   for(i=0;i<phnum;i++)
  176.     {
  177.       printf("第%d个段的信息:\n",i);
  178.       fread(e_Phdr,phentsize,1,file);
  179.       print_Phdr(e_Phdr);
  180.       printf("\n");
  181.     }

  182. }

  183. void print_Phdr(struct Elf32_Phdr * phdr)
  184. {
  185.   switch(phdr->p_type)
  186.     {
  187.     case 0:
  188.       printf("空,该数组元素没有使用\n");
  189.       break;
  190.     case 1:
  191.       printf("该段为可装入段\n");
  192.       break;
  193.     case 2:
  194.       printf("该数组元素说明了动态联接信息\n");
  195.       break;
  196.     case 3:
  197.       printf("该元素说明调用解释程序的位置和长度,该路径位置以空结尾\n");
  198.       break;
  199.     case 4:
  200.       printf("该元素说明辅助信息的位置和长度\n");
  201.       break;
  202.     case 5:
  203.       printf("保留.未使用\n");
  204.       break;
  205.     case 6:
  206.       printf("该元素说明在程序的文件映象和其内存映象中的程序头表头本身的位置和长度\n");
  207.       break;
  208.     default :
  209.       printf("处理机专用语义:%x\n",phdr->p_type);
  210.     }
  211.   
  212.   printf("该段在文件中的位移为:0x%x\n",phdr->p_offset);
  213.   
  214.   printf("该段的虚存地址为:%u\n",phdr->p_vaddr);

  215.   printf("p_paddr=%u\n",phdr->p_paddr);
  216.   
  217.   printf("该段的文件映象中字节的数目:0x%x\n",phdr->p_filesz);

  218.   printf("该段的内存映象的字节的数目:0x%x\n",phdr->p_memsz);

  219.   printf("该段段权限:");

  220.   Elf32_Word flag1,flag2,flag3;
  221.   flag1=phdr->p_flags&0x1;
  222.   flag2=phdr->p_flags&0x2;
  223.   flag3=phdr->p_flags&0x4;
  224.   if(flag1==1)
  225.     {
  226.       printf("执行 ");
  227.     }
  228.   if(flag2==2)
  229.     {
  230.       printf("写 ");
  231.     }
  232.   if(flag3==4)
  233.     {
  234.       printf("读 ");
  235.     }
  236.   printf("\n");
  237. }
  238. void print_Shdr_list(FILE* file,Elf32_Half shentsize,Elf32_Half shnum)
  239. {
  240. int j=0;

  241. struct Elf32_Shdr * e_Shdr;
  242.   e_Shdr=(struct Elf32_Shdr *) malloc(sizeof(struct Elf32_Shdr));
  243.   if(shentsize!=sizeof(struct Elf32_Shdr))
  244.       {
  245.      printf("shentsize!=sizeof(struct Elf32_Shdr)\n");
  246.      exit(0);
  247.       }
  248.   for(j=0;j<shnum;j++)
  249.     {
  250.       
  251.       printf("第%d个节的信息:\n",j);
  252.       /*  
  253.       if(j==ehd->e_shstrndx)
  254.         {
  255.           long temp;

  256.           temp=ftell(file);
  257.           
  258.           printf("%x\n",(Elf32_Off)temp);
  259.      
  260.         }
  261.       */
  262.       fread(e_Shdr,shentsize,1,file);
  263.       print_Shdr(e_Shdr);
  264.       printf("\n");
  265.     }
  266. }
  267. void print_Shdr(struct Elf32_Shdr * shdr)
  268. {
  269.   printf("节名在节头串表节的索引为:%u\n",shdr->sh_name);

  270.   //打印节名
  271.     print_shname(shdr->sh_name);
  272. /*
  273.   Elf32_Off Shdr_offset,S_offset;
  274.   //  Elf32_
  275.   Shdr_offset=ehd->e_shoff+ehd->e_shentsize*ehd->e_shstrndx;
  276.   printf("%x\n",Shdr_offset);
  277.   rewind(fp);
  278.   fseek(fp,Shdr_offset,SEEK_SET);
  279.   fread(ehd,sizeof(struct Elf32_Ehd) , 1, fp);   
  280.   // printf("sh_offset=%u",temp->sh_offset);
  281.   //  printf("节名表的偏移是:%x\n",((struct Elf32_Shdr *)(ehd->e_shoff+ehd->e_shentsize*ehd->e_shstrndx))->sh_offset);
  282.   //   printf("节名为:%s",(char *)(((struct Elf32_Shdr *)(ehd->e_shoff+ehd->e_shentsize*ehd->e_shstrndx))->sh_offset+shdr->sh_name+mapf));
  283.   */
  284.   //type
  285.   switch(shdr->sh_type)
  286.     {
  287.     case 0:
  288.       printf("该节头不活动,没有与其相应的节.节头中其它成员的值没有定义\n");
  289.       break;
  290.     case 1:
  291.       printf("该节保存有程序定义的信息.\n");
  292.       break;
  293.     case 2:
  294.       printf("该节存放符号表.\n");
  295.       print_Sym(shdr->sh_offset,shdr->sh_size);
  296.       break;
  297.     case 3:
  298.       printf("该节存放串表.\n");
  299.       break;
  300.     case 4:
  301.       printf("该节存放带有显式加数的重定位表项.\n");
  302.       break;
  303.     case 5:
  304.       printf("该节存放符号散列表.\n");
  305.       break;
  306.     case 6:
  307.       printf("该节存放动态联接的信息.\n");
  308.       break;
  309.     case 7:
  310.       printf("该节存放以某种方式标记的文件的信息.\n");
  311.       break;
  312.     case 8:
  313.       printf("该类型的节不占文件空间\n");
  314.       break;
  315.     case 9:
  316.       printf("该节存放不带显式加数的重定位表项.\n");
  317.       break;
  318.     case 10:
  319.       printf("类型被保留,没有指定语义\n");
  320.       break;
  321.     case 11:
  322.       printf("该节存放符号表.\n");
  323.       print_Sym(shdr->sh_offset,shdr->sh_size);
  324.       break;
  325.       
  326.     default:
  327.       printf("%x\n",shdr->sh_type);
  328.     }
  329.   
  330.   printf("标志为:%x--->",shdr->sh_flags);
  331.   Elf32_Word flag1,flag2,flag3;
  332.   flag1=shdr->sh_flags&0x1;
  333.   flag2=shdr->sh_flags&0x2;
  334.   flag3=shdr->sh_flags&0x4;
  335.   if(flag1==1)
  336.     {
  337.       printf("包含进程执行时可以写的数据 ");
  338.     }
  339.   if(flag2==2)
  340.     {
  341.       printf("该节在进程执行其间占用内存  ");
  342.     }
  343.   if(flag3==4)
  344.     {
  345.       printf("该节包含可执行的程序指令  ");
  346.     }
  347.   printf("\n");

  348.   printf("该节的第一个字节将存放在内存映象中的:0x%x\n",shdr->sh_addr);

  349.   printf("该节的位移为:0x%x\n",shdr->sh_offset);

  350.   printf("该节的字节长度为:0x%x\n",shdr->sh_size);



  351. }

  352. void print_shname( Elf32_Word offset)
  353. {
  354.   // void * name_table;
  355.   // printf("now,read the table\n");
  356.   // name_table=read_shname_table();
  357.   printf("该节的节名为:%s\n",shname_table+offset);
  358. }
  359. void * read_shname_table()
  360. {
  361. Elf32_Off Shdr_offset,S_offset;

  362.    struct   Elf32_Shdr *shname_shdr;
  363.   shname_shdr=(struct Elf32_Shdr*)malloc(sizeof(struct Elf32_Shdr));
  364. Shdr_offset=ehd->e_shoff+ehd->e_shentsize*ehd->e_shstrndx;

  365.      rewind(fp);
  366.    
  367.   fseek(fp,Shdr_offset,SEEK_SET);
  368.   fread(shname_shdr,sizeof(struct Elf32_Shdr) , 1, fp);
  369.   S_offset=shname_shdr->sh_offset;
  370.   shname_table=malloc(shname_shdr->sh_size);

  371.   rewind(fp);
  372.   fseek(fp,S_offset,SEEK_SET);
  373.    fread(shname_table,shname_shdr->sh_size,1,fp);
  374.   return shname_table;
  375. }

  376. void print_Sym( Elf32_Off sym_off,Elf32_Word sym_size)
  377. {
  378.   //首先应该保存文件指针
  379.   long file_point;
  380.   file_point=ftell(fp);
  381.   //重定位文件指针
  382.   fseek(fp,sym_off,SEEK_SET);
  383.   //获得存储空间,读取符号表
  384.   void * sym_table;
  385.   sym_table=malloc(sym_size);
  386.   fread( sym_table,sym_size,1,fp);
  387.   int n,i;
  388.   n=sym_size/sizeof( Elf32_Sym );
  389.   printf("现在打印符号表信息:\n");
  390.   for( i=0;i<n;i++ )
  391.     {
  392.       printf( "  符号%d的信息:\n",i);
  393.       print_Sym_element( (Elf32_Sym *)(sym_table+i*sizeof( Elf32_Sym )) );
  394.     }

  395. //恢复文件指针
  396.   fseek(fp,file_point,SEEK_SET);
  397.   
  398. }
  399. void print_Sym_element( Elf32_Sym * sym_element )
  400. {
  401.   print_Sym_element_name( sym_element->st_name );
  402.   printf("    该符号的值为:0x%x\n",sym_element->st_value );
  403.   printf("    该符号的字节大小为:0x%x\n",sym_element->st_size);
  404.   unsigned char temp;
  405.   temp=sym_element->st_info;
  406.   switch( ELF32_ST_BIND( temp ) )
  407.     {
  408.     case 0:
  409.       printf("    该符号为局部符号(STB_LOCAL)\n");
  410.       break;
  411.     case 1:
  412.       printf("    该符号为全局符号(STB_GLOBAL)\n");
  413.       break;
  414.     case 2:
  415.       printf("    该符号为弱符号(STB_WEAK)\n");
  416.       break;
  417.     default:
  418.       printf("    该符号为处理机专用\n");
  419.     }
  420.   temp=sym_element->st_info;
  421.   switch( ELF32_ST_TYPE( temp ) )
  422.     {
  423.     case 0:
  424.       printf( "    该符号类型没有定义\n");
  425.       break;
  426.     case 1:
  427.       printf( "    该符号与变量数组等有关\n");
  428.       break;
  429.     case 2:
  430.       printf( "    该符号与函数和可执行代码有关\n");
  431.       break;
  432.     case 3:
  433.       printf( "    该符号与一个节有关\n");
  434.       break;
  435.     case 4:
  436.       printf( "    该符号的名称给出了对应于目标文件的源文件的名字\n");
  437.       break;
  438.     default:
  439.       printf( "    该符号的值为处理机专用\n");
  440.     }
  441. }

  442. void print_Sym_element_name( Elf32_Word offset)
  443. {
  444.   printf("    该符号的名称为:%s\n",shname_table+offset);
  445. }

复制代码
发表于 2005-6-14 20:49:09 | 显示全部楼层
自己定个程序来了解elf的结构是不错的。
ps:可以不需要定义那么多宏吧。linux系统上就有elf.h,直接使用它不是更省事吗?
同时建议不要用#define类型定义成宏。用typedef。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-6-14 23:57:37 | 显示全部楼层
Post by kj501
自己定个程序来了解elf的结构是不错的。
ps:可以不需要定义那么多宏吧。linux系统上就有elf.h,直接使用它不是更省事吗?
同时建议不要用#define类型定义成宏。用typedef。

谢谢kj501的建议,我原先不知道elf.h这个头文件,所以,呵呵-----
等我知道的时候程序已经写的差不多了,所以也没有改,本来就是一个自己写着玩儿的程序...所以没有那样严格....
不过俺以后会注意的,谢谢了-----
回复 支持 反对

使用道具 举报

发表于 2005-6-17 12:18:02 | 显示全部楼层
不去调用也有好处呀,不是学习吗?
不过不知道分析这个有什么用啊?
难道想写病毒?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-6-17 16:26:36 | 显示全部楼层
不是了,只是想了解一下而已----
回复 支持 反对

使用道具 举报

发表于 2005-6-17 19:16:05 | 显示全部楼层
这么长的程序,我还从来没有写过!





/*我是菜鸟*/
回复 支持 反对

使用道具 举报

发表于 2005-6-17 21:13:34 | 显示全部楼层
这个东西很有用的!不错。
但有个建议,不要在main函数之外的任何函数里调用输出(printf),而是把elf格式里的信息分析到结构体里,然后返回。在main里再把信息打印出来。
当然了,最好是连main也不要,做成一个elf格式分析的库。
回复 支持 反对

使用道具 举报

发表于 2005-6-17 21:18:17 | 显示全部楼层
有篇文章可以参考:http://www.muppetlabs.com/~breadbox/software/ELF.txt

kj 读 linkers & loaders 读的怎么样了?
什么时候写个心得啊?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-6-18 01:03:18 | 显示全部楼层
Post by Tetris
这个东西很有用的!不错。
但有个建议,不要在main函数之外的任何函数里调用输出(printf),而是把elf格式里的信息分析到结构体里,然后返回。在main里再把信息打印出来。
当然了,最好是连main也不要,做成一个elf格式分析的库。

分析elf文件格式的工具已经很多了,比如bjdump和readelf,,这些已经足够了。我写这个程序的目的只是想更好的学习了解elf而已,没想那么多了。。。
如果把按照Tetris的这样做,是不是很麻烦???我不知道为什么不建议在main函数之外调用printf???
回复 支持 反对

使用道具 举报

 楼主| 发表于 2005-6-18 01:04:33 | 显示全部楼层
Post by rickxbx
有篇文章可以参考:http://www.muppetlabs.com/~breadbox/software/ELF.txt

kj 读 linkers & loaders 读的怎么样了?
什么时候写个心得啊?

感谢提供的这份资料,我大体看了一下,好像我看的这份资料就是它的中文翻译,书名为:<<UNIX系统V第4版 程序员指南:ANSI C 和编程支持工具>>,后边有一章第13章:目标文件 就是这篇文章的中文翻译,另外这篇文章好像网上有人翻译过http://elfhack.whitecell.org/mydocs/ELF_chinese.txt,,,,
我也在学习linkers&loaders,刚开始看第一章----
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表