elf.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <stdint.h>
  4. #include <stdbool.h>
  5. // https://www.man7.org/linux/man-pages/man5/elf.5.html
  6. #include <elf.h>
  7. // #pragma pack(1)
  8. bool is_elf(const unsigned char* const buf, unsigned int bufsize, bool *is_64bit) {
  9. if (bufsize < EI_NIDENT) {
  10. return false;
  11. }
  12. bool valid = true;
  13. if (buf[0] != 0x7f) {// EI_MAG0
  14. valid = false;
  15. } else if (buf[1] != 'E') { // EI_MAG1
  16. valid = false;
  17. } else if (buf[2] != 'L') { // EI_MAG2
  18. valid= false;
  19. } else if (buf[3] != 'F') { // EI_MAG3
  20. valid = false;
  21. } else if (buf[EI_CLASS] == ELFCLASSNONE) {
  22. valid = false;
  23. } else if (buf[EI_CLASS] == ELFCLASS64) {
  24. *is_64bit = true;
  25. } else if (buf[EI_VERSION] == EV_NONE) {
  26. valid = false;
  27. }
  28. return valid;
  29. }
  30. void show_elf_header (Elf32_Ehdr* eh) {
  31. printf("e_ident = %s\n", eh -> e_ident);
  32. printf("e_machine = %x\n", eh -> e_machine);
  33. printf("e_version = %x\n", eh -> e_version);
  34. printf("e_entry = %x\n", eh -> e_entry);
  35. printf("e_phoff = %x\n", eh -> e_phoff);
  36. printf("e_shoff = %x\n", eh -> e_shoff);
  37. printf("e_flags = %x\n", eh -> e_flags);
  38. printf("e_phentsize = %x\n", eh -> e_phentsize);
  39. return;
  40. }
  41. void print_shdr(const Elf32_Shdr * const sh) {
  42. void print_type (uint32_t a) {
  43. switch (a) {
  44. case SHT_NULL:
  45. printf(" (SHT_NULL)\n");
  46. break;
  47. case SHT_PROGBITS:
  48. printf(" (SHT_PROGBITS)\n");
  49. break;
  50. case SHT_SYMTAB:
  51. printf(" (SHT_SYMTAB)\n");
  52. break;
  53. case SHT_STRTAB:
  54. printf(" (SHT_STRTAB)\n");
  55. break;
  56. case SHT_HASH:
  57. printf(" (SHT_HASH)\n");
  58. break;
  59. case SHT_DYNAMIC:
  60. printf(" (SHT_DYNAMIC)\n");
  61. break;
  62. case SHT_NOTE:
  63. printf(" (SHT_NOTE)\n");
  64. break;
  65. case SHT_NOBITS:
  66. printf(" (SHT_NOBITS)\n");
  67. break;
  68. case SHT_SHLIB:
  69. printf(" (SHT_SHLIB)\n");
  70. break;
  71. case SHT_DYNSYM:
  72. printf(" (SHT_DYNSYM)\n");
  73. break;
  74. case SHT_LOUSER:
  75. printf(" (SHT_NOTE)\n");
  76. break;
  77. case SHT_HIUSER:
  78. printf(" (SHT_NOTE)\n");
  79. break;
  80. default:
  81. if (SHT_LOPROC < a && a < SHT_HIPROC) {
  82. printf(" (reserved)\n");
  83. }
  84. break;
  85. }
  86. }
  87. if (sh == NULL) {
  88. printf("print_shdr: null ptr\n");
  89. return;
  90. }
  91. const char *names[] = {
  92. "sh_name", "sh_type", "sh_flags", "sh_addr", "sh_offset",
  93. "sh_size", "sh_link", "sh_info", "sh_addralign", "sh_entsize"
  94. };
  95. for (unsigned int i = 0; i < 10; ++i) {
  96. // all attributes in the 32-bit version are the same type
  97. uint32_t *x = (uint32_t*)((char*)sh + (sizeof(uint32_t) * i));
  98. printf("%s = %x", names[i], *x);
  99. switch (i) {
  100. default:
  101. printf("\n");
  102. break;
  103. case 1: // sh_type
  104. print_type(*x);
  105. break;
  106. }
  107. }
  108. }
  109. void print_phdr(const Elf32_Phdr* const ph) {
  110. if (ph == NULL) {
  111. return;
  112. }
  113. const char *names[] = {
  114. "p_type", "p_offset", "p_vaddr", "p_paddr",
  115. "p_filesz", "p_memsz", "p_flags", "p_align"
  116. };
  117. for (unsigned int i = 0; i < 8; i++) { // 8 = # of attributes
  118. uint32_t *x =(uint32_t*)((char*)ph + (sizeof(uint32_t) * i));
  119. printf("%s = %x\n", names[i], *x);
  120. }
  121. }
  122. // generic, load any binary file
  123. char *loadfile(const char *fname, unsigned int *s) {
  124. FILE *f = fopen(fname, "rb");
  125. unsigned int size = 0; // number of elements to buffer;
  126. unsigned int rcnt = 0; // number of char's read by fread(...)
  127. if (f == NULL) {
  128. perror("file handler is null ptr");
  129. return NULL;
  130. }
  131. // this method of determining file size works up to 2 GB.
  132. fseek(f, 0, SEEK_END);
  133. size = ftell(f);
  134. rewind(f);
  135. char *buf = (char*)malloc(sizeof(char) * size);
  136. if (buf == NULL) {
  137. perror("buf is null after malloc");
  138. free(buf);
  139. return NULL;
  140. }
  141. rcnt = fread(buf, sizeof(char), size, f);
  142. if (rcnt < size) {
  143. perror("read count < size");
  144. free(buf);
  145. return NULL;
  146. }
  147. fclose(f);
  148. *s = rcnt;
  149. return buf;
  150. }
  151. void* init(char * const buf, unsigned int offset, const unsigned int bufsize) {
  152. if (buf+offset > buf+bufsize) {
  153. printf("invalid (%x, %x)\n", buf+offset, buf+bufsize);
  154. return NULL;
  155. }
  156. return (buf+offset);
  157. }
  158. // print all program and section headers
  159. void test_00(Elf32_Ehdr * eh, char *buffer, unsigned int bufsize) {
  160. for (unsigned int i = 0; i < eh -> e_phnum; ++i) {
  161. printf("-- program header %.2i --\n", i);
  162. unsigned int offset = i * (eh -> e_phentsize) + eh -> e_phoff;
  163. Elf32_Phdr *p = init(buffer, offset, bufsize);
  164. print_phdr(p);
  165. printf("-----------------------\n");
  166. }
  167. for (unsigned int i = 0; i < eh -> e_shnum; ++i) {
  168. printf("-- section header %.2i --\n", i);
  169. Elf32_Shdr *sample;
  170. unsigned int offset = i * (eh -> e_shentsize) + eh -> e_shoff;
  171. sample = init(buffer, offset, bufsize);
  172. print_shdr(sample);
  173. printf("-----------------------\n");
  174. }
  175. }
  176. void test_01(Elf32_Ehdr *eh, unsigned int i, const unsigned int bufsize) {
  177. char *buf = (char*)eh; // beginning of file
  178. // get ith section
  179. if (i > eh -> e_shnum) {
  180. return;
  181. }
  182. unsigned int offset = i * (eh -> e_shentsize) + eh -> e_shoff;
  183. const Elf32_Shdr *s = init(buf, offset, bufsize);
  184. const unsigned char *section = buf + s -> sh_offset;
  185. }
  186. int main(int argc, char ** argv) {
  187. if (argc < 2) {
  188. printf("usage: program filename\n");
  189. return 0;
  190. }
  191. unsigned int bufsize = 0;
  192. char *f = argv[1];
  193. char *buffer = loadfile(f, &bufsize);
  194. bool is_64;
  195. if (!is_elf(buffer, bufsize, &is_64)) {
  196. return 0;
  197. }
  198. Elf32_Ehdr *eh;
  199. eh = (Elf32_Ehdr*)buffer;
  200. show_elf_header(eh);
  201. test_00(eh, buffer, bufsize);
  202. test_01(eh, 1, bufsize);
  203. free(buffer);
  204. return 0;
  205. }