navicat-keygen/navicat-patcher/X64ImageInterpreter.hpp
2019-12-10 13:21:09 +08:00

223 lines
7.9 KiB
C++

#pragma once
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <string.h>
#include <vector>
#include <map>
#include "Exception.hpp"
#include "ExceptionGeneric.hpp"
#include "MemoryAccess.hpp"
namespace nkg {
using X64ImageAddress = decltype(section_64::addr);
using X64ImageOffset = decltype(section_64::offset);
class X64ImageInterpreter {
private:
size_t m_MachOSize;
const mach_header_64* m_MachOHeader;
std::vector<const segment_command_64*> m_Segments;
std::vector<const section_64*> m_Sections;
std::map<X64ImageAddress, const section_64*> m_SectionsAddressMap;
std::map<X64ImageOffset, const section_64*> m_SectionsOffsetMap;
struct {
const dysymtab_command* dysymtab;
const symtab_command* symtab;
const dyld_info_command* dyld_info;
} m_SpecialLoadCommands;
X64ImageInterpreter() :
m_MachOSize(0),
m_MachOHeader(nullptr),
m_SpecialLoadCommands{} {}
public:
[[nodiscard]]
static X64ImageInterpreter Parse(const void* lpImage, size_t cbImage);
template<typename __ReturnType = void*>
[[nodiscard]]
__ReturnType ImageBase() const noexcept {
static_assert(std::is_pointer_v<__ReturnType>);
return reinterpret_cast<__ReturnType>(
const_cast<mach_header_64*>(m_MachOHeader)
);
}
template<typename __ReturnType = void*>
[[nodiscard]]
__ReturnType ImageOffset(size_t Offset) const {
if (Offset < m_MachOSize) {
return ARL::AddressOffsetWithCast<__ReturnType>(m_MachOHeader, Offset);
} else {
throw ARL::OverflowError(__FILE__, __LINE__, "X64ImageInterpreter: out of range.");
}
}
[[nodiscard]]
size_t ImageSize() const noexcept {
return m_MachOSize;
}
[[nodiscard]]
size_t NumberOfSegmentCommands() const noexcept;
[[nodiscard]]
size_t NumberOfSections() const noexcept;
[[nodiscard]]
const section_64* ImageSection(size_t Index) const;
[[nodiscard]]
const section_64* ImageSection(const char* SegmentName, const char* SectionName) const;
[[nodiscard]]
const section_64* ImageSectionFromOffset(X64ImageOffset Offset) const;
[[nodiscard]]
const section_64* ImageSectionFromRva(X64ImageAddress Rva) const;
template<typename __ReturnType = void*>
[[nodiscard]]
__ReturnType ImageSectionView(const section_64* Section) const noexcept {
return ImageOffset<__ReturnType>(Section->offset);
}
template<typename __ReturnType = void*>
[[nodiscard]]
__ReturnType ImageSectionView(size_t Index) const {
return ImageSectionView<__ReturnType>(ImageSection(Index));
}
template<typename __ReturnType = void*>
[[nodiscard]]
__ReturnType ImageSectionView(const char* SegmentName, const char* SectionName) const {
return ImageSectionView<__ReturnType>(ImageSection(SegmentName, SectionName));
}
template<unsigned __CommandMacro>
[[nodiscard]]
auto SpecialLoadCommand() const noexcept {
if constexpr (__CommandMacro == LC_DYSYMTAB) {
return m_SpecialLoadCommands.dysymtab;
} else if constexpr (__CommandMacro == LC_SYMTAB) {
return m_SpecialLoadCommands.symtab;
} else if constexpr (__CommandMacro == LC_DYLD_INFO_ONLY) {
return m_SpecialLoadCommands.dyld_info;
} else {
#pragma clang diagnostic push
#pragma GCC diagnostic ignored "-Wtautological-compare"
constexpr bool always_false = __CommandMacro != __CommandMacro;
#pragma clang diagnostic pop
static_assert(always_false);
}
}
template<typename __ReturnType = void*, typename __HintType>
[[nodiscard]]
__ReturnType SearchSection(const section_64* Section, __HintType&& Hint) const {
static_assert(std::is_pointer_v<__ReturnType>);
auto base = ImageSectionView<const uint8_t*>(Section);
for (decltype(section_64::size) i = 0; i < Section->size; ++i) {
if (Hint(base, i, Section->size) == true) {
return ARL::AddressOffsetWithCast<__ReturnType>(base, i);
}
}
return nullptr;
}
template<typename __ReturnType = void*, typename __HintType>
[[nodiscard]]
__ReturnType SearchSection(const section_64* Section, size_t Offset, __HintType&& Hint) const {
static_assert(std::is_pointer_v<__ReturnType>);
auto base = ImageSectionView<const uint8_t*>(Section);
for (decltype(section_64::size) i = Offset; i < Section->size; ++i) {
if (Hint(base, i, Section->size) == true) {
return ARL::AddressOffsetWithCast<__ReturnType>(base, i);
}
}
return nullptr;
}
template<typename __ReturnType = void*, typename __HintType>
[[nodiscard]]
__ReturnType SearchSection(size_t Index, __HintType&& Hint) const {
return SearchSection<__ReturnType>(ImageSection(Index), std::forward<__HintType>(Hint));
}
template<typename __ReturnType = void*, typename __HintType>
[[nodiscard]]
__ReturnType SearchSection(size_t Index, size_t Offset, __HintType&& Hint) const {
return SearchSection<__ReturnType>(ImageSection(Index), Offset, std::forward<__HintType>(Hint));
}
template<typename __ReturnType = void*, typename __HintType>
[[nodiscard]]
__ReturnType SearchSection(const char* SegmentName, const char* SectionName, __HintType&& Hint) const {
return SearchSection<__ReturnType>(ImageSection(SegmentName, SectionName), std::forward<__HintType>(Hint));
}
template<typename __ReturnType = void*, typename __HintType>
[[nodiscard]]
__ReturnType SearchSection(const char* SegmentName, const char* SectionName, size_t Offset, __HintType&& Hint) const {
return SearchSection<__ReturnType>(ImageSection(SegmentName, SectionName), Offset, std::forward<__HintType>(Hint));
}
[[nodiscard]]
X64ImageAddress ConvertOffsetToRva(X64ImageOffset Offset) const;
template<typename __ReturnType = void*>
[[nodiscard]]
__ReturnType ConvertOffsetToPtr(X64ImageOffset Offset) const {
return ImageOffset<__ReturnType>(Offset);
}
[[nodiscard]]
X64ImageOffset ConvertRvaToOffset(X64ImageAddress Address) const;
template<typename __ReturnType = void*>
[[nodiscard]]
__ReturnType ConvertRvaToPtr(X64ImageAddress Rva) const {
return ConvertOffsetToPtr<__ReturnType>(ConvertRvaToOffset(Rva));
}
template<typename __PtrType>
[[nodiscard]]
X64ImageAddress ConvertPtrToRva(__PtrType Ptr) const {
auto offset = ARL::AddressDelta(Ptr, m_MachOHeader);
if (offset < m_MachOSize) {
return ConvertOffsetToRva(offset);
} else {
throw ARL::OverflowError(__FILE__, __LINE__, "X64ImageInterpreter: out of range.");
}
}
template<typename __PtrType>
[[nodiscard]]
X64ImageAddress ConvertPtrToOffset(__PtrType Ptr) const {
auto offset = ARL::AddressDelta(Ptr, m_MachOHeader);
if (offset < m_MachOSize) {
return offset;
} else {
throw ARL::OverflowError(__FILE__, __LINE__, "X64ImageInterpreter: out of range.");
}
}
};
}