123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- #include "ImageInterpreter.hpp"
- #undef NKG_CURRENT_SOURCE_FILE
- #undef NKG_CURRENT_SOURCE_LINE
- #define NKG_CURRENT_SOURCE_FILE() TEXT(".\\navicat-patcher\\ImageInterpreter.cpp")
- #define NKG_CURRENT_SOURCE_LINE() __LINE__
- namespace nkg {
- ImageInterpreter::ImageInterpreter() :
- _DosHeader(nullptr),
- _NtHeaders(nullptr),
- _SectionHeaderTable(nullptr),
- _VsFixedFileInfo(nullptr) {}
- [[nodiscard]]
- ImageInterpreter ImageInterpreter::ParseImage(PVOID ImageBase, bool DisableRelocationParsing) {
- ImageInterpreter NewImage;
- NewImage._DosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(ImageBase);
- if (NewImage._DosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (DOS signature check failure)"))
- .AddHint(TEXT("Are you sure you DO provide a valid WinPE file?"));
- }
- NewImage._NtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(
- reinterpret_cast<uint8_t*>(ImageBase) + NewImage._DosHeader->e_lfanew
- );
- if (NewImage._NtHeaders->Signature != IMAGE_NT_SIGNATURE) {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (NT signature check failure)"))
- .AddHint(TEXT("Are you sure you DO provide a valid WinPE file?"));
- }
-
- #if defined(_M_AMD64)
- if (NewImage._NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (Optional header magic check failure)"))
- .AddHint(TEXT("Are you sure you DO provide a valid 64-bits WinPE file?"));
- }
- if (NewImage._NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (Machine check failure)"))
- .AddHint(TEXT("Are you sure you DO provide a valid 64-bits WinPE file?"));
- }
- #elif defined(_M_IX86)
- if (NewImage._NtHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (Optional header magic check failure)"))
- .AddHint(TEXT("Are you sure you DO provide a valid 32-bits WinPE file?"));
- }
- if (NewImage._NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Invalid Image. (Machine check failure)"))
- .AddHint(TEXT("Are you sure you DO provide a valid 32-bits WinPE file?"));
- }
- #else
- #error "Unsupported architecture."
- #endif
- NewImage._SectionHeaderTable = reinterpret_cast<PIMAGE_SECTION_HEADER>(
- reinterpret_cast<char*>(&NewImage._NtHeaders->OptionalHeader) + NewImage._NtHeaders->FileHeader.SizeOfOptionalHeader
- );
- for (WORD i = 0; i < NewImage._NtHeaders->FileHeader.NumberOfSections; ++i) {
- uint64_t SectionName = *reinterpret_cast<uint64_t*>(NewImage._SectionHeaderTable[i].Name);
- if (NewImage._SectionNameTable.find(SectionName) == NewImage._SectionNameTable.end()) {
- NewImage._SectionNameTable[SectionName] = i;
- }
- NewImage._SectionRvaTable[NewImage._SectionHeaderTable[i].VirtualAddress] = i;
- NewImage._SectionFileOffsetTable[NewImage._SectionHeaderTable[i].PointerToRawData] = i;
- }
- if (!DisableRelocationParsing && NewImage._NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) {
- auto RelocTableRva = NewImage._NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
- auto RelocTable = NewImage.RvaToPointer<PIMAGE_BASE_RELOCATION>(RelocTableRva);
- while (RelocTable->VirtualAddress != 0) {
- uintptr_t Rva = RelocTable->VirtualAddress;
- PWORD RelocItems = reinterpret_cast<PWORD>(RelocTable + 1);
- DWORD RelocItemsCount = (RelocTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
- for (DWORD i = 0; i < RelocItemsCount; ++i) {
- auto RelocType = RelocItems[i] >> 12;
- switch (RelocType) {
- case IMAGE_REL_BASED_ABSOLUTE:
- break;
- case IMAGE_REL_BASED_HIGH:
- case IMAGE_REL_BASED_LOW:
- case IMAGE_REL_BASED_HIGHADJ:
- NewImage._RelocationRvaTable[Rva + (RelocItems[i] & 0x0fff)] = 2;
- break;
- case IMAGE_REL_BASED_HIGHLOW:
- NewImage._RelocationRvaTable[Rva + (RelocItems[i] & 0x0fff)] = 4;
- break;
- #if defined(IMAGE_REL_BASED_DIR64)
- case IMAGE_REL_BASED_DIR64:
- NewImage._RelocationRvaTable[Rva + (RelocItems[i] & 0x0fff)] = 8;
- break;
- #endif
- default:
- break;
- }
- }
- RelocTable = reinterpret_cast<PIMAGE_BASE_RELOCATION>(&RelocItems[RelocItemsCount]);
- }
- }
- if (NewImage._NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) {
- uintptr_t ResourceRva = NewImage._NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
- auto ResourceTypeTable =
- NewImage.RvaToPointer<PIMAGE_RESOURCE_DIRECTORY>(ResourceRva);
- auto ResourceTypeNameEntries =
- reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(ResourceTypeTable + 1);
- auto ResourceTypeIdEntries =
- ResourceTypeNameEntries + ResourceTypeTable->NumberOfNamedEntries;
- bool VS_FII_Ok = false;
- for (WORD i = 0; i < ResourceTypeTable->NumberOfIdEntries && !VS_FII_Ok; ++i) {
- if (ResourceTypeIdEntries[i].Id == reinterpret_cast<uintptr_t>(RT_VERSION) && ResourceTypeIdEntries[i].DataIsDirectory) {
- auto ResourceNameTable =
- NewImage.RvaToPointer<PIMAGE_RESOURCE_DIRECTORY>(ResourceRva + ResourceTypeIdEntries[i].OffsetToDirectory);
- auto ResourceNameNameEntries =
- reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(ResourceNameTable + 1);
- auto ResourceNameIdEntries =
- ResourceNameNameEntries + ResourceNameTable->NumberOfNamedEntries;
- for (WORD j = 0; j < ResourceNameTable->NumberOfIdEntries && !VS_FII_Ok; ++j) {
- if (ResourceNameIdEntries[j].Id == VS_VERSION_INFO && ResourceNameIdEntries[j].DataIsDirectory) {
- auto ResourceLangTable =
- NewImage.RvaToPointer<PIMAGE_RESOURCE_DIRECTORY>(ResourceRva + ResourceNameIdEntries[j].OffsetToDirectory);
- auto ResourceLangNameEntries =
- reinterpret_cast<PIMAGE_RESOURCE_DIRECTORY_ENTRY>(ResourceLangTable + 1);
- auto ResourceLangIdEntries =
- ResourceLangNameEntries + ResourceLangTable->NumberOfNamedEntries;
-
- for (WORD k = 0; k < ResourceLangTable->NumberOfIdEntries && !VS_FII_Ok; ++k) {
- if (ResourceLangIdEntries[k].Id == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) && !ResourceLangIdEntries[k].DataIsDirectory) {
- auto ResourceDataEntry =
- NewImage.RvaToPointer<PIMAGE_RESOURCE_DATA_ENTRY>(ResourceRva + ResourceLangIdEntries[k].OffsetToData);
- auto VsVersionInfo = NewImage.RvaToPointer<PBYTE>(ResourceDataEntry->OffsetToData);
- auto VsVersionInfoszKey = reinterpret_cast<PWSTR>(VsVersionInfo + 6);
- if (_wcsicmp(VsVersionInfoszKey, L"VS_VERSION_INFO") == 0) {
- auto p = reinterpret_cast<PBYTE>(VsVersionInfoszKey + _countof(L"VS_VERSION_INFO"));
- while (NewImage.PointerToRva(p) % sizeof(DWORD)) {
- ++p;
- }
- if (reinterpret_cast<VS_FIXEDFILEINFO*>(p)->dwSignature == VS_FFI_SIGNATURE) {
- NewImage._VsFixedFileInfo = reinterpret_cast<VS_FIXEDFILEINFO*>(p);
- VS_FII_Ok = true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return NewImage;
- }
- [[nodiscard]]
- PIMAGE_DOS_HEADER ImageInterpreter::ImageDosHeader() const noexcept {
- return _DosHeader;
- }
- [[nodiscard]]
- PIMAGE_NT_HEADERS ImageInterpreter::ImageNtHeaders() const noexcept {
- return _NtHeaders;
- }
- [[nodiscard]]
- PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionTable() const noexcept {
- return _SectionHeaderTable;
- }
- [[nodiscard]]
- PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeader(size_t Idx) const {
- if (Idx < _NtHeaders->FileHeader.NumberOfSections) {
- return _SectionHeaderTable + Idx;
- } else {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Idx is out of range."));
- }
- }
- [[nodiscard]]
- PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByName(PCSTR lpszSectionName) const {
- uint64_t NameValue = 0;
- for (int i = 0; i < sizeof(NameValue) && lpszSectionName[i]; ++i)
- reinterpret_cast<PSTR>(&NameValue)[i] = lpszSectionName[i];
- auto it = _SectionNameTable.find(NameValue);
- if (it == _SectionNameTable.end()) {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Target section header is not found."))
- .AddHint(std::xstring::format(TEXT("lpszSectionName = %s"), lpszSectionName));
- }
- return &_SectionHeaderTable[it->second];
- }
- [[nodiscard]]
- PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByRva(uintptr_t Rva) const {
- auto it = _SectionRvaTable.upper_bound(Rva);
- if (it != _SectionRvaTable.begin()) {
- --it;
- }
- auto SectionHeader = &_SectionHeaderTable[it->second];
- uintptr_t SectionRvaBegin = SectionHeader->VirtualAddress;
- uintptr_t SectionRvaEnd = SectionRvaBegin + SectionHeader->Misc.VirtualSize;
- if (SectionRvaBegin <= Rva && Rva < SectionRvaEnd) {
- return SectionHeader;
- } else {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Target section header is not found."))
- .AddHint(std::xstring::format(TEXT("Rva = 0x%zx"), Rva));
- }
- }
- [[nodiscard]]
- PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByVa(uintptr_t Va) const {
- return ImageSectionHeaderByRva(Va - _NtHeaders->OptionalHeader.ImageBase);
- }
- [[nodiscard]]
- PIMAGE_SECTION_HEADER ImageInterpreter::ImageSectionHeaderByFileOffset(uintptr_t FileOffset) const {
- auto it = _SectionFileOffsetTable.upper_bound(FileOffset);
- if (it != _SectionFileOffsetTable.begin()) {
- --it;
- }
- auto SectionHeader = &_SectionHeaderTable[it->second];
- uintptr_t SectionFileOffsetBegin = SectionHeader->PointerToRawData;
- uintptr_t SectionFileOffsetEnd = SectionFileOffsetBegin + SectionHeader->SizeOfRawData;
- if (SectionFileOffsetBegin <= FileOffset && FileOffset < SectionFileOffsetEnd) {
- return SectionHeader;
- } else {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Target section header is not found."))
- .AddHint(std::xstring::format(TEXT("FileOffset = 0x%zx"), FileOffset));
- }
- }
- [[nodiscard]]
- uintptr_t ImageInterpreter::RvaToVa(uintptr_t Rva) const noexcept {
- return Rva + _NtHeaders->OptionalHeader.ImageBase;
- }
- [[nodiscard]]
- uintptr_t ImageInterpreter::RvaToFileOffset(uintptr_t Rva) const {
- auto SectionHeader = ImageSectionHeaderByRva(Rva);
- return SectionHeader->PointerToRawData + (Rva - static_cast<uintptr_t>(SectionHeader->VirtualAddress));
- }
- [[nodiscard]]
- uintptr_t ImageInterpreter::FileOffsetToRva(uintptr_t FileOffset) const {
- auto SectionHeader = ImageSectionHeaderByFileOffset(FileOffset);
- return SectionHeader->VirtualAddress + (FileOffset - SectionHeader->PointerToRawData);
- }
- [[nodiscard]]
- uintptr_t ImageInterpreter::FileOffsetToVa(uintptr_t FileOffset) const {
- return FileOffsetToRva(FileOffset) + _NtHeaders->OptionalHeader.ImageBase;
- }
- [[nodiscard]]
- uintptr_t ImageInterpreter::VaToRva(uintptr_t Va) const noexcept {
- return Va - _NtHeaders->OptionalHeader.ImageBase;
- }
- [[nodiscard]]
- uintptr_t ImageInterpreter::VaToFileOffset(uintptr_t Va) const {
- return ImageSectionHeaderByVa(Va)->PointerToRawData;
- }
- [[nodiscard]]
- bool ImageInterpreter::IsRvaRangeInRelocTable(uintptr_t Rva, size_t Size) const {
- auto it = _RelocationRvaTable.upper_bound(Rva);
- if (it != _RelocationRvaTable.begin()) {
- --it;
- }
- return it->first <= Rva && Rva < it->first + it->second;
- }
- [[nodiscard]]
- bool ImageInterpreter::IsVaRangeInRelocTable(uintptr_t Va, size_t Size) const {
- return IsRvaRangeInRelocTable(VaToRva(Va), Size);
- }
- [[nodiscard]]
- bool ImageInterpreter::IsFileOffsetRangeInRelocTable(uintptr_t FileOffset, size_t Size) const {
- return IsRvaRangeInRelocTable(FileOffsetToRva(FileOffset), Size);
- }
- [[nodiscard]]
- DWORD ImageInterpreter::ImageFileMajorVersion() const {
- if (_VsFixedFileInfo) {
- return _VsFixedFileInfo->dwFileVersionMS;
- } else {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Image does not have version info."));
- }
- }
- [[nodiscard]]
- DWORD ImageInterpreter::ImageFileMinorVersion() const {
- if (_VsFixedFileInfo) {
- return _VsFixedFileInfo->dwFileVersionLS;
- } else {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Image does not have version info."));
- }
- }
- [[nodiscard]]
- DWORD ImageInterpreter::ImageProductMajorVersion() const {
- if (_VsFixedFileInfo) {
- return _VsFixedFileInfo->dwProductVersionMS;
- } else {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Image does not have version info."));
- }
- }
- [[nodiscard]]
- DWORD ImageInterpreter::ImageProductMinorVersion() const {
- if (_VsFixedFileInfo) {
- return _VsFixedFileInfo->dwProductVersionLS;
- } else {
- throw Exception(NKG_CURRENT_SOURCE_FILE(), NKG_CURRENT_SOURCE_LINE(), TEXT("Image does not have version info."));
- }
- }
- [[nodiscard]]
- size_t ImageInterpreter::NumberOfSections() const noexcept {
- return _NtHeaders->FileHeader.NumberOfSections;
- }
- }
|