elf64_interpreter.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. #include "elf64_interpreter.hpp"
  2. #include "exceptions/index_exception.hpp"
  3. #include "exceptions/key_exception.hpp"
  4. #include <memory.h>
  5. #include <algorithm>
  6. #include <fmt/format.h>
  7. #define NKG_CURRENT_SOURCE_FILE() ".\\navicat-patcher\\elf64_interpreter.cpp"
  8. #define NKG_CURRENT_SOURCE_LINE() __LINE__
  9. namespace nkg {
  10. elf64_interpreter::elf64_interpreter() :
  11. m_elf_size(0),
  12. m_elf_header(nullptr),
  13. m_elf_program_headers(nullptr),
  14. m_elf_section_headers(nullptr),
  15. m_dynamic_rela(nullptr),
  16. m_dynamic_relasz(nullptr),
  17. m_dynamic_rel(nullptr),
  18. m_dynamic_relsz(nullptr),
  19. m_dynamic_pltgot(nullptr),
  20. m_dynamic_jmprel(nullptr),
  21. m_dynamic_pltrel(nullptr),
  22. m_dynamic_pltrelsz(nullptr),
  23. m_dynamic_symtab(nullptr),
  24. m_dynamic_strtab(nullptr) {}
  25. [[nodiscard]]
  26. elf64_interpreter elf64_interpreter::parse(void* image_ptr, size_t image_size) {
  27. elf64_interpreter new_image;
  28. // check ELF header
  29. new_image.m_elf_size = image_size;
  30. new_image.m_elf_header = reinterpret_cast<Elf64_Ehdr*>(image_ptr);
  31. if (is_address_in_range(new_image.m_elf_header, sizeof(Elf64_Ehdr), image_ptr, image_size) == false) {
  32. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: image is corrupted.");
  33. }
  34. if (memcmp(new_image.m_elf_header->e_ident, ELFMAG, SELFMAG) != 0) {
  35. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: header magic check failed.");
  36. }
  37. if (new_image.m_elf_header->e_ident[EI_CLASS] != ELFCLASS64) {
  38. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Unsupported ELF file: not ELF64 image.");
  39. }
  40. if (new_image.m_elf_header->e_ident[EI_DATA] == ELFDATA2LSB && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) {
  41. ; // pass
  42. } else if (new_image.m_elf_header->e_ident[EI_DATA] == ELFDATA2MSB && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) {
  43. ; // pass
  44. } else {
  45. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Unsupported ELF file: unsupported endian.");
  46. }
  47. if (new_image.m_elf_header->e_ident[EI_VERSION] != EV_CURRENT) {
  48. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: Elf64_Ehdr::e_ident[EI_VERSION] check failed.");
  49. }
  50. // new_image.m_elf_header->e_ident[EI_OSABI]
  51. // new_image.m_elf_header->e_ident[EI_ABIVERSION]
  52. for (int i = EI_PAD; i < sizeof(new_image.m_elf_header->e_ident); ++i) {
  53. if (new_image.m_elf_header->e_ident[i] != 0) {
  54. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: Elf64_Ehdr::e_ident padding contains non-zero byte(s).");
  55. }
  56. }
  57. if (new_image.m_elf_header->e_version != EV_CURRENT) {
  58. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: Elf64_Ehdr::e_version check failed.");
  59. }
  60. if (new_image.m_elf_header->e_ehsize != sizeof(Elf64_Ehdr)) {
  61. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: Elf64_Ehdr::e_ehsize check failed.");
  62. }
  63. if (new_image.m_elf_header->e_phoff && new_image.m_elf_header->e_phentsize && new_image.m_elf_header->e_phnum) {
  64. if (new_image.m_elf_header->e_phentsize != sizeof(Elf64_Phdr)) {
  65. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: Elf64_Ehdr::e_phentsize check failed.");
  66. }
  67. new_image.m_elf_program_headers = address_offset_cast<Elf64_Phdr*>(image_ptr, new_image.m_elf_header->e_phoff);
  68. if (is_address_in_range(new_image.m_elf_program_headers, new_image.m_elf_header->e_phnum * sizeof(Elf64_Phdr), image_ptr, image_size) == false) {
  69. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: image is corrupted.");
  70. }
  71. } else if (new_image.m_elf_header->e_phoff == 0 && new_image.m_elf_header->e_phentsize == 0 && new_image.m_elf_header->e_phnum == 0) {
  72. new_image.m_elf_program_headers = nullptr;
  73. } else {
  74. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: Elf64_Ehdr::e_ph* check failed.");
  75. }
  76. if (new_image.m_elf_header->e_shoff && new_image.m_elf_header->e_shentsize && new_image.m_elf_header->e_shnum) {
  77. if (new_image.m_elf_header->e_shentsize != sizeof(Elf64_Shdr)) {
  78. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: Elf64_Ehdr::e_shentsize check failed.");
  79. }
  80. new_image.m_elf_section_headers = address_offset_cast<Elf64_Shdr*>(image_ptr, new_image.m_elf_header->e_shoff);
  81. if (is_address_in_range(new_image.m_elf_section_headers, new_image.m_elf_header->e_shnum * sizeof(Elf64_Shdr), image_ptr, image_size) == false) {
  82. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: image is corrupted.");
  83. }
  84. } else if (new_image.m_elf_header->e_shoff == 0 && new_image.m_elf_header->e_shentsize == 0 && new_image.m_elf_header->e_shnum == 0) {
  85. new_image.m_elf_section_headers = nullptr;
  86. } else {
  87. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: Elf64_Ehdr::e_sh* check failed.");
  88. }
  89. if (new_image.m_elf_header->e_shstrndx != SHN_UNDEF) {
  90. if (new_image.m_elf_header->e_shstrndx >= new_image.m_elf_header->e_shnum) {
  91. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: Elf64_Ehdr::e_shstrndx is out of range.");
  92. }
  93. }
  94. // check program header table and section header table are not overlapped
  95. if (new_image.m_elf_program_headers && new_image.m_elf_section_headers) {
  96. auto a1 = new_image.m_elf_program_headers;
  97. auto a2 = new_image.m_elf_program_headers + new_image.m_elf_header->e_phnum;
  98. auto b1 = new_image.m_elf_section_headers;
  99. auto b2 = new_image.m_elf_section_headers + new_image.m_elf_header->e_shnum;
  100. bool not_overlapped = address_delta(a1, b1) < 0 && address_delta(a2, b1) <= 0 || address_delta(b1, a1) < 0 && address_delta(b2, a1) <= 0;
  101. if (!not_overlapped) {
  102. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: program header table and section header table overlapped.");
  103. }
  104. }
  105. // parse program header
  106. for (size_t i = 0; i < new_image.m_elf_header->e_phnum; ++i) {
  107. auto& prog_hdr = new_image.m_elf_program_headers[i];
  108. if (!is_address_in_range(address_offset(image_ptr, static_cast<ptrdiff_t>(prog_hdr.p_offset)), prog_hdr.p_filesz, image_ptr, image_size)) {
  109. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: image is corrupted.");
  110. }
  111. auto prog_hdr_align = prog_hdr.p_align;
  112. if (prog_hdr_align) {
  113. // align must be a power of 2
  114. if ((prog_hdr_align & (prog_hdr_align - 1)) != 0) {
  115. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Phdr[{}]: p_align is not a power of 2.", i));
  116. }
  117. if (prog_hdr.p_offset % prog_hdr_align != prog_hdr.p_vaddr % prog_hdr_align) {
  118. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Phdr[{}]: p_offset !== p_vaddr (mod prog_hdr_align).", i));
  119. }
  120. }
  121. if (prog_hdr.p_type == PT_LOAD) {
  122. new_image.m_segment_va_lookup_table.emplace(std::make_pair(prog_hdr.p_vaddr, &prog_hdr));
  123. new_image.m_segment_fo_lookup_table.emplace(std::make_pair(prog_hdr.p_offset, &prog_hdr));
  124. }
  125. }
  126. // parse section header
  127. if (new_image.m_elf_header->e_shstrndx != SHN_UNDEF) {
  128. auto sect_hdr_strtab = &new_image.m_elf_section_headers[new_image.m_elf_header->e_shstrndx];
  129. auto sect_view_strtab = address_offset_cast<const char*>(image_ptr, sect_hdr_strtab->sh_offset);
  130. if (sect_hdr_strtab->sh_type != SHT_STRTAB) {
  131. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: sect_hdr_strtab->sh_type != SHT_STRTAB.");
  132. }
  133. if (!is_address_in_range(sect_view_strtab, sect_hdr_strtab->sh_size, image_ptr, image_size)) {
  134. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: image is corrupted.");
  135. }
  136. for (size_t i = 0; i < new_image.m_elf_header->e_shnum; ++i) {
  137. new_image.m_section_name_lookup_table
  138. .emplace(std::make_pair(std::string_view(address_offset(sect_view_strtab, new_image.m_elf_section_headers[i].sh_name)), &new_image.m_elf_section_headers[i]));
  139. }
  140. }
  141. for (int i = 0; i < new_image.m_elf_header->e_shnum; ++i) {
  142. auto& sect_hdr = new_image.m_elf_section_headers[i];
  143. switch (sect_hdr.sh_type) {
  144. case SHT_SYMTAB:
  145. if (sect_hdr.sh_entsize != sizeof(Elf64_Sym)) {
  146. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_entsize != sizeof(Elf64_Sym).", i));
  147. }
  148. // check sh_link
  149. if (sect_hdr.sh_link == SHN_UNDEF) {
  150. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link == SHN_UNDEF.", i));
  151. }
  152. if (sect_hdr.sh_link >= new_image.m_elf_header->e_shnum) {
  153. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link is out of range.", i));
  154. }
  155. if (new_image.m_elf_section_headers[sect_hdr.sh_link].sh_type != SHT_STRTAB) {
  156. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: bad value of sh_link.", i));
  157. }
  158. // todo: check sh_info
  159. break;
  160. case SHT_RELA:
  161. if (sect_hdr.sh_entsize != sizeof(Elf64_Rela)) {
  162. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_entsize != sizeof(Elf64_Rela).", i));
  163. }
  164. // check sh_link
  165. if (sect_hdr.sh_link == SHN_UNDEF) {
  166. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link == SHN_UNDEF.", i));
  167. }
  168. if (sect_hdr.sh_link >= new_image.m_elf_header->e_shnum) {
  169. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link is out of range.", i));
  170. }
  171. if (new_image.m_elf_section_headers[sect_hdr.sh_link].sh_type != SHT_SYMTAB && new_image.m_elf_section_headers[sect_hdr.sh_link].sh_type != SHT_DYNSYM) {
  172. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[%u]: bad value of sh_link.", i));
  173. }
  174. // check sh_info
  175. if (sect_hdr.sh_flags & SHF_INFO_LINK) {
  176. if (sect_hdr.sh_info == SHN_UNDEF) {
  177. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_info == SHN_UNDEF.", i));
  178. }
  179. if (sect_hdr.sh_info >= new_image.m_elf_header->e_shnum) {
  180. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_info is out of range.", i));
  181. }
  182. } else {
  183. if (sect_hdr.sh_info != 0) {
  184. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_info != 0.", i));
  185. }
  186. }
  187. break;
  188. case SHT_HASH:
  189. if (sect_hdr.sh_link == SHN_UNDEF) {
  190. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link == SHN_UNDEF.", i));
  191. }
  192. if (sect_hdr.sh_link >= new_image.m_elf_header->e_shnum) {
  193. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link is out of range.", i));
  194. }
  195. if (new_image.m_elf_section_headers[sect_hdr.sh_link].sh_type != SHT_SYMTAB && new_image.m_elf_section_headers[sect_hdr.sh_link].sh_type != SHT_DYNSYM) {
  196. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: bad value of sh_link.", i));
  197. }
  198. if (sect_hdr.sh_info != 0) {
  199. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_info != 0.", i));
  200. }
  201. break;
  202. case SHT_DYNAMIC:
  203. if (sect_hdr.sh_entsize != sizeof(Elf64_Dyn)) {
  204. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_entsize != sizeof(Elf64_Dyn).", i));
  205. }
  206. // check sh_link
  207. if (sect_hdr.sh_link == SHN_UNDEF) {
  208. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link == SHN_UNDEF.", i));
  209. }
  210. if (sect_hdr.sh_link >= new_image.m_elf_header->e_shnum) {
  211. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link is out of range.", i));
  212. }
  213. if (new_image.m_elf_section_headers[sect_hdr.sh_link].sh_type != SHT_STRTAB) {
  214. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: bad value of sh_link.", i));
  215. }
  216. // check sh_info
  217. if (sect_hdr.sh_info != 0) {
  218. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_info != 0.", i));
  219. }
  220. break;
  221. case SHT_REL:
  222. if (sect_hdr.sh_entsize != sizeof(Elf64_Rel)) {
  223. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_entsize != sizeof(Elf64_Rel).", i));
  224. }
  225. // check sh_link
  226. if (sect_hdr.sh_link == SHN_UNDEF) {
  227. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link == SHN_UNDEF.", i));
  228. }
  229. if (sect_hdr.sh_link >= new_image.m_elf_header->e_shnum) {
  230. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link is out of range.", i));
  231. }
  232. if (new_image.m_elf_section_headers[sect_hdr.sh_link].sh_type != SHT_SYMTAB && new_image.m_elf_section_headers[sect_hdr.sh_link].sh_type != SHT_DYNSYM) {
  233. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[%u]: bad value of sh_link.", i));
  234. }
  235. // check sh_info
  236. if (sect_hdr.sh_flags & SHF_INFO_LINK) {
  237. if (sect_hdr.sh_info == SHN_UNDEF) {
  238. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_info == SHN_UNDEF.", i));
  239. }
  240. if (sect_hdr.sh_info >= new_image.m_elf_header->e_shnum) {
  241. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_info is out of range.", i));
  242. }
  243. } else {
  244. if (sect_hdr.sh_info != 0) {
  245. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_info != 0.", i));
  246. }
  247. }
  248. break;
  249. case SHT_DYNSYM:
  250. if (sect_hdr.sh_entsize != sizeof(Elf64_Sym)) {
  251. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_entsize != sizeof(Elf64_Dyn).", i));
  252. }
  253. // check sh_link
  254. if (sect_hdr.sh_link == SHN_UNDEF) {
  255. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link == SHN_UNDEF.", i));
  256. }
  257. if (sect_hdr.sh_link >= new_image.m_elf_header->e_shnum) {
  258. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_link is out of range.", i));
  259. }
  260. if (new_image.m_elf_section_headers[sect_hdr.sh_link].sh_type != SHT_STRTAB) {
  261. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: bad value of sh_link.", i));
  262. }
  263. // todo: check sh_info
  264. break;
  265. default:
  266. break;
  267. }
  268. if (sect_hdr.sh_type != SHT_NOBITS) {
  269. if (is_address_in_range(address_offset(image_ptr, sect_hdr.sh_offset), sect_hdr.sh_size, image_ptr, image_size) == false) {
  270. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: image is corrupted.", i));
  271. }
  272. new_image.m_section_fo_lookup_table.emplace(std::make_pair(sect_hdr.sh_offset, new_image.m_elf_section_headers + i));
  273. }
  274. if (sect_hdr.sh_addr) {
  275. if (sect_hdr.sh_addralign && sect_hdr.sh_addr % sect_hdr.sh_addralign != 0) {
  276. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: Elf64_Shdr[{}]: sh_addr is not aligned to sh_addralign.", i));
  277. }
  278. new_image.m_section_va_lookup_table.emplace(std::make_pair(sect_hdr.sh_addr, &new_image.m_elf_section_headers[i]));
  279. }
  280. }
  281. // parse program header, second parse
  282. for (size_t i = 0; i < new_image.m_elf_header->e_phnum; ++i) {
  283. auto& prog_hdr = new_image.m_elf_program_headers[i];
  284. if (prog_hdr.p_type == PT_DYNAMIC) {
  285. auto seg_dynamic_base = address_offset_cast<Elf64_Dyn*>(image_ptr, prog_hdr.p_offset);
  286. auto seg_dyncmic_size = prog_hdr.p_filesz;
  287. // first parse
  288. for (size_t j = 0; j * sizeof(Elf64_Dyn) < seg_dyncmic_size && seg_dynamic_base[j].d_tag != DT_NULL; ++j) {
  289. auto& dyn_entry = seg_dynamic_base[j];
  290. switch (dyn_entry.d_tag) {
  291. case DT_RELA:
  292. new_image.m_dynamic_rela = &seg_dynamic_base[j];
  293. break;
  294. case DT_RELAENT:
  295. if (seg_dynamic_base[j].d_un.d_val != sizeof(Elf64_Rela)) {
  296. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: the value of DT_RELAENT.dval != sizeof(Elf64_Rela).");
  297. }
  298. break;
  299. case DT_RELASZ:
  300. new_image.m_dynamic_relasz = &seg_dynamic_base[j];
  301. break;
  302. case DT_REL:
  303. new_image.m_dynamic_rel = &seg_dynamic_base[j];
  304. break;
  305. case DT_RELENT:
  306. if (seg_dynamic_base[j].d_un.d_val != sizeof(Elf64_Rel)) {
  307. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: the value of DT_RELENT.dval != sizeof(Elf64_Rel).");
  308. }
  309. break;
  310. case DT_RELSZ:
  311. new_image.m_dynamic_relsz = &seg_dynamic_base[j];
  312. break;
  313. case DT_PLTGOT:
  314. new_image.m_dynamic_pltgot = &seg_dynamic_base[j];
  315. break;
  316. case DT_JMPREL:
  317. new_image.m_dynamic_jmprel = &seg_dynamic_base[j];
  318. break;
  319. case DT_PLTREL:
  320. if (seg_dynamic_base[j].d_un.d_val == DT_REL || seg_dynamic_base[j].d_un.d_val == DT_RELA) {
  321. new_image.m_dynamic_pltrel = &seg_dynamic_base[j];
  322. } else {
  323. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Bad ELF file: the value of DT_PLTREL.dval is neither DT_REL nor DT_RELA.");
  324. }
  325. break;
  326. case DT_PLTRELSZ:
  327. new_image.m_dynamic_pltrelsz = &seg_dynamic_base[j];
  328. break;
  329. case DT_STRTAB:
  330. new_image.m_dynamic_strtab = &seg_dynamic_base[j];
  331. break;
  332. case DT_SYMTAB:
  333. new_image.m_dynamic_symtab = &seg_dynamic_base[j];
  334. break;
  335. default:
  336. break;
  337. }
  338. }
  339. }
  340. }
  341. if (new_image.m_dynamic_rela && new_image.m_dynamic_relasz) {
  342. auto rela_base = new_image.convert_va_to_ptr<Elf64_Rela*>(new_image.m_dynamic_rela->d_un.d_ptr);
  343. auto rela_size = new_image.m_dynamic_relasz->d_un.d_val;
  344. for (size_t i = 0; i * sizeof(Elf64_Rela) < rela_size; ++i) {
  345. auto reloc_va = rela_base[i].r_offset;
  346. auto reloc_type = ELF64_R_TYPE(rela_base[i].r_info);
  347. switch(reloc_type) {
  348. case R_X86_64_64:
  349. case R_X86_64_GLOB_DAT:
  350. case R_X86_64_RELATIVE:
  351. new_image.m_relocation_distribute.emplace(std::make_pair(reloc_va, 8));
  352. break;
  353. default:
  354. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Unsupported ELF file: unhandled relocation type({}).", reloc_type));
  355. }
  356. }
  357. }
  358. if (new_image.m_dynamic_rel && new_image.m_dynamic_relsz) {
  359. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Unsupported ELF file: DT_REL is not parsed.");
  360. }
  361. if (new_image.m_dynamic_jmprel && new_image.m_dynamic_pltrel && new_image.m_dynamic_pltrelsz) {
  362. if (new_image.m_dynamic_pltrel->d_un.d_val == DT_RELA) {
  363. auto jmprel_base = new_image.convert_va_to_ptr<Elf64_Rela*>(new_image.m_dynamic_jmprel->d_un.d_ptr);
  364. auto jmprel_size = new_image.m_dynamic_pltrelsz->d_un.d_val;
  365. for (size_t i = 0; i * sizeof(Elf64_Rela) < jmprel_size; ++i) {
  366. auto reloc_va = jmprel_base[i].r_offset;
  367. auto reloc_type = ELF64_R_TYPE(jmprel_base[i].r_info);
  368. if (reloc_type == R_X86_64_JUMP_SLOT) {
  369. new_image.m_relocation_distribute.emplace(std::make_pair(reloc_va, 8));
  370. } else {
  371. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: bad relocation type({}) in JMPREL relocation table.", reloc_type));
  372. }
  373. }
  374. } else {
  375. auto jmprel_base = new_image.convert_va_to_ptr<Elf64_Rel*>(new_image.m_dynamic_jmprel->d_un.d_ptr);
  376. auto jmprel_size = new_image.m_dynamic_pltrelsz->d_un.d_val;
  377. for (size_t i = 0; i * sizeof(Elf64_Rela) < jmprel_size; ++i) {
  378. auto reloc_va = jmprel_base[i].r_offset;
  379. auto reloc_type = ELF64_R_TYPE(jmprel_base[i].r_info);
  380. if (reloc_type == R_X86_64_JUMP_SLOT) {
  381. new_image.m_relocation_distribute.emplace(std::make_pair(reloc_va, 8));
  382. } else {
  383. throw parse_error(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Bad ELF file: bad relocation type({}) in JMPREL relocation table.", reloc_type));
  384. }
  385. }
  386. }
  387. }
  388. return new_image;
  389. }
  390. [[nodiscard]]
  391. size_t elf64_interpreter::elf_size() const noexcept {
  392. return m_elf_size;
  393. }
  394. [[nodiscard]]
  395. Elf64_Ehdr* elf64_interpreter::elf_header() const noexcept {
  396. return m_elf_header;
  397. }
  398. [[nodiscard]]
  399. Elf64_Phdr* elf64_interpreter::elf_program_header(size_t n) const {
  400. if (n < m_elf_header->e_phnum) {
  401. return m_elf_program_headers + n;
  402. } else {
  403. throw exceptions::index_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Out of range.");
  404. }
  405. }
  406. [[nodiscard]]
  407. Elf64_Phdr* elf64_interpreter::elf_program_header_from_fo(fo_t file_offset) const {
  408. auto it = m_segment_fo_lookup_table.upper_bound(file_offset);
  409. if (it != m_segment_fo_lookup_table.begin()) {
  410. --it;
  411. if (it->second->p_offset <= file_offset && file_offset < it->second->p_offset + it->second->p_filesz) {
  412. return it->second;
  413. }
  414. }
  415. throw bad_fo_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("File offset({:#x}) doesn't point to any segment."));
  416. }
  417. [[nodiscard]]
  418. Elf64_Phdr* elf64_interpreter::elf_program_header_from_rva(rva_t rva) const {
  419. return elf_program_header_from_va(convert_rva_to_va(rva));
  420. }
  421. [[nodiscard]]
  422. Elf64_Phdr* elf64_interpreter::elf_program_header_from_va(va_t va) const {
  423. auto it = m_segment_va_lookup_table.upper_bound(va);
  424. if (it != m_segment_va_lookup_table.begin()) {
  425. --it;
  426. if (it->second->p_vaddr <= va && va < it->second->p_vaddr + it->second->p_memsz) {
  427. return it->second;
  428. }
  429. }
  430. throw bad_va_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Invalid virtual address({:#016x}).", va));
  431. }
  432. [[nodiscard]]
  433. size_t elf64_interpreter::elf_program_headers_num() const noexcept {
  434. return m_elf_header->e_shnum;
  435. }
  436. [[nodiscard]]
  437. Elf64_Shdr* elf64_interpreter::elf_section_header(size_t n) const {
  438. if (n < m_elf_header->e_shnum) {
  439. return m_elf_section_headers + n;
  440. } else {
  441. throw exceptions::index_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), "Out of range.");
  442. }
  443. }
  444. [[nodiscard]]
  445. Elf64_Shdr* elf64_interpreter::elf_section_header(std::string_view section_name) const {
  446. auto it = m_section_name_lookup_table.find(section_name);
  447. if (it != m_section_name_lookup_table.end()) {
  448. return it->second;
  449. } else {
  450. throw exceptions::key_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Section `{}` is not found.", section_name.data()));
  451. }
  452. }
  453. [[nodiscard]]
  454. size_t elf64_interpreter::elf_section_headers_num() const noexcept {
  455. return m_elf_header->e_shnum;
  456. }
  457. [[nodiscard]]
  458. elf64_interpreter::fo_t elf64_interpreter::convert_rva_to_fo(rva_t rva) const {
  459. return convert_va_to_fo(convert_rva_to_va(rva));
  460. }
  461. [[nodiscard]]
  462. elf64_interpreter::fo_t elf64_interpreter::convert_va_to_fo(va_t va) const {
  463. auto it = m_segment_va_lookup_table.upper_bound(va);
  464. if (it != m_segment_va_lookup_table.begin()) {
  465. --it;
  466. if (it->second->p_vaddr <= va && va < it->second->p_vaddr + it->second->p_memsz) {
  467. if (va - it->second->p_vaddr < it->second->p_filesz) {
  468. return it->second->p_offset + (va - it->second->p_vaddr);
  469. } else {
  470. throw bad_va_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Virtual address({:#016x}) doesn't have corresponding file offset.", va));
  471. }
  472. }
  473. }
  474. throw bad_va_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("Invalid virtual address({:#016x})", va));
  475. }
  476. [[nodiscard]]
  477. elf64_interpreter::rva_t elf64_interpreter::convert_fo_to_rva(fo_t file_offset) const {
  478. return convert_va_to_rva(convert_fo_to_va(file_offset));
  479. }
  480. elf64_interpreter::rva_t elf64_interpreter::convert_va_to_rva(va_t va) const {
  481. return va - m_segment_va_lookup_table.begin()->first;
  482. }
  483. [[nodiscard]]
  484. elf64_interpreter::va_t elf64_interpreter::convert_fo_to_va(fo_t file_offset) const {
  485. auto it = m_segment_fo_lookup_table.upper_bound(file_offset);
  486. if (it != m_segment_fo_lookup_table.begin()) {
  487. --it;
  488. if (it->second->p_offset <= file_offset && file_offset < it->second->p_offset + it->second->p_filesz) {
  489. return it->second->p_vaddr + (file_offset - it->second->p_offset);
  490. }
  491. }
  492. throw bad_fo_exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), fmt::format("File offset({:#x}) doesn't have corresponding virtual address.", file_offset));
  493. }
  494. [[nodiscard]]
  495. elf64_interpreter::va_t elf64_interpreter::convert_rva_to_va(rva_t rva) const {
  496. return m_segment_va_lookup_table.begin()->first + rva;
  497. }
  498. [[nodiscard]]
  499. std::optional<elf64_interpreter::va_t> elf64_interpreter::elf_dynamic_rela() const {
  500. return m_dynamic_rela ? std::make_optional(m_dynamic_rela->d_un.d_ptr) : std::nullopt;
  501. }
  502. [[nodiscard]]
  503. std::optional<size_t> elf64_interpreter::elf_dynamic_relasz() const {
  504. return m_dynamic_relasz ? std::make_optional(m_dynamic_relasz->d_un.d_ptr) : std::nullopt;
  505. }
  506. [[nodiscard]]
  507. std::optional<elf64_interpreter::va_t> elf64_interpreter::elf_dynamic_rel() const {
  508. return m_dynamic_rel ? std::make_optional(m_dynamic_rel->d_un.d_ptr) : std::nullopt;
  509. }
  510. [[nodiscard]]
  511. std::optional<size_t> elf64_interpreter::elf_dynamic_relsz() const {
  512. return m_dynamic_relsz ? std::make_optional(m_dynamic_relsz->d_un.d_ptr) : std::nullopt;
  513. }
  514. [[nodiscard]]
  515. std::optional<elf64_interpreter::va_t> elf64_interpreter::elf_dynamic_pltgot() const {
  516. return m_dynamic_pltgot ? std::make_optional(m_dynamic_pltgot->d_un.d_ptr) : std::nullopt;
  517. }
  518. [[nodiscard]]
  519. std::optional<elf64_interpreter::va_t> elf64_interpreter::elf_dynamic_jmprel() const {
  520. return m_dynamic_jmprel ? std::make_optional(m_dynamic_jmprel->d_un.d_ptr) : std::nullopt;
  521. }
  522. [[nodiscard]]
  523. std::optional<int> elf64_interpreter::elf_dynamic_pltrel() const {
  524. return m_dynamic_pltrel ? std::make_optional(m_dynamic_pltrel->d_un.d_val) : std::nullopt;
  525. }
  526. [[nodiscard]]
  527. std::optional<size_t> elf64_interpreter::elf_dynamic_pltrelsz() const {
  528. return m_dynamic_pltrelsz ? std::make_optional(m_dynamic_pltrelsz->d_un.d_val) : std::nullopt;
  529. }
  530. [[nodiscard]]
  531. std::optional<elf64_interpreter::va_t> elf64_interpreter::elf_dynamic_symtab() const {
  532. return m_dynamic_symtab ? std::make_optional(m_dynamic_symtab->d_un.d_ptr) : std::nullopt;
  533. }
  534. [[nodiscard]]
  535. std::optional<elf64_interpreter::va_t> elf64_interpreter::elf_dynamic_strtab() const {
  536. return m_dynamic_strtab ? std::make_optional(m_dynamic_strtab->d_un.d_ptr) : std::nullopt;
  537. }
  538. [[nodiscard]]
  539. const std::map<elf64_interpreter::va_t, size_t>& elf64_interpreter::relocation_distribute() const {
  540. return m_relocation_distribute;
  541. }
  542. }
  543. #undef NKG_CURRENT_SOURCE_LINE
  544. #undef NKG_CURRENT_SOURCE_FILE