X64ImageInterpreter.hpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #pragma once
  2. #include <mach-o/loader.h>
  3. #include <mach-o/nlist.h>
  4. #include <string.h>
  5. #include <vector>
  6. #include <map>
  7. #include "Exception.hpp"
  8. #include "ExceptionGeneric.hpp"
  9. #include "MemoryAccess.hpp"
  10. namespace nkg {
  11. using X64ImageAddress = decltype(section_64::addr);
  12. using X64ImageOffset = decltype(section_64::offset);
  13. using X64ImageSize = decltype(section_64::size);
  14. class X64ImageInterpreter {
  15. private:
  16. size_t m_MachOSize;
  17. const mach_header_64* m_MachOHeader;
  18. std::vector<const segment_command_64*> m_Segments;
  19. std::vector<const section_64*> m_Sections;
  20. std::map<X64ImageAddress, const section_64*> m_SectionsAddressMap;
  21. std::map<X64ImageOffset, const section_64*> m_SectionsOffsetMap;
  22. struct {
  23. const dysymtab_command* dysymtab;
  24. const symtab_command* symtab;
  25. const dyld_info_command* dyld_info;
  26. } m_SpecialLoadCommands;
  27. X64ImageInterpreter() :
  28. m_MachOSize(0),
  29. m_MachOHeader(nullptr),
  30. m_SpecialLoadCommands{} {}
  31. public:
  32. [[nodiscard]]
  33. static X64ImageInterpreter Parse(const void* lpImage, size_t cbImage);
  34. template<typename __ReturnType = void*>
  35. [[nodiscard]]
  36. __ReturnType ImageBase() const noexcept {
  37. static_assert(std::is_pointer_v<__ReturnType>);
  38. return reinterpret_cast<__ReturnType>(
  39. const_cast<mach_header_64*>(m_MachOHeader)
  40. );
  41. }
  42. template<typename __ReturnType = void*>
  43. [[nodiscard]]
  44. __ReturnType ImageOffset(size_t Offset) const {
  45. if (Offset < m_MachOSize) {
  46. return ARL::AddressOffsetWithCast<__ReturnType>(m_MachOHeader, Offset);
  47. } else {
  48. throw ARL::OverflowError(__FILE__, __LINE__, "X64ImageInterpreter: out of range.");
  49. }
  50. }
  51. [[nodiscard]]
  52. size_t ImageSize() const noexcept {
  53. return m_MachOSize;
  54. }
  55. [[nodiscard]]
  56. size_t NumberOfSegments() const noexcept;
  57. [[nodiscard]]
  58. size_t NumberOfSections() const noexcept;
  59. [[nodiscard]]
  60. const segment_command_64* ImageSegment(size_t Index) const;
  61. [[nodiscard]]
  62. const segment_command_64* ImageSegment(const char* SegmentName) const;
  63. [[nodiscard]]
  64. const section_64* ImageSection(size_t Index) const;
  65. [[nodiscard]]
  66. const section_64* ImageSection(const char* SegmentName, const char* SectionName) const;
  67. [[nodiscard]]
  68. const section_64* ImageSectionFromOffset(X64ImageOffset Offset) const;
  69. [[nodiscard]]
  70. const section_64* ImageSectionFromRva(X64ImageAddress Rva) const;
  71. template<typename __ReturnType = void*>
  72. [[nodiscard]]
  73. __ReturnType ImageSectionView(const section_64* Section) const noexcept {
  74. return ImageOffset<__ReturnType>(Section->offset);
  75. }
  76. template<typename __ReturnType = void*>
  77. [[nodiscard]]
  78. __ReturnType ImageSectionView(size_t Index) const {
  79. return ImageSectionView<__ReturnType>(ImageSection(Index));
  80. }
  81. template<typename __ReturnType = void*>
  82. [[nodiscard]]
  83. __ReturnType ImageSectionView(const char* SegmentName, const char* SectionName) const {
  84. return ImageSectionView<__ReturnType>(ImageSection(SegmentName, SectionName));
  85. }
  86. template<unsigned __CommandMacro>
  87. [[nodiscard]]
  88. auto SpecialLoadCommand() const noexcept {
  89. if constexpr (__CommandMacro == LC_DYSYMTAB) {
  90. return m_SpecialLoadCommands.dysymtab;
  91. } else if constexpr (__CommandMacro == LC_SYMTAB) {
  92. return m_SpecialLoadCommands.symtab;
  93. } else if constexpr (__CommandMacro == LC_DYLD_INFO_ONLY) {
  94. return m_SpecialLoadCommands.dyld_info;
  95. } else {
  96. #pragma clang diagnostic push
  97. #pragma GCC diagnostic ignored "-Wtautological-compare"
  98. constexpr bool always_false = __CommandMacro != __CommandMacro;
  99. #pragma clang diagnostic pop
  100. static_assert(always_false);
  101. }
  102. }
  103. template<typename __ReturnType = void*, typename __HintType>
  104. [[nodiscard]]
  105. __ReturnType SearchSection(const section_64* Section, __HintType&& Hint) const {
  106. static_assert(std::is_pointer_v<__ReturnType>);
  107. auto base = ImageSectionView<const uint8_t*>(Section);
  108. for (decltype(section_64::size) i = 0; i < Section->size; ++i) {
  109. if (Hint(base, i, Section->size) == true) {
  110. return ARL::AddressOffsetWithCast<__ReturnType>(base, i);
  111. }
  112. }
  113. return nullptr;
  114. }
  115. template<typename __ReturnType = void*, typename __HintType>
  116. [[nodiscard]]
  117. __ReturnType SearchSection(const section_64* Section, size_t Offset, __HintType&& Hint) const {
  118. static_assert(std::is_pointer_v<__ReturnType>);
  119. auto base = ImageSectionView<const uint8_t*>(Section);
  120. for (decltype(section_64::size) i = Offset; i < Section->size; ++i) {
  121. if (Hint(base, i, Section->size) == true) {
  122. return ARL::AddressOffsetWithCast<__ReturnType>(base, i);
  123. }
  124. }
  125. return nullptr;
  126. }
  127. template<typename __ReturnType = void*, typename __HintType>
  128. [[nodiscard]]
  129. __ReturnType SearchSection(size_t Index, __HintType&& Hint) const {
  130. return SearchSection<__ReturnType>(ImageSection(Index), std::forward<__HintType>(Hint));
  131. }
  132. template<typename __ReturnType = void*, typename __HintType>
  133. [[nodiscard]]
  134. __ReturnType SearchSection(size_t Index, size_t Offset, __HintType&& Hint) const {
  135. return SearchSection<__ReturnType>(ImageSection(Index), Offset, std::forward<__HintType>(Hint));
  136. }
  137. template<typename __ReturnType = void*, typename __HintType>
  138. [[nodiscard]]
  139. __ReturnType SearchSection(const char* SegmentName, const char* SectionName, __HintType&& Hint) const {
  140. return SearchSection<__ReturnType>(ImageSection(SegmentName, SectionName), std::forward<__HintType>(Hint));
  141. }
  142. template<typename __ReturnType = void*, typename __HintType>
  143. [[nodiscard]]
  144. __ReturnType SearchSection(const char* SegmentName, const char* SectionName, size_t Offset, __HintType&& Hint) const {
  145. return SearchSection<__ReturnType>(ImageSection(SegmentName, SectionName), Offset, std::forward<__HintType>(Hint));
  146. }
  147. [[nodiscard]]
  148. X64ImageAddress ConvertOffsetToRva(X64ImageOffset Offset) const;
  149. template<typename __ReturnType = void*>
  150. [[nodiscard]]
  151. __ReturnType ConvertOffsetToPtr(X64ImageOffset Offset) const {
  152. return ImageOffset<__ReturnType>(Offset);
  153. }
  154. [[nodiscard]]
  155. X64ImageOffset ConvertRvaToOffset(X64ImageAddress Address) const;
  156. template<typename __ReturnType = void*>
  157. [[nodiscard]]
  158. __ReturnType ConvertRvaToPtr(X64ImageAddress Rva) const {
  159. return ConvertOffsetToPtr<__ReturnType>(ConvertRvaToOffset(Rva));
  160. }
  161. template<typename __PtrType>
  162. [[nodiscard]]
  163. X64ImageAddress ConvertPtrToRva(__PtrType Ptr) const {
  164. auto offset = ARL::AddressDelta(Ptr, m_MachOHeader);
  165. if (offset < m_MachOSize) {
  166. return ConvertOffsetToRva(offset);
  167. } else {
  168. throw ARL::OverflowError(__FILE__, __LINE__, "X64ImageInterpreter: out of range.");
  169. }
  170. }
  171. template<typename __PtrType>
  172. [[nodiscard]]
  173. X64ImageAddress ConvertPtrToOffset(__PtrType Ptr) const {
  174. auto offset = ARL::AddressDelta(Ptr, m_MachOHeader);
  175. if (offset < m_MachOSize) {
  176. return offset;
  177. } else {
  178. throw ARL::OverflowError(__FILE__, __LINE__, "X64ImageInterpreter: out of range.");
  179. }
  180. }
  181. };
  182. }