#pragma once #include #include #include #include #include "exception.hpp" namespace nkg { class image_interpreter { public: using va_t = uintptr_t; using rva_t = uintptr_t; using fo_t = uintptr_t; private: PIMAGE_DOS_HEADER m_dos_header; PIMAGE_NT_HEADERS m_nt_headers; PIMAGE_SECTION_HEADER m_section_header_table; std::map, PIMAGE_SECTION_HEADER> m_section_header_name_lookup_table; std::map m_section_header_rva_lookup_table; std::map m_section_header_fo_lookup_table; std::map m_relocation_rva_lookup_table; std::map> m_iat_rva_lookup_table; VS_FIXEDFILEINFO* m_vs_fixed_file_info; image_interpreter(); static std::array make_section_name(const BYTE (&name)[8]) { std::array retval; std::copy(std::begin(name), std::end(name), retval.begin()); return retval; } public: class parse_error : public ::nkg::exception { public: parse_error(std::string_view file, int line, std::string_view message) noexcept : ::nkg::exception(file, line, message) {} }; [[nodiscard]] static image_interpreter parse(void* image_base, bool parse_relocation); template [[nodiscard]] ptr_t image_base() const noexcept { static_assert(std::is_pointer_v); return reinterpret_cast(m_dos_header); } [[nodiscard]] PIMAGE_DOS_HEADER image_dos_header() const noexcept; [[nodiscard]] PIMAGE_NT_HEADERS image_nt_headers() const noexcept; [[nodiscard]] PIMAGE_SECTION_HEADER image_section_header_table() const noexcept; [[nodiscard]] PIMAGE_SECTION_HEADER image_section_header(size_t n) const; [[nodiscard]] PIMAGE_SECTION_HEADER image_section_header(std::string_view name) const; [[nodiscard]] PIMAGE_SECTION_HEADER image_section_header_from_rva(rva_t rva) const; [[nodiscard]] PIMAGE_SECTION_HEADER image_section_header_from_va(va_t va) const; [[nodiscard]] PIMAGE_SECTION_HEADER image_section_header_from_fo(fo_t file_offset) const; [[nodiscard]] va_t convert_rva_to_va(rva_t rva) const noexcept; [[nodiscard]] fo_t convert_rva_to_fo(rva_t rva) const; template [[nodiscard]] ptr_t convert_rva_to_ptr(rva_t rva) const { static_assert(std::is_pointer_v); return convert_fo_to_ptr(convert_rva_to_fo(rva)); } [[nodiscard]] rva_t convert_fo_to_rva(fo_t file_offset) const; [[nodiscard]] va_t convert_fo_to_va(fo_t file_offset) const; template [[nodiscard]] ptr_t convert_fo_to_ptr(fo_t file_offset) const noexcept { static_assert(std::is_pointer_v); return reinterpret_cast(image_base() + file_offset); } [[nodiscard]] rva_t convert_va_to_rva(va_t va) const noexcept; [[nodiscard]] fo_t convert_va_to_fo(va_t va) const; template [[nodiscard]] ptr_t convert_va_to_ptr(va_t va) const noexcept { return convert_rva_to_ptr(convert_va_to_rva(va)); } template [[nodiscard]] fo_t convert_ptr_to_fo(ptr_t ptr) const noexcept { static_assert(std::is_pointer_v); return reinterpret_cast(ptr) - image_base(); } template [[nodiscard]] rva_t convert_ptr_to_rva(ptr_t ptr) const { return convert_fo_to_rva(convert_ptr_to_fo(ptr)); } template [[nodiscard]] va_t convert_ptr_to_va(ptr_t ptr) const { return convert_fo_to_va(convert_ptr_to_fo(ptr)); } [[nodiscard]] size_t number_of_sections() const noexcept; template [[nodiscard]] ptr_t image_section_view(size_t n, size_t offset = 0) const { static_assert(std::is_pointer_v); return reinterpret_cast(image_base() + image_section_header(n)->PointerToRawData + offset); } template [[nodiscard]] ptr_t image_section_view(std::string_view section_name, size_t offset = 0) const { static_assert(std::is_pointer_v); return reinterpret_cast(image_base() + image_section_header(section_name)->PointerToRawData + offset); } template [[nodiscard]] ptr_t search_section(size_t n, pred_func_t&& pred_func) const { static_assert(std::is_pointer_v); auto section_header = image_section_header(n); auto begin = image_base() + section_header->PointerToRawData; auto end = begin + section_header->Misc.VirtualSize; for (; begin < end; ++begin) { if (pred_func(begin, end - begin)) { return reinterpret_cast(const_cast(begin)); } } return nullptr; } template [[nodiscard]] ptr_t search_section(std::string_view section_name, pred_func_t&& pred_func) const { static_assert(std::is_pointer_v); auto section_header = image_section_header(section_name); auto begin = image_base() + section_header->PointerToRawData; auto end = begin + section_header->Misc.VirtualSize; for (; begin < end; ++begin) { if (pred_func(begin, end - begin)) { return reinterpret_cast(const_cast(begin)); } } return nullptr; } PIMAGE_IMPORT_DESCRIPTOR import_descriptor_from_rva(rva_t rva); PIMAGE_THUNK_DATA import_lookup_entry_from_rva(rva_t rva); auto& relocation_distribute() { return m_relocation_rva_lookup_table; } }; }