elf.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <stdint.h>
  4. #include <stdbool.h>
  5. // for memcpy
  6. #include <string.h>
  7. // https://www.man7.org/linux/man-pages/man5/elf.5.html
  8. #include <elf.h>
  9. // #pragma pack(1)
  10. bool is_elf(const unsigned char* const buf, unsigned int bufsize, bool *is_64bit) {
  11. if (bufsize < EI_NIDENT) {
  12. return false;
  13. }
  14. bool valid = true;
  15. if (buf[0] != 0x7f) {// EI_MAG0
  16. valid = false;
  17. }
  18. if (buf[1] != 'E') { // EI_MAG1
  19. valid = false;
  20. }
  21. if (buf[2] != 'L') { // EI_MAG2
  22. valid= false;
  23. }
  24. if (buf[3] != 'F') { // EI_MAG3
  25. valid = false;
  26. }
  27. if (buf[EI_CLASS] == ELFCLASSNONE) {
  28. valid = false;
  29. }
  30. if (buf[EI_CLASS] == ELFCLASS64) {
  31. *is_64bit = true;
  32. } else {
  33. *is_64bit = false;
  34. }
  35. if (buf[EI_VERSION] == EV_NONE) {
  36. valid = false;
  37. }
  38. return valid;
  39. }
  40. void show_elf_header (Elf32_Ehdr* eh) {
  41. printf("e_ident = %s\n", eh -> e_ident);
  42. printf("e_machine = %x\n", eh -> e_machine);
  43. printf("e_version = %x\n", eh -> e_version);
  44. printf("e_entry = %x\n", eh -> e_entry);
  45. printf("e_phoff = %x\n", eh -> e_phoff);
  46. printf("e_shoff = %x\n", eh -> e_shoff);
  47. printf("e_flags = %x\n", eh -> e_flags);
  48. printf("e_phentsize = %x\n", eh -> e_phentsize);
  49. return;
  50. }
  51. void print_shdr(const Elf32_Shdr * const sh) {
  52. void print_type (uint32_t a) {
  53. switch (a) {
  54. case SHT_NULL:
  55. printf(" (SHT_NULL)\n");
  56. break;
  57. case SHT_PROGBITS:
  58. printf(" (SHT_PROGBITS)\n");
  59. break;
  60. case SHT_SYMTAB:
  61. printf(" (SHT_SYMTAB)\n");
  62. break;
  63. case SHT_STRTAB:
  64. printf(" (SHT_STRTAB)\n");
  65. break;
  66. case SHT_HASH:
  67. printf(" (SHT_HASH)\n");
  68. break;
  69. case SHT_DYNAMIC:
  70. printf(" (SHT_DYNAMIC)\n");
  71. break;
  72. case SHT_NOTE:
  73. printf(" (SHT_NOTE)\n");
  74. break;
  75. case SHT_NOBITS:
  76. printf(" (SHT_NOBITS)\n");
  77. break;
  78. case SHT_SHLIB:
  79. printf(" (SHT_SHLIB)\n");
  80. break;
  81. case SHT_DYNSYM:
  82. printf(" (SHT_DYNSYM)\n");
  83. break;
  84. case SHT_LOUSER:
  85. printf(" (SHT_NOTE)\n");
  86. break;
  87. case SHT_HIUSER:
  88. printf(" (SHT_NOTE)\n");
  89. break;
  90. default:
  91. if (SHT_LOPROC < a && a < SHT_HIPROC) {
  92. printf(" (reserved)\n");
  93. }
  94. break;
  95. }
  96. }
  97. if (sh == NULL) {
  98. printf("print_shdr: null ptr\n");
  99. return;
  100. }
  101. const char *names[] = {
  102. "sh_name", "sh_type", "sh_flags", "sh_addr", "sh_offset",
  103. "sh_size", "sh_link", "sh_info", "sh_addralign", "sh_entsize"
  104. };
  105. for (unsigned int i = 0; i < 10; ++i) {
  106. // all attributes in the 32-bit version are the same type
  107. uint32_t *x = (uint32_t*)((char*)sh + (sizeof(uint32_t) * i));
  108. printf("%s = %x", names[i], *x);
  109. switch (i) {
  110. default:
  111. printf("\n");
  112. break;
  113. case 1: // sh_type
  114. print_type(*x);
  115. break;
  116. }
  117. }
  118. }
  119. void print_phdr(const Elf32_Phdr* const ph) {
  120. if (ph == NULL) {
  121. return;
  122. }
  123. const char *names[] = {
  124. "p_type", "p_offset", "p_vaddr", "p_paddr",
  125. "p_filesz", "p_memsz", "p_flags", "p_align"
  126. };
  127. for (unsigned int i = 0; i < 8; i++) { // 8 = # of attributes
  128. uint32_t *x =(uint32_t*)((char*)ph + (sizeof(uint32_t) * i));
  129. printf("%s = %x\n", names[i], *x);
  130. }
  131. }
  132. void* init(char * const buf, const unsigned int bufsize, unsigned int offset) {
  133. if (buf+offset > buf+bufsize) {
  134. printf("invalid (%x, %x)\n", buf+offset, buf+bufsize);
  135. return NULL;
  136. }
  137. return (buf+offset);
  138. }
  139. int elf_get_number_of_sections(unsigned char* elf_file, unsigned int len) {
  140. bool is_64bit;
  141. if (!is_elf(elf_file, len, &is_64bit)) {
  142. return -1;
  143. }
  144. int no_of_sections;
  145. if (is_64bit) {
  146. Elf64_Ehdr *eh;
  147. eh = (Elf64_Ehdr*)elf_file;
  148. no_of_sections = eh -> e_shnum;
  149. } else {
  150. Elf32_Ehdr *eh;
  151. eh = (Elf32_Ehdr*)elf_file;
  152. no_of_sections = eh -> e_shnum;
  153. }
  154. return no_of_sections;
  155. }
  156. void *elf_get_section_header(unsigned char *elf_file, unsigned int len,
  157. unsigned int n) {
  158. bool is_64bit;
  159. if (!is_elf(elf_file, len, &is_64bit)) {
  160. return NULL;
  161. }
  162. // to do: use 64 bit elf header if is_64bit
  163. int shnum;
  164. int shentsize;
  165. int shoff;
  166. if (is_64bit) {
  167. Elf64_Ehdr *eh;
  168. eh = (Elf64_Ehdr*)elf_file;
  169. shnum = eh -> e_shnum;
  170. shoff = eh -> e_shoff;
  171. shentsize = eh -> e_shentsize;
  172. } else {
  173. Elf32_Ehdr *eh;
  174. eh = (Elf32_Ehdr*)elf_file;
  175. shnum = eh -> e_shnum;
  176. shoff = eh -> e_shoff;
  177. shentsize = eh -> e_shentsize;
  178. }
  179. if (n > shnum) {
  180. return NULL;
  181. }
  182. unsigned int offset = n * shentsize + shoff;
  183. void *sh = init(elf_file, len, offset);
  184. // return value may also be null
  185. return sh;
  186. }
  187. // implemented before elf_get_section_header
  188. int elf_get_sh_flags(unsigned char *elf_file, unsigned int len,
  189. unsigned int n) {
  190. bool is_64bit;
  191. if (!is_elf(elf_file, len, &is_64bit)) {
  192. return -1;
  193. }
  194. void *section_header = elf_get_section_header(elf_file, len, n);
  195. if (section_header == NULL) {
  196. return -1;
  197. }
  198. int sh_flags;
  199. if (is_64bit) {
  200. Elf64_Shdr *sh = section_header;
  201. sh_flags = sh -> sh_flags;
  202. } else {
  203. Elf32_Shdr *sh = section_header;
  204. sh_flags = sh -> sh_flags;
  205. }
  206. return sh_flags;
  207. }
  208. int elf_copy_section_to_array(unsigned char *elf_file, unsigned int len,
  209. int n, uint8_t **array) {
  210. bool is_64bit;
  211. if (!is_elf(elf_file, len, &is_64bit)) {
  212. return -1;
  213. }
  214. void *section_header = elf_get_section_header(elf_file, len, n);
  215. if (section_header == NULL) {
  216. return -1;
  217. }
  218. unsigned int offset;
  219. unsigned int size;
  220. unsigned int type;
  221. if (is_64bit) {
  222. return -1; // not yet impelmented
  223. } else {
  224. Elf32_Shdr *sh = section_header;
  225. type = sh -> sh_type;
  226. offset = sh -> sh_offset;
  227. size = sh -> sh_size;
  228. }
  229. if (size <= 0) {
  230. return size; // hits for SHT_NULL or SHT_NOBITS
  231. }
  232. unsigned char* source = elf_file + offset;
  233. if ((source + size) > (elf_file + len)) {
  234. // section as specified goes beyond buffer (seg fault)
  235. return -1;
  236. }
  237. *array = (uint8_t*)malloc(sizeof(uint8_t) * (size));
  238. memcpy(*array, source, size);
  239. return size;
  240. }
  241. // demo/testing purposes
  242. #ifdef STANDALONE
  243. // generic, load any binary file
  244. char *loadfile(const char *fname, unsigned int *s) {
  245. FILE *f = fopen(fname, "rb");
  246. unsigned int size = 0; // number of elements to buffer;
  247. unsigned int rcnt = 0; // number of char's read by fread(...)
  248. if (f == NULL) {
  249. perror("file handler is null ptr");
  250. return NULL;
  251. }
  252. // this method of determining file size works up to 2 GB.
  253. fseek(f, 0, SEEK_END);
  254. size = ftell(f);
  255. rewind(f);
  256. char *buf = (char*)malloc(sizeof(char) * size);
  257. if (buf == NULL) {
  258. perror("buf is null after malloc");
  259. free(buf);
  260. return NULL;
  261. }
  262. rcnt = fread(buf, sizeof(char), size, f);
  263. if (rcnt < size) {
  264. perror("read count < size");
  265. free(buf);
  266. return NULL;
  267. }
  268. fclose(f);
  269. *s = rcnt;
  270. return buf;
  271. }
  272. // print all program and section headers
  273. void test_00(Elf32_Ehdr * eh, char *buffer, unsigned int bufsize) {
  274. for (unsigned int i = 0; i < eh -> e_phnum; ++i) {
  275. printf("-- program header %.2i --\n", i);
  276. unsigned int offset = i * (eh -> e_phentsize) + eh -> e_phoff;
  277. Elf32_Phdr *p = init(buffer, bufsize, offset);
  278. print_phdr(p);
  279. printf("-----------------------\n");
  280. }
  281. for (unsigned int i = 0; i < eh -> e_shnum; ++i) {
  282. printf("-- section header %.2i --\n", i);
  283. Elf32_Shdr *sample;
  284. unsigned int offset = i * (eh -> e_shentsize) + eh -> e_shoff;
  285. sample = init(buffer, bufsize, offset);
  286. print_shdr(sample);
  287. printf("-----------------------\n");
  288. }
  289. }
  290. void test_01(unsigned char* elf_file, unsigned int len) {
  291. // test file has 7 sections
  292. int count = elf_get_number_of_sections(elf_file, len);
  293. if (count <= 0) {
  294. printf("!\n");
  295. return;
  296. }
  297. for (unsigned int i = 0; i < count; i++) {
  298. int flags = elf_get_sh_flags(elf_file, len, i);
  299. printf("flag: %x\n", flags);
  300. }
  301. }
  302. int main(int argc, char ** argv) {
  303. if (argc < 2) {
  304. printf("usage: program filename\n");
  305. return 0;
  306. }
  307. unsigned int bufsize = 0;
  308. char *f = argv[1];
  309. char *buffer = loadfile(f, &bufsize);
  310. bool is_64;
  311. if (!is_elf(buffer, bufsize, &is_64)) {
  312. return 0;
  313. }
  314. Elf32_Ehdr *eh;
  315. eh = (Elf32_Ehdr*)buffer;
  316. show_elf_header(eh);
  317. test_00(eh, buffer, bufsize);
  318. test_01(buffer, bufsize);
  319. uint8_t *test = NULL;
  320. int c = elf_copy_section_to_array(buffer, bufsize, 1, &test);
  321. // printf("%p\n",test);
  322. if (test != NULL) {
  323. for (unsigned int i=0; i < c; i++) {
  324. printf("%x, ", test[i]);
  325. }
  326. printf("\n");
  327. }
  328. free(test);
  329. free(buffer);
  330. return 0;
  331. }
  332. # endif