From a5fbd06db99fb20e2a84cf5d8caed17db43db643 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 16 Jun 2020 08:39:46 +0200 Subject: [PATCH 01/34] ImageLoader: Import Directory 1 --- include/retdec/pelib/ImageLoader.h | 216 +++++ src/pelib/ImageLoader.cpp | 1411 ++++++++++++++++++++++++++++ src/pelib/PelibTest.cpp | 466 +++++++++ src/pelib/PelibTest_vs17.sln | 31 + 4 files changed, 2124 insertions(+) create mode 100644 include/retdec/pelib/ImageLoader.h create mode 100644 src/pelib/ImageLoader.cpp create mode 100644 src/pelib/PelibTest.cpp create mode 100644 src/pelib/PelibTest_vs17.sln diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h new file mode 100644 index 000000000..f05851a7b --- /dev/null +++ b/include/retdec/pelib/ImageLoader.h @@ -0,0 +1,216 @@ +/* +* ImageLoader.h - Interface to the PE imaage loader class +* +* Copyright (c) 2020 Ladislav Zezula +* All rights reserved. +* +* This software is licensed under the zlib/libpng License. +* For more details see http://www.opensource.org/licenses/zlib-license.php +* or the license information file (license.htm) in the root directory +* of PeLib. +*/ + +#ifndef IMAGE_LOADER_H +#define IMAGE_LOADER_H + +#include +#include + +#include "PeLibAux.h" + +namespace PeLib { + +//----------------------------------------------------------------------------- +// Enum for Windows loader emulation + +enum : std::uint32_t +{ + LoaderModeWindowsXP = 0x51, // Behavior equal to Windows XP + LoaderModeWindows7 = 0x61, // Behavior equal to Windows 7 + LoaderModeWindows10 = 0xA0, // Behavior equal to Windows 10 + WindowsVerMask = 0x0FFF, // Mask for extracting the operating system + StrictMode = 0x1000, // Strict mode. Refuse to load images that are cut + SecImageNoExecute = 0x2000, // As if the image was loaded with SEC_IMAGE_NO_EXECUTE +}; + +//----------------------------------------------------------------------------- +// Support structure for one PE image compare result + +enum PELIB_COMPARE_RESULT : std::uint32_t +{ + ImagesEqual, // The images are equal + ImagesWindowsLoadedWeDidnt, // + ImagesWindowsDidntLoadWeDid, // + ImagesDifferentSize, // The images have different size + ImagesDifferentPageAccess, // An image page is different (accessible vs non-accessible) + ImagesDifferentPageValue, // There is a different value at a certain offset +}; + +typedef bool (_cdecl * PFN_VERIFY_ADDRESS)(void * ptr, size_t length); + +struct PELIB_IMAGE_COMPARE +{ + PFN_VERIFY_ADDRESS PfnVerifyAddress; // Custom function for verifying memory address + PELIB_COMPARE_RESULT compareResult; + const char * dumpIfNotEqual; // If non-NULL, the image will be dumped into that file + std::uint32_t differenceOffset; +}; + +//----------------------------------------------------------------------------- +// Support structure for one PE file page + +struct PELIB_FILE_PAGE +{ + PELIB_FILE_PAGE() + { + isInvalidPage = true; + isZeroPage = false; + } + + ~PELIB_FILE_PAGE() + {} + + // Initializes the page with a valid data + bool setValidPage(const void * data, size_t length) + { + // Write the valid data to the page + writeToPage(data, 0, length); + + // Write zero data to the end of the page + memset(buffer.data() + length, 0, PELIB_PAGE_SIZE - length); + + isInvalidPage = false; + isZeroPage = false; + return true; + } + + // Initializes the page as zero page. To save memory, we won't initialize buffer + void setZeroPage() + { + buffer.clear(); + isInvalidPage = false; + isZeroPage = true; + } + + void writeToPage(const void * data, size_t offset, size_t length) + { + if(offset < PELIB_PAGE_SIZE) + { + // Make sure that there is buffer allocated + if(buffer.size() != PELIB_PAGE_SIZE) + buffer.resize(PELIB_PAGE_SIZE); + + // Copy the data, up to page size + if((offset + length) > PELIB_PAGE_SIZE) + length = PELIB_PAGE_SIZE - offset; + memcpy(buffer.data() + offset, data, length); + } + } + + std::vector buffer; // A page-sized buffer, holding one image page. Empty if isInvalidPage + bool isInvalidPage; // For invalid pages within image (SectionAlignment > 0x1000) + bool isZeroPage; // For sections with VirtualSize != 0, RawSize = 0 +}; + +//----------------------------------------------------------------------------- +// Image loader class interface + +class ImageLoader +{ + public: + + ImageLoader(std::uint32_t loaderFlags = 0); + ~ImageLoader(); + + int Load(std::vector & fileData, bool loadHeadersOnly = false); + int Load(std::ifstream & fs, std::streamoff fileOffset = 0, bool loadHeadersOnly = false); + int Load(const char * fileName, bool loadHeadersOnly = false); + + bool relocateImage(std::uint64_t newImageBase); + + std::uint32_t readImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead); + std::uint32_t writeImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead); + + std::uint32_t dumpImage(const char * fileName); + + std::uint64_t getImageBase(); + std::uint32_t getSizeOfImage(); + std::uint32_t getSizeOfImageAligned(); + std::uint32_t getFileOffsetFromRva(std::uint32_t rva); + std::uint32_t getImageProtection(std::uint32_t characteristics); + + int setLoaderError(LoaderError ldrErr); + LoaderError loaderError(); + + // Testing function + void compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & ImageCompare, void * imageData, std::uint32_t imageSize); + + protected: + + typedef void (*READWRITE)(PeLib::PELIB_FILE_PAGE & page, void * buffer, std::size_t offsetInPage, std::size_t bytesInPage); + + static void readFromPage(PELIB_FILE_PAGE & page, void * buffer, size_t offsetInPage, size_t bytesInPage); + static void writeToPage(PELIB_FILE_PAGE & page, void * buffer, size_t offsetInPage, size_t bytesInPage); + std::uint32_t readWriteImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead, READWRITE ReadWrite); + + bool processImageRelocations(std::uint64_t oldImageBase, std::uint64_t getImageBase, std::uint32_t VirtualAddress, std::uint32_t Size); + void writeNewImageBase(std::uint64_t newImageBase); + + int captureDosHeader(std::vector & fileData); + int captureNtHeaders(std::vector & fileData); + int captureSectionHeaders(std::vector & fileData); + int captureImageSections(std::vector & fileData); + int captureOptionalHeader32(std::uint8_t * filePtr, std::uint8_t * fileEnd); + int captureOptionalHeader64(std::uint8_t * filePtr, std::uint8_t * fileEnd); + + int loadImageAsIs(std::vector & fileData); + + std::size_t getMismatchOffset(void * buffer1, void * buffer2, std::uint32_t rva, std::size_t length); + + std::uint32_t captureImageSection(std::vector & fileData, + std::uint32_t virtualAddress, + std::uint32_t virtualSize, + std::uint32_t pointerToRawData, + std::uint32_t sizeOfRawData, + std::uint32_t characteristics, + bool isImageHeader = false); + + bool isGoodPagePointer(PFN_VERIFY_ADDRESS PfnVerifyAddress, void * pagePtr); + bool isGoodMappedPage(std::uint32_t rva); + bool isZeroPage(std::uint32_t rva); + + bool isRvaOfSectionHeaderPointerToRawData(uint32_t rva); + bool isLegacyImageArchitecture(std::uint16_t Machine); + bool checkForBadAppContainer(); + bool isImageMappedOk(); + + std::uint32_t AlignToSize(std::uint32_t ByteSize, std::uint32_t AlignSize) + { + return ((ByteSize + (AlignSize - 1)) & ~(AlignSize - 1)); + } + + std::uint32_t BytesToPages(std::uint32_t ByteSize) + { + return (ByteSize >> PELIB_PAGE_SIZE_SHIFT) + ((ByteSize & (PELIB_PAGE_SIZE - 1)) != 0); + } + + static uint8_t ImageProtectionArray[16]; + + std::vector sections; // Vector of headers + std::vector pages; // PE file pages as if mapped + std::vector imageAsIs; // Loaded content of the image in case it couldn't have been mapped + PELIB_IMAGE_DOS_HEADER dosHeader; // Loaded DOS header + PELIB_IMAGE_FILE_HEADER fileHeader; // Loaded NT file header + PELIB_IMAGE_OPTIONAL_HEADER optionalHeader; // 32/64-bit optional header + LoaderError ldrError; + std::uint32_t loaderMode; + std::uint32_t maxSectionCount; + bool ntHeadersSizeCheck; // If true, the loader requires minimum size of NT headers + bool sizeofImageMustMatch; // If true, the SizeOfImage must match virtual end of the last section + bool appContainerCheck; // If true, app container flag is tested in the optional header + bool strictMode; // If true, the loader refuses corrupt images like Windows loader would do +}; + +} // namespace PeLib + +#endif // IMAGE_LOADER_H diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp new file mode 100644 index 000000000..d009ede7a --- /dev/null +++ b/src/pelib/ImageLoader.cpp @@ -0,0 +1,1411 @@ +/*****************************************************************************/ +/* ImageLoader.cpp Copyright (c) Ladislav Zezula 2020 */ +/*---------------------------------------------------------------------------*/ +/* Implementation of PE image loader */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.05.20 1.00 Lad Created */ +/*****************************************************************************/ + +#include +#include + +#include "ImageLoader.h" + +//----------------------------------------------------------------------------- +// Anti-headache + +using std::uint8_t; +using std::uint16_t; +using std::uint32_t; +using std::uint64_t; +using std::int16_t; +using std::int32_t; +using std::int64_t; +using std::size_t; + +//----------------------------------------------------------------------------- +// Static class variables + +uint8_t PeLib::ImageLoader::ImageProtectionArray[16] = +{ + PELIB_PAGE_NOACCESS, + PELIB_PAGE_EXECUTE, + PELIB_PAGE_READONLY, + PELIB_PAGE_EXECUTE_READ, + PELIB_PAGE_WRITECOPY, + PELIB_PAGE_EXECUTE_WRITECOPY, + PELIB_PAGE_WRITECOPY, + PELIB_PAGE_EXECUTE_WRITECOPY, + PELIB_PAGE_NOACCESS, + PELIB_PAGE_EXECUTE, + PELIB_PAGE_READONLY, + PELIB_PAGE_EXECUTE_READ, + PELIB_PAGE_READWRITE, + PELIB_PAGE_EXECUTE_READWRITE, + PELIB_PAGE_READWRITE, + PELIB_PAGE_EXECUTE_READWRITE +}; + +//----------------------------------------------------------------------------- +// Constructor and destructor + +PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) +{ + memset(&dosHeader, 0, sizeof(PELIB_IMAGE_DOS_HEADER)); + memset(&fileHeader, 0, sizeof(PELIB_IMAGE_FILE_HEADER)); + memset(&optionalHeader, 0, sizeof(PELIB_IMAGE_OPTIONAL_HEADER)); + ldrError = LDR_ERROR_NONE; + + // By default, set the most benevolent settings + sizeofImageMustMatch = false; + ntHeadersSizeCheck = false; + appContainerCheck = false; + maxSectionCount = 255; + + // Resolve os-specific restrictions + switch(loaderMode = (loaderFlags & WindowsVerMask)) + { + case LoaderModeWindowsXP: + maxSectionCount = PE_MAX_SECTION_COUNT_XP; + sizeofImageMustMatch = true; + break; + + case LoaderModeWindows7: + maxSectionCount = PE_MAX_SECTION_COUNT_7; + ntHeadersSizeCheck = true; + sizeofImageMustMatch = true; + break; + + case LoaderModeWindows10: + maxSectionCount = PE_MAX_SECTION_COUNT_7; + ntHeadersSizeCheck = true; + appContainerCheck = true; + break; + } +} + +PeLib::ImageLoader::~ImageLoader() +{} + +//----------------------------------------------------------------------------- +// Public functions + +bool PeLib::ImageLoader::relocateImage(uint64_t newImageBase) +{ + uint32_t VirtualAddress; + uint32_t Size; + bool result = true; + + // Only relocate the image if the image base is different + if(newImageBase != optionalHeader.ImageBase) + { + // If relocations are stripped, there is no relocation + if(fileHeader.Characteristics & PELIB_IMAGE_FILE_RELOCS_STRIPPED) + return false; + + // Windows 10 (built 10240) performs this check + if(appContainerCheck && checkForBadAppContainer()) + return false; + + // Don't relocate 32-bit images to an address greater than 32bits + if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC && (newImageBase >> 32)) + return false; + + // Change the image base in the header. This happens even if the image does not have relocations. + // Sample: f5bae114007e5f5eb2a7e41fbd7cf4062b21e1a33e0648a07eb1e25c106bd7eb + writeNewImageBase(newImageBase); + + // The image must have relocation directory + if(optionalHeader.NumberOfRvaAndSizes <= PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC) + return false; + + // The relocation data directory must be valid + VirtualAddress = optionalHeader.DataDirectory[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + Size = optionalHeader.DataDirectory[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + if(VirtualAddress == 0 || Size == 0) + return false; + + // Resolve case when the reloc block is too big + if((VirtualAddress + Size) > getSizeOfImage()) + Size = getSizeOfImage() - VirtualAddress; + + // Perform relocations + result = processImageRelocations(optionalHeader.ImageBase, newImageBase, VirtualAddress, Size); + } + + return result; +} + +uint32_t PeLib::ImageLoader::readImage(void * buffer, uint32_t rva, uint32_t bytesToRead) +{ + return readWriteImage(buffer, rva, bytesToRead, readFromPage); +} + +uint32_t PeLib::ImageLoader::writeImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead) +{ + return readWriteImage(buffer, rva, bytesToRead, writeToPage); +} + +uint32_t PeLib::ImageLoader::dumpImage(const char * fileName) +{ + // Create the file for dumping + std::ofstream fs(fileName, std::ofstream::binary); + uint32_t bytesWritten = 0; + + if(fs.is_open()) + { + // Allocate one page filled with zeros + uint8_t zeroPage[PELIB_PAGE_SIZE] = {0}; + char * dataToWrite; + + // Write each page to the file + for(auto & page : pages) + { + dataToWrite = (char *)(page.buffer.size() ? page.buffer.data() : zeroPage); + fs.write(dataToWrite, PELIB_PAGE_SIZE); + bytesWritten += PELIB_PAGE_SIZE; + } + } + + return bytesWritten; +} + +uint64_t PeLib::ImageLoader::getImageBase() +{ + return optionalHeader.ImageBase; +} + +uint32_t PeLib::ImageLoader::getSizeOfImage() +{ + return optionalHeader.SizeOfImage; +} + +uint32_t PeLib::ImageLoader::getSizeOfImageAligned() +{ + return AlignToSize(optionalHeader.SizeOfImage, PELIB_PAGE_SIZE); +} + +uint32_t PeLib::ImageLoader::getFileOffsetFromRva(std::uint32_t rva) +{ + // If we have sections loaded, then we calculate the file offset from section headers + if(sections.size()) + { + // Check whether the rva goes into any section + for(auto & sectHdr : sections) + { + // Only if the pointer to raw data is not zero + if(sectHdr.PointerToRawData != 0 && sectHdr.SizeOfRawData != 0) + { + uint32_t sectionRvaStart = sectHdr.VirtualAddress; + uint32_t virtualSize = (sectHdr.VirtualSize != 0) ? sectHdr.VirtualSize : sectHdr.SizeOfRawData; + + if(sectionRvaStart <= rva && rva < (sectionRvaStart + virtualSize)) + { + // Make sure we round the pointer to raw data down to PELIB_SECTOR_SIZE. + // In case when PointerToRawData is less than 0x200, it maps to the header! + return sectHdr.PointerToRawData & ~(PELIB_SECTOR_SIZE - 1); + } + } + } + + // Check if the rva goes into the header + return (rva < optionalHeader.SizeOfHeaders) ? rva : UINT32_MAX; + } + + // The rva maps directly to the fille offset + return rva; +} + +uint32_t PeLib::ImageLoader::getImageProtection(std::uint32_t sectionCharacteristics) +{ + uint32_t Index = 0; + + if (sectionCharacteristics & PELIB_IMAGE_SCN_MEM_EXECUTE) + Index |= 1; + + if (sectionCharacteristics & PELIB_IMAGE_SCN_MEM_READ) + Index |= 2; + + if (sectionCharacteristics & PELIB_IMAGE_SCN_MEM_WRITE) + Index |= 4; + + if (sectionCharacteristics & PELIB_IMAGE_SCN_MEM_SHARED) + Index |= 8; + + return ImageProtectionArray[Index]; +} + +//----------------------------------------------------------------------------- +// Loader error + +int PeLib::ImageLoader::setLoaderError(PeLib::LoaderError ldrErr) +{ + // Do not override existing loader error + if(ldrError == LDR_ERROR_NONE) + { + ldrError = ldrErr; + } + return ERROR_NONE; +} + +PeLib::LoaderError PeLib::ImageLoader::loaderError() +{ + return ldrError; +} + +//----------------------------------------------------------------------------- +// Interface for loading files + +int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOnly) +{ + int fileError; + + // Check and capture DOS header + fileError = captureDosHeader(fileData); + if(fileError != ERROR_NONE) + return fileError; + + // Check and capture NT headers + fileError = captureNtHeaders(fileData); + if(fileError != ERROR_NONE) + return fileError; + + // Check and capture section headers + fileError = captureSectionHeaders(fileData); + if(fileError != ERROR_NONE) + return fileError; + + // Shall we map the image content? + if(loadHeadersOnly == false) + { + // If there was no detected image error, map the image as if Windows loader would do + if(ldrError == LDR_ERROR_NONE || ldrError == LDR_ERROR_FILE_IS_CUT_LOADABLE) + { + fileError = captureImageSections(fileData); + } + + // If there was any kind of error that prevents the image from being mapped, + // we load the content as-is and translate virtual addresses using getFileOffsetFromRva + if(pages.size() == 0) + { + fileError = loadImageAsIs(fileData); + } + } + + return fileError; +} + +int PeLib::ImageLoader::Load(std::ifstream & fs, std::streamoff fileOffset, bool loadHeadersOnly) +{ + std::vector fileData; + std::streampos fileSize; + size_t fileSize2; + + // Get the file size and move to the desired offset + fs.seekg(0, std::ios::end); + fileSize = fs.tellg(); + fs.seekg(fileOffset); + + // The file must be greater than sizeof DOS header + if(fileSize < sizeof(PELIB_IMAGE_DOS_HEADER)) + return ERROR_INVALID_FILE; + + // Windows loader refuses to load any file which is larger than 0xFFFFFFFF + if((fileSize >> 32) != 0) + return setLoaderError(LDR_ERROR_FILE_TOO_BIG); + fileSize2 = static_cast(fileSize); + + // Resize the vector so it can hold entire file + fileData.resize(fileSize2); + + // Read the entire file to memory + if(fs.read(reinterpret_cast(fileData.data()), fileSize2).bad()) + return false; + + // Call the Load interface on char buffer + return Load(fileData, loadHeadersOnly); +} + +int PeLib::ImageLoader::Load(const char * fileName, bool loadHeadersOnly) +{ + std::ifstream fs(fileName, std::ifstream::in | std::ifstream::binary); + if(!fs.is_open()) + return ERROR_OPENING_FILE; + + return Load(fs, loadHeadersOnly); +} + +//----------------------------------------------------------------------------- +// Protected functions + +void PeLib::ImageLoader::readFromPage(PELIB_FILE_PAGE & page, void * buffer, size_t offsetInPage, size_t bytesInPage) +{ + // Is it a page with actual data? + if(page.buffer.size()) + { + memcpy(buffer, page.buffer.data() + offsetInPage, bytesInPage); + } + else + { + memset(buffer, 0, bytesInPage); + } +} + +void PeLib::ImageLoader::writeToPage(PELIB_FILE_PAGE & page, void * buffer, size_t offsetInPage, size_t bytesInPage) +{ + // Write the data to the page + page.writeToPage(buffer, offsetInPage, bytesInPage); +} + +uint32_t PeLib::ImageLoader::readWriteImage(void * buffer, uint32_t rva, uint32_t bytesToRead, READWRITE ReadWrite) +{ + uint32_t bytesRead = 0; + uint32_t rvaEnd = rva + bytesToRead; + + // Check the last possible address where we read + if(rvaEnd > getSizeOfImageAligned()) + rvaEnd = getSizeOfImageAligned(); + + // Is the offset within the image? + if(rva < rvaEnd) + { + uint8_t * bufferPtr = static_cast(buffer); + size_t pageIndex = rva / PELIB_PAGE_SIZE; + + // The page index must be in range + if(pageIndex < pages.size()) + { + while(rva < rvaEnd) + { + PELIB_FILE_PAGE & page = pages[pageIndex++]; + uint32_t offsetInPage = rva & (PELIB_PAGE_SIZE - 1); + uint32_t bytesInPage = PELIB_PAGE_SIZE - offsetInPage; + + // Perhaps the last page loaded? + if(bytesInPage > (rvaEnd - rva)) + bytesInPage = (rvaEnd - rva); + + // Perform the read/write operation + ReadWrite(page, bufferPtr, offsetInPage, bytesInPage); + + // Move pointers + bufferPtr += bytesInPage; + bytesRead += bytesInPage; + rva += bytesInPage; + } + } + } + + // Return the number of bytes that were read + return bytesRead; +} + +bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t newImageBase, uint32_t VirtualAddress, uint32_t Size) +{ + uint64_t difference = (newImageBase - oldImageBase); + uint8_t * bufferEnd; + uint8_t * bufferPtr; + uint8_t * buffer; + + // No not accept anything less than size of relocation block + if(Size < sizeof(PELIB_IMAGE_BASE_RELOCATION)) + return false; + + // Allocate and read the relocation block + bufferPtr = buffer = new uint8_t[Size]; + if(buffer != nullptr) + { + // Read the relocations from the file + bufferEnd = buffer + readImage(buffer, VirtualAddress, Size); + + // Keep going while there is relocation blocks + while((bufferPtr + sizeof(PELIB_IMAGE_BASE_RELOCATION)) <= bufferEnd) + { + PELIB_IMAGE_BASE_RELOCATION * pRelocBlock = (PELIB_IMAGE_BASE_RELOCATION *)(bufferPtr); + uint16_t * typeAndOffset = (uint16_t * )(pRelocBlock + 1); + uint32_t numRelocations; + + // Skip relocation blocks which have invalid size in the header + if(pRelocBlock->SizeOfBlock <= sizeof(PELIB_IMAGE_BASE_RELOCATION)) + { + bufferPtr += sizeof(PELIB_IMAGE_BASE_RELOCATION); + continue; + } + + // Windows loader seems to skip relocation blocks that go into a zero page + // Sample: e380e6968f1b431e245f811f94cef6a5b6e17fd7c90ef283338fa1959eb3c536 + if(isZeroPage(pRelocBlock->VirtualAddress)) + { + bufferPtr += pRelocBlock->SizeOfBlock; + continue; + } + + // Calculate number of relocation entries. Prevent buffer overflow + if((bufferPtr + pRelocBlock->SizeOfBlock) > bufferEnd) + pRelocBlock->SizeOfBlock = bufferEnd - bufferPtr; + numRelocations = (pRelocBlock->SizeOfBlock - sizeof(PELIB_IMAGE_BASE_RELOCATION)) / sizeof(uint16_t); + + // Parse relocations + for(uint32_t i = 0; i < numRelocations; i++) + { + uint32_t fixupAddress = pRelocBlock->VirtualAddress + (typeAndOffset[i] & 0x0FFF); + int32_t temp; + + switch(typeAndOffset[i] >> 12) + { + case PELIB_IMAGE_REL_BASED_DIR64: // The base relocation applies the difference to the 64-bit field at offset. + { + int64_t fixupValue = 0; + + if(readImage(&fixupValue, fixupAddress, sizeof(fixupValue)) != sizeof(fixupValue)) + break; + fixupValue += difference; + writeImage(&fixupValue, fixupAddress, sizeof(fixupValue)); + break; + } + + case PELIB_IMAGE_REL_BASED_HIGHLOW: // The base relocation applies all 32 bits of the difference to the 32-bit field at offset. + { + int32_t fixupValue = 0; + + if(readImage(&fixupValue, fixupAddress, sizeof(fixupValue)) != sizeof(fixupValue)) + break; + fixupValue += (int32_t)difference; + writeImage(&fixupValue, fixupAddress, sizeof(fixupValue)); + break; + } + + case PELIB_IMAGE_REL_BASED_HIGH: // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. + { + int16_t fixupValue = 0; + + if(readImage(&fixupValue, fixupAddress, sizeof(fixupValue)) != sizeof(fixupValue)) + break; + temp = (fixupValue << 16); + temp += (int32_t)difference; + fixupValue = (int16_t)(temp >> 16); + writeImage(&fixupValue, fixupAddress, sizeof(fixupValue)); + break; + } + + case PELIB_IMAGE_REL_BASED_HIGHADJ: // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. + { + int16_t fixupValue = 0; + + if(readImage(&fixupValue, fixupAddress, sizeof(fixupValue)) != sizeof(fixupValue)) + break; + temp = (fixupValue << 16); + temp += (int32_t)typeAndOffset[++i]; + temp += (int32_t)difference; + temp += 0x8000; + fixupValue = (int16_t)(temp >> 16); + writeImage(&fixupValue, fixupAddress, sizeof(fixupValue)); + break; + } + + case PELIB_IMAGE_REL_BASED_LOW: // The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. + { + int16_t fixupValue = 0; + + if(readImage(&fixupValue, fixupAddress, sizeof(fixupValue)) != sizeof(fixupValue)) + break; + fixupValue = (int16_t)((int32_t)fixupValue + difference); + writeImage(&fixupValue, fixupAddress, sizeof(fixupValue)); + break; + } + + case PELIB_IMAGE_REL_BASED_MIPS_JMPADDR: // Relocate a MIPS jump address. + { + uint32_t fixupValue = 0; + + if(readImage(&fixupValue, fixupAddress, sizeof(fixupValue)) != sizeof(fixupValue)) + break; + temp = (fixupValue & 0x3ffffff) << 2; + temp += (int32_t)difference; + fixupValue = (fixupValue & ~0x3ffffff) | ((temp >> 2) & 0x3ffffff); + writeImage(&fixupValue, fixupAddress, sizeof(fixupValue)); + break; + } + + case PELIB_IMAGE_REL_BASED_ABSOLUTE: // Absolute - no fixup required. + break; + + default: + return false; + } + } + + // Move to the next relocation block + bufferPtr = bufferPtr + pRelocBlock->SizeOfBlock; + } + + // Free the relocation buffer + delete [] buffer; + } + + return true; +} + +void PeLib::ImageLoader::writeNewImageBase(std::uint64_t newImageBase) +{ + uint32_t offset = dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER); + + // 64-bit images + if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + PELIB_IMAGE_OPTIONAL_HEADER64 header64{}; + + readImage(&header64, offset, fileHeader.SizeOfOptionalHeader); + header64.ImageBase = newImageBase; + writeImage(&header64, offset, fileHeader.SizeOfOptionalHeader); + } + + // 32-bit images + if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PELIB_IMAGE_OPTIONAL_HEADER32 header32{}; + + readImage(&header32, offset, fileHeader.SizeOfOptionalHeader); + header32.ImageBase = (uint32_t)newImageBase; + writeImage(&header32, offset, fileHeader.SizeOfOptionalHeader); + } +} + +int PeLib::ImageLoader::captureDosHeader(std::vector & fileData) +{ + uint8_t * fileBegin = fileData.data(); + uint8_t * fileEnd = fileBegin + fileData.size(); + + // Capture the DOS header + if((fileBegin + sizeof(PELIB_IMAGE_DOS_HEADER)) >= fileEnd) + return ERROR_INVALID_FILE; + memcpy(&dosHeader, fileBegin, sizeof(PELIB_IMAGE_DOS_HEADER)); + + // Verify DOS header + if(dosHeader.e_magic != PELIB_IMAGE_DOS_SIGNATURE) + return ERROR_INVALID_FILE; + if(dosHeader.e_lfanew & 3) + return setLoaderError(LDR_ERROR_E_LFANEW_UNALIGNED); + if(dosHeader.e_lfanew > fileData.size()) + return setLoaderError(LDR_ERROR_E_LFANEW_OUT_OF_FILE); + + return ERROR_NONE; +} + +int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) +{ + uint8_t * fileBegin = fileData.data(); + uint8_t * filePtr = fileBegin + dosHeader.e_lfanew; + uint8_t * fileEnd = fileBegin + fileData.size(); + uint32_t ntSignature; + size_t ntHeaderSize; + + // Windows 7 or newer require that the file size is greater or equal to sizeof(IMAGE_NT_HEADERS) + // Note that 64-bit kernel requires this to be sizeof(IMAGE_NT_HEADERS64) + if(ntHeadersSizeCheck) + { + uint32_t minFileSize = dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + sizeof(PELIB_IMAGE_OPTIONAL_HEADER32); + + if((filePtr + minFileSize) > fileEnd) + return setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); + } + + // Capture the NT signature + if((filePtr + sizeof(uint32_t)) >= fileEnd) + setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); + ntSignature = *(reinterpret_cast(filePtr)); + + // Check the NT signature + if(ntSignature != PELIB_IMAGE_NT_SIGNATURE) + setLoaderError(LDR_ERROR_NO_NT_SIGNATURE); + filePtr += sizeof(uint32_t); + + // Capture the file header + if((filePtr + sizeof(PELIB_IMAGE_FILE_HEADER)) >= fileEnd) + setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); + memcpy(&fileHeader, filePtr, sizeof(PELIB_IMAGE_FILE_HEADER)); + + // 7baebc6d9f2185fafa760c875ab1386f385a0b3fecf2e6ae339abb4d9ac58f3e + if (fileHeader.Machine == 0 && fileHeader.SizeOfOptionalHeader == 0) + setLoaderError(LDR_ERROR_FILE_HEADER_INVALID); + if (!(fileHeader.Characteristics & PELIB_IMAGE_FILE_EXECUTABLE_IMAGE)) + setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE); + filePtr += sizeof(PELIB_IMAGE_FILE_HEADER); + + // Windows XP: Number of section must be 96 + // Windows 7: Number of section must be 192 + if(fileHeader.NumberOfSections > maxSectionCount) + setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE); + + // Check the position of the NT header for integer overflow and for file size overflow + ntHeaderSize = sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; + if((dosHeader.e_lfanew + ntHeaderSize) < dosHeader.e_lfanew) + setLoaderError(LDR_ERROR_NTHEADER_OFFSET_OVERFLOW); + + // Capture optional header + if(fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_I386) + captureOptionalHeader32(filePtr, fileEnd); + else + captureOptionalHeader64(filePtr, fileEnd); + + // Performed by Windows 10 (nt!MiVerifyImageHeader): + // Sample: 04d3577d1b6309a0032d4c4c1252c55416a09bb617aebafe512fffbdd4f08f18 + if(appContainerCheck && checkForBadAppContainer()) + setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE); + + // SizeOfHeaders must be nonzero if not a single subsection + if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE && optionalHeader.SizeOfHeaders == 0) + setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_ZERO); + + // File alignment must not be 0 + if(optionalHeader.FileAlignment == 0) + setLoaderError(LDR_ERROR_FILE_ALIGNMENT_ZERO); + + // File alignment must be a power of 2 + if(optionalHeader.FileAlignment & (optionalHeader.FileAlignment-1)) + setLoaderError(LDR_ERROR_FILE_ALIGNMENT_NOT_POW2); + + // Section alignment must not be 0 + if (optionalHeader.SectionAlignment == 0) + setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_ZERO); + + // Section alignment must be a power of 2 + if (optionalHeader.SectionAlignment & (optionalHeader.SectionAlignment - 1)) + setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_NOT_POW2); + + if (optionalHeader.SectionAlignment < optionalHeader.FileAlignment) + setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_TOO_SMALL); + + // Check for images with "super-section": FileAlignment must be equal to SectionAlignment + if ((optionalHeader.FileAlignment & 511) && (optionalHeader.SectionAlignment != optionalHeader.FileAlignment)) + setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_INVALID); + + // Check for largest image + if(optionalHeader.SizeOfImage > PELIB_MM_SIZE_OF_LARGEST_IMAGE) + setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_TOO_BIG); + + // Check for 32-bit images + if (optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC && fileHeader.Machine != PELIB_IMAGE_FILE_MACHINE_I386) + setLoaderError(LDR_ERROR_INVALID_MACHINE32); + + // Check for 64-bit images + if (optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + if (fileHeader.Machine != PELIB_IMAGE_FILE_MACHINE_AMD64 && fileHeader.Machine != PELIB_IMAGE_FILE_MACHINE_IA64) + setLoaderError(LDR_ERROR_INVALID_MACHINE64); + } + + // Check the size of image + if(optionalHeader.SizeOfHeaders > optionalHeader.SizeOfImage) + setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); + + // On 64-bit Windows, size of optional header must be properly aligned to 8-byte boundary + if (fileHeader.SizeOfOptionalHeader & (sizeof(uint64_t) - 1)) + setLoaderError(LDR_ERROR_SIZE_OF_OPTHDR_NOT_ALIGNED); + + // Set the size of image + if(BytesToPages(optionalHeader.SizeOfImage) == 0) + setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_ZERO); + + // Check for proper alignment of the image base + if(optionalHeader.ImageBase & (PELIB_SIZE_64KB - 1)) + setLoaderError(LDR_ERROR_IMAGE_BASE_NOT_ALIGNED); + + return ERROR_NONE; +} + +int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) +{ + uint8_t * fileBegin = fileData.data(); + uint8_t * filePtr; + uint8_t * fileEnd = fileBegin + fileData.size(); + bool bRawDataBeyondEOF = false; + + // Check whether the sections are within the file + filePtr = fileBegin + dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; + if(filePtr > fileEnd) + return setLoaderError(LDR_ERROR_SECTION_HEADERS_OUT_OF_IMAGE); + + // Set the counters + uint32_t NumberOfSectionPTEs = AlignToSize(optionalHeader.SizeOfHeaders, optionalHeader.SectionAlignment) / PELIB_PAGE_SIZE; + uint64_t NextVirtualAddress = 0; + uint32_t NumberOfPTEs = BytesToPages(optionalHeader.SizeOfImage); + uint32_t FileAlignmentMask = optionalHeader.FileAlignment - 1; + bool SingleSubsection = (optionalHeader.SectionAlignment < PELIB_PAGE_SIZE); + + // Verify the image + if (!SingleSubsection) + { + // Some extra checks done by the loader + if ((optionalHeader.SizeOfHeaders + (optionalHeader.SectionAlignment - 1)) < optionalHeader.SizeOfHeaders) + setLoaderError(LDR_ERROR_SECTION_HEADERS_OVERFLOW); + + if (NumberOfSectionPTEs > NumberOfPTEs) + setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); + + // Update the virtual address + NextVirtualAddress += NumberOfSectionPTEs * PELIB_PAGE_SIZE; + NumberOfPTEs -= NumberOfSectionPTEs; + } + else + { + NumberOfSectionPTEs = AlignToSize(optionalHeader.SizeOfImage, PELIB_PAGE_SIZE) / PELIB_PAGE_SIZE; + NumberOfPTEs -= NumberOfSectionPTEs; + } + + // Read and verify all section headers + for(uint16_t i = 0; i < fileHeader.NumberOfSections; i++) + { + PELIB_IMAGE_SECTION_HEADER sectHdr{}; + + // Capture one section header + if((filePtr + sizeof(PELIB_IMAGE_SECTION_HEADER)) > fileEnd) + break; + memcpy(§Hdr, filePtr, sizeof(PELIB_IMAGE_SECTION_HEADER)); + + uint32_t PointerToRawData = (sectHdr.SizeOfRawData != 0) ? sectHdr.PointerToRawData : 0; + uint32_t EndOfRawData = PointerToRawData + sectHdr.SizeOfRawData; + uint32_t VirtualSize = (sectHdr.VirtualSize != 0) ? sectHdr.VirtualSize : sectHdr.SizeOfRawData; + + // Overflow check + if ((PointerToRawData + sectHdr.SizeOfRawData) < PointerToRawData) + setLoaderError(LDR_ERROR_RAW_DATA_OVERFLOW); + + // Verify the image + if (SingleSubsection) + { + // If the image is mapped as single subsection, + // then the virtual values must match raw values + if ((sectHdr.VirtualAddress != PointerToRawData) || sectHdr.SizeOfRawData < VirtualSize) + setLoaderError(LDR_ERROR_SECTION_SIZE_MISMATCH); + } + else + { + // Check the virtual address of the section + if (NextVirtualAddress != sectHdr.VirtualAddress) + setLoaderError(LDR_ERROR_INVALID_SECTION_VA); + + // Check the end of the section + if((NextVirtualAddress + VirtualSize) <= NextVirtualAddress) + setLoaderError(LDR_ERROR_INVALID_SECTION_VSIZE); + + // Check section size + if ((VirtualSize + (PELIB_PAGE_SIZE - 1)) <= VirtualSize) + setLoaderError(LDR_ERROR_INVALID_SECTION_VSIZE); + + // Calculate number of PTEs in the section + NumberOfSectionPTEs = AlignToSize(VirtualSize, optionalHeader.SectionAlignment) / PELIB_PAGE_SIZE; + if (NumberOfSectionPTEs > NumberOfPTEs) + setLoaderError(LDR_ERROR_INVALID_SECTION_VSIZE); + + NumberOfPTEs -= NumberOfSectionPTEs; + + // Check end of the raw data for the section + if (((PointerToRawData + sectHdr.SizeOfRawData + FileAlignmentMask) & ~FileAlignmentMask) < PointerToRawData) + setLoaderError(LDR_ERROR_INVALID_SECTION_RAWSIZE); + + // On last section, size of raw data must not go after the end of the file + // Sample: a5957dad4b3a53a5894708c7c1ba91be0668ecbed49e33affee3a18c0737c3a5 + if(i == fileHeader.NumberOfSections - 1 && sectHdr.SizeOfRawData != 0) + { + if((sectHdr.PointerToRawData + sectHdr.SizeOfRawData) > fileData.size()) + setLoaderError(LDR_ERROR_INVALID_SECTION_RAWSIZE); + } + + NextVirtualAddress += NumberOfSectionPTEs * PELIB_PAGE_SIZE; + } + + // Check for raw data beyond end-of-file + // Note that Windows loader doesn't check this on files that are mapped as single section. + // We will do that nontheless, because we want to know that a file is cut. + if (PointerToRawData != 0 && (fileBegin + EndOfRawData) > fileEnd) + bRawDataBeyondEOF = true; + + // Insert the header to the list + sections.push_back(sectHdr); + filePtr += sizeof(PELIB_IMAGE_SECTION_HEADER); + } + + // Verify the image size. Note that this check is no longer performed by Windows 10 + if(sizeofImageMustMatch) + { + uint32_t ThresholdNumberOfPTEs = (SingleSubsection == false) ? (optionalHeader.SectionAlignment / PELIB_PAGE_SIZE) : 1; + if (NumberOfPTEs >= ThresholdNumberOfPTEs) + { + setLoaderError(LDR_ERROR_INVALID_SIZE_OF_IMAGE); + } + } + + // Did we detect a trimmed file? + if (bRawDataBeyondEOF) + { + bool bFileLoadable = false; + + // Special exception: Even if cut, the file is still loadable + // if the last section is in the file range. This is because + // the PE loader in Windows only cares about whether the last section is in the file range + if(SingleSubsection == false) + { + if (!sections.empty()) + { + PELIB_IMAGE_SECTION_HEADER & lastSection = sections.back(); + uint32_t PointerToRawData = (lastSection.SizeOfRawData != 0) ? lastSection.PointerToRawData : 0; + uint32_t EndOfRawData = PointerToRawData + lastSection.SizeOfRawData; + + if ((lastSection.SizeOfRawData == 0) || (fileBegin + EndOfRawData) <= fileEnd) + { + setLoaderError(LDR_ERROR_FILE_IS_CUT_LOADABLE); + bFileLoadable = true; + } + } + } + else + { + setLoaderError(LDR_ERROR_FILE_IS_CUT_LOADABLE); + bFileLoadable = true; + } + + // If the file is not loadable, set the "file is cut" error + if (bFileLoadable == false) + { + setLoaderError(LDR_ERROR_FILE_IS_CUT); + } + } + + return ERROR_NONE; +} + +int PeLib::ImageLoader::captureImageSections(std::vector & fileData) +{ + uint32_t virtualAddress = 0; + uint32_t sizeOfImage; + + // Reserve the image size, aligned up to the page size + sizeOfImage = AlignToSize(optionalHeader.SizeOfImage, PELIB_PAGE_SIZE); + pages.resize(sizeOfImage / PELIB_PAGE_SIZE); + + // Section-based mapping / file-based mapping + if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE) + { + // Capture the file header + virtualAddress = captureImageSection(fileData, virtualAddress, optionalHeader.SizeOfHeaders, 0, optionalHeader.SizeOfHeaders, PELIB_IMAGE_SCN_MEM_READ, true); + if(virtualAddress == 0) + return ERROR_INVALID_FILE; + + // Capture each section + if(sections.size() != 0) + { + for(auto & sectionHeader : sections) + { + // Capture all pages from the section + if(captureImageSection(fileData, sectionHeader.VirtualAddress, + sectionHeader.VirtualSize, + sectionHeader.PointerToRawData, + sectionHeader.SizeOfRawData, + sectionHeader.Characteristics) == 0) + { + setLoaderError(LDR_ERROR_INVALID_SECTION_VA); + break; + } + } + } + else + { + // If the file has no sections, we need to check the SizeOfImage against + // the virtual address. They must match, otherwise Windows will not load the file. + // Sample: cdf2a3ff23ec8a0814e285d94c4f081202ea6fe69661ff9940dcafc28e5fc626 + if(virtualAddress > optionalHeader.SizeOfImage || (optionalHeader.SizeOfImage - virtualAddress) > optionalHeader.SectionAlignment) + { + setLoaderError(LDR_ERROR_INVALID_SIZE_OF_IMAGE); + } + } + } + else + { + // Capture the file as-is + virtualAddress = captureImageSection(fileData, 0, sizeOfImage, 0, sizeOfImage, PELIB_IMAGE_SCN_MEM_WRITE | PELIB_IMAGE_SCN_MEM_READ | PELIB_IMAGE_SCN_MEM_EXECUTE, true); + if(virtualAddress == 0) + return ERROR_INVALID_FILE; + } + + // If a section has SizeOfRawData equal to 0, + // Windows loader patches PointerToRawData to zero, including the mapped image. + // Tested on Windows XP and Windows 10. + uint32_t rva = dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; + for(size_t i = 0; i < sections.size(); i++, rva += sizeof(PELIB_IMAGE_SECTION_HEADER)) + { + PELIB_IMAGE_SECTION_HEADER sectHdr{}; + + // Read the section from the header. This is necessary, as for some files, + // section headers are not contained in the image. + // Example: c8b31a912d91407a834071268366eb404d5e771b8281fdde301e15a8a82bf01b + readImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER)); + + // Patch PointerToRawData to zero, if SizeOfRawData is zero. + if(sectHdr.PointerToRawData != 0 && sectHdr.SizeOfRawData == 0) + { + sectHdr.PointerToRawData = 0; + writeImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER)); + } + } + + return ERROR_NONE; +} + +int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * filePtr, uint8_t * fileEnd) +{ + PELIB_IMAGE_OPTIONAL_HEADER32 optionalHeader32{}; + uint32_t sizeOfOptionalHeader = fileHeader.SizeOfOptionalHeader; + uint32_t numberOfRvaAndSizes; + + // Capture optional header + if((filePtr + sizeOfOptionalHeader) > fileEnd) + return setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); + if(sizeOfOptionalHeader > sizeof(PELIB_IMAGE_OPTIONAL_HEADER32)) + sizeOfOptionalHeader = sizeof(PELIB_IMAGE_OPTIONAL_HEADER32); + memcpy(&optionalHeader32, filePtr, sizeOfOptionalHeader); + + // Verify whether it's 32-bit optional header + if(optionalHeader32.Magic != PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) + return setLoaderError(LDR_ERROR_NO_OPTHDR_MAGIC); + + // Convert 32-bit optional header to common optional header + optionalHeader.Magic = optionalHeader32.Magic; + optionalHeader.MajorLinkerVersion = optionalHeader32.MajorLinkerVersion; + optionalHeader.MinorLinkerVersion = optionalHeader32.MinorLinkerVersion; + optionalHeader.SizeOfCode = optionalHeader32.SizeOfCode; + optionalHeader.SizeOfInitializedData = optionalHeader32.SizeOfInitializedData; + optionalHeader.SizeOfUninitializedData = optionalHeader32.SizeOfUninitializedData; + optionalHeader.AddressOfEntryPoint = optionalHeader32.AddressOfEntryPoint; + optionalHeader.BaseOfCode = optionalHeader32.BaseOfCode; + optionalHeader.BaseOfData = optionalHeader32.BaseOfData; + optionalHeader.ImageBase = optionalHeader32.ImageBase; + optionalHeader.SectionAlignment = optionalHeader32.SectionAlignment; + optionalHeader.FileAlignment = optionalHeader32.FileAlignment; + optionalHeader.MajorOperatingSystemVersion = optionalHeader32.MajorOperatingSystemVersion; + optionalHeader.MinorOperatingSystemVersion = optionalHeader32.MinorOperatingSystemVersion; + optionalHeader.MajorImageVersion = optionalHeader32.MajorImageVersion; + optionalHeader.MinorImageVersion = optionalHeader32.MinorImageVersion; + optionalHeader.MajorSubsystemVersion = optionalHeader32.MajorSubsystemVersion; + optionalHeader.MinorSubsystemVersion = optionalHeader32.MinorSubsystemVersion; + optionalHeader.Win32VersionValue = optionalHeader32.Win32VersionValue; + optionalHeader.SizeOfImage = optionalHeader32.SizeOfImage; + optionalHeader.SizeOfHeaders = optionalHeader32.SizeOfHeaders; + optionalHeader.CheckSum = optionalHeader32.CheckSum; + optionalHeader.Subsystem = optionalHeader32.Subsystem; + optionalHeader.DllCharacteristics = optionalHeader32.DllCharacteristics; + optionalHeader.SizeOfStackReserve = optionalHeader32.SizeOfStackReserve; + optionalHeader.SizeOfStackCommit = optionalHeader32.SizeOfStackCommit; + optionalHeader.SizeOfHeapReserve = optionalHeader32.SizeOfHeapReserve; + optionalHeader.SizeOfHeapCommit = optionalHeader32.SizeOfHeapCommit; + optionalHeader.LoaderFlags = optionalHeader32.LoaderFlags; + optionalHeader.NumberOfRvaAndSizes = optionalHeader32.NumberOfRvaAndSizes; + + // Copy data directories + if((numberOfRvaAndSizes = optionalHeader32.NumberOfRvaAndSizes) > PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES) + numberOfRvaAndSizes = PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES; + memcpy(optionalHeader.DataDirectory, optionalHeader32.DataDirectory, sizeof(PELIB_IMAGE_DATA_DIRECTORY) * numberOfRvaAndSizes); + + return ERROR_NONE; +} + +int PeLib::ImageLoader::loadImageAsIs(std::vector & fileData) +{ + imageAsIs = fileData; + return ERROR_NONE; +} + +int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * filePtr, uint8_t * fileEnd) +{ + PELIB_IMAGE_OPTIONAL_HEADER64 optionalHeader64{}; + uint32_t sizeOfOptionalHeader = fileHeader.SizeOfOptionalHeader; + uint32_t numberOfRvaAndSizes; + + // Capture optional header + if((filePtr + sizeOfOptionalHeader) > fileEnd) + return setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); + if(sizeOfOptionalHeader > sizeof(PELIB_IMAGE_OPTIONAL_HEADER64)) + sizeOfOptionalHeader = sizeof(PELIB_IMAGE_OPTIONAL_HEADER64); + memcpy(&optionalHeader64, filePtr, sizeOfOptionalHeader); + + // Verify whether it's 64-bit optional header + if(optionalHeader64.Magic != PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) + return setLoaderError(LDR_ERROR_NO_OPTHDR_MAGIC); + + // Convert 32-bit optional header to common optional header + optionalHeader.Magic = optionalHeader64.Magic; + optionalHeader.MajorLinkerVersion = optionalHeader64.MajorLinkerVersion; + optionalHeader.MinorLinkerVersion = optionalHeader64.MinorLinkerVersion; + optionalHeader.SizeOfCode = optionalHeader64.SizeOfCode; + optionalHeader.SizeOfInitializedData = optionalHeader64.SizeOfInitializedData; + optionalHeader.SizeOfUninitializedData = optionalHeader64.SizeOfUninitializedData; + optionalHeader.AddressOfEntryPoint = optionalHeader64.AddressOfEntryPoint; + optionalHeader.BaseOfCode = optionalHeader64.BaseOfCode; + optionalHeader.ImageBase = optionalHeader64.ImageBase; + optionalHeader.SectionAlignment = optionalHeader64.SectionAlignment; + optionalHeader.FileAlignment = optionalHeader64.FileAlignment; + optionalHeader.MajorOperatingSystemVersion = optionalHeader64.MajorOperatingSystemVersion; + optionalHeader.MinorOperatingSystemVersion = optionalHeader64.MinorOperatingSystemVersion; + optionalHeader.MajorImageVersion = optionalHeader64.MajorImageVersion; + optionalHeader.MinorImageVersion = optionalHeader64.MinorImageVersion; + optionalHeader.MajorSubsystemVersion = optionalHeader64.MajorSubsystemVersion; + optionalHeader.MinorSubsystemVersion = optionalHeader64.MinorSubsystemVersion; + optionalHeader.Win32VersionValue = optionalHeader64.Win32VersionValue; + optionalHeader.SizeOfImage = optionalHeader64.SizeOfImage; + optionalHeader.SizeOfHeaders = optionalHeader64.SizeOfHeaders; + optionalHeader.CheckSum = optionalHeader64.CheckSum; + optionalHeader.Subsystem = optionalHeader64.Subsystem; + optionalHeader.DllCharacteristics = optionalHeader64.DllCharacteristics; + optionalHeader.SizeOfStackReserve = optionalHeader64.SizeOfStackReserve; + optionalHeader.SizeOfStackCommit = optionalHeader64.SizeOfStackCommit; + optionalHeader.SizeOfHeapReserve = optionalHeader64.SizeOfHeapReserve; + optionalHeader.SizeOfHeapCommit = optionalHeader64.SizeOfHeapCommit; + optionalHeader.LoaderFlags = optionalHeader64.LoaderFlags; + optionalHeader.NumberOfRvaAndSizes = optionalHeader64.NumberOfRvaAndSizes; + + // Copy data directories + if((numberOfRvaAndSizes = optionalHeader64.NumberOfRvaAndSizes) > PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES) + numberOfRvaAndSizes = PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES; + memcpy(optionalHeader.DataDirectory, optionalHeader64.DataDirectory, sizeof(PELIB_IMAGE_DATA_DIRECTORY) * numberOfRvaAndSizes); + + return ERROR_NONE; +} + +size_t PeLib::ImageLoader::getMismatchOffset(void * buffer1, void * buffer2, uint32_t rva, size_t length) +{ + uint8_t * byteBuffer1 = reinterpret_cast(buffer1); + uint8_t * byteBuffer2 = reinterpret_cast(buffer2); + + for(size_t i = 0; i < length; i++) + { + if(byteBuffer1[i] != byteBuffer2[i]) + { + // Windows loader puts 0 in IMAGE_SECTION_HEADER::PointerToRawData + // if IMAGE_SECTION_HEADER::SizeOfRawData is also zero. + // However, on random samples, there seems to be the original value. + // This seems to happen randomly on some samples, often dissappears + // when the sample is copied to another location. + if(isRvaOfSectionHeaderPointerToRawData(rva + i)) + continue; + + //for(int j = i & 0xFFFFFFF0; j < 0xD00; j++) + // printf("byteBuffer1[j]: %02x, byteBuffer2[j]: %02x\n", byteBuffer1[j], byteBuffer2[j]); + return i; + } + } + + return (size_t)(-1); +} + +uint32_t PeLib::ImageLoader::captureImageSection( + std::vector & fileData, + uint32_t virtualAddress, + uint32_t virtualSize, + uint32_t pointerToRawData, + uint32_t sizeOfRawData, + uint32_t characteristics, + bool isImageHeader) +{ + uint8_t * fileBegin = fileData.data(); + uint8_t * rawDataPtr; + uint8_t * rawDataEnd; + uint8_t * fileEnd = fileBegin + fileData.size(); + uint32_t sizeOfInitializedPages; // The part of section with initialized pages + uint32_t sizeOfValidPages; // The part of section with valid pages + uint32_t sizeOfSection; // Total virtual size of the section + uint32_t pageOffset = 0; + size_t pageIndex; + + // If the virtual size of a section is zero, take the size of raw data + virtualSize = (virtualSize == 0) ? sizeOfRawData : virtualSize; + + // Virtual size is aligned to PAGE_SIZE (not SectionAlignment!) + // If SectionAlignment > PAGE_SIZE, header and sections are padded with invalid pages (PAGE_NOACCESS) + // Sample: f73e66052c8b0a49d56ccadcecdf497c015b5ec6f6724e056f35b57b59afaf59 + virtualSize = AlignToSize(virtualSize, PELIB_PAGE_SIZE); + + // If SizeOfRawData is greater than VirtualSize, cut it to virtual size + // Note that up to the aligned virtual size, the data are in the section + if(sizeOfRawData > virtualSize) + sizeOfRawData = virtualSize; + + // If SectionAlignment is greater than page size, then there are going to be + // gaps of inaccessible memory after the end of raw data + // Example: b811f2c047a3e828517c234bd4aa4883e1ec591d88fad21289ae68a6915a6665 + // * has 0x1000 bytes of inaccessible memory at ImageBase+0x1000 (1 page after section header) + sizeOfInitializedPages = AlignToSize(sizeOfRawData, PELIB_PAGE_SIZE); + sizeOfValidPages = AlignToSize(virtualSize, PELIB_PAGE_SIZE); + sizeOfSection = AlignToSize(virtualSize, optionalHeader.SectionAlignment); + + // Get the range of the file containing valid data (aka nonzeros) + // Pointer to raw data is aligned down to the sector size + // due to the Windows Loader logic that sets sector offset in the page table entries + rawDataPtr = fileBegin + (pointerToRawData & ~(PELIB_SECTOR_SIZE - 1)); + rawDataEnd = rawDataPtr + sizeOfRawData; + + // End of raw data is aligned to the file alignment. This does not apply to image header + // Sample: ab0a9c4a8beee49a13cbf6c684b58f9604d673c9d5522a73ec5dffda909695a1 + // SizeOfHeaders = 0x400, FileAlignment = 0x1000. Only 0x400 bytes is copied to the image + if(isImageHeader == false) + rawDataEnd = fileBegin + AlignToSize(pointerToRawData + sizeOfRawData, optionalHeader.FileAlignment); + + // Virtual address must begin exactly at the end of previous VA + pageIndex = virtualAddress / PELIB_PAGE_SIZE; + + // Some combination of flags in IMAGE_SECTION_HEADER::Characteristics give PAGE_NOACCESS + // If the image is mapped with SEC_IMAGE_NO_EXECUTE (Windows 10), + // some of the NOACCESS sections turn into READONLY sections. + if(getImageProtection(characteristics) != PELIB_PAGE_NOACCESS) + { + // If the pointerToRawData is less than SECTOR_SIZE, it will contain file header in it. + // However, if the pointerToRawData contains 0, then the + if(pointerToRawData || isImageHeader) + { + // Fill all pages that contain data + while(pageOffset < sizeOfInitializedPages) + { + PELIB_FILE_PAGE & filePage = pages[pageIndex++]; + + // Only if we didn't get out of the file + if(rawDataPtr < fileEnd) + { + size_t bytesToCopy = PELIB_PAGE_SIZE; + + // Check range validity + if((rawDataPtr + bytesToCopy) > fileEnd) + bytesToCopy = (fileEnd - rawDataPtr); + if((rawDataPtr + bytesToCopy) > rawDataEnd) + bytesToCopy = (rawDataEnd - rawDataPtr); + + // Initialize the page with valid data + filePage.setValidPage(rawDataPtr, bytesToCopy); + } + else + { + filePage.setZeroPage(); + } + + // Move pointers + rawDataPtr += PELIB_PAGE_SIZE; + pageOffset += PELIB_PAGE_SIZE; + } + } + + // Fill all pages that contain zeroed pages + while(pageOffset < sizeOfValidPages) + { + PELIB_FILE_PAGE & filePage = pages[pageIndex++]; + + filePage.setZeroPage(); + pageOffset += PELIB_PAGE_SIZE; + } + } + + // Leave all other pages filled with zeros + return virtualAddress + sizeOfSection; +} + +bool PeLib::ImageLoader::isGoodPagePointer(PFN_VERIFY_ADDRESS PfnVerifyAddress, void * pagePtr) +{ + // If the caller didn't supply a verification procedure, use default one + // The verification procedure can possibly be system-specific, like IsBadReadPtr on Windows + if(PfnVerifyAddress == nullptr) + { + // In order to work in Windows, it must be built with /EHa + // (Enable C++ Exceptions: Yes with SEH Exceptions (/EHa)) + try + { + uint8_t dummyBuffer[0x10] = {0}; + memcmp(pagePtr, dummyBuffer, sizeof(dummyBuffer)); + return true; + } + catch(...) + { + return false; + } + } + else + { + return PfnVerifyAddress(pagePtr, PELIB_PAGE_SIZE); + } +} + +bool PeLib::ImageLoader::isGoodMappedPage(uint32_t rva) +{ + uint32_t pageIndex = (rva / PELIB_PAGE_SIZE); + + if(pageIndex > pages.size()) + return false; + return (pages[pageIndex].isInvalidPage == false); +} + +bool PeLib::ImageLoader::isZeroPage(std::uint32_t rva) +{ + uint32_t pageIndex = (rva / PELIB_PAGE_SIZE); + + if(pageIndex > pages.size()) + return false; + return (pages[pageIndex].isZeroPage); +} + +bool PeLib::ImageLoader::isRvaOfSectionHeaderPointerToRawData(uint32_t rva) +{ + uint32_t rvaOfLastSectionPointerToRawData; + + // If there is at least one section + for(size_t i = 0; i < sections.size(); i++) + { + // Get the reference to the section header + PELIB_IMAGE_SECTION_HEADER & sectHdr = sections[i]; + + // Must be a section with SizeOfRawData = 0 + if(sectHdr.SizeOfRawData == 0) + { + // Calculate the RVA of the PointerToRawData variable in the last section + rvaOfLastSectionPointerToRawData = dosHeader.e_lfanew + + sizeof(uint32_t) + + sizeof(PELIB_IMAGE_FILE_HEADER) + + fileHeader.SizeOfOptionalHeader + + i * sizeof(PELIB_IMAGE_SECTION_HEADER) + + 0x14; // FIELD_OFFSET(PELIB_IMAGE_SECTION_HEADER, PointerToRawData) + + if(rvaOfLastSectionPointerToRawData <= rva && rva < rvaOfLastSectionPointerToRawData + sizeof(uint32_t)) + return true; + } + } + + return false; +} + +// MiIsLegacyImageArchitecture from Windows 10 +bool PeLib::ImageLoader::isLegacyImageArchitecture(std::uint16_t Machine) +{ + if(Machine == PELIB_IMAGE_FILE_MACHINE_I386) + return true; + if(Machine == PELIB_IMAGE_FILE_MACHINE_AMD64) + return true; + return false; +} + +// Windows 10: For IMAGE_FILE_MACHINE_I386 and IMAGE_FILE_MACHINE_AMD64, +// if (Characteristics & IMAGE_FILE_RELOCS_STRIPPED) and (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER), +// MiVerifyImageHeader returns STATUS_INVALID_IMAGE_FORMAT. +bool PeLib::ImageLoader::checkForBadAppContainer() +{ + if(isLegacyImageArchitecture(fileHeader.Machine)) + { + if(optionalHeader.DllCharacteristics & PELIB_IMAGE_DLLCHARACTERISTICS_APPCONTAINER) + { + if(fileHeader.Characteristics & PELIB_IMAGE_FILE_RELOCS_STRIPPED) + { + return true; + } + } + } + + return false; +} + +bool PeLib::ImageLoader::isImageMappedOk() +{ + // If there was loader error, we didn't map the image + if(ldrError != LDR_ERROR_NONE && ldrError != LDR_ERROR_FILE_IS_CUT_LOADABLE) + return false; + if(pages.size() == 0) + return false; + return true; +} + +//----------------------------------------------------------------------------- +// Testing function + +void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & ImageCompare, void * imageDataPtr, std::uint32_t imageSize) +{ + uint8_t * winImageData = reinterpret_cast(imageDataPtr); + uint8_t * winImageEnd = winImageData + imageSize; + uint8_t singlePage[PELIB_PAGE_SIZE]; + size_t mismatchOffset; + size_t rva = 0; + + // Are both loaded? + if(winImageData != nullptr && isImageMappedOk()) + { + // Check whether the image size is the same + if(imageSize != getSizeOfImageAligned()) + { + ImageCompare.compareResult = ImagesDifferentSize; + ImageCompare.differenceOffset = 0; + return; + } + + // Compare images page-by-page + while(winImageData < winImageEnd) + { + // If the windows page is inaccessible, our page must be inaccessible as well + bool isGoodPageWin = isGoodPagePointer(ImageCompare.PfnVerifyAddress, winImageData); + bool isGoodPageMy = isGoodMappedPage(rva); + + // Both are accessible -> Compare the page + if(isGoodPageWin && isGoodPageMy) + { + // Read the image page + readImage(singlePage, rva, sizeof(singlePage)); + + // Check for difference + // Note that if this is done in a debugger (e.g. Visual Studio) and PDB is available, + // it might place breakpoint to the position of __crt_debugger_hook, which will cause + // this memcmp return difference. + if(memcmp(winImageData, singlePage, PELIB_PAGE_SIZE)) + { + mismatchOffset = getMismatchOffset(winImageData, singlePage, rva, PELIB_PAGE_SIZE); + if(mismatchOffset != (size_t)(-1)) + { + ImageCompare.compareResult = ImagesDifferentPageValue; + ImageCompare.differenceOffset = rva + mismatchOffset; + return; + } + } + } + else + { + // Accessible vs inacessible? + if(isGoodPageWin != isGoodPageMy) + { + ImageCompare.compareResult = ImagesDifferentPageAccess; + ImageCompare.differenceOffset = rva; + return; + } + } + + // Move pointers + winImageData += PELIB_PAGE_SIZE; + rva += PELIB_PAGE_SIZE; + } + } + + // Check whether both we and Windows mapped the image OK + if(isImageMappedOk()) + { + // Windows didn't map the image + if(winImageData == nullptr) + { + ImageCompare.compareResult = ImagesWindowsDidntLoadWeDid; + return; + } + } + else + { + // Windows mapped the image + if(winImageData != nullptr) + { + ImageCompare.compareResult = ImagesWindowsLoadedWeDidnt; + return; + } + } + + // Both Windows and our image are the same + ImageCompare.compareResult = ImagesEqual; + ImageCompare.differenceOffset = 0; +} diff --git a/src/pelib/PelibTest.cpp b/src/pelib/PelibTest.cpp new file mode 100644 index 000000000..55312013c --- /dev/null +++ b/src/pelib/PelibTest.cpp @@ -0,0 +1,466 @@ +/*****************************************************************************/ +/* PelibTest.cpp Copyright (c) Ladislav Zezula 2020 */ +/*---------------------------------------------------------------------------*/ +/* Testing suite for pelib. Windows platform only. */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.05.20 1.00 Lad Created */ +/*****************************************************************************/ + +#ifndef UNICODE +#define UNICODE +#define _UNICODE +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4091) // imagehlp.h(1873) : warning C4091 : 'typedef ' : ignored on left of '' when no variable is declared +#endif // _MSC_VER + +#define WIN32_NO_STATUS +#include +#include +#include +#include +#include +#include +#undef WIN32_NO_STATUS +#include +#include +#include + +#include +#include + +#include "ImageLoader.h" +#include "Utils.h" +#include "ntdll.h" + +//----------------------------------------------------------------------------- +// Local variables + +OSVERSIONINFO g_osvi = {0}; +DWORD g_dwFilesTested = 0; +DWORD g_dwFilesMatched = 0; +DWORD g_dwFilesMismatch = 0; +DWORD g_dwWinVer = 0; + +#define WIN32_PAGE_SIZE 0x1000 + +#ifndef SEC_IMAGE_NO_EXECUTE +#define SEC_IMAGE_NO_EXECUTE 0x11000000 +#endif + +//----------------------------------------------------------------------------- +// Local functions + +static LPCTSTR GetStringArg(int argIndex, LPCTSTR szDefault = NULL) +{ + if(__argc > argIndex) + { + if(__targv[argIndex] && __targv[argIndex][0]) + { + return __targv[argIndex]; + } + } + + return szDefault; +} + +static int PrintError(LPCTSTR szFormat, ...) +{ + va_list argList; + + va_start(argList, szFormat); + _vtprintf(szFormat, argList); + va_end(argList); + + return 3; +} + +static void PrintCompareResult(LPCTSTR szFileName, LPCTSTR format, ...) +{ + va_list argList; + + va_start(argList, format); + _tprintf(_T("%s\n * "), szFileName); + _vtprintf(format, argList); + _tprintf(_T("\n")); + va_end(argList); +} + +static ULONG64 GetImageBase(LPBYTE pbImage) +{ + PIMAGE_NT_HEADERS64 pNtHdrs64; + PIMAGE_NT_HEADERS32 pNtHdrs32; + PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)pbImage; + + // Make sure that the image base is valid + if(pbImage != NULL) + { + // Try 64-bit image + pNtHdrs64 = (PIMAGE_NT_HEADERS64)(pbImage + pDosHdr->e_lfanew); + if(pNtHdrs64->Signature == IMAGE_NT_SIGNATURE && pNtHdrs64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + return pNtHdrs64->OptionalHeader.ImageBase; + } + + // Try 32-bit image + pNtHdrs32 = (PIMAGE_NT_HEADERS32)(pbImage + pDosHdr->e_lfanew); + if(pNtHdrs32->Signature == IMAGE_NT_SIGNATURE && pNtHdrs32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + return pNtHdrs32->OptionalHeader.ImageBase; + } + } + + return 0; +} + +static bool _cdecl VerifyMemoryAddress(void * ptr, size_t length) +{ + MEMORY_BASIC_INFORMATION mbi; + + // Query the virtual memory + if(!VirtualQuery(ptr, &mbi, length)) + return false; + return (mbi.Protect > PAGE_NOACCESS); +} + +static void WriteDataToFile(LPCTSTR szFileName, LPBYTE pbData, DWORD cbData) +{ + HANDLE hFile; + DWORD dwWritten = 0; + + hFile = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + WriteFile(hFile, pbData, cbData, &dwWritten, NULL); + CloseHandle(hFile); + } +} + +static bool CopySampleToFolder(LPCTSTR szFileName, LPCTSTR szCopyFolder) +{ + TCHAR szTargetName[MAX_PATH]; + TCHAR szPlainName[MAX_PATH]; + LPTSTR szExtension; + int nTryCount = 1; + + if(szCopyFolder && szCopyFolder[0]) + { + // Split the name to plain name and extension + StringCchCopy(szPlainName, _countof(szPlainName), GetPlainName(szFileName)); + szExtension = GetFileExtension(szPlainName); + if(szExtension[0] == _T('.')) + *szExtension++ = 0; + + // The first try + StringCchPrintf(szTargetName, _countof(szTargetName), _T("%s\\%s.%s"), szCopyFolder, szPlainName, szExtension); + + // Keep working + while(nTryCount < 100) + { + // If the target file doesn't exist, copy it + if(GetFileAttributes(szTargetName) == INVALID_FILE_ATTRIBUTES) + { + return CopyFile(szFileName, szTargetName, TRUE); + } + + // Create next name iteration + StringCchPrintf(szTargetName, _countof(szTargetName), _T("%s\\%s_%03u.%s"), szCopyFolder, szPlainName, nTryCount, szExtension); + nTryCount++; + } + } + + return false; +} + +static NTSTATUS MapFileByWindowsLoader(LPCTSTR szFileName, LPBYTE * PtrPointerToImage, LPDWORD PtrSizeOfImage) +{ + OBJECT_ATTRIBUTES ObjAttr; + LARGE_INTEGER MappedSize = {0}; + LARGE_INTEGER ByteOffset = {0}; + NTSTATUS Status = STATUS_SUCCESS; + HANDLE SectionHandle = NULL; + HANDLE FileHandle; + SIZE_T ViewSize = 0; + PVOID BaseAddress = NULL; + ULONG AllocationAttributes = SEC_IMAGE; + + // Use SEC_IMAGE_NO_EXECUTE on Windows 10 or newer +// if(g_dwWinVer >= 0x0601) +// AllocationAttributes = SEC_IMAGE_NO_EXECUTE; + + // Open the file for creating image + FileHandle = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if(FileHandle != INVALID_HANDLE_VALUE) + { + InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL, NULL); + +#ifndef _DEBUG + if(IsDebuggerPresent() == FALSE) + { + //__debugbreak(); + } +#endif + + Status = NtCreateSection(&SectionHandle, + SECTION_MAP_READ, + &ObjAttr, + &MappedSize, + PAGE_READONLY, + AllocationAttributes, + FileHandle); + + if(NT_SUCCESS(Status)) + { + // Map the entire file to memory + Status = NtMapViewOfSection(SectionHandle, + NtCurrentProcess(), + &BaseAddress, + 0, + 0, + &ByteOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READONLY); + NtClose(SectionHandle); + } + + CloseHandle(FileHandle); + } + + // Give the results + PtrPointerToImage[0] = (LPBYTE)BaseAddress; + PtrSizeOfImage[0] = (DWORD)ViewSize; + return Status; +} + +void MapAndCompareImage(LPCTSTR szFileName, LPBYTE pbImageWin, DWORD cbImageWin, PeLib::PELIB_IMAGE_COMPARE & ImageCompare) +{ + ULONG64 WinImageBase = GetImageBase(pbImageWin); + LPSTR szFileNameA; + size_t nLength = _tcslen(szFileName) + 1; + DWORD SizeOfImage; + DWORD loaderMode = PeLib::LoaderModeWindows7; + + // Set the proper loader mode + if(g_dwWinVer >= 0x0602) + loaderMode = PeLib::LoaderModeWindows10; + + // Create ANSI name of the file + if((szFileNameA = new char[nLength]) != NULL) + { + PeLib::ImageLoader imageLoader(loaderMode); + + // Convert to UNICODE + WideCharToMultiByte(CP_ACP, 0, szFileName, -1, szFileNameA, (int)nLength, NULL, NULL); + + // Load the image using our section reader + if(imageLoader.Load(szFileNameA) == 0) + { + if((SizeOfImage = imageLoader.getSizeOfImageAligned()) != 0) + { + // Windows Vista loader performs relocation in the kernel. + // To be able to compare images, we need to relocate ours + if(loaderMode >= PeLib::LoaderModeWindows7) + imageLoader.relocateImage(WinImageBase); + + // Compare the image with the mapped Windows image + if(pbImageWin && cbImageWin) + imageLoader.compareWithWindowsMappedImage(ImageCompare, pbImageWin, cbImageWin); + + // Dump the image, if not equal + if(ImageCompare.compareResult == PeLib::ImagesDifferentPageValue && ImageCompare.dumpIfNotEqual != nullptr) + imageLoader.dumpImage(ImageCompare.dumpIfNotEqual); + } + } + + delete [] szFileNameA; + } +} + +static void TestFile(LPCTSTR szFileName, LPCTSTR szCopyFolder) +{ + PeLib::PELIB_IMAGE_COMPARE ImageCompare{}; + NTSTATUS Status; + LPBYTE pbImageWin = NULL; + DWORD cbImageWin = 0; + TCHAR szErrMsg[0x200]; + bool bNeedDumpBothImages = false; + bool bNotEnoughMemory = false; + bool bCompareOK = true; + + // Update the console title + StringCchPrintf(szErrMsg, _countof(szErrMsg), _T("%u files checked - Section Reader Test"), g_dwFilesTested); + SetConsoleTitle(szErrMsg); + g_dwFilesTested++; + + // Frame the reading by exception + __try + { + // Load the image using Windows loader + Status = MapFileByWindowsLoader(szFileName, &pbImageWin, &cbImageWin); + + // Only continue the comparison if Windows loader didn't report + // an out-of-memory error code, because we cannot reliably verify anything + if(Status != STATUS_NO_MEMORY) + { + // Load the PE file using our reader + ImageCompare.PfnVerifyAddress = VerifyMemoryAddress; + //ImageCompare.dumpIfNotEqual = "C:\\MappedImageOur.bin"; + MapAndCompareImage(szFileName, pbImageWin, cbImageWin, ImageCompare); + bCompareOK = (ImageCompare.compareResult == PeLib::ImagesEqual); + + // Print the result + switch(ImageCompare.compareResult) + { + case PeLib::ImagesEqual: + break; + + case PeLib::ImagesWindowsLoadedWeDidnt: + PrintCompareResult(szFileName, _T("Windows mapped the image OK, but we didn't")); + break; + + case PeLib::ImagesWindowsDidntLoadWeDid: + PrintCompareResult(szFileName, _T("Windows didn't map the image (%08x), but we did"), Status); + break; + + case PeLib::ImagesDifferentSize: + PrintCompareResult(szFileName, _T("SizeOfImage mismatch")); + break; + + case PeLib::ImagesDifferentPageAccess: + PrintCompareResult(szFileName, _T("Image page accessibility mismatch at offset %08x"), ImageCompare.differenceOffset); + break; + + case PeLib::ImagesDifferentPageValue: + PrintCompareResult(szFileName, _T("Image mismatch at offset %08x"), ImageCompare.differenceOffset); + bNeedDumpBothImages = true; + break; + } + + // Dump both images for fuhrter investigation, if needed + if(ImageCompare.dumpIfNotEqual && bNeedDumpBothImages) + { + WriteDataToFile(_T("C:\\MappedImageWin.bin"), pbImageWin, cbImageWin); + _tprintf(_T(" * Images dumped. Press any key to continue ...\n")); + _getch(); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + _tprintf(_T("%s\n * Exception when processing image\n"), szFileName); + } + + // Free resources + if(pbImageWin != NULL) + NtUnmapViewOfSection(NtCurrentProcess(), pbImageWin); + pbImageWin = NULL; + + // Copy the file to a link folder, if compare failed + if(bCompareOK == false && bNotEnoughMemory == false) + { + CopySampleToFolder(szFileName, szCopyFolder); + g_dwFilesMismatch++; + } + else + { + g_dwFilesMatched++; + } +} + +static void TestFolder(LPCTSTR szFolderName, LPCTSTR szCopyFolder) +{ + WIN32_FIND_DATA wf; + HANDLE hFind; + TCHAR szNameBuff[MAX_PATH]; + BOOL bFound = TRUE; + + // Initiate file search + StringCchPrintf(szNameBuff, _countof(szNameBuff), _T("%s\\*"), szFolderName); + hFind = FindFirstFile(szNameBuff, &wf); + if(hFind != INVALID_HANDLE_VALUE) + { + // Keep searching + while(bFound) + { + // Exclude the "." and ".." directory entries + if(_tcscmp(wf.cFileName, _T(".")) && _tcscmp(wf.cFileName, _T(".."))) + { + // Construct the full name + StringCchPrintf(szNameBuff, _countof(szNameBuff), _T("%s\\%s"), szFolderName, wf.cFileName); + + // Folder/file? + if(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + TestFolder(szNameBuff, szCopyFolder); + } + else + { + TestFile(szNameBuff, szCopyFolder); + } + } + + // Search the next file/folder + bFound = FindNextFile(hFind, &wf); + } + + // Close the find handle + FindClose(hFind); + } +} + +//----------------------------------------------------------------------------- +// The 'main' function + +int _tmain(void) +{ + LPCTSTR szFileOrFolder = NULL; + LPCTSTR szCopyFolder = NULL; + DWORD dwAttr; + + // Get Windows version + g_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&g_osvi); + g_dwWinVer = (g_osvi.dwMajorVersion << 0x08) | g_osvi.dwMinorVersion; + + // ARG1: Name of file/folder + szFileOrFolder = GetStringArg(1, _T(".")); + + // ARG2: Name of collection folder + szCopyFolder = GetStringArg(2, NULL); + + // For stopping in the debugger + //_tprintf(_T("Press any key to begin ...\n")); + //_getch(); + + // Check whether the argument is folder or file + dwAttr = GetFileAttributes(szFileOrFolder); + if(dwAttr == INVALID_FILE_ATTRIBUTES) + return PrintError(_T("Failed to open \"%s\" (error code %u)\n"), szFileOrFolder, GetLastError()); + + // If a folder, we're gonna recursively go over all files + if(dwAttr & FILE_ATTRIBUTE_DIRECTORY) + { + TestFolder(szFileOrFolder, szCopyFolder); + } + else + { + TestFile(szFileOrFolder, szCopyFolder); + } + + // Print summary + _tprintf(_T("\n=[*]= Summary ==========================================\n")); + _tprintf(_T(" * Files tested: %u\n"), g_dwFilesTested); + _tprintf(_T(" * Files matched: %u\n"), g_dwFilesMatched); + _tprintf(_T(" * Files mismatched: %u\n\n"), g_dwFilesMismatch); + SetConsoleTitle(_T("Complete - Section Reader Test")); + + // Exit + _tprintf(_T("Press any key to exit ...\n")); + _getch(); +} + diff --git a/src/pelib/PelibTest_vs17.sln b/src/pelib/PelibTest_vs17.sln new file mode 100644 index 000000000..bdde92e03 --- /dev/null +++ b/src/pelib/PelibTest_vs17.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.1082 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PelibTest", "PelibTest_vs17.vcxproj", "{A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Debug|Win32.ActiveCfg = Debug|Win32 + {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Debug|Win32.Build.0 = Debug|Win32 + {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Debug|x64.ActiveCfg = Debug|x64 + {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Debug|x64.Build.0 = Debug|x64 + {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Release|Win32.ActiveCfg = Release|Win32 + {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Release|Win32.Build.0 = Release|Win32 + {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Release|x64.ActiveCfg = Release|x64 + {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7E200C33-58F7-43F9-B94B-CC8125E389FB} + EndGlobalSection +EndGlobal From 546dbdb3cc961d368d404cf29cca462e53166322 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 16 Jun 2020 16:30:46 +0200 Subject: [PATCH 02/34] ImageLoader: Import & IAT --- .../fileformat/file_format/pe/pe_template.h | 10 +- include/retdec/pelib/BoundImportDirectory.h | 46 +- include/retdec/pelib/CoffSymbolTable.h | 25 +- include/retdec/pelib/ComHeaderDirectory.h | 80 +- include/retdec/pelib/DebugDirectory.h | 40 +- include/retdec/pelib/DelayImportDirectory.h | 22 +- include/retdec/pelib/ExportDirectory.h | 80 +- include/retdec/pelib/IatDirectory.h | 55 +- include/retdec/pelib/ImageLoader.h | 39 +- include/retdec/pelib/ImportDirectory.h | 544 ++++++------ include/retdec/pelib/MzHeader.h | 80 +- include/retdec/pelib/PeFile.h | 90 +- include/retdec/pelib/PeHeader.h | 732 ++++++++-------- include/retdec/pelib/PeLibAux.h | 780 ++++++++---------- include/retdec/pelib/RelocationsDirectory.h | 16 +- include/retdec/pelib/ResourceDirectory.h | 158 ++-- include/retdec/pelib/RichHeader.h | 8 +- include/retdec/pelib/TlsDirectory.h | 40 +- src/fileformat/file_format/file_format.cpp | 36 +- src/fileformat/file_format/pe/pe_format.cpp | 47 +- .../pe_format_parser/pe_format_parser32.cpp | 2 +- .../pe_format_parser/pe_format_parser64.cpp | 2 +- src/fileformat/utils/format_detection.cpp | 18 +- src/fileinfo/file_detector/pe_detector.cpp | 4 +- src/fileinfo/file_wrapper/pe/pe_wrapper.cpp | 8 +- src/pelib/BoundImportDirectory.cpp | 64 +- src/pelib/CMakeLists.txt | 1 + src/pelib/CoffSymbolTable.cpp | 71 +- src/pelib/ComHeaderDirectory.cpp | 80 +- src/pelib/DebugDirectory.cpp | 40 +- src/pelib/ExportDirectory.cpp | 72 +- src/pelib/IatDirectory.cpp | 45 +- src/pelib/ImageLoader.cpp | 298 +++++-- src/pelib/MzHeader.cpp | 92 +-- src/pelib/PeHeader.cpp | 10 +- src/pelib/PeLibAux.cpp | 41 +- src/pelib/PelibTest.cpp | 466 ----------- src/pelib/PelibTest_vs17.sln | 31 - src/pelib/RelocationsDirectory.cpp | 18 +- src/pelib/ResourceDirectory.cpp | 164 ++-- src/pelib/RichHeader.cpp | 24 +- .../plugins/upx/pe/pe_upx_stub.cpp | 7 +- 42 files changed, 2022 insertions(+), 2464 deletions(-) delete mode 100644 src/pelib/PelibTest.cpp delete mode 100644 src/pelib/PelibTest_vs17.sln diff --git a/include/retdec/fileformat/file_format/pe/pe_template.h b/include/retdec/fileformat/file_format/pe/pe_template.h index ca886763a..735377519 100644 --- a/include/retdec/fileformat/file_format/pe/pe_template.h +++ b/include/retdec/fileformat/file_format/pe/pe_template.h @@ -329,7 +329,7 @@ template unsigned long long peNumberOfStoredDataDirectories(const PeLi * @param peImports Parser of PE import directory * @return Number of imported libraries */ -template unsigned long long peNumberOfImportedLibraries(const PeLib::ImportDirectory &peImports) +inline unsigned long long peNumberOfImportedLibraries(const PeLib::ImportDirectory &peImports) { return peImports.getNumberOfFiles(PeLib::OLDDIR); } @@ -484,8 +484,8 @@ template bool peDataDirectoryAbsolute(const PeLib::PeHeaderT &pe * * If function returns @c false, @a fileName is left unchanged. */ -template bool peImportedLibraryFileName( - const PeLib::ImportDirectory &peImports, +inline bool peImportedLibraryFileName( + const PeLib::ImportDirectory &peImports, std::string &fileName, unsigned long long index) { @@ -531,7 +531,7 @@ template bool peDelayImportedLibraryFileName(const PeLib::DelayImportD * If function returns info about import, or @c nullptr if invalid import is requested. */ template std::unique_ptr peImport(const PeLib::PeHeaderT &peHeader, - const PeLib::ImportDirectory &peImports, + const PeLib::ImportDirectory &peImports, unsigned long long fileIndex, unsigned long long importIndex) { if(fileIndex >= peNumberOfImportedLibraries(peImports) || @@ -885,7 +885,7 @@ template unsigned long long peSecurityDirSize(const PeLib::PeHeaderT retdec::common::RangeContainer peImportDirectoryOccupiedAddresses(const PeLib::ImportDirectory &peImports) +inline retdec::common::RangeContainer peImportDirectoryOccupiedAddresses(const PeLib::ImportDirectory &peImports) { retdec::common::RangeContainer result; for (const auto& addresses : peImports.getOccupiedAddresses()) diff --git a/include/retdec/pelib/BoundImportDirectory.h b/include/retdec/pelib/BoundImportDirectory.h index 6bb636d77..76dd24bee 100644 --- a/include/retdec/pelib/BoundImportDirectory.h +++ b/include/retdec/pelib/BoundImportDirectory.h @@ -33,7 +33,7 @@ namespace PeLib virtual ~BoundImportDirectory() = default; /// Adds another bound import. - int addBoundImport(const std::string& strModuleName, dword dwTds, word dwOmn, word wWfr); // EXPORT + int addBoundImport(const std::string& strModuleName, std::uint32_t dwTds, std::uint16_t dwOmn, std::uint16_t wWfr); // EXPORT /// Identifies a module through it's name. int getModuleIndex(const std::string& strModuleName) const; // EXPORT /// Returns the number of files in the BoundImport directory. @@ -41,7 +41,7 @@ namespace PeLib /// Reads the BoundImport directory table from a PE file. int read(unsigned char* pcBuffer, unsigned int uiSize); // EXPORT /// Rebuilds the BoundImport directory. - void rebuild(std::vector& vBuffer, bool fMakeValid = true) const; // EXPORT + void rebuild(std::vector& vBuffer, bool fMakeValid = true) const; // EXPORT /// Empties the BoundImport directory. void clear(); // EXPORT /// Removes a bound import. @@ -49,39 +49,39 @@ namespace PeLib /// Returns the size of the BoundImport directory. unsigned int size() const; // EXPORT /// Writes the current bound import directory to a file. - int write(const std::string& strFilename, dword dwOffset, bool fMakeValid = true) const; // EXPORT + int write(const std::string& strFilename, std::uint32_t dwOffset, bool fMakeValid = true) const; // EXPORT /// Retrieves the TimeDateStamp value of a bound import. - dword getTimeDateStamp(dword dwBidnr) const; // EXPORT + std::uint32_t getTimeDateStamp(std::uint32_t dwBidnr) const; // EXPORT /// Retrieves the OffsetModuleName value of a bound import. - word getOffsetModuleName(dword dwBidnr) const; // EXPORT + std::uint16_t getOffsetModuleName(std::uint32_t dwBidnr) const; // EXPORT /// Retrieves the NumberOfModuleForwarderRefs value of a bound import. - word getNumberOfModuleForwarderRefs(dword dwBidnr) const; // EXPORT + std::uint16_t getNumberOfModuleForwarderRefs(std::uint32_t dwBidnr) const; // EXPORT /// Retrieves the ModuleName value of a bound import. - std::string getModuleName(dword dwBidnr) const; // EXPORT + std::string getModuleName(std::uint32_t dwBidnr) const; // EXPORT /// Updates the TimeDateStamp value of a bound import. - void setTimeDateStamp(dword dwBidnr, dword dwTds); // EXPORT + void setTimeDateStamp(std::uint32_t dwBidnr, std::uint32_t dwTds); // EXPORT /// Updates the OffsetModuleName value of a bound import. - void setOffsetModuleName(dword dwBidnr, word wOmn); // EXPORT + void setOffsetModuleName(std::uint32_t dwBidnr, std::uint16_t wOmn); // EXPORT /// Updates the NumberOfModuleForwarderRefs value of a bound import. - void setNumberOfModuleForwarderRefs(dword dwBidnr, word wMfr); // EXPORT + void setNumberOfModuleForwarderRefs(std::uint32_t dwBidnr, std::uint16_t wMfr); // EXPORT /// Updates the ModuleName value of a bound import. - void setModuleName(dword dwBidnr, const std::string& strModuleName); // EXPORT + void setModuleName(std::uint32_t dwBidnr, const std::string& strModuleName); // EXPORT - dword getTimeDateStamp(dword dwBidnr, dword forwardedModule) const; // EXPORT _module - word getOffsetModuleName(dword dwBidnr, dword forwardedModule) const; // EXPORT _module - word getNumberOfModuleForwarderRefs(dword dwBidnr, dword forwardedModule) const; // EXPORT _module - std::string getModuleName(dword dwBidnr, dword forwardedModule) const; // EXPORT _module + std::uint32_t getTimeDateStamp(std::uint32_t dwBidnr, std::uint32_t forwardedModule) const; // EXPORT _module + std::uint16_t getOffsetModuleName(std::uint32_t dwBidnr, std::uint32_t forwardedModule) const; // EXPORT _module + std::uint16_t getNumberOfModuleForwarderRefs(std::uint32_t dwBidnr, std::uint32_t forwardedModule) const; // EXPORT _module + std::string getModuleName(std::uint32_t dwBidnr, std::uint32_t forwardedModule) const; // EXPORT _module - void setTimeDateStamp(dword dwBidnr, dword forwardedModule, dword dwTds); // EXPORT _module - void setOffsetModuleName(dword dwBidnr, dword forwardedModule, word wOmn); // EXPORT _module - void setNumberOfModuleForwarderRefs(dword dwBidnr, dword forwardedModule, word wMfr); // EXPORT _module - void setModuleName(dword dwBidnr, dword forwardedModule, const std::string& strModuleName); // EXPORT _module + void setTimeDateStamp(std::uint32_t dwBidnr, std::uint32_t forwardedModule, std::uint32_t dwTds); // EXPORT _module + void setOffsetModuleName(std::uint32_t dwBidnr, std::uint32_t forwardedModule, std::uint16_t wOmn); // EXPORT _module + void setNumberOfModuleForwarderRefs(std::uint32_t dwBidnr, std::uint32_t forwardedModule, std::uint16_t wMfr); // EXPORT _module + void setModuleName(std::uint32_t dwBidnr, std::uint32_t forwardedModule, const std::string& strModuleName); // EXPORT _module - word calcNumberOfModuleForwarderRefs(dword dwBidnr) const; // EXPORT - void addForwardedModule(dword dwBidnr, const std::string& name, dword timeStamp = 0, word offsetModuleName = 0, word forwardedModules = 0); // EXPORT - void removeForwardedModule(dword dwBidnr, word forwardedModule); // EXPORT + std::uint16_t calcNumberOfModuleForwarderRefs(std::uint32_t dwBidnr) const; // EXPORT + void addForwardedModule(std::uint32_t dwBidnr, const std::string& name, std::uint32_t timeStamp = 0, std::uint16_t offsetModuleName = 0, std::uint16_t forwardedModules = 0); // EXPORT + void removeForwardedModule(std::uint32_t dwBidnr, std::uint16_t forwardedModule); // EXPORT }; template @@ -109,7 +109,7 @@ namespace PeLib return ERROR_OPENING_FILE; } - dword dwOffset = peHeader.rvaToOffset(peHeader.getIddBoundImportRva()); + std::uint32_t dwOffset = peHeader.rvaToOffset(peHeader.getIddBoundImportRva()); unsigned int uiSize = peHeader.getIddBoundImportSize(); if (fileSize(inStream_w) < dwOffset + uiSize) diff --git a/include/retdec/pelib/CoffSymbolTable.h b/include/retdec/pelib/CoffSymbolTable.h index d3cf6a44f..00677ad79 100644 --- a/include/retdec/pelib/CoffSymbolTable.h +++ b/include/retdec/pelib/CoffSymbolTable.h @@ -18,9 +18,9 @@ namespace PeLib { private: std::size_t stringTableSize; - dword numberOfStoredSymbols; - std::vector stringTable; - std::vector symbolTableDump; + std::uint32_t numberOfStoredSymbols; + ByteBuffer stringTable; + ByteBuffer symbolTableDump; std::vector symbolTable; LoaderError m_ldrError; @@ -32,20 +32,17 @@ namespace PeLib LoaderError loaderError() const; void setLoaderError(LoaderError ldrError); - int read( - std::istream& inStream, - unsigned int uiOffset, - unsigned int uiSize); + int read(ByteBuffer & fileData, std::size_t uiOffset, std::size_t uiSize); std::size_t getSizeOfStringTable() const; std::size_t getNumberOfStoredSymbols() const; - dword getSymbolIndex(std::size_t ulSymbol) const; + std::uint32_t getSymbolIndex(std::size_t ulSymbol) const; std::string getSymbolName(std::size_t ulSymbol) const; - dword getSymbolValue(std::size_t ulSymbol) const; - word getSymbolSectionNumber(std::size_t ulSymbol) const; - byte getSymbolTypeComplex(std::size_t ulSymbol) const; - byte getSymbolTypeSimple(std::size_t ulSymbol) const; - byte getSymbolStorageClass(std::size_t ulSymbol) const; - byte getSymbolNumberOfAuxSymbols(std::size_t ulSymbol) const; + std::uint32_t getSymbolValue(std::size_t ulSymbol) const; + std::uint16_t getSymbolSectionNumber(std::size_t ulSymbol) const; + std::uint8_t getSymbolTypeComplex(std::size_t ulSymbol) const; + std::uint8_t getSymbolTypeSimple(std::size_t ulSymbol) const; + std::uint8_t getSymbolStorageClass(std::size_t ulSymbol) const; + std::uint8_t getSymbolNumberOfAuxSymbols(std::size_t ulSymbol) const; }; } diff --git a/include/retdec/pelib/ComHeaderDirectory.h b/include/retdec/pelib/ComHeaderDirectory.h index 235ba8a84..34d96ce3b 100644 --- a/include/retdec/pelib/ComHeaderDirectory.h +++ b/include/retdec/pelib/ComHeaderDirectory.h @@ -35,89 +35,89 @@ namespace PeLib /// Read a file's COM+ runtime descriptor directory. int read(unsigned char* buffer, unsigned int buffersize); // EXPORT /// Rebuild the COM+ descriptor. - void rebuild(std::vector& vBuffer) const; // EXPORT + void rebuild(std::vector& vBuffer) const; // EXPORT /// Returns the size of the current COM+ descriptor. unsigned int size() const; // EXPORT /// Writes the current COM+ descriptor directory to a file. int write(const std::string& strFilename, unsigned int dwOffset) const; // EXPORT /// Get the COM+ descriptor's SizeOfHeader (cb) value. - dword getSizeOfHeader() const; // EXPORT + std::uint32_t getSizeOfHeader() const; // EXPORT /// Get the COM+ descriptor's MajorRuntimeVersion value. - word getMajorRuntimeVersion() const; // EXPORT + std::uint16_t getMajorRuntimeVersion() const; // EXPORT /// Get the COM+ descriptor's MinorRuntimeVersion value. - word getMinorRuntimeVersion() const; // EXPORT + std::uint16_t getMinorRuntimeVersion() const; // EXPORT /// Get the COM+ descriptor's MetaData (Virtual Address) value. - dword getMetaDataVa() const; // EXPORT + std::uint32_t getMetaDataVa() const; // EXPORT /// Get the COM+ descriptor's MetaData (Size) value. - dword getMetaDataSize() const; // EXPORT + std::uint32_t getMetaDataSize() const; // EXPORT /// Get the COM+ descriptor's Flags value. - dword getFlags() const; // EXPORT + std::uint32_t getFlags() const; // EXPORT /// Get the COM+ descriptor's EntryPointToken value. - dword getEntryPointToken() const; // EXPORT + std::uint32_t getEntryPointToken() const; // EXPORT /// Get the COM+ descriptor's Resources (Virtual Address) value. - dword getResourcesVa() const; // EXPORT + std::uint32_t getResourcesVa() const; // EXPORT /// Get the COM+ descriptor's Resources (Size) value. - dword getResourcesSize() const; // EXPORT + std::uint32_t getResourcesSize() const; // EXPORT /// Get the COM+ descriptor's StrongNameSignature (Virtual Address) value. - dword getStrongNameSignatureVa() const; // EXPORT + std::uint32_t getStrongNameSignatureVa() const; // EXPORT /// Get the COM+ descriptor's StrongNameSignature (Size) value. - dword getStrongNameSignatureSize() const; // EXPORT + std::uint32_t getStrongNameSignatureSize() const; // EXPORT /// Get the COM+ descriptor's CodeManagerTable (Virtual Address) value. - dword getCodeManagerTableVa() const; // EXPORT + std::uint32_t getCodeManagerTableVa() const; // EXPORT /// Get the COM+ descriptor's CodeManagerTable (Size) value. - dword getCodeManagerTableSize() const; // EXPORT + std::uint32_t getCodeManagerTableSize() const; // EXPORT /// Get the COM+ descriptor's VTableFixup (Virtual Address) value. - dword getVTableFixupsVa() const; // EXPORT + std::uint32_t getVTableFixupsVa() const; // EXPORT /// Get the COM+ descriptor's VTableFixup (Size) value. - dword getVTableFixupsSize() const; // EXPORT + std::uint32_t getVTableFixupsSize() const; // EXPORT /// Get the COM+ descriptor's ExportAddressTable (Virtual Address) value. - dword getExportAddressTableJumpsVa() const; // EXPORT + std::uint32_t getExportAddressTableJumpsVa() const; // EXPORT /// Get the COM+ descriptor's ExportAddressTable (Size) value. - dword getExportAddressTableJumpsSize() const; // EXPORT + std::uint32_t getExportAddressTableJumpsSize() const; // EXPORT /// Get the COM+ descriptor's ManagedNativeHeader (Virtual Address) value. - dword getManagedNativeHeaderVa() const; // EXPORT + std::uint32_t getManagedNativeHeaderVa() const; // EXPORT /// Get the COM+ descriptor's ManagedNativeHeader (Size) value. - dword getManagedNativeHeaderSize() const; // EXPORT + std::uint32_t getManagedNativeHeaderSize() const; // EXPORT /// Change the COM+ descriptor's SizeOfHeader (cb) value. - void setSizeOfHeader(dword dwValue); // EXPORT + void setSizeOfHeader(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's MajorRuntimeVersion value. - void setMajorRuntimeVersion(word wValue); // EXPORT + void setMajorRuntimeVersion(std::uint16_t wValue); // EXPORT /// Change the COM+ descriptor's MinorRuntimeVersion value. - void setMinorRuntimeVersion(word wValue); // EXPORT + void setMinorRuntimeVersion(std::uint16_t wValue); // EXPORT /// Change the COM+ descriptor's MetaData (VirtualAddress) value. - void setMetaDataVa(dword dwValue); // EXPORT + void setMetaDataVa(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's MetaData (Size) value. - void setMetaDataSize(dword dwValue); // EXPORT + void setMetaDataSize(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's Flags value. - void setFlags(dword dwValue); // EXPORT + void setFlags(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's EntryPointToken value. - void setEntryPointToken(dword dwValue); // EXPORT + void setEntryPointToken(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's Resources (VirtualAddress) value. - void setResourcesVa(dword dwValue); // EXPORT + void setResourcesVa(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's Resources (Size) value. - void setResourcesSize(dword dwValue); // EXPORT + void setResourcesSize(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's StrongNameSignatureVa (VirtualAddress) value. - void setStrongNameSignatureVa(dword dwValue); // EXPORT + void setStrongNameSignatureVa(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's StrongNameSignatureVa (Size) value. - void setStrongNameSignagureSize(dword dwValue); // EXPORT + void setStrongNameSignagureSize(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's CodeManagerTable (VirtualAddress) value. - void setCodeManagerTableVa(dword dwValue); // EXPORT + void setCodeManagerTableVa(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's CodeManagerTable (Size) value. - void setCodeManagerTableSize(dword dwValue); // EXPORT + void setCodeManagerTableSize(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's VTableFixups (VirtualAddress) value. - void setVTableFixupsVa(dword dwValue); // EXPORT + void setVTableFixupsVa(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's VTableFixups (Size) value. - void setVTableFixupsSize(dword dwValue); // EXPORT + void setVTableFixupsSize(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's ExportAddressTableJumps (VirtualAddress) value. - void setExportAddressTableJumpsVa(dword dwValue); // EXPORT + void setExportAddressTableJumpsVa(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's ExportAddressTableJumps (Size) value. - void setExportAddressTableJumpsSize(dword dwValue); // EXPORT + void setExportAddressTableJumpsSize(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's ManagedNativeHeader (VirtualAddress) value. - void setManagedNativeHeaderVa(dword dwValue); // EXPORT + void setManagedNativeHeaderVa(std::uint32_t dwValue); // EXPORT /// Change the COM+ descriptor's ManagedNativeHeader (Size) value. - void setManagedNativeHeaderSize(dword dwValue); // EXPORT + void setManagedNativeHeaderSize(std::uint32_t dwValue); // EXPORT }; template @@ -155,7 +155,7 @@ namespace PeLib inStream_w.seekg(uiOffset, std::ios::beg); - std::vector vComDescDirectory(uiSize); + std::vector vComDescDirectory(uiSize); inStream_w.read(reinterpret_cast(vComDescDirectory.data()), uiSize); InputBuffer ibBuffer{vComDescDirectory}; diff --git a/include/retdec/pelib/DebugDirectory.h b/include/retdec/pelib/DebugDirectory.h index b0828324f..5ee5b6876 100644 --- a/include/retdec/pelib/DebugDirectory.h +++ b/include/retdec/pelib/DebugDirectory.h @@ -35,7 +35,7 @@ namespace PeLib /// Reads the Debug directory from a file. int read(unsigned char* buffer, unsigned int buffersize); /// Rebuilds the current Debug directory. - void rebuild(std::vector& obBuffer) const; // EXPORT + void rebuild(std::vector& obBuffer) const; // EXPORT /// Returns the size the current Debug directory needs after rebuilding. unsigned int size() const; /// Writes the current Debug directory back to a file. @@ -50,40 +50,40 @@ namespace PeLib void removeEntry(std::size_t uiIndex); // EXPORT /// Returns the Characteristics value of a debug structure. - dword getCharacteristics(std::size_t uiIndex) const; // EXPORT + std::uint32_t getCharacteristics(std::size_t uiIndex) const; // EXPORT /// Returns the TimeDateStamp value of a debug structure. - dword getTimeDateStamp(std::size_t uiIndex) const; // EXPORT + std::uint32_t getTimeDateStamp(std::size_t uiIndex) const; // EXPORT /// Returns the MajorVersion value of a debug structure. - word getMajorVersion(std::size_t uiIndex) const; // EXPORT + std::uint16_t getMajorVersion(std::size_t uiIndex) const; // EXPORT /// Returns the MinorVersion value of a debug structure. - word getMinorVersion(std::size_t uiIndex) const; // EXPORT + std::uint16_t getMinorVersion(std::size_t uiIndex) const; // EXPORT /// Returns the Type value of a debug structure. - dword getType(std::size_t uiIndex) const; // EXPORT + std::uint32_t getType(std::size_t uiIndex) const; // EXPORT /// Returns the SizeOfData value of a debug structure. - dword getSizeOfData(std::size_t uiIndex) const; // EXPORT + std::uint32_t getSizeOfData(std::size_t uiIndex) const; // EXPORT /// Returns the AddressOfRawData value of a debug structure. - dword getAddressOfRawData(std::size_t uiIndex) const; // EXPORT + std::uint32_t getAddressOfRawData(std::size_t uiIndex) const; // EXPORT /// Returns the PointerToRawData value of a debug structure. - dword getPointerToRawData(std::size_t uiIndex) const; // EXPORT - std::vector getData(std::size_t index) const; // EXPORT + std::uint32_t getPointerToRawData(std::size_t uiIndex) const; // EXPORT + std::vector getData(std::size_t index) const; // EXPORT /// Sets the Characteristics value of a debug structure. - void setCharacteristics(std::size_t uiIndex, dword dwValue); // EXPORT + void setCharacteristics(std::size_t uiIndex, std::uint32_t dwValue); // EXPORT /// Sets the TimeDateStamp value of a debug structure. - void setTimeDateStamp(std::size_t uiIndex, dword dwValue); // EXPORT + void setTimeDateStamp(std::size_t uiIndex, std::uint32_t dwValue); // EXPORT /// Sets the MajorVersion value of a debug structure. - void setMajorVersion(std::size_t uiIndex, word wValue); // EXPORT + void setMajorVersion(std::size_t uiIndex, std::uint16_t wValue); // EXPORT /// Sets the MinorVersion value of a debug structure. - void setMinorVersion(std::size_t uiIndex, word wValue); // EXPORT + void setMinorVersion(std::size_t uiIndex, std::uint16_t wValue); // EXPORT /// Sets the Type value of a debug structure. - void setType(std::size_t uiIndex, dword dwValue); // EXPORT + void setType(std::size_t uiIndex, std::uint32_t dwValue); // EXPORT /// Sets the SizeOfData value of a debug structure. - void setSizeOfData(std::size_t uiIndex, dword dwValue); // EXPORT + void setSizeOfData(std::size_t uiIndex, std::uint32_t dwValue); // EXPORT /// Sets the AddressOfRawData value of a debug structure. - void setAddressOfRawData(std::size_t uiIndex, dword dwValue); // EXPORT + void setAddressOfRawData(std::size_t uiIndex, std::uint32_t dwValue); // EXPORT /// Sets the PointerToRawData value of a debug structure. - void setPointerToRawData(std::size_t uiIndex, dword dwValue); // EXPORT - void setData(std::size_t index, const std::vector& data); // EXPORT + void setPointerToRawData(std::size_t uiIndex, std::uint32_t dwValue); // EXPORT + void setData(std::size_t index, const std::vector& data); // EXPORT const std::vector>& getOccupiedAddresses() const; }; @@ -123,7 +123,7 @@ namespace PeLib inStream_w.seekg(uiOffset, std::ios::beg); - std::vector vDebugDirectory(uiSize); + std::vector vDebugDirectory(uiSize); inStream_w.read(reinterpret_cast(vDebugDirectory.data()), uiSize); InputBuffer ibBuffer{vDebugDirectory}; diff --git a/include/retdec/pelib/DelayImportDirectory.h b/include/retdec/pelib/DelayImportDirectory.h index 48afccbbd..7161a4090 100644 --- a/include/retdec/pelib/DelayImportDirectory.h +++ b/include/retdec/pelib/DelayImportDirectory.h @@ -123,15 +123,15 @@ namespace PeLib // Convert older (MS Visual C++ 6.0) delay-import descriptor to newer one. // These delay-import descriptors are distinguishable by lowest bit in rec.Attributes to be zero. // Sample: 2775d97f8bdb3311ace960a42eee35dbec84b9d71a6abbacb26c14e83f5897e4 - rec.NameRva = (dword)normalizeDelayImportValue(rec, peHeader, rec.NameRva); - rec.ModuleHandleRva = (dword)normalizeDelayImportValue(rec, peHeader, rec.ModuleHandleRva); - rec.DelayImportAddressTableRva = (dword)normalizeDelayImportValue(rec, peHeader, rec.DelayImportAddressTableRva); - rec.DelayImportNameTableRva = (dword)normalizeDelayImportValue(rec, peHeader, rec.DelayImportNameTableRva); - rec.BoundDelayImportTableRva = (dword)normalizeDelayImportValue(rec, peHeader, rec.BoundDelayImportTableRva); - rec.UnloadDelayImportTableRva = (dword)normalizeDelayImportValue(rec, peHeader, rec.UnloadDelayImportTableRva); + rec.NameRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.NameRva); + rec.ModuleHandleRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.ModuleHandleRva); + rec.DelayImportAddressTableRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.DelayImportAddressTableRva); + rec.DelayImportNameTableRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.DelayImportNameTableRva); + rec.BoundDelayImportTableRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.BoundDelayImportTableRva); + rec.UnloadDelayImportTableRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.UnloadDelayImportTableRva); - rec.DelayImportAddressTableOffset = (dword)peHeader.rvaToOffset(rec.DelayImportAddressTableRva); - rec.DelayImportNameTableOffset = (dword)peHeader.rvaToOffset(rec.DelayImportNameTableRva); + rec.DelayImportAddressTableOffset = (std::uint32_t)peHeader.rvaToOffset(rec.DelayImportAddressTableRva); + rec.DelayImportNameTableOffset = (std::uint32_t)peHeader.rvaToOffset(rec.DelayImportNameTableRva); // Get name of library getStringFromFileOffset(inStream_w, rec.Name, (std::size_t)peHeader.rvaToOffset(rec.NameRva), IMPORT_LIBRARY_MAX_LENGTH); @@ -152,7 +152,7 @@ namespace PeLib for(;;) { PELIB_VAR_SIZE nameAddr; - std::vector vBuffer(sizeof(nameAddr.Value)); + std::vector vBuffer(sizeof(nameAddr.Value)); // Read the value from the file inStream_w.read(reinterpret_cast(vBuffer.data()), sizeof(nameAddr.Value)); @@ -184,7 +184,7 @@ namespace PeLib for (std::size_t i = 0, e = nameAddresses.size(); i < e; ++i) { PELIB_VAR_SIZE funcAddr; - std::vector vBuffer(sizeof(funcAddr.Value)); + std::vector vBuffer(sizeof(funcAddr.Value)); // Read the value from the file inStream_w.read(reinterpret_cast(vBuffer.data()), sizeof(funcAddr.Value)); @@ -228,7 +228,7 @@ namespace PeLib } else { - function.hint = (word)(nameAddr.Value & 0xFFFF); + function.hint = (std::uint16_t)(nameAddr.Value & 0xFFFF); } // Fill-in function address. The table is always in the image itself diff --git a/include/retdec/pelib/ExportDirectory.h b/include/retdec/pelib/ExportDirectory.h index 2821b0859..42ec7bedd 100644 --- a/include/retdec/pelib/ExportDirectory.h +++ b/include/retdec/pelib/ExportDirectory.h @@ -34,13 +34,13 @@ namespace PeLib virtual ~ExportDirectory() = default; /// Add another function to be exported. - void addFunction(const std::string& strFuncname, dword dwFuncAddr); // EXPORT + void addFunction(const std::string& strFuncname, std::uint32_t dwFuncAddr); // EXPORT unsigned int calcNumberOfFunctions() const; // EXPORT void clear(); // EXPORT /// Identifies a function through it's name. int getFunctionIndex(const std::string& strFunctionName) const; // EXPORT /// Rebuild the current export directory. - void rebuild(std::vector& vBuffer, dword dwRva) const; // EXPORT + void rebuild(std::vector& vBuffer, std::uint32_t dwRva) const; // EXPORT void removeFunction(unsigned int index); // EXPORT /// Returns the size of the current export directory. unsigned int size() const; // EXPORT @@ -54,82 +54,82 @@ namespace PeLib /// Get the name of an exported function. std::string getFunctionName(std::size_t index) const; // EXPORT /// Get the ordinal of an exported function. - word getFunctionOrdinal(std::size_t index) const; // EXPORT + std::uint16_t getFunctionOrdinal(std::size_t index) const; // EXPORT /// Get the address of the name of an exported function. - dword getAddressOfName(std::size_t index) const; // EXPORT + std::uint32_t getAddressOfName(std::size_t index) const; // EXPORT /// Get the address of an exported function. - dword getAddressOfFunction(std::size_t index) const; // EXPORT + std::uint32_t getAddressOfFunction(std::size_t index) const; // EXPORT /// Change the name of an exported function. void setFunctionName(std::size_t index, const std::string& strName); // EXPORT /// Change the ordinal of an exported function. - void setFunctionOrdinal(std::size_t index, word wValue); // EXPORT + void setFunctionOrdinal(std::size_t index, std::uint16_t wValue); // EXPORT /// Change the address of the name of an exported function. - void setAddressOfName(std::size_t index, dword dwValue); // EXPORT + void setAddressOfName(std::size_t index, std::uint32_t dwValue); // EXPORT /// Change the address of an exported function. - void setAddressOfFunction(std::size_t index, dword dwValue); // EXPORT + void setAddressOfFunction(std::size_t index, std::uint32_t dwValue); // EXPORT /* - word getFunctionOrdinal(std::string strFuncname) const; - dword getAddressOfName(std::string strFuncname) const; - dword getAddressOfFunction(std::string strFuncname) const; + std::uint16_t getFunctionOrdinal(std::string strFuncname) const; + std::uint32_t getAddressOfName(std::string strFuncname) const; + std::uint32_t getAddressOfFunction(std::string strFuncname) const; - void setFunctionOrdinal(std::string strFuncname, word wValue); - void setAddressOfName(std::string strFuncname, dword dwValue); - void setAddressOfFunction(std::string strFuncname, dword dwValue); + void setFunctionOrdinal(std::string strFuncname, std::uint16_t wValue); + void setAddressOfName(std::string strFuncname, std::uint32_t dwValue); + void setAddressOfFunction(std::string strFuncname, std::uint32_t dwValue); */ /// Return the Base value of the export directory. - dword getBase() const; // EXPORT + std::uint32_t getBase() const; // EXPORT /// Return the Characteristics value of the export directory. - dword getCharacteristics() const; // EXPORT + std::uint32_t getCharacteristics() const; // EXPORT /// Return the TimeDateStamp value of the export directory. - dword getTimeDateStamp() const; // EXPORT + std::uint32_t getTimeDateStamp() const; // EXPORT /// Return the MajorVersion value of the export directory. - word getMajorVersion() const; // EXPORT + std::uint16_t getMajorVersion() const; // EXPORT /// Return the MinorVersion value of the export directory. - word getMinorVersion() const; // EXPORT + std::uint16_t getMinorVersion() const; // EXPORT /// Return the Name value of the export directory. - dword getName() const; // EXPORT + std::uint32_t getName() const; // EXPORT /// Return the NumberOfFunctions value of the export directory. - dword getNumberOfFunctions() const; // EXPORT + std::uint32_t getNumberOfFunctions() const; // EXPORT /// Return the NumberOfNames value of the export directory. - dword getNumberOfNames() const; // EXPORT + std::uint32_t getNumberOfNames() const; // EXPORT /// Return the AddressOfFunctions value of the export directory. - dword getAddressOfFunctions() const; // EXPORT + std::uint32_t getAddressOfFunctions() const; // EXPORT /// Return the AddressOfNames value of the export directory. - dword getAddressOfNames() const; // EXPORT + std::uint32_t getAddressOfNames() const; // EXPORT /// Returns the AddressOfNameOrdinals value. - dword getAddressOfNameOrdinals() const; // EXPORT + std::uint32_t getAddressOfNameOrdinals() const; // EXPORT /* /// Returns the number of NameOrdinals. - dword getNumberOfNameOrdinals() const; // EXPORT + std::uint32_t getNumberOfNameOrdinals() const; // EXPORT /// Returns the number of AddressOfFunctionNames values. - dword getNumberOfAddressOfFunctionNames() const; // EXPORT + std::uint32_t getNumberOfAddressOfFunctionNames() const; // EXPORT /// Returns the number of AddressOfFunction values. - dword getNumberOfAddressOfFunctions() const; // EXPORT + std::uint32_t getNumberOfAddressOfFunctions() const; // EXPORT */ /// Set the Base value of the export directory. - void setBase(dword dwValue); // EXPORT + void setBase(std::uint32_t dwValue); // EXPORT /// Set the Characteristics value of the export directory. - void setCharacteristics(dword dwValue); // EXPORT + void setCharacteristics(std::uint32_t dwValue); // EXPORT /// Set the TimeDateStamp value of the export directory. - void setTimeDateStamp(dword dwValue); // EXPORT + void setTimeDateStamp(std::uint32_t dwValue); // EXPORT /// Set the MajorVersion value of the export directory. - void setMajorVersion(word wValue); // EXPORT + void setMajorVersion(std::uint16_t wValue); // EXPORT /// Set the MinorVersion value of the export directory. - void setMinorVersion(word wValue); // EXPORT + void setMinorVersion(std::uint16_t wValue); // EXPORT /// Set the Name value of the export directory. - void setName(dword dwValue); // EXPORT + void setName(std::uint32_t dwValue); // EXPORT /// Set the NumberOfFunctions value of the export directory. - void setNumberOfFunctions(dword dwValue); // EXPORT + void setNumberOfFunctions(std::uint32_t dwValue); // EXPORT /// Set the NumberOfNames value of the export directory. - void setNumberOfNames(dword dwValue); // EXPORT + void setNumberOfNames(std::uint32_t dwValue); // EXPORT /// Set the AddressOfFunctions value of the export directory. - void setAddressOfFunctions(dword dwValue); // EXPORT + void setAddressOfFunctions(std::uint32_t dwValue); // EXPORT /// Set the AddressOfNames value of the export directory. - void setAddressOfNames(dword dwValue); // EXPORT - void setAddressOfNameOrdinals(dword value); // EXPORT + void setAddressOfNames(std::uint32_t dwValue); // EXPORT + void setAddressOfNameOrdinals(std::uint32_t value); // EXPORT const std::vector>& getOccupiedAddresses() const; }; @@ -236,7 +236,7 @@ namespace PeLib if (offset >= ulFileSize) return ERROR_INVALID_FILE; inStream_w.seekg(offset, std::ios::beg); - word ordinal; + std::uint16_t ordinal; inStream_w.read(reinterpret_cast(&ordinal), sizeof(ordinal)); m_occupiedAddresses.emplace_back( iedCurr.ied.AddressOfNameOrdinals + i*sizeof(efiCurr.ordinal), diff --git a/include/retdec/pelib/IatDirectory.h b/include/retdec/pelib/IatDirectory.h index 261b7bc3e..4b0967dd9 100644 --- a/include/retdec/pelib/IatDirectory.h +++ b/include/retdec/pelib/IatDirectory.h @@ -15,6 +15,7 @@ #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { @@ -25,7 +26,7 @@ namespace PeLib class IatDirectory { protected: - std::vector m_vIat; ///< Stores the individual IAT fields. + std::vector m_vIat; ///< Stores the individual IAT fields. int read(InputBuffer& inputBuffer, unsigned int dwOffset, unsigned int dwFileSize); @@ -34,68 +35,28 @@ namespace PeLib /// Reads the Import Address Table from a PE file. int read(unsigned char* buffer, unsigned int buffersize); // EXPORT + /// Reads the Import Address Table from an image loader + int read(PeLib::ImageLoader & imageLoader); // EXPORT /// Returns the number of fields in the IAT. unsigned int calcNumberOfAddresses() const; // EXPORT /// Adds another address to the IAT. - void addAddress(dword dwValue); // EXPORT + void addAddress(std::uint32_t dwValue); // EXPORT /// Removes an address from the IAT. void removeAddress(unsigned int index); // EXPORT /// Empties the IAT. void clear(); // EXPORT // Rebuilds the IAT. - void rebuild(std::vector& vBuffer) const; // EXPORT + void rebuild(std::vector& vBuffer) const; // EXPORT /// Returns the size of the current IAT. unsigned int size() const; // EXPORT /// Writes the current IAT to a file. int write(const std::string& strFilename, unsigned int uiOffset) const; // EXPORT /// Retrieve the value of a field in the IAT. - dword getAddress(unsigned int index) const; // EXPORT + std::uint32_t getAddress(unsigned int index) const; // EXPORT /// Change the value of a field in the IAT. - void setAddress(dword dwAddrnr, dword dwValue); // EXPORT + void setAddress(std::uint32_t dwAddrnr, std::uint32_t dwValue); // EXPORT }; - - template - class IatDirectoryT : public IatDirectory - { - public: - int read(std::istream& inStream, const PeHeaderT& peHeader); // EXPORT - }; - - /** - * Reads the Import Address table from a file. - * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. - **/ - template - int IatDirectoryT::read(std::istream& inStream, const PeHeaderT& peHeader) - { - IStreamWrapper inStream_w(inStream); - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - std::uint64_t ulFileSize = fileSize(inStream_w); - std::uint64_t dwOffset = peHeader.rvaToOffset(peHeader.getIddIatRva()); - std::uint64_t dwSize = peHeader.getIddIatSize(); - - if (ulFileSize <= dwOffset) - { - return ERROR_INVALID_FILE; - } - - dwSize = std::min(ulFileSize - dwOffset, dwSize); - inStream_w.seekg(dwOffset, std::ios::beg); - - std::vector vBuffer(dwSize); - inStream_w.read(reinterpret_cast(vBuffer.data()), dwSize); - - InputBuffer inpBuffer{vBuffer}; - return IatDirectory::read(inpBuffer, dwOffset, ulFileSize); - } - } #endif diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index f05851a7b..0e7261537 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -47,10 +47,12 @@ enum PELIB_COMPARE_RESULT : std::uint32_t }; typedef bool (_cdecl * PFN_VERIFY_ADDRESS)(void * ptr, size_t length); +typedef bool (_cdecl * PFN_COMPARE_CALLBACK)(size_t BytesCompared, size_t BytesTotal); struct PELIB_IMAGE_COMPARE { PFN_VERIFY_ADDRESS PfnVerifyAddress; // Custom function for verifying memory address + PFN_COMPARE_CALLBACK PfnCompareCallback; // Custom function for calling compare callback PELIB_COMPARE_RESULT compareResult; const char * dumpIfNotEqual; // If non-NULL, the image will be dumped into that file std::uint32_t differenceOffset; @@ -123,7 +125,7 @@ class ImageLoader ~ImageLoader(); int Load(std::vector & fileData, bool loadHeadersOnly = false); - int Load(std::ifstream & fs, std::streamoff fileOffset = 0, bool loadHeadersOnly = false); + int Load(std::istream & fs, std::streamoff fileOffset = 0, bool loadHeadersOnly = false); int Load(const char * fileName, bool loadHeadersOnly = false); bool relocateImage(std::uint64_t newImageBase); @@ -131,13 +133,26 @@ class ImageLoader std::uint32_t readImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead); std::uint32_t writeImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead); + std::uint32_t readString(std::string & str, std::uint32_t rva, std::uint32_t maxLength = 65535); + std::uint32_t stringLength(std::uint32_t rva, std::uint32_t maxLength = 65535) const; + + std::uint32_t readPointer(std::uint32_t rva, std::uint64_t & pointerValue); + std::uint32_t pointerSize() const; + std::uint32_t dumpImage(const char * fileName); - std::uint64_t getImageBase(); - std::uint32_t getSizeOfImage(); - std::uint32_t getSizeOfImageAligned(); - std::uint32_t getFileOffsetFromRva(std::uint32_t rva); - std::uint32_t getImageProtection(std::uint32_t characteristics); + std::uint32_t getPeFileBitability() const; + std::uint32_t getNtSignature() const; + std::uint32_t getPointerToSymbolTable() const; + std::uint32_t getNumberOfSymbols() const; + std::uint64_t getImageBase() const; + std::uint32_t getSizeOfHeaders() const; + std::uint32_t getSizeOfImage() const; + std::uint32_t getSizeOfImageAligned() const; + std::uint32_t getDataDirRva(std::size_t dataDirIndex) const; + std::uint32_t getDataDirSize(std::size_t dataDirIndex) const; + std::uint32_t getFileOffsetFromRva(std::uint32_t rva) const; + std::uint32_t getImageProtection(std::uint32_t characteristics) const; int setLoaderError(LoaderError ldrErr); LoaderError loaderError(); @@ -163,6 +178,9 @@ class ImageLoader int captureOptionalHeader32(std::uint8_t * filePtr, std::uint8_t * fileEnd); int captureOptionalHeader64(std::uint8_t * filePtr, std::uint8_t * fileEnd); + int verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_t fileSize); + int verifyDosHeader(std::istream & fs, std::streamoff fileOffset, std::size_t fileSize); + int loadImageAsIs(std::vector & fileData); std::size_t getMismatchOffset(void * buffer1, void * buffer2, std::uint32_t rva, std::size_t length); @@ -184,25 +202,26 @@ class ImageLoader bool checkForBadAppContainer(); bool isImageMappedOk(); - std::uint32_t AlignToSize(std::uint32_t ByteSize, std::uint32_t AlignSize) + static std::uint32_t AlignToSize(std::uint32_t ByteSize, std::uint32_t AlignSize) { return ((ByteSize + (AlignSize - 1)) & ~(AlignSize - 1)); } - std::uint32_t BytesToPages(std::uint32_t ByteSize) + static std::uint32_t BytesToPages(std::uint32_t ByteSize) { return (ByteSize >> PELIB_PAGE_SIZE_SHIFT) + ((ByteSize & (PELIB_PAGE_SIZE - 1)) != 0); } static uint8_t ImageProtectionArray[16]; - - std::vector sections; // Vector of headers + + std::vector sections; // Vector of section headers std::vector pages; // PE file pages as if mapped std::vector imageAsIs; // Loaded content of the image in case it couldn't have been mapped PELIB_IMAGE_DOS_HEADER dosHeader; // Loaded DOS header PELIB_IMAGE_FILE_HEADER fileHeader; // Loaded NT file header PELIB_IMAGE_OPTIONAL_HEADER optionalHeader; // 32/64-bit optional header LoaderError ldrError; + std::uint32_t ntSignature; std::uint32_t loaderMode; std::uint32_t maxSectionCount; bool ntHeadersSizeCheck; // If true, the loader requires minimum size of NT headers diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index f238c8314..ab53b0d21 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -36,27 +36,30 @@ namespace PeLib * \todo Adding functions by ordinal doesn't work yet (rebuild needs to be changed). * \todo Somehow store the rvas of the chunks in the file. **/ - template + class ImportDirectory { - typedef typename FieldSizes::VAR4_8 VAR4_8; - typedef typename std::vector >::iterator ImpDirFileIterator; - typedef typename std::vector >::const_iterator ConstImpDirFileIterator; + typedef typename std::vector::iterator ImpDirFileIterator; + typedef typename std::vector::const_iterator ConstImpDirFileIterator; private: /// Stores information about already imported DLLs. - std::vector > m_vOldiid; + std::vector m_vOldiid; /// Stores information about imported DLLs which will be added. - std::vector > m_vNewiid; + std::vector m_vNewiid; /// Stores RVAs which are occupied by this import directory. std::vector> m_occupiedAddresses; + /// Mask for file ordinal + std::uint64_t m_ordinalMask; /// Error detected by the import table parser LoaderError m_ldrError; + /// size of single thunk item + std::size_t m_thunkSize; // I can't convince Borland C++ to compile the function outside of the class declaration. // That's why the function definition is here. /// Tests if a certain function is imported. - template bool hasFunction(std::string strFilename, T value, bool(PELIB_THUNK_DATA::* comp)(T) const) const + template bool hasFunction(std::string strFilename, T value, bool(PELIB_THUNK_DATA::* comp)(T) const) const { ConstImpDirFileIterator FileIter = m_vOldiid.begin(); ConstImpDirFileIterator EndIter = m_vOldiid.end(); @@ -98,10 +101,13 @@ namespace PeLib /// Constructor ImportDirectory() : m_ldrError(LDR_ERROR_NONE) - {} + { + m_ordinalMask = 0x80000000; + m_thunkSize = 4; + } /// Add a function to the import directory. - int addFunction(const std::string& strFilename, word wHint); // EXPORT _byHint + int addFunction(const std::string& strFilename, std::uint16_t wHint); // EXPORT _byHint /// Add a function to the import directory. int addFunction(const std::string& strFilename, const std::string& strFuncname); // EXPORT _byName @@ -111,77 +117,77 @@ namespace PeLib unsigned int getFunctionIndex(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const; // EXPORT /// Get the name of an imported file. - std::string getFileName(dword dwFilenr, currdir cdDir) const; // EXPORT + std::string getFileName(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT - void setFileName(dword filenr, currdir dir, const std::string& name); // EXPORT + void setFileName(std::uint32_t filenr, currdir cdDir, const std::string& name); // EXPORT /// Retrieve the loader error LoaderError loaderError() const; void setLoaderError(LoaderError ldrError); /// Get the hint of an imported function. - word getFunctionHint(dword dwFilenr, dword dwFuncnr, currdir cdDir) const; // EXPORT - void setFunctionHint(dword dwFilenr, dword dwFuncnr, currdir cdDir, word value); // EXPORT + std::uint16_t getFunctionHint(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT + void setFunctionHint(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint16_t value); // EXPORT /// Get the name of an imported function. - std::string getFunctionName(dword dwFilenr, dword dwFuncnr, currdir cdDir) const; // EXPORT - void setFunctionName(dword dwFilenr, dword dwFuncnr, currdir cdDir, const std::string& functionName); // EXPORT + std::string getFunctionName(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT + void setFunctionName(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, const std::string& functionName); // EXPORT /// Get the number of files which are imported. - dword getNumberOfFiles(currdir cdDir) const; // EXPORT + std::uint32_t getNumberOfFiles(currdir cdDir) const; // EXPORT /// Get the number of fucntions which are imported by a specific file. - dword getNumberOfFunctions(dword dwFilenr, currdir cdDir) const; // EXPORT + std::uint32_t getNumberOfFunctions(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT /// Read a file's import directory. - int read(std::istream& inStream, const PeHeaderT& peHeader); // EXPORT + int read(ImageLoader & imageLoader); // EXPORT /// Rebuild the import directory. - void rebuild(std::vector& vBuffer, dword dwRva, bool fixEntries = true); // EXPORT + void rebuild(std::vector& vBuffer, std::uint32_t dwRva, bool fixEntries = true); // EXPORT /// Remove a file from the import directory. int removeFile(const std::string& strFilename); // EXPORT /// Remove a function from the import directory. int removeFunction(const std::string& strFilename, const std::string& strFuncname); // EXPORT _byName /// Remove a function from the import directory. - int removeFunction(const std::string& strFilename, word wHint); // EXPORT _byHint + int removeFunction(const std::string& strFilename, std::uint16_t wHint); // EXPORT _byHint /// Returns the size of the current import directory. unsigned int size() const; // EXPORT /// Writes the import directory to a file. int write(const std::string& strFilename, unsigned int uiOffset, unsigned int uiRva); // EXPORT /// Returns the FirstThunk value of a function. - VAR4_8 getFirstThunk(dword dwFilenr, dword dwFuncnr, currdir cdDir) const; // EXPORT _byNumber - void setFirstThunk(dword dwFilenr, dword dwFuncnr, currdir cdDir, VAR4_8 value); // EXPORT _byNumber + std::uint32_t getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber + void setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber /// Returns the OriginalFirstThunk value of a function. - VAR4_8 getOriginalFirstThunk(dword dwFilenr, dword dwFuncnr, currdir cdDir) const; // EXPORT _byNumber - void setOriginalFirstThunk(dword dwFilenr, dword dwFuncnr, currdir cdDir, VAR4_8 value); // EXPORT + std::uint32_t getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber + void setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value); // EXPORT -// dword getFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); -// dword getOriginalFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); +// std::uint32_t getFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); +// std::uint32_t getOriginalFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); /// Returns the FirstThunk value of a file. - dword getFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName + std::uint32_t getFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the OriginalFirstThunk value of a file. - dword getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName + std::uint32_t getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the ForwarderChain value of a file. - dword getForwarderChain(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName - dword getRvaOfName(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName + std::uint32_t getForwarderChain(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName + std::uint32_t getRvaOfName(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the TimeDateStamp value of a file. - dword getTimeDateStamp(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName + std::uint32_t getTimeDateStamp(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the FirstThunk value of a file. - dword getFirstThunk(dword dwFilenr, currdir cdDir) const; // EXPORT - void setFirstThunk(dword dwFilenr, currdir cdDir, dword value); // EXPORT _byNumber_function + std::uint32_t getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT + void setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber_function /// Returns the OriginalFirstThunk value of a file. - dword getOriginalFirstThunk(dword dwFilenr, currdir cdDir) const; // EXPORT - void setOriginalFirstThunk(dword dwFilenr, currdir cdDir, dword value); // EXPORT _byNumber_function + std::uint32_t getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT + void setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber_function /// Returns the ForwarderChain value of a file. - dword getForwarderChain(dword dwFilenr, currdir cdDir) const; // EXPORT _byNumber - void setForwarderChain(dword dwFilenr, currdir cdDir, dword value); // EXPORT _byNumber_function - dword getRvaOfName(dword dwFilenr, currdir cdDir) const; // EXPORT _byNumber - void setRvaOfName(dword dwFilenr, currdir cdDir, dword value); // EXPORT + std::uint32_t getForwarderChain(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT _byNumber + void setForwarderChain(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber_function + std::uint32_t getRvaOfName(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT _byNumber + void setRvaOfName(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT /// Returns the TimeDateStamp value of a file. - dword getTimeDateStamp(dword dwFilenr, currdir cdDir) const; // EXPORT - void setTimeDateStamp(dword dwFilenr, currdir cdDir, dword value); // EXPORT _byNumber + std::uint32_t getTimeDateStamp(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT + void setTimeDateStamp(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber const std::vector>& getOccupiedAddresses() const; -// word getFunctionHint(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); +// std::uint16_t getFunctionHint(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); }; /** @@ -193,12 +199,10 @@ namespace PeLib * * @return True if valid, otherwise false. */ - template - bool hasValidOriginalFirstThunk(const PELIB_IMAGE_IMPORT_DESCRIPTOR& impDesc, const PeHeaderT& peHeader) + + inline bool hasValidOriginalFirstThunk(const PELIB_IMAGE_IMPORT_DESCRIPTOR& impDesc, const ImageLoader & imageLoader) { - // This check for file alignment is little bit hacky, but we have no other way to know whether OriginalFirstThunk points to valid data. - // If it points to the value lower than file alignment, it points PE header and that should not be correct. - return (impDesc.OriginalFirstThunk >= peHeader.getFileAlignment()) && (peHeader.rvaToOffset(impDesc.OriginalFirstThunk) != -1); + return (imageLoader.getSizeOfHeaders() <= impDesc.OriginalFirstThunk && impDesc.OriginalFirstThunk < imageLoader.getSizeOfImage()); } /** @@ -208,10 +212,10 @@ namespace PeLib * @param strFilename The name of a DLL. * @param wHint The ordinal of the function in the DLL. **/ - template - int ImportDirectory::addFunction(const std::string& strFilename, word wHint) + inline + int ImportDirectory::addFunction(const std::string& strFilename, std::uint16_t wHint) { - if (hasFunction(strFilename, wHint, &PELIB_THUNK_DATA::equalHint)) + if (hasFunction(strFilename, wHint, &PELIB_THUNK_DATA::equalHint)) { return ERROR_DUPLICATE_ENTRY; } @@ -223,10 +227,10 @@ namespace PeLib [&](const auto& i) { return i == strFilename; } ); - PELIB_IMAGE_IMPORT_DIRECTORY iid; - PELIB_THUNK_DATA td; + PELIB_IMAGE_IMPORT_DIRECTORY iid; + PELIB_THUNK_DATA td; td.hint = wHint; - td.itd.Ordinal = wHint | PELIB_IMAGE_ORDINAL_FLAGS::PELIB_IMAGE_ORDINAL_FLAG; + td.itd.Ordinal = wHint /* | PELIB_IMAGE_ORDINAL_FLAGS::PELIB_IMAGE_ORDINAL_FLAG */; iid.name = strFilename; if (FileIter == m_vNewiid.end()) { @@ -248,10 +252,10 @@ namespace PeLib * @param strFilename Name of the file which will be imported * @param strFuncname Name of the function which will be imported. **/ - template - int ImportDirectory::addFunction(const std::string& strFilename, const std::string& strFuncname) + inline + int ImportDirectory::addFunction(const std::string& strFilename, const std::string& strFuncname) { - if (hasFunction(strFilename, strFuncname, &PELIB_THUNK_DATA::equalFunctionName)) + if (hasFunction(strFilename, strFuncname, &PELIB_THUNK_DATA::equalFunctionName)) { return ERROR_DUPLICATE_ENTRY; } @@ -263,8 +267,8 @@ namespace PeLib [&](const auto& i) { return i == strFilename; } ); - PELIB_IMAGE_IMPORT_DIRECTORY iid; - PELIB_THUNK_DATA td; + PELIB_IMAGE_IMPORT_DIRECTORY iid; + PELIB_THUNK_DATA td; td.fname = strFuncname; iid.name = strFilename; if (FileIter == m_vNewiid.end()) @@ -289,10 +293,10 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return The ID of an imported file. **/ - template - unsigned int ImportDirectory::getFileIndex(const std::string& strFilename, currdir cdDir) const + inline + unsigned int ImportDirectory::getFileIndex(const std::string& strFilename, currdir cdDir) const { - const std::vector >* currDir; + const std::vector* currDir; if (cdDir == OLDDIR) { @@ -329,8 +333,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return ID of the imported function. **/ - template - unsigned int ImportDirectory::getFunctionIndex(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const + inline + unsigned int ImportDirectory::getFunctionIndex(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const { unsigned int uiFile = getFileIndex(strFilename, cdDir); @@ -348,17 +352,17 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return Name of an imported file. **/ - template - std::string ImportDirectory::getFileName(dword dwFilenr, currdir cdDir) const + inline + std::string ImportDirectory::getFileName(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) return m_vOldiid[dwFilenr].name; else return m_vNewiid[dwFilenr].name; } - template - void ImportDirectory::setFileName(dword filenr, currdir dir, const std::string& name) + inline + void ImportDirectory::setFileName(std::uint32_t filenr, currdir cdDir, const std::string& name) { - if (dir == OLDDIR) m_vOldiid[filenr].name = name; + if (cdDir == OLDDIR) m_vOldiid[filenr].name = name; else m_vNewiid[filenr].name = name; } @@ -370,8 +374,8 @@ namespace PeLib * @return Name of an imported function. * \todo Marked line is unsafe (function should be rewritten). **/ - template - std::string ImportDirectory::getFunctionName(dword dwFilenr, dword dwFuncnr, currdir cdDir) const + inline + std::string ImportDirectory::getFunctionName(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -399,8 +403,8 @@ namespace PeLib } } - template - void ImportDirectory::setFunctionName(dword dwFilenr, dword dwFuncnr, currdir cdDir, const std::string& functionName) + inline + void ImportDirectory::setFunctionName(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, const std::string& functionName) { if (cdDir == OLDDIR) { @@ -430,14 +434,14 @@ namespace PeLib /** * Get the error that was detected during import table parsing **/ - template - LoaderError ImportDirectory::loaderError() const + inline + LoaderError ImportDirectory::loaderError() const { return m_ldrError; } - template - void ImportDirectory::setLoaderError(LoaderError ldrError) + inline + void ImportDirectory::setLoaderError(LoaderError ldrError) { // Do not override an existing loader error if (m_ldrError == LDR_ERROR_NONE) @@ -453,8 +457,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return Hint of an imported function. **/ - template - word ImportDirectory::getFunctionHint(dword dwFilenr, dword dwFuncnr, currdir cdDir) const + inline + std::uint16_t ImportDirectory::getFunctionHint(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -471,8 +475,8 @@ namespace PeLib else return m_vNewiid[dwFilenr].originalfirstthunk[dwFuncnr].hint; } - template - void ImportDirectory::setFunctionHint(dword dwFilenr, dword dwFuncnr, currdir cdDir, word value) + inline + void ImportDirectory::setFunctionHint(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint16_t value) { if (cdDir == OLDDIR) { @@ -493,11 +497,11 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return Number of files which are currently being imported. **/ - template - dword ImportDirectory::getNumberOfFiles(currdir cdDir) const + inline + std::uint32_t ImportDirectory::getNumberOfFiles(currdir cdDir) const { - if (cdDir == OLDDIR) return static_cast(m_vOldiid.size()); - else return static_cast(m_vNewiid.size()); + if (cdDir == OLDDIR) return static_cast(m_vOldiid.size()); + else return static_cast(m_vNewiid.size()); } /** @@ -506,8 +510,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return Number of functions which are currently being imported from a specific file. **/ - template - dword ImportDirectory::getNumberOfFunctions(dword dwFilenr, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getNumberOfFunctions(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) return static_cast(m_vOldiid[dwFilenr].firstthunk.size()); else return static_cast(m_vNewiid[dwFilenr].firstthunk.size()); @@ -519,84 +523,48 @@ namespace PeLib * @param inStream Input stream. * @param peHeader A valid PE header. **/ - template - int ImportDirectory::read( - std::istream& inStream, - const PeHeaderT& peHeader) + inline + int ImportDirectory::read(ImageLoader & imageLoader) { - IStreamWrapper inStream_w(inStream); - - VAR4_8 OrdinalMask = ((VAR4_8)1 << (bits - 1)); - VAR4_8 SizeOfImage = peHeader.getSizeOfImage(); - dword uiIndex; + std::uint64_t OrdinalMask = ((std::uint64_t)1 << (imageLoader.getPeFileBitability() - 1)); + std::uint32_t SizeOfImage = imageLoader.getSizeOfImage(); + std::uint32_t uiIndex; + std::uint32_t rvaBegin = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT); + std::uint32_t rva = rvaBegin; + m_thunkSize = imageLoader.getPeFileBitability() / 8; m_ldrError = LDR_ERROR_NONE; - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - if(peHeader.getIddImportRva() > peHeader.getSizeOfImage()) + // Verify whether the import directory is within the image + if(rva > SizeOfImage) { setLoaderError(LDR_ERROR_IMPDIR_OUT_OF_FILE); return ERROR_INVALID_FILE; } - std::uint64_t ulFileSize = fileSize(inStream_w); - unsigned int uiRva = peHeader.getIddImportRva(); - unsigned int uiOffset = (unsigned int)peHeader.rvaToOffset(uiRva); - - if ((uiOffset + PELIB_IMAGE_IMPORT_DESCRIPTOR::size()) > ulFileSize) - { - setLoaderError(LDR_ERROR_IMPDIR_OUT_OF_FILE); - return ERROR_INVALID_FILE; - } - - inStream_w.seekg(uiOffset, std::ios_base::beg); - - PELIB_IMAGE_IMPORT_DIRECTORY iidCurr; - std::vector > vOldIidCurr; - unsigned int uiDescCounter = 0; - unsigned int uiDescOffset = uiOffset; - // For tracking unique imported DLLs + std::vector vOldIidCurr; std::unordered_map uniqueDllList; + std::uint32_t uiDescCounter = 0; // Read and store all descriptors for (;;) { - std::vector vImportDescriptor(PELIB_IMAGE_IMPORT_DESCRIPTOR::size()); + PELIB_IMAGE_IMPORT_DIRECTORY iidCurr; // If the required range is within the file, then we read the data. // If not, it's RVA may still be valid due mapping -> keep zeros. // Example sample: de0dea00414015bacbcbfc1fa53af9f6731522687d82f5de2e9402410488d190 // (single entry in the import directory at file offset 0x3EC4 followed by end-of-file) - if ((uiDescOffset + PELIB_IMAGE_IMPORT_DESCRIPTOR::size()) <= ulFileSize) - { - // The offset is within the file range -> read it from the file - inStream_w.read(reinterpret_cast(vImportDescriptor.data()), PELIB_IMAGE_IMPORT_DESCRIPTOR::size()); - } - else + if ((rva + sizeof(PELIB_IMAGE_IMPORT_DESCRIPTOR)) >= SizeOfImage) { - // The offset is out of physical file -> is the RVA still valid? - if (!peHeader.isValidRva(uiRva + PELIB_IMAGE_IMPORT_DESCRIPTOR::size())) - { - setLoaderError(LDR_ERROR_IMPDIR_CUT); - break; - } + setLoaderError(LDR_ERROR_IMPDIR_CUT); + break; } - InputBuffer inpBuffer(vImportDescriptor); - - inpBuffer >> iidCurr.impdesc.OriginalFirstThunk; - inpBuffer >> iidCurr.impdesc.TimeDateStamp; - inpBuffer >> iidCurr.impdesc.ForwarderChain; - inpBuffer >> iidCurr.impdesc.Name; - inpBuffer >> iidCurr.impdesc.FirstThunk; - - uiDescOffset += PELIB_IMAGE_IMPORT_DESCRIPTOR::size(); - uiRva += PELIB_IMAGE_IMPORT_DESCRIPTOR::size(); + // The offset is within the file range -> read it from the image + imageLoader.readImage(&iidCurr.impdesc, rva, sizeof(PELIB_IMAGE_IMPORT_DESCRIPTOR)); + rva += sizeof(PELIB_IMAGE_IMPORT_DESCRIPTOR); uiDescCounter++; // If Name or FirstThunk are 0, this descriptor is considered as null-terminator. @@ -604,7 +572,7 @@ namespace PeLib break; // We ignore import names that go beyond the file - if (iidCurr.impdesc.Name > SizeOfImage || !peHeader.isValidRva(iidCurr.impdesc.Name)) + if (iidCurr.impdesc.Name > SizeOfImage) { setLoaderError(LDR_ERROR_IMPDIR_NAME_RVA_INVALID); break; @@ -616,8 +584,8 @@ namespace PeLib break; } - // Retrieve the import name string from the image - getStringFromFileOffset(inStream_w, iidCurr.name, peHeader.rvaToOffset(iidCurr.impdesc.Name), IMPORT_LIBRARY_MAX_LENGTH); + // Retrieve the library name from the image as ASCIIZ string + imageLoader.readString(iidCurr.name, iidCurr.impdesc.Name); // Ignore too large import directories // Sample: CCE461B6EB23728BA3B8A97B9BE84C0FB9175DB31B9949E64144198AB3F702CE, # of impdesc 0x6253 (invalid) @@ -647,29 +615,23 @@ namespace PeLib } // Space occupied by import descriptors - m_occupiedAddresses.emplace_back(peHeader.getIddImportRva(), peHeader.getIddImportRva() + (uiDescOffset - uiOffset - 1)); + m_occupiedAddresses.emplace_back(rvaBegin, rva); // OriginalFirstThunk - ILT - for (unsigned int i=0;i tdCurr; - dword uiVaoft = vOldIidCurr[i].impdesc.OriginalFirstThunk; - - inStream_w.clear(); - inStream_w.seekg(static_cast(peHeader.rvaToOffset(uiVaoft)), std::ios_base::beg); + PELIB_THUNK_DATA tdCurr; for(uiIndex = 0; ; uiIndex++) { - if (ulFileSize < peHeader.rvaToOffset(uiVaoft) + sizeof(tdCurr.itd.Ordinal)) - { - return ERROR_INVALID_FILE; - } - uiVaoft += sizeof(tdCurr.itd.Ordinal); - - inStream_w.read(reinterpret_cast(&tdCurr.itd.Ordinal), sizeof(tdCurr.itd.Ordinal)); + // Read single value (32-bit or 64-bit) from the thunk chain + if(!imageLoader.readPointer(thunkRva, tdCurr.itd.Ordinal)) + break; // Are we at the end of the list? if (tdCurr.itd.Ordinal == 0) @@ -692,48 +654,45 @@ namespace PeLib // Insert ordinal to the list vOldIidCurr[i].originalfirstthunk.push_back(tdCurr); + thunkRva += m_thunkSize; } // Space occupied by OriginalFirstThunks // -1 because we need open interval - if (vOldIidCurr[i].impdesc.OriginalFirstThunk < uiVaoft) - m_occupiedAddresses.emplace_back(vOldIidCurr[i].impdesc.OriginalFirstThunk, uiVaoft - 1); + if (vOldIidCurr[i].impdesc.OriginalFirstThunk < thunkRva) + m_occupiedAddresses.emplace_back(vOldIidCurr[i].impdesc.OriginalFirstThunk, thunkRva - 1); } // FirstThunk - IAT - std::set seenOffsets; - for (unsigned int i=0;i seenOffsets; + for (std::size_t i = 0; i < vOldIidCurr.size(); i++) { - bool hasValidIlt = hasValidOriginalFirstThunk(vOldIidCurr[i].impdesc, peHeader); + std::uint32_t thunkRva = vOldIidCurr[i].impdesc.FirstThunk; + bool hasValidIlt = hasValidOriginalFirstThunk(vOldIidCurr[i].impdesc, imageLoader); - dword uiVaoft = vOldIidCurr[i].impdesc.FirstThunk; - if (!peHeader.isValidRva(uiVaoft)) + if (thunkRva >= imageLoader.getSizeOfImage()) { return ERROR_INVALID_FILE; } - if (seenOffsets.count(uiVaoft)) + if (seenOffsets.count(thunkRva)) { continue; } - seenOffsets.insert(uiVaoft); - PELIB_THUNK_DATA tdCurr; - - inStream_w.clear(); - inStream_w.seekg(static_cast(peHeader.rvaToOffset(uiVaoft)), std::ios_base::beg); + seenOffsets.insert(thunkRva); + PELIB_THUNK_DATA tdCurr; for(uiIndex = 0; ; uiIndex++) { - if (ulFileSize < peHeader.rvaToOffset(uiVaoft) + sizeof(tdCurr.itd.Ordinal)) + if ((thunkRva + m_thunkSize) > SizeOfImage) { setLoaderError(LDR_ERROR_IMPDIR_THUNK_RVA_INVALID); return ERROR_INVALID_FILE; } - uiVaoft += sizeof(tdCurr.itd.Ordinal); - // Read the import thunk. Make sure it's initialized in case the file read fails tdCurr.itd.Ordinal = 0; - inStream_w.read(reinterpret_cast(&tdCurr.itd.Ordinal), sizeof(tdCurr.itd.Ordinal)); + imageLoader.readPointer(thunkRva, tdCurr.itd.Ordinal); + thunkRva += m_thunkSize; // Are we at the end of the list? if (tdCurr.itd.Ordinal == 0) @@ -748,8 +707,8 @@ namespace PeLib // Check samples that have import name out of the image // Sample: CCE461B6EB23728BA3B8A97B9BE84C0FB9175DB31B9949E64144198AB3F702CE -// if ((tdCurr.itd.Ordinal & OrdinalMask) == 0 && (tdCurr.itd.Ordinal >= SizeOfImage)) -// break; + // if ((tdCurr.itd.Ordinal & OrdinalMask) == 0 && (tdCurr.itd.Ordinal >= SizeOfImage)) + // break; vOldIidCurr[i].firstthunk.push_back(tdCurr); @@ -757,88 +716,48 @@ namespace PeLib if (hasValidIlt && vOldIidCurr[i].originalfirstthunk.size() == vOldIidCurr[i].firstthunk.size()) { // We need to move this offset in this case because otherwise we would calculate the occupied addresses wrongly - uiVaoft += sizeof(tdCurr.itd.Ordinal); + thunkRva += m_thunkSize; break; } } // Space occupied by FirstThunks // -1 because we need open interval - if (vOldIidCurr[i].impdesc.FirstThunk < uiVaoft) - m_occupiedAddresses.emplace_back(vOldIidCurr[i].impdesc.FirstThunk, uiVaoft - 1); + if (vOldIidCurr[i].impdesc.FirstThunk < thunkRva) + m_occupiedAddresses.emplace_back(vOldIidCurr[i].impdesc.FirstThunk, thunkRva - 1); } // Names for (unsigned int i=0;i & thunkVector = hasValidOriginalFirstThunk(vOldIidCurr[i].impdesc, imageLoader) ? + vOldIidCurr[i].originalfirstthunk : + vOldIidCurr[i].firstthunk; + for (auto & thunkData : thunkVector) { - for (unsigned int j=0;j::PELIB_IMAGE_ORDINAL_FLAG) - { - vOldIidCurr[i].originalfirstthunk[j].hint = 0; - continue; - } - - inStream_w.seekg(static_cast(peHeader.rvaToOffset(vOldIidCurr[i].originalfirstthunk[j].itd.Ordinal)), std::ios_base::beg); - - inStream_w.read(reinterpret_cast(&vOldIidCurr[i].originalfirstthunk[j].hint), sizeof(vOldIidCurr[i].originalfirstthunk[j].hint)); - - if (!inStream_w) - return ERROR_INVALID_FILE; - - getStringFromFileOffset( - inStream_w, - vOldIidCurr[i].originalfirstthunk[j].fname, - inStream_w.tellg(), - IMPORT_SYMBOL_MAX_LENGTH); - - // Space occupied by names - // +1 for null terminator - // If the end address is even, we need to align it by 2, so next name always starts at even address - m_occupiedAddresses.emplace_back( - static_cast(vOldIidCurr[i].originalfirstthunk[j].itd.Ordinal), - static_cast(vOldIidCurr[i].originalfirstthunk[j].itd.Ordinal + sizeof(vOldIidCurr[i].originalfirstthunk[j].hint) + vOldIidCurr[i].originalfirstthunk[j].fname.length() + 1) - ); - if (!(m_occupiedAddresses.back().second & 1)) - m_occupiedAddresses.back().second += 1; + thunkData.hint = 0; + continue; } - } - else - { - for (unsigned int j=0;j::PELIB_IMAGE_ORDINAL_FLAG) - { - continue; - } - - inStream_w.seekg(static_cast(peHeader.rvaToOffset(vOldIidCurr[i].firstthunk[j].itd.Ordinal)), std::ios_base::beg); - inStream_w.read(reinterpret_cast(&vOldIidCurr[i].firstthunk[j].hint), sizeof(vOldIidCurr[i].firstthunk[j].hint)); - - if (!inStream_w) - return ERROR_INVALID_FILE; + if(imageLoader.readImage(&thunkData.hint, thunkData.itd.Ordinal, sizeof(std::uint16_t)) != sizeof(std::uint16_t)) + return ERROR_INVALID_FILE; - getStringFromFileOffset( - inStream_w, - vOldIidCurr[i].firstthunk[j].fname, - inStream_w.tellg(), - IMPORT_SYMBOL_MAX_LENGTH); + imageLoader.readString(thunkData.fname, thunkData.itd.Ordinal + sizeof(std::uint16_t), IMPORT_SYMBOL_MAX_LENGTH); - // Space occupied by names - // +1 for null terminator - // If the end address is even, we need to align it by 2, so next name always starts at even address - m_occupiedAddresses.emplace_back( - static_cast(vOldIidCurr[i].firstthunk[j].itd.Ordinal), - static_cast(vOldIidCurr[i].firstthunk[j].itd.Ordinal + sizeof(vOldIidCurr[i].firstthunk[j].hint) + vOldIidCurr[i].firstthunk[j].fname.length() + 1) - ); - if (!(m_occupiedAddresses.back().second & 1)) - m_occupiedAddresses.back().second += 1; - } + // Space occupied by names + // +1 for null terminator + // If the end address is even, we need to align it by 2, so next name always starts at even address + m_occupiedAddresses.emplace_back( + static_cast(thunkData.itd.Ordinal), + static_cast(thunkData.itd.Ordinal + sizeof(thunkData.hint) + thunkData.fname.length() + 1) + ); + if (!(m_occupiedAddresses.back().second & 1)) + m_occupiedAddresses.back().second += 1; } } + std::swap(vOldIidCurr, m_vOldiid); return ERROR_NONE; } @@ -850,8 +769,8 @@ namespace PeLib * @param fixEntries Boolean flag. * \todo uiSizeoffuncnames is not used. **/ - template - void ImportDirectory::rebuild(std::vector& vBuffer, dword dwRva, bool fixEntries) + inline + void ImportDirectory::rebuild(std::vector& vBuffer, std::uint32_t dwRva, bool fixEntries) { unsigned int uiImprva = dwRva; unsigned int uiSizeofdescriptors = (static_cast(m_vNewiid.size() + m_vOldiid.size()) + 1) * PELIB_IMAGE_IMPORT_DESCRIPTOR::size(); @@ -862,18 +781,18 @@ namespace PeLib for (unsigned int i=0;i(m_vNewiid[i].name.size()) + 1; - uiSizeofoft += (static_cast(m_vNewiid[i].originalfirstthunk.size())+1) * PELIB_IMAGE_THUNK_DATA::size(); + uiSizeofoft += (static_cast(m_vNewiid[i].originalfirstthunk.size())+1) * m_thunkSize; for(unsigned int j=0;j(m_vNewiid[i].originalfirstthunk[j].fname.size()) + 3); } } // for (unsigned int i=0;i(m_vNewiid[i].originalfirstthunk.size())+1) * PELIB_IMAGE_THUNK_DATA::size(); +// uiSizeofoft += (static_cast(m_vNewiid[i].originalfirstthunk.size())+1) * PELIB_IMAGE_THUNK_DATA::size(); // } OutputBuffer obBuffer(vBuffer); @@ -892,17 +811,17 @@ namespace PeLib for (unsigned int i=0;i(m_vNewiid[j-1].originalfirstthunk.size()) + 1) * PELIB_IMAGE_THUNK_DATA::size(); + dwPoft += (static_cast(m_vNewiid[j-1].originalfirstthunk.size()) + 1) * m_thunkSize; } obBuffer << (fixEntries ? dwPoft : m_vNewiid[i].impdesc.OriginalFirstThunk); obBuffer << m_vNewiid[i].impdesc.TimeDateStamp; obBuffer << m_vNewiid[i].impdesc.ForwarderChain; - dword dwPdll = uiSizeofdescriptors + uiSizeofoft + uiImprva + dllsize; + std::uint32_t dwPdll = uiSizeofdescriptors + uiSizeofoft + uiImprva + dllsize; obBuffer << (fixEntries ? dwPdll : m_vNewiid[i].impdesc.Name); obBuffer << m_vNewiid[i].impdesc.FirstThunk; @@ -916,20 +835,20 @@ namespace PeLib dllsize += static_cast(m_vNewiid[i].name.size()) + 1; } - obBuffer << static_cast(0); - obBuffer << static_cast(0); - obBuffer << static_cast(0); - obBuffer << static_cast(0); - obBuffer << static_cast(0); + obBuffer << static_cast(0); + obBuffer << static_cast(0); + obBuffer << static_cast(0); + obBuffer << static_cast(0); + obBuffer << static_cast(0); - VAR4_8 uiPfunc = uiSizeofdescriptors + uiSizeofoft + uiSizeofdllnames + uiImprva; + std::uint64_t uiPfunc = uiSizeofdescriptors + uiSizeofoft + uiSizeofdllnames + uiImprva; // Rebuild original first thunk for (unsigned int i=0;i::PELIB_IMAGE_ORDINAL_FLAG + if (m_vNewiid[i].originalfirstthunk[j].itd.Ordinal & m_ordinalMask || fixEntries == false) { obBuffer << m_vNewiid[i].originalfirstthunk[j].itd.Ordinal; @@ -940,9 +859,9 @@ namespace PeLib // store the offset in Ordinal, they cannot overlay thanks to PELIB_IMAGE_ORDINAL_FLAG m_vNewiid[i].originalfirstthunk[j].itd.Ordinal = uiPfunc; } - uiPfunc += static_cast(m_vNewiid[i].originalfirstthunk[j].fname.size()) + 3; + uiPfunc += static_cast(m_vNewiid[i].originalfirstthunk[j].fname.size()) + 3; } - obBuffer << static_cast(0); + obBuffer << static_cast(0); } // Write dllnames into import directory @@ -966,8 +885,8 @@ namespace PeLib * Removes a specific file and all functions of it from the import directory. * @param strFilename Name of the file which will be removed. **/ - template - int ImportDirectory::removeFile(const std::string& strFilename) + inline + int ImportDirectory::removeFile(const std::string& strFilename) { unsigned int oldSize = static_cast(m_vNewiid.size()); @@ -988,8 +907,8 @@ namespace PeLib * @param strFilename Name of the file which exports the function. * @param strFuncname Name of the imported function. **/ - template - int ImportDirectory::removeFunction(const std::string& strFilename, const std::string& strFuncname) + inline + int ImportDirectory::removeFunction(const std::string& strFilename, const std::string& strFuncname) { ImpDirFileIterator viPos = m_vNewiid.begin(); @@ -1021,8 +940,8 @@ namespace PeLib * @param strFilename Name of the file which exports the function. * @param wHint The hint of the function. **/ - template - int ImportDirectory::removeFunction(const std::string& strFilename, word wHint) + inline + int ImportDirectory::removeFunction(const std::string& strFilename, std::uint16_t wHint) { ImpDirFileIterator viPos = m_vNewiid.begin(); int notFound = 1; @@ -1054,8 +973,8 @@ namespace PeLib * @param uiOffset File Offset of the new import directory. * @param uiRva RVA which belongs to that file offset. **/ - template - int ImportDirectory::write(const std::string& strFilename, unsigned int uiOffset, unsigned int uiRva) + inline + int ImportDirectory::write(const std::string& strFilename, unsigned int uiOffset, unsigned int uiRva) { std::fstream ofFile(strFilename.c_str(), std::ios_base::in); @@ -1077,7 +996,7 @@ namespace PeLib ofFile.seekp(uiOffset, std::ios_base::beg); - std::vector vBuffer; + std::vector vBuffer; rebuild(vBuffer, uiRva); @@ -1094,11 +1013,11 @@ namespace PeLib * Returns the size of the import directory. * @return Size of the import directory. **/ - template - unsigned int ImportDirectory::size() const + inline + unsigned int ImportDirectory::size() const { // Only the descriptors of m_vOldiid must be rebuilt, not the data they point to. - return std::accumulate(m_vNewiid.begin(), m_vNewiid.end(), 0, accumulate >) + return std::accumulate(m_vNewiid.begin(), m_vNewiid.end(), 0, accumulate) + (m_vOldiid.size() + 1) * PELIB_IMAGE_IMPORT_DESCRIPTOR::size(); } @@ -1107,8 +1026,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return FirstThunk value of an imported file. **/ - template - dword ImportDirectory::getFirstThunk(const std::string& strFilename, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getFirstThunk(const std::string& strFilename, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1125,8 +1044,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return OriginalFirstThunk value of an imported file. **/ - template - dword ImportDirectory::getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1143,8 +1062,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return ForwarderChain value of an imported file. **/ - template - dword ImportDirectory::getForwarderChain(const std::string& strFilename, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getForwarderChain(const std::string& strFilename, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1161,8 +1080,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return TimeDateStamp value of an imported file. **/ - template - dword ImportDirectory::getTimeDateStamp(const std::string& strFilename, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getTimeDateStamp(const std::string& strFilename, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1174,8 +1093,8 @@ namespace PeLib } } - template - dword ImportDirectory::getRvaOfName(const std::string& strFilename, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getRvaOfName(const std::string& strFilename, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1192,8 +1111,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return FirstThunk value of an imported file. **/ - template - dword ImportDirectory::getFirstThunk(dword dwFilenr, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1205,8 +1124,8 @@ namespace PeLib } } - template - void ImportDirectory::setFirstThunk(dword dwFilenr, currdir cdDir, dword value) + inline + void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) { @@ -1223,8 +1142,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return OriginalFirstThunk value of an imported file. **/ - template - dword ImportDirectory::getOriginalFirstThunk(dword dwFilenr, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1236,8 +1155,8 @@ namespace PeLib } } - template - void ImportDirectory::setOriginalFirstThunk(dword dwFilenr, currdir cdDir, dword value) + inline + void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) { @@ -1254,8 +1173,9 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return ForwarderChain value of an imported file. **/ - template - dword ImportDirectory::getForwarderChain(dword dwFilenr, currdir cdDir) const + + inline + std::uint32_t ImportDirectory::getForwarderChain(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1267,8 +1187,8 @@ namespace PeLib } } - template - void ImportDirectory::setForwarderChain(dword dwFilenr, currdir cdDir, dword value) + inline + void ImportDirectory::setForwarderChain(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) { @@ -1285,8 +1205,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return TimeDateStamp value of an imported file. **/ - template - dword ImportDirectory::getTimeDateStamp(dword dwFilenr, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getTimeDateStamp(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1298,8 +1218,8 @@ namespace PeLib } } - template - void ImportDirectory::setTimeDateStamp(dword dwFilenr, currdir cdDir, dword value) + inline + void ImportDirectory::setTimeDateStamp(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) { @@ -1311,8 +1231,8 @@ namespace PeLib } } - template - dword ImportDirectory::getRvaOfName(dword dwFilenr, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getRvaOfName(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1324,8 +1244,8 @@ namespace PeLib } } - template - void ImportDirectory::setRvaOfName(dword dwFilenr, currdir cdDir, dword value) + inline + void ImportDirectory::setRvaOfName(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) { @@ -1343,15 +1263,15 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return FirstThunk value of an imported function. **/ - template - typename FieldSizes::VAR4_8 ImportDirectory::getFirstThunk(dword dwFilenr, dword dwFuncnr, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const { if (cdDir == OLDDIR) return m_vOldiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal; else return m_vNewiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal; } - template - void ImportDirectory::setFirstThunk(dword dwFilenr, dword dwFuncnr, currdir cdDir, VAR4_8 value) + inline + void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) m_vOldiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal = value; else m_vNewiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal = value; @@ -1363,8 +1283,8 @@ namespace PeLib * @param cdDir Flag to decide if the OLDDIR or new import directory is used. * @return OriginalFirstThunk value of an imported function. **/ - template - typename FieldSizes::VAR4_8 ImportDirectory::getOriginalFirstThunk(dword dwFilenr, dword dwFuncnr, currdir cdDir) const + inline + std::uint32_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1383,21 +1303,19 @@ namespace PeLib } } - template - void ImportDirectory::setOriginalFirstThunk(dword dwFilenr, dword dwFuncnr, currdir cdDir, VAR4_8 value) + inline + void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) m_vOldiid[dwFilenr].originalfirstthunk[dwFuncnr].itd.Ordinal = value; else m_vNewiid[dwFilenr].originalfirstthunk[dwFuncnr].itd.Ordinal = value; } - template - const std::vector>& ImportDirectory::getOccupiedAddresses() const + inline + const std::vector>& ImportDirectory::getOccupiedAddresses() const { return m_occupiedAddresses; } - typedef ImportDirectory<32> ImportDirectory32; - typedef ImportDirectory<64> ImportDirectory64; -} +} // namespace PeLib #endif diff --git a/include/retdec/pelib/MzHeader.h b/include/retdec/pelib/MzHeader.h index 0aca628dd..d55f54e36 100644 --- a/include/retdec/pelib/MzHeader.h +++ b/include/retdec/pelib/MzHeader.h @@ -66,13 +66,13 @@ namespace PeLib int read(unsigned char* pcBuffer, unsigned int uiSize, unsigned int originalOffs = 0); // EXPORT _fromMemory /// Rebuild the MZ header. - void rebuild(std::vector& vBuffer) const; // EXPORT + void rebuild(std::vector& vBuffer) const; // EXPORT /// Returns the size of the current MZ header. unsigned int size() const; // EXPORT /// Writes the current MZ header to offset 0 of a file. - int write(const std::string& strFilename, dword dwOffset) const; // EXPORT + int write(const std::string& strFilename, std::uint32_t dwOffset) const; // EXPORT /// Gets MZ header. const PELIB_IMAGE_DOS_HEADER& getHeader() const; // EXPORT @@ -80,82 +80,82 @@ namespace PeLib const std::string& getString() const; // EXPORT /// Gets the e_magic value of the MZ header. - word getMagicNumber() const; // EXPORT + std::uint16_t getMagicNumber() const; // EXPORT /// Gets the e_cblp value of the MZ header. - word getBytesOnLastPage() const; // EXPORT + std::uint16_t getBytesOnLastPage() const; // EXPORT /// Gets the e_cp value of the MZ header. - word getPagesInFile() const; // EXPORT + std::uint16_t getPagesInFile() const; // EXPORT /// Gets the e_crlc value of the MZ header. - word getRelocations() const; // EXPORT + std::uint16_t getRelocations() const; // EXPORT /// Gets the e_cparhdr value of the MZ header. - word getSizeOfHeader() const; // EXPORT + std::uint16_t getSizeOfHeader() const; // EXPORT /// Gets the e_minalloc value of the MZ header. - word getMinExtraParagraphs() const; // EXPORT + std::uint16_t getMinExtraParagraphs() const; // EXPORT /// Gets the e_maxalloc value of the MZ header. - word getMaxExtraParagraphs() const; // EXPORT + std::uint16_t getMaxExtraParagraphs() const; // EXPORT /// Gets the e_ss value of the MZ header. - word getSsValue() const; // EXPORT + std::uint16_t getSsValue() const; // EXPORT /// Gets the e_sp value of the MZ header. - word getSpValue() const; // EXPORT + std::uint16_t getSpValue() const; // EXPORT /// Gets the e_csum value of the MZ header. - word getChecksum() const; // EXPORT + std::uint16_t getChecksum() const; // EXPORT /// Gets the e_ip value of the MZ header. - word getIpValue() const; // EXPORT + std::uint16_t getIpValue() const; // EXPORT /// Gets the e_cs value of the MZ header. - word getCsValue() const; // EXPORT + std::uint16_t getCsValue() const; // EXPORT /// Gets the e_lfarlc value of the MZ header. - word getAddrOfRelocationTable() const; // EXPORT + std::uint16_t getAddrOfRelocationTable() const; // EXPORT /// Gets the e_ovnovalue of the MZ header. - word getOverlayNumber() const; // EXPORT + std::uint16_t getOverlayNumber() const; // EXPORT /// Gets the e_oemid value of the MZ header. - word getOemIdentifier() const; // EXPORT + std::uint16_t getOemIdentifier() const; // EXPORT /// Gets the e_oeminfo value of the MZ header. - word getOemInformation() const; // EXPORT + std::uint16_t getOemInformation() const; // EXPORT /// Gets the e_lfanew value of the MZ header. - dword getAddressOfPeHeader() const; // EXPORT + std::uint32_t getAddressOfPeHeader() const; // EXPORT /// Gets the e_res of the MZ header. - word getReservedWords1(unsigned int uiNr) const; // EXPORT + std::uint16_t getReservedWords1(unsigned int uiNr) const; // EXPORT /// Gets the e_res2 of the MZ header. - word getReservedWords2(unsigned int uiNr) const; // EXPORT + std::uint16_t getReservedWords2(unsigned int uiNr) const; // EXPORT /// Sets the e_magic value of the MZ header. - void setMagicNumber(word wValue); // EXPORT + void setMagicNumber(std::uint16_t wValue); // EXPORT /// Sets the e_cblp value of the MZ header. - void setBytesOnLastPage(word wValue); // EXPORT + void setBytesOnLastPage(std::uint16_t wValue); // EXPORT /// Sets the e_cp value of the MZ header. - void setPagesInFile(word wValue); // EXPORT + void setPagesInFile(std::uint16_t wValue); // EXPORT /// Sets the e_crlc value of the MZ header. - void setRelocations(word wValue); // EXPORT + void setRelocations(std::uint16_t wValue); // EXPORT /// Sets the e_cparhdr value of the MZ header. - void setSizeOfHeader(word wValue); // EXPORT + void setSizeOfHeader(std::uint16_t wValue); // EXPORT /// Sets the e_minalloc value of the MZ header. - void setMinExtraParagraphs(word wValue); // EXPORT + void setMinExtraParagraphs(std::uint16_t wValue); // EXPORT /// Sets the e_maxalloc value of the MZ header. - void setMaxExtraParagraphs(word wValue); // EXPORT + void setMaxExtraParagraphs(std::uint16_t wValue); // EXPORT /// Sets the e_ss value of the MZ header. - void setSsValue(word wValue); // EXPORT + void setSsValue(std::uint16_t wValue); // EXPORT /// Sets the e_sp value of the MZ header. - void setSpValue(word wValue); // EXPORT + void setSpValue(std::uint16_t wValue); // EXPORT /// Sets the e_csum value of the MZ header. - void setChecksum(word wValue); // EXPORT + void setChecksum(std::uint16_t wValue); // EXPORT /// Sets the e_ip value of the MZ header. - void setIpValue(word wValue); // EXPORT + void setIpValue(std::uint16_t wValue); // EXPORT /// Sets the e_cs value of the MZ header. - void setCsValue(word wValue); // EXPORT + void setCsValue(std::uint16_t wValue); // EXPORT /// Sets the e_lfarlc value of the MZ header. - void setAddrOfRelocationTable(word wValue); // EXPORT + void setAddrOfRelocationTable(std::uint16_t wValue); // EXPORT /// Sets the e_ovno value of the MZ header. - void setOverlayNumber(word wValue); // EXPORT + void setOverlayNumber(std::uint16_t wValue); // EXPORT /// Sets the e_oemid value of the MZ header. - void setOemIdentifier(word wValue); // EXPORT + void setOemIdentifier(std::uint16_t wValue); // EXPORT /// Sets the e_oeminfo value of the MZ header. - void setOemInformation(word wValue); // EXPORT + void setOemInformation(std::uint16_t wValue); // EXPORT /// Sets the e_lfanew value of the MZ header. - void setAddressOfPeHeader(dword dwValue); // EXPORT + void setAddressOfPeHeader(std::uint32_t dwValue); // EXPORT /// Sets the e_res value of the MZ header. - void setReservedWords1(unsigned int uiNr, word wValue); // EXPORT + void setReservedWords1(unsigned int uiNr, std::uint16_t wValue); // EXPORT /// Sets the e_res2 value of the MZ header. - void setReservedWords2(unsigned int uiNr, word wValue); // EXPORT + void setReservedWords2(unsigned int uiNr, std::uint16_t wValue); // EXPORT }; } diff --git a/include/retdec/pelib/PeFile.h b/include/retdec/pelib/PeFile.h index ca3b70985..3107fcada 100644 --- a/include/retdec/pelib/PeFile.h +++ b/include/retdec/pelib/PeFile.h @@ -16,6 +16,7 @@ #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/MzHeader.h" #include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" #include "retdec/pelib/ImportDirectory.h" #include "retdec/pelib/ExportDirectory.h" #include "retdec/pelib/BoundImportDirectory.h" @@ -85,6 +86,8 @@ namespace PeLib virtual void visit(PeFileVisitor &v) = 0; + /// Reads the basic headers needed to process the file + virtual int loadPeHeaders(ByteBuffer & fileData) = 0; /// Reads the MZ header of the current file from disc. virtual int readMzHeader() = 0; // EXPORT /// Reads the export directory of the current file from disc. @@ -110,7 +113,7 @@ namespace PeLib /// Reads rich header of the current file. virtual int readRichHeader(std::size_t offset, std::size_t size, bool ignoreInvalidKey = false) = 0; // EXPORT /// Reads the COFF symbol table of the current file. - virtual int readCoffSymbolTable() = 0; // EXPORT + virtual int readCoffSymbolTable(ByteBuffer & fileData) = 0; // EXPORT /// Reads delay import directory of the current file. virtual int readDelayImportDirectory() = 0; // EXPORT /// Reads security directory of the current file. @@ -153,17 +156,18 @@ namespace PeLib std::ifstream m_ifStream; std::istream& m_iStream; - PeHeader32_64 m_peh; ///< PE header of the current file. - ExportDirectoryT m_expdir; ///< Export directory of the current file. - ImportDirectory m_impdir; ///< Import directory of the current file. - BoundImportDirectoryT m_boundimpdir; ///< BoundImportDirectory of the current file. - ResourceDirectoryT m_resdir; ///< ResourceDirectory of the current file. - RelocationsDirectoryT m_relocs; ///< Relocations directory of the current file. - ComHeaderDirectoryT m_comdesc; ///< COM+ descriptor directory of the current file. - IatDirectoryT m_iat; ///< Import address table of the current file. - DebugDirectoryT m_debugdir; ///< Debug directory of the current file. - DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file. - TlsDirectory m_tlsdir; ///< TLS directory of the current file. + ImageLoader m_imageLoader; + PeHeader32_64 m_peh; ///< PE header of the current file. + ExportDirectoryT m_expdir; ///< Export directory of the current file. + ImportDirectory m_impdir; ///< Import directory of the current file. + BoundImportDirectoryT m_boundimpdir; ///< BoundImportDirectory of the current file. + ResourceDirectoryT m_resdir; ///< ResourceDirectory of the current file. + RelocationsDirectoryT m_relocs; ///< Relocations directory of the current file. + ComHeaderDirectoryT m_comdesc; ///< COM+ descriptor directory of the current file. + IatDirectory m_iat; ///< Import address table of the current file. + DebugDirectoryT m_debugdir; ///< Debug directory of the current file. + DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file. + TlsDirectory m_tlsdir; ///< TLS directory of the current file. public: /// Default constructor which exists only for the sake of allowing to construct files without filenames. @@ -180,6 +184,8 @@ namespace PeLib /// Changes the name of the current file. void setFileName(std::string strFilename); + /// Reads the basic headers needed to process the file + int loadPeHeaders(ByteBuffer & fileData); /// Reads the MZ header of the current file from disc. int readMzHeader() ; /// Reads the export directory of the current file from disc. @@ -205,7 +211,7 @@ namespace PeLib /// Reads rich header of the current file. int readRichHeader(std::size_t offset, std::size_t size, bool ignoreInvalidKey = false) ; /// Reads the COFF symbol table of the current file. - int readCoffSymbolTable() ; + int readCoffSymbolTable(ByteBuffer & fileData); /// Reads delay import directory of the current file. int readDelayImportDirectory() ; /// Reads the security directory of the current file. @@ -234,9 +240,9 @@ namespace PeLib ExportDirectoryT& expDir(); // EXPORT /// Accessor function for the import directory. - const ImportDirectory& impDir() const; + const ImportDirectory & impDir() const; /// Accessor function for the import directory. - ImportDirectory& impDir(); + ImportDirectory & impDir(); /// Accessor function for the bound import directory. const BoundImportDirectoryT& boundImpDir() const; @@ -259,9 +265,9 @@ namespace PeLib ComHeaderDirectoryT& comDir(); // EXPORT /// Accessor function for the IAT directory. - const IatDirectoryT& iatDir() const; + const IatDirectory & iatDir() const; /// Accessor function for the IAT directory. - IatDirectoryT& iatDir(); // EXPORT + IatDirectory & iatDir(); // EXPORT /// Accessor function for the debug directory. const DebugDirectoryT& debugDir() const; @@ -317,7 +323,7 @@ namespace PeLib **/ template PeFileT::PeFileT(const std::string& strFilename) : - m_iStream(m_ifStream) + m_iStream(m_ifStream), m_imageLoader(0) { m_filename = strFilename; m_ifStream.open(m_filename, std::ifstream::binary); @@ -326,15 +332,16 @@ namespace PeLib /** * @param stream Input stream. **/ + template PeFileT::PeFileT(std::istream& stream) : - m_iStream(stream) + m_iStream(stream), m_imageLoader(0) { } template PeFileT::PeFileT() : - m_iStream(m_ifStream) + m_iStream(m_ifStream), m_imageLoader(0) { } @@ -366,7 +373,7 @@ namespace PeLib * @return A reference to the file's import directory. **/ template - const ImportDirectory& PeFileT::impDir() const + const ImportDirectory & PeFileT::impDir() const { return m_impdir; } @@ -375,7 +382,7 @@ namespace PeLib * @return A reference to the file's import directory. **/ template - ImportDirectory& PeFileT::impDir() + ImportDirectory & PeFileT::impDir() { return m_impdir; } @@ -501,13 +508,13 @@ namespace PeLib } template - const IatDirectoryT& PeFileT::iatDir() const + const IatDirectory & PeFileT::iatDir() const { return m_iat; } template - IatDirectoryT& PeFileT::iatDir() + IatDirectory & PeFileT::iatDir() { return m_iat; } @@ -547,6 +554,12 @@ namespace PeLib m_ifStream.open(m_filename, std::ifstream::binary); } + template + int PeFileT::loadPeHeaders(ByteBuffer & fileData) + { + return m_imageLoader.Load(fileData); + } + template int PeFileT::readMzHeader() { @@ -563,15 +576,14 @@ namespace PeLib } template - int PeFileT::readCoffSymbolTable() + int PeFileT::readCoffSymbolTable(ByteBuffer & fileData) { - if (peHeader().getPointerToSymbolTable() - && peHeader().getNumberOfSymbols()) + if(m_imageLoader.getPointerToSymbolTable() && m_imageLoader.getNumberOfSymbols()) { return coffSymTab().read( - m_iStream, - static_cast(peHeader().getPointerToSymbolTable()), - peHeader().getNumberOfSymbols() * PELIB_IMAGE_SIZEOF_COFF_SYMBOL); + fileData, + m_imageLoader.getPointerToSymbolTable(), + m_imageLoader.getNumberOfSymbols() * PELIB_IMAGE_SIZEOF_COFF_SYMBOL); } return ERROR_COFF_SYMBOL_TABLE_DOES_NOT_EXIST; } @@ -590,10 +602,9 @@ namespace PeLib template int PeFileT::readImportDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 2 - && peHeader().getIddImportRva()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT)) { - return impDir().read(m_iStream, peHeader()); + return impDir().read(m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } @@ -671,10 +682,9 @@ namespace PeLib template int PeFileT::readIatDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 13 - && peHeader().getIddIatRva() && peHeader().getIddIatSize()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IAT)) { - return iatDir().read(m_iStream, peHeader()); + return iatDir().read(m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } @@ -748,9 +758,9 @@ namespace PeLib // The file size must be greater or equal to SizeOfImage if(ulFileSize >= sizeOfImage) { - dword sectionAlignment = peHeader().getSectionAlignment(); - dword fileAlignment = peHeader().getFileAlignment(); - dword sizeOfHeaders = peHeader().getSizeOfHeaders(); + std::uint32_t sectionAlignment = peHeader().getSectionAlignment(); + std::uint32_t fileAlignment = peHeader().getFileAlignment(); + std::uint32_t sizeOfHeaders = peHeader().getSizeOfHeaders(); // SectionAlignment must be greater than file alignment if(sectionAlignment >= PELIB_PAGE_SIZE && sectionAlignment > fileAlignment) @@ -761,7 +771,7 @@ namespace PeLib std::size_t headerDataSize = sectionAlignment - sizeOfHeaders; // Read the entire after-header-data - std::vector headerData(headerDataSize); + ByteBuffer headerData(headerDataSize); m_iStream.seekg(peHeader().getSizeOfHeaders(), std::ios::beg); m_iStream.read(reinterpret_cast(headerData.data()), headerDataSize); diff --git a/include/retdec/pelib/PeHeader.h b/include/retdec/pelib/PeHeader.h index 56a123d6c..fd25faf27 100644 --- a/include/retdec/pelib/PeHeader.h +++ b/include/retdec/pelib/PeHeader.h @@ -42,14 +42,14 @@ namespace PeLib class PeHeaderT : public PeHeader { private: - void readBaseOfData(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS& header) const; + //void readBaseOfData(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS & header) const; void rebuildBaseOfData(OutputBuffer& obBuffer) const; protected: std::vector m_vIsh; ///< Stores section header information. - PELIB_IMAGE_NT_HEADERS m_inthHeader; ///< Stores Nt header information. + PELIB_IMAGE_NT_HEADERS_EX m_inthHeader; ///< Stores Nt header information. MzHeader m_mzHeader; ///< Stored DOS header. - dword m_uiOffset; ///< Equivalent to the value returned by #PeLib::MzHeader::getAddressOfPeHeader + std::uint32_t m_uiOffset; ///< Equivalent to the value returned by #PeLib::MzHeader::getAddressOfPeHeader LoaderError m_ldrError; unsigned long m_checksumFileOffset; ///< File offset of checksum field in optional PE header unsigned long m_secDirFileOffset; ///< File offset of security data directory @@ -66,13 +66,13 @@ namespace PeLib LoaderError loaderError() const; /// Add a section to the header. - int addSection(const std::string& strName, dword dwSize); // EXPORT + int addSection(const std::string& strName, std::uint32_t dwSize); // EXPORT // Splits a section into two. - int splitSection(word uiSectionnr, const std::string& first, const std::string& second, dword dwSplitOffset); // EXPORT + int splitSection(std::uint16_t uiSectionnr, const std::string& first, const std::string& second, std::uint32_t dwSplitOffset); // EXPORT // Removes a section. - int removeSection(word uiSectionnr); // EXPORT + int removeSection(std::uint16_t uiSectionnr); // EXPORT unsigned int calcSizeOfImage() const; // EXPORT @@ -89,21 +89,21 @@ namespace PeLib unsigned int calcRva() const; // EXPORT /// Returns the number of sections in the current file. - word calcNumberOfSections() const; // EXPORT + std::uint16_t calcNumberOfSections() const; // EXPORT void enlargeLastSection(unsigned int uiSize); // EXPORT /// Returns the section Id of the section that contains the offset. - word getSectionWithOffset(VAR4_8 dwOffset) const; // EXPORT + std::uint16_t getSectionWithOffset(VAR4_8 dwOffset) const; // EXPORT /// Returns the number of the section which the given relative address points to. - word getSectionWithRva(VAR4_8 rva) const; // EXPORT + std::uint16_t getSectionWithRva(VAR4_8 rva) const; // EXPORT bool isValid() const; // EXPORT bool isValid(unsigned int foo) const; // EXPORT /// Corrects the current PE header. - void makeValid(dword dwOffset); // EXPORT + void makeValid(std::uint32_t dwOffset); // EXPORT /// Converts a file offset to a relative virtual offset. unsigned int offsetToRva(VAR4_8 dwOffset) const; // EXPORT @@ -117,18 +117,18 @@ namespace PeLib unsigned int uiOffset, const MzHeader &mzHeader); // EXPORT - void readHeader(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS& header); + void readHeader(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS_EX& header); void readDataDirectories( std::istream& inStream, unsigned int uiOffset, - PELIB_IMAGE_NT_HEADERS& header); + PELIB_IMAGE_NT_HEADERS_EX& header); std::vector readSections( std::istream& inStream, unsigned int uiOffset, - PELIB_IMAGE_NT_HEADERS& header); + PELIB_IMAGE_NT_HEADERS_EX& header); /// Rebuilds the current PE header. - void rebuild(std::vector& vBuffer) const; // EXPORT + void rebuild(std::vector& vBuffer) const; // EXPORT // Checks whether RVA is valid for this image. bool isValidRva(VAR4_8 dwRva) const; // EXPORT @@ -153,7 +153,7 @@ namespace PeLib /// Writes sections to a file. int writeSections(const std::string& strFilename) const; // EXPORT /// Overwrites a section with new data. - int writeSectionData(const std::string& strFilename, word wSecnr, const std::vector& vBuffer) const; // EXPORT + int writeSectionData(const std::string& strFilename, std::uint16_t wSecnr, const std::vector& vBuffer) const; // EXPORT /// Returns file offset of checksum field unsigned int getChecksumFileOffset() const; // EXPORT @@ -162,70 +162,70 @@ namespace PeLib // header getters /// Returns reference to NT headers. - const PELIB_IMAGE_NT_HEADERS& getNtHeaders() const; // EXPORT + const PELIB_IMAGE_NT_HEADERS_EX& getNtHeaders() const; // EXPORT /// Returns the Signature value of the header. - dword getNtSignature() const; // EXPORT + std::uint32_t getNtSignature() const; // EXPORT /// Returns the Machine value of the header. - word getMachine() const; // EXPORT + std::uint16_t getMachine() const; // EXPORT /// Returns the Sections value of the header. - word getNumberOfSections() const; // EXPORT + std::uint16_t getNumberOfSections() const; // EXPORT /// Returns the TimeDateStamp value of the header. - dword getTimeDateStamp() const; // EXPORT + std::uint32_t getTimeDateStamp() const; // EXPORT /// Returns the PointerToSymbolTable value of the header. - dword getPointerToSymbolTable() const; // EXPORT + std::uint32_t getPointerToSymbolTable() const; // EXPORT /// Returns the NumberOfSymbols value of the header. - dword getNumberOfSymbols() const; // EXPORT + std::uint32_t getNumberOfSymbols() const; // EXPORT /// Returns the SizeOfOptionalHeader value of the header. - word getSizeOfOptionalHeader() const; // EXPORT + std::uint16_t getSizeOfOptionalHeader() const; // EXPORT /// Returns the Characteristics value of the header. - word getCharacteristics() const; // EXPORT + std::uint16_t getCharacteristics() const; // EXPORT /// Returns the Magic value of the header. - word getMagic() const; // EXPORT + std::uint16_t getMagic() const; // EXPORT /// Returns the MajorLinkerVersion value of the header. - byte getMajorLinkerVersion() const; // EXPORT + std::uint8_t getMajorLinkerVersion() const; // EXPORT /// Returns the MinorLinkerVersion value of the header. - byte getMinorLinkerVersion() const; // EXPORT + std::uint8_t getMinorLinkerVersion() const; // EXPORT /// Returns the SizeOfCode value of the header. - dword getSizeOfCode() const; // EXPORT + std::uint32_t getSizeOfCode() const; // EXPORT /// Returns the SizeOfInitializedData value of the header. - dword getSizeOfInitializedData() const; // EXPORT + std::uint32_t getSizeOfInitializedData() const; // EXPORT /// Returns the SizeOfUninitializedData value of the header. - dword getSizeOfUninitializedData() const; // EXPORT + std::uint32_t getSizeOfUninitializedData() const; // EXPORT /// Returns the AddressOfEntryPoint value of the header. - dword getAddressOfEntryPoint() const; // EXPORT + std::uint32_t getAddressOfEntryPoint() const; // EXPORT /// Returns the BaseOfCode value of the header. - dword getBaseOfCode() const; // EXPORT + std::uint32_t getBaseOfCode() const; // EXPORT /// Returns the ImageBase value of the header. VAR4_8 getImageBase() const; // EXPORT /// Returns the SectionAlignment value of the header. - dword getSectionAlignment() const; // EXPORT + std::uint32_t getSectionAlignment() const; // EXPORT /// Returns the FileAlignment value of the header. - dword getFileAlignment() const; // EXPORT + std::uint32_t getFileAlignment() const; // EXPORT /// Returns the MajorOperatingSystemVersion value of the header. - word getMajorOperatingSystemVersion() const; // EXPORT + std::uint16_t getMajorOperatingSystemVersion() const; // EXPORT /// Returns the MinorOperatingSystemVersion value of the header. - word getMinorOperatingSystemVersion() const; // EXPORT + std::uint16_t getMinorOperatingSystemVersion() const; // EXPORT /// Returns the MajorImageVersion value of the header. - word getMajorImageVersion() const; // EXPORT + std::uint16_t getMajorImageVersion() const; // EXPORT /// Returns the MinorImageVersion value of the header. - word getMinorImageVersion() const; // EXPORT + std::uint16_t getMinorImageVersion() const; // EXPORT /// Returns the MajorSubsystemVersion value of the header. - word getMajorSubsystemVersion() const; // EXPORT + std::uint16_t getMajorSubsystemVersion() const; // EXPORT /// Returns the MinorSubsystemVersion value of the header. - word getMinorSubsystemVersion() const; // EXPORT + std::uint16_t getMinorSubsystemVersion() const; // EXPORT /// Returns the Reserved1 value of the header. - dword getWin32VersionValue() const; // EXPORT + std::uint32_t getWin32VersionValue() const; // EXPORT /// Returns the SizeOfImage value of the header. - dword getSizeOfImage() const; // EXPORT + std::uint32_t getSizeOfImage() const; // EXPORT /// Returns the SizeOfHeaders value of the header. - dword getSizeOfHeaders() const; // EXPORT + std::uint32_t getSizeOfHeaders() const; // EXPORT /// Returns the CheckSum value of the header. - dword getCheckSum() const; // EXPORT + std::uint32_t getCheckSum() const; // EXPORT /// Returns the Subsystem value of the header. - word getSubsystem() const; // EXPORT + std::uint16_t getSubsystem() const; // EXPORT /// Returns the DllCharacteristics value of the header. - word getDllCharacteristics() const; // EXPORT + std::uint16_t getDllCharacteristics() const; // EXPORT /// Returns the SizeOfStackReserve value of the header. VAR4_8 getSizeOfStackReserve() const; // EXPORT /// Returns the SizeOfStackCommit value of the header. @@ -235,172 +235,172 @@ namespace PeLib /// Returns the SizeOfHeapCommit value of the header. VAR4_8 getSizeOfHeapCommit() const; // EXPORT /// Returns the LoaderFlags value of the header. - dword getLoaderFlags() const; // EXPORT + std::uint32_t getLoaderFlags() const; // EXPORT /// Returns the NumberOfRvaAndSizes value of the header. - dword getNumberOfRvaAndSizes() const; // EXPORT - dword calcNumberOfRvaAndSizes() const; // EXPORT + std::uint32_t getNumberOfRvaAndSizes() const; // EXPORT + std::uint32_t calcNumberOfRvaAndSizes() const; // EXPORT void addDataDirectory(); // EXPORT - void removeDataDirectory(dword index); // EXPORT + void removeDataDirectory(std::uint32_t index); // EXPORT // image directory getters /// Returns the relative virtual address of the image directory Export. - dword getIddExportRva() const; // EXPORT + std::uint32_t getIddExportRva() const; // EXPORT /// Returns the size of the image directory Export. - dword getIddExportSize() const; // EXPORT + std::uint32_t getIddExportSize() const; // EXPORT /// Returns the relative virtual address of the image directory Import. - dword getIddImportRva() const; // EXPORT + std::uint32_t getIddImportRva() const; // EXPORT /// Returns the size of the image directory Import. - dword getIddImportSize() const; // EXPORT + std::uint32_t getIddImportSize() const; // EXPORT /// Returns the relative virtual address of the image directory Resource. - dword getIddResourceRva() const; // EXPORT + std::uint32_t getIddResourceRva() const; // EXPORT /// Returns the size of the image directory Resource. - dword getIddResourceSize() const; // EXPORT + std::uint32_t getIddResourceSize() const; // EXPORT /// Returns the relative virtual address of the image directory Exception. - dword getIddExceptionRva() const; // EXPORT + std::uint32_t getIddExceptionRva() const; // EXPORT /// Returns the size of the image directory Exception. - dword getIddExceptionSize() const; // EXPORT + std::uint32_t getIddExceptionSize() const; // EXPORT /// Returns the relative virtual address of the image directory Security. - dword getIddSecurityRva() const; // EXPORT + std::uint32_t getIddSecurityRva() const; // EXPORT /// Returns the size of the image directory Security. - dword getIddSecuritySize() const; // EXPORT + std::uint32_t getIddSecuritySize() const; // EXPORT /// Returns the relative virtual address of the image directory Base Reloc. - dword getIddBaseRelocRva() const; // EXPORT + std::uint32_t getIddBaseRelocRva() const; // EXPORT /// Returns the size of the image directory Base Reloc. - dword getIddBaseRelocSize() const; // EXPORT + std::uint32_t getIddBaseRelocSize() const; // EXPORT /// Returns the relative virtual address of the image directory Debug. - dword getIddDebugRva() const; // EXPORT + std::uint32_t getIddDebugRva() const; // EXPORT /// Returns the size of the image directory Debug. - dword getIddDebugSize() const; // EXPORT + std::uint32_t getIddDebugSize() const; // EXPORT /// Returns the relative virtual address of the image directory Architecture. - dword getIddArchitectureRva() const; // EXPORT + std::uint32_t getIddArchitectureRva() const; // EXPORT /// Returns the size of the image directory Architecture. - dword getIddArchitectureSize() const; // EXPORT + std::uint32_t getIddArchitectureSize() const; // EXPORT /// Returns the relative virtual address of the image directory GlobalPtr. - dword getIddGlobalPtrRva() const; // EXPORT + std::uint32_t getIddGlobalPtrRva() const; // EXPORT /// Returns the size of the image directory GlobalPtr. - dword getIddGlobalPtrSize() const; // EXPORT + std::uint32_t getIddGlobalPtrSize() const; // EXPORT /// Returns the relative virtual address of the image directory Tls. - dword getIddTlsRva() const; // EXPORT + std::uint32_t getIddTlsRva() const; // EXPORT /// Returns the size of the image directory Tls. - dword getIddTlsSize() const; // EXPORT + std::uint32_t getIddTlsSize() const; // EXPORT /// Returns the relative virtual address of the image directory LoadConfig. - dword getIddLoadConfigRva() const; // EXPORT + std::uint32_t getIddLoadConfigRva() const; // EXPORT /// Returns the size of the image directory LoadConfig. - dword getIddLoadConfigSize() const; // EXPORT + std::uint32_t getIddLoadConfigSize() const; // EXPORT /// Returns the relative virtual address of the image directory BoundImport. - dword getIddBoundImportRva() const; // EXPORT + std::uint32_t getIddBoundImportRva() const; // EXPORT /// Returns the size of the image directory BoundImport. - dword getIddBoundImportSize() const; // EXPORT + std::uint32_t getIddBoundImportSize() const; // EXPORT /// Returns the relative virtual address of the image directory Iat. - dword getIddIatRva() const; // EXPORT + std::uint32_t getIddIatRva() const; // EXPORT /// Returns the size of the image directory Iat. - dword getIddIatSize() const; // EXPORT + std::uint32_t getIddIatSize() const; // EXPORT /// Returns the relative virtual address of the image directory DelayImport. - dword getIddDelayImportRva() const; // EXPORT + std::uint32_t getIddDelayImportRva() const; // EXPORT /// Returns the size of the image directory DelayImport. - dword getIddDelayImportSize() const; // EXPORT + std::uint32_t getIddDelayImportSize() const; // EXPORT /// Returns the relative virtual address of the image directory COM Descriptor. - dword getIddComHeaderRva() const; // EXPORT + std::uint32_t getIddComHeaderRva() const; // EXPORT /// Returns the size of the image directory COM Descriptor. - dword getIddComHeaderSize() const; // EXPORT + std::uint32_t getIddComHeaderSize() const; // EXPORT /// Returns the relative virtual address of an image directory. - dword getImageDataDirectoryRva(dword dwDirectory) const; // EXPORT + std::uint32_t getImageDataDirectoryRva(std::uint32_t dwDirectory) const; // EXPORT /// Returns the size of an image directory. - dword getImageDataDirectorySize(dword dwDirectory) const; // EXPORT + std::uint32_t getImageDataDirectorySize(std::uint32_t dwDirectory) const; // EXPORT - void setImageDataDirectoryRva(dword dwDirectory, dword value); // EXPORT - void setImageDataDirectorySize(dword dwDirectory, dword value); // EXPORT + void setImageDataDirectoryRva(std::uint32_t dwDirectory, std::uint32_t value); // EXPORT + void setImageDataDirectorySize(std::uint32_t dwDirectory, std::uint32_t value); // EXPORT // section getters /// Returns the name of a section. - std::string getSectionName(word uiSectionnr) const; // EXPORT + std::string getSectionName(std::uint16_t uiSectionnr) const; // EXPORT // Returns the name of a section stored in string table - std::string getSectionNameFromStringTable(word uiSectionnr) const; // EXPORT + std::string getSectionNameFromStringTable(std::uint16_t uiSectionnr) const; // EXPORT /// Returns the virtual size of a section. - dword getVirtualSize(word uiSectionnr) const; // EXPORT + std::uint32_t getVirtualSize(std::uint16_t uiSectionnr) const; // EXPORT /// Returns the virtual address of a section. - dword getVirtualAddress(word uiSectionnr) const; // EXPORT + std::uint32_t getVirtualAddress(std::uint16_t uiSectionnr) const; // EXPORT /// Returns the size of a section's raw data. - dword getSizeOfRawData(word uiSectionnr) const; // EXPORT + std::uint32_t getSizeOfRawData(std::uint16_t uiSectionnr) const; // EXPORT /// Returns file offset of the data of a section. - dword getPointerToRawData(word uiSectionnr) const; // EXPORT + std::uint32_t getPointerToRawData(std::uint16_t uiSectionnr) const; // EXPORT /// Returns the rva of the relocations of a section. - dword getPointerToRelocations(word uiSectionnr) const; // EXPORT + std::uint32_t getPointerToRelocations(std::uint16_t uiSectionnr) const; // EXPORT /// Returns the rva of the line numbers of a section. - dword getPointerToLinenumbers(word uiSectionnr) const; // EXPORT + std::uint32_t getPointerToLinenumbers(std::uint16_t uiSectionnr) const; // EXPORT /// Returns the number of relocations of a section. - dword getNumberOfRelocations(word uiSectionnr) const; // EXPORT + std::uint32_t getNumberOfRelocations(std::uint16_t uiSectionnr) const; // EXPORT /// Returns the number of line numbers of a section. - dword getNumberOfLinenumbers(word uiSectionnr) const; // EXPORT + std::uint32_t getNumberOfLinenumbers(std::uint16_t uiSectionnr) const; // EXPORT /// Returns the characteristics of a section. - dword getCharacteristics(word uiSectionnr) const; // EXPORT _section + std::uint32_t getCharacteristics(std::uint16_t uiSectionnr) const; // EXPORT _section // header setters /// Sets the Signature value of the header. - void setNtSignature(dword value); // EXPORT + void setNtSignature(std::uint32_t value); // EXPORT /// Sets the Machine value of the header. - void setMachine(word value); // EXPORT + void setMachine(std::uint16_t value); // EXPORT /// Sets the Sections value of the header. - void setNumberOfSections(word value); // EXPORT + void setNumberOfSections(std::uint16_t value); // EXPORT /// Sets the TimeDateStamp value of the header. - void setTimeDateStamp(dword value); // EXPORT + void setTimeDateStamp(std::uint32_t value); // EXPORT /// Sets the PointerToSymbolTable value of the header. - void setPointerToSymbolTable(dword value); // EXPORT + void setPointerToSymbolTable(std::uint32_t value); // EXPORT /// Sets the NumberOfSymbols value of the header. - void setNumberOfSymbols(dword value); // EXPORT + void setNumberOfSymbols(std::uint32_t value); // EXPORT /// Sets the SizeOfOptionalHeader value of the header. - void setSizeOfOptionalHeader(word value); // EXPORT + void setSizeOfOptionalHeader(std::uint16_t value); // EXPORT /// Sets the Characteristics value of the header. - void setCharacteristics(word value); // EXPORT _section + void setCharacteristics(std::uint16_t value); // EXPORT _section /// Sets the Magic value of the header. - void setMagic(word value); // EXPORT + void setMagic(std::uint16_t value); // EXPORT /// Sets the MajorLinkerVersion value of the header. - void setMajorLinkerVersion(byte value); // EXPORT + void setMajorLinkerVersion(std::uint8_t value); // EXPORT /// Sets the MinorLinkerVersion value of the header. - void setMinorLinkerVersion(byte value); // EXPORT + void setMinorLinkerVersion(std::uint8_t value); // EXPORT /// Sets the SizeOfCode value of the header. - void setSizeOfCode(dword value); // EXPORT + void setSizeOfCode(std::uint32_t value); // EXPORT /// Sets the SizeOfInitializedData value of the header. - void setSizeOfInitializedData(dword value); // EXPORT + void setSizeOfInitializedData(std::uint32_t value); // EXPORT /// Sets the SizeOfUninitializedData value of the header. - void setSizeOfUninitializedData(dword value); // EXPORT + void setSizeOfUninitializedData(std::uint32_t value); // EXPORT /// Sets the AddressOfEntryPoint value of the header. - void setAddressOfEntryPoint(dword value); // EXPORT + void setAddressOfEntryPoint(std::uint32_t value); // EXPORT /// Sets the BaseOfCode value of the header. - void setBaseOfCode(dword value); // EXPORT + void setBaseOfCode(std::uint32_t value); // EXPORT /// Sets the ImageBase value of the header. void setImageBase(VAR4_8 value); // EXPORT /// Sets the SectionAlignment value of the header. - void setSectionAlignment(dword value); // EXPORT + void setSectionAlignment(std::uint32_t value); // EXPORT /// Sets the FileAlignment value of the header. - void setFileAlignment(dword value); // EXPORT + void setFileAlignment(std::uint32_t value); // EXPORT /// Sets the MajorOperatingSystemVersion value of the header. - void setMajorOperatingSystemVersion(word value); // EXPORT + void setMajorOperatingSystemVersion(std::uint16_t value); // EXPORT /// Sets the MinorOperatingSystemVersion value of the header. - void setMinorOperatingSystemVersion(word value); // EXPORT + void setMinorOperatingSystemVersion(std::uint16_t value); // EXPORT /// Sets the MajorImageVersion value of the header. - void setMajorImageVersion(word value); // EXPORT + void setMajorImageVersion(std::uint16_t value); // EXPORT /// Sets the MinorImageVersion value of the header. - void setMinorImageVersion(word value); // EXPORT + void setMinorImageVersion(std::uint16_t value); // EXPORT /// Sets the MajorSubsystemVersion value of the header. - void setMajorSubsystemVersion(word value); // EXPORT + void setMajorSubsystemVersion(std::uint16_t value); // EXPORT /// Sets the MinorSubsystemVersion value of the header. - void setMinorSubsystemVersion(word value); // EXPORT + void setMinorSubsystemVersion(std::uint16_t value); // EXPORT /// Sets the Reserved1 value of the header. - void setWin32VersionValue(dword value); // EXPORT + void setWin32VersionValue(std::uint32_t value); // EXPORT /// Sets the SizeOfImage value of the header. - void setSizeOfImage(dword value); // EXPORT + void setSizeOfImage(std::uint32_t value); // EXPORT /// Sets the SizeOfHeaders value of the header. - void setSizeOfHeaders(dword value); // EXPORT + void setSizeOfHeaders(std::uint32_t value); // EXPORT /// Sets the CheckSum value of the header. - void setCheckSum(dword value); // EXPORT + void setCheckSum(std::uint32_t value); // EXPORT /// Sets the Subsystem value of the header. - void setSubsystem(word value); // EXPORT + void setSubsystem(std::uint16_t value); // EXPORT /// Sets the DllCharacteristics value of the header. - void setDllCharacteristics(word value); // EXPORT + void setDllCharacteristics(std::uint16_t value); // EXPORT /// Sets the SizeOfStackReserve value of the header. void setSizeOfStackReserve(VAR4_8 value); // EXPORT /// Sets the SizeOfStackCommit value of the header. @@ -410,71 +410,71 @@ namespace PeLib /// Sets the SizeOfHeapCommit value of the header. void setSizeOfHeapCommit(VAR4_8 value); // EXPORT /// Sets the LoaderFlags value of the header. - void setLoaderFlags(dword value); // EXPORT + void setLoaderFlags(std::uint32_t value); // EXPORT /// Sets the NumberOfRvaAndSizes value of the header. - void setNumberOfRvaAndSizes(dword value); // EXPORT + void setNumberOfRvaAndSizes(std::uint32_t value); // EXPORT // image directory getters - void setIddDebugRva(dword dwValue); // EXPORT - void setIddDebugSize(dword dwValue); // EXPORT - void setIddDelayImportRva(dword dwValue); // EXPORT - void setIddDelayImportSize(dword dwValue); // EXPORT - void setIddExceptionRva(dword dwValue); // EXPORT - void setIddExceptionSize(dword dwValue); // EXPORT - void setIddGlobalPtrRva(dword dwValue); // EXPORT - void setIddGlobalPtrSize(dword dwValue); // EXPORT - void setIddIatRva(dword dwValue); // EXPORT - void setIddIatSize(dword dwValue); // EXPORT - void setIddLoadConfigRva(dword dwValue); // EXPORT - void setIddLoadConfigSize(dword dwValue); // EXPORT - void setIddResourceRva(dword dwValue); // EXPORT - void setIddResourceSize(dword dwValue); // EXPORT - void setIddSecurityRva(dword dwValue); // EXPORT - void setIddSecuritySize(dword dwValue); // EXPORT - void setIddTlsRva(dword dwValue); // EXPORT - void setIddTlsSize(dword dwValue); // EXPORT - - void setIddImportRva(dword dwValue); // EXPORT - void setIddImportSize(dword dwValue); // EXPORT - void setIddExportRva(dword dwValue); // EXPORT - void setIddExportSize(dword dwValue); // EXPORT - - void setIddBaseRelocRva(dword value); // EXPORT - void setIddBaseRelocSize(dword value); // EXPORT - void setIddArchitectureRva(dword value); // EXPORT - void setIddArchitectureSize(dword value); // EXPORT - void setIddComHeaderRva(dword value); // EXPORT - void setIddComHeaderSize(dword value); // EXPORT + void setIddDebugRva(std::uint32_t dwValue); // EXPORT + void setIddDebugSize(std::uint32_t dwValue); // EXPORT + void setIddDelayImportRva(std::uint32_t dwValue); // EXPORT + void setIddDelayImportSize(std::uint32_t dwValue); // EXPORT + void setIddExceptionRva(std::uint32_t dwValue); // EXPORT + void setIddExceptionSize(std::uint32_t dwValue); // EXPORT + void setIddGlobalPtrRva(std::uint32_t dwValue); // EXPORT + void setIddGlobalPtrSize(std::uint32_t dwValue); // EXPORT + void setIddIatRva(std::uint32_t dwValue); // EXPORT + void setIddIatSize(std::uint32_t dwValue); // EXPORT + void setIddLoadConfigRva(std::uint32_t dwValue); // EXPORT + void setIddLoadConfigSize(std::uint32_t dwValue); // EXPORT + void setIddResourceRva(std::uint32_t dwValue); // EXPORT + void setIddResourceSize(std::uint32_t dwValue); // EXPORT + void setIddSecurityRva(std::uint32_t dwValue); // EXPORT + void setIddSecuritySize(std::uint32_t dwValue); // EXPORT + void setIddTlsRva(std::uint32_t dwValue); // EXPORT + void setIddTlsSize(std::uint32_t dwValue); // EXPORT + + void setIddImportRva(std::uint32_t dwValue); // EXPORT + void setIddImportSize(std::uint32_t dwValue); // EXPORT + void setIddExportRva(std::uint32_t dwValue); // EXPORT + void setIddExportSize(std::uint32_t dwValue); // EXPORT + + void setIddBaseRelocRva(std::uint32_t value); // EXPORT + void setIddBaseRelocSize(std::uint32_t value); // EXPORT + void setIddArchitectureRva(std::uint32_t value); // EXPORT + void setIddArchitectureSize(std::uint32_t value); // EXPORT + void setIddComHeaderRva(std::uint32_t value); // EXPORT + void setIddComHeaderSize(std::uint32_t value); // EXPORT /// Set the name of a section. - void setSectionName(word uiSectionnr, std::string strName); // EXPORT + void setSectionName(std::uint16_t uiSectionnr, std::string strName); // EXPORT /// Set the virtual size of a section. - void setVirtualSize(word uiSectionnr, dword dwValue); // EXPORT + void setVirtualSize(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT /// Set the virtual address of a section. - void setVirtualAddress(word uiSectionnr, dword dwValue); // EXPORT + void setVirtualAddress(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT /// Set the size of raw data of a section. - void setSizeOfRawData(word uiSectionnr, dword dwValue); // EXPORT + void setSizeOfRawData(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT /// Set the file offset of a section. - void setPointerToRawData(word uiSectionnr, dword dwValue); // EXPORT + void setPointerToRawData(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT /// Set the pointer to relocations of a section. - void setPointerToRelocations(word uiSectionnr, dword dwValue); // EXPORT + void setPointerToRelocations(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT /// Set the pointer to linenumbers of a section. - void setPointerToLinenumbers(word uiSectionnr, dword dwValue); // EXPORT + void setPointerToLinenumbers(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT /// Set the number of relocations a section. - void setNumberOfRelocations(word uiSectionnr, dword dwValue); // EXPORT + void setNumberOfRelocations(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT /// Set the number of linenumbers section. - void setNumberOfLinenumbers(word uiSectionnr, dword dwValue); // EXPORT + void setNumberOfLinenumbers(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT /// Set the characteristics of a section. - void setCharacteristics(word uiSectionnr, dword dwValue); // EXPORT + void setCharacteristics(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT }; class PeHeader32 : public PeHeaderT<32> { public: /// Returns the BaseOfData value of the header. - dword getBaseOfData() const; // EXPORT + std::uint32_t getBaseOfData() const; // EXPORT /// Sets the BaseOfData value of the header. - void setBaseOfData(dword value); // EXPORT + void setBaseOfData(std::uint32_t value); // EXPORT }; class PeHeader64 : public PeHeaderT<64> @@ -488,7 +488,7 @@ namespace PeLib } template - void PeHeaderT::removeDataDirectory(dword index) + void PeHeaderT::removeDataDirectory(std::uint32_t index) { if (m_inthHeader.lastDirectoryIsIncomplete && index == m_inthHeader.dataDirectories.size() - 1) { @@ -509,7 +509,7 @@ namespace PeLib * \todo Better code that handles files with 0 sections. **/ template - int PeHeaderT::addSection(const std::string& strName, dword dwSize) + int PeHeaderT::addSection(const std::string& strName, std::uint32_t dwSize) { unsigned int uiSecnr = calcNumberOfSections(); @@ -530,8 +530,8 @@ namespace PeLib } } - dword dwOffset = calcOffset(/*dwSize*/); - dword dwRva = calcRva(/*dwSize*/); + std::uint32_t dwOffset = calcOffset(/*dwSize*/); + std::uint32_t dwRva = calcRva(/*dwSize*/); PELIB_IMAGE_SECTION_HEADER ishdCurr; m_vIsh.push_back(ishdCurr); @@ -558,7 +558,7 @@ namespace PeLib * @todo Add option to split any section without restrictions. **/ template - int PeHeaderT::splitSection(word uiSectionnr, const std::string& first, const std::string& second, dword dwSplitOffset) + int PeHeaderT::splitSection(std::uint16_t uiSectionnr, const std::string& first, const std::string& second, std::uint32_t dwSplitOffset) { if (!getFileAlignment()) { @@ -587,7 +587,7 @@ namespace PeLib for (int i = calcNumberOfSections() - 2; i >= uiSectionnr + 1; --i) m_vIsh[i + 1] = m_vIsh[i]; - dword originalSize = getSizeOfRawData(uiSectionnr); + std::uint32_t originalSize = getSizeOfRawData(uiSectionnr); // Setup the first of the new sections setSectionName(uiSectionnr, first); @@ -611,13 +611,13 @@ namespace PeLib * @param uiSectionnr The index of the section to remove. **/ template - int PeHeaderT::removeSection(word uiSectionnr) + int PeHeaderT::removeSection(std::uint16_t uiSectionnr) { if (uiSectionnr >= calcNumberOfSections()) return ERROR_ENTRY_NOT_FOUND; - dword rawDiff = getSizeOfRawData(uiSectionnr); - dword virtualDiff = getVirtualSize(uiSectionnr); + std::uint32_t rawDiff = getSizeOfRawData(uiSectionnr); + std::uint32_t virtualDiff = getVirtualSize(uiSectionnr); for (int i = uiSectionnr + 1; i < calcNumberOfSections(); ++i) { setPointerToRawData(i, getPointerToRawData(i) - rawDiff); @@ -652,7 +652,7 @@ namespace PeLib } /** - * Calculates the space between the last byte of the header and the first byte that's used for something + * Calculates the space between the last std::uint8_t of the header and the first std::uint8_t that's used for something * else (that's either the first section or an image directory). * @return Unused space after the header. * \todo There are PE files with sections beginning at offset 0. They @@ -694,7 +694,7 @@ namespace PeLib if (directories >= 14 && getIddDelayImportRva() && rvaToOffset(getIddDelayImportRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddDelayImportRva()); if (directories >= 15 && getIddComHeaderRva() && rvaToOffset(getIddComHeaderRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddComHeaderRva()); - for (word i=0;i maxoffset) maxoffset = getPointerToRawData(i) + getSizeOfRawData(i); } @@ -736,7 +736,7 @@ namespace PeLib // In this file each and every section has a VSize of 0 but it still runs. unsigned int maxoffset = size(); - for (word i=0;i maxoffset) maxoffset = getVirtualAddress(i) + std::max(getVirtualSize(i), getSizeOfRawData(i)); } @@ -750,9 +750,9 @@ namespace PeLib * @return Number of currently defined sections. **/ template - word PeHeaderT::calcNumberOfSections() const + std::uint16_t PeHeaderT::calcNumberOfSections() const { - return static_cast(m_vIsh.size()); + return static_cast(m_vIsh.size()); } /** @@ -781,22 +781,22 @@ namespace PeLib * @return Section Id of the section which contains the offset. **/ template - word PeHeaderT::getSectionWithOffset(VAR4_8 dwOffset) const + std::uint16_t PeHeaderT::getSectionWithOffset(VAR4_8 dwOffset) const { // Offset = 0 must be handled explicitly as there are files // with sections that begin at offset 0, that means the section // only exists in memory. - if (!dwOffset) return std::numeric_limits::max(); + if (!dwOffset) return std::numeric_limits::max(); - for (word i=0;i dwOffset) return i; } - return std::numeric_limits::max(); + return std::numeric_limits::max(); } /** @@ -805,23 +805,23 @@ namespace PeLib * @return Section Id of the section which contains the Rva. **/ template - word PeHeaderT::getSectionWithRva(VAR4_8 dwRva) const + std::uint16_t PeHeaderT::getSectionWithRva(VAR4_8 dwRva) const { // Major note here: It's possible for sections to exist with a Virtual Size of 0. // That's why it's necessary to use std::max(Vsize, RawSize) here. // An example for such a file is dbeng6.exe (made by Sybase). // In this file each and every section has a VSize of 0 but it still runs. - word actIndex = 0; + std::uint16_t actIndex = 0; bool detected = false; - for (word i=0;i= getSizeOfRawData(i) ? getVirtualSize(i) : getSizeOfRawData(i); + std::uint32_t max = getVirtualSize(i) >= getSizeOfRawData(i) ? getVirtualSize(i) : getSizeOfRawData(i); if (getVirtualAddress(i) <= dwRva && getVirtualAddress(i) + max > dwRva) { - dword actMax = getVirtualSize(actIndex) >= getSizeOfRawData(actIndex) ? getVirtualSize(actIndex) : getSizeOfRawData(actIndex); + std::uint32_t actMax = getVirtualSize(actIndex) >= getSizeOfRawData(actIndex) ? getVirtualSize(actIndex) : getSizeOfRawData(actIndex); if (!detected || (getVirtualAddress(i) > getVirtualAddress(actIndex) || (getVirtualAddress(i) == getVirtualAddress(actIndex) && max < actMax))) { actIndex = i; @@ -842,11 +842,11 @@ namespace PeLib * \todo 32bit and 64bit versions. **/ template - void PeHeaderT::makeValid(dword dwOffset) + void PeHeaderT::makeValid(std::uint32_t dwOffset) { setNtSignature(PELIB_IMAGE_NT_SIGNATURE); // 'PE' setNumberOfSections(calcNumberOfSections()); - setSizeOfOptionalHeader(PELIB_IMAGE_OPTIONAL_HEADER::size() + calcNumberOfRvaAndSizes() * 8); + setSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER) + calcNumberOfRvaAndSizes() * 8); if (getCharacteristics() == 0) setCharacteristics(PELIB_IMAGE_FILE_EXECUTABLE_IMAGE | PELIB_IMAGE_FILE_32BIT_MACHINE); @@ -878,12 +878,12 @@ namespace PeLib m_inthHeader.dataDirectories.resize(getNumberOfRvaAndSizes()); // Code below depends on code above. Don't change the order. - dword dwSizeOfHeaders = alignOffset(dwOffset + size(), getFileAlignment()); + std::uint32_t dwSizeOfHeaders = alignOffset(dwOffset + size(), getFileAlignment()); setSizeOfHeaders(dwSizeOfHeaders); - dword dwSizeOfImage = alignOffset(dwSizeOfHeaders, getSectionAlignment()); + std::uint32_t dwSizeOfImage = alignOffset(dwSizeOfHeaders, getSectionAlignment()); - dword dwOffsetDiff = dwSizeOfHeaders - getPointerToRawData(0); + std::uint32_t dwOffsetDiff = dwSizeOfHeaders - getPointerToRawData(0); for (int i=0;i - void PeHeaderT::readHeader(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS& header) + void PeHeaderT::readHeader(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS_EX& header) { ibBuffer >> header.Signature; @@ -947,7 +947,7 @@ namespace PeLib ibBuffer >> header.OptionalHeader.SizeOfUninitializedData; ibBuffer >> header.OptionalHeader.AddressOfEntryPoint; ibBuffer >> header.OptionalHeader.BaseOfCode; - readBaseOfData(ibBuffer, header); + //readBaseOfData(ibBuffer, header); ibBuffer >> header.OptionalHeader.ImageBase; ibBuffer >> header.OptionalHeader.SectionAlignment; ibBuffer >> header.OptionalHeader.FileAlignment; @@ -976,7 +976,7 @@ namespace PeLib void PeHeaderT::readDataDirectories( std::istream& inStream, unsigned int uiOffset, - PELIB_IMAGE_NT_HEADERS& header) + PELIB_IMAGE_NT_HEADERS_EX& header) { IStreamWrapper inStream_w(inStream); @@ -1030,7 +1030,7 @@ namespace PeLib std::vector PeHeaderT::readSections( std::istream& inStream, unsigned int uiOffset, - PELIB_IMAGE_NT_HEADERS& header) + PELIB_IMAGE_NT_HEADERS_EX& header) { IStreamWrapper inStream_w(inStream); @@ -1038,7 +1038,7 @@ namespace PeLib std::vector vIshdCurr; bool bRawDataBeyondEOF = false; - std::vector ishBuffer(PELIB_IMAGE_SECTION_HEADER::size()); + std::vector ishBuffer(sizeof(PELIB_IMAGE_SECTION_HEADER)); PELIB_IMAGE_SECTION_HEADER ishCurr; std::uint64_t ulFileSize = fileSize(inStream_w); @@ -1049,7 +1049,7 @@ namespace PeLib for (unsigned int i = 0; i < header.FileHeader.NumberOfSections; i++) { - if (uiOffset + PELIB_IMAGE_SECTION_HEADER::size() > ulFileSize) + if (uiOffset + sizeof(PELIB_IMAGE_SECTION_HEADER) > ulFileSize) break; // Clear error bits, because reading from symbol table might have failed. @@ -1106,7 +1106,7 @@ namespace PeLib vIshdCurr.push_back(ishCurr); - uiOffset += PELIB_IMAGE_SECTION_HEADER::size(); + uiOffset += sizeof(PELIB_IMAGE_SECTION_HEADER); } // Verify section headers @@ -1263,7 +1263,7 @@ namespace PeLib m_mzHeader = mzHeader; m_uiOffset = ntHeaderOffset; - PELIB_IMAGE_NT_HEADERS header; + PELIB_IMAGE_NT_HEADERS_EX header; if (!inStream_w) { @@ -1345,7 +1345,7 @@ namespace PeLib if(header.OptionalHeader.SizeOfHeaders > header.OptionalHeader.SizeOfImage) setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); - // On 64-bit Windows, size of optional header must be properly aligned to 8-byte boundary + // On 64-bit Windows, size of optional header must be properly aligned to 8-std::uint8_t boundary if (header.FileHeader.SizeOfOptionalHeader & (sizeof(std::uint64_t) - 1)) setLoaderError(LDR_ERROR_SIZE_OF_OPTHDR_NOT_ALIGNED); @@ -1380,7 +1380,7 @@ namespace PeLib * @param vBuffer Buffer where the rebuilt header will be stored. **/ template - void PeHeaderT::rebuild(std::vector& vBuffer) const + void PeHeaderT::rebuild(std::vector& vBuffer) const { OutputBuffer obBuffer(vBuffer); @@ -1472,7 +1472,7 @@ namespace PeLib if (rva < getFileAlignment()) return true; - for (word i = 0; i < calcNumberOfSections(); ++i) + for (std::uint16_t i = 0; i < calcNumberOfSections(); ++i) { // Sample 91DE52AB3F94A6372088DD843485414BA2B3734BDF58C4DE40DF3B50B4301C57: // Section[0].VirtualAddress = 0x1000 @@ -1480,8 +1480,8 @@ namespace PeLib // Section[0].SizeOfRawData = 0x3600 // IMAGE_IMPORT_DESCRIPTOR[0]::Name is 0x44DE, which is evaluated as invalid if alignment is not taken into account - dword beginOfSection = getVirtualAddress(i); - dword sizeOfSection = getVirtualSize(i); + std::uint32_t beginOfSection = getVirtualAddress(i); + std::uint32_t sizeOfSection = getVirtualSize(i); // Perform proper alignment on the section length if (sizeOfSection == 0) @@ -1508,7 +1508,7 @@ namespace PeLib // XXX: Not correct if (dwRva < 0x1000) return dwRva; - PeLib::word uiSecnr = getSectionWithRva(dwRva); + std::uint16_t uiSecnr = getSectionWithRva(dwRva); if (uiSecnr == 0xFFFF || dwRva > getVirtualAddress(uiSecnr) + getSizeOfRawData(uiSecnr)) { @@ -1640,7 +1640,7 @@ namespace PeLib * @param vBuffer New data of the section. **/ template - int PeHeaderT::writeSectionData(const std::string& strFilename, word wSecnr, const std::vector& vBuffer) const + int PeHeaderT::writeSectionData(const std::string& strFilename, std::uint16_t wSecnr, const std::vector& vBuffer) const { std::fstream ofFile(strFilename.c_str(), std::ios_base::in); @@ -1728,7 +1728,7 @@ namespace PeLib * @return Reference to NT headers. **/ template - const PELIB_IMAGE_NT_HEADERS& PeHeaderT::getNtHeaders() const + const PELIB_IMAGE_NT_HEADERS_EX& PeHeaderT::getNtHeaders() const { return m_inthHeader; } @@ -1738,7 +1738,7 @@ namespace PeLib * @return The Nt signature value from the PE header. **/ template - dword PeHeaderT::getNtSignature() const + std::uint32_t PeHeaderT::getNtSignature() const { return m_inthHeader.Signature; } @@ -1748,7 +1748,7 @@ namespace PeLib * @return The Machine value from the PE header. **/ template - word PeHeaderT::getMachine() const + std::uint16_t PeHeaderT::getMachine() const { return m_inthHeader.FileHeader.Machine; } @@ -1759,7 +1759,7 @@ namespace PeLib * @return The NumberOfSections value from the PE header. **/ template - word PeHeaderT::getNumberOfSections() const + std::uint16_t PeHeaderT::getNumberOfSections() const { return m_inthHeader.FileHeader.NumberOfSections; } @@ -1769,7 +1769,7 @@ namespace PeLib * @return The TimeDateStamp value from the PE header. **/ template - dword PeHeaderT::getTimeDateStamp() const + std::uint32_t PeHeaderT::getTimeDateStamp() const { return m_inthHeader.FileHeader.TimeDateStamp; } @@ -1779,7 +1779,7 @@ namespace PeLib * @return The PointerToSymbolTable value from the PE header. **/ template - dword PeHeaderT::getPointerToSymbolTable() const + std::uint32_t PeHeaderT::getPointerToSymbolTable() const { return m_inthHeader.FileHeader.PointerToSymbolTable; } @@ -1789,7 +1789,7 @@ namespace PeLib * @return The NumberOfSymbols value from the PE header. **/ template - dword PeHeaderT::getNumberOfSymbols() const + std::uint32_t PeHeaderT::getNumberOfSymbols() const { return m_inthHeader.FileHeader.NumberOfSymbols; } @@ -1799,7 +1799,7 @@ namespace PeLib * @return The SizeOfOptionalHeader value from the PE header. **/ template - word PeHeaderT::getSizeOfOptionalHeader() const + std::uint16_t PeHeaderT::getSizeOfOptionalHeader() const { return m_inthHeader.FileHeader.SizeOfOptionalHeader; } @@ -1808,7 +1808,7 @@ namespace PeLib * @return The Characteristics value from the PE header. **/ template - word PeHeaderT::getCharacteristics() const + std::uint16_t PeHeaderT::getCharacteristics() const { return m_inthHeader.FileHeader.Characteristics; } @@ -1817,7 +1817,7 @@ namespace PeLib * @return The Magic value from the PE header. **/ template - word PeHeaderT::getMagic() const + std::uint16_t PeHeaderT::getMagic() const { return m_inthHeader.OptionalHeader.Magic; } @@ -1826,7 +1826,7 @@ namespace PeLib * @return The MajorLinkerVersion value from the PE header. **/ template - byte PeHeaderT::getMajorLinkerVersion() const + std::uint8_t PeHeaderT::getMajorLinkerVersion() const { return m_inthHeader.OptionalHeader.MajorLinkerVersion; } @@ -1835,7 +1835,7 @@ namespace PeLib * @return The MinorLinkerVersion value from the PE header. **/ template - byte PeHeaderT::getMinorLinkerVersion() const + std::uint8_t PeHeaderT::getMinorLinkerVersion() const { return m_inthHeader.OptionalHeader.MinorLinkerVersion; } @@ -1844,7 +1844,7 @@ namespace PeLib * @return The SizeOfCode value from the PE header. **/ template - dword PeHeaderT::getSizeOfCode() const + std::uint32_t PeHeaderT::getSizeOfCode() const { return m_inthHeader.OptionalHeader.SizeOfCode; } @@ -1853,7 +1853,7 @@ namespace PeLib * @return The SizeOfInitializedData value from the PE header. **/ template - dword PeHeaderT::getSizeOfInitializedData() const + std::uint32_t PeHeaderT::getSizeOfInitializedData() const { return m_inthHeader.OptionalHeader.SizeOfInitializedData; } @@ -1862,7 +1862,7 @@ namespace PeLib * @return The SizeOfUninitializedData value from the PE header. **/ template - dword PeHeaderT::getSizeOfUninitializedData() const + std::uint32_t PeHeaderT::getSizeOfUninitializedData() const { return m_inthHeader.OptionalHeader.SizeOfUninitializedData; } @@ -1871,7 +1871,7 @@ namespace PeLib * @return The AddressOfEntryPoint value from the PE header. **/ template - dword PeHeaderT::getAddressOfEntryPoint() const + std::uint32_t PeHeaderT::getAddressOfEntryPoint() const { return m_inthHeader.OptionalHeader.AddressOfEntryPoint; } @@ -1880,7 +1880,7 @@ namespace PeLib * @return The BaseOfCode value from the PE header. **/ template - dword PeHeaderT::getBaseOfCode() const + std::uint32_t PeHeaderT::getBaseOfCode() const { return m_inthHeader.OptionalHeader.BaseOfCode; } @@ -1898,7 +1898,7 @@ namespace PeLib * @return The SectionAlignment value from the PE header. **/ template - dword PeHeaderT::getSectionAlignment() const + std::uint32_t PeHeaderT::getSectionAlignment() const { return m_inthHeader.OptionalHeader.SectionAlignment; } @@ -1907,7 +1907,7 @@ namespace PeLib * @return The FileAlignment value from the PE header. **/ template - dword PeHeaderT::getFileAlignment() const + std::uint32_t PeHeaderT::getFileAlignment() const { return m_inthHeader.OptionalHeader.FileAlignment; } @@ -1916,7 +1916,7 @@ namespace PeLib * @return The MajorOperatingSystemVersion value from the PE header. **/ template - word PeHeaderT::getMajorOperatingSystemVersion() const + std::uint16_t PeHeaderT::getMajorOperatingSystemVersion() const { return m_inthHeader.OptionalHeader.MajorOperatingSystemVersion; } @@ -1925,7 +1925,7 @@ namespace PeLib * @return The MinorOperatingSystemVersion value from the PE header. **/ template - word PeHeaderT::getMinorOperatingSystemVersion() const + std::uint16_t PeHeaderT::getMinorOperatingSystemVersion() const { return m_inthHeader.OptionalHeader.MinorOperatingSystemVersion; } @@ -1934,7 +1934,7 @@ namespace PeLib * @return The MajorImageVersion value from the PE header. **/ template - word PeHeaderT::getMajorImageVersion() const + std::uint16_t PeHeaderT::getMajorImageVersion() const { return m_inthHeader.OptionalHeader.MajorImageVersion; } @@ -1943,7 +1943,7 @@ namespace PeLib * @return The MinorImageVersion value from the PE header. **/ template - word PeHeaderT::getMinorImageVersion() const + std::uint16_t PeHeaderT::getMinorImageVersion() const { return m_inthHeader.OptionalHeader.MinorImageVersion; } @@ -1952,7 +1952,7 @@ namespace PeLib * @return The MajorSubsystemVersion value from the PE header. **/ template - word PeHeaderT::getMajorSubsystemVersion() const + std::uint16_t PeHeaderT::getMajorSubsystemVersion() const { return m_inthHeader.OptionalHeader.MajorSubsystemVersion; } @@ -1961,7 +1961,7 @@ namespace PeLib * @return The MinorSubsystemVersion value from the PE header. **/ template - word PeHeaderT::getMinorSubsystemVersion() const + std::uint16_t PeHeaderT::getMinorSubsystemVersion() const { return m_inthHeader.OptionalHeader.MinorSubsystemVersion; } @@ -1970,7 +1970,7 @@ namespace PeLib * @return The WinVersionValue value from the PE header. **/ template - dword PeHeaderT::getWin32VersionValue() const + std::uint32_t PeHeaderT::getWin32VersionValue() const { return m_inthHeader.OptionalHeader.Win32VersionValue; } @@ -1979,7 +1979,7 @@ namespace PeLib * @return The SizeOfImage value from the PE header. **/ template - dword PeHeaderT::getSizeOfImage() const + std::uint32_t PeHeaderT::getSizeOfImage() const { return m_inthHeader.OptionalHeader.SizeOfImage; } @@ -1988,7 +1988,7 @@ namespace PeLib * @return The SizeOfHeaders value from the PE header. **/ template - dword PeHeaderT::getSizeOfHeaders() const + std::uint32_t PeHeaderT::getSizeOfHeaders() const { return m_inthHeader.OptionalHeader.SizeOfHeaders; } @@ -1997,7 +1997,7 @@ namespace PeLib * @return The CheckSums value from the PE header. **/ template - dword PeHeaderT::getCheckSum() const + std::uint32_t PeHeaderT::getCheckSum() const { return m_inthHeader.OptionalHeader.CheckSum; } @@ -2006,7 +2006,7 @@ namespace PeLib * @return The Subsystem value from the PE header. **/ template - word PeHeaderT::getSubsystem() const + std::uint16_t PeHeaderT::getSubsystem() const { return m_inthHeader.OptionalHeader.Subsystem; } @@ -2015,7 +2015,7 @@ namespace PeLib * @return The DllCharacteristics value from the PE header. **/ template - word PeHeaderT::getDllCharacteristics() const + std::uint16_t PeHeaderT::getDllCharacteristics() const { return m_inthHeader.OptionalHeader.DllCharacteristics; } @@ -2060,7 +2060,7 @@ namespace PeLib * @return The LoaderFlags value from the PE header. **/ template - dword PeHeaderT::getLoaderFlags() const + std::uint32_t PeHeaderT::getLoaderFlags() const { return m_inthHeader.OptionalHeader.LoaderFlags; } @@ -2069,15 +2069,15 @@ namespace PeLib * @return The NumberOfRvaAndSizes value from the PE header. **/ template - dword PeHeaderT::getNumberOfRvaAndSizes() const + std::uint32_t PeHeaderT::getNumberOfRvaAndSizes() const { return m_inthHeader.OptionalHeader.NumberOfRvaAndSizes; } template - dword PeHeaderT::calcNumberOfRvaAndSizes() const + std::uint32_t PeHeaderT::calcNumberOfRvaAndSizes() const { - return static_cast(m_inthHeader.dataDirectories.size()); + return static_cast(m_inthHeader.dataDirectories.size()); } /** @@ -2085,7 +2085,7 @@ namespace PeLib * @return The Rva of the Export directory. **/ template - dword PeHeaderT::getIddExportRva() const + std::uint32_t PeHeaderT::getIddExportRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; } @@ -2095,7 +2095,7 @@ namespace PeLib * @return The sizeof the Export directory. **/ template - dword PeHeaderT::getIddExportSize() const + std::uint32_t PeHeaderT::getIddExportSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT].Size; } @@ -2105,7 +2105,7 @@ namespace PeLib * @return The Rva of the Import directory. **/ template - dword PeHeaderT::getIddImportRva() const + std::uint32_t PeHeaderT::getIddImportRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; } @@ -2115,7 +2115,7 @@ namespace PeLib * @return The size of the Import directory. **/ template - dword PeHeaderT::getIddImportSize() const + std::uint32_t PeHeaderT::getIddImportSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT].Size; } @@ -2125,7 +2125,7 @@ namespace PeLib * @return The Rva of the Resource directory. **/ template - dword PeHeaderT::getIddResourceRva() const + std::uint32_t PeHeaderT::getIddResourceRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; } @@ -2135,7 +2135,7 @@ namespace PeLib * @return The size of the Resource directory. **/ template - dword PeHeaderT::getIddResourceSize() const + std::uint32_t PeHeaderT::getIddResourceSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; } @@ -2145,7 +2145,7 @@ namespace PeLib * @return The Rva of the Exception directory. **/ template - dword PeHeaderT::getIddExceptionRva() const + std::uint32_t PeHeaderT::getIddExceptionRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress; } @@ -2155,7 +2155,7 @@ namespace PeLib * @return The size of the Exception directory. **/ template - dword PeHeaderT::getIddExceptionSize() const + std::uint32_t PeHeaderT::getIddExceptionSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size; } @@ -2165,7 +2165,7 @@ namespace PeLib * @return The Rva of the Security directory. **/ template - dword PeHeaderT::getIddSecurityRva() const + std::uint32_t PeHeaderT::getIddSecurityRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress; } @@ -2175,7 +2175,7 @@ namespace PeLib * @return The size of the Security directory. **/ template - dword PeHeaderT::getIddSecuritySize() const + std::uint32_t PeHeaderT::getIddSecuritySize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; } @@ -2185,7 +2185,7 @@ namespace PeLib * @return The Rva of the Base Reloc directory. **/ template - dword PeHeaderT::getIddBaseRelocRva() const + std::uint32_t PeHeaderT::getIddBaseRelocRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; } @@ -2195,7 +2195,7 @@ namespace PeLib * @return The size of the Base Reloc directory. **/ template - dword PeHeaderT::getIddBaseRelocSize() const + std::uint32_t PeHeaderT::getIddBaseRelocSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; } @@ -2205,7 +2205,7 @@ namespace PeLib * @return The Rva of the Debug directory. **/ template - dword PeHeaderT::getIddDebugRva() const + std::uint32_t PeHeaderT::getIddDebugRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; } @@ -2215,7 +2215,7 @@ namespace PeLib * @return The size of the Debug directory. **/ template - dword PeHeaderT::getIddDebugSize() const + std::uint32_t PeHeaderT::getIddDebugSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; } @@ -2225,7 +2225,7 @@ namespace PeLib * @return The Rva of the Architecture directory. **/ template - dword PeHeaderT::getIddArchitectureRva() const + std::uint32_t PeHeaderT::getIddArchitectureRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress; } @@ -2235,7 +2235,7 @@ namespace PeLib * @return The size of the Architecture directory. **/ template - dword PeHeaderT::getIddArchitectureSize() const + std::uint32_t PeHeaderT::getIddArchitectureSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size; } @@ -2245,7 +2245,7 @@ namespace PeLib * @return The Rva of the GlobalPtr directory. **/ template - dword PeHeaderT::getIddGlobalPtrRva() const + std::uint32_t PeHeaderT::getIddGlobalPtrRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress; } @@ -2255,7 +2255,7 @@ namespace PeLib * @return The size of the GlobalPtr directory. **/ template - dword PeHeaderT::getIddGlobalPtrSize() const + std::uint32_t PeHeaderT::getIddGlobalPtrSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size; } @@ -2265,7 +2265,7 @@ namespace PeLib * @return The Rva of the Tls directory. **/ template - dword PeHeaderT::getIddTlsRva() const + std::uint32_t PeHeaderT::getIddTlsRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; } @@ -2275,7 +2275,7 @@ namespace PeLib * @return The size of the Tls directory. **/ template - dword PeHeaderT::getIddTlsSize() const + std::uint32_t PeHeaderT::getIddTlsSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_TLS].Size; } @@ -2285,7 +2285,7 @@ namespace PeLib * @return The Rva of the LoadConfig directory. **/ template - dword PeHeaderT::getIddLoadConfigRva() const + std::uint32_t PeHeaderT::getIddLoadConfigRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress; } @@ -2295,7 +2295,7 @@ namespace PeLib * @return The size of the LoadConfig directory. **/ template - dword PeHeaderT::getIddLoadConfigSize() const + std::uint32_t PeHeaderT::getIddLoadConfigSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size; } @@ -2305,7 +2305,7 @@ namespace PeLib * @return The Rva of the BoundImport directory. **/ template - dword PeHeaderT::getIddBoundImportRva() const + std::uint32_t PeHeaderT::getIddBoundImportRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress; } @@ -2315,7 +2315,7 @@ namespace PeLib * @return The size of the BoundImport directory. **/ template - dword PeHeaderT::getIddBoundImportSize() const + std::uint32_t PeHeaderT::getIddBoundImportSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size; } @@ -2325,7 +2325,7 @@ namespace PeLib * @return The Rva of the IAT directory. **/ template - dword PeHeaderT::getIddIatRva() const + std::uint32_t PeHeaderT::getIddIatRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; } @@ -2335,7 +2335,7 @@ namespace PeLib * @return The size of the IAT directory. **/ template - dword PeHeaderT::getIddIatSize() const + std::uint32_t PeHeaderT::getIddIatSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IAT].Size; } @@ -2345,7 +2345,7 @@ namespace PeLib * @return The Rva of the DelayImport directory. **/ template - dword PeHeaderT::getIddDelayImportRva() const + std::uint32_t PeHeaderT::getIddDelayImportRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress; } @@ -2355,7 +2355,7 @@ namespace PeLib * @return The size of the DelayImport directory. **/ template - dword PeHeaderT::getIddDelayImportSize() const + std::uint32_t PeHeaderT::getIddDelayImportSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size; } @@ -2365,7 +2365,7 @@ namespace PeLib * @return The Rva of the COM Descriptor directory. **/ template - dword PeHeaderT::getIddComHeaderRva() const + std::uint32_t PeHeaderT::getIddComHeaderRva() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress; } @@ -2375,7 +2375,7 @@ namespace PeLib * @return The Rva of the COM Descriptor directory. **/ template - dword PeHeaderT::getIddComHeaderSize() const + std::uint32_t PeHeaderT::getIddComHeaderSize() const { return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; } @@ -2386,13 +2386,13 @@ namespace PeLib * @return The Rva of the image directory. **/ template - dword PeHeaderT::getImageDataDirectoryRva(dword dwDirectory) const + std::uint32_t PeHeaderT::getImageDataDirectoryRva(std::uint32_t dwDirectory) const { return m_inthHeader.dataDirectories[dwDirectory].VirtualAddress; } template - void PeHeaderT::setImageDataDirectoryRva(dword dwDirectory, dword value) + void PeHeaderT::setImageDataDirectoryRva(std::uint32_t dwDirectory, std::uint32_t value) { m_inthHeader.dataDirectories[dwDirectory].VirtualAddress = value; } @@ -2403,13 +2403,13 @@ namespace PeLib * @return The size of the image directory. **/ template - dword PeHeaderT::getImageDataDirectorySize(dword dwDirectory) const + std::uint32_t PeHeaderT::getImageDataDirectorySize(std::uint32_t dwDirectory) const { return m_inthHeader.dataDirectories[dwDirectory].Size; } template - void PeHeaderT::setImageDataDirectorySize(dword dwDirectory, dword value) + void PeHeaderT::setImageDataDirectorySize(std::uint32_t dwDirectory, std::uint32_t value) { m_inthHeader.dataDirectories[dwDirectory].Size = value; } @@ -2420,7 +2420,7 @@ namespace PeLib * @return The name of the section. **/ template - std::string PeHeaderT::getSectionName(word wSectionnr) const + std::string PeHeaderT::getSectionName(std::uint16_t wSectionnr) const { std::string sectionName = ""; @@ -2433,7 +2433,7 @@ namespace PeLib } template - std::string PeHeaderT::getSectionNameFromStringTable(word wSectionnr) const + std::string PeHeaderT::getSectionNameFromStringTable(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].StringTableName; } @@ -2444,7 +2444,7 @@ namespace PeLib * @return The virtual size of the section. **/ template - dword PeHeaderT::getVirtualSize(word wSectionnr) const + std::uint32_t PeHeaderT::getVirtualSize(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].VirtualSize; } @@ -2455,7 +2455,7 @@ namespace PeLib * @return The Rva of the section. **/ template - dword PeHeaderT::getVirtualAddress(word wSectionnr) const + std::uint32_t PeHeaderT::getVirtualAddress(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].VirtualAddress; } @@ -2466,7 +2466,7 @@ namespace PeLib * @return The size of raw data of the section. **/ template - dword PeHeaderT::getSizeOfRawData(word wSectionnr) const + std::uint32_t PeHeaderT::getSizeOfRawData(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].SizeOfRawData; } @@ -2477,7 +2477,7 @@ namespace PeLib * @return The file offset of the section. **/ template - dword PeHeaderT::getPointerToRawData(word wSectionnr) const + std::uint32_t PeHeaderT::getPointerToRawData(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].PointerToRawData; } @@ -2488,7 +2488,7 @@ namespace PeLib * @return The pointer to relocations of the section. **/ template - dword PeHeaderT::getPointerToRelocations(word wSectionnr) const + std::uint32_t PeHeaderT::getPointerToRelocations(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].PointerToRelocations; } @@ -2499,7 +2499,7 @@ namespace PeLib * @return The pointer to line numbers of the section. **/ template - dword PeHeaderT::getPointerToLinenumbers(word wSectionnr) const + std::uint32_t PeHeaderT::getPointerToLinenumbers(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].PointerToLinenumbers; } @@ -2510,7 +2510,7 @@ namespace PeLib * @return The number of relocations of the section. **/ template - dword PeHeaderT::getNumberOfRelocations(word wSectionnr) const + std::uint32_t PeHeaderT::getNumberOfRelocations(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].NumberOfRelocations; } @@ -2521,7 +2521,7 @@ namespace PeLib * @return The number of line numbers of the section. **/ template - dword PeHeaderT::getNumberOfLinenumbers(word wSectionnr) const + std::uint32_t PeHeaderT::getNumberOfLinenumbers(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].NumberOfLinenumbers; } @@ -2532,7 +2532,7 @@ namespace PeLib * @return The characteristics of the section. **/ template - dword PeHeaderT::getCharacteristics(word wSectionnr) const + std::uint32_t PeHeaderT::getCharacteristics(std::uint16_t wSectionnr) const { return m_vIsh[wSectionnr].Characteristics; } @@ -2542,7 +2542,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setNtSignature(dword dwValue) + void PeHeaderT::setNtSignature(std::uint32_t dwValue) { m_inthHeader.Signature = dwValue; } @@ -2552,7 +2552,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setMachine(word wValue) + void PeHeaderT::setMachine(std::uint16_t wValue) { m_inthHeader.FileHeader.Machine = wValue; } @@ -2562,7 +2562,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setNumberOfSections(word wValue) + void PeHeaderT::setNumberOfSections(std::uint16_t wValue) { m_inthHeader.FileHeader.NumberOfSections = wValue; } @@ -2572,7 +2572,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setTimeDateStamp(dword dwValue) + void PeHeaderT::setTimeDateStamp(std::uint32_t dwValue) { m_inthHeader.FileHeader.TimeDateStamp = dwValue; } @@ -2582,7 +2582,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setPointerToSymbolTable(dword dwValue) + void PeHeaderT::setPointerToSymbolTable(std::uint32_t dwValue) { m_inthHeader.FileHeader.PointerToSymbolTable = dwValue; } @@ -2592,7 +2592,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setNumberOfSymbols(dword dwValue) + void PeHeaderT::setNumberOfSymbols(std::uint32_t dwValue) { m_inthHeader.FileHeader.NumberOfSymbols = dwValue; } @@ -2602,7 +2602,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setSizeOfOptionalHeader(word wValue) + void PeHeaderT::setSizeOfOptionalHeader(std::uint16_t wValue) { m_inthHeader.FileHeader.SizeOfOptionalHeader = wValue; } @@ -2612,7 +2612,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setCharacteristics(word wValue) + void PeHeaderT::setCharacteristics(std::uint16_t wValue) { m_inthHeader.FileHeader.Characteristics = wValue; } @@ -2622,7 +2622,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setMagic(word wValue) + void PeHeaderT::setMagic(std::uint16_t wValue) { m_inthHeader.OptionalHeader.Magic = wValue; } @@ -2632,7 +2632,7 @@ namespace PeLib * @param bValue New value. **/ template - void PeHeaderT::setMajorLinkerVersion(byte bValue) + void PeHeaderT::setMajorLinkerVersion(std::uint8_t bValue) { m_inthHeader.OptionalHeader.MajorLinkerVersion = bValue; } @@ -2642,7 +2642,7 @@ namespace PeLib * @param bValue New value. **/ template - void PeHeaderT::setMinorLinkerVersion(byte bValue) + void PeHeaderT::setMinorLinkerVersion(std::uint8_t bValue) { m_inthHeader.OptionalHeader.MinorLinkerVersion = bValue; } @@ -2652,7 +2652,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setSizeOfCode(dword dwValue) + void PeHeaderT::setSizeOfCode(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.SizeOfCode = dwValue; } @@ -2662,7 +2662,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setSizeOfInitializedData(dword dwValue) + void PeHeaderT::setSizeOfInitializedData(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.SizeOfInitializedData = dwValue; } @@ -2672,7 +2672,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setSizeOfUninitializedData(dword dwValue) + void PeHeaderT::setSizeOfUninitializedData(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.SizeOfUninitializedData = dwValue; } @@ -2682,7 +2682,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setAddressOfEntryPoint(dword dwValue) + void PeHeaderT::setAddressOfEntryPoint(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.AddressOfEntryPoint = dwValue; } @@ -2692,7 +2692,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setBaseOfCode(dword dwValue) + void PeHeaderT::setBaseOfCode(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.BaseOfCode = dwValue; } @@ -2712,7 +2712,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setSectionAlignment(dword dwValue) + void PeHeaderT::setSectionAlignment(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.SectionAlignment = dwValue; } @@ -2722,7 +2722,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setFileAlignment(dword dwValue) + void PeHeaderT::setFileAlignment(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.FileAlignment = dwValue; } @@ -2732,7 +2732,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setMajorOperatingSystemVersion(word wValue) + void PeHeaderT::setMajorOperatingSystemVersion(std::uint16_t wValue) { m_inthHeader.OptionalHeader.MajorOperatingSystemVersion = wValue; } @@ -2742,7 +2742,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setMinorOperatingSystemVersion(word wValue) + void PeHeaderT::setMinorOperatingSystemVersion(std::uint16_t wValue) { m_inthHeader.OptionalHeader.MinorOperatingSystemVersion = wValue; } @@ -2752,7 +2752,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setMajorImageVersion(word wValue) + void PeHeaderT::setMajorImageVersion(std::uint16_t wValue) { m_inthHeader.OptionalHeader.MajorImageVersion = wValue; } @@ -2762,7 +2762,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setMinorImageVersion(word wValue) + void PeHeaderT::setMinorImageVersion(std::uint16_t wValue) { m_inthHeader.OptionalHeader.MinorImageVersion = wValue; } @@ -2772,7 +2772,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setMajorSubsystemVersion(word wValue) + void PeHeaderT::setMajorSubsystemVersion(std::uint16_t wValue) { m_inthHeader.OptionalHeader.MajorSubsystemVersion = wValue; } @@ -2782,7 +2782,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setMinorSubsystemVersion(word wValue) + void PeHeaderT::setMinorSubsystemVersion(std::uint16_t wValue) { m_inthHeader.OptionalHeader.MinorSubsystemVersion = wValue; } @@ -2792,7 +2792,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setWin32VersionValue(dword dwValue) + void PeHeaderT::setWin32VersionValue(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.Win32VersionValue = dwValue; } @@ -2802,7 +2802,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setSizeOfImage(dword dwValue) + void PeHeaderT::setSizeOfImage(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.SizeOfImage = dwValue; } @@ -2812,7 +2812,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setSizeOfHeaders(dword dwValue) + void PeHeaderT::setSizeOfHeaders(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.SizeOfHeaders = dwValue; } @@ -2822,7 +2822,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setCheckSum(dword dwValue) + void PeHeaderT::setCheckSum(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.CheckSum = dwValue; } @@ -2832,7 +2832,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setSubsystem(word wValue) + void PeHeaderT::setSubsystem(std::uint16_t wValue) { m_inthHeader.OptionalHeader.Subsystem = wValue; } @@ -2842,7 +2842,7 @@ namespace PeLib * @param wValue New value. **/ template - void PeHeaderT::setDllCharacteristics(word wValue) + void PeHeaderT::setDllCharacteristics(std::uint16_t wValue) { m_inthHeader.OptionalHeader.DllCharacteristics = wValue; } @@ -2892,7 +2892,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setLoaderFlags(dword dwValue) + void PeHeaderT::setLoaderFlags(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.LoaderFlags = dwValue; } @@ -2902,115 +2902,115 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setNumberOfRvaAndSizes(dword dwValue) + void PeHeaderT::setNumberOfRvaAndSizes(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.NumberOfRvaAndSizes = dwValue; } template - void PeHeaderT::setIddDebugRva(dword dwValue) + void PeHeaderT::setIddDebugRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = dwValue; } template - void PeHeaderT::setIddDebugSize(dword dwValue) + void PeHeaderT::setIddDebugSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = dwValue; } template - void PeHeaderT::setIddDelayImportRva(dword dwValue) + void PeHeaderT::setIddDelayImportRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = dwValue; } template - void PeHeaderT::setIddDelayImportSize(dword dwValue) + void PeHeaderT::setIddDelayImportSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = dwValue; } template - void PeHeaderT::setIddExceptionRva(dword dwValue) + void PeHeaderT::setIddExceptionRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = dwValue; } template - void PeHeaderT::setIddExceptionSize(dword dwValue) + void PeHeaderT::setIddExceptionSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = dwValue; } template - void PeHeaderT::setIddGlobalPtrRva(dword dwValue) + void PeHeaderT::setIddGlobalPtrRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress = dwValue; } template - void PeHeaderT::setIddGlobalPtrSize(dword dwValue) + void PeHeaderT::setIddGlobalPtrSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size = dwValue; } template - void PeHeaderT::setIddIatRva(dword dwValue) + void PeHeaderT::setIddIatRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dwValue; } template - void PeHeaderT::setIddIatSize(dword dwValue) + void PeHeaderT::setIddIatSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IAT].Size = dwValue; } template - void PeHeaderT::setIddLoadConfigRva(dword dwValue) + void PeHeaderT::setIddLoadConfigRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = dwValue; } template - void PeHeaderT::setIddLoadConfigSize(dword dwValue) + void PeHeaderT::setIddLoadConfigSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = dwValue; } template - void PeHeaderT::setIddResourceRva(dword dwValue) + void PeHeaderT::setIddResourceRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = dwValue; } template - void PeHeaderT::setIddResourceSize(dword dwValue) + void PeHeaderT::setIddResourceSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = dwValue; } template - void PeHeaderT::setIddSecurityRva(dword dwValue) + void PeHeaderT::setIddSecurityRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = dwValue; } template - void PeHeaderT::setIddSecuritySize(dword dwValue) + void PeHeaderT::setIddSecuritySize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY].Size = dwValue; } template - void PeHeaderT::setIddTlsRva(dword dwValue) + void PeHeaderT::setIddTlsRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = dwValue; } template - void PeHeaderT::setIddTlsSize(dword dwValue) + void PeHeaderT::setIddTlsSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_TLS].Size = dwValue; } @@ -3020,7 +3020,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setIddExportRva(dword dwValue) + void PeHeaderT::setIddExportRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = dwValue; } @@ -3030,43 +3030,43 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setIddExportSize(dword dwValue) + void PeHeaderT::setIddExportSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT].Size = dwValue; } template - void PeHeaderT::setIddBaseRelocRva(dword value) + void PeHeaderT::setIddBaseRelocRva(std::uint32_t value) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = value; } template - void PeHeaderT::setIddBaseRelocSize(dword value) + void PeHeaderT::setIddBaseRelocSize(std::uint32_t value) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = value; } template - void PeHeaderT::setIddArchitectureRva(dword value) + void PeHeaderT::setIddArchitectureRva(std::uint32_t value) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress = value; } template - void PeHeaderT::setIddArchitectureSize(dword value) + void PeHeaderT::setIddArchitectureSize(std::uint32_t value) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size = value; } template - void PeHeaderT::setIddComHeaderRva(dword value) + void PeHeaderT::setIddComHeaderRva(std::uint32_t value) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = value; } template - void PeHeaderT::setIddComHeaderSize(dword value) + void PeHeaderT::setIddComHeaderSize(std::uint32_t value) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = value; } @@ -3076,7 +3076,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setIddImportRva(dword dwValue) + void PeHeaderT::setIddImportRva(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = dwValue; } @@ -3086,7 +3086,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setIddImportSize(dword dwValue) + void PeHeaderT::setIddImportSize(std::uint32_t dwValue) { m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT].Size = dwValue; } @@ -3097,7 +3097,7 @@ namespace PeLib * @param strName New name. **/ template - void PeHeaderT::setSectionName(word wSectionnr, std::string strName) + void PeHeaderT::setSectionName(std::uint16_t wSectionnr, std::string strName) { strncpy(reinterpret_cast(m_vIsh[wSectionnr].Name), strName.c_str(), sizeof(m_vIsh[wSectionnr].Name)); } @@ -3108,7 +3108,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setVirtualSize(word wSectionnr, dword dwValue) + void PeHeaderT::setVirtualSize(std::uint16_t wSectionnr, std::uint32_t dwValue) { m_vIsh[wSectionnr].VirtualSize = dwValue; } @@ -3119,7 +3119,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setVirtualAddress(word wSectionnr, dword dwValue) + void PeHeaderT::setVirtualAddress(std::uint16_t wSectionnr, std::uint32_t dwValue) { m_vIsh[wSectionnr].VirtualAddress = dwValue; } @@ -3130,7 +3130,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setSizeOfRawData(word wSectionnr, dword dwValue) + void PeHeaderT::setSizeOfRawData(std::uint16_t wSectionnr, std::uint32_t dwValue) { m_vIsh[wSectionnr].SizeOfRawData = dwValue; } @@ -3141,7 +3141,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setPointerToRawData(word wSectionnr, dword dwValue) + void PeHeaderT::setPointerToRawData(std::uint16_t wSectionnr, std::uint32_t dwValue) { m_vIsh[wSectionnr].PointerToRawData = dwValue; } @@ -3152,7 +3152,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setPointerToRelocations(word wSectionnr, dword dwValue) + void PeHeaderT::setPointerToRelocations(std::uint16_t wSectionnr, std::uint32_t dwValue) { m_vIsh[wSectionnr].PointerToRelocations = dwValue; } @@ -3163,7 +3163,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setPointerToLinenumbers(word wSectionnr, dword dwValue) + void PeHeaderT::setPointerToLinenumbers(std::uint16_t wSectionnr, std::uint32_t dwValue) { m_vIsh[wSectionnr].PointerToLinenumbers = dwValue; } @@ -3174,7 +3174,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setNumberOfRelocations(word wSectionnr, dword dwValue) + void PeHeaderT::setNumberOfRelocations(std::uint16_t wSectionnr, std::uint32_t dwValue) { m_vIsh[wSectionnr].NumberOfRelocations = dwValue; } @@ -3185,7 +3185,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setNumberOfLinenumbers(word wSectionnr, dword dwValue) + void PeHeaderT::setNumberOfLinenumbers(std::uint16_t wSectionnr, std::uint32_t dwValue) { m_vIsh[wSectionnr].NumberOfLinenumbers = dwValue; } @@ -3196,7 +3196,7 @@ namespace PeLib * @param dwValue New value. **/ template - void PeHeaderT::setCharacteristics(word wSectionnr, dword dwValue) + void PeHeaderT::setCharacteristics(std::uint16_t wSectionnr, std::uint32_t dwValue) { m_vIsh[wSectionnr].Characteristics = dwValue; } diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index 34af2ced8..ec03676ca 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -129,111 +129,37 @@ namespace PeLib class PeFile; -// It's necessary to make sure that a byte has 8 bits and that the platform has a 8 bit type, -// a 16bit type and a bit type. That's because binary PE files are pretty picky about their -// structure. - - #if CHAR_BIT == 8 - #if UCHAR_MAX == 255 - typedef unsigned char byte; - // typedef std::bitset<8> byte; - #else - #error You need to change some typedefs (Code: 8). Please read the PeLib documentation. - #endif - - #if USHRT_MAX == 65535U - typedef unsigned short word; - // typedef std::bitset<16> word; - #else - #error You need to change some typedefs (Code: 16). Please read the PeLib documentation. - #endif - - #if UINT_MAX == 4294967295UL - typedef unsigned int dword; - // typedef std::bitset<32> dword; - #else - #error You need to change some typedefs (Code: 32). Please read the PeLib documentation. - #endif - - typedef unsigned long long qword; - -// #if ULLONG_MAX == 18446744073709551615 -// typedef unsigned long long qword; -// #else -// #error You need to change some typedefs (Code: 32). Please read the PeLib documentation. -// #endif - #else - #error You need to change some typedefs. Please read the PeLib documentation. - #endif - -/* enum bits {BITS_BYTE = 8, BITS_WORD = 16, BITS_DWORD = 32}; - - template - class DataType - { - private: - std::bitset bsValue; - unsigned long ulValue; + typedef std::vector ByteBuffer; - public: - void operator=(unsigned long ulValue) - { - bsValue = ulValue; - } - - operator unsigned long() const - { - return bsValue.to_ulong(); - } - - const int operator&() - { - ulValue = bsValue; - return ulValue; - } + enum {PEFILE32 = 32, + PEFILE64 = 64, + PEFILE_UNKNOWN = 0}; - }; + const std::uint16_t PELIB_IMAGE_DOS_SIGNATURE = 0x5A4D; - typedef DataType byte; - typedef DataType word; - typedef DataType dword; -*/ + const std::uint32_t PELIB_PAGE_SIZE = 0x1000; - enum {PEFILE32 = 32, - PEFILE64 = 64, - PEFILE_UNKNOWN = 0}; - - enum {BoundImportDirectoryId = 1, - ComHeaderDirectoryId, - ExportDirectoryId, - IatDirectoryId, - ImportDirectoryId, - MzHeaderId, - PeHeaderId, - RelocationsId, - PeFileId, - ResourceDirectoryId, - DebugDirectoryId, - TlsDirectoryId - }; + const std::uint32_t PELIB_PAGE_SIZE_SHIFT = 12; - const word PELIB_IMAGE_DOS_SIGNATURE = 0x5A4D; + const std::uint32_t PELIB_SIZE_64KB = 0x10000; - const dword PELIB_PAGE_SIZE = 0x1000; + const std::uint32_t PELIB_IMAGE_NT_SIGNATURE = 0x00004550; - const dword PELIB_PAGE_SIZE_SHIFT = 12; + const std::uint32_t PELIB_MM_SIZE_OF_LARGEST_IMAGE = 0x77000000; - const dword PELIB_SIZE_64KB = 0x10000; + const std::uint32_t PELIB_MAX_IMPORT_DLLS = 0x100; // Maximum number of imported DLLs we consider OK + const std::uint32_t PELIB_MAX_IMPORTED_FUNCTIONS = 0x1000; // Maximum number of exported functions (per DLL) that we support + const std::uint32_t PELIB_MAX_EXPORTED_FUNCTIONS = 0x1000; // Maximum number of exported functions that we support + const std::uint32_t PE_MAX_SECTION_COUNT_XP = 96; + const std::uint32_t PE_MAX_SECTION_COUNT_7 = 192; - const dword PELIB_IMAGE_NT_SIGNATURE = 0x00004550; + const std::uint32_t PELIB_SECTOR_SIZE = 0x200; - const dword PELIB_MM_SIZE_OF_LARGEST_IMAGE = 0x77000000; + const std::uint32_t PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; - const dword PELIB_MAX_IMPORT_DLLS = 0x100; // Maximum number of imported DLLs we consider OK - const dword PELIB_MAX_IMPORTED_FUNCTIONS = 0x1000; // Maximum number of exported functions (per DLL) that we support - const dword PELIB_MAX_EXPORTED_FUNCTIONS = 0x1000; // Maximum number of exported functions that we support + const std::uint32_t PELIB_IMAGE_RESOURCE_NAME_IS_STRING = 0x80000000; - const dword PELIB_SECTOR_SIZE = 0x200; + const std::uint32_t PELIB_IMAGE_RESOURCE_DATA_IS_DIRECTORY = 0x80000000; template struct PELIB_IMAGE_ORDINAL_FLAGS; @@ -241,21 +167,15 @@ namespace PeLib template<> struct PELIB_IMAGE_ORDINAL_FLAGS<32> { - static const dword PELIB_IMAGE_ORDINAL_FLAG = 0x80000000; + static const std::uint32_t PELIB_IMAGE_ORDINAL_FLAG = 0x80000000; }; template<> struct PELIB_IMAGE_ORDINAL_FLAGS<64> { - static const qword PELIB_IMAGE_ORDINAL_FLAG; + static const std::uint64_t PELIB_IMAGE_ORDINAL_FLAG; }; - const unsigned long PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; - - const unsigned long PELIB_IMAGE_RESOURCE_NAME_IS_STRING = 0x80000000; - - const unsigned long PELIB_IMAGE_RESOURCE_DATA_IS_DIRECTORY = 0x80000000; - enum { PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT, // OK @@ -275,7 +195,19 @@ namespace PeLib PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR }; - enum : unsigned long long + enum : std::uint32_t + { + PELIB_PAGE_NOACCESS = 0x01, + PELIB_PAGE_READONLY = 0x02, + PELIB_PAGE_READWRITE = 0x04, + PELIB_PAGE_WRITECOPY = 0x08, + PELIB_PAGE_EXECUTE = 0x10, + PELIB_PAGE_EXECUTE_READ = 0x20, + PELIB_PAGE_EXECUTE_READWRITE = 0x40, + PELIB_PAGE_EXECUTE_WRITECOPY = 0x80, + }; + + enum : std::uint32_t { PELIB_IMAGE_SCN_TYPE_NO_PAD = 0x00000008, PELIB_IMAGE_SCN_CNT_CODE = 0x00000020, @@ -355,58 +287,6 @@ namespace PeLib PELIB_IMAGE_FILE_MACHINE_MSIL = 0xC0EE }; - class PELIB_IMAGE_FILE_MACHINE_ITERATOR - { - public: - typedef std::vector::const_iterator imageFileMachineIterator; - private: - const std::vector all = - { - PELIB_IMAGE_FILE_MACHINE_UNKNOWN, - PELIB_IMAGE_FILE_MACHINE_I386, - PELIB_IMAGE_FILE_MACHINE_I486, - PELIB_IMAGE_FILE_MACHINE_PENTIUM, - PELIB_IMAGE_FILE_MACHINE_R3000_BIG, - PELIB_IMAGE_FILE_MACHINE_R3000_LITTLE, - PELIB_IMAGE_FILE_MACHINE_R4000, - PELIB_IMAGE_FILE_MACHINE_R10000, - PELIB_IMAGE_FILE_MACHINE_WCEMIPSV2, - PELIB_IMAGE_FILE_MACHINE_ALPHA, - PELIB_IMAGE_FILE_MACHINE_SH3, - PELIB_IMAGE_FILE_MACHINE_SH3DSP, - PELIB_IMAGE_FILE_MACHINE_SH3E, - PELIB_IMAGE_FILE_MACHINE_SH4, - PELIB_IMAGE_FILE_MACHINE_SH5, - PELIB_IMAGE_FILE_MACHINE_ARM, - PELIB_IMAGE_FILE_MACHINE_THUMB, - PELIB_IMAGE_FILE_MACHINE_ARMNT, - PELIB_IMAGE_FILE_MACHINE_AM33, - PELIB_IMAGE_FILE_MACHINE_POWERPC, - PELIB_IMAGE_FILE_MACHINE_POWERPCFP, - PELIB_IMAGE_FILE_MACHINE_IA64, - PELIB_IMAGE_FILE_MACHINE_MIPS16, - PELIB_IMAGE_FILE_MACHINE_MOTOROLA68000, - PELIB_IMAGE_FILE_MACHINE_PARISC, - PELIB_IMAGE_FILE_MACHINE_ALPHA64, - PELIB_IMAGE_FILE_MACHINE_AXP64, - PELIB_IMAGE_FILE_MACHINE_MIPSFPU, - PELIB_IMAGE_FILE_MACHINE_MIPSFPU16, - PELIB_IMAGE_FILE_MACHINE_TRICORE, - PELIB_IMAGE_FILE_MACHINE_EBC, - PELIB_IMAGE_FILE_MACHINE_AMD64, - PELIB_IMAGE_FILE_MACHINE_M32R, - PELIB_IMAGE_FILE_MACHINE_ARM64, - PELIB_IMAGE_FILE_MACHINE_MSIL - }; - public: - PELIB_IMAGE_FILE_MACHINE_ITERATOR(); - ~PELIB_IMAGE_FILE_MACHINE_ITERATOR(); - - bool isValidMachineCode(PELIB_IMAGE_FILE_MACHINE value) const; - imageFileMachineIterator begin() const; - imageFileMachineIterator end() const; - }; - enum { PELIB_IMAGE_FILE_RELOCS_STRIPPED = 0x0001, @@ -434,7 +314,9 @@ namespace PeLib PELIB_IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200, PELIB_IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400, PELIB_IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800, + PELIB_IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000, PELIB_IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000, + PELIB_IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000, PELIB_IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000 }; @@ -628,42 +510,100 @@ namespace PeLib return size + v.size(); } + class PELIB_IMAGE_FILE_MACHINE_ITERATOR + { + public: + typedef std::vector::const_iterator imageFileMachineIterator; + private: + const std::vector all = + { + PELIB_IMAGE_FILE_MACHINE_UNKNOWN, + PELIB_IMAGE_FILE_MACHINE_I386, + PELIB_IMAGE_FILE_MACHINE_I486, + PELIB_IMAGE_FILE_MACHINE_PENTIUM, + PELIB_IMAGE_FILE_MACHINE_R3000_BIG, + PELIB_IMAGE_FILE_MACHINE_R3000_LITTLE, + PELIB_IMAGE_FILE_MACHINE_R4000, + PELIB_IMAGE_FILE_MACHINE_R10000, + PELIB_IMAGE_FILE_MACHINE_WCEMIPSV2, + PELIB_IMAGE_FILE_MACHINE_ALPHA, + PELIB_IMAGE_FILE_MACHINE_SH3, + PELIB_IMAGE_FILE_MACHINE_SH3DSP, + PELIB_IMAGE_FILE_MACHINE_SH3E, + PELIB_IMAGE_FILE_MACHINE_SH4, + PELIB_IMAGE_FILE_MACHINE_SH5, + PELIB_IMAGE_FILE_MACHINE_ARM, + PELIB_IMAGE_FILE_MACHINE_THUMB, + PELIB_IMAGE_FILE_MACHINE_ARMNT, + PELIB_IMAGE_FILE_MACHINE_AM33, + PELIB_IMAGE_FILE_MACHINE_POWERPC, + PELIB_IMAGE_FILE_MACHINE_POWERPCFP, + PELIB_IMAGE_FILE_MACHINE_IA64, + PELIB_IMAGE_FILE_MACHINE_MIPS16, + PELIB_IMAGE_FILE_MACHINE_MOTOROLA68000, + PELIB_IMAGE_FILE_MACHINE_PARISC, + PELIB_IMAGE_FILE_MACHINE_ALPHA64, + PELIB_IMAGE_FILE_MACHINE_AXP64, + PELIB_IMAGE_FILE_MACHINE_MIPSFPU, + PELIB_IMAGE_FILE_MACHINE_MIPSFPU16, + PELIB_IMAGE_FILE_MACHINE_TRICORE, + PELIB_IMAGE_FILE_MACHINE_EBC, + PELIB_IMAGE_FILE_MACHINE_AMD64, + PELIB_IMAGE_FILE_MACHINE_M32R, + PELIB_IMAGE_FILE_MACHINE_ARM64, + PELIB_IMAGE_FILE_MACHINE_MSIL + }; + public: + PELIB_IMAGE_FILE_MACHINE_ITERATOR(); + ~PELIB_IMAGE_FILE_MACHINE_ITERATOR(); + + bool isValidMachineCode(PELIB_IMAGE_FILE_MACHINE value) const; + imageFileMachineIterator begin() const; + imageFileMachineIterator end() const; + }; + struct PELIB_IMAGE_DOS_HEADER { - word e_magic; - word e_cblp; - word e_cp; - word e_crlc; - word e_cparhdr; - word e_minalloc; - word e_maxalloc; - word e_ss; - word e_sp; - word e_csum; - word e_ip; - word e_cs; - word e_lfarlc; - word e_ovno; - word e_res[4]; - word e_oemid; - word e_oeminfo; - word e_res2[10]; - dword e_lfanew; - - PELIB_IMAGE_DOS_HEADER(); - - static inline unsigned int size() {return 64;} + std::uint16_t e_magic; + std::uint16_t e_cblp; + std::uint16_t e_cp; + std::uint16_t e_crlc; + std::uint16_t e_cparhdr; + std::uint16_t e_minalloc; + std::uint16_t e_maxalloc; + std::uint16_t e_ss; + std::uint16_t e_sp; + std::uint16_t e_csum; + std::uint16_t e_ip; + std::uint16_t e_cs; + std::uint16_t e_lfarlc; + std::uint16_t e_ovno; + std::uint16_t e_res[4]; + std::uint16_t e_oemid; + std::uint16_t e_oeminfo; + std::uint16_t e_res2[10]; + std::uint32_t e_lfanew; + + PELIB_IMAGE_DOS_HEADER() + { + memset(this, 0, sizeof(PELIB_IMAGE_DOS_HEADER)); + } + + static inline std::size_t size() + { + return 64; + } }; struct PELIB_IMAGE_FILE_HEADER { - word Machine; - word NumberOfSections; - dword TimeDateStamp; - dword PointerToSymbolTable; - dword NumberOfSymbols; - word SizeOfOptionalHeader; - word Characteristics; + std::uint16_t Machine; + std::uint16_t NumberOfSections; + std::uint32_t TimeDateStamp; + std::uint32_t PointerToSymbolTable; + std::uint32_t NumberOfSymbols; + std::uint16_t SizeOfOptionalHeader; + std::uint16_t Characteristics; PELIB_IMAGE_FILE_HEADER() { @@ -676,13 +616,16 @@ namespace PeLib Characteristics = 0; } - static inline unsigned int size() {return 20;} + static inline std::size_t size() + { + return 20; + } }; struct PELIB_IMAGE_DATA_DIRECTORY { - dword VirtualAddress; - dword Size; + std::uint32_t VirtualAddress; + std::uint32_t Size; PELIB_IMAGE_DATA_DIRECTORY() { @@ -690,7 +633,7 @@ namespace PeLib Size = 0; } - static inline unsigned int size() {return 8;} + static inline std::size_t size() {return 8;} }; template @@ -699,136 +642,142 @@ namespace PeLib template<> struct FieldSizes<32> { - typedef dword VAR4_8; + typedef std::uint32_t VAR4_8; }; template<> struct FieldSizes<64> { - typedef qword VAR4_8; + typedef std::uint64_t VAR4_8; }; - template - struct PELIB_IMAGE_OPTIONAL_HEADER_BASE + struct PELIB_IMAGE_OPTIONAL_HEADER32 { - typedef typename FieldSizes::VAR4_8 VAR4_8; - - word Magic; - byte MajorLinkerVersion; - byte MinorLinkerVersion; - dword SizeOfCode; - dword SizeOfInitializedData; - dword SizeOfUninitializedData; - dword AddressOfEntryPoint; - dword BaseOfCode; - dword BaseOfData; - VAR4_8 ImageBase; - dword SectionAlignment; - dword FileAlignment; - word MajorOperatingSystemVersion; - word MinorOperatingSystemVersion; - word MajorImageVersion; - word MinorImageVersion; - word MajorSubsystemVersion; - word MinorSubsystemVersion; - dword Win32VersionValue; - dword SizeOfImage; - dword SizeOfHeaders; - dword CheckSum; - word Subsystem; - word DllCharacteristics; - VAR4_8 SizeOfStackReserve; - VAR4_8 SizeOfStackCommit; - VAR4_8 SizeOfHeapReserve; - VAR4_8 SizeOfHeapCommit; - dword LoaderFlags; - dword NumberOfRvaAndSizes; -// PELIB_IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - - PELIB_IMAGE_OPTIONAL_HEADER_BASE(); + std::uint16_t Magic; + std::uint8_t MajorLinkerVersion; + std::uint8_t MinorLinkerVersion; + std::uint32_t SizeOfCode; + std::uint32_t SizeOfInitializedData; + std::uint32_t SizeOfUninitializedData; + std::uint32_t AddressOfEntryPoint; + std::uint32_t BaseOfCode; + std::uint32_t BaseOfData; + std::uint32_t ImageBase; + std::uint32_t SectionAlignment; + std::uint32_t FileAlignment; + std::uint16_t MajorOperatingSystemVersion; + std::uint16_t MinorOperatingSystemVersion; + std::uint16_t MajorImageVersion; + std::uint16_t MinorImageVersion; + std::uint16_t MajorSubsystemVersion; + std::uint16_t MinorSubsystemVersion; + std::uint32_t Win32VersionValue; + std::uint32_t SizeOfImage; + std::uint32_t SizeOfHeaders; + std::uint32_t CheckSum; + std::uint16_t Subsystem; + std::uint16_t DllCharacteristics; + std::uint32_t SizeOfStackReserve; + std::uint32_t SizeOfStackCommit; + std::uint32_t SizeOfHeapReserve; + std::uint32_t SizeOfHeapCommit; + std::uint32_t LoaderFlags; + std::uint32_t NumberOfRvaAndSizes; + + PELIB_IMAGE_DATA_DIRECTORY DataDirectory[PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; }; - template - PELIB_IMAGE_OPTIONAL_HEADER_BASE::PELIB_IMAGE_OPTIONAL_HEADER_BASE() + struct PELIB_IMAGE_OPTIONAL_HEADER64 { - Magic = 0; - MajorLinkerVersion = 0; - MinorLinkerVersion = 0; - SizeOfCode = 0; - SizeOfInitializedData = 0; - SizeOfUninitializedData = 0; - AddressOfEntryPoint = 0; - BaseOfCode = 0; -// BaseOfData = 0; - ImageBase = 0; - SectionAlignment = 0; - FileAlignment = 0; - MajorOperatingSystemVersion = 0; - MinorOperatingSystemVersion = 0; - MajorImageVersion = 0; - MinorImageVersion = 0; - MajorSubsystemVersion = 0; - MinorSubsystemVersion = 0; - Win32VersionValue = 0; - SizeOfImage = 0; - SizeOfHeaders = 0; - CheckSum = 0; - Subsystem = 0; - DllCharacteristics = 0; - SizeOfStackReserve = 0; - SizeOfStackCommit = 0; - SizeOfHeapReserve = 0; - SizeOfHeapCommit = 0; - LoaderFlags = 0; - NumberOfRvaAndSizes = 0; - } - - template - struct PELIB_IMAGE_OPTIONAL_HEADER; - - template<> - struct PELIB_IMAGE_OPTIONAL_HEADER<32> : public PELIB_IMAGE_OPTIONAL_HEADER_BASE<32> - { - dword BaseOfData; - - static inline unsigned int size() {return 224 - 0x10 * 8;} - - PELIB_IMAGE_OPTIONAL_HEADER<32>() : PELIB_IMAGE_OPTIONAL_HEADER_BASE<32>(), BaseOfData(0) - { - - } + std::uint16_t Magic; + std::uint8_t MajorLinkerVersion; + std::uint8_t MinorLinkerVersion; + std::uint32_t SizeOfCode; + std::uint32_t SizeOfInitializedData; + std::uint32_t SizeOfUninitializedData; + std::uint32_t AddressOfEntryPoint; + std::uint32_t BaseOfCode; + std::uint64_t ImageBase; + std::uint32_t SectionAlignment; + std::uint32_t FileAlignment; + std::uint16_t MajorOperatingSystemVersion; + std::uint16_t MinorOperatingSystemVersion; + std::uint16_t MajorImageVersion; + std::uint16_t MinorImageVersion; + std::uint16_t MajorSubsystemVersion; + std::uint16_t MinorSubsystemVersion; + std::uint32_t Win32VersionValue; + std::uint32_t SizeOfImage; + std::uint32_t SizeOfHeaders; + std::uint32_t CheckSum; + std::uint16_t Subsystem; + std::uint16_t DllCharacteristics; + std::uint64_t SizeOfStackReserve; + std::uint64_t SizeOfStackCommit; + std::uint64_t SizeOfHeapReserve; + std::uint64_t SizeOfHeapCommit; + std::uint32_t LoaderFlags; + std::uint32_t NumberOfRvaAndSizes; + + PELIB_IMAGE_DATA_DIRECTORY DataDirectory[PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; }; - template<> - struct PELIB_IMAGE_OPTIONAL_HEADER<64> : public PELIB_IMAGE_OPTIONAL_HEADER_BASE<64> + // Common structure for both 32-bit and 64-bit PE files + struct PELIB_IMAGE_OPTIONAL_HEADER { - static inline unsigned int size() {return 240 - 0x10 * 8;} - - PELIB_IMAGE_OPTIONAL_HEADER<64>() : PELIB_IMAGE_OPTIONAL_HEADER_BASE<64>() - { - - } + std::uint16_t Magic; + std::uint8_t MajorLinkerVersion; + std::uint8_t MinorLinkerVersion; + std::uint32_t SizeOfCode; + std::uint32_t SizeOfInitializedData; + std::uint32_t SizeOfUninitializedData; + std::uint32_t AddressOfEntryPoint; + std::uint32_t BaseOfCode; + std::uint32_t BaseOfData; + std::uint64_t ImageBase; + std::uint32_t SectionAlignment; + std::uint32_t FileAlignment; + std::uint16_t MajorOperatingSystemVersion; + std::uint16_t MinorOperatingSystemVersion; + std::uint16_t MajorImageVersion; + std::uint16_t MinorImageVersion; + std::uint16_t MajorSubsystemVersion; + std::uint16_t MinorSubsystemVersion; + std::uint32_t Win32VersionValue; + std::uint32_t SizeOfImage; + std::uint32_t SizeOfHeaders; + std::uint32_t CheckSum; + std::uint16_t Subsystem; + std::uint16_t DllCharacteristics; + std::uint64_t SizeOfStackReserve; + std::uint64_t SizeOfStackCommit; + std::uint64_t SizeOfHeapReserve; + std::uint64_t SizeOfHeapCommit; + std::uint32_t LoaderFlags; + std::uint32_t NumberOfRvaAndSizes; + + PELIB_IMAGE_DATA_DIRECTORY DataDirectory[PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; }; template - struct PELIB_IMAGE_NT_HEADERS + struct PELIB_IMAGE_NT_HEADERS_EX { - dword Signature; + std::uint32_t Signature; PELIB_IMAGE_FILE_HEADER FileHeader; - PELIB_IMAGE_OPTIONAL_HEADER OptionalHeader; + PELIB_IMAGE_OPTIONAL_HEADER OptionalHeader; std::vector dataDirectories; bool lastDirectoryIsIncomplete; unsigned int sizeOfSignature() const { - return sizeof(dword); + return sizeof(std::uint32_t); } unsigned int size() const { return sizeOfSignature() + PELIB_IMAGE_FILE_HEADER::size() - + PELIB_IMAGE_OPTIONAL_HEADER::size() + + sizeof(PELIB_IMAGE_OPTIONAL_HEADER) + static_cast(dataDirectories.size()) * PELIB_IMAGE_DATA_DIRECTORY::size(); } @@ -843,7 +792,7 @@ namespace PeLib return res; } - PELIB_IMAGE_NT_HEADERS() + PELIB_IMAGE_NT_HEADERS_EX() { Signature = 0; lastDirectoryIsIncomplete = false; @@ -853,27 +802,28 @@ namespace PeLib const unsigned int PELIB_IMAGE_SIZEOF_SHORT_NAME = 8; const unsigned int PELIB_IMAGE_SIZEOF_MAX_NAME = 1024; - struct PELIB_IMAGE_SECTION_HEADER + struct PELIB_IMAGE_SECTION_HEADER_BASE + { + std::uint8_t Name[PELIB_IMAGE_SIZEOF_SHORT_NAME]; + std::uint32_t VirtualSize; + std::uint32_t VirtualAddress; + std::uint32_t SizeOfRawData; + std::uint32_t PointerToRawData; + std::uint32_t PointerToRelocations; + std::uint32_t PointerToLinenumbers; + std::uint16_t NumberOfRelocations; + std::uint16_t NumberOfLinenumbers; + std::uint32_t Characteristics; + }; + + + struct PELIB_IMAGE_SECTION_HEADER : public PELIB_IMAGE_SECTION_HEADER_BASE { - byte Name[PELIB_IMAGE_SIZEOF_SHORT_NAME]; - dword VirtualSize; - dword VirtualAddress; - dword SizeOfRawData; - dword PointerToRawData; - dword PointerToRelocations; - dword PointerToLinenumbers; - word NumberOfRelocations; - word NumberOfLinenumbers; - dword Characteristics; std::string StringTableName; PELIB_IMAGE_SECTION_HEADER() { - for (unsigned int i = 0; i < sizeof(Name) / sizeof(Name[0]); i++) - { - Name[i] = 0; - } - + memset(Name, 0, sizeof(Name)); VirtualSize = 0; VirtualAddress = 0; SizeOfRawData = 0; @@ -886,23 +836,21 @@ namespace PeLib StringTableName = ""; } - static inline unsigned int size() {return 40;} + static inline std::size_t size() { return sizeof(PELIB_IMAGE_SECTION_HEADER); } + bool biggerFileOffset(const PELIB_IMAGE_SECTION_HEADER& ish) const; bool biggerVirtualAddress(const PELIB_IMAGE_SECTION_HEADER& ish) const; bool isFullNameSet() const; }; - template struct PELIB_IMAGE_THUNK_DATA { - typename FieldSizes::VAR4_8 Ordinal; + std::uint64_t Ordinal; PELIB_IMAGE_THUNK_DATA() { Ordinal = 0; } - - static inline unsigned int size() { return sizeof(typename FieldSizes::VAR4_8); } }; template @@ -918,11 +866,11 @@ namespace PeLib struct PELIB_IMAGE_IMPORT_DESCRIPTOR { - dword OriginalFirstThunk; - dword TimeDateStamp; - dword ForwarderChain; - dword Name; - dword FirstThunk; + std::uint32_t OriginalFirstThunk; + std::uint32_t TimeDateStamp; + std::uint32_t ForwarderChain; + std::uint32_t Name; + std::uint32_t FirstThunk; PELIB_IMAGE_IMPORT_DESCRIPTOR() { @@ -933,22 +881,22 @@ namespace PeLib FirstThunk = 0; } - static inline unsigned int size() {return 20;} + static inline std::size_t size() {return 20;} }; struct PELIB_IMAGE_EXPORT_DIRECTORY { - dword Characteristics; - dword TimeDateStamp; - word MajorVersion; - word MinorVersion; - dword Name; - dword Base; - dword NumberOfFunctions; - dword NumberOfNames; - dword AddressOfFunctions; - dword AddressOfNames; - dword AddressOfNameOrdinals; + std::uint32_t Characteristics; + std::uint32_t TimeDateStamp; + std::uint16_t MajorVersion; + std::uint16_t MinorVersion; + std::uint32_t Name; + std::uint32_t Base; + std::uint32_t NumberOfFunctions; + std::uint32_t NumberOfNames; + std::uint32_t AddressOfFunctions; + std::uint32_t AddressOfNames; + std::uint32_t AddressOfNameOrdinals; PELIB_IMAGE_EXPORT_DIRECTORY() { @@ -965,14 +913,17 @@ namespace PeLib AddressOfNameOrdinals = 0; } - static inline unsigned int size() {return 40;} + static inline std::size_t size() + { + return sizeof(PELIB_IMAGE_EXPORT_DIRECTORY); + } }; struct PELIB_IMAGE_BOUND_IMPORT_DESCRIPTOR { - dword TimeDateStamp; - word OffsetModuleName; - word NumberOfModuleForwarderRefs; + std::uint32_t TimeDateStamp; + std::uint16_t OffsetModuleName; + std::uint16_t NumberOfModuleForwarderRefs; PELIB_IMAGE_BOUND_IMPORT_DESCRIPTOR() { @@ -981,7 +932,7 @@ namespace PeLib NumberOfModuleForwarderRefs = 0; } - static unsigned int size() + static inline std::size_t size() { return 8; } @@ -999,14 +950,14 @@ namespace PeLib /// Compares the passed filename to the struct's filename. bool equal(const std::string strModuleName2) const; - unsigned int size() const; + std::size_t size() const; }; struct PELIB_EXP_FUNC_INFORMATION { - dword addroffunc; - dword addrofname; - word ordinal; + std::uint32_t addroffunc; + std::uint32_t addrofname; + std::uint16_t ordinal; std::string funcname; PELIB_EXP_FUNC_INFORMATION(); @@ -1024,24 +975,26 @@ namespace PeLib struct PELIB_IMAGE_RESOURCE_DIRECTORY { - dword Characteristics; - dword TimeDateStamp; - word MajorVersion; - word MinorVersion; - word NumberOfNamedEntries; - word NumberOfIdEntries; - + std::uint32_t Characteristics; + std::uint32_t TimeDateStamp; + std::uint16_t MajorVersion; + std::uint16_t MinorVersion; + std::uint16_t NumberOfNamedEntries; + std::uint16_t NumberOfIdEntries; + PELIB_IMAGE_RESOURCE_DIRECTORY(); - static inline unsigned int size() {return 16;} + static inline std::size_t size() {return 16;} }; struct PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY { - dword Name; - dword OffsetToData; + std::uint32_t Name; + std::uint32_t OffsetToData; + PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY(); - static inline unsigned int size() {return 8;} + + static inline std::size_t size() {return 8;} }; const unsigned int PELIB_IMAGE_SIZEOF_BASE_RELOCATION = 8; @@ -1057,21 +1010,21 @@ namespace PeLib struct PELIB_IMAGE_BASE_RELOCATION { - dword VirtualAddress; - dword SizeOfBlock; + std::uint32_t VirtualAddress; + std::uint32_t SizeOfBlock; PELIB_IMAGE_BASE_RELOCATION(); - static inline unsigned int size() {return 8;} + static inline std::size_t size() {return 72;} }; struct PELIB_IMAGE_COR20_HEADER { - dword cb; - word MajorRuntimeVersion; - word MinorRuntimeVersion; + std::uint32_t cb; + std::uint16_t MajorRuntimeVersion; + std::uint16_t MinorRuntimeVersion; PELIB_IMAGE_DATA_DIRECTORY MetaData; - dword Flags; - dword EntryPointToken; + std::uint32_t Flags; + std::uint32_t EntryPointToken; PELIB_IMAGE_DATA_DIRECTORY Resources; PELIB_IMAGE_DATA_DIRECTORY StrongNameSignature; PELIB_IMAGE_DATA_DIRECTORY CodeManagerTable; @@ -1080,7 +1033,7 @@ namespace PeLib PELIB_IMAGE_DATA_DIRECTORY ManagedNativeHeader; PELIB_IMAGE_COR20_HEADER(); - static inline unsigned int size() {return 72;} + static inline std::size_t size() {return 72;} }; // Used to store a file's export table. @@ -1091,23 +1044,24 @@ namespace PeLib /// The original filename of current file. std::string name; std::vector functions; - inline unsigned int size() const + + inline std::size_t size() const { - return (unsigned int)(PELIB_IMAGE_EXPORT_DIRECTORY::size() + name.size() + 1 + + return (PELIB_IMAGE_EXPORT_DIRECTORY::size() + name.size() + 1 + std::accumulate(functions.begin(), functions.end(), 0, accumulate)); } }; bool isEqualNc(const std::string& s1, const std::string& s2); + // Used for parsing a file's import table. It combines the function name, the hint // and the IMAGE_THUNK_DATA of an imported function. - template struct PELIB_THUNK_DATA { /// The IMAGE_THUNK_DATA struct of an imported function. - PELIB_IMAGE_THUNK_DATA itd; + PELIB_IMAGE_THUNK_DATA itd; /// The hint of an imported function. - word hint; + std::uint16_t hint; /// The function name of an imported function. std::string fname; @@ -1116,7 +1070,7 @@ namespace PeLib hint = 0; } - bool equalHint(word wHint) const + bool equalHint(std::uint16_t wHint) const { return hint == wHint; // return itd.Ordinal == (wHint | PELIB_IMAGE_ORDINAL_FLAGS::PELIB_IMAGE_ORDINAL_FLAG); @@ -1126,15 +1080,13 @@ namespace PeLib { return isEqualNc(fname, strFunctionName); } - - unsigned int size() const {return PELIB_IMAGE_THUNK_DATA::size() + fname.size() + 1 + sizeof(hint);} }; template struct PELIB_DELAY_IMPORT { PELIB_VAR_SIZE address; - word hint; + std::uint16_t hint; std::string fname; PELIB_DELAY_IMPORT() : hint(0) @@ -1145,7 +1097,6 @@ namespace PeLib // Used to store a file's import table. Every struct of this sort // can store import information of one DLL. - template struct PELIB_IMAGE_IMPORT_DIRECTORY { /// The IMAGE_IMPORT_DESCRIPTOR of an imported DLL. @@ -1153,18 +1104,19 @@ namespace PeLib /// The name of an imported DLL. std::string name; /// All original first thunk values of an imported DLL. - std::vector > originalfirstthunk; + std::vector originalfirstthunk; /// All first thunk value of an imported DLL. - std::vector > firstthunk; + std::vector firstthunk; -// bool operator==(std::string strFilename) const; - inline unsigned int size() const + inline std::size_t size() const { - return PELIB_IMAGE_IMPORT_DESCRIPTOR::size() + name.size() + 1 + // descriptor + dllname - std::accumulate(originalfirstthunk.begin(), originalfirstthunk.end(), 0, accumulate >) + // thunks (PeLib uses only one thunk) - PELIB_IMAGE_THUNK_DATA::size(); // zero-termination + return sizeof(PELIB_IMAGE_IMPORT_DESCRIPTOR) + // descriptor + name.size() + 1 + // dllname + sizeof(PELIB_THUNK_DATA) * originalfirstthunk.size() + // thunks (PeLib uses only one thunk) + sizeof(PELIB_IMAGE_THUNK_DATA); // zero-termination } + bool operator==(std::string strFilename) const { return isEqualNc(this->name, strFilename); @@ -1176,10 +1128,10 @@ namespace PeLib struct PELIB_IMAGE_RESOURCE_DATA_ENTRY { - dword OffsetToData; - dword Size; - dword CodePage; - dword Reserved; + std::uint32_t OffsetToData; + std::uint32_t Size; + std::uint32_t CodePage; + std::uint32_t Reserved; static inline unsigned int size() {return 16;} @@ -1189,27 +1141,27 @@ namespace PeLib struct PELIB_IMAGE_RESOURCE_DATA { PELIB_IMAGE_RESOURCE_DATA_ENTRY irdEntry; - std::vector vData; + std::vector vData; }; struct IMG_BASE_RELOC { PELIB_IMAGE_BASE_RELOCATION ibrRelocation; - std::vector vRelocData; + std::vector vRelocData; }; struct PELIB_IMAGE_DEBUG_DIRECTORY { - dword Characteristics; - dword TimeDateStamp; - word MajorVersion; - word MinorVersion; - dword Type; - dword SizeOfData; - dword AddressOfRawData; - dword PointerToRawData; + std::uint32_t Characteristics; + std::uint32_t TimeDateStamp; + std::uint16_t MajorVersion; + std::uint16_t MinorVersion; + std::uint32_t Type; + std::uint32_t SizeOfData; + std::uint32_t AddressOfRawData; + std::uint32_t PointerToRawData; - static unsigned int size() {return 28;} + static std::size_t size() {return 28;} PELIB_IMAGE_DEBUG_DIRECTORY(); }; @@ -1217,7 +1169,7 @@ namespace PeLib struct PELIB_IMG_DEBUG_DIRECTORY { PELIB_IMAGE_DEBUG_DIRECTORY idd; - std::vector data; + std::vector data; }; template @@ -1227,8 +1179,8 @@ namespace PeLib typename FieldSizes::VAR4_8 EndAddressOfRawData; typename FieldSizes::VAR4_8 AddressOfIndex; typename FieldSizes::VAR4_8 AddressOfCallBacks; - dword SizeOfZeroFill; - dword Characteristics; + std::uint32_t SizeOfZeroFill; + std::uint32_t Characteristics; PELIB_IMAGE_TLS_DIRECTORY_BASE() { @@ -1306,14 +1258,14 @@ namespace PeLib struct PELIB_IMAGE_COFF_SYMBOL { - dword Index; + std::uint32_t Index; std::string Name; - dword Value; - word SectionNumber; - byte TypeComplex; - byte TypeSimple; - byte StorageClass; - byte NumberOfAuxSymbols; + std::uint32_t Value; + std::uint16_t SectionNumber; + std::uint8_t TypeComplex; + std::uint8_t TypeSimple; + std::uint8_t StorageClass; + std::uint8_t NumberOfAuxSymbols; PELIB_IMAGE_COFF_SYMBOL() : Index(0), Value(0), SectionNumber(0), TypeComplex(0), TypeSimple(0), StorageClass(0), NumberOfAuxSymbols(0) @@ -1325,9 +1277,9 @@ namespace PeLib struct PELIB_IMAGE_RICH_HEADER_RECORD { std::string Signature; - word ProductId; - word ProductBuild; - dword Count; + std::uint16_t ProductId; + std::uint16_t ProductBuild; + std::uint32_t Count; std::string ProductName; std::string VisualStudioName; @@ -1348,17 +1300,17 @@ namespace PeLib std::vector> Functions; public: - dword Attributes; - dword NameRva; + std::uint32_t Attributes; + std::uint32_t NameRva; std::string Name; - dword ModuleHandleRva; - dword DelayImportAddressTableRva; - dword DelayImportNameTableRva; - dword BoundDelayImportTableRva; - dword UnloadDelayImportTableRva; - dword TimeStamp; - dword DelayImportAddressTableOffset; - dword DelayImportNameTableOffset; + std::uint32_t ModuleHandleRva; + std::uint32_t DelayImportAddressTableRva; + std::uint32_t DelayImportNameTableRva; + std::uint32_t BoundDelayImportTableRva; + std::uint32_t UnloadDelayImportTableRva; + std::uint32_t TimeStamp; + std::uint32_t DelayImportAddressTableOffset; + std::uint32_t DelayImportNameTableOffset; PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD() { @@ -1453,9 +1405,9 @@ namespace PeLib struct PELIB_IMAGE_CERTIFICATE_ENTRY { - dword Length; - word Revision; - word CertificateType; + std::uint32_t Length; + std::uint16_t Revision; + std::uint16_t CertificateType; std::vector Certificate; static inline unsigned int size() { return 8; } diff --git a/include/retdec/pelib/RelocationsDirectory.h b/include/retdec/pelib/RelocationsDirectory.h index 8882fe6db..6b973ba4d 100644 --- a/include/retdec/pelib/RelocationsDirectory.h +++ b/include/retdec/pelib/RelocationsDirectory.h @@ -49,25 +49,25 @@ namespace PeLib unsigned int size() const; // EXPORT /// Returns the VA of a relocation. - dword getVirtualAddress(unsigned int ulRelocation) const; // EXPORT + std::uint32_t getVirtualAddress(unsigned int ulRelocation) const; // EXPORT /// Returns the SizeOfBlock value of a relocation. - dword getSizeOfBlock(unsigned int ulRelocation) const; // EXPORT + std::uint32_t getSizeOfBlock(unsigned int ulRelocation) const; // EXPORT /// Returns the RelocationData of a relocation. - word getRelocationData(unsigned int ulRelocation, unsigned int ulDataNumber) const; // EXPORT + std::uint16_t getRelocationData(unsigned int ulRelocation, unsigned int ulDataNumber) const; // EXPORT /// Changes the relocation data of a relocation. - void setRelocationData(unsigned int ulRelocation, unsigned int ulDataNumber, word wData); // EXPORT + void setRelocationData(unsigned int ulRelocation, unsigned int ulDataNumber, std::uint16_t wData); // EXPORT /// Changes the VirtualAddress of a relocation. - void setVirtualAddress(unsigned int ulRelocation, dword dwValue); // EXPORT + void setVirtualAddress(unsigned int ulRelocation, std::uint32_t dwValue); // EXPORT /// Changes the SizeOfBlock of a relocation. - void setSizeOfBlock(unsigned int ulRelocation, dword dwValue); // EXPORT + void setSizeOfBlock(unsigned int ulRelocation, std::uint32_t dwValue); // EXPORT void addRelocation(); // EXPORT /// Adds new data to a relocation. - void addRelocationData(unsigned int ulRelocation, word wValue); // EXPORT + void addRelocationData(unsigned int ulRelocation, std::uint16_t wValue); // EXPORT /// Removes data from a relocation. -// void removeRelocationData(unsigned int ulRelocation, word wValue); // EXPORT + void removeRelocationData(unsigned int ulRelocation, std::uint16_t wValue); // EXPORT void removeRelocation(unsigned int index); // EXPORT void removeRelocationData(unsigned int relocindex, unsigned int dataindex); // EXPORT }; diff --git a/include/retdec/pelib/ResourceDirectory.h b/include/retdec/pelib/ResourceDirectory.h index aad165d74..42bd5738e 100644 --- a/include/retdec/pelib/ResourceDirectory.h +++ b/include/retdec/pelib/ResourceDirectory.h @@ -40,7 +40,7 @@ namespace PeLib public: /// Function which compares a resource ID to the node's resource ID. - bool equalId(dword wId) const; // EXPORT + bool equalId(std::uint32_t wId) const; // EXPORT /// Function which compares a string to the node's resource name. bool equalName(std::string strName) const; // EXPORT /// Predicate that determines if a child is identified by name or by ID. @@ -49,7 +49,7 @@ namespace PeLib bool operator<(const ResourceChild& rc) const; // EXPORT /// A comparison function for searching a resource element by its ID. - bool hasEqual(dword id) const { return equalId(id); } + bool hasEqual(std::uint32_t id) const { return equalId(id); } /// A comparison function for searching a resource element by its name. bool hasEqual(const std::string& name) const { return equalName(name); } @@ -68,16 +68,16 @@ namespace PeLib /// Returns the name of the node. std::string getName() const; // EXPORT /// Returns the Name value of the node. - dword getOffsetToName() const; // EXPORT + std::uint32_t getOffsetToName() const; // EXPORT /// Returns the OffsetToData value of the node. - dword getOffsetToData() const; // EXPORT + std::uint32_t getOffsetToData() const; // EXPORT /// Sets the name of the node. void setName(const std::string& strNewName); // EXPORT /// Sets the Name value of the node. - void setOffsetToName(dword dwNewOffset); // EXPORT + void setOffsetToName(std::uint32_t dwNewOffset); // EXPORT /// Sets the OffsetToData value of the node. - void setOffsetToData(dword dwNewOffset); // EXPORT + void setOffsetToData(std::uint32_t dwNewOffset); // EXPORT /// Returns the size of a resource child. // unsigned int size() const; @@ -136,7 +136,7 @@ namespace PeLib private: /// The resource data. - std::vector m_data; + std::vector m_data; /// PeLib equivalent of the Win32 structure IMAGE_RESOURCE_DATA_ENTRY PELIB_IMAGE_RESOURCE_DATA_ENTRY entry; @@ -157,27 +157,27 @@ namespace PeLib // unsigned int size() const; /// Returns the resource data of this resource leaf. - std::vector getData() const; // EXPORT + std::vector getData() const; // EXPORT /// Sets the resource data of this resource leaf. - void setData(const std::vector& vData); // EXPORT + void setData(const std::vector& vData); // EXPORT /// Returns the OffsetToData value of this resource leaf. - dword getOffsetToData() const; // EXPORT + std::uint32_t getOffsetToData() const; // EXPORT /// Returns the Size value of this resource leaf. - dword getSize() const; // EXPORT + std::uint32_t getSize() const; // EXPORT /// Returns the CodePage value of this resource leaf. - dword getCodePage() const; // EXPORT + std::uint32_t getCodePage() const; // EXPORT /// Returns the Reserved value of this resource leaf. - dword getReserved() const; // EXPORT + std::uint32_t getReserved() const; // EXPORT /// Sets the OffsetToData value of this resource leaf. - void setOffsetToData(dword dwValue); // EXPORT + void setOffsetToData(std::uint32_t dwValue); // EXPORT /// Sets the Size value of this resource leaf. - void setSize(dword dwValue); // EXPORT + void setSize(std::uint32_t dwValue); // EXPORT /// Sets the CodePage value of this resource leaf. - void setCodePage(dword dwValue); // EXPORT + void setCodePage(std::uint32_t dwValue); // EXPORT /// Sets the Reserved value of this resource leaf. - void setReserved(dword dwValue); // EXPORT + void setReserved(std::uint32_t dwValue); // EXPORT /// Constructor ResourceLeaf(); /// Destructor @@ -224,42 +224,42 @@ namespace PeLib /// Returns the name of one of the node's children. std::string getChildName(unsigned int uiIndex) const; // EXPORT /// Returns the Name value of one of the node's children. - dword getOffsetToChildName(unsigned int uiIndex) const; // EXPORT + std::uint32_t getOffsetToChildName(unsigned int uiIndex) const; // EXPORT /// Returns the OffsetToData value of one of the node's children. - dword getOffsetToChildData(unsigned int uiIndex) const; // EXPORT + std::uint32_t getOffsetToChildData(unsigned int uiIndex) const; // EXPORT /// Sets the name of one of the node's children. void setChildName(unsigned int uiIndex, const std::string& strNewName); // EXPORT /// Sets the Name value of one of the node's children. - void setOffsetToChildName(unsigned int uiIndex, dword dwNewOffset); // EXPORT + void setOffsetToChildName(unsigned int uiIndex, std::uint32_t dwNewOffset); // EXPORT /// Sets the OffsetToData value of one of the node's children. - void setOffsetToChildData(unsigned int uiIndex, dword dwNewOffset); // EXPORT + void setOffsetToChildData(unsigned int uiIndex, std::uint32_t dwNewOffset); // EXPORT /// Returns the node's Characteristics value. - dword getCharacteristics() const; // EXPORT + std::uint32_t getCharacteristics() const; // EXPORT /// Returns the node's TimeDateStamp value. - dword getTimeDateStamp() const; // EXPORT + std::uint32_t getTimeDateStamp() const; // EXPORT /// Returns the node's MajorVersion value. - word getMajorVersion() const; // EXPORT + std::uint16_t getMajorVersion() const; // EXPORT /// Returns the node's MinorVersion value. - word getMinorVersion() const; // EXPORT + std::uint16_t getMinorVersion() const; // EXPORT /// Returns the node's NumberOfNamedEntries value. - word getNumberOfNamedEntries() const; // EXPORT + std::uint16_t getNumberOfNamedEntries() const; // EXPORT /// Returns the node's NumberOfIdEntries value. - word getNumberOfIdEntries() const; // EXPORT + std::uint16_t getNumberOfIdEntries() const; // EXPORT /// Sets the node's Characteristics value. - void setCharacteristics(dword value); // EXPORT + void setCharacteristics(std::uint32_t value); // EXPORT /// Sets the node's TimeDateStamp value. - void setTimeDateStamp(dword value); // EXPORT + void setTimeDateStamp(std::uint32_t value); // EXPORT /// Sets the node's MajorVersion value. - void setMajorVersion(word value); // EXPORT + void setMajorVersion(std::uint16_t value); // EXPORT /// Sets the node's MinorVersion value. - void setMinorVersion(word value); // EXPORT + void setMinorVersion(std::uint16_t value); // EXPORT /// Sets the node's NumberOfNamedEntries value. - void setNumberOfNamedEntries(word value); // EXPORT + void setNumberOfNamedEntries(std::uint16_t value); // EXPORT /// Sets the node's NumberOfIdEntries value. - void setNumberOfIdEntries(word value); // EXPORT + void setNumberOfIdEntries(std::uint16_t value); // EXPORT /// Returns the size of a resource node. // unsigned int size() const; @@ -280,12 +280,12 @@ namespace PeLib /// Fixes NumberOfIdEntries value of a node. template<> - struct fixNumberOfEntries + struct fixNumberOfEntries { /// Fixes a resource node's NumberOfIdEntries value. static void fix(ResourceNode* node) { - node->header.NumberOfIdEntries = static_cast( + node->header.NumberOfIdEntries = static_cast( node->children.size() - std::count_if( node->children.begin(), node->children.end(), @@ -302,7 +302,7 @@ namespace PeLib /// Fixes a resource node's NumberOfNamedEntries value. static void fix(ResourceNode* node) { - node->header.NumberOfNamedEntries = static_cast( + node->header.NumberOfNamedEntries = static_cast( std::count_if( node->children.begin(), node->children.end(), @@ -373,19 +373,19 @@ namespace PeLib /// Returns the data of a resource. template - int getResourceDataT(S restypeid, T resid, std::vector& data) const; + int getResourceDataT(S restypeid, T resid, std::vector& data) const; /// Sets the data of a resource. template - int setResourceDataT(S restypeid, T resid, std::vector& data); + int setResourceDataT(S restypeid, T resid, std::vector& data); /// Returns the ID of a resource. template - dword getResourceIdT(S restypeid, T resid) const; + std::uint32_t getResourceIdT(S restypeid, T resid) const; /// Sets the ID of a resource. template - int setResourceIdT(S restypeid, T resid, dword dwNewResId); + int setResourceIdT(S restypeid, T resid, std::uint32_t dwNewResId); /// Returns the name of a resource. template @@ -411,7 +411,7 @@ namespace PeLib /// Corrects a erroneous resource directory. void makeValid(); /// Rebuilds the resource directory. - void rebuild(std::vector& vBuffer, unsigned int uiRva) const; + void rebuild(std::vector& vBuffer, unsigned int uiRva) const; /// Recalculate the tree for different RVA void recalculate(unsigned int& uiNewSize, unsigned int uiNewRva); /// Returns the size of the rebuilt resource directory. @@ -420,12 +420,12 @@ namespace PeLib int write(const std::string& strFilename, unsigned int uiOffset, unsigned int uiRva) const; /// Adds a new resource type. - int addResourceType(dword dwResTypeId); + int addResourceType(std::uint32_t dwResTypeId); /// Adds a new resource type. int addResourceType(const std::string& strResTypeName); /// Removes a resource type and all of it's resources. - int removeResourceType(dword dwResTypeId); + int removeResourceType(std::uint32_t dwResTypeId); /// Removes a resource type and all of it's resources. int removeResourceType(const std::string& strResTypeName); @@ -433,20 +433,20 @@ namespace PeLib int removeResourceTypeByIndex(unsigned int uiIndex); /// Adds a new resource. - int addResource(dword dwResTypeId, dword dwResId); + int addResource(std::uint32_t dwResTypeId, std::uint32_t dwResId); /// Adds a new resource. - int addResource(dword dwResTypeId, const std::string& strResName); + int addResource(std::uint32_t dwResTypeId, const std::string& strResName); /// Adds a new resource. - int addResource(const std::string& strResTypeName, dword dwResId); + int addResource(const std::string& strResTypeName, std::uint32_t dwResId); /// Adds a new resource. int addResource(const std::string& strResTypeName, const std::string& strResName); /// Removes a resource. - int removeResource(dword dwResTypeId, dword dwResId); + int removeResource(std::uint32_t dwResTypeId, std::uint32_t dwResId); /// Removes a resource. - int removeResource(dword dwResTypeId, const std::string& strResName); + int removeResource(std::uint32_t dwResTypeId, const std::string& strResName); /// Removes a resource. - int removeResource(const std::string& strResTypeName, dword dwResId); + int removeResource(const std::string& strResTypeName, std::uint32_t dwResId); /// Removes a resource. int removeResource(const std::string& strResTypeName, const std::string& strResName); @@ -457,17 +457,17 @@ namespace PeLib unsigned int getNumberOfResourceTypes() const; /// Returns the ID of a resource type. - dword getResourceTypeIdByIndex(unsigned int uiIndex) const; + std::uint32_t getResourceTypeIdByIndex(unsigned int uiIndex) const; /// Returns the name of a resource type. std::string getResourceTypeNameByIndex(unsigned int uiIndex) const; /// Converts a resource type ID to an index. - int resourceTypeIdToIndex(dword dwResTypeId) const; + int resourceTypeIdToIndex(std::uint32_t dwResTypeId) const; /// Converts a resource type name to an index. int resourceTypeNameToIndex(const std::string& strResTypeName) const; /// Returns the number of resources of a certain resource type. - unsigned int getNumberOfResources(dword dwId) const; + unsigned int getNumberOfResources(std::uint32_t dwId) const; /// Returns the number of resources of a certain resource type. unsigned int getNumberOfResources(const std::string& strResTypeName) const; @@ -475,63 +475,63 @@ namespace PeLib unsigned int getNumberOfResourcesByIndex(unsigned int uiIndex) const; /// Returns the data of a certain resource. - void getResourceData(dword dwResTypeId, dword dwResId, std::vector& data) const; + void getResourceData(std::uint32_t dwResTypeId, std::uint32_t dwResId, std::vector& data) const; /// Returns the data of a certain resource. - void getResourceData(dword dwResTypeId, const std::string& strResName, std::vector& data) const; + void getResourceData(std::uint32_t dwResTypeId, const std::string& strResName, std::vector& data) const; /// Returns the data of a certain resource. - void getResourceData(const std::string& strResTypeName, dword dwResId, std::vector& data) const; + void getResourceData(const std::string& strResTypeName, std::uint32_t dwResId, std::vector& data) const; /// Returns the data of a certain resource. - void getResourceData(const std::string& strResTypeName, const std::string& strResName, std::vector& data) const; + void getResourceData(const std::string& strResTypeName, const std::string& strResName, std::vector& data) const; /// Returns the data of a certain resource. - void getResourceDataByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::vector& data) const; + void getResourceDataByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::vector& data) const; /// Sets the data of a certain resource. - void setResourceData(dword dwResTypeId, dword dwResId, std::vector& data); + void setResourceData(std::uint32_t dwResTypeId, std::uint32_t dwResId, std::vector& data); /// Sets the data of a certain resource. - void setResourceData(dword dwResTypeId, const std::string& strResName, std::vector& data); + void setResourceData(std::uint32_t dwResTypeId, const std::string& strResName, std::vector& data); /// Sets the data of a certain resource. - void setResourceData(const std::string& strResTypeName, dword dwResId, std::vector& data); + void setResourceData(const std::string& strResTypeName, std::uint32_t dwResId, std::vector& data); /// Sets the data of a certain resource. - void setResourceData(const std::string& strResTypeName, const std::string& strResName, std::vector& data); + void setResourceData(const std::string& strResTypeName, const std::string& strResName, std::vector& data); /// Sets the data of a certain resource. - void setResourceDataByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::vector& data); + void setResourceDataByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::vector& data); /// Returns the ID of a certain resource. - dword getResourceId(dword dwResTypeId, const std::string& strResName) const; + std::uint32_t getResourceId(std::uint32_t dwResTypeId, const std::string& strResName) const; /// Returns the ID of a certain resource. - dword getResourceId(const std::string& strResTypeName, const std::string& strResName) const; + std::uint32_t getResourceId(const std::string& strResTypeName, const std::string& strResName) const; /// Returns the ID of a certain resource. - dword getResourceIdByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex) const; + std::uint32_t getResourceIdByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex) const; /// Sets the ID of a certain resource. - void setResourceId(dword dwResTypeId, dword dwResId, dword dwNewResId); + void setResourceId(std::uint32_t dwResTypeId, std::uint32_t dwResId, std::uint32_t dwNewResId); /// Sets the ID of a certain resource. - void setResourceId(dword dwResTypeId, const std::string& strResName, dword dwNewResId); + void setResourceId(std::uint32_t dwResTypeId, const std::string& strResName, std::uint32_t dwNewResId); /// Sets the ID of a certain resource. - void setResourceId(const std::string& strResTypeName, dword dwResId, dword dwNewResId); + void setResourceId(const std::string& strResTypeName, std::uint32_t dwResId, std::uint32_t dwNewResId); /// Sets the ID of a certain resource. - void setResourceId(const std::string& strResTypeName, const std::string& strResName, dword dwNewResId); + void setResourceId(const std::string& strResTypeName, const std::string& strResName, std::uint32_t dwNewResId); /// Sets the ID of a certain resource. - void setResourceIdByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, dword dwNewResId); + void setResourceIdByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::uint32_t dwNewResId); /// Returns the name of a certain resource. - std::string getResourceName(dword dwResTypeId, dword dwResId) const; + std::string getResourceName(std::uint32_t dwResTypeId, std::uint32_t dwResId) const; /// Returns the name of a certain resource. - std::string getResourceName(const std::string& strResTypeName, dword dwResId) const; + std::string getResourceName(const std::string& strResTypeName, std::uint32_t dwResId) const; /// Returns the name of a certain resource. std::string getResourceNameByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex) const; /// Sets the name of a certain resource. - void setResourceName(dword dwResTypeId, dword dwResId, const std::string& strNewResName); + void setResourceName(std::uint32_t dwResTypeId, std::uint32_t dwResId, const std::string& strNewResName); /// Sets the name of a certain resource. - void setResourceName(dword dwResTypeId, const std::string& strResName, const std::string& strNewResName); + void setResourceName(std::uint32_t dwResTypeId, const std::string& strResName, const std::string& strNewResName); /// Sets the name of a certain resource. - void setResourceName(const std::string& strResTypeName, dword dwResId, const std::string& strNewResName); + void setResourceName(const std::string& strResTypeName, std::uint32_t dwResId, const std::string& strNewResName); /// Sets the name of a certain resource. void setResourceName(const std::string& strResTypeName, const std::string& strResName, const std::string& strNewResName); @@ -693,7 +693,7 @@ namespace PeLib * @param data The data of the resource will be written into this vector. **/ template - int ResourceDirectory::getResourceDataT(S restypeid, T resid, std::vector& data) const + int ResourceDirectory::getResourceDataT(S restypeid, T resid, std::vector& data) const { std::vector::const_iterator ResIter = locateResourceT(restypeid, resid); ResourceNode* currNode = static_cast(ResIter->child); @@ -710,7 +710,7 @@ namespace PeLib * @param data The new data of the resource is taken from this vector. **/ template - int ResourceDirectory::setResourceDataT(S restypeid, T resid, std::vector& data) + int ResourceDirectory::setResourceDataT(S restypeid, T resid, std::vector& data) { std::vector::iterator ResIter = locateResourceT(restypeid, resid); ResourceNode* currNode = static_cast(ResIter->child); @@ -728,7 +728,7 @@ namespace PeLib * @return The ID of the specified resource. **/ template - dword ResourceDirectory::getResourceIdT(S restypeid, T resid) const + std::uint32_t ResourceDirectory::getResourceIdT(S restypeid, T resid) const { std::vector::const_iterator ResIter = locateResourceT(restypeid, resid); return ResIter->entry.irde.Name; @@ -741,7 +741,7 @@ namespace PeLib * @param dwNewResId New ID of the resource. **/ template - int ResourceDirectory::setResourceIdT(S restypeid, T resid, dword dwNewResId) + int ResourceDirectory::setResourceIdT(S restypeid, T resid, std::uint32_t dwNewResId) { std::vector::iterator ResIter = locateResourceT(restypeid, resid); ResIter->entry.irde.Name = dwNewResId; diff --git a/include/retdec/pelib/RichHeader.h b/include/retdec/pelib/RichHeader.h index 3f81feb94..30c4b139c 100644 --- a/include/retdec/pelib/RichHeader.h +++ b/include/retdec/pelib/RichHeader.h @@ -23,9 +23,9 @@ namespace PeLib private: bool headerIsValid; bool validStructure; - dword key; + std::uint32_t key; std::size_t noOfIters; - std::vector decryptedHeader; + std::vector decryptedHeader; std::vector records; void init(); @@ -45,8 +45,8 @@ namespace PeLib bool isHeaderValid() const; bool isStructureValid() const; std::size_t getNumberOfIterations() const; - dword getKey() const; - const dword* getDecryptedHeaderItem(std::size_t index) const; + std::uint32_t getKey() const; + const std::uint32_t* getDecryptedHeaderItem(std::size_t index) const; std::string getDecryptedHeaderItemSignature(std::size_t index) const; std::string getDecryptedHeaderItemsSignature(std::initializer_list indexes) const; std::vector getDecryptedHeaderBytes() const; diff --git a/include/retdec/pelib/TlsDirectory.h b/include/retdec/pelib/TlsDirectory.h index edc1f9d34..828a8fd15 100644 --- a/include/retdec/pelib/TlsDirectory.h +++ b/include/retdec/pelib/TlsDirectory.h @@ -34,7 +34,7 @@ namespace PeLib int read(std::istream& inStream, const PeHeaderT &peHeader); // EXPORT int read(unsigned char* buffer, unsigned int buffersize); // EXPORT /// Rebuilds the TLS directory. - void rebuild(std::vector& vBuffer) const; // EXPORT + void rebuild(std::vector& vBuffer) const; // EXPORT /// Returns the size of the TLS Directory. unsigned int size() const; // EXPORT /// Writes the TLS directory to a file. @@ -49,22 +49,22 @@ namespace PeLib /// Returns the AddressOfCallBacks value of the TLS header. typename FieldSizes::VAR4_8 getAddressOfCallBacks() const; // EXPORT /// Returns the SizeOfZeroFill value of the TLS header. - dword getSizeOfZeroFill() const; // EXPORT + std::uint32_t getSizeOfZeroFill() const; // EXPORT /// Returns the Characteristics value of the TLS header. - dword getCharacteristics() const; // EXPORT + std::uint32_t getCharacteristics() const; // EXPORT /// Sets the StartAddressOfRawData value of the TLS header. - void setStartAddressOfRawData(dword dwValue); // EXPORT + void setStartAddressOfRawData(std::uint32_t dwValue); // EXPORT /// Sets the EndAddressOfRawData value of the TLS header. - void setEndAddressOfRawData(dword dwValue); // EXPORT + void setEndAddressOfRawData(std::uint32_t dwValue); // EXPORT /// Sets the AddressOfIndex value of the TLS header. - void setAddressOfIndex(dword dwValue); // EXPORT + void setAddressOfIndex(std::uint32_t dwValue); // EXPORT /// Sets the AddressOfCallBacks value of the TLS header. - void setAddressOfCallBacks(dword dwValue); // EXPORT + void setAddressOfCallBacks(std::uint32_t dwValue); // EXPORT /// Sets the SizeOfZeroFill value of the TLS header. - void setSizeOfZeroFill(dword dwValue); // EXPORT + void setSizeOfZeroFill(std::uint32_t dwValue); // EXPORT /// Sets the Characteristics value of the TLS header. - void setCharacteristics(dword dwValue); // EXPORT + void setCharacteristics(std::uint32_t dwValue); // EXPORT }; template @@ -90,7 +90,7 @@ namespace PeLib return ERROR_INVALID_FILE; } - std::vector vTlsDirectory(buffer, buffer + buffersize); + std::vector vTlsDirectory(buffer, buffer + buffersize); InputBuffer ibBuffer(vTlsDirectory); read(ibBuffer); @@ -124,7 +124,7 @@ namespace PeLib inStream_w.seekg(uiOffset, std::ios::beg); - std::vector vTlsDirectory(uiSize); + std::vector vTlsDirectory(uiSize); inStream_w.read(reinterpret_cast(vTlsDirectory.data()), uiSize); InputBuffer ibBuffer{vTlsDirectory}; @@ -137,7 +137,7 @@ namespace PeLib * @param vBuffer Buffer where the TLS directory will be written to. **/ template - void TlsDirectory::rebuild(std::vector& vBuffer) const + void TlsDirectory::rebuild(std::vector& vBuffer) const { OutputBuffer obBuffer(vBuffer); @@ -237,7 +237,7 @@ namespace PeLib * @return The SizeOfZeroFill value of the TLS directory. **/ template - dword TlsDirectory::getSizeOfZeroFill() const + std::uint32_t TlsDirectory::getSizeOfZeroFill() const { return m_tls.SizeOfZeroFill; } @@ -246,7 +246,7 @@ namespace PeLib * @return The Characteristics value of the TLS directory. **/ template - dword TlsDirectory::getCharacteristics() const + std::uint32_t TlsDirectory::getCharacteristics() const { return m_tls.Characteristics; } @@ -255,7 +255,7 @@ namespace PeLib * @param dwValue The new StartAddressOfRawData value of the TLS directory. **/ template - void TlsDirectory::setStartAddressOfRawData(dword dwValue) + void TlsDirectory::setStartAddressOfRawData(std::uint32_t dwValue) { m_tls.StartAddressOfRawData = dwValue; } @@ -264,7 +264,7 @@ namespace PeLib * @param dwValue The new EndAddressOfRawData value of the TLS directory. **/ template - void TlsDirectory::setEndAddressOfRawData(dword dwValue) + void TlsDirectory::setEndAddressOfRawData(std::uint32_t dwValue) { m_tls.EndAddressOfRawData = dwValue; } @@ -273,7 +273,7 @@ namespace PeLib * @param dwValue The new AddressOfIndex value of the TLS directory. **/ template - void TlsDirectory::setAddressOfIndex(dword dwValue) + void TlsDirectory::setAddressOfIndex(std::uint32_t dwValue) { m_tls.AddressOfIndex = dwValue; } @@ -282,7 +282,7 @@ namespace PeLib * @param dwValue The new AddressOfCallBacks value of the TLS directory. **/ template - void TlsDirectory::setAddressOfCallBacks(dword dwValue) + void TlsDirectory::setAddressOfCallBacks(std::uint32_t dwValue) { m_tls.AddressOfCallBacks = dwValue; } @@ -291,7 +291,7 @@ namespace PeLib * @param dwValue The new SizeOfZeroFill value of the TLS directory. **/ template - void TlsDirectory::setSizeOfZeroFill(dword dwValue) + void TlsDirectory::setSizeOfZeroFill(std::uint32_t dwValue) { m_tls.SizeOfZeroFill = dwValue; } @@ -300,7 +300,7 @@ namespace PeLib * @param dwValue The new Characteristics value of the TLS directory. **/ template - void TlsDirectory::setCharacteristics(dword dwValue) + void TlsDirectory::setCharacteristics(std::uint32_t dwValue) { m_tls.Characteristics = dwValue; } diff --git a/src/fileformat/file_format/file_format.cpp b/src/fileformat/file_format/file_format.cpp index 3377dd993..eec2b9e8c 100644 --- a/src/fileformat/file_format/file_format.cpp +++ b/src/fileformat/file_format/file_format.cpp @@ -333,7 +333,7 @@ void FileFormat::setLoadedBytes(std::vector *lBytes) /** * If fileformat is Intel HEX or raw binary then it does not contain - * critical information like architecture, endianness or word size. + * critical information like architecture, endianness or std::uint16_t size. * However, fileformat users expect it to contain this information. * Therefore, this method needs to be called to set these critical information. */ @@ -684,8 +684,8 @@ std::size_t FileFormat::getNibbleLength() const } /** - * Get number of bits in one byte - * @return Number of bits in one byte + * Get number of bits in one std::uint8_t + * @return Number of bits in one std::uint8_t * @note This assumes architectures with 8-bit bytes and may break if some * exotic architecture is encountered. */ @@ -696,8 +696,8 @@ std::size_t FileFormat::getByteLength() const } /** - * Get number of bits in one word - * @return Number of bits in one word or zero if this feature is not + * Get number of bits in one std::uint16_t + * @return Number of bits in one std::uint16_t or zero if this feature is not * supported for target architecture of input file. * * Supported architectures are defined as enumeration type Architecture. @@ -708,8 +708,8 @@ std::size_t FileFormat::getWordLength() const } /** - * Get number of nibbles in one byte - * @return Number of nibbles in one byte or zero if this feature is not + * Get number of nibbles in one std::uint8_t + * @return Number of nibbles in one std::uint8_t or zero if this feature is not * supported for target architecture of input file. * * Supported architectures are defined as enumeration type Architecture. @@ -1967,7 +1967,7 @@ bool FileFormat::getXByte(std::uint64_t address, std::uint64_t x, std::uint64_t } /** - * Get @a x bytes long byte array from specified address + * Get @a x bytes long std::uint8_t array from specified address * @param address Address to get array from * @param x Number of bytes for get * @param res Result array @@ -2061,8 +2061,8 @@ bool FileFormat::get8ByteOffset(std::uint64_t offset, std::uint64_t &res, retdec /** * Get long double from the specified offset - * If system has 80-bit (10-byte) long double, copy data directly. - * Else convert 80-bit (10-byte) long double into 64-bit (8-byte) double. + * If system has 80-bit (10-std::uint8_t) long double, copy data directly. + * Else convert 80-bit (10-std::uint8_t) long double into 64-bit (8-std::uint8_t) double. * @param offset Offset to get double from * @param res Result double * @return Status of operation (@c true if all is OK, @c false otherwise) @@ -2107,7 +2107,7 @@ bool FileFormat::getXByteOffset(std::uint64_t offset, std::uint64_t x, std::uint } /** - * Get @a x bytes long byte array from specified offset + * Get @a x bytes long std::uint8_t array from specified offset * @param offset Offset to get array from * @param x Number of bytes for get * @param res Result array @@ -2126,7 +2126,7 @@ bool FileFormat::getXBytesOffset(std::uint64_t offset, std::uint64_t x, std::vec } /** - * Get word located at provided offset using the specified endian or default file endian + * Get std::uint16_t located at provided offset using the specified endian or default file endian * @param offset Offset to get integer from * @param res Result integer * @param e Endian - if specified it is forced, otherwise file's endian is used @@ -2138,10 +2138,10 @@ bool FileFormat::getWordOffset(std::uint64_t offset, std::uint64_t &res, retdec: } /** - * Get NTBS (null-terminated byte string) from specified offset + * Get NTBS (null-terminated std::uint8_t string) from specified offset * @param offset Offset to get string from * @param res Result string - * @param size Requested size of string (if @a size is zero, read until zero byte) + * @param size Requested size of string (if @a size is zero, read until zero std::uint8_t) * @return Status of operation (@c true if all is OK, @c false otherwise) */ bool FileFormat::getNTBSOffset(std::uint64_t offset, std::string &res, std::size_t size) const @@ -2445,11 +2445,11 @@ void FileFormat::dump(std::string &dumpFile) ret << "; Entry point offset: " << offset << "\n"; } - ret << "; Bytes per word: " << std::dec << getBytesPerWord() << "\n"; - ret << "; Bits per word: " << getWordLength() << "\n"; - ret << "; Bits per byte: " << getByteLength() << "\n"; + ret << "; Bytes per std::uint16_t: " << std::dec << getBytesPerWord() << "\n"; + ret << "; Bits per std::uint16_t: " << getWordLength() << "\n"; + ret << "; Bits per std::uint8_t: " << getByteLength() << "\n"; ret << "; Bits per nibble: " << getNibbleLength() << "\n"; - ret << "; Nibbles per byte: " << getNumberOfNibblesInByte() << "\n"; + ret << "; Nibbles per std::uint8_t: " << getNumberOfNibblesInByte() << "\n"; if(getNumberOfSections()) { diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index 20d522fe6..02ddcae96 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -31,6 +31,8 @@ #include "retdec/fileformat/utils/conversions.h" #include "retdec/fileformat/utils/crypto.h" #include "retdec/fileformat/utils/file_io.h" +#include "retdec/crypto/crypto.h" +#include "retdec/pelib/ImageLoader.h" using namespace retdec::utils; using namespace PeLib; @@ -460,13 +462,13 @@ std::size_t findDosStub(const std::string &plainFile) * @param storageClass PE symbol storage class * @return Type of symbol */ -Symbol::Type getSymbolType(word link, dword value, byte storageClass) +Symbol::Type getSymbolType(std::uint16_t link, std::uint16_t value, std::uint8_t storageClass) { if(!link) { return value ? Symbol::Type::COMMON : Symbol::Type::EXTERN; } - else if(link == std::numeric_limits::max() || link == std::numeric_limits::max() - 1) + else if(link == std::numeric_limits::max() || link == std::numeric_limits::max() - 1) { return Symbol::Type::ABSOLUTE_SYM; } @@ -488,7 +490,7 @@ Symbol::Type getSymbolType(word link, dword value, byte storageClass) * @param complexType PE symbol type * @return Usage type of symbol */ -Symbol::UsageType getSymbolUsageType(byte storageClass, byte complexType) +Symbol::UsageType getSymbolUsageType(std::uint8_t storageClass, std::uint8_t complexType) { if(complexType >= 0x20 && complexType < 0x30) { @@ -580,16 +582,19 @@ void PeFormat::initStructures(const std::string & dllListFile) // If we got an override list of dependency DLLs, we load them into the map initDllList(dllListFile); + stateIsValid = false; - file = openPeFile(fileStream); + file = new PeFile64(fileStream); if (file) { - stateIsValid = true; try { - file->readMzHeader(); - file->readPeHeader(); - file->readCoffSymbolTable(); + if(file->loadPeHeaders(bytes) == ERROR_NONE) + stateIsValid = true; + + //file->readMzHeader(); + //file->readPeHeader(); + file->readCoffSymbolTable(bytes); file->readImportDirectory(); file->readIatDirectory(); file->readBoundImportDirectory(); @@ -617,19 +622,9 @@ void PeFormat::initStructures(const std::string & dllListFile) peHeader64 = &(f64->peHeader()); formatParser = new PeFormatParser64(this, static_cast*>(file)); } - else - { - stateIsValid = false; - } } catch(...) - { - stateIsValid = false; - } - } - else - { - stateIsValid = false; + {} } if(stateIsValid) @@ -1413,8 +1408,8 @@ void PeFormat::loadSymbols() for(std::size_t i = 0, e = symTab.getNumberOfStoredSymbols(); i < e; ++i) { auto symbol = std::make_shared(); - const word link = symTab.getSymbolSectionNumber(i); - if(!link || link == std::numeric_limits::max() || link == std::numeric_limits::max() - 1) + const std::uint16_t link = symTab.getSymbolSectionNumber(i); + if(!link || link == std::numeric_limits::max() || link == std::numeric_limits::max() - 1) { symbol->invalidateLinkToSection(); symbol->invalidateAddress(); @@ -2302,7 +2297,7 @@ void PeFormat::parseMetadataStream(std::uint64_t baseAddress, std::uint64_t offs metadataStream->setMajorVersion(majorVersion); metadataStream->setMinorVersion(minorVersion); - // 'heapOffsetSizes' define whether we should use word or dword for indexes into different streams + // 'heapOffsetSizes' define whether we should use std::uint16_t or dstd::uint16_t for indexes into different streams metadataStream->setStringStreamIndexSize(heapOffsetSizes & 0x01 ? 4 : 2); metadataStream->setGuidStreamIndexSize(heapOffsetSizes & 0x02 ? 4 : 2); metadataStream->setBlobStreamIndexSize(heapOffsetSizes & 0x04 ? 4 : 2); @@ -2494,14 +2489,14 @@ void PeFormat::parseBlobStream(std::uint64_t baseAddress, std::uint64_t offset, std::size_t inStreamOffset = 0; while (inStreamOffset < size) { - // First byte is length of next element in the blob + // First std::uint8_t is length of next element in the blob lengthSize = 1; if (!get1Byte(address + inStreamOffset, length)) { return; } - // 2-byte length encoding if the length is 10xxxxxx + // 2-std::uint8_t length encoding if the length is 10xxxxxx if ((length & 0xC0) == 0x80) { if (!get2Byte(address + inStreamOffset, length, Endianness::BIG)) @@ -2512,7 +2507,7 @@ void PeFormat::parseBlobStream(std::uint64_t baseAddress, std::uint64_t offset, length &= ~0xC000; lengthSize = 2; } - // 4-byte length encoding if the length is 110xxxxx + // 4-std::uint8_t length encoding if the length is 110xxxxx else if ((length & 0xE0) == 0xC0) { if (!get4Byte(address + inStreamOffset, length, Endianness::BIG)) @@ -2724,7 +2719,7 @@ void PeFormat::detectTypeLibId() continue; } - // Custom attributes contain one word 0x0001 at the beginning so we skip it, + // Custom attributes contain one std::uint16_t 0x0001 at the beginning so we skip it, // followed by length of the string, which is GUID we are looking for auto length = typeLibData[2]; typeLibId = retdec::utils::toLower(std::string(reinterpret_cast(typeLibData.data() + 3), length)); diff --git a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.cpp b/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.cpp index 8e48a97ce..959483a3d 100644 --- a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.cpp +++ b/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.cpp @@ -191,7 +191,7 @@ bool PeFormatParser32::getEpOffset(unsigned long long &epOffset) const } const auto offset = peEpOffset(peHeader); - if(offset == std::numeric_limits::max()) + if(offset == std::numeric_limits::max()) { return false; } diff --git a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.cpp b/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.cpp index 83962cfa0..75da5ec60 100644 --- a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.cpp +++ b/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.cpp @@ -191,7 +191,7 @@ bool PeFormatParser64::getEpOffset(unsigned long long &epOffset) const } const auto offset = peEpOffset(peHeader); - if(offset == std::numeric_limits::max()) + if(offset == std::numeric_limits::max()) { return false; } diff --git a/src/fileformat/utils/format_detection.cpp b/src/fileformat/utils/format_detection.cpp index 0014d0163..d63c4c24b 100644 --- a/src/fileformat/utils/format_detection.cpp +++ b/src/fileformat/utils/format_detection.cpp @@ -17,6 +17,7 @@ #include "retdec/fileformat/utils/byte_array_buffer.h" #include "retdec/fileformat/utils/format_detection.h" #include "retdec/pelib/PeLib.h" +#include "retdec/pelib/ImageLoader.h" using namespace retdec::utils; using namespace llvm; @@ -125,6 +126,16 @@ std::uint64_t streamSize(std::istream& stream) */ bool isPe(std::istream& stream) { + // Create instance of the ImageLoader with most benevolent flags + ImageLoader imgLoader(0); + bool bIsPe = false; + + // Load the image from stream. Only load headers. + if(imgLoader.Load(stream, 0, true) == ERROR_NONE) + bIsPe = (imgLoader.getNtSignature() == PELIB_IMAGE_NT_SIGNATURE); + return bIsPe; + +/* resetStream(stream); std::unique_ptr file(openPeFile(stream)); @@ -133,7 +144,7 @@ bool isPe(std::istream& stream) return false; } - dword signature = 0; + std::uint32_t signature = 0; try { file->readMzHeader(); @@ -154,6 +165,7 @@ bool isPe(std::istream& stream) } return signature == 0x4550 || signature == 0x50450000; +*/ } /** @@ -181,7 +193,7 @@ bool isJava(std::istream& stream) if (sys::IsLittleEndianHost) { - // Both are in big endian byte order + // Both are in big endian std::uint8_t order fatCount = sys::SwapByteOrder_32(fatCount); } @@ -212,7 +224,7 @@ bool isStrangeFeedface(std::istream& stream) if (sys::IsBigEndianHost) { - // All such files found were in little endian byte order + // All such files found were in little endian std::uint8_t order for (int i = 0; i < 4; ++i) { ints[i] = sys::SwapByteOrder_32(ints[i]); diff --git a/src/fileinfo/file_detector/pe_detector.cpp b/src/fileinfo/file_detector/pe_detector.cpp index 7f5583bd3..13502235e 100644 --- a/src/fileinfo/file_detector/pe_detector.cpp +++ b/src/fileinfo/file_detector/pe_detector.cpp @@ -82,7 +82,7 @@ void PeDetector::getFileFlags() "aggressively trim working set", "application can handle addresses larger than 2 GB", "reversed endianness", - "computer supports 32-bit words", + "computer supports 32-bit std::uint16_ts", "debugging information was removed", "copy image from removable media", "copy image from network", @@ -475,7 +475,7 @@ void PeDetector::detectArchitecture() result = "Matsushita AM33"; break; case PELIB_IMAGE_FILE_MACHINE_EBC: - result = "EFI byte code"; + result = "EFI std::uint8_t code"; break; case PELIB_IMAGE_FILE_MACHINE_MSIL: result = "MSIL - Microsoft Intermediate Language (aka CIL - Common Intermediate Language)"; diff --git a/src/fileinfo/file_wrapper/pe/pe_wrapper.cpp b/src/fileinfo/file_wrapper/pe/pe_wrapper.cpp index eafb61d7d..e64ed34ec 100644 --- a/src/fileinfo/file_wrapper/pe/pe_wrapper.cpp +++ b/src/fileinfo/file_wrapper/pe/pe_wrapper.cpp @@ -42,17 +42,17 @@ std::string getDirectoryType(unsigned long long dirIndex) * @param link Link to section in number representation * @return Link to section in string representation */ -std::string getSymbolLinkToSection(word link) +std::string getSymbolLinkToSection(std::uint16_t link) { if(!link) { return "UNDEFINED"; } - else if(link == std::numeric_limits::max()) + else if(link == std::numeric_limits::max()) { return "ABSOLUTE"; } - else if(link == std::numeric_limits::max() - 1) + else if(link == std::numeric_limits::max() - 1) { return "DEBUG"; } @@ -65,7 +65,7 @@ std::string getSymbolLinkToSection(word link) * @param type Type of symbol in number representation * @return Type of symbol in string representation */ -std::string getSymbolType(byte type) +std::string getSymbolType(std::uint8_t type) { if(type < 0x10) { diff --git a/src/pelib/BoundImportDirectory.cpp b/src/pelib/BoundImportDirectory.cpp index 57e4b9d85..59b8c46fe 100644 --- a/src/pelib/BoundImportDirectory.cpp +++ b/src/pelib/BoundImportDirectory.cpp @@ -26,7 +26,7 @@ namespace PeLib * @param wOmn Value of the OffsetModuleName of the bound import field. * @param wWfr Value of the NumberOfModuleForwarderRefs of the bound import field. **/ - int BoundImportDirectory::addBoundImport(const std::string& strModuleName, dword dwTds, word wOmn, word wWfr) + int BoundImportDirectory::addBoundImport(const std::string& strModuleName, std::uint32_t dwTds, std::uint16_t wOmn, std::uint16_t wWfr) { for (unsigned int i=0;i dwSize) { return ERROR_INVALID_FILE; @@ -128,7 +128,7 @@ namespace PeLib for (unsigned int j=0;j dwSize) { return ERROR_INVALID_FILE; @@ -174,13 +174,13 @@ namespace PeLib * @param vBuffer Buffer where the rebuilt BoundImport directory will be stored. * @param fMakeValid If this flag is true a valid directory will be produced. **/ - void BoundImportDirectory::rebuild(std::vector& vBuffer, bool fMakeValid) const + void BoundImportDirectory::rebuild(std::vector& vBuffer, bool fMakeValid) const { - std::map filename_offsets; + std::map filename_offsets; OutputBuffer obBuffer(vBuffer); - word ulNameOffset = static_cast((totalModules() + 1) * PELIB_IMAGE_BOUND_IMPORT_DESCRIPTOR::size()); + std::uint16_t ulNameOffset = static_cast((totalModules() + 1) * PELIB_IMAGE_BOUND_IMPORT_DESCRIPTOR::size()); for (unsigned int i=0;i(m_vIbd[i].strModuleName.size() + 1); + ulNameOffset += static_cast(m_vIbd[i].strModuleName.size() + 1); } else { @@ -217,7 +217,7 @@ namespace PeLib { filename_offsets[m_vIbd[i].moduleForwarders[j].strModuleName] = ulNameOffset; obBuffer << ulNameOffset; - ulNameOffset += static_cast(m_vIbd[i].moduleForwarders[j].strModuleName.size() + 1); + ulNameOffset += static_cast(m_vIbd[i].moduleForwarders[j].strModuleName.size() + 1); } else { @@ -233,9 +233,9 @@ namespace PeLib } } - obBuffer << static_cast(0); - obBuffer << static_cast(0); - obBuffer << static_cast(0); + obBuffer << static_cast(0); + obBuffer << static_cast(0); + obBuffer << static_cast(0); for (unsigned int i=0;i(m_vIbd[dwBidnr].moduleForwarders.size()); + return static_cast(m_vIbd[dwBidnr].moduleForwarders.size()); } - void BoundImportDirectory::addForwardedModule(dword dwBidnr, const std::string& name, dword timeStamp, word offsetModuleName, word forwardedModules) + void BoundImportDirectory::addForwardedModule(std::uint32_t dwBidnr, const std::string& name, std::uint32_t timeStamp, std::uint16_t offsetModuleName, std::uint16_t forwardedModules) { // XXX: Maybe test if there are already 0xFFFF forwarded modules. // XXX: Check for duplicate entries. Is it also necessary to check @@ -491,7 +491,7 @@ namespace PeLib m_vIbd[dwBidnr].moduleForwarders.push_back(ibdCurrent); } - void BoundImportDirectory::removeForwardedModule(dword dwBidnr, word forwardedModule) + void BoundImportDirectory::removeForwardedModule(std::uint32_t dwBidnr, std::uint16_t forwardedModule) { m_vIbd[dwBidnr].moduleForwarders.erase(m_vIbd[dwBidnr].moduleForwarders.begin() + forwardedModule); } diff --git a/src/pelib/CMakeLists.txt b/src/pelib/CMakeLists.txt index 840c571a5..29362a932 100644 --- a/src/pelib/CMakeLists.txt +++ b/src/pelib/CMakeLists.txt @@ -6,6 +6,7 @@ add_library(pelib STATIC DebugDirectory.cpp ExportDirectory.cpp IatDirectory.cpp + ImageLoader.cpp InputBuffer.cpp MzHeader.cpp OutputBuffer.cpp diff --git a/src/pelib/CoffSymbolTable.cpp b/src/pelib/CoffSymbolTable.cpp index 05028b97a..21ac93f9b 100644 --- a/src/pelib/CoffSymbolTable.cpp +++ b/src/pelib/CoffSymbolTable.cpp @@ -28,7 +28,7 @@ namespace PeLib for (std::size_t i = 0, e = uiSize / PELIB_IMAGE_SIZEOF_COFF_SYMBOL; i < e; ++i) { symbol.Name.clear(); - dword Zeroes, NameOffset; + std::uint32_t Zeroes, NameOffset; inputbuffer >> Zeroes; inputbuffer >> NameOffset; inputbuffer >> symbol.Value; @@ -37,7 +37,7 @@ namespace PeLib inputbuffer >> symbol.TypeSimple; inputbuffer >> symbol.StorageClass; inputbuffer >> symbol.NumberOfAuxSymbols; - symbol.Index = (PeLib::dword)i; + symbol.Index = (std::uint32_t)i; if (!Zeroes) { if (stringTableSize && NameOffset) @@ -69,71 +69,62 @@ namespace PeLib symbolTable.push_back(symbol); } - numberOfStoredSymbols = (dword)symbolTable.size(); + numberOfStoredSymbols = (std::uint32_t)symbolTable.size(); } - int CoffSymbolTable::read( - std::istream& inStream, - unsigned int uiOffset, - unsigned int uiSize) + int CoffSymbolTable::read(ByteBuffer & fileData, std::size_t uiOffset, std::size_t uiSize) { - IStreamWrapper inStream_w(inStream); - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - // Check for overflow if ((uiOffset + uiSize) < uiOffset) { return ERROR_INVALID_FILE; } - std::uint64_t ulFileSize = fileSize(inStream_w); - std::uint64_t stringTableOffset = uiOffset + uiSize; + std::size_t ulFileSize = fileData.size(); + std::size_t stringTableOffset = uiOffset + uiSize; if (uiOffset >= ulFileSize || stringTableOffset >= ulFileSize) { return ERROR_INVALID_FILE; } - inStream_w.seekg(uiOffset, std::ios::beg); - symbolTableDump.resize(uiSize); - inStream_w.read(reinterpret_cast(symbolTableDump.data()), uiSize); + // Copy part of the file data into symbol table dump + symbolTableDump.assign(fileData.begin() + uiOffset, fileData.begin() + uiOffset + uiSize); + uiOffset += uiSize; + InputBuffer ibBuffer(symbolTableDump); - // read size of string table + // Read size of string table if (ulFileSize >= stringTableOffset + 4) { - stringTable.resize(4); - inStream_w.read(reinterpret_cast(stringTable.data()), 4); - InputBuffer strBuf(stringTable); - strBuf >> stringTableSize; + memcpy(&stringTableSize, fileData.data() + stringTableOffset, sizeof(uint32_t)); + uiOffset = stringTableOffset + sizeof(uint32_t); } - if (inStream_w.gcount() < 4) - { - stringTableSize = (std::size_t)inStream_w.gcount(); - } - else if (inStream_w.gcount() == 4 && stringTableSize < 4) + if(ulFileSize > uiOffset) { - stringTableSize = 4; + if ((ulFileSize - uiOffset) < 4) + { + memcpy(&stringTableSize, fileData.data() + stringTableOffset, sizeof(uint32_t)); + } + else if ((ulFileSize - uiOffset) == 4 && stringTableSize < 4) + { + stringTableSize = 4; + } } if (stringTableSize > ulFileSize || uiOffset + stringTableSize > ulFileSize) { - stringTableSize = (std::size_t)(ulFileSize - uiOffset); + stringTableSize = (ulFileSize - uiOffset); } // read string table if (stringTableSize > 4) { stringTable.resize(stringTableSize); - inStream_w.read(reinterpret_cast(stringTable.data() + 4), stringTableSize - 4); + memcpy(stringTable.data() + 4, fileData.data() + uiOffset, stringTableSize - 4); } read(ibBuffer, uiSize); - return ERROR_NONE; } @@ -160,7 +151,7 @@ namespace PeLib return numberOfStoredSymbols; } - dword CoffSymbolTable::getSymbolIndex(std::size_t ulSymbol) const + std::uint32_t CoffSymbolTable::getSymbolIndex(std::size_t ulSymbol) const { return symbolTable[ulSymbol].Index; } @@ -170,32 +161,32 @@ namespace PeLib return symbolTable[ulSymbol].Name; } - dword CoffSymbolTable::getSymbolValue(std::size_t ulSymbol) const + std::uint32_t CoffSymbolTable::getSymbolValue(std::size_t ulSymbol) const { return symbolTable[ulSymbol].Value; } - word CoffSymbolTable::getSymbolSectionNumber(std::size_t ulSymbol) const + std::uint16_t CoffSymbolTable::getSymbolSectionNumber(std::size_t ulSymbol) const { return symbolTable[ulSymbol].SectionNumber; } - byte CoffSymbolTable::getSymbolTypeComplex(std::size_t ulSymbol) const + std::uint8_t CoffSymbolTable::getSymbolTypeComplex(std::size_t ulSymbol) const { return symbolTable[ulSymbol].TypeComplex; } - byte CoffSymbolTable::getSymbolTypeSimple(std::size_t ulSymbol) const + std::uint8_t CoffSymbolTable::getSymbolTypeSimple(std::size_t ulSymbol) const { return symbolTable[ulSymbol].TypeSimple; } - byte CoffSymbolTable::getSymbolStorageClass(std::size_t ulSymbol) const + std::uint8_t CoffSymbolTable::getSymbolStorageClass(std::size_t ulSymbol) const { return symbolTable[ulSymbol].StorageClass; } - byte CoffSymbolTable::getSymbolNumberOfAuxSymbols(std::size_t ulSymbol) const + std::uint8_t CoffSymbolTable::getSymbolNumberOfAuxSymbols(std::size_t ulSymbol) const { return symbolTable[ulSymbol].NumberOfAuxSymbols; } diff --git a/src/pelib/ComHeaderDirectory.cpp b/src/pelib/ComHeaderDirectory.cpp index f09cf4436..60476cb4e 100644 --- a/src/pelib/ComHeaderDirectory.cpp +++ b/src/pelib/ComHeaderDirectory.cpp @@ -49,7 +49,7 @@ namespace PeLib return ERROR_INVALID_FILE; } - std::vector vComDescDirectory(buffer, buffer + buffersize); + std::vector vComDescDirectory(buffer, buffer + buffersize); InputBuffer ibBuffer(vComDescDirectory); read(ibBuffer); @@ -60,7 +60,7 @@ namespace PeLib * Rebuilds the current COM+ descriptor. * @param vBuffer Buffer where the COM+ descriptor will be written to. **/ - void ComHeaderDirectory::rebuild(std::vector& vBuffer) const + void ComHeaderDirectory::rebuild(std::vector& vBuffer) const { OutputBuffer obBuffer(vBuffer); @@ -132,7 +132,7 @@ namespace PeLib /** * @return SizeOfHeader value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getSizeOfHeader() const + std::uint32_t ComHeaderDirectory::getSizeOfHeader() const { return m_ichComHeader.cb; } @@ -140,7 +140,7 @@ namespace PeLib /** * @return MajorRuntimeVersion value of the current COM+ descriptor. **/ - word ComHeaderDirectory::getMajorRuntimeVersion() const + std::uint16_t ComHeaderDirectory::getMajorRuntimeVersion() const { return m_ichComHeader.MajorRuntimeVersion; } @@ -148,7 +148,7 @@ namespace PeLib /** * @return MinorRuntimeVersion value of the current COM+ descriptor. **/ - word ComHeaderDirectory::getMinorRuntimeVersion() const + std::uint16_t ComHeaderDirectory::getMinorRuntimeVersion() const { return m_ichComHeader.MinorRuntimeVersion; } @@ -156,7 +156,7 @@ namespace PeLib /** * @return MetaData (Virtual Address) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getMetaDataVa() const + std::uint32_t ComHeaderDirectory::getMetaDataVa() const { return m_ichComHeader.MetaData.VirtualAddress; } @@ -164,7 +164,7 @@ namespace PeLib /** * @return MetaData (Size) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getMetaDataSize() const + std::uint32_t ComHeaderDirectory::getMetaDataSize() const { return m_ichComHeader.MetaData.Size; } @@ -172,7 +172,7 @@ namespace PeLib /** * @return Flags value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getFlags() const + std::uint32_t ComHeaderDirectory::getFlags() const { return m_ichComHeader.Flags; } @@ -180,7 +180,7 @@ namespace PeLib /** * @return EntryPointToken value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getEntryPointToken() const + std::uint32_t ComHeaderDirectory::getEntryPointToken() const { return m_ichComHeader.EntryPointToken; } @@ -188,7 +188,7 @@ namespace PeLib /** * @return Resources (Virtual Address) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getResourcesVa() const + std::uint32_t ComHeaderDirectory::getResourcesVa() const { return m_ichComHeader.Resources.VirtualAddress; } @@ -196,7 +196,7 @@ namespace PeLib /** * @return Resources (Size) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getResourcesSize() const + std::uint32_t ComHeaderDirectory::getResourcesSize() const { return m_ichComHeader.Resources.Size; } @@ -204,7 +204,7 @@ namespace PeLib /** * @return StrongNameSignature (Virtual Address) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getStrongNameSignatureVa() const + std::uint32_t ComHeaderDirectory::getStrongNameSignatureVa() const { return m_ichComHeader.StrongNameSignature.VirtualAddress; } @@ -212,7 +212,7 @@ namespace PeLib /** * @return StrongNameSignature (Size) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getStrongNameSignatureSize() const + std::uint32_t ComHeaderDirectory::getStrongNameSignatureSize() const { return m_ichComHeader.StrongNameSignature.Size; } @@ -220,7 +220,7 @@ namespace PeLib /** * @return CodeManagerTable (Virtual Address) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getCodeManagerTableVa() const + std::uint32_t ComHeaderDirectory::getCodeManagerTableVa() const { return m_ichComHeader.CodeManagerTable.VirtualAddress; } @@ -228,7 +228,7 @@ namespace PeLib /** * @return CodeManagerTable (Size) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getCodeManagerTableSize() const + std::uint32_t ComHeaderDirectory::getCodeManagerTableSize() const { return m_ichComHeader.CodeManagerTable.Size; } @@ -236,7 +236,7 @@ namespace PeLib /** * @return VTableFixups (Virtual Address) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getVTableFixupsVa() const + std::uint32_t ComHeaderDirectory::getVTableFixupsVa() const { return m_ichComHeader.VTableFixups.VirtualAddress; } @@ -244,7 +244,7 @@ namespace PeLib /** * @return VTableFixups (Size) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getVTableFixupsSize() const + std::uint32_t ComHeaderDirectory::getVTableFixupsSize() const { return m_ichComHeader.VTableFixups.Size; } @@ -252,7 +252,7 @@ namespace PeLib /** * @return ExportAddressTableJumps (Virtual Address) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getExportAddressTableJumpsVa() const + std::uint32_t ComHeaderDirectory::getExportAddressTableJumpsVa() const { return m_ichComHeader.ExportAddressTableJumps.VirtualAddress; } @@ -260,7 +260,7 @@ namespace PeLib /** * @return ExportAddressTableJumps (Size) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getExportAddressTableJumpsSize() const + std::uint32_t ComHeaderDirectory::getExportAddressTableJumpsSize() const { return m_ichComHeader.ExportAddressTableJumps.Size; } @@ -268,7 +268,7 @@ namespace PeLib /** * @return ManagedNativeHeader (Virtual Address) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getManagedNativeHeaderVa() const + std::uint32_t ComHeaderDirectory::getManagedNativeHeaderVa() const { return m_ichComHeader.ManagedNativeHeader.VirtualAddress; } @@ -276,7 +276,7 @@ namespace PeLib /** * @return ManagedNativeHeader (Size) value of the current COM+ descriptor. **/ - dword ComHeaderDirectory::getManagedNativeHeaderSize() const + std::uint32_t ComHeaderDirectory::getManagedNativeHeaderSize() const { return m_ichComHeader.ManagedNativeHeader.Size; } @@ -284,7 +284,7 @@ namespace PeLib /** * @param dwValue New value for the current SizeOfHeader (cb) value. **/ - void ComHeaderDirectory::setSizeOfHeader(dword dwValue) + void ComHeaderDirectory::setSizeOfHeader(std::uint32_t dwValue) { m_ichComHeader.cb = dwValue; } @@ -292,7 +292,7 @@ namespace PeLib /** * @param wValue New value for the current MajorRuntimeVersion value. **/ - void ComHeaderDirectory::setMajorRuntimeVersion(word wValue) + void ComHeaderDirectory::setMajorRuntimeVersion(std::uint16_t wValue) { m_ichComHeader.MajorRuntimeVersion = wValue; } @@ -300,7 +300,7 @@ namespace PeLib /** * @param wValue New value for the current MinorRuntimeVersion value. **/ - void ComHeaderDirectory::setMinorRuntimeVersion(word wValue) + void ComHeaderDirectory::setMinorRuntimeVersion(std::uint16_t wValue) { m_ichComHeader.MinorRuntimeVersion = wValue; } @@ -308,7 +308,7 @@ namespace PeLib /** * @param dwValue New value for the current MetaData (VirtualAddress) value. **/ - void ComHeaderDirectory::setMetaDataVa(dword dwValue) + void ComHeaderDirectory::setMetaDataVa(std::uint32_t dwValue) { m_ichComHeader.MetaData.VirtualAddress = dwValue; } @@ -316,7 +316,7 @@ namespace PeLib /** * @param dwValue New value for the current MetaData (Size) value. **/ - void ComHeaderDirectory::setMetaDataSize(dword dwValue) + void ComHeaderDirectory::setMetaDataSize(std::uint32_t dwValue) { m_ichComHeader.MetaData.Size = dwValue; } @@ -324,7 +324,7 @@ namespace PeLib /** * @param dwValue New value for the current Flags value. **/ - void ComHeaderDirectory::setFlags(dword dwValue) + void ComHeaderDirectory::setFlags(std::uint32_t dwValue) { m_ichComHeader.Flags = dwValue; } @@ -332,7 +332,7 @@ namespace PeLib /** * @param dwValue New value for the current EntryPointToken value. **/ - void ComHeaderDirectory::setEntryPointToken(dword dwValue) + void ComHeaderDirectory::setEntryPointToken(std::uint32_t dwValue) { m_ichComHeader.EntryPointToken = dwValue; } @@ -340,7 +340,7 @@ namespace PeLib /** * @param dwValue New value for the current Resources (VirtualAddress) value. **/ - void ComHeaderDirectory::setResourcesVa(dword dwValue) + void ComHeaderDirectory::setResourcesVa(std::uint32_t dwValue) { m_ichComHeader.Resources.VirtualAddress = dwValue; } @@ -348,7 +348,7 @@ namespace PeLib /** * @param dwValue New value for the current Resources (Size) value. **/ - void ComHeaderDirectory::setResourcesSize(dword dwValue) + void ComHeaderDirectory::setResourcesSize(std::uint32_t dwValue) { m_ichComHeader.Resources.Size = dwValue; } @@ -356,7 +356,7 @@ namespace PeLib /** * @param dwValue New value for the current StrongNameSignature (VirtualAddress) value. **/ - void ComHeaderDirectory::setStrongNameSignatureVa(dword dwValue) + void ComHeaderDirectory::setStrongNameSignatureVa(std::uint32_t dwValue) { m_ichComHeader.StrongNameSignature.VirtualAddress = dwValue; } @@ -364,7 +364,7 @@ namespace PeLib /** * @param dwValue New value for the current StrongNameSignature (Size) value. **/ - void ComHeaderDirectory::setStrongNameSignagureSize(dword dwValue) + void ComHeaderDirectory::setStrongNameSignagureSize(std::uint32_t dwValue) { m_ichComHeader.StrongNameSignature.Size = dwValue; } @@ -372,7 +372,7 @@ namespace PeLib /** * @param dwValue New value for the current CodeManagerTable (VirtualAddress) value. **/ - void ComHeaderDirectory::setCodeManagerTableVa(dword dwValue) + void ComHeaderDirectory::setCodeManagerTableVa(std::uint32_t dwValue) { m_ichComHeader.CodeManagerTable.VirtualAddress = dwValue; } @@ -380,7 +380,7 @@ namespace PeLib /** * @param dwValue New value for the current CodeManagerTable (Size) value. **/ - void ComHeaderDirectory::setCodeManagerTableSize(dword dwValue) + void ComHeaderDirectory::setCodeManagerTableSize(std::uint32_t dwValue) { m_ichComHeader.CodeManagerTable.Size = dwValue; } @@ -388,7 +388,7 @@ namespace PeLib /** * @param dwValue New value for the current VTableFixups (VirtualAddress) value. **/ - void ComHeaderDirectory::setVTableFixupsVa(dword dwValue) + void ComHeaderDirectory::setVTableFixupsVa(std::uint32_t dwValue) { m_ichComHeader.VTableFixups.VirtualAddress = dwValue; } @@ -396,7 +396,7 @@ namespace PeLib /** * @param dwValue New value for the current VTableFixups (Size) value. **/ - void ComHeaderDirectory::setVTableFixupsSize(dword dwValue) + void ComHeaderDirectory::setVTableFixupsSize(std::uint32_t dwValue) { m_ichComHeader.VTableFixups.Size = dwValue; } @@ -404,7 +404,7 @@ namespace PeLib /** * @param dwValue New value for the current ExportAddressTableJumps (VirtualAddress) value. **/ - void ComHeaderDirectory::setExportAddressTableJumpsVa(dword dwValue) + void ComHeaderDirectory::setExportAddressTableJumpsVa(std::uint32_t dwValue) { m_ichComHeader.ExportAddressTableJumps.VirtualAddress = dwValue; } @@ -412,7 +412,7 @@ namespace PeLib /** * @param dwValue New value for the current ExportAddressTableJumps (Size) value. **/ - void ComHeaderDirectory::setExportAddressTableJumpsSize(dword dwValue) + void ComHeaderDirectory::setExportAddressTableJumpsSize(std::uint32_t dwValue) { m_ichComHeader.ExportAddressTableJumps.Size = dwValue; } @@ -420,7 +420,7 @@ namespace PeLib /** * @param dwValue New value for the current ManagedNativeHeader (VirtualAddress) value. **/ - void ComHeaderDirectory::setManagedNativeHeaderVa(dword dwValue) + void ComHeaderDirectory::setManagedNativeHeaderVa(std::uint32_t dwValue) { m_ichComHeader.ManagedNativeHeader.VirtualAddress = dwValue; } @@ -428,7 +428,7 @@ namespace PeLib /** * @param dwValue New value for the current ManagedNativeHeader (Size) value. **/ - void ComHeaderDirectory::setManagedNativeHeaderSize(dword dwValue) + void ComHeaderDirectory::setManagedNativeHeaderSize(std::uint32_t dwValue) { m_ichComHeader.ManagedNativeHeader.Size = dwValue; } diff --git a/src/pelib/DebugDirectory.cpp b/src/pelib/DebugDirectory.cpp index 92ea983ac..aeb0a024a 100644 --- a/src/pelib/DebugDirectory.cpp +++ b/src/pelib/DebugDirectory.cpp @@ -58,7 +58,7 @@ namespace PeLib // XXX: Note, debug data is not read at all. This might or might not change // in the future. - std::vector vDebugDirectory(buffer, buffer + buffersize); + std::vector vDebugDirectory(buffer, buffer + buffersize); InputBuffer ibBuffer(vDebugDirectory); @@ -73,7 +73,7 @@ namespace PeLib * Rebuilds the current debug directory. * @param vBuffer Buffer where the rebuilt directory is stored. **/ - void DebugDirectory::rebuild(std::vector& vBuffer) const + void DebugDirectory::rebuild(std::vector& vBuffer) const { OutputBuffer obBuffer(vBuffer); @@ -168,7 +168,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @return Characteristics value of the debug structure. **/ - dword DebugDirectory::getCharacteristics(std::size_t uiIndex) const + std::uint32_t DebugDirectory::getCharacteristics(std::size_t uiIndex) const { return m_vDebugInfo[uiIndex].idd.Characteristics; } @@ -179,7 +179,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @return TimeDateStamp value of the debug structure. **/ - dword DebugDirectory::getTimeDateStamp(std::size_t uiIndex) const + std::uint32_t DebugDirectory::getTimeDateStamp(std::size_t uiIndex) const { return m_vDebugInfo[uiIndex].idd.TimeDateStamp; } @@ -190,7 +190,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @return MajorVersion value of the debug structure. **/ - word DebugDirectory::getMajorVersion(std::size_t uiIndex) const + std::uint16_t DebugDirectory::getMajorVersion(std::size_t uiIndex) const { return m_vDebugInfo[uiIndex].idd.MajorVersion; } @@ -201,7 +201,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @return MinorVersion value of the debug structure. **/ - word DebugDirectory::getMinorVersion(std::size_t uiIndex) const + std::uint16_t DebugDirectory::getMinorVersion(std::size_t uiIndex) const { return m_vDebugInfo[uiIndex].idd.MinorVersion; } @@ -212,7 +212,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @return Type value of the debug structure. **/ - dword DebugDirectory::getType(std::size_t uiIndex) const + std::uint32_t DebugDirectory::getType(std::size_t uiIndex) const { return m_vDebugInfo[uiIndex].idd.Type; } @@ -223,7 +223,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @return SizeOfData value of the debug structure. **/ - dword DebugDirectory::getSizeOfData(std::size_t uiIndex) const + std::uint32_t DebugDirectory::getSizeOfData(std::size_t uiIndex) const { return m_vDebugInfo[uiIndex].idd.SizeOfData; } @@ -234,7 +234,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @return AddressOfRawData value of the debug structure. **/ - dword DebugDirectory::getAddressOfRawData(std::size_t uiIndex) const + std::uint32_t DebugDirectory::getAddressOfRawData(std::size_t uiIndex) const { return m_vDebugInfo[uiIndex].idd.AddressOfRawData; } @@ -245,12 +245,12 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @return PointerToRawData value of the debug structure. **/ - dword DebugDirectory::getPointerToRawData(std::size_t uiIndex) const + std::uint32_t DebugDirectory::getPointerToRawData(std::size_t uiIndex) const { return m_vDebugInfo[uiIndex].idd.PointerToRawData; } - std::vector DebugDirectory::getData(std::size_t index) const + std::vector DebugDirectory::getData(std::size_t index) const { return m_vDebugInfo[index].data; } @@ -261,7 +261,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @param dwValue New value of the Characteristics value of the debug structure. **/ - void DebugDirectory::setCharacteristics(std::size_t uiIndex, dword dwValue) + void DebugDirectory::setCharacteristics(std::size_t uiIndex, std::uint32_t dwValue) { m_vDebugInfo[uiIndex].idd.Characteristics = dwValue; } @@ -272,7 +272,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @param dwValue New value of the TimeDateStamp value of the debug structure. **/ - void DebugDirectory::setTimeDateStamp(std::size_t uiIndex, dword dwValue) + void DebugDirectory::setTimeDateStamp(std::size_t uiIndex, std::uint32_t dwValue) { m_vDebugInfo[uiIndex].idd.TimeDateStamp = dwValue; } @@ -283,7 +283,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @param wValue New value of the MajorVersion value of the debug structure. **/ - void DebugDirectory::setMajorVersion(std::size_t uiIndex, word wValue) + void DebugDirectory::setMajorVersion(std::size_t uiIndex, std::uint16_t wValue) { m_vDebugInfo[uiIndex].idd.MajorVersion = wValue; } @@ -294,7 +294,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @param wValue New value of the MinorVersion value of the debug structure. **/ - void DebugDirectory::setMinorVersion(std::size_t uiIndex, word wValue) + void DebugDirectory::setMinorVersion(std::size_t uiIndex, std::uint16_t wValue) { m_vDebugInfo[uiIndex].idd.MinorVersion = wValue; } @@ -305,7 +305,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @param dwValue New value of the Type value of the debug structure. **/ - void DebugDirectory::setType(std::size_t uiIndex, dword dwValue) + void DebugDirectory::setType(std::size_t uiIndex, std::uint32_t dwValue) { m_vDebugInfo[uiIndex].idd.Type = dwValue; } @@ -316,7 +316,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @param dwValue New value of the SizeOfData value of the debug structure. **/ - void DebugDirectory::setSizeOfData(std::size_t uiIndex, dword dwValue) + void DebugDirectory::setSizeOfData(std::size_t uiIndex, std::uint32_t dwValue) { m_vDebugInfo[uiIndex].idd.SizeOfData = dwValue; } @@ -327,7 +327,7 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @param dwValue New value of the AddressOfRawData value of the debug structure. **/ - void DebugDirectory::setAddressOfRawData(std::size_t uiIndex, dword dwValue) + void DebugDirectory::setAddressOfRawData(std::size_t uiIndex, std::uint32_t dwValue) { m_vDebugInfo[uiIndex].idd.AddressOfRawData = dwValue; } @@ -338,12 +338,12 @@ namespace PeLib * @param uiIndex Identifies the debug structure. * @param dwValue New value of the PointerToRawData value of the debug structure. **/ - void DebugDirectory::setPointerToRawData(std::size_t uiIndex, dword dwValue) + void DebugDirectory::setPointerToRawData(std::size_t uiIndex, std::uint32_t dwValue) { m_vDebugInfo[uiIndex].idd.PointerToRawData = dwValue; } - void DebugDirectory::setData(std::size_t index, const std::vector& data) + void DebugDirectory::setData(std::size_t index, const std::vector& data) { m_vDebugInfo[index].data = data; } diff --git a/src/pelib/ExportDirectory.cpp b/src/pelib/ExportDirectory.cpp index 32f210523..896564182 100644 --- a/src/pelib/ExportDirectory.cpp +++ b/src/pelib/ExportDirectory.cpp @@ -19,7 +19,7 @@ namespace PeLib * @param strFuncname Name of the function. * @param dwFuncAddr RVA of the function. **/ - void ExportDirectory::addFunction(const std::string& strFuncname, dword dwFuncAddr) + void ExportDirectory::addFunction(const std::string& strFuncname, std::uint32_t dwFuncAddr) { PELIB_EXP_FUNC_INFORMATION efiCurr; efiCurr.funcname = strFuncname; @@ -69,7 +69,7 @@ namespace PeLib * @param dwRva RVA of the export directory. * \todo fValid flag **/ - void ExportDirectory::rebuild(std::vector& vBuffer, dword dwRva) const + void ExportDirectory::rebuild(std::vector& vBuffer, std::uint32_t dwRva) const { unsigned int uiSizeDirectory = sizeof(PELIB_IMAGE_EXPORT_DIRECTORY); @@ -220,7 +220,7 @@ namespace PeLib * @param dwIndex Number which identifies an exported function. * @return The ordinal of that function. **/ - word ExportDirectory::getFunctionOrdinal(std::size_t dwIndex) const + std::uint16_t ExportDirectory::getFunctionOrdinal(std::size_t dwIndex) const { return m_ied.functions[dwIndex].ordinal; } @@ -229,7 +229,7 @@ namespace PeLib * @param dwIndex Number which identifies an exported function. * @return The RVA of the name string of that function. **/ - dword ExportDirectory::getAddressOfName(std::size_t dwIndex) const + std::uint32_t ExportDirectory::getAddressOfName(std::size_t dwIndex) const { return m_ied.functions[dwIndex].addrofname; } @@ -238,7 +238,7 @@ namespace PeLib * @param dwIndex Number which identifies an exported function. * @return The RVA of that function. **/ - dword ExportDirectory::getAddressOfFunction(std::size_t dwIndex) const + std::uint32_t ExportDirectory::getAddressOfFunction(std::size_t dwIndex) const { return m_ied.functions[dwIndex].addroffunc; } @@ -256,7 +256,7 @@ namespace PeLib * @param dwIndex Number which identifies an exported function. * @param wValue The ordinal of that function. **/ - void ExportDirectory::setFunctionOrdinal(std::size_t dwIndex, word wValue) + void ExportDirectory::setFunctionOrdinal(std::size_t dwIndex, std::uint16_t wValue) { m_ied.functions[dwIndex].ordinal = wValue; } @@ -265,7 +265,7 @@ namespace PeLib * @param dwIndex Number which identifies an exported function. * @param dwValue The RVA of the name string of that function. **/ - void ExportDirectory::setAddressOfName(std::size_t dwIndex, dword dwValue) + void ExportDirectory::setAddressOfName(std::size_t dwIndex, std::uint32_t dwValue) { m_ied.functions[dwIndex].addrofname = dwValue; } @@ -274,7 +274,7 @@ namespace PeLib * @param dwIndex Number which identifies an exported function. * @param dwValue The RVA of that function. **/ - void ExportDirectory::setAddressOfFunction(std::size_t dwIndex, dword dwValue) + void ExportDirectory::setAddressOfFunction(std::size_t dwIndex, std::uint32_t dwValue) { m_ied.functions[dwIndex].addroffunc = dwValue; } @@ -282,7 +282,7 @@ namespace PeLib /** * @return The ordinal base of the export directory. **/ - dword ExportDirectory::getBase() const + std::uint32_t ExportDirectory::getBase() const { return m_ied.ied.Base; } @@ -290,7 +290,7 @@ namespace PeLib /** * @return The characteristics of the export directory. **/ - dword ExportDirectory::getCharacteristics() const + std::uint32_t ExportDirectory::getCharacteristics() const { return m_ied.ied.Characteristics; } @@ -298,7 +298,7 @@ namespace PeLib /** * @return The time/date stamp of the export directory. **/ - dword ExportDirectory::getTimeDateStamp() const + std::uint32_t ExportDirectory::getTimeDateStamp() const { return m_ied.ied.TimeDateStamp; } @@ -306,7 +306,7 @@ namespace PeLib /** * @return The MajorVersion of the export directory. **/ - word ExportDirectory::getMajorVersion() const + std::uint16_t ExportDirectory::getMajorVersion() const { return m_ied.ied.MajorVersion; } @@ -314,7 +314,7 @@ namespace PeLib /** * @return The MinorVersion of the export directory. **/ - word ExportDirectory::getMinorVersion() const + std::uint16_t ExportDirectory::getMinorVersion() const { return m_ied.ied.MinorVersion; } @@ -322,7 +322,7 @@ namespace PeLib /** * @return The RVA of the name of the file. **/ - dword ExportDirectory::getName() const + std::uint32_t ExportDirectory::getName() const { return m_ied.ied.Name; } @@ -330,7 +330,7 @@ namespace PeLib /** * @return The NumberOfFunctions of the export directory. **/ - dword ExportDirectory::getNumberOfFunctions() const + std::uint32_t ExportDirectory::getNumberOfFunctions() const { return m_ied.ied.NumberOfFunctions; } @@ -338,7 +338,7 @@ namespace PeLib /** * @return The NumberOfNames of the export directory. **/ - dword ExportDirectory::getNumberOfNames() const + std::uint32_t ExportDirectory::getNumberOfNames() const { return m_ied.ied.NumberOfNames; } @@ -346,7 +346,7 @@ namespace PeLib /** * @return The AddressOfFunctions of the export directory. **/ - dword ExportDirectory::getAddressOfFunctions() const + std::uint32_t ExportDirectory::getAddressOfFunctions() const { return m_ied.ied.AddressOfFunctions; } @@ -354,30 +354,30 @@ namespace PeLib /** * @return The AddressOfNames of the export directory. **/ - dword ExportDirectory::getAddressOfNames() const + std::uint32_t ExportDirectory::getAddressOfNames() const { return m_ied.ied.AddressOfNames; } -/* dword ExportDirectory::getNumberOfNameOrdinals() const +/* std::uint32_t ExportDirectory::getNumberOfNameOrdinals() const { - return static_cast(m_ied.functions.size()); + return static_cast(m_ied.functions.size()); } - dword ExportDirectory::getNumberOfAddressOfFunctionNames() const + std::uint32_t ExportDirectory::getNumberOfAddressOfFunctionNames() const { - return static_cast(m_ied.functions.size()); + return static_cast(m_ied.functions.size()); } - dword ExportDirectory::getNumberOfAddressOfFunctions() const + std::uint32_t ExportDirectory::getNumberOfAddressOfFunctions() const { - return static_cast(m_ied.functions.size()); + return static_cast(m_ied.functions.size()); } */ /** * @return The AddressOfNameOrdinals of the export directory. **/ - dword ExportDirectory::getAddressOfNameOrdinals() const + std::uint32_t ExportDirectory::getAddressOfNameOrdinals() const { return m_ied.ied.AddressOfNameOrdinals; } @@ -385,7 +385,7 @@ namespace PeLib /** * @param dwValue The ordinal base of the export directory. **/ - void ExportDirectory::setBase(dword dwValue) + void ExportDirectory::setBase(std::uint32_t dwValue) { m_ied.ied.Base = dwValue; } @@ -393,7 +393,7 @@ namespace PeLib /** * @param dwValue The Characteristics of the export directory. **/ - void ExportDirectory::setCharacteristics(dword dwValue) + void ExportDirectory::setCharacteristics(std::uint32_t dwValue) { m_ied.ied.Characteristics = dwValue; } @@ -401,7 +401,7 @@ namespace PeLib /** * @param dwValue The TimeDateStamp of the export directory. **/ - void ExportDirectory::setTimeDateStamp(dword dwValue) + void ExportDirectory::setTimeDateStamp(std::uint32_t dwValue) { m_ied.ied.TimeDateStamp = dwValue; } @@ -409,7 +409,7 @@ namespace PeLib /** * @param wValue The MajorVersion of the export directory. **/ - void ExportDirectory::setMajorVersion(word wValue) + void ExportDirectory::setMajorVersion(std::uint16_t wValue) { m_ied.ied.MajorVersion = wValue; } @@ -417,7 +417,7 @@ namespace PeLib /** * @param wValue The MinorVersion of the export directory. **/ - void ExportDirectory::setMinorVersion(word wValue) + void ExportDirectory::setMinorVersion(std::uint16_t wValue) { m_ied.ied.MinorVersion = wValue; } @@ -425,7 +425,7 @@ namespace PeLib /** * @param dwValue The Name of the export directory. **/ - void ExportDirectory::setName(dword dwValue) + void ExportDirectory::setName(std::uint32_t dwValue) { m_ied.ied.Name = dwValue; } @@ -433,7 +433,7 @@ namespace PeLib /** * @param dwValue The NumberOfFunctions of the export directory. **/ - void ExportDirectory::setNumberOfFunctions(dword dwValue) + void ExportDirectory::setNumberOfFunctions(std::uint32_t dwValue) { m_ied.ied.NumberOfFunctions = dwValue; } @@ -441,7 +441,7 @@ namespace PeLib /** * @param dwValue The NumberOfNames of the export directory. **/ - void ExportDirectory::setNumberOfNames(dword dwValue) + void ExportDirectory::setNumberOfNames(std::uint32_t dwValue) { m_ied.ied.NumberOfNames = dwValue; } @@ -449,7 +449,7 @@ namespace PeLib /** * @param dwValue The AddressOfFunctions of the export directory. **/ - void ExportDirectory::setAddressOfFunctions(dword dwValue) + void ExportDirectory::setAddressOfFunctions(std::uint32_t dwValue) { m_ied.ied.AddressOfFunctions = dwValue; } @@ -457,12 +457,12 @@ namespace PeLib /** * @param dwValue The AddressOfNames of the export directory. **/ - void ExportDirectory::setAddressOfNames(dword dwValue) + void ExportDirectory::setAddressOfNames(std::uint32_t dwValue) { m_ied.ied.AddressOfNames = dwValue; } - void ExportDirectory::setAddressOfNameOrdinals(dword value) + void ExportDirectory::setAddressOfNameOrdinals(std::uint32_t value) { m_ied.ied.AddressOfNameOrdinals = value; } diff --git a/src/pelib/IatDirectory.cpp b/src/pelib/IatDirectory.cpp index ace43bda0..ab76e2469 100644 --- a/src/pelib/IatDirectory.cpp +++ b/src/pelib/IatDirectory.cpp @@ -16,9 +16,9 @@ namespace PeLib { int IatDirectory::read(InputBuffer& inputBuffer, unsigned int dwOffset, unsigned int dwFileSize) { - dword dwAddr; + std::uint32_t dwAddr; - std::vector vIat; + std::vector vIat; unsigned int dwCurrentOffset = dwOffset; while (dwCurrentOffset < dwFileSize) @@ -38,11 +38,38 @@ namespace PeLib int IatDirectory::read(unsigned char* buffer, unsigned int buffersize) { - std::vector vBuffer(buffer, buffer + buffersize); + std::vector vBuffer(buffer, buffer + buffersize); InputBuffer inpBuffer(vBuffer); return read(inpBuffer, 0, buffersize); } + /** + * Reads the Import Address table from a file. + * @param inStream Input stream. + * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. + **/ + int IatDirectory::read(ImageLoader & imageLoader) + { + std::uint32_t iatRva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IAT); + std::uint32_t iatSize = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_IAT); + std::uint32_t sizeofImage = imageLoader.getSizeOfImage(); + + // Check whether the IAT is outside the image + if(iatRva >= sizeofImage) + { + return ERROR_INVALID_FILE; + } + + // Read the IAT from the image + std::uint32_t dwSize = std::min(sizeofImage - iatRva, iatSize); + std::vector vBuffer(dwSize); + imageLoader.readImage(reinterpret_cast(vBuffer.data()), iatRva, dwSize); + + InputBuffer inpBuffer{vBuffer}; + return IatDirectory::read(inpBuffer, 0, dwSize); + } + + /** * Returns the number of fields in the IAT. This is equivalent to the number of * imported functions. @@ -58,7 +85,7 @@ namespace PeLib * @param index Number identifying the field. * @return dwValue of the field. **/ - dword IatDirectory::getAddress(unsigned int index) const + std::uint32_t IatDirectory::getAddress(unsigned int index) const { return m_vIat[index]; } @@ -68,7 +95,7 @@ namespace PeLib * @param dwAddrnr Number identifying the field. * @param dwValue New dwValue of the field. **/ - void IatDirectory::setAddress(dword dwAddrnr, dword dwValue) + void IatDirectory::setAddress(std::uint32_t dwAddrnr, std::uint32_t dwValue) { m_vIat[dwAddrnr] = dwValue; } @@ -77,7 +104,7 @@ namespace PeLib * Adds another field to the IAT. * @param dwValue dwValue of the new field. **/ - void IatDirectory::addAddress(dword dwValue) + void IatDirectory::addAddress(std::uint32_t dwValue) { m_vIat.push_back(dwValue); } @@ -88,7 +115,7 @@ namespace PeLib **/ void IatDirectory::removeAddress(unsigned int index) { - std::vector::iterator pos = m_vIat.begin() + index; + std::vector::iterator pos = m_vIat.begin() + index; m_vIat.erase(pos); } @@ -104,7 +131,7 @@ namespace PeLib * Rebuilds the complete Import Address Table. * @param vBuffer Buffer where the rebuilt IAT will be stored. **/ - void IatDirectory::rebuild(std::vector& vBuffer) const + void IatDirectory::rebuild(std::vector& vBuffer) const { vBuffer.resize(size()); OutputBuffer obBuffer(vBuffer); @@ -117,7 +144,7 @@ namespace PeLib unsigned int IatDirectory::size() const { - return static_cast(m_vIat.size())* sizeof(dword); + return static_cast(m_vIat.size())* sizeof(std::uint32_t); } /// Writes the current IAT to a file. diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index d009ede7a..9e0e7c51b 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -11,7 +11,7 @@ #include #include -#include "ImageLoader.h" +#include "retdec/pelib/ImageLoader.h" //----------------------------------------------------------------------------- // Anti-headache @@ -56,6 +56,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) memset(&dosHeader, 0, sizeof(PELIB_IMAGE_DOS_HEADER)); memset(&fileHeader, 0, sizeof(PELIB_IMAGE_FILE_HEADER)); memset(&optionalHeader, 0, sizeof(PELIB_IMAGE_OPTIONAL_HEADER)); + ntSignature = 0; ldrError = LDR_ERROR_NONE; // By default, set the most benevolent settings @@ -148,6 +149,102 @@ uint32_t PeLib::ImageLoader::writeImage(void * buffer, std::uint32_t rva, std::u return readWriteImage(buffer, rva, bytesToRead, writeToPage); } +uint32_t PeLib::ImageLoader::stringLength(uint32_t rva, uint32_t maxLength) const +{ + uint32_t rvaBegin = rva; + uint32_t rvaEnd = rva + maxLength; + + // Check the last possible address where we read + if(rvaEnd > getSizeOfImageAligned()) + rvaEnd = getSizeOfImageAligned(); + + // Is the offset within the image? + if(rva < rvaEnd) + { + size_t pageIndex = rva / PELIB_PAGE_SIZE; + + // The page index must be in range + if(pageIndex < pages.size()) + { + while(rva < rvaEnd) + { + const PELIB_FILE_PAGE & page = pages[pageIndex]; + uint32_t rvaEndPage = (pageIndex + 1) * PELIB_PAGE_SIZE; + + // If zero page, means we found an RVA with zero + if(page.buffer.empty()) + return rva; + + // Perhaps the last page loaded? + if(rvaEndPage > rvaEnd) + rvaEndPage = rvaEnd; + + // Try to find the zero byte on the page + for(; rva < rvaEndPage; rva++) + { + if(page.buffer[rva & (PELIB_PAGE_SIZE - 1)] == 0) + { + return rva; + } + } + + // Move pointers + pageIndex++; + } + } + } + + // Return the offset of the zero byte on the page + return rva - rvaBegin; +} + +uint32_t PeLib::ImageLoader::readString(std::string & str, uint32_t rva, uint32_t maxLength) +{ + // Check the length of the string at the rva + uint32_t length = stringLength(rva, maxLength); + + // Allocate needeed size in the string + str.resize(length + 1); + + // Read the string from the image + readImage((void *)str.data(), rva, length); + return length; +} + +uint32_t PeLib::ImageLoader::readPointer(uint32_t rva, uint64_t & pointerValue) +{ + uint32_t bytesRead = 0; + + switch(getPeFileBitability()) + { + case 64: + if(readImage(&pointerValue, rva, sizeof(uint64_t)) == sizeof(uint64_t)) + return sizeof(uint64_t); + break; + + case 32: + { + uint32_t pointerValue32 = 0; + + bytesRead = readImage(&pointerValue32, rva, sizeof(uint32_t)); + if(bytesRead == sizeof(uint32_t)) + { + pointerValue = pointerValue32; + return sizeof(uint32_t); + } + + break; + } + } + + return 0; +} + +uint32_t PeLib::ImageLoader::pointerSize() const +{ + return getPeFileBitability() / 8; +} + uint32_t PeLib::ImageLoader::dumpImage(const char * fileName) { // Create the file for dumping @@ -172,22 +269,65 @@ uint32_t PeLib::ImageLoader::dumpImage(const char * fileName) return bytesWritten; } -uint64_t PeLib::ImageLoader::getImageBase() +uint32_t PeLib::ImageLoader::getPeFileBitability() const +{ + if(fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_AMD64 || fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_IA64) + return 64; + + if(fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_I386) + return 32; + + return 0; +} + +uint32_t PeLib::ImageLoader::getNtSignature() const +{ + return ntSignature; +} + +uint32_t PeLib::ImageLoader::getPointerToSymbolTable() const +{ + return fileHeader.PointerToSymbolTable; +} + +uint32_t PeLib::ImageLoader::getNumberOfSymbols() const +{ + return fileHeader.NumberOfSymbols; +} + +uint64_t PeLib::ImageLoader::getImageBase() const { return optionalHeader.ImageBase; } -uint32_t PeLib::ImageLoader::getSizeOfImage() +uint32_t PeLib::ImageLoader::getSizeOfHeaders() const +{ + return optionalHeader.SizeOfHeaders; +} + +uint32_t PeLib::ImageLoader::getSizeOfImage() const { return optionalHeader.SizeOfImage; } -uint32_t PeLib::ImageLoader::getSizeOfImageAligned() +uint32_t PeLib::ImageLoader::getSizeOfImageAligned() const { return AlignToSize(optionalHeader.SizeOfImage, PELIB_PAGE_SIZE); } -uint32_t PeLib::ImageLoader::getFileOffsetFromRva(std::uint32_t rva) +uint32_t PeLib::ImageLoader::getDataDirRva(size_t dataDirIndex) const +{ + // The data directory must be present there + return (optionalHeader.NumberOfRvaAndSizes > dataDirIndex) ? optionalHeader.DataDirectory[dataDirIndex].VirtualAddress : 0; +} + +uint32_t PeLib::ImageLoader::getDataDirSize(size_t dataDirIndex) const +{ + // The data directory must be present there + return (optionalHeader.NumberOfRvaAndSizes > dataDirIndex) ? optionalHeader.DataDirectory[dataDirIndex].Size : 0; +} + +uint32_t PeLib::ImageLoader::getFileOffsetFromRva(std::uint32_t rva) const { // If we have sections loaded, then we calculate the file offset from section headers if(sections.size()) @@ -218,7 +358,7 @@ uint32_t PeLib::ImageLoader::getFileOffsetFromRva(std::uint32_t rva) return rva; } -uint32_t PeLib::ImageLoader::getImageProtection(std::uint32_t sectionCharacteristics) +uint32_t PeLib::ImageLoader::getImageProtection(std::uint32_t sectionCharacteristics) const { uint32_t Index = 0; @@ -280,49 +420,79 @@ int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOn // Shall we map the image content? if(loadHeadersOnly == false) { - // If there was no detected image error, map the image as if Windows loader would do - if(ldrError == LDR_ERROR_NONE || ldrError == LDR_ERROR_FILE_IS_CUT_LOADABLE) + // Large amount of memory may be allocated during loading the image to memory. + // We need to handle low memory condition carefully here + try { - fileError = captureImageSections(fileData); - } + // If there was no detected image error, map the image as if Windows loader would do + if(ldrError == LDR_ERROR_NONE || ldrError == LDR_ERROR_FILE_IS_CUT_LOADABLE) + { + fileError = captureImageSections(fileData); + } - // If there was any kind of error that prevents the image from being mapped, - // we load the content as-is and translate virtual addresses using getFileOffsetFromRva - if(pages.size() == 0) + // If there was any kind of error that prevents the image from being mapped, + // we load the content as-is and translate virtual addresses using getFileOffsetFromRva + if(pages.size() == 0) + { + fileError = loadImageAsIs(fileData); + } + } + catch(const std::bad_alloc&) { - fileError = loadImageAsIs(fileData); + fileError = ERROR_NOT_ENOUGH_SPACE; } } return fileError; } -int PeLib::ImageLoader::Load(std::ifstream & fs, std::streamoff fileOffset, bool loadHeadersOnly) +int PeLib::ImageLoader::Load(std::istream & fs, std::streamoff fileOffset, bool loadHeadersOnly) { std::vector fileData; std::streampos fileSize; size_t fileSize2; + int fileError; - // Get the file size and move to the desired offset + // Get the file size fs.seekg(0, std::ios::end); fileSize = fs.tellg(); - fs.seekg(fileOffset); - // The file must be greater than sizeof DOS header - if(fileSize < sizeof(PELIB_IMAGE_DOS_HEADER)) + // Verify overflow of the file offset + if(fileOffset > fileSize) return ERROR_INVALID_FILE; - + // Windows loader refuses to load any file which is larger than 0xFFFFFFFF - if((fileSize >> 32) != 0) + if(((fileSize - fileOffset) >> 32) != 0) return setLoaderError(LDR_ERROR_FILE_TOO_BIG); - fileSize2 = static_cast(fileSize); + fileSize2 = static_cast(fileSize - fileOffset); - // Resize the vector so it can hold entire file - fileData.resize(fileSize2); + // Optimization: Read and verify IMAGE_DOS_HEADER first to see if it *could* be a PE file + // This prevents reading the entire file (possibly a very large one) just to find out it's not a PE + if((fileError = verifyDosHeader(fs, fileOffset, fileSize2)) != ERROR_NONE) + return fileError; - // Read the entire file to memory - if(fs.read(reinterpret_cast(fileData.data()), fileSize2).bad()) - return false; + // Resize the vector so it can hold entire file. Note that this can + // potentially allocate a very large memory block, so we need to handle that carefully + try + { + fileData.resize(fileSize2); + } + catch(const std::bad_alloc&) + { + return ERROR_NOT_ENOUGH_SPACE; + } + + // Read the entire file to memory. Note that under Windows + // and under low memory condition, the underlying OS call (NtReadFile) + // can fail on low memory. When that happens, fs.read will read less than + // required. We need to verify the number of bytes read + // and set the low memory condition flag + fs.seekg(fileOffset); + fs.read(reinterpret_cast(fileData.data()), fileSize2); + if(fs.gcount() < (fileSize - fileOffset)) + { + return ERROR_NOT_ENOUGH_SPACE; + } // Call the Load interface on char buffer return Load(fileData, loadHeadersOnly); @@ -584,14 +754,7 @@ int PeLib::ImageLoader::captureDosHeader(std::vector & fileData) memcpy(&dosHeader, fileBegin, sizeof(PELIB_IMAGE_DOS_HEADER)); // Verify DOS header - if(dosHeader.e_magic != PELIB_IMAGE_DOS_SIGNATURE) - return ERROR_INVALID_FILE; - if(dosHeader.e_lfanew & 3) - return setLoaderError(LDR_ERROR_E_LFANEW_UNALIGNED); - if(dosHeader.e_lfanew > fileData.size()) - return setLoaderError(LDR_ERROR_E_LFANEW_OUT_OF_FILE); - - return ERROR_NONE; + return verifyDosHeader(dosHeader, fileData.size()); } int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) @@ -599,7 +762,6 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) uint8_t * fileBegin = fileData.data(); uint8_t * filePtr = fileBegin + dosHeader.e_lfanew; uint8_t * fileEnd = fileBegin + fileData.size(); - uint32_t ntSignature; size_t ntHeaderSize; // Windows 7 or newer require that the file size is greater or equal to sizeof(IMAGE_NT_HEADERS) @@ -758,12 +920,12 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) // Read and verify all section headers for(uint16_t i = 0; i < fileHeader.NumberOfSections; i++) { - PELIB_IMAGE_SECTION_HEADER sectHdr{}; + PELIB_IMAGE_SECTION_HEADER_BASE sectHdr{}; // Capture one section header - if((filePtr + sizeof(PELIB_IMAGE_SECTION_HEADER)) > fileEnd) + if((filePtr + sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)) > fileEnd) break; - memcpy(§Hdr, filePtr, sizeof(PELIB_IMAGE_SECTION_HEADER)); + memcpy(§Hdr, filePtr, sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)); uint32_t PointerToRawData = (sectHdr.SizeOfRawData != 0) ? sectHdr.PointerToRawData : 0; uint32_t EndOfRawData = PointerToRawData + sectHdr.SizeOfRawData; @@ -825,7 +987,7 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) // Insert the header to the list sections.push_back(sectHdr); - filePtr += sizeof(PELIB_IMAGE_SECTION_HEADER); + filePtr += sizeof(PELIB_IMAGE_SECTION_HEADER_BASE); } // Verify the image size. Note that this check is no longer performed by Windows 10 @@ -850,7 +1012,7 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) { if (!sections.empty()) { - PELIB_IMAGE_SECTION_HEADER & lastSection = sections.back(); + PELIB_IMAGE_SECTION_HEADER_BASE & lastSection = sections.back(); uint32_t PointerToRawData = (lastSection.SizeOfRawData != 0) ? lastSection.PointerToRawData : 0; uint32_t EndOfRawData = PointerToRawData + lastSection.SizeOfRawData; @@ -934,20 +1096,20 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) // Windows loader patches PointerToRawData to zero, including the mapped image. // Tested on Windows XP and Windows 10. uint32_t rva = dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; - for(size_t i = 0; i < sections.size(); i++, rva += sizeof(PELIB_IMAGE_SECTION_HEADER)) + for(size_t i = 0; i < sections.size(); i++, rva += sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)) { - PELIB_IMAGE_SECTION_HEADER sectHdr{}; + PELIB_IMAGE_SECTION_HEADER_BASE sectHdr{}; // Read the section from the header. This is necessary, as for some files, // section headers are not contained in the image. // Example: c8b31a912d91407a834071268366eb404d5e771b8281fdde301e15a8a82bf01b - readImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER)); + readImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)); // Patch PointerToRawData to zero, if SizeOfRawData is zero. if(sectHdr.PointerToRawData != 0 && sectHdr.SizeOfRawData == 0) { sectHdr.PointerToRawData = 0; - writeImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER)); + writeImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)); } } @@ -1011,6 +1173,40 @@ int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * filePtr, uint8_t * fil return ERROR_NONE; } +int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, size_t fileSize) +{ + if(hdr.e_magic != PELIB_IMAGE_DOS_SIGNATURE) + return ERROR_INVALID_FILE; + if(hdr.e_lfanew & 3) + return setLoaderError(LDR_ERROR_E_LFANEW_UNALIGNED); + if(hdr.e_lfanew > fileSize) + return setLoaderError(LDR_ERROR_E_LFANEW_OUT_OF_FILE); + + return ERROR_NONE; +} + +int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, std::size_t fileSize) +{ + PELIB_IMAGE_DOS_HEADER tempDosHeader; + int fileError; + + // The file size must be at least size of DOS header + if((fileOffset + sizeof(PELIB_IMAGE_DOS_HEADER)) >= fileSize) + return ERROR_INVALID_FILE; + fs.seekg(fileOffset); + + // Read the DOS header + if(fs.read(reinterpret_cast(&tempDosHeader), sizeof(PELIB_IMAGE_DOS_HEADER)).bad()) + return ERROR_INVALID_FILE; + + // Verify the DOS header + if((fileError = verifyDosHeader(tempDosHeader, fileSize)) != ERROR_NONE) + return fileError; + + // If the DOS header points out of the file, it's a wrong file too + return (ldrError == LDR_ERROR_E_LFANEW_OUT_OF_FILE) ? ERROR_INVALID_FILE : ERROR_NONE; +} + int PeLib::ImageLoader::loadImageAsIs(std::vector & fileData) { imageAsIs = fileData; @@ -1258,7 +1454,7 @@ bool PeLib::ImageLoader::isRvaOfSectionHeaderPointerToRawData(uint32_t rva) for(size_t i = 0; i < sections.size(); i++) { // Get the reference to the section header - PELIB_IMAGE_SECTION_HEADER & sectHdr = sections[i]; + PELIB_IMAGE_SECTION_HEADER_BASE & sectHdr = sections[i]; // Must be a section with SizeOfRawData = 0 if(sectHdr.SizeOfRawData == 0) @@ -1268,8 +1464,8 @@ bool PeLib::ImageLoader::isRvaOfSectionHeaderPointerToRawData(uint32_t rva) sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader + - i * sizeof(PELIB_IMAGE_SECTION_HEADER) + - 0x14; // FIELD_OFFSET(PELIB_IMAGE_SECTION_HEADER, PointerToRawData) + i * sizeof(PELIB_IMAGE_SECTION_HEADER_BASE) + + 0x14; // FIELD_OFFSET(PELIB_IMAGE_SECTION_HEADER_BASE, PointerToRawData) if(rvaOfLastSectionPointerToRawData <= rva && rva < rvaOfLastSectionPointerToRawData + sizeof(uint32_t)) return true; @@ -1347,6 +1543,12 @@ void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & Ima bool isGoodPageWin = isGoodPagePointer(ImageCompare.PfnVerifyAddress, winImageData); bool isGoodPageMy = isGoodMappedPage(rva); + // If we have a compare callback, call it + if(ImageCompare.PfnCompareCallback != nullptr) + { + ImageCompare.PfnCompareCallback(rva, imageSize); + } + // Both are accessible -> Compare the page if(isGoodPageWin && isGoodPageMy) { diff --git a/src/pelib/MzHeader.cpp b/src/pelib/MzHeader.cpp index 9457efc4d..21597ecaa 100644 --- a/src/pelib/MzHeader.cpp +++ b/src/pelib/MzHeader.cpp @@ -149,7 +149,7 @@ namespace PeLib originalOffset = 0; - std::vector vBuffer(PELIB_IMAGE_DOS_HEADER::size()); + std::vector vBuffer(PELIB_IMAGE_DOS_HEADER::size()); inStream_w.read(reinterpret_cast(vBuffer.data()), static_cast(vBuffer.size())); inStream_w.seekg(0, std::ios::beg); m_headerString.clear(); @@ -185,7 +185,7 @@ namespace PeLib return ERROR_INVALID_FILE; } - std::vector vBuffer(pcBuffer, pcBuffer + uiSize); + std::vector vBuffer(pcBuffer, pcBuffer + uiSize); for (int i=0;i<0x40;i++) std::cout << std::hex << (int)vBuffer[i] << " "; originalOffset = originalOffs; @@ -201,7 +201,7 @@ namespace PeLib * must call #PeLib::MzHeader::makeValid first. * @param vBuffer Buffer where the rebuilt MZ header will be stored. **/ - void MzHeader::rebuild(std::vector& vBuffer) const + void MzHeader::rebuild(std::vector& vBuffer) const { OutputBuffer obBuffer(vBuffer); @@ -254,7 +254,7 @@ namespace PeLib * @param dwOffset Offset the header will be written to (defaults to 0). * @return A non-zero value is returned if a problem occurred. **/ - int MzHeader::write(const std::string& strFilename, dword dwOffset = 0) const + int MzHeader::write(const std::string& strFilename, std::uint32_t dwOffset = 0) const { std::fstream ofFile(strFilename.c_str(), std::ios_base::in); @@ -306,7 +306,7 @@ namespace PeLib /** * Returns the MZ header's e_magic value. **/ - word MzHeader::getMagicNumber() const + std::uint16_t MzHeader::getMagicNumber() const { return m_idhHeader.e_magic; } @@ -314,7 +314,7 @@ namespace PeLib /** * Returns the MZ header's e_cblp value. **/ - word MzHeader::getBytesOnLastPage() const + std::uint16_t MzHeader::getBytesOnLastPage() const { return m_idhHeader.e_cblp; } @@ -322,7 +322,7 @@ namespace PeLib /** * Returns the MZ header's e_cp value. **/ - word MzHeader::getPagesInFile() const + std::uint16_t MzHeader::getPagesInFile() const { return m_idhHeader.e_cp; } @@ -330,7 +330,7 @@ namespace PeLib /** * Returns the MZ header's e_crlc value. **/ - word MzHeader::getRelocations() const + std::uint16_t MzHeader::getRelocations() const { return m_idhHeader.e_crlc; } @@ -338,7 +338,7 @@ namespace PeLib /** * Returns the MZ header's e_cparhdr value. **/ - word MzHeader::getSizeOfHeader() const + std::uint16_t MzHeader::getSizeOfHeader() const { return m_idhHeader.e_cparhdr; } @@ -346,7 +346,7 @@ namespace PeLib /** * Returns the MZ header's e_minalloc value. **/ - word MzHeader::getMinExtraParagraphs() const + std::uint16_t MzHeader::getMinExtraParagraphs() const { return m_idhHeader.e_minalloc; } @@ -354,7 +354,7 @@ namespace PeLib /** * Returns the MZ header's e_maxalloc value. **/ - word MzHeader::getMaxExtraParagraphs() const + std::uint16_t MzHeader::getMaxExtraParagraphs() const { return m_idhHeader.e_maxalloc; } @@ -362,7 +362,7 @@ namespace PeLib /** * Returns the MZ header's e_ss value. **/ - word MzHeader::getSsValue() const + std::uint16_t MzHeader::getSsValue() const { return m_idhHeader.e_ss; } @@ -370,7 +370,7 @@ namespace PeLib /** * Returns the MZ header's e_sp value. **/ - word MzHeader::getSpValue() const + std::uint16_t MzHeader::getSpValue() const { return m_idhHeader.e_sp; } @@ -378,7 +378,7 @@ namespace PeLib /** * Returns the MZ header's e_csum value. **/ - word MzHeader::getChecksum() const + std::uint16_t MzHeader::getChecksum() const { return m_idhHeader.e_csum; } @@ -386,7 +386,7 @@ namespace PeLib /** * Returns the MZ header's e_ip value. **/ - word MzHeader::getIpValue() const + std::uint16_t MzHeader::getIpValue() const { return m_idhHeader.e_ip; } @@ -394,7 +394,7 @@ namespace PeLib /** * Returns the MZ header's e_cs value. **/ - word MzHeader::getCsValue() const + std::uint16_t MzHeader::getCsValue() const { return m_idhHeader.e_cs; } @@ -402,7 +402,7 @@ namespace PeLib /** * Returns the MZ header's e_lfarlc value. **/ - word MzHeader::getAddrOfRelocationTable() const + std::uint16_t MzHeader::getAddrOfRelocationTable() const { return m_idhHeader.e_lfarlc; } @@ -410,7 +410,7 @@ namespace PeLib /** * Returns the MZ header's e_ovno value. **/ - word MzHeader::getOverlayNumber() const + std::uint16_t MzHeader::getOverlayNumber() const { return m_idhHeader.e_ovno; } @@ -418,7 +418,7 @@ namespace PeLib /** * Returns the MZ header's e_oemid value. **/ - word MzHeader::getOemIdentifier() const + std::uint16_t MzHeader::getOemIdentifier() const { return m_idhHeader.e_oemid; } @@ -426,7 +426,7 @@ namespace PeLib /** * Returns the MZ header's e_oeminfo value. **/ - word MzHeader::getOemInformation() const + std::uint16_t MzHeader::getOemInformation() const { return m_idhHeader.e_oeminfo; } @@ -434,7 +434,7 @@ namespace PeLib /** * Returns the MZ header's e_lfanew value. **/ - dword MzHeader::getAddressOfPeHeader() const + std::uint32_t MzHeader::getAddressOfPeHeader() const { return m_idhHeader.e_lfanew; } @@ -442,9 +442,9 @@ namespace PeLib /** * Returns the MZ header's e_res[uiNr] value. If the parameter uiNr is out of range * you will get undefined behaviour. - * @param uiNr The index of the word in the e_res array (valid range: 0-3) + * @param uiNr The index of the std::uint16_t in the e_res array (valid range: 0-3) **/ - word MzHeader::getReservedWords1(unsigned int uiNr) const + std::uint16_t MzHeader::getReservedWords1(unsigned int uiNr) const { return m_idhHeader.e_res[uiNr]; } @@ -452,9 +452,9 @@ namespace PeLib /** * Returns the MZ header's e_res2[uiNr] value. If the parameter uiNr is out of range * you will get undefined behaviour. - * @param uiNr The index of the word in the e_res array (valid range: 0-9) + * @param uiNr The index of the std::uint16_t in the e_res array (valid range: 0-9) **/ - word MzHeader::getReservedWords2(unsigned int uiNr) const + std::uint16_t MzHeader::getReservedWords2(unsigned int uiNr) const { return m_idhHeader.e_res2[uiNr]; } @@ -463,7 +463,7 @@ namespace PeLib * Sets the MZ header's e_magic value. * @param wValue The new value of e_magic. **/ - void MzHeader::setMagicNumber(word wValue) + void MzHeader::setMagicNumber(std::uint16_t wValue) { m_idhHeader.e_magic = wValue; } @@ -472,7 +472,7 @@ namespace PeLib * Sets the MZ header's e_cblp value. * @param wValue The new value of e_cblp. **/ - void MzHeader::setBytesOnLastPage(word wValue) + void MzHeader::setBytesOnLastPage(std::uint16_t wValue) { m_idhHeader.e_cblp = wValue; } @@ -481,7 +481,7 @@ namespace PeLib * Sets the MZ header's e_cp value. * @param wValue The new value of e_cp. **/ - void MzHeader::setPagesInFile(word wValue) + void MzHeader::setPagesInFile(std::uint16_t wValue) { m_idhHeader.e_cp = wValue; } @@ -490,7 +490,7 @@ namespace PeLib * Sets the MZ header's e_crlc value. * @param wValue The new value of e_crlc. **/ - void MzHeader::setRelocations(word wValue) + void MzHeader::setRelocations(std::uint16_t wValue) { m_idhHeader.e_crlc = wValue; } @@ -499,7 +499,7 @@ namespace PeLib * Sets the MZ header's e_cparhdr value. * @param wValue The new value of e_cparhdr. **/ - void MzHeader::setSizeOfHeader(word wValue) + void MzHeader::setSizeOfHeader(std::uint16_t wValue) { m_idhHeader.e_cparhdr = wValue; } @@ -508,7 +508,7 @@ namespace PeLib * Sets the MZ header's e_minalloc value. * @param wValue The new value of e_minalloc. **/ - void MzHeader::setMinExtraParagraphs(word wValue) + void MzHeader::setMinExtraParagraphs(std::uint16_t wValue) { m_idhHeader.e_minalloc = wValue; } @@ -517,7 +517,7 @@ namespace PeLib * Sets the MZ header's e_maxalloc value. * @param wValue The new value of e_maxalloc. **/ - void MzHeader::setMaxExtraParagraphs(word wValue) + void MzHeader::setMaxExtraParagraphs(std::uint16_t wValue) { m_idhHeader.e_maxalloc = wValue; } @@ -526,7 +526,7 @@ namespace PeLib * Sets the MZ header's e_ss value. * @param wValue The new value of e_ss. **/ - void MzHeader::setSsValue(word wValue) + void MzHeader::setSsValue(std::uint16_t wValue) { m_idhHeader.e_ss = wValue; } @@ -535,7 +535,7 @@ namespace PeLib * Sets the MZ header's e_sp value. * @param wValue The new value of e_sp. **/ - void MzHeader::setSpValue(word wValue) + void MzHeader::setSpValue(std::uint16_t wValue) { m_idhHeader.e_sp = wValue; } @@ -544,7 +544,7 @@ namespace PeLib * Sets the MZ header's e_csum value. * @param wValue The new value of e_csum. **/ - void MzHeader::setChecksum(word wValue) + void MzHeader::setChecksum(std::uint16_t wValue) { m_idhHeader.e_csum = wValue; } @@ -553,7 +553,7 @@ namespace PeLib * Sets the MZ header's e_ip value. * @param wValue The new value of e_ip. **/ - void MzHeader::setIpValue(word wValue) + void MzHeader::setIpValue(std::uint16_t wValue) { m_idhHeader.e_ip = wValue; } @@ -562,7 +562,7 @@ namespace PeLib * Sets the MZ header's e_cs value. * @param wValue The new value of e_cs. **/ - void MzHeader::setCsValue(word wValue) + void MzHeader::setCsValue(std::uint16_t wValue) { m_idhHeader.e_cs = wValue; } @@ -571,7 +571,7 @@ namespace PeLib * Sets the MZ header's e_lfarlc value. * @param wValue The new value of e_lfarlc. **/ - void MzHeader::setAddrOfRelocationTable(word wValue) + void MzHeader::setAddrOfRelocationTable(std::uint16_t wValue) { m_idhHeader.e_lfarlc = wValue; } @@ -580,7 +580,7 @@ namespace PeLib * Sets the MZ header's e_ovno value. * @param wValue The new value of e_ovno. **/ - void MzHeader::setOverlayNumber(word wValue) + void MzHeader::setOverlayNumber(std::uint16_t wValue) { m_idhHeader.e_ovno = wValue; } @@ -589,7 +589,7 @@ namespace PeLib * Sets the MZ header's e_oemid value. * @param wValue The new value of e_oemid. **/ - void MzHeader::setOemIdentifier(word wValue) + void MzHeader::setOemIdentifier(std::uint16_t wValue) { m_idhHeader.e_oemid = wValue; } @@ -598,7 +598,7 @@ namespace PeLib * Sets the MZ header's e_oeminfo value. * @param wValue The new value of e_oeminfo. **/ - void MzHeader::setOemInformation(word wValue) + void MzHeader::setOemInformation(std::uint16_t wValue) { m_idhHeader.e_oeminfo = wValue; } @@ -607,7 +607,7 @@ namespace PeLib * Sets the MZ header's e_lfanew value. * @param lValue The new value of e_lfanew. **/ - void MzHeader::setAddressOfPeHeader(dword lValue) + void MzHeader::setAddressOfPeHeader(std::uint32_t lValue) { m_idhHeader.e_lfanew = lValue; } @@ -615,10 +615,10 @@ namespace PeLib /** * Sets the MZ header's e_res[uiNr] value. If the parameter uiNr is out of range * you will get undefined behaviour. - * @param uiNr The index of the word in the e_res array (valid range: 0-3) + * @param uiNr The index of the std::uint16_t in the e_res array (valid range: 0-3) * @param wValue The new value of e_res[nr]. **/ - void MzHeader::setReservedWords1(unsigned int uiNr, word wValue) + void MzHeader::setReservedWords1(unsigned int uiNr, std::uint16_t wValue) { m_idhHeader.e_res[uiNr] = wValue; } @@ -626,10 +626,10 @@ namespace PeLib /** * Sets the MZ header's e_res2[uiNr] value. If the parameter uiNr is out of range * you will get undefined behaviour. - * @param uiNr The index of the word in the e_res2 array (valid range: 0-9) + * @param uiNr The index of the std::uint16_t in the e_res2 array (valid range: 0-9) * @param wValue The new value of e_res[nr]. **/ - void MzHeader::setReservedWords2(unsigned int uiNr, word wValue) + void MzHeader::setReservedWords2(unsigned int uiNr, std::uint16_t wValue) { m_idhHeader.e_res2[uiNr] = wValue; } diff --git a/src/pelib/PeHeader.cpp b/src/pelib/PeHeader.cpp index c5327f0db..feac20520 100644 --- a/src/pelib/PeHeader.cpp +++ b/src/pelib/PeHeader.cpp @@ -15,16 +15,18 @@ namespace PeLib { + /* template<> - void PeHeaderT<32>::readBaseOfData(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS<32>& header) const + void PeHeaderT<32>::readBaseOfData(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS & header) const { ibBuffer >> header.OptionalHeader.BaseOfData; } template<> - void PeHeaderT<64>::readBaseOfData(InputBuffer&, PELIB_IMAGE_NT_HEADERS<64>&) const + void PeHeaderT<64>::readBaseOfData(InputBuffer&, PELIB_IMAGE_NT_HEADERS &) const { } + */ template<> void PeHeaderT<32>::rebuildBaseOfData(OutputBuffer& obBuffer) const @@ -75,7 +77,7 @@ namespace PeLib /** * @return The BaseOfData value from the PE header. **/ - dword PeHeader32::getBaseOfData() const + std::uint32_t PeHeader32::getBaseOfData() const { return m_inthHeader.OptionalHeader.BaseOfData; } @@ -84,7 +86,7 @@ namespace PeLib * Changes the file's BaseOfData. * @param dwValue New value. **/ - void PeHeader32::setBaseOfData(dword dwValue) + void PeHeader32::setBaseOfData(std::uint32_t dwValue) { m_inthHeader.OptionalHeader.BaseOfData = dwValue; } diff --git a/src/pelib/PeLibAux.cpp b/src/pelib/PeLibAux.cpp index 350fade95..39220fed9 100644 --- a/src/pelib/PeLibAux.cpp +++ b/src/pelib/PeLibAux.cpp @@ -22,7 +22,7 @@ namespace PeLib { - const qword PELIB_IMAGE_ORDINAL_FLAGS<64>::PELIB_IMAGE_ORDINAL_FLAG = 0x8000000000000000ULL; + const std::uint64_t PELIB_IMAGE_ORDINAL_FLAGS<64>::PELIB_IMAGE_ORDINAL_FLAG = 0x8000000000000000ULL; // Keep in sync with PeLib::LoaderError!!! static const std::vector LdrErrStrings = @@ -302,39 +302,6 @@ namespace PeLib return t1 == t2; } - PELIB_IMAGE_DOS_HEADER::PELIB_IMAGE_DOS_HEADER() - { - e_magic = 0; - e_cblp = 0; - e_cp = 0; - e_crlc = 0; - e_cparhdr = 0; - e_minalloc = 0; - e_maxalloc = 0; - e_ss = 0; - e_sp = 0; - e_csum = 0; - e_ip = 0; - e_cs = 0; - e_lfarlc = 0; - e_ovno = 0; - - for (unsigned int i = 0; i < sizeof(e_res) / sizeof(e_res[0]); i++) - { - e_res[i] = 0; - } - - e_oemid = 0; - e_oeminfo = 0; - - for (unsigned int i = 0; i < sizeof(e_res2) / sizeof(e_res2[0]); i++) - { - e_res2[i] = 0; - } - - e_lfanew = 0; - } - PELIB_EXP_FUNC_INFORMATION::PELIB_EXP_FUNC_INFORMATION() { addroffunc = 0; @@ -462,8 +429,8 @@ namespace PeLib return PEFILE_UNKNOWN; } - word machine = pef.peHeader().getMachine(); - word magic = pef.peHeader().getMagic(); + std::uint16_t machine = pef.peHeader().getMachine(); + std::uint16_t magic = pef.peHeader().getMagic(); // jk2012-02-20: make the PEFILE32 be the default return value if ((machine == PELIB_IMAGE_FILE_MACHINE_AMD64 @@ -540,7 +507,7 @@ namespace PeLib } } - unsigned int PELIB_IMAGE_BOUND_DIRECTORY::size() const + std::size_t PELIB_IMAGE_BOUND_DIRECTORY::size() const { unsigned int size = 0; for (unsigned int i = 0; i < moduleForwarders.size(); ++i) diff --git a/src/pelib/PelibTest.cpp b/src/pelib/PelibTest.cpp deleted file mode 100644 index 55312013c..000000000 --- a/src/pelib/PelibTest.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/*****************************************************************************/ -/* PelibTest.cpp Copyright (c) Ladislav Zezula 2020 */ -/*---------------------------------------------------------------------------*/ -/* Testing suite for pelib. Windows platform only. */ -/*---------------------------------------------------------------------------*/ -/* Date Ver Who Comment */ -/* -------- ---- --- ------- */ -/* 30.05.20 1.00 Lad Created */ -/*****************************************************************************/ - -#ifndef UNICODE -#define UNICODE -#define _UNICODE -#endif - -#ifdef _MSC_VER -#pragma warning(disable:4091) // imagehlp.h(1873) : warning C4091 : 'typedef ' : ignored on left of '' when no variable is declared -#endif // _MSC_VER - -#define WIN32_NO_STATUS -#include -#include -#include -#include -#include -#include -#undef WIN32_NO_STATUS -#include -#include -#include - -#include -#include - -#include "ImageLoader.h" -#include "Utils.h" -#include "ntdll.h" - -//----------------------------------------------------------------------------- -// Local variables - -OSVERSIONINFO g_osvi = {0}; -DWORD g_dwFilesTested = 0; -DWORD g_dwFilesMatched = 0; -DWORD g_dwFilesMismatch = 0; -DWORD g_dwWinVer = 0; - -#define WIN32_PAGE_SIZE 0x1000 - -#ifndef SEC_IMAGE_NO_EXECUTE -#define SEC_IMAGE_NO_EXECUTE 0x11000000 -#endif - -//----------------------------------------------------------------------------- -// Local functions - -static LPCTSTR GetStringArg(int argIndex, LPCTSTR szDefault = NULL) -{ - if(__argc > argIndex) - { - if(__targv[argIndex] && __targv[argIndex][0]) - { - return __targv[argIndex]; - } - } - - return szDefault; -} - -static int PrintError(LPCTSTR szFormat, ...) -{ - va_list argList; - - va_start(argList, szFormat); - _vtprintf(szFormat, argList); - va_end(argList); - - return 3; -} - -static void PrintCompareResult(LPCTSTR szFileName, LPCTSTR format, ...) -{ - va_list argList; - - va_start(argList, format); - _tprintf(_T("%s\n * "), szFileName); - _vtprintf(format, argList); - _tprintf(_T("\n")); - va_end(argList); -} - -static ULONG64 GetImageBase(LPBYTE pbImage) -{ - PIMAGE_NT_HEADERS64 pNtHdrs64; - PIMAGE_NT_HEADERS32 pNtHdrs32; - PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)pbImage; - - // Make sure that the image base is valid - if(pbImage != NULL) - { - // Try 64-bit image - pNtHdrs64 = (PIMAGE_NT_HEADERS64)(pbImage + pDosHdr->e_lfanew); - if(pNtHdrs64->Signature == IMAGE_NT_SIGNATURE && pNtHdrs64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - return pNtHdrs64->OptionalHeader.ImageBase; - } - - // Try 32-bit image - pNtHdrs32 = (PIMAGE_NT_HEADERS32)(pbImage + pDosHdr->e_lfanew); - if(pNtHdrs32->Signature == IMAGE_NT_SIGNATURE && pNtHdrs32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - return pNtHdrs32->OptionalHeader.ImageBase; - } - } - - return 0; -} - -static bool _cdecl VerifyMemoryAddress(void * ptr, size_t length) -{ - MEMORY_BASIC_INFORMATION mbi; - - // Query the virtual memory - if(!VirtualQuery(ptr, &mbi, length)) - return false; - return (mbi.Protect > PAGE_NOACCESS); -} - -static void WriteDataToFile(LPCTSTR szFileName, LPBYTE pbData, DWORD cbData) -{ - HANDLE hFile; - DWORD dwWritten = 0; - - hFile = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); - if(hFile != INVALID_HANDLE_VALUE) - { - WriteFile(hFile, pbData, cbData, &dwWritten, NULL); - CloseHandle(hFile); - } -} - -static bool CopySampleToFolder(LPCTSTR szFileName, LPCTSTR szCopyFolder) -{ - TCHAR szTargetName[MAX_PATH]; - TCHAR szPlainName[MAX_PATH]; - LPTSTR szExtension; - int nTryCount = 1; - - if(szCopyFolder && szCopyFolder[0]) - { - // Split the name to plain name and extension - StringCchCopy(szPlainName, _countof(szPlainName), GetPlainName(szFileName)); - szExtension = GetFileExtension(szPlainName); - if(szExtension[0] == _T('.')) - *szExtension++ = 0; - - // The first try - StringCchPrintf(szTargetName, _countof(szTargetName), _T("%s\\%s.%s"), szCopyFolder, szPlainName, szExtension); - - // Keep working - while(nTryCount < 100) - { - // If the target file doesn't exist, copy it - if(GetFileAttributes(szTargetName) == INVALID_FILE_ATTRIBUTES) - { - return CopyFile(szFileName, szTargetName, TRUE); - } - - // Create next name iteration - StringCchPrintf(szTargetName, _countof(szTargetName), _T("%s\\%s_%03u.%s"), szCopyFolder, szPlainName, nTryCount, szExtension); - nTryCount++; - } - } - - return false; -} - -static NTSTATUS MapFileByWindowsLoader(LPCTSTR szFileName, LPBYTE * PtrPointerToImage, LPDWORD PtrSizeOfImage) -{ - OBJECT_ATTRIBUTES ObjAttr; - LARGE_INTEGER MappedSize = {0}; - LARGE_INTEGER ByteOffset = {0}; - NTSTATUS Status = STATUS_SUCCESS; - HANDLE SectionHandle = NULL; - HANDLE FileHandle; - SIZE_T ViewSize = 0; - PVOID BaseAddress = NULL; - ULONG AllocationAttributes = SEC_IMAGE; - - // Use SEC_IMAGE_NO_EXECUTE on Windows 10 or newer -// if(g_dwWinVer >= 0x0601) -// AllocationAttributes = SEC_IMAGE_NO_EXECUTE; - - // Open the file for creating image - FileHandle = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if(FileHandle != INVALID_HANDLE_VALUE) - { - InitializeObjectAttributes(&ObjAttr, NULL, 0, NULL, NULL); - -#ifndef _DEBUG - if(IsDebuggerPresent() == FALSE) - { - //__debugbreak(); - } -#endif - - Status = NtCreateSection(&SectionHandle, - SECTION_MAP_READ, - &ObjAttr, - &MappedSize, - PAGE_READONLY, - AllocationAttributes, - FileHandle); - - if(NT_SUCCESS(Status)) - { - // Map the entire file to memory - Status = NtMapViewOfSection(SectionHandle, - NtCurrentProcess(), - &BaseAddress, - 0, - 0, - &ByteOffset, - &ViewSize, - ViewShare, - 0, - PAGE_READONLY); - NtClose(SectionHandle); - } - - CloseHandle(FileHandle); - } - - // Give the results - PtrPointerToImage[0] = (LPBYTE)BaseAddress; - PtrSizeOfImage[0] = (DWORD)ViewSize; - return Status; -} - -void MapAndCompareImage(LPCTSTR szFileName, LPBYTE pbImageWin, DWORD cbImageWin, PeLib::PELIB_IMAGE_COMPARE & ImageCompare) -{ - ULONG64 WinImageBase = GetImageBase(pbImageWin); - LPSTR szFileNameA; - size_t nLength = _tcslen(szFileName) + 1; - DWORD SizeOfImage; - DWORD loaderMode = PeLib::LoaderModeWindows7; - - // Set the proper loader mode - if(g_dwWinVer >= 0x0602) - loaderMode = PeLib::LoaderModeWindows10; - - // Create ANSI name of the file - if((szFileNameA = new char[nLength]) != NULL) - { - PeLib::ImageLoader imageLoader(loaderMode); - - // Convert to UNICODE - WideCharToMultiByte(CP_ACP, 0, szFileName, -1, szFileNameA, (int)nLength, NULL, NULL); - - // Load the image using our section reader - if(imageLoader.Load(szFileNameA) == 0) - { - if((SizeOfImage = imageLoader.getSizeOfImageAligned()) != 0) - { - // Windows Vista loader performs relocation in the kernel. - // To be able to compare images, we need to relocate ours - if(loaderMode >= PeLib::LoaderModeWindows7) - imageLoader.relocateImage(WinImageBase); - - // Compare the image with the mapped Windows image - if(pbImageWin && cbImageWin) - imageLoader.compareWithWindowsMappedImage(ImageCompare, pbImageWin, cbImageWin); - - // Dump the image, if not equal - if(ImageCompare.compareResult == PeLib::ImagesDifferentPageValue && ImageCompare.dumpIfNotEqual != nullptr) - imageLoader.dumpImage(ImageCompare.dumpIfNotEqual); - } - } - - delete [] szFileNameA; - } -} - -static void TestFile(LPCTSTR szFileName, LPCTSTR szCopyFolder) -{ - PeLib::PELIB_IMAGE_COMPARE ImageCompare{}; - NTSTATUS Status; - LPBYTE pbImageWin = NULL; - DWORD cbImageWin = 0; - TCHAR szErrMsg[0x200]; - bool bNeedDumpBothImages = false; - bool bNotEnoughMemory = false; - bool bCompareOK = true; - - // Update the console title - StringCchPrintf(szErrMsg, _countof(szErrMsg), _T("%u files checked - Section Reader Test"), g_dwFilesTested); - SetConsoleTitle(szErrMsg); - g_dwFilesTested++; - - // Frame the reading by exception - __try - { - // Load the image using Windows loader - Status = MapFileByWindowsLoader(szFileName, &pbImageWin, &cbImageWin); - - // Only continue the comparison if Windows loader didn't report - // an out-of-memory error code, because we cannot reliably verify anything - if(Status != STATUS_NO_MEMORY) - { - // Load the PE file using our reader - ImageCompare.PfnVerifyAddress = VerifyMemoryAddress; - //ImageCompare.dumpIfNotEqual = "C:\\MappedImageOur.bin"; - MapAndCompareImage(szFileName, pbImageWin, cbImageWin, ImageCompare); - bCompareOK = (ImageCompare.compareResult == PeLib::ImagesEqual); - - // Print the result - switch(ImageCompare.compareResult) - { - case PeLib::ImagesEqual: - break; - - case PeLib::ImagesWindowsLoadedWeDidnt: - PrintCompareResult(szFileName, _T("Windows mapped the image OK, but we didn't")); - break; - - case PeLib::ImagesWindowsDidntLoadWeDid: - PrintCompareResult(szFileName, _T("Windows didn't map the image (%08x), but we did"), Status); - break; - - case PeLib::ImagesDifferentSize: - PrintCompareResult(szFileName, _T("SizeOfImage mismatch")); - break; - - case PeLib::ImagesDifferentPageAccess: - PrintCompareResult(szFileName, _T("Image page accessibility mismatch at offset %08x"), ImageCompare.differenceOffset); - break; - - case PeLib::ImagesDifferentPageValue: - PrintCompareResult(szFileName, _T("Image mismatch at offset %08x"), ImageCompare.differenceOffset); - bNeedDumpBothImages = true; - break; - } - - // Dump both images for fuhrter investigation, if needed - if(ImageCompare.dumpIfNotEqual && bNeedDumpBothImages) - { - WriteDataToFile(_T("C:\\MappedImageWin.bin"), pbImageWin, cbImageWin); - _tprintf(_T(" * Images dumped. Press any key to continue ...\n")); - _getch(); - } - } - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - _tprintf(_T("%s\n * Exception when processing image\n"), szFileName); - } - - // Free resources - if(pbImageWin != NULL) - NtUnmapViewOfSection(NtCurrentProcess(), pbImageWin); - pbImageWin = NULL; - - // Copy the file to a link folder, if compare failed - if(bCompareOK == false && bNotEnoughMemory == false) - { - CopySampleToFolder(szFileName, szCopyFolder); - g_dwFilesMismatch++; - } - else - { - g_dwFilesMatched++; - } -} - -static void TestFolder(LPCTSTR szFolderName, LPCTSTR szCopyFolder) -{ - WIN32_FIND_DATA wf; - HANDLE hFind; - TCHAR szNameBuff[MAX_PATH]; - BOOL bFound = TRUE; - - // Initiate file search - StringCchPrintf(szNameBuff, _countof(szNameBuff), _T("%s\\*"), szFolderName); - hFind = FindFirstFile(szNameBuff, &wf); - if(hFind != INVALID_HANDLE_VALUE) - { - // Keep searching - while(bFound) - { - // Exclude the "." and ".." directory entries - if(_tcscmp(wf.cFileName, _T(".")) && _tcscmp(wf.cFileName, _T(".."))) - { - // Construct the full name - StringCchPrintf(szNameBuff, _countof(szNameBuff), _T("%s\\%s"), szFolderName, wf.cFileName); - - // Folder/file? - if(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - TestFolder(szNameBuff, szCopyFolder); - } - else - { - TestFile(szNameBuff, szCopyFolder); - } - } - - // Search the next file/folder - bFound = FindNextFile(hFind, &wf); - } - - // Close the find handle - FindClose(hFind); - } -} - -//----------------------------------------------------------------------------- -// The 'main' function - -int _tmain(void) -{ - LPCTSTR szFileOrFolder = NULL; - LPCTSTR szCopyFolder = NULL; - DWORD dwAttr; - - // Get Windows version - g_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&g_osvi); - g_dwWinVer = (g_osvi.dwMajorVersion << 0x08) | g_osvi.dwMinorVersion; - - // ARG1: Name of file/folder - szFileOrFolder = GetStringArg(1, _T(".")); - - // ARG2: Name of collection folder - szCopyFolder = GetStringArg(2, NULL); - - // For stopping in the debugger - //_tprintf(_T("Press any key to begin ...\n")); - //_getch(); - - // Check whether the argument is folder or file - dwAttr = GetFileAttributes(szFileOrFolder); - if(dwAttr == INVALID_FILE_ATTRIBUTES) - return PrintError(_T("Failed to open \"%s\" (error code %u)\n"), szFileOrFolder, GetLastError()); - - // If a folder, we're gonna recursively go over all files - if(dwAttr & FILE_ATTRIBUTE_DIRECTORY) - { - TestFolder(szFileOrFolder, szCopyFolder); - } - else - { - TestFile(szFileOrFolder, szCopyFolder); - } - - // Print summary - _tprintf(_T("\n=[*]= Summary ==========================================\n")); - _tprintf(_T(" * Files tested: %u\n"), g_dwFilesTested); - _tprintf(_T(" * Files matched: %u\n"), g_dwFilesMatched); - _tprintf(_T(" * Files mismatched: %u\n\n"), g_dwFilesMismatch); - SetConsoleTitle(_T("Complete - Section Reader Test")); - - // Exit - _tprintf(_T("Press any key to exit ...\n")); - _getch(); -} - diff --git a/src/pelib/PelibTest_vs17.sln b/src/pelib/PelibTest_vs17.sln deleted file mode 100644 index bdde92e03..000000000 --- a/src/pelib/PelibTest_vs17.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.1082 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PelibTest", "PelibTest_vs17.vcxproj", "{A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Debug|Win32.ActiveCfg = Debug|Win32 - {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Debug|Win32.Build.0 = Debug|Win32 - {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Debug|x64.ActiveCfg = Debug|x64 - {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Debug|x64.Build.0 = Debug|x64 - {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Release|Win32.ActiveCfg = Release|Win32 - {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Release|Win32.Build.0 = Release|Win32 - {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Release|x64.ActiveCfg = Release|x64 - {A19185D8-4FEB-4DDC-B5C9-372E1DA3E82E}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {7E200C33-58F7-43F9-B94B-CC8125E389FB} - EndGlobalSection -EndGlobal diff --git a/src/pelib/RelocationsDirectory.cpp b/src/pelib/RelocationsDirectory.cpp index f2d365f78..271c5ead7 100644 --- a/src/pelib/RelocationsDirectory.cpp +++ b/src/pelib/RelocationsDirectory.cpp @@ -38,7 +38,7 @@ namespace PeLib } } - void RelocationsDirectory::setRelocationData(unsigned int ulRelocation, unsigned int ulDataNumber, word wData) + void RelocationsDirectory::setRelocationData(unsigned int ulRelocation, unsigned int ulDataNumber, std::uint16_t wData) { m_vRelocations[ulRelocation].vRelocData[ulDataNumber] = wData; } @@ -144,7 +144,7 @@ namespace PeLib for (unsigned int i=0;i(m_vRelocations[i].vRelocData.size()) * sizeof(word); + size2 += static_cast(m_vRelocations[i].vRelocData.size()) * sizeof(std::uint16_t); } return size2; @@ -155,12 +155,12 @@ namespace PeLib return static_cast(m_vRelocations.size()); } - dword RelocationsDirectory::getVirtualAddress(unsigned int ulRelocation) const + std::uint32_t RelocationsDirectory::getVirtualAddress(unsigned int ulRelocation) const { return m_vRelocations[ulRelocation].ibrRelocation.VirtualAddress; } - dword RelocationsDirectory::getSizeOfBlock(unsigned int ulRelocation) const + std::uint32_t RelocationsDirectory::getSizeOfBlock(unsigned int ulRelocation) const { return m_vRelocations[ulRelocation].ibrRelocation.SizeOfBlock; } @@ -170,17 +170,17 @@ namespace PeLib return static_cast(m_vRelocations[ulRelocation].vRelocData.size()); } - word RelocationsDirectory::getRelocationData(unsigned int ulRelocation, unsigned int ulDataNumber) const + std::uint16_t RelocationsDirectory::getRelocationData(unsigned int ulRelocation, unsigned int ulDataNumber) const { return m_vRelocations[ulRelocation].vRelocData[ulDataNumber]; } - void RelocationsDirectory::setVirtualAddress(unsigned int ulRelocation, dword dwValue) + void RelocationsDirectory::setVirtualAddress(unsigned int ulRelocation, std::uint32_t dwValue) { m_vRelocations[ulRelocation].ibrRelocation.VirtualAddress = dwValue; } - void RelocationsDirectory::setSizeOfBlock(unsigned int ulRelocation, dword dwValue) + void RelocationsDirectory::setSizeOfBlock(unsigned int ulRelocation, std::uint32_t dwValue) { m_vRelocations[ulRelocation].ibrRelocation.SizeOfBlock = dwValue; } @@ -191,12 +191,12 @@ namespace PeLib m_vRelocations.push_back(newrelocation); } - void RelocationsDirectory::addRelocationData(unsigned int ulRelocation, word wValue) + void RelocationsDirectory::addRelocationData(unsigned int ulRelocation, std::uint16_t wValue) { m_vRelocations[ulRelocation].vRelocData.push_back(wValue); } -/* void RelocationsDirectory::removeRelocationData(unsigned int ulRelocation, word wValue) +/* void RelocationsDirectory::removeRelocationData(unsigned int ulRelocation, std::uint16_t wValue) { // If you get an error with Borland C++ here you have two options: Upgrade your compiler // or use the commented line instead of the line below. diff --git a/src/pelib/ResourceDirectory.cpp b/src/pelib/ResourceDirectory.cpp index c06f26e91..70eb4d58b 100644 --- a/src/pelib/ResourceDirectory.cpp +++ b/src/pelib/ResourceDirectory.cpp @@ -86,7 +86,7 @@ namespace PeLib * @param dwId ID of a resource. * @return True, if the resource child's id equals the parameter. **/ - bool ResourceChild::equalId(dword dwId) const + bool ResourceChild::equalId(std::uint32_t dwId) const { return entry.irde.Name == dwId; } @@ -220,7 +220,7 @@ namespace PeLib * * @return Name value of the node. */ - dword ResourceChild::getOffsetToName() const + std::uint32_t ResourceChild::getOffsetToName() const { return entry.irde.Name; } @@ -230,7 +230,7 @@ namespace PeLib * * @return OffsetToData value of the node. */ - dword ResourceChild::getOffsetToData() const + std::uint32_t ResourceChild::getOffsetToData() const { return entry.irde.OffsetToData; } @@ -250,7 +250,7 @@ namespace PeLib * * @param dwNewOffset Name value to set. */ - void ResourceChild::setOffsetToName(dword dwNewOffset) + void ResourceChild::setOffsetToName(std::uint32_t dwNewOffset) { entry.irde.Name = dwNewOffset; } @@ -260,7 +260,7 @@ namespace PeLib * * @param dwNewOffset OffsetToData value to set. */ - void ResourceChild::setOffsetToData(dword dwNewOffset) + void ResourceChild::setOffsetToData(std::uint32_t dwNewOffset) { entry.irde.OffsetToData = dwNewOffset; } @@ -433,7 +433,7 @@ namespace PeLib * Returns a vector that contains the raw data of a resource leaf. * @return Raw data of the resource. **/ - std::vector ResourceLeaf::getData() const + std::vector ResourceLeaf::getData() const { return m_data; } @@ -442,7 +442,7 @@ namespace PeLib * Overwrites the raw data of a resource. * @param vData New data of the resource. **/ - void ResourceLeaf::setData(const std::vector& vData) + void ResourceLeaf::setData(const std::vector& vData) { m_data = vData; } @@ -452,7 +452,7 @@ namespace PeLib * can be found. * @return The leaf's OffsetToData value. **/ - dword ResourceLeaf::getOffsetToData() const + std::uint32_t ResourceLeaf::getOffsetToData() const { return entry.OffsetToData; } @@ -461,7 +461,7 @@ namespace PeLib * Returns the leaf's Size value. That's the size of the raw data of the resource. * @return The leaf's Size value. **/ - dword ResourceLeaf::getSize() const + std::uint32_t ResourceLeaf::getSize() const { return entry.Size; } @@ -470,7 +470,7 @@ namespace PeLib * Returns the leaf's CodePage value. * @return The leaf's CodePage value. **/ - dword ResourceLeaf::getCodePage() const + std::uint32_t ResourceLeaf::getCodePage() const { return entry.CodePage; } @@ -479,7 +479,7 @@ namespace PeLib * Returns the leaf's Reserved value. * @return The leaf's Reserved value. **/ - dword ResourceLeaf::getReserved() const + std::uint32_t ResourceLeaf::getReserved() const { return entry.Reserved; } @@ -488,7 +488,7 @@ namespace PeLib * Sets the leaf's OffsetToData value. * @param dwValue The leaf's new OffsetToData value. **/ - void ResourceLeaf::setOffsetToData(dword dwValue) + void ResourceLeaf::setOffsetToData(std::uint32_t dwValue) { entry.OffsetToData = dwValue; } @@ -497,7 +497,7 @@ namespace PeLib * Sets the leaf's Size value. * @param dwValue The leaf's new Size value. **/ - void ResourceLeaf::setSize(dword dwValue) + void ResourceLeaf::setSize(std::uint32_t dwValue) { entry.Size = dwValue; } @@ -506,7 +506,7 @@ namespace PeLib * Sets the leaf's CodePage value. * @param dwValue The leaf's new CodePage value. **/ - void ResourceLeaf::setCodePage(dword dwValue) + void ResourceLeaf::setCodePage(std::uint32_t dwValue) { entry.CodePage = dwValue; } @@ -515,7 +515,7 @@ namespace PeLib * Sets the leaf's Reserved value. * @param dwValue The leaf's new Reserved value. **/ - void ResourceLeaf::setReserved(dword dwValue) + void ResourceLeaf::setReserved(std::uint32_t dwValue) { entry.Reserved = dwValue; } @@ -547,7 +547,7 @@ namespace PeLib void ResourceNode::makeValid() { std::sort(children.begin(), children.end()); - header.NumberOfNamedEntries = static_cast(std::count_if( + header.NumberOfNamedEntries = static_cast(std::count_if( children.begin(), children.end(), [](const auto& i) { return i.isNamedResource(); } @@ -594,12 +594,12 @@ namespace PeLib if (children[i].entry.irde.Name & PELIB_IMAGE_RESOURCE_NAME_IS_STRING) { unsigned int uiNameOffset = children[i].entry.irde.Name & ~PELIB_IMAGE_RESOURCE_NAME_IS_STRING; - obBuffer.insert(uiNameOffset, (word)children[i].entry.wstrName.size()); + obBuffer.insert(uiNameOffset, (std::uint16_t)children[i].entry.wstrName.size()); uiNameOffset += 2; for (unsigned int j = 0; j < children[i].entry.wstrName.size(); ++j) { - obBuffer.insert(uiNameOffset, (word)children[i].entry.wstrName[j]); + obBuffer.insert(uiNameOffset, (std::uint16_t)children[i].entry.wstrName[j]); uiNameOffset += 2; } } @@ -621,7 +621,7 @@ namespace PeLib { // There is always directory and its entries at the beginning uiCurrentOffset += PELIB_IMAGE_RESOURCE_DIRECTORY::size(); - uiCurrentOffset += (PeLib::PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size() * getNumberOfChildren()); + uiCurrentOffset += (PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size() * getNumberOfChildren()); for (unsigned int i = 0; i < getNumberOfChildren(); ++i) { @@ -762,15 +762,15 @@ namespace PeLib if ((rc.entry.irde.Name & ~PELIB_IMAGE_RESOURCE_NAME_IS_STRING) + 2 < fileSize(inStream_w)) { unsigned int uiNameOffset = rc.entry.irde.Name & ~PELIB_IMAGE_RESOURCE_NAME_IS_STRING; - if (uiRsrcOffset + uiNameOffset + sizeof(word) > fileSize(inStream_w)) + if (uiRsrcOffset + uiNameOffset + sizeof(std::uint16_t) > fileSize(inStream_w)) { return ERROR_INVALID_FILE; } inStream_w.seekg(uiRsrcOffset + uiNameOffset, std::ios_base::beg); - word len; - inStream_w.read(reinterpret_cast(&len), sizeof(word)); + std::uint16_t len; + inStream_w.read(reinterpret_cast(&len), sizeof(std::uint16_t)); // Enough space to read string? if (uiRsrcOffset + uiNameOffset + 2 * len > fileSize(inStream_w)) @@ -780,10 +780,10 @@ namespace PeLib // jk: This construction is incorrect on 64bit systems // wchar_t c; - word c; - for (word ii=0; ii(&c), sizeof(word)); + inStream_w.read(reinterpret_cast(&c), sizeof(std::uint16_t)); rc.entry.wstrName += c; } } @@ -886,7 +886,7 @@ namespace PeLib * @param uiIndex Index of the child. * @return Name value of a child. **/ - dword ResourceNode::getOffsetToChildName(unsigned int uiIndex) const + std::uint32_t ResourceNode::getOffsetToChildName(unsigned int uiIndex) const { return children[uiIndex].getOffsetToName(); } @@ -896,7 +896,7 @@ namespace PeLib * @param uiIndex Index of the child. * @return OffsetToData value of a child. **/ - dword ResourceNode::getOffsetToChildData(unsigned int uiIndex) const + std::uint32_t ResourceNode::getOffsetToChildData(unsigned int uiIndex) const { return children[uiIndex].getOffsetToData(); } @@ -916,7 +916,7 @@ namespace PeLib * @param uiIndex Index of the child. * @param dwNewOffset New Name value of the resource. **/ - void ResourceNode::setOffsetToChildName(unsigned int uiIndex, dword dwNewOffset) + void ResourceNode::setOffsetToChildName(unsigned int uiIndex, std::uint32_t dwNewOffset) { children[uiIndex].setOffsetToName(dwNewOffset); } @@ -926,7 +926,7 @@ namespace PeLib * @param uiIndex Index of the child. * @param dwNewOffset New OffsetToData value of the resource. **/ - void ResourceNode::setOffsetToChildData(unsigned int uiIndex, dword dwNewOffset) + void ResourceNode::setOffsetToChildData(unsigned int uiIndex, std::uint32_t dwNewOffset) { children[uiIndex].setOffsetToData(dwNewOffset); } @@ -935,7 +935,7 @@ namespace PeLib * Returns the Characteristics value of the node. * @return Characteristics value of the node. **/ - dword ResourceNode::getCharacteristics() const + std::uint32_t ResourceNode::getCharacteristics() const { return header.Characteristics; } @@ -944,7 +944,7 @@ namespace PeLib * Returns the TimeDateStamp value of the node. * @return TimeDateStamp value of the node. **/ - dword ResourceNode::getTimeDateStamp() const + std::uint32_t ResourceNode::getTimeDateStamp() const { return header.TimeDateStamp; } @@ -953,7 +953,7 @@ namespace PeLib * Returns the MajorVersion value of the node. * @return MajorVersion value of the node. **/ - word ResourceNode::getMajorVersion() const + std::uint16_t ResourceNode::getMajorVersion() const { return header.MajorVersion; } @@ -962,7 +962,7 @@ namespace PeLib * Returns the MinorVersion value of the node. * @return MinorVersion value of the node. **/ - word ResourceNode::getMinorVersion() const + std::uint16_t ResourceNode::getMinorVersion() const { return header.MinorVersion; } @@ -971,7 +971,7 @@ namespace PeLib * Returns the NumberOfNamedEntries value of the node. * @return NumberOfNamedEntries value of the node. **/ - word ResourceNode::getNumberOfNamedEntries() const + std::uint16_t ResourceNode::getNumberOfNamedEntries() const { return header.NumberOfNamedEntries; } @@ -980,7 +980,7 @@ namespace PeLib * Returns the NumberOfIdEntries value of the node. * @return NumberOfIdEntries value of the node. **/ - word ResourceNode::getNumberOfIdEntries() const + std::uint16_t ResourceNode::getNumberOfIdEntries() const { return header.NumberOfIdEntries; } @@ -989,7 +989,7 @@ namespace PeLib * Sets the Characteristics value of the node. * @param value New Characteristics value of the node. **/ - void ResourceNode::setCharacteristics(dword value) + void ResourceNode::setCharacteristics(std::uint32_t value) { header.Characteristics = value; } @@ -998,7 +998,7 @@ namespace PeLib * Sets the TimeDateStamp value of the node. * @param value New TimeDateStamp value of the node. **/ - void ResourceNode::setTimeDateStamp(dword value) + void ResourceNode::setTimeDateStamp(std::uint32_t value) { header.TimeDateStamp = value; } @@ -1007,7 +1007,7 @@ namespace PeLib * Sets the MajorVersion value of the node. * @param value New MajorVersion value of the node. **/ - void ResourceNode::setMajorVersion(word value) + void ResourceNode::setMajorVersion(std::uint16_t value) { header.MajorVersion = value; } @@ -1016,7 +1016,7 @@ namespace PeLib * Sets the MinorVersion value of the node. * @param value New MinorVersion value of the node. **/ - void ResourceNode::setMinorVersion(word value) + void ResourceNode::setMinorVersion(std::uint16_t value) { header.MinorVersion = value; } @@ -1025,7 +1025,7 @@ namespace PeLib * Sets the NumberOfNamedEntries value of the node. * @param value New NumberOfNamedEntries value of the node. **/ - void ResourceNode::setNumberOfNamedEntries(word value) + void ResourceNode::setNumberOfNamedEntries(std::uint16_t value) { header.NumberOfNamedEntries = value; } @@ -1034,7 +1034,7 @@ namespace PeLib * Sets the NumberOfIdEntries value of the node. * @param value New NumberOfIdEntries value of the node. **/ - void ResourceNode::setNumberOfIdEntries(word value) + void ResourceNode::setNumberOfIdEntries(std::uint16_t value) { header.NumberOfIdEntries = value; } @@ -1124,7 +1124,7 @@ namespace PeLib * @param vBuffer Buffer the source directory will be written to. * @param uiRva RVA of the resource directory. **/ - void ResourceDirectory::rebuild(std::vector& vBuffer, unsigned int uiRva) const + void ResourceDirectory::rebuild(std::vector& vBuffer, unsigned int uiRva) const { OutputBuffer obBuffer(vBuffer); unsigned int offs = 0; @@ -1195,7 +1195,7 @@ namespace PeLib * Adds another resource type. The new resource type is identified by the ID dwResTypeId. * @param dwResTypeId ID which identifies the resource type. **/ - int ResourceDirectory::addResourceType(dword dwResTypeId) + int ResourceDirectory::addResourceType(std::uint32_t dwResTypeId) { std::vector::iterator Iter = std::find_if( m_rnRoot.children.begin(), @@ -1245,7 +1245,7 @@ namespace PeLib * Removes the resource type identified by the ID dwResTypeId. * @param dwResTypeId ID which identifies the resource type. **/ - int ResourceDirectory::removeResourceType(dword dwResTypeId) + int ResourceDirectory::removeResourceType(std::uint32_t dwResTypeId) { auto Iter = std::find_if( m_rnRoot.children.begin(), @@ -1263,8 +1263,8 @@ namespace PeLib m_rnRoot.children.erase(Iter); - if (isNamed) m_rnRoot.header.NumberOfNamedEntries = static_cast(m_rnRoot.children.size()); - else m_rnRoot.header.NumberOfIdEntries = static_cast(m_rnRoot.children.size()); + if (isNamed) m_rnRoot.header.NumberOfNamedEntries = static_cast(m_rnRoot.children.size()); + else m_rnRoot.header.NumberOfIdEntries = static_cast(m_rnRoot.children.size()); return ERROR_NONE; } @@ -1291,8 +1291,8 @@ namespace PeLib m_rnRoot.children.erase(Iter); - if (isNamed) m_rnRoot.header.NumberOfNamedEntries = static_cast(m_rnRoot.children.size()); - else m_rnRoot.header.NumberOfIdEntries = static_cast(m_rnRoot.children.size()); + if (isNamed) m_rnRoot.header.NumberOfNamedEntries = static_cast(m_rnRoot.children.size()); + else m_rnRoot.header.NumberOfIdEntries = static_cast(m_rnRoot.children.size()); return ERROR_NONE; } @@ -1308,8 +1308,8 @@ namespace PeLib m_rnRoot.children.erase(m_rnRoot.children.begin() + uiIndex); - if (isNamed) m_rnRoot.header.NumberOfNamedEntries = static_cast(m_rnRoot.children.size()); - else m_rnRoot.header.NumberOfIdEntries = static_cast(m_rnRoot.children.size()); + if (isNamed) m_rnRoot.header.NumberOfNamedEntries = static_cast(m_rnRoot.children.size()); + else m_rnRoot.header.NumberOfIdEntries = static_cast(m_rnRoot.children.size()); return ERROR_NONE; } @@ -1320,7 +1320,7 @@ namespace PeLib * @param dwResTypeId ID of the resource type. * @param dwResId ID of the resource. **/ - int ResourceDirectory::addResource(dword dwResTypeId, dword dwResId) + int ResourceDirectory::addResource(std::uint32_t dwResTypeId, std::uint32_t dwResId) { ResourceChild rcCurr; rcCurr.entry.irde.Name = dwResId; @@ -1333,7 +1333,7 @@ namespace PeLib * @param dwResTypeId ID of the resource type. * @param strResName Name of the resource. **/ - int ResourceDirectory::addResource(dword dwResTypeId, const std::string& strResName) + int ResourceDirectory::addResource(std::uint32_t dwResTypeId, const std::string& strResName) { ResourceChild rcCurr; rcCurr.entry.wstrName = strResName; @@ -1346,7 +1346,7 @@ namespace PeLib * @param strResTypeName Name of the resource type. * @param dwResId ID of the resource. **/ - int ResourceDirectory::addResource(const std::string& strResTypeName, dword dwResId) + int ResourceDirectory::addResource(const std::string& strResTypeName, std::uint32_t dwResId) { ResourceChild rcCurr; rcCurr.entry.irde.Name = dwResId; @@ -1372,7 +1372,7 @@ namespace PeLib * @param dwResTypeIndex ID of the resource type. * @param dwResId ID of the resource. **/ - int ResourceDirectory::removeResource(dword dwResTypeIndex, dword dwResId) + int ResourceDirectory::removeResource(std::uint32_t dwResTypeIndex, std::uint32_t dwResId) { return removeResourceT(dwResTypeIndex, dwResId); } @@ -1383,7 +1383,7 @@ namespace PeLib * @param dwResTypeIndex ID of the resource type. * @param strResName Name of the resource. **/ - int ResourceDirectory::removeResource(dword dwResTypeIndex, const std::string& strResName) + int ResourceDirectory::removeResource(std::uint32_t dwResTypeIndex, const std::string& strResName) { return removeResourceT(dwResTypeIndex, strResName); } @@ -1394,7 +1394,7 @@ namespace PeLib * @param strResTypeName Name of the resource type. * @param dwResId ID of the resource. **/ - int ResourceDirectory::removeResource(const std::string& strResTypeName, dword dwResId) + int ResourceDirectory::removeResource(const std::string& strResTypeName, std::uint32_t dwResId) { return removeResourceT(strResTypeName, dwResId); } @@ -1433,7 +1433,7 @@ namespace PeLib * @param uiIndex Index which identifies a resource type. * @return The ID of the specified resource type. **/ - dword ResourceDirectory::getResourceTypeIdByIndex(unsigned int uiIndex) const + std::uint32_t ResourceDirectory::getResourceTypeIdByIndex(unsigned int uiIndex) const { return m_rnRoot.children[uiIndex].entry.irde.Name; } @@ -1455,7 +1455,7 @@ namespace PeLib * @param dwResTypeId ID of the resource type. * @return Index of that resource type. **/ - int ResourceDirectory::resourceTypeIdToIndex(dword dwResTypeId) const + int ResourceDirectory::resourceTypeIdToIndex(std::uint32_t dwResTypeId) const { auto Iter = std::find_if( m_rnRoot.children.begin(), @@ -1487,7 +1487,7 @@ namespace PeLib * @param dwId ID of the resource type. * @return Number of resources of resource type dwId. **/ - unsigned int ResourceDirectory::getNumberOfResources(dword dwId) const + unsigned int ResourceDirectory::getNumberOfResources(std::uint32_t dwId) const { // std::vector::const_iterator IterD = m_rnRoot.children.begin(); // std::cout << dwId << std::endl; @@ -1555,7 +1555,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @param data Vector where the data is stored. **/ - void ResourceDirectory::getResourceData(dword dwResTypeId, dword dwResId, std::vector& data) const + void ResourceDirectory::getResourceData(std::uint32_t dwResTypeId, std::uint32_t dwResId, std::vector& data) const { getResourceDataT(dwResTypeId, dwResId, data); } @@ -1566,7 +1566,7 @@ namespace PeLib * @param strResName Identifies the resource. * @param data Vector where the data is stored. **/ - void ResourceDirectory::getResourceData(dword dwResTypeId, const std::string& strResName, std::vector& data) const + void ResourceDirectory::getResourceData(std::uint32_t dwResTypeId, const std::string& strResName, std::vector& data) const { getResourceDataT(dwResTypeId, strResName, data); } @@ -1577,7 +1577,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @param data Vector where the data is stored. **/ - void ResourceDirectory::getResourceData(const std::string& strResTypeName, dword dwResId, std::vector& data) const + void ResourceDirectory::getResourceData(const std::string& strResTypeName, std::uint32_t dwResId, std::vector& data) const { getResourceDataT(strResTypeName, dwResId, data); } @@ -1588,7 +1588,7 @@ namespace PeLib * @param strResName Identifies the resource. * @param data Vector where the data is stored. **/ - void ResourceDirectory::getResourceData(const std::string& strResTypeName, const std::string& strResName, std::vector& data) const + void ResourceDirectory::getResourceData(const std::string& strResTypeName, const std::string& strResName, std::vector& data) const { getResourceDataT(strResTypeName, strResName, data); } @@ -1602,7 +1602,7 @@ namespace PeLib * @param uiResIndex Identifies the resource. * @param data Vector where the data is stored. **/ - void ResourceDirectory::getResourceDataByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::vector& data) const + void ResourceDirectory::getResourceDataByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::vector& data) const { ResourceNode* currNode = static_cast(m_rnRoot.children[uiResTypeIndex].child); currNode = static_cast(currNode->children[uiResIndex].child); @@ -1617,7 +1617,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @param data The new resource data. **/ - void ResourceDirectory::setResourceData(dword dwResTypeId, dword dwResId, std::vector& data) + void ResourceDirectory::setResourceData(std::uint32_t dwResTypeId, std::uint32_t dwResId, std::vector& data) { setResourceDataT(dwResTypeId, dwResId, data); } @@ -1628,7 +1628,7 @@ namespace PeLib * @param strResName Identifies the resource. * @param data The new resource data. **/ - void ResourceDirectory::setResourceData(dword dwResTypeId, const std::string& strResName, std::vector& data) + void ResourceDirectory::setResourceData(std::uint32_t dwResTypeId, const std::string& strResName, std::vector& data) { setResourceDataT(dwResTypeId, strResName, data); } @@ -1639,7 +1639,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @param data The new resource data. **/ - void ResourceDirectory::setResourceData(const std::string& strResTypeName, dword dwResId, std::vector& data) + void ResourceDirectory::setResourceData(const std::string& strResTypeName, std::uint32_t dwResId, std::vector& data) { setResourceDataT(strResTypeName, dwResId, data); } @@ -1650,7 +1650,7 @@ namespace PeLib * @param strResName Identifies the resource. * @param data The new resource data. **/ - void ResourceDirectory::setResourceData(const std::string& strResTypeName, const std::string& strResName, std::vector& data) + void ResourceDirectory::setResourceData(const std::string& strResTypeName, const std::string& strResName, std::vector& data) { setResourceDataT(strResTypeName, strResName, data); } @@ -1664,7 +1664,7 @@ namespace PeLib * @param uiResIndex Identifies the resource. * @param data The new resource data. **/ - void ResourceDirectory::setResourceDataByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::vector& data) + void ResourceDirectory::setResourceDataByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::vector& data) { ResourceNode* currNode = static_cast(m_rnRoot.children[uiResTypeIndex].child); currNode = static_cast(currNode->children[uiResIndex].child); @@ -1678,7 +1678,7 @@ namespace PeLib * @param strResName Identifies the resource. * @return ID of the specified resource. **/ - dword ResourceDirectory::getResourceId(dword dwResTypeId, const std::string& strResName) const + std::uint32_t ResourceDirectory::getResourceId(std::uint32_t dwResTypeId, const std::string& strResName) const { return getResourceIdT(dwResTypeId, strResName); } @@ -1689,7 +1689,7 @@ namespace PeLib * @param strResName Identifies the resource. * @return ID of the specified resource. **/ - dword ResourceDirectory::getResourceId(const std::string& strResTypeName, const std::string& strResName) const + std::uint32_t ResourceDirectory::getResourceId(const std::string& strResTypeName, const std::string& strResName) const { return getResourceIdT(strResTypeName, strResName); } @@ -1700,7 +1700,7 @@ namespace PeLib * @param uiResIndex Identifies the resource. * @return ID of the specified resource. **/ - dword ResourceDirectory::getResourceIdByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex) const + std::uint32_t ResourceDirectory::getResourceIdByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex) const { ResourceNode* currNode = static_cast(m_rnRoot.children[uiResTypeIndex].child); return currNode->children[uiResIndex].entry.irde.Name; @@ -1712,7 +1712,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @param dwNewResId New ID of the resource. **/ - void ResourceDirectory::setResourceId(dword dwResTypeId, dword dwResId, dword dwNewResId) + void ResourceDirectory::setResourceId(std::uint32_t dwResTypeId, std::uint32_t dwResId, std::uint32_t dwNewResId) { setResourceIdT(dwResTypeId, dwResId, dwNewResId); } @@ -1723,7 +1723,7 @@ namespace PeLib * @param strResName Identifies the resource. * @param dwNewResId New ID of the resource. **/ - void ResourceDirectory::setResourceId(dword dwResTypeId, const std::string& strResName, dword dwNewResId) + void ResourceDirectory::setResourceId(std::uint32_t dwResTypeId, const std::string& strResName, std::uint32_t dwNewResId) { setResourceIdT(dwResTypeId, strResName, dwNewResId); } @@ -1734,7 +1734,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @param dwNewResId New ID of the resource. **/ - void ResourceDirectory::setResourceId(const std::string& strResTypeName, dword dwResId, dword dwNewResId) + void ResourceDirectory::setResourceId(const std::string& strResTypeName, std::uint32_t dwResId, std::uint32_t dwNewResId) { setResourceIdT(strResTypeName, dwResId, dwNewResId); } @@ -1745,7 +1745,7 @@ namespace PeLib * @param strResName Identifies the resource. * @param dwNewResId New ID of the resource. **/ - void ResourceDirectory::setResourceId(const std::string& strResTypeName, const std::string& strResName, dword dwNewResId) + void ResourceDirectory::setResourceId(const std::string& strResTypeName, const std::string& strResName, std::uint32_t dwNewResId) { setResourceIdT(strResTypeName, strResName, dwNewResId); } @@ -1756,7 +1756,7 @@ namespace PeLib * @param uiResIndex Identifies the resource. * @param dwNewResId New ID of the specified resource. **/ - void ResourceDirectory::setResourceIdByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, dword dwNewResId) + void ResourceDirectory::setResourceIdByIndex(unsigned int uiResTypeIndex, unsigned int uiResIndex, std::uint32_t dwNewResId) { ResourceNode* currNode = static_cast(m_rnRoot.children[uiResTypeIndex].child); currNode->children[uiResIndex].entry.irde.Name = dwNewResId; @@ -1768,7 +1768,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @return Name of the specified resource. **/ - std::string ResourceDirectory::getResourceName(dword dwResTypeId, dword dwResId) const + std::string ResourceDirectory::getResourceName(std::uint32_t dwResTypeId, std::uint32_t dwResId) const { return getResourceNameT(dwResTypeId, dwResId); } @@ -1779,7 +1779,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @return Name of the specified resource. **/ - std::string ResourceDirectory::getResourceName(const std::string& strResTypeName, dword dwResId) const + std::string ResourceDirectory::getResourceName(const std::string& strResTypeName, std::uint32_t dwResId) const { return getResourceNameT(strResTypeName, dwResId); } @@ -1802,7 +1802,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @param strNewResName New name of the specified resource. **/ - void ResourceDirectory::setResourceName(dword dwResTypeId, dword dwResId, const std::string& strNewResName) + void ResourceDirectory::setResourceName(std::uint32_t dwResTypeId, std::uint32_t dwResId, const std::string& strNewResName) { setResourceNameT(dwResTypeId, dwResId, strNewResName); } @@ -1813,7 +1813,7 @@ namespace PeLib * @param strResName Identifies the resource. * @param strNewResName New name of the specified resource. **/ - void ResourceDirectory::setResourceName(dword dwResTypeId, const std::string& strResName, const std::string& strNewResName) + void ResourceDirectory::setResourceName(std::uint32_t dwResTypeId, const std::string& strResName, const std::string& strNewResName) { setResourceNameT(dwResTypeId, strResName, strNewResName); } @@ -1824,7 +1824,7 @@ namespace PeLib * @param dwResId Identifies the resource. * @param strNewResName New name of the specified resource. **/ - void ResourceDirectory::setResourceName(const std::string& strResTypeName, dword dwResId, const std::string& strNewResName) + void ResourceDirectory::setResourceName(const std::string& strResTypeName, std::uint32_t dwResId, const std::string& strNewResName) { setResourceNameT(strResTypeName, dwResId, strNewResName); } diff --git a/src/pelib/RichHeader.cpp b/src/pelib/RichHeader.cpp index 3e31dd992..3b87ea253 100644 --- a/src/pelib/RichHeader.cpp +++ b/src/pelib/RichHeader.cpp @@ -697,14 +697,14 @@ namespace PeLib namespace { - std::string makeSignature(dword value) + std::string makeSignature(std::uint32_t value) { std::stringstream signature; - signature << std::hex << std::setfill('0') << std::setw(2 * sizeof(dword)) << std::uppercase << value; + signature << std::hex << std::setfill('0') << std::setw(2 * sizeof(std::uint32_t)) << std::uppercase << value; return signature.str(); } - std::string makeSignature(dword first, dword second) + std::string makeSignature(std::uint32_t first, std::uint32_t second) { return makeSignature(first) + makeSignature(second); } @@ -822,8 +822,8 @@ namespace { PELIB_IMAGE_RICH_HEADER_RECORD record; - record.ProductId = (word)(decryptedHeader[i] >> 0x10); - record.ProductBuild = (word)(decryptedHeader[i] & 0xFFFF); + record.ProductId = (std::uint16_t)(decryptedHeader[i] >> 0x10); + record.ProductBuild = (std::uint16_t)(decryptedHeader[i] & 0xFFFF); record.Count = decryptedHeader[i + 1]; record.Signature = makeSignature(decryptedHeader[i], decryptedHeader[i + 1]); @@ -838,16 +838,16 @@ namespace void RichHeader::read(InputBuffer& inputbuffer, std::size_t uiSize, bool ignoreInvalidKey) { init(); - std::vector rich; + std::vector rich; - for (std::size_t i = 0, e = uiSize / sizeof(dword); i < e; ++i) + for (std::size_t i = 0, e = uiSize / sizeof(std::uint32_t); i < e; ++i) { - dword actInput; + std::uint32_t actInput; inputbuffer >> actInput; rich.push_back(actInput); } - dword sign[] = {0x68636952}; + std::uint32_t sign[] = {0x68636952}; auto lastPos = rich.end(); // try to find signature of rich header and key for decryption @@ -922,12 +922,12 @@ namespace return noOfIters; } - dword RichHeader::getKey() const + std::uint32_t RichHeader::getKey() const { return key; } - const dword* RichHeader::getDecryptedHeaderItem(std::size_t index) const + const std::uint32_t* RichHeader::getDecryptedHeaderItem(std::size_t index) const { return (index < decryptedHeader.size()) ? &decryptedHeader[index] : nullptr; } @@ -952,7 +952,7 @@ namespace std::vector RichHeader::getDecryptedHeaderBytes() const { - std::vector result(decryptedHeader.size() * sizeof(dword)); + std::vector result(decryptedHeader.size() * sizeof(std::uint32_t)); std::memcpy(result.data(), reinterpret_cast(decryptedHeader.data()), result.size()); return result; } diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp index 88e3b4ec4..6fc147186 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp @@ -556,7 +556,8 @@ template UpxExtraData PeUpxStub::parseExtraData(DynamicBuffer& std::uint16_t numberOfSections = unpackedData.read(originalHeaderOffset + sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + 0x2); std::uint32_t numberOfDirectories = unpackedData.read(originalHeaderOffset + PeUpxStubTraits::NumberOfRvaAndSizesOffset); - std::uint32_t dataDirectoriesStart = sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size() + PeLib::PELIB_IMAGE_OPTIONAL_HEADER::size(); + std::uint32_t sizeOfOptionalHeader = (bits == 64) ? sizeof(PeLib::PELIB_IMAGE_OPTIONAL_HEADER64) : sizeof(PeLib::PELIB_IMAGE_OPTIONAL_HEADER32); + std::uint32_t dataDirectoriesStart = sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size() + sizeOfOptionalHeader; std::uint32_t sectionHeadersStart = dataDirectoriesStart + numberOfDirectories * PeLib::PELIB_IMAGE_DATA_DIRECTORY::size(); std::uint32_t sectionHeadersEnd = sectionHeadersStart + PeLib::PELIB_IMAGE_SECTION_HEADER::size() * numberOfSections; @@ -674,7 +675,7 @@ template void PeUpxStub::fixImports(const DynamicBuffer& unpack lowestFirstThunk = std::min(lowestFirstThunk, firstThunk); readPos += 4; - // There is some kind of 1 byte "hint" + // There is some kind of 1 std::uint8_t "hint" // Recognizes between import by name and by ordinal // Hint 0 means end of the symbols in this library std::uint8_t hint; @@ -1307,7 +1308,7 @@ template void PeUpxStub::loadResources(PeLib::ResourceNode* roo std::string name = ""; // It is wide string, but rarely contains any unicode characters - // We will use regular ASCII string and pretend we are reading 1-byte characters + // We will use regular ASCII string and pretend we are reading 1-std::uint8_t characters std::uint16_t charsRead = 0; while (charsRead < nameLength) { From d20fe2a50237a730e4b9999c3678c87322a6af78 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 17 Jun 2020 10:22:35 +0200 Subject: [PATCH 03/34] Image Loader: IAT --- include/retdec/pelib/IatDirectory.h | 4 +- src/pelib/IatDirectory.cpp | 73 +++++++++++++++++------------ 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/include/retdec/pelib/IatDirectory.h b/include/retdec/pelib/IatDirectory.h index 4b0967dd9..06abfd8ab 100644 --- a/include/retdec/pelib/IatDirectory.h +++ b/include/retdec/pelib/IatDirectory.h @@ -28,13 +28,11 @@ namespace PeLib protected: std::vector m_vIat; ///< Stores the individual IAT fields. - int read(InputBuffer& inputBuffer, unsigned int dwOffset, unsigned int dwFileSize); - public: virtual ~IatDirectory() = default; /// Reads the Import Address Table from a PE file. - int read(unsigned char* buffer, unsigned int buffersize); // EXPORT + int read(const void * buffer, std::size_t buffersize); // EXPORT /// Reads the Import Address Table from an image loader int read(PeLib::ImageLoader & imageLoader); // EXPORT /// Returns the number of fields in the IAT. diff --git a/src/pelib/IatDirectory.cpp b/src/pelib/IatDirectory.cpp index ab76e2469..712efac6e 100644 --- a/src/pelib/IatDirectory.cpp +++ b/src/pelib/IatDirectory.cpp @@ -14,61 +14,72 @@ namespace PeLib { - int IatDirectory::read(InputBuffer& inputBuffer, unsigned int dwOffset, unsigned int dwFileSize) + /** + * Reads the Import Address table from an image + * @param buffer Pointer to the IAT data + * @param buffersize Length of the data pointed by 'buffer' + **/ + int IatDirectory::read(const void * buffer, std::size_t buffersize) { - std::uint32_t dwAddr; + const std::uint32_t * itemArray = reinterpret_cast(buffer); - std::vector vIat; + // Resize the IAT vector to contain all items + std::size_t itemCount = buffersize / sizeof(std::uint8_t); + m_vIat.clear(); - unsigned int dwCurrentOffset = dwOffset; - while (dwCurrentOffset < dwFileSize) + // Read the items, one-by-one, until we find a zero value + for(std::size_t i = 0; i < itemCount; i++) { - inputBuffer >> dwAddr; - if (dwAddr == 0) + // Insert that item + m_vIat.push_back(itemArray[i]); + + // Zero is considered terminator + if(itemArray[i] == 0) break; - - vIat.push_back(dwAddr); - dwCurrentOffset += sizeof(dwAddr); } - std::swap(vIat, m_vIat); - return ERROR_NONE; } - int IatDirectory::read(unsigned char* buffer, unsigned int buffersize) - { - std::vector vBuffer(buffer, buffer + buffersize); - InputBuffer inpBuffer(vBuffer); - return read(inpBuffer, 0, buffersize); - } - /** - * Reads the Import Address table from a file. - * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. + * Reads the Import Address table from an image + * @param imageLoader Initialized image loader **/ int IatDirectory::read(ImageLoader & imageLoader) { + std::uint8_t * iatArray; std::uint32_t iatRva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IAT); std::uint32_t iatSize = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_IAT); - std::uint32_t sizeofImage = imageLoader.getSizeOfImage(); + std::uint32_t sizeOfImage = imageLoader.getSizeOfImage(); + int fileError = ERROR_NONE; // Check whether the IAT is outside the image - if(iatRva >= sizeofImage) + if(iatRva >= sizeOfImage) { return ERROR_INVALID_FILE; } - // Read the IAT from the image - std::uint32_t dwSize = std::min(sizeofImage - iatRva, iatSize); - std::vector vBuffer(dwSize); - imageLoader.readImage(reinterpret_cast(vBuffer.data()), iatRva, dwSize); + // Trim the array size to the size of image + if((iatRva + iatSize) > sizeOfImage) + iatSize = sizeOfImage - iatRva; - InputBuffer inpBuffer{vBuffer}; - return IatDirectory::read(inpBuffer, 0, dwSize); - } + // Allocate array for the entire IAT + if((iatArray = new std::uint8_t[iatSize]) != nullptr) + { + // Read the entire IAT to the memory + iatSize = imageLoader.readImage(iatArray, iatRva, iatSize); + + // Insert the IAT array to the internal IAT vector + fileError = read(iatArray, iatSize); + delete [] iatArray; + } + else + { + fileError = ERROR_NOT_ENOUGH_SPACE; + } + return fileError; + } /** * Returns the number of fields in the IAT. This is equivalent to the number of From b728684b930f4eabbb36ddb1766d0aab32776392 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Fri, 19 Jun 2020 07:43:51 +0200 Subject: [PATCH 04/34] ImageLoader: Debug Directory --- .../fileformat/file_format/pe/pe_template.h | 24 +- include/retdec/pelib/BoundImportDirectory.h | 44 +--- include/retdec/pelib/DebugDirectory.h | 79 +------ include/retdec/pelib/DelayImportDirectory.h | 220 ++++++++---------- include/retdec/pelib/ExportDirectory.h | 166 +------------ include/retdec/pelib/ImageLoader.h | 9 +- include/retdec/pelib/ImportDirectory.h | 4 +- include/retdec/pelib/PeFile.h | 100 ++++---- include/retdec/pelib/PeLibAux.h | 52 ++--- src/fileformat/file_format/pe/pe_format.cpp | 2 +- src/pelib/BoundImportDirectory.cpp | 23 ++ src/pelib/DebugDirectory.cpp | 100 +++++--- src/pelib/ExportDirectory.cpp | 107 +++++++++ src/pelib/ImageLoader.cpp | 32 ++- src/pelib/PeFile.cpp | 18 ++ 15 files changed, 434 insertions(+), 546 deletions(-) diff --git a/include/retdec/fileformat/file_format/pe/pe_template.h b/include/retdec/fileformat/file_format/pe/pe_template.h index 735377519..70269a0a6 100644 --- a/include/retdec/fileformat/file_format/pe/pe_template.h +++ b/include/retdec/fileformat/file_format/pe/pe_template.h @@ -339,7 +339,7 @@ inline unsigned long long peNumberOfImportedLibraries(const PeLib::ImportDirecto * @param delay Parser of PE delay import directory * @return Number of delay imported libraries */ -template unsigned long long peNumberOfDelayImportedLibraries(const PeLib::DelayImportDirectory &delay) +inline unsigned long long peNumberOfDelayImportedLibraries(const PeLib::DelayImportDirectory &delay) { return delay.getNumberOfFiles(); } @@ -507,7 +507,7 @@ inline bool peImportedLibraryFileName( * * If function returns @c false, @a fileName is left unchanged. */ -template bool peDelayImportedLibraryFileName(const PeLib::DelayImportDirectory &delay, std::string &fileName, unsigned long long index) +inline bool peDelayImportedLibraryFileName(const PeLib::DelayImportDirectory &delay, std::string &fileName, unsigned long long index) { const auto *library = delay.getFile(index); if(!library) @@ -586,7 +586,7 @@ template std::unique_ptr peImport(const PeLib::PeHeaderT std::unique_ptr peDelayImport(const PeLib::PeHeaderT &peHeader, - const PeLib::DelayImportDirectory &delay, + const PeLib::DelayImportDirectory &delay, unsigned long long fileIndex, unsigned long long importIndex) { const auto *library = delay.getFile(fileIndex); @@ -603,7 +603,7 @@ template std::unique_ptr peDelayImport(const PeLib::PeHeader auto import = std::make_unique(PeImportFlag::Delayed); import->setName(function->fname); - import->setAddress(peImageBase(peHeader) + function->address.Value); + import->setAddress(peImageBase(peHeader) + function->address); import->setLibraryIndex(fileIndex); import->invalidateOrdinalNumber(); if(library->ordinalNumbersAreValid() && function->hint != 0) @@ -619,7 +619,7 @@ template std::unique_ptr peDelayImport(const PeLib::PeHeader * @param exports Parser of PE export directory * @return Number of exported functions */ -template unsigned long long peNumberOfExportedFunctions(const PeLib::ExportDirectoryT &exports) +inline unsigned long long peNumberOfExportedFunctions(const PeLib::ExportDirectory &exports) { return exports.calcNumberOfFunctions(); } @@ -632,7 +632,7 @@ template unsigned long long peNumberOfExportedFunctions(const PeLib::E * @param exportedFunction Exported function to fill * @return @c false if index is out of bounds, otherwise @c true */ -template bool peExportedFunction(const PeLib::PeHeaderT &peHeader, const PeLib::ExportDirectoryT &exports, unsigned long long index, Export& exportedFunction) +template bool peExportedFunction(const PeLib::PeHeaderT &peHeader, const PeLib::ExportDirectory &exports, unsigned long long index, Export& exportedFunction) { if (index >= peNumberOfExportedFunctions(exports)) { @@ -650,7 +650,7 @@ template bool peExportedFunction(const PeLib::PeHeaderT &peHeade * @param debug Parser of PE debug directory * @return Number of debug entries */ -template unsigned long long peNumberOfDebugEntries(const PeLib::DebugDirectoryT &debug) +inline unsigned long long peNumberOfDebugEntries(const PeLib::DebugDirectory &debug) { return debug.calcNumberOfEntries(); } @@ -662,7 +662,7 @@ template unsigned long long peNumberOfDebugEntries(const PeLib::DebugD * @param data Data to fill * @return @c false if index is out of bounds, otherwise @c true */ -template bool peDebugEntryData(const PeLib::DebugDirectoryT &debug, unsigned long long index, std::vector& data) +inline bool peDebugEntryData(const PeLib::DebugDirectory &debug, unsigned long long index, std::vector& data) { if (index >= peNumberOfDebugEntries(debug)) { @@ -680,7 +680,7 @@ template bool peDebugEntryData(const PeLib::DebugDirectoryT &deb * @param timeDateStamp Timestamp to fill * @return @c false if index is out of bounds, otherwise @c true */ -template bool peDebugEntryTimeDateStamp(const PeLib::DebugDirectoryT &debug, unsigned long long index, unsigned long long& timeDateStamp) +inline bool peDebugEntryTimeDateStamp(const PeLib::DebugDirectory &debug, unsigned long long index, unsigned long long& timeDateStamp) { if (index >= peNumberOfDebugEntries(debug)) { @@ -698,7 +698,7 @@ template bool peDebugEntryTimeDateStamp(const PeLib::DebugDirectoryT bool peDebugEntryPointerToRawData(const PeLib::DebugDirectoryT &debug, unsigned long long index, unsigned long long& pointerToRawData) +inline bool peDebugEntryPointerToRawData(const PeLib::DebugDirectory &debug, unsigned long long index, unsigned long long& pointerToRawData) { if (index >= peNumberOfDebugEntries(debug)) { @@ -908,7 +908,7 @@ inline retdec::common::RangeContainer peImportDirectoryOccupiedAd * @param peExports Parser of PE export directory * @return Occupied address ranges */ -template retdec::common::RangeContainer peExportDirectoryOccupiedAddresses(const PeLib::ExportDirectoryT &peExports) +inline retdec::common::RangeContainer peExportDirectoryOccupiedAddresses(const PeLib::ExportDirectory &peExports) { retdec::common::RangeContainer result; for (const auto& addresses : peExports.getOccupiedAddresses()) @@ -931,7 +931,7 @@ template retdec::common::RangeContainer peExportDirecto * @param peDebug Parser of PE debug directory * @return Occupied address ranges */ -template retdec::common::RangeContainer peDebugDirectoryOccupiedAddresses(const PeLib::DebugDirectoryT &peDebug) +inline retdec::common::RangeContainer peDebugDirectoryOccupiedAddresses(const PeLib::DebugDirectory &peDebug) { retdec::common::RangeContainer result; for (const auto& addresses : peDebug.getOccupiedAddresses()) diff --git a/include/retdec/pelib/BoundImportDirectory.h b/include/retdec/pelib/BoundImportDirectory.h index 76dd24bee..3e43dee5e 100644 --- a/include/retdec/pelib/BoundImportDirectory.h +++ b/include/retdec/pelib/BoundImportDirectory.h @@ -15,6 +15,7 @@ #include "retdec/pelib/PeHeader.h" #include "retdec/pelib/PeLibAux.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { @@ -32,6 +33,8 @@ namespace PeLib public: virtual ~BoundImportDirectory() = default; + /// Reads the BoundImport directory table from a PE file. + int read(ImageLoader & imageLoader); // EXPORT /// Adds another bound import. int addBoundImport(const std::string& strModuleName, std::uint32_t dwTds, std::uint16_t dwOmn, std::uint16_t wWfr); // EXPORT /// Identifies a module through it's name. @@ -83,47 +86,6 @@ namespace PeLib void addForwardedModule(std::uint32_t dwBidnr, const std::string& name, std::uint32_t timeStamp = 0, std::uint16_t offsetModuleName = 0, std::uint16_t forwardedModules = 0); // EXPORT void removeForwardedModule(std::uint32_t dwBidnr, std::uint16_t forwardedModule); // EXPORT }; - - template - class BoundImportDirectoryT : public BoundImportDirectory - { - public: - /// Reads the BoundImport directory table from a PE file. - int read(std::istream& inStream, const PeHeaderT& peHeader); // EXPORT - }; - - /** - * Reads the BoundImport directory from a PE file. - * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. - **/ - template - int BoundImportDirectoryT::read( - std::istream& inStream, - const PeHeaderT& peHeader) - { - IStreamWrapper inStream_w(inStream); - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - std::uint32_t dwOffset = peHeader.rvaToOffset(peHeader.getIddBoundImportRva()); - unsigned int uiSize = peHeader.getIddBoundImportSize(); - - if (fileSize(inStream_w) < dwOffset + uiSize) - { - return ERROR_INVALID_FILE; - } - - std::vector vBimpDir(uiSize); - inStream_w.seekg(dwOffset, std::ios::beg); - inStream_w.read(reinterpret_cast(vBimpDir.data()), uiSize); - - InputBuffer inpBuffer{vBimpDir}; - return BoundImportDirectory::read(inpBuffer, vBimpDir.data(), uiSize); - } } #endif diff --git a/include/retdec/pelib/DebugDirectory.h b/include/retdec/pelib/DebugDirectory.h index 5ee5b6876..e57706b30 100644 --- a/include/retdec/pelib/DebugDirectory.h +++ b/include/retdec/pelib/DebugDirectory.h @@ -13,7 +13,7 @@ #ifndef DEBUGDIRECTORY_H #define DEBUGDIRECTORY_H -#include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { @@ -26,14 +26,15 @@ namespace PeLib /// Stores RVAs which are occupied by this debug directory. std::vector> m_occupiedAddresses; - std::vector read(InputBuffer& ibBuffer, unsigned int uiRva, unsigned int uiSize); + void read(ImageLoader & imageLoader, std::vector & debugInfo, std::uint32_t rva, std::uint32_t size); public: virtual ~DebugDirectory() = default; - void clear(); // EXPORT /// Reads the Debug directory from a file. - int read(unsigned char* buffer, unsigned int buffersize); + int read(std::istream& inStream, ImageLoader & imageLoader); + /// + void clear(); // EXPORT /// Rebuilds the current Debug directory. void rebuild(std::vector& obBuffer) const; // EXPORT /// Returns the size the current Debug directory needs after rebuilding. @@ -87,75 +88,5 @@ namespace PeLib const std::vector>& getOccupiedAddresses() const; }; - - template - class DebugDirectoryT : public DebugDirectory - { - public: - /// Reads the Debug directory from a file. - int read(std::istream& inStream, const PeHeaderT& peHeader); - }; - - /** - * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. - **/ - template - int DebugDirectoryT::read(std::istream& inStream, const PeHeaderT& peHeader) - { - IStreamWrapper inStream_w(inStream); - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - std::uint64_t ulFileSize = fileSize(inStream_w); - - unsigned int uiRva = peHeader.getIddDebugRva(); - unsigned int uiOffset = peHeader.rvaToOffset(uiRva); - unsigned int uiSize = peHeader.getIddDebugSize(); - - if (ulFileSize < uiOffset + uiSize) - { - return ERROR_INVALID_FILE; - } - - inStream_w.seekg(uiOffset, std::ios::beg); - - std::vector vDebugDirectory(uiSize); - inStream_w.read(reinterpret_cast(vDebugDirectory.data()), uiSize); - - InputBuffer ibBuffer{vDebugDirectory}; - - std::vector currDebugInfo = DebugDirectory::read(ibBuffer, uiRva, uiSize); - - for (unsigned int i=0;i= ulFileSize) || - (currDebugInfo[i].idd.PointerToRawData + currDebugInfo[i].idd.SizeOfData >= ulFileSize)) - { - return ERROR_INVALID_FILE; - } - - inStream_w.seekg(currDebugInfo[i].idd.PointerToRawData, std::ios::beg); - currDebugInfo[i].data.resize(currDebugInfo[i].idd.SizeOfData); - inStream_w.read(reinterpret_cast(currDebugInfo[i].data.data()), currDebugInfo[i].idd.SizeOfData); - if (!inStream_w) return ERROR_INVALID_FILE; - - if (currDebugInfo[i].idd.SizeOfData > 0) - { - m_occupiedAddresses.push_back( - std::make_pair( - currDebugInfo[i].idd.AddressOfRawData, - currDebugInfo[i].idd.AddressOfRawData + currDebugInfo[i].idd.SizeOfData - 1 - )); - } - } - - std::swap(currDebugInfo, m_vDebugInfo); - - return ERROR_NONE; - } } #endif diff --git a/include/retdec/pelib/DelayImportDirectory.h b/include/retdec/pelib/DelayImportDirectory.h index 7161a4090..e8e207975 100644 --- a/include/retdec/pelib/DelayImportDirectory.h +++ b/include/retdec/pelib/DelayImportDirectory.h @@ -9,20 +9,20 @@ #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { /** - * This class handless delay import directory. + * This class handles delay import directory. */ - template + class DelayImportDirectory { - typedef typename std::vector >::const_iterator DelayImportDirectoryIterator; - typedef typename FieldSizes::VAR4_8 VAR4_8; + typedef typename std::vector::const_iterator DelayImportDirectoryIterator; private: - std::vector > records; + std::vector records; void init() { @@ -40,164 +40,136 @@ namespace PeLib } - // Delay-import descriptors made by MS Visual C++ 6.0 has an old format + // Delay-import descriptors made by MS Visual C++ 6.0 have old format // of delay import directory, where all entries are VAs (as opposite to RVAs from newer MS compilers). // We convert the delay-import directory entries to RVAs by checking the lowest bit in the delay-import descriptor's Attributes value - VAR4_8 normalizeDelayImportValue(const PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD & rec, const PeHeaderT& peHeader, VAR4_8 valueToConvert) + std::uint64_t normalizeDelayImportValue(std::uint64_t imageBase, std::uint64_t virtualAddress) { // Ignore zero items - if (valueToConvert != 0) + if (virtualAddress != 0) { - // Is this the old format version? - if((rec.Attributes & 0x01) == 0) + // Sample: 0fc4cb0620f95bdd624f2c78eea4d2b59594244c6671cf249526adf2f2cb71ec + // Contains artificially created delay import directory with incorrect values: + // + // Attributes 0x00000000 <-- Old MS delay import record, contains VAs + // NameRva 0x004010e6 + // ModuleHandleRva 0x00000000 + // DelayImportAddressTableRva 0x00001140 <-- WRONG! This is an RVA + // DelayImportNameTableRva 0x004010c0 + // BoundDelayImportTableRva 0x00000000 + // ... + + if (virtualAddress > imageBase) { - // Sample: 0fc4cb0620f95bdd624f2c78eea4d2b59594244c6671cf249526adf2f2cb71ec - // Contains artificially created delay import directory with incorrect values: - // - // Attributes 0x00000000 <-- Old MS delay import record, contains VAs - // NameRva 0x004010e6 - // ModuleHandleRva 0x00000000 - // DelayImportAddressTableRva 0x00001140 <-- WRONG! This is an RVA - // DelayImportNameTableRva 0x004010c0 - // BoundDelayImportTableRva 0x00000000 - // ... - - if (valueToConvert > peHeader.getImageBase()) - { - valueToConvert = valueToConvert - peHeader.getImageBase(); - } + virtualAddress = virtualAddress - imageBase; } } - return valueToConvert; + return virtualAddress; } - int read(std::istream& inStream, const PeHeaderT& peHeader) + void normalize32BitDelayImport(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR & rec, std::uint64_t imageBase) { - init(); + rec.NameRva = (std::uint32_t)normalizeDelayImportValue(imageBase, rec.NameRva); + rec.ModuleHandleRva = (std::uint32_t)normalizeDelayImportValue(imageBase, rec.ModuleHandleRva); + rec.DelayImportAddressTableRva = (std::uint32_t)normalizeDelayImportValue(imageBase, rec.DelayImportAddressTableRva); + rec.DelayImportNameTableRva = (std::uint32_t)normalizeDelayImportValue(imageBase, rec.DelayImportNameTableRva); + rec.BoundDelayImportTableRva = (std::uint32_t)normalizeDelayImportValue(imageBase, rec.BoundDelayImportTableRva); + rec.UnloadDelayImportTableRva = (std::uint32_t)normalizeDelayImportValue(imageBase, rec.UnloadDelayImportTableRva); + } - IStreamWrapper inStream_w(inStream); - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } + bool isTerminationEntry(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR & importDescriptor) + { + return (importDescriptor.Attributes == 0 && + importDescriptor.NameRva == 0 && + importDescriptor.ModuleHandleRva == 0 && + importDescriptor.DelayImportAddressTableRva == 0 && + importDescriptor.DelayImportNameTableRva == 0 && + importDescriptor.BoundDelayImportTableRva == 0 && + importDescriptor.UnloadDelayImportTableRva == 0 && + importDescriptor.TimeStamp == 0); + } - std::uint64_t ulFileSize = fileSize(inStream_w); - std::uint64_t uiOffset = peHeader.rvaToOffset(peHeader.getIddDelayImportRva()); - if (uiOffset >= ulFileSize) - { + int read(ImageLoader & imageLoader) + { + std::uint32_t rva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); + std::uint32_t size = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); + std::uint32_t sizeOfImage = imageLoader.getSizeOfImage(); + std::uint32_t pointerSize = imageLoader.getPointerSize(); + std::uint64_t imageBase = imageLoader.getImageBase(); + std::uint64_t ordinalMask = imageLoader.getOrdinalMask(); + + if(rva >= sizeOfImage) return ERROR_INVALID_FILE; - } - - PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD rec; - std::vector dump; - dump.resize(PELIB_IMAGE_SIZEOF_DELAY_IMPORT_DIRECTORY_RECORD); + init(); // Keep loading until we encounter an entry filles with zeros - for(std::size_t i = 0;; i += PELIB_IMAGE_SIZEOF_DELAY_IMPORT_DIRECTORY_RECORD) + for(std::size_t i = 0;; i += sizeof(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR)) { - InputBuffer inputbuffer(dump); + PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD rec; - // Read the n-th import sdirectory entry - if (!inStream_w.seekg(uiOffset + i, std::ios::beg)) + // Read the n-th import directory entry + if((rva + i) >= sizeOfImage) break; - if (!inStream_w.read(reinterpret_cast(dump.data()), PELIB_IMAGE_SIZEOF_DELAY_IMPORT_DIRECTORY_RECORD)) + if(!imageLoader.readImage(&rec.delayedImport, rva + i, sizeof(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR))) break; - rec.init(); - inputbuffer >> rec.Attributes; - inputbuffer >> rec.NameRva; - inputbuffer >> rec.ModuleHandleRva; - inputbuffer >> rec.DelayImportAddressTableRva; - inputbuffer >> rec.DelayImportNameTableRva; - inputbuffer >> rec.BoundDelayImportTableRva; - inputbuffer >> rec.UnloadDelayImportTableRva; - inputbuffer >> rec.TimeStamp; - if ( rec.Attributes == 0 && rec.NameRva == 0 && rec.ModuleHandleRva == 0 && rec.DelayImportAddressTableRva == 0 && - rec.DelayImportNameTableRva == 0 && rec.BoundDelayImportTableRva == 0 && rec.UnloadDelayImportTableRva == 0 && - rec.TimeStamp == 0) - { + // Check for the termination entry + if(isTerminationEntry(rec.delayedImport)) break; - } // Convert older (MS Visual C++ 6.0) delay-import descriptor to newer one. // These delay-import descriptors are distinguishable by lowest bit in rec.Attributes to be zero. // Sample: 2775d97f8bdb3311ace960a42eee35dbec84b9d71a6abbacb26c14e83f5897e4 - rec.NameRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.NameRva); - rec.ModuleHandleRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.ModuleHandleRva); - rec.DelayImportAddressTableRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.DelayImportAddressTableRva); - rec.DelayImportNameTableRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.DelayImportNameTableRva); - rec.BoundDelayImportTableRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.BoundDelayImportTableRva); - rec.UnloadDelayImportTableRva = (std::uint32_t)normalizeDelayImportValue(rec, peHeader, rec.UnloadDelayImportTableRva); - - rec.DelayImportAddressTableOffset = (std::uint32_t)peHeader.rvaToOffset(rec.DelayImportAddressTableRva); - rec.DelayImportNameTableOffset = (std::uint32_t)peHeader.rvaToOffset(rec.DelayImportNameTableRva); + if(imageLoader.getImageBitability() == 32 && (rec.delayedImport.Attributes & PELIB_DELAY_ATTRIBUTE_V2) == 0) + normalize32BitDelayImport(rec.delayedImport, (std::uint32_t)imageBase); // Get name of library - getStringFromFileOffset(inStream_w, rec.Name, (std::size_t)peHeader.rvaToOffset(rec.NameRva), IMPORT_LIBRARY_MAX_LENGTH); + imageLoader.readString(rec.Name, rec.delayedImport.NameRva, IMPORT_LIBRARY_MAX_LENGTH); // // LOADING NAME ADDRESSES/NAME ORDINALS // - // Address table is not guaranteed to be null-terminated and therefore we need to first read name table. - inStream_w.seekg(rec.DelayImportNameTableOffset, std::ios::beg); - if(!inStream_w) - { - return ERROR_INVALID_FILE; - } + std::vector nameAddresses; + std::uint32_t rva = rec.delayedImport.DelayImportNameTableRva; - // Read all RVAs (or VAs) of import names - std::vector> nameAddresses; for(;;) { - PELIB_VAR_SIZE nameAddr; - std::vector vBuffer(sizeof(nameAddr.Value)); + std::uint64_t nameAddress; - // Read the value from the file - inStream_w.read(reinterpret_cast(vBuffer.data()), sizeof(nameAddr.Value)); - if (!inStream_w || inStream_w.gcount() < sizeof(nameAddr.Value)) + // Read single name address + if(imageLoader.readPointer(rva, nameAddress) != pointerSize) break; - - InputBuffer inb(vBuffer); - inb >> nameAddr.Value; + rva += pointerSize; // Value of zero means that this is the end of the bound import name table - if (nameAddr.Value == 0) + if(nameAddress == 0) break; - nameAddresses.push_back(nameAddr); + nameAddresses.push_back(nameAddress); } // // LOADING FUNCTION POINTERS // - // Move to the offset of function addresses - inStream_w.seekg(rec.DelayImportAddressTableOffset, std::ios::beg); - if (!inStream_w) - { - return ERROR_INVALID_FILE; - } + std::vector funcAddresses; + rva = rec.delayedImport.DelayImportAddressTableRva; // Read all (VAs) of import names - std::vector> funcAddresses; - for (std::size_t i = 0, e = nameAddresses.size(); i < e; ++i) + for (std::size_t i = 0; i < nameAddresses.size(); i++) { - PELIB_VAR_SIZE funcAddr; - std::vector vBuffer(sizeof(funcAddr.Value)); + std::uint64_t funcAddress; - // Read the value from the file - inStream_w.read(reinterpret_cast(vBuffer.data()), sizeof(funcAddr.Value)); - if (!inStream_w || inStream_w.gcount() < sizeof(funcAddr.Value)) + // Read single name address + if(imageLoader.readPointer(rva, funcAddress) != pointerSize) break; + rva += pointerSize; - InputBuffer inb(vBuffer); - inb >> funcAddr.Value; - - // The value of zero means terminator of the function table - if (funcAddr.Value == 0) + // Value of zero means that this is the end of the bound import name table + if(funcAddress == 0) break; - funcAddresses.push_back(funcAddr); + funcAddresses.push_back(funcAddress); } // @@ -207,34 +179,33 @@ namespace PeLib std::size_t numberOfFunctions = std::min(nameAddresses.size(), funcAddresses.size()); for (std::size_t i = 0; i < numberOfFunctions; i++) { - PELIB_DELAY_IMPORT function; - PELIB_VAR_SIZE nameAddr = nameAddresses[i]; - PELIB_VAR_SIZE funcAddr = funcAddresses[i]; + PELIB_DELAY_IMPORT function; + std::uint64_t nameAddress = nameAddresses[i]; + std::uint64_t funcAddress = funcAddresses[i]; // Check name address. It could be ordinal, VA or RVA - if (!(nameAddr.Value & PELIB_IMAGE_ORDINAL_FLAGS::PELIB_IMAGE_ORDINAL_FLAG)) + if (!(nameAddress & ordinalMask)) { - // Convert value to RVA, if needed - nameAddr.Value = normalizeDelayImportValue(rec, peHeader, nameAddr.Value); + // Convert name address to RVA, if needed + if((rec.delayedImport.Attributes & PELIB_DELAY_ATTRIBUTE_V2) == 0) + nameAddress = normalizeDelayImportValue(imageBase, nameAddress); // Read the function hint - inStream_w.seekg(peHeader.rvaToOffset(nameAddr.Value), std::ios::beg); - inStream_w.read(reinterpret_cast(&function.hint), sizeof(function.hint)); - if (!inStream_w || inStream_w.gcount() < sizeof(function.hint)) + if(imageLoader.readImage(&function.hint, nameAddress, sizeof(function.hint)) != sizeof(function.hint)) break; // Read the function name - getStringFromFileOffset(inStream_w, function.fname, inStream_w.tellg(), IMPORT_SYMBOL_MAX_LENGTH); + imageLoader.readString(function.fname, nameAddress + sizeof(function.hint), IMPORT_SYMBOL_MAX_LENGTH); } else { - function.hint = (std::uint16_t)(nameAddr.Value & 0xFFFF); + function.hint = (std::uint16_t)(nameAddress & 0xFFFF); } - // Fill-in function address. The table is always in the image itself - if (peHeader.getImageBase() <= funcAddr.Value && funcAddr.Value < peHeader.getImageBase() + peHeader.getSizeOfImage()) - funcAddr.Value -= peHeader.getImageBase(); - function.address.Value = funcAddr.Value; + // Convert function address to RVA, if needed + if((rec.delayedImport.Attributes & PELIB_DELAY_ATTRIBUTE_V2) == 0) + funcAddress = normalizeDelayImportValue(imageBase, funcAddress); + function.address = normalizeDelayImportValue(imageBase, funcAddress); // Insert the function to the list rec.addFunction(function); @@ -242,7 +213,6 @@ namespace PeLib records.push_back(rec); } - return ERROR_NONE; } @@ -251,7 +221,7 @@ namespace PeLib return records.size(); } - const PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD *getFile(std::size_t index) const + const PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD *getFile(std::size_t index) const { return index < getNumberOfFiles() ? &records[index] : nullptr; } diff --git a/include/retdec/pelib/ExportDirectory.h b/include/retdec/pelib/ExportDirectory.h index 42ec7bedd..89dee5792 100644 --- a/include/retdec/pelib/ExportDirectory.h +++ b/include/retdec/pelib/ExportDirectory.h @@ -13,7 +13,7 @@ #ifndef EXPORTDIRECTORY_H #define EXPORTDIRECTORY_H -#include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { @@ -30,9 +30,14 @@ namespace PeLib /// Stores RVAs which are occupied by this export directory. std::vector> m_occupiedAddresses; + void addOccupiedAddress(const std::string & str, std::uint32_t rva); + public: virtual ~ExportDirectory() = default; + /// Load the export directory from the image loader + int read(ImageLoader & imageLoader); + /// Add another function to be exported. void addFunction(const std::string& strFuncname, std::uint32_t dwFuncAddr); // EXPORT unsigned int calcNumberOfFunctions() const; // EXPORT @@ -133,164 +138,5 @@ namespace PeLib const std::vector>& getOccupiedAddresses() const; }; - - template - class ExportDirectoryT : public ExportDirectory - { - public: - /// Read a file's export directory. - int read(std::istream& inStream, const PeHeaderT& peHeader); // EXPORT - }; - - /** - * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. - * \todo: Proper use of InputBuffer - **/ - template - int ExportDirectoryT::read( - std::istream& inStream, - const PeHeaderT& peHeader) - { - IStreamWrapper inStream_w(inStream); - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - std::uint64_t ulFileSize = fileSize(inStream_w); - unsigned int dirRva = peHeader.getIddExportRva(); - unsigned int dirOffset = peHeader.rvaToOffset(dirRva); - if (ulFileSize < dirOffset + PELIB_IMAGE_EXPORT_DIRECTORY::size()) - { - return ERROR_INVALID_FILE; - } - inStream_w.seekg(dirOffset, std::ios::beg); - - std::vector vExportDirectory(PELIB_IMAGE_EXPORT_DIRECTORY::size()); - inStream_w.read(reinterpret_cast(vExportDirectory.data()), PELIB_IMAGE_EXPORT_DIRECTORY::size()); - - InputBuffer inpBuffer(vExportDirectory); - - PELIB_IMAGE_EXP_DIRECTORY iedCurr; - inpBuffer >> iedCurr.ied.Characteristics; - inpBuffer >> iedCurr.ied.TimeDateStamp; - inpBuffer >> iedCurr.ied.MajorVersion; - inpBuffer >> iedCurr.ied.MinorVersion; - inpBuffer >> iedCurr.ied.Name; - inpBuffer >> iedCurr.ied.Base; - inpBuffer >> iedCurr.ied.NumberOfFunctions; - inpBuffer >> iedCurr.ied.NumberOfNames; - inpBuffer >> iedCurr.ied.AddressOfFunctions; - inpBuffer >> iedCurr.ied.AddressOfNames; - inpBuffer >> iedCurr.ied.AddressOfNameOrdinals; - m_occupiedAddresses.emplace_back(dirRva, dirRva + PELIB_IMAGE_EXPORT_DIRECTORY::size() - 1); - - // Verify the export directory. Do not allow more functions than the limit - // Sample: CCE461B6EB23728BA3B8A97B9BE84C0FB9175DB31B9949E64144198AB3F702CE - if (iedCurr.ied.NumberOfFunctions > PELIB_MAX_EXPORTED_FUNCTIONS || iedCurr.ied.NumberOfNames > PELIB_MAX_EXPORTED_FUNCTIONS) - return ERROR_INVALID_FILE; - - unsigned int offset = peHeader.rvaToOffset(iedCurr.ied.Name); - if (offset >= ulFileSize) - return ERROR_INVALID_FILE; - inStream_w.seekg(offset, std::ios::beg); - - char c = 0; - std::string strFname = ""; - do - { - inStream_w.read(reinterpret_cast(&c), sizeof(c)); - if (!inStream_w) return ERROR_INVALID_FILE; - if (c) strFname += c; - } - while (c != 0); - iedCurr.name = strFname; - m_occupiedAddresses.push_back(std::make_pair(iedCurr.ied.Name, iedCurr.ied.Name + strFname.length() + 1)); - - PELIB_EXP_FUNC_INFORMATION efiCurr; - efiCurr.ordinal = 0; efiCurr.addroffunc = 0; efiCurr.addrofname = 0; - for (unsigned int i=0;i= ulFileSize) - return ERROR_INVALID_FILE; - inStream_w.seekg(offset, std::ios::beg); - inStream_w.read(reinterpret_cast(&efiCurr.addroffunc), sizeof(efiCurr.addroffunc)); - if (!inStream_w) - return ERROR_INVALID_FILE; - - efiCurr.ordinal = iedCurr.ied.Base + i; - iedCurr.functions.push_back(efiCurr); - - m_occupiedAddresses.emplace_back( - iedCurr.ied.AddressOfFunctions + i*sizeof(efiCurr.addroffunc), - iedCurr.ied.AddressOfFunctions + i*sizeof(efiCurr.addroffunc) + sizeof(efiCurr.addroffunc) - 1 - ); - } - - for (unsigned int i=0;i= ulFileSize) - return ERROR_INVALID_FILE; - inStream_w.seekg(offset, std::ios::beg); - std::uint16_t ordinal; - inStream_w.read(reinterpret_cast(&ordinal), sizeof(ordinal)); - m_occupiedAddresses.emplace_back( - iedCurr.ied.AddressOfNameOrdinals + i*sizeof(efiCurr.ordinal), - iedCurr.ied.AddressOfNameOrdinals + i*sizeof(efiCurr.ordinal) + sizeof(efiCurr.ordinal) - 1 - ); - - if (!inStream_w) - return ERROR_INVALID_FILE; - else if (ordinal >= iedCurr.functions.size()) - continue; - - iedCurr.functions[ordinal].ordinal = iedCurr.ied.Base + ordinal; - - offset = peHeader.rvaToOffset(iedCurr.ied.AddressOfNames) + i*sizeof(efiCurr.addrofname); - if (offset >= ulFileSize) - return ERROR_INVALID_FILE; - inStream_w.seekg(offset, std::ios::beg); - inStream_w.read(reinterpret_cast(&iedCurr.functions[ordinal].addrofname), sizeof(iedCurr.functions[ordinal].addrofname)); - if (!inStream_w) - return ERROR_INVALID_FILE; - m_occupiedAddresses.emplace_back( - iedCurr.ied.AddressOfNames + i*sizeof(efiCurr.addrofname), - iedCurr.ied.AddressOfNames + i*sizeof(efiCurr.addrofname) + sizeof(iedCurr.functions[ordinal].addrofname) - 1 - ); - - offset = peHeader.rvaToOffset(iedCurr.functions[ordinal].addrofname); - if (offset >= ulFileSize) - return ERROR_INVALID_FILE; - inStream_w.seekg(offset, std::ios::beg); - - char cc = 0; - std::string strFname2 = ""; - do - { - inStream_w.read(reinterpret_cast(&cc), sizeof(cc)); - - if (!inStream_w) - return ERROR_INVALID_FILE; - - if (cc) strFname2 += cc; - } - while (cc != 0); - - iedCurr.functions[ordinal].funcname = strFname2; - - m_occupiedAddresses.emplace_back( - iedCurr.functions[ordinal].addrofname, - iedCurr.functions[ordinal].addrofname + strFname2.length() + 1 - ); - } - - std::swap(m_ied, iedCurr); - - return ERROR_NONE; - } } #endif diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 0e7261537..15bb24b8e 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -137,15 +137,18 @@ class ImageLoader std::uint32_t stringLength(std::uint32_t rva, std::uint32_t maxLength = 65535) const; std::uint32_t readPointer(std::uint32_t rva, std::uint64_t & pointerValue); - std::uint32_t pointerSize() const; + std::uint32_t getPointerSize() const; std::uint32_t dumpImage(const char * fileName); - std::uint32_t getPeFileBitability() const; + std::uint32_t getImageBitability() const; + std::uint64_t getOrdinalMask() const; std::uint32_t getNtSignature() const; + std::uint32_t getMachine() const; std::uint32_t getPointerToSymbolTable() const; std::uint32_t getNumberOfSymbols() const; std::uint64_t getImageBase() const; + std::uint32_t getAddressOfEntryPoint() const; std::uint32_t getSizeOfHeaders() const; std::uint32_t getSizeOfImage() const; std::uint32_t getSizeOfImageAligned() const; @@ -155,7 +158,7 @@ class ImageLoader std::uint32_t getImageProtection(std::uint32_t characteristics) const; int setLoaderError(LoaderError ldrErr); - LoaderError loaderError(); + LoaderError loaderError() const; // Testing function void compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & ImageCompare, void * imageData, std::uint32_t imageSize); diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index ab53b0d21..e5490ce07 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -526,13 +526,13 @@ namespace PeLib inline int ImportDirectory::read(ImageLoader & imageLoader) { - std::uint64_t OrdinalMask = ((std::uint64_t)1 << (imageLoader.getPeFileBitability() - 1)); + std::uint64_t OrdinalMask = imageLoader.getOrdinalMask(); std::uint32_t SizeOfImage = imageLoader.getSizeOfImage(); std::uint32_t uiIndex; std::uint32_t rvaBegin = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT); std::uint32_t rva = rvaBegin; - m_thunkSize = imageLoader.getPeFileBitability() / 8; + m_thunkSize = imageLoader.getPointerSize(); m_ldrError = LDR_ERROR_NONE; // Verify whether the import directory is within the image diff --git a/include/retdec/pelib/PeFile.h b/include/retdec/pelib/PeFile.h index 3107fcada..1a58d15cd 100644 --- a/include/retdec/pelib/PeFile.h +++ b/include/retdec/pelib/PeFile.h @@ -73,6 +73,7 @@ namespace PeLib protected: std::string m_filename; ///< Name of the current file. MzHeader m_mzh; ///< MZ header of the current file. + ImageLoader m_imageLoader; RichHeader m_richheader; ///< Rich header of the current file. CoffSymbolTable m_coffsymtab; ///< Symbol table of the current file. SecurityDirectory m_secdir; ///< Security directory of the current file. @@ -128,6 +129,11 @@ namespace PeLib /// Accessor function for the MZ header. MzHeader& mzHeader(); // EXPORT + /// Accessor function for the image loader + const ImageLoader & imageLoader() const; + /// Accessor function for the MZ header. + ImageLoader & imageLoader(); // EXPORT + /// Accessor function for the Rich header. const RichHeader& richHeader() const; /// Accessor function for the Rich header. @@ -156,17 +162,16 @@ namespace PeLib std::ifstream m_ifStream; std::istream& m_iStream; - ImageLoader m_imageLoader; PeHeader32_64 m_peh; ///< PE header of the current file. - ExportDirectoryT m_expdir; ///< Export directory of the current file. + ExportDirectory m_expdir; ///< Export directory of the current file. ImportDirectory m_impdir; ///< Import directory of the current file. - BoundImportDirectoryT m_boundimpdir; ///< BoundImportDirectory of the current file. + BoundImportDirectory m_boundimpdir; ///< BoundImportDirectory of the current file. ResourceDirectoryT m_resdir; ///< ResourceDirectory of the current file. RelocationsDirectoryT m_relocs; ///< Relocations directory of the current file. ComHeaderDirectoryT m_comdesc; ///< COM+ descriptor directory of the current file. IatDirectory m_iat; ///< Import address table of the current file. - DebugDirectoryT m_debugdir; ///< Debug directory of the current file. - DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file. + DebugDirectory m_debugdir; ///< Debug directory of the current file. + DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file. TlsDirectory m_tlsdir; ///< TLS directory of the current file. public: @@ -235,9 +240,9 @@ namespace PeLib PeHeader32_64& peHeader(); /// Accessor function for the export directory. - const ExportDirectoryT& expDir() const; + const ExportDirectory & expDir() const; /// Accessor function for the export directory. - ExportDirectoryT& expDir(); // EXPORT + ExportDirectory & expDir(); // EXPORT /// Accessor function for the import directory. const ImportDirectory & impDir() const; @@ -245,9 +250,9 @@ namespace PeLib ImportDirectory & impDir(); /// Accessor function for the bound import directory. - const BoundImportDirectoryT& boundImpDir() const; + const BoundImportDirectory & boundImpDir() const; /// Accessor function for the bound import directory. - BoundImportDirectoryT& boundImpDir(); // EXPORT + BoundImportDirectory & boundImpDir(); // EXPORT /// Accessor function for the resource directory. const ResourceDirectoryT& resDir() const; @@ -270,14 +275,14 @@ namespace PeLib IatDirectory & iatDir(); // EXPORT /// Accessor function for the debug directory. - const DebugDirectoryT& debugDir() const; + const DebugDirectory & debugDir() const; /// Accessor function for the debug directory. - DebugDirectoryT& debugDir(); // EXPORT + DebugDirectory & debugDir(); // EXPORT /// Accessor function for the delay import directory. - const DelayImportDirectory& delayImports() const; + const DelayImportDirectory & delayImports() const; /// Accessor function for the delay import directory. - DelayImportDirectory& delayImports(); // EXPORT + DelayImportDirectory & delayImports(); // EXPORT /// Accessor function for the TLS directory. const TlsDirectory& tlsDir() const; @@ -323,7 +328,7 @@ namespace PeLib **/ template PeFileT::PeFileT(const std::string& strFilename) : - m_iStream(m_ifStream), m_imageLoader(0) + m_iStream(m_ifStream) { m_filename = strFilename; m_ifStream.open(m_filename, std::ifstream::binary); @@ -335,13 +340,13 @@ namespace PeLib template PeFileT::PeFileT(std::istream& stream) : - m_iStream(stream), m_imageLoader(0) + m_iStream(stream) { } template PeFileT::PeFileT() : - m_iStream(m_ifStream), m_imageLoader(0) + m_iStream(m_ifStream) { } @@ -403,7 +408,7 @@ namespace PeLib * @return A reference to the file's delay import directory. **/ template - const DelayImportDirectory& PeFileT::delayImports() const + const DelayImportDirectory & PeFileT::delayImports() const { return m_delayimpdir; } @@ -412,7 +417,7 @@ namespace PeLib * @return A reference to the file's delay import directory. **/ template - DelayImportDirectory& PeFileT::delayImports() + DelayImportDirectory & PeFileT::delayImports() { return m_delayimpdir; } @@ -421,7 +426,7 @@ namespace PeLib * @return A reference to the file's export directory. **/ template - const ExportDirectoryT& PeFileT::expDir() const + const ExportDirectory & PeFileT::expDir() const { return m_expdir; } @@ -430,7 +435,7 @@ namespace PeLib * @return A reference to the file's export directory. **/ template - ExportDirectoryT& PeFileT::expDir() + ExportDirectory & PeFileT::expDir() { return m_expdir; } @@ -439,7 +444,7 @@ namespace PeLib * @return A reference to the file's bound import directory. **/ template - const BoundImportDirectoryT& PeFileT::boundImpDir() const + const BoundImportDirectory & PeFileT::boundImpDir() const { return m_boundimpdir; } @@ -448,7 +453,7 @@ namespace PeLib * @return A reference to the file's bound import directory. **/ template - BoundImportDirectoryT& PeFileT::boundImpDir() + BoundImportDirectory & PeFileT::boundImpDir() { return m_boundimpdir; } @@ -520,13 +525,13 @@ namespace PeLib } template - const DebugDirectoryT& PeFileT::debugDir() const + const DebugDirectory & PeFileT::debugDir() const { return m_debugdir; } template - DebugDirectoryT& PeFileT::debugDir() + DebugDirectory & PeFileT::debugDir() { return m_debugdir; } @@ -591,10 +596,9 @@ namespace PeLib template int PeFileT::readExportDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 1 - && peHeader().getIddExportRva()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT)) { - return expDir().read(m_iStream, peHeader()); + return expDir().read(m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } @@ -649,10 +653,9 @@ namespace PeLib template int PeFileT::readDebugDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 7 - && peHeader().getIddDebugRva() && peHeader().getIddDebugSize()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG)) { - return debugDir().read(m_iStream, peHeader()); + return debugDir().read(m_iStream, m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } @@ -671,10 +674,9 @@ namespace PeLib template int PeFileT::readBoundImportDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 12 - && peHeader().getIddBoundImportRva() && peHeader().getIddBoundImportSize()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)) { - return boundImpDir().read(m_iStream, peHeader()); + return boundImpDir().read(m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } @@ -693,9 +695,9 @@ namespace PeLib int PeFileT::readDelayImportDirectory() { // Note: Delay imports can have arbitrary size and Windows loader will still load them - if (peHeader().calcNumberOfRvaAndSizes() >= 14 && peHeader().getIddDelayImportRva() /* && peHeader().getIddDelayImportSize() */) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)) { - return delayImports().read(m_iStream, peHeader()); + return delayImports().read(m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } @@ -714,27 +716,25 @@ namespace PeLib template LoaderError PeFileT::checkEntryPointErrors() const { - unsigned int uiEntryPointRva = peHeader().getAddressOfEntryPoint(); - std::uint64_t uiOffset = peHeader().rvaToOffset(uiEntryPointRva); - // Initialize to anything not zero, because later we check if zero. - std::uint64_t entryPointCode[2] = {1, 1}; + ImageLoader & imgLoader = const_cast(m_imageLoader); + std::uint32_t addressOfEntryPoint = m_imageLoader.getAddressOfEntryPoint(); + std::uint32_t sizeOfImage = m_imageLoader.getSizeOfImage(); - // No point of reading entry point that is beyond the file size - std::uint64_t ulFileSize = fileSize(m_iStream); - if (uiOffset > ulFileSize) + if(addressOfEntryPoint >= sizeOfImage) { return LDR_ERROR_ENTRY_POINT_OUT_OF_IMAGE; } // Only check PE files compiled for i386 or x64 processors. - if (peHeader().getMachine() == PELIB_IMAGE_FILE_MACHINE_I386 || peHeader().getMachine() == PELIB_IMAGE_FILE_MACHINE_AMD64) + if (m_imageLoader.getMachine() == PELIB_IMAGE_FILE_MACHINE_I386 || m_imageLoader.getMachine() == PELIB_IMAGE_FILE_MACHINE_AMD64) { + std::uint64_t entryPointCode[2] = {0, 0}; + // Check if 16 bytes of code are available in the file - if ((uiOffset + sizeof(entryPointCode)) < ulFileSize) + if ((addressOfEntryPoint + sizeof(entryPointCode)) < sizeOfImage) { // Read the entry point code - m_iStream.seekg(uiOffset, std::ios::beg); - m_iStream.read((char *)entryPointCode, sizeof(entryPointCode)); + imgLoader.readImage(entryPointCode, addressOfEntryPoint, sizeof(entryPointCode)); // Zeroed instructions at entry point map either to "add [eax], al" (i386) or "add [rax], al" (AMD64). // Neither of these instructions makes sense on the entry point. We check 16 bytes of the entry point, @@ -791,12 +791,8 @@ namespace PeLib template LoaderError PeFileT::loaderError() const { - // Check for problems in DOS header - LoaderError ldrError = mzHeader().loaderError(); - - // Was there a problem in the NT headers? - if (ldrError == LDR_ERROR_NONE) - ldrError = peHeader().loaderError(); + // Check for problems in image loader + LoaderError ldrError = imageLoader().loaderError(); // Check the loader error if (ldrError == LDR_ERROR_NONE) diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index ec03676ca..628c511ff 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -1082,10 +1082,9 @@ namespace PeLib } }; - template struct PELIB_DELAY_IMPORT { - PELIB_VAR_SIZE address; + std::uint64_t address; std::uint16_t hint; std::string fname; @@ -1289,28 +1288,32 @@ namespace PeLib } }; - const unsigned int PELIB_IMAGE_SIZEOF_DELAY_IMPORT_DIRECTORY_RECORD = 32; + // This structure is defined in the "delayimp.h" header file as ImgDelayDescrV1 or ImgDelayDescrV2. + // Fields suffixed with "Rva" are direct virtual addresses in the "V1" version of the structure. + struct PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR + { + std::uint32_t Attributes; // Attributes. See PELIB_DELAY_ATTRIBUTE_XXX for more info + std::uint32_t NameRva; // RVA to dll name + std::uint32_t ModuleHandleRva; // RVA of module handle + std::uint32_t DelayImportAddressTableRva; // RVA of the IAT + std::uint32_t DelayImportNameTableRva; // RVA of the INT + std::uint32_t BoundDelayImportTableRva; // RVA of the optional bound IAT + std::uint32_t UnloadDelayImportTableRva; // RVA of optional copy of original IAT + std::uint32_t TimeStamp; // 0 if not bound, O.W. date/time stamp of DLL bound to (Old BIND) + }; + + const std::uint32_t PELIB_DELAY_ATTRIBUTE_V2 = 0x01; // If this bit is set, then the structure is version 2 - template struct PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD { private: - typedef typename std::vector>::const_iterator DelayImportIterator; + typedef typename std::vector::const_iterator DelayImportIterator; bool hasOrdinalNumbers; - std::vector> Functions; + std::vector Functions; public: - std::uint32_t Attributes; - std::uint32_t NameRva; + PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR delayedImport; std::string Name; - std::uint32_t ModuleHandleRva; - std::uint32_t DelayImportAddressTableRva; - std::uint32_t DelayImportNameTableRva; - std::uint32_t BoundDelayImportTableRva; - std::uint32_t UnloadDelayImportTableRva; - std::uint32_t TimeStamp; - std::uint32_t DelayImportAddressTableOffset; - std::uint32_t DelayImportNameTableOffset; PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD() { @@ -1324,22 +1327,13 @@ namespace PeLib void init() { + memset(&delayedImport, 0, sizeof(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR)); hasOrdinalNumbers = false; Functions.clear(); - Attributes = 0; - NameRva = 0; Name.clear(); - ModuleHandleRva = 0; - DelayImportAddressTableRva = 0; - DelayImportNameTableRva = 0; - BoundDelayImportTableRva = 0; - UnloadDelayImportTableRva = 0; - TimeStamp = 0; - DelayImportAddressTableOffset = 0; - DelayImportNameTableOffset = 0; } - void addFunction(const PELIB_DELAY_IMPORT &function) + void addFunction(const PELIB_DELAY_IMPORT &function) { Functions.push_back(function); if(function.hint) @@ -1358,12 +1352,12 @@ namespace PeLib return Functions.size(); } - const PELIB_DELAY_IMPORT *getFunction(std::size_t index) const + const PELIB_DELAY_IMPORT *getFunction(std::size_t index) const { return index < getNumberOfFunctions() ? &Functions[index] : nullptr; } - PELIB_DELAY_IMPORT *getFunction(std::size_t index) + PELIB_DELAY_IMPORT *getFunction(std::size_t index) { return index < getNumberOfFunctions() ? &Functions[index] : nullptr; } diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index 02ddcae96..a3766fb08 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -610,7 +610,7 @@ void PeFormat::initStructures(const std::string & dllListFile) // Fill-in the loader error info from PE file initLoaderErrorInfo(); - mzHeader = file->mzHeader(); + //mzHeader = file->mzHeader(); if (auto *f32 = isPe32()) { diff --git a/src/pelib/BoundImportDirectory.cpp b/src/pelib/BoundImportDirectory.cpp index 59b8c46fe..e71d26aab 100644 --- a/src/pelib/BoundImportDirectory.cpp +++ b/src/pelib/BoundImportDirectory.cpp @@ -156,6 +156,29 @@ namespace PeLib return read(inpBuffer, vBimpDir.data(), uiSize); } + /** + * Reads the BoundImport directory from a PE file. + * @param inStream Input stream. + * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. + **/ + int BoundImportDirectory::read(ImageLoader & imageLoader) + { + std::uint32_t importRva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT); + std::uint32_t importSize = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT); + std::uint32_t sizeOfImage = imageLoader.getSizeOfImage(); + + if(importRva > sizeOfImage || (importRva > importSize) > sizeOfImage) + { + return ERROR_INVALID_FILE; + } + + std::vector vBimpDir(importSize); + imageLoader.readImage(reinterpret_cast(vBimpDir.data()), importRva, importSize); + + InputBuffer inpBuffer{vBimpDir}; + return BoundImportDirectory::read(inpBuffer, vBimpDir.data(), importSize); + } + unsigned int BoundImportDirectory::totalModules() const { unsigned int modules = static_cast(m_vIbd.size()); diff --git a/src/pelib/DebugDirectory.cpp b/src/pelib/DebugDirectory.cpp index aeb0a024a..8066bf9b8 100644 --- a/src/pelib/DebugDirectory.cpp +++ b/src/pelib/DebugDirectory.cpp @@ -15,58 +15,82 @@ namespace PeLib { - void DebugDirectory::clear() - { - m_vDebugInfo.clear(); - } + /** + * @param inStream Input stream. + * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. + **/ - std::vector DebugDirectory::read(InputBuffer& ibBuffer, unsigned int uiRva, unsigned int uiSize) + int DebugDirectory::read(std::istream& inStream, ImageLoader & imageLoader) { - std::vector currDebugInfo; - - PELIB_IMG_DEBUG_DIRECTORY iddCurr; - - unsigned int uiEntryCount = uiSize / PELIB_IMAGE_DEBUG_DIRECTORY::size(); - for (unsigned int i = 0; i < uiEntryCount; i++) + std::vector debugInfo; + std::uint64_t ulFileSize = fileSize(inStream); + std::size_t rva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG); + std::size_t size = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG); + std::size_t sizeOfImage = imageLoader.getSizeOfImage(); + if ((rva + size) > sizeOfImage) { - - ibBuffer >> iddCurr.idd.Characteristics; - ibBuffer >> iddCurr.idd.TimeDateStamp; - ibBuffer >> iddCurr.idd.MajorVersion; - ibBuffer >> iddCurr.idd.MinorVersion; - ibBuffer >> iddCurr.idd.Type; - ibBuffer >> iddCurr.idd.SizeOfData; - ibBuffer >> iddCurr.idd.AddressOfRawData; - ibBuffer >> iddCurr.idd.PointerToRawData; - - currDebugInfo.push_back(iddCurr); + return ERROR_INVALID_FILE; } - if (!currDebugInfo.empty()) + // Read the array of debug directories + read(imageLoader, debugInfo, rva, size); + + // For each debug directory, also read its data + for(auto & debugEntry : debugInfo) { - m_occupiedAddresses.emplace_back( - uiRva, - uiRva + uiEntryCount * PELIB_IMAGE_DEBUG_DIRECTORY::size() - 1 - ); + if ((debugEntry.idd.PointerToRawData >= ulFileSize) || + (debugEntry.idd.PointerToRawData + debugEntry.idd.SizeOfData >= ulFileSize)) + { + return ERROR_INVALID_FILE; + } + + // Load the debug info data from the file, not from the image. + // Some samples may have debug info part of the overlay + debugEntry.data.resize(debugEntry.idd.SizeOfData); + inStream.seekg(debugEntry.idd.PointerToRawData); + inStream.read(reinterpret_cast(debugEntry.data.data()), debugEntry.idd.SizeOfData); + + // Verify the number of bytes read + if(inStream.gcount() != debugEntry.idd.SizeOfData) + return ERROR_INVALID_FILE; + + if (debugEntry.idd.SizeOfData > 0) + { + m_occupiedAddresses.push_back( + std::make_pair( + debugEntry.idd.AddressOfRawData, + debugEntry.idd.AddressOfRawData + debugEntry.idd.SizeOfData - 1 + )); + } } - return currDebugInfo; + std::swap(debugInfo, m_vDebugInfo); + return ERROR_NONE; } - int DebugDirectory::read(unsigned char* buffer, unsigned int buffersize) + void DebugDirectory::read(ImageLoader & imageLoader, std::vector & debugInfo, std::uint32_t rva, std::uint32_t size) { - // XXX: Note, debug data is not read at all. This might or might not change - // in the future. - - std::vector vDebugDirectory(buffer, buffer + buffersize); - - InputBuffer ibBuffer(vDebugDirectory); + PELIB_IMG_DEBUG_DIRECTORY iddCurr; + std::size_t entryCount = size / PELIB_IMAGE_DEBUG_DIRECTORY::size(); + std::uint32_t bytesRead; - std::vector currDebugInfo = read(ibBuffer, 0, buffersize); + for (std::size_t i = 0; i < entryCount; i++) + { + bytesRead = imageLoader.readImage(&iddCurr.idd, rva, sizeof(PELIB_IMAGE_DEBUG_DIRECTORY)); + if(bytesRead != sizeof(PELIB_IMAGE_DEBUG_DIRECTORY)) + break; - std::swap(currDebugInfo, m_vDebugInfo); + debugInfo.push_back(iddCurr); + rva += sizeof(PELIB_IMAGE_DEBUG_DIRECTORY); + } - return ERROR_NONE; + if (!debugInfo.empty()) + { + m_occupiedAddresses.emplace_back( + rva, + rva + entryCount * PELIB_IMAGE_DEBUG_DIRECTORY::size() - 1 + ); + } } /** diff --git a/src/pelib/ExportDirectory.cpp b/src/pelib/ExportDirectory.cpp index 896564182..3aedbfe05 100644 --- a/src/pelib/ExportDirectory.cpp +++ b/src/pelib/ExportDirectory.cpp @@ -15,6 +15,113 @@ namespace PeLib { + /** + * @param str Value of the ASCIIZ string. + * @param rva RVA of the begin of the string + **/ + void ExportDirectory::addOccupiedAddress(const std::string & str, std::uint32_t rva) + { + std::uint32_t rvaEnd = rva + str.length() + 1; + + m_occupiedAddresses.push_back(std::make_pair(rva, rvaEnd)); + } + + /** + * @param imageLoader Initialized image loader + * \todo: Proper use of InputBuffer + **/ + int ExportDirectory::read(ImageLoader & imageLoader) + { + PELIB_IMAGE_EXP_DIRECTORY iedCurr; + std::uint32_t exportRva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT); + std::uint32_t sizeofImage = imageLoader.getSizeOfImage(); + std::uint32_t bytesRead; + + if(exportRva >= sizeofImage) + { + return ERROR_INVALID_FILE; + } + + // Load the export directory from the image + bytesRead = imageLoader.readImage(&iedCurr.ied, exportRva, sizeof(PELIB_IMAGE_EXPORT_DIRECTORY)); + if(bytesRead != sizeof(PELIB_IMAGE_EXPORT_DIRECTORY)) + { + return ERROR_INVALID_FILE; + } + + m_occupiedAddresses.emplace_back(exportRva, exportRva + sizeof(PELIB_IMAGE_EXPORT_DIRECTORY) - 1); + + // Verify the export directory. Do not allow more functions than the limit + // Sample: CCE461B6EB23728BA3B8A97B9BE84C0FB9175DB31B9949E64144198AB3F702CE + if (iedCurr.ied.NumberOfFunctions > PELIB_MAX_EXPORTED_FUNCTIONS || iedCurr.ied.NumberOfNames > PELIB_MAX_EXPORTED_FUNCTIONS) + return ERROR_INVALID_FILE; + + // Read the name of the export + imageLoader.readString(iedCurr.name, iedCurr.ied.Name); + addOccupiedAddress(iedCurr.name, iedCurr.ied.Name); + + // Read the array of functions + for (std::uint32_t i = 0; i < iedCurr.ied.NumberOfFunctions; i++) + { + PELIB_EXP_FUNC_INFORMATION efiCurr; + std::uint32_t rva = iedCurr.ied.AddressOfFunctions + i * sizeof(efiCurr.addroffunc); + + bytesRead = imageLoader.readImage(&efiCurr.addroffunc, rva, sizeof(efiCurr.addroffunc)); + if(bytesRead != sizeof(efiCurr.addroffunc)) + return ERROR_INVALID_FILE; + + efiCurr.ordinal = iedCurr.ied.Base + i; + iedCurr.functions.push_back(efiCurr); + + m_occupiedAddresses.emplace_back( + iedCurr.ied.AddressOfFunctions + i*sizeof(efiCurr.addroffunc), + iedCurr.ied.AddressOfFunctions + i*sizeof(efiCurr.addroffunc) + sizeof(efiCurr.addroffunc) - 1 + ); + } + + for (std::uint32_t i = 0; i < iedCurr.ied.NumberOfNames; i++) + { + PELIB_EXP_FUNC_INFORMATION efiCurr; + std::uint16_t ordinal; + std::uint32_t rva = iedCurr.ied.AddressOfNameOrdinals + i * sizeof(efiCurr.ordinal); + + // Read the ordinal + bytesRead = imageLoader.readImage(&ordinal, rva, sizeof(ordinal)); + if(bytesRead != sizeof(ordinal)) + return ERROR_INVALID_FILE; + + m_occupiedAddresses.emplace_back( + iedCurr.ied.AddressOfNameOrdinals + i*sizeof(efiCurr.ordinal), + iedCurr.ied.AddressOfNameOrdinals + i*sizeof(efiCurr.ordinal) + sizeof(efiCurr.ordinal) - 1 + ); + + if (ordinal >= iedCurr.functions.size()) + continue; + + iedCurr.functions[ordinal].ordinal = iedCurr.ied.Base + ordinal; + + rva = iedCurr.ied.AddressOfNames + i * sizeof(efiCurr.addrofname); + if(rva >= sizeofImage) + return ERROR_INVALID_FILE; + + bytesRead = imageLoader.readImage(&iedCurr.functions[ordinal].addrofname, rva, sizeof(std::uint32_t)); + if(bytesRead != sizeof(std::uint32_t)) + return ERROR_INVALID_FILE; + + m_occupiedAddresses.emplace_back( + iedCurr.ied.AddressOfNames + i*sizeof(efiCurr.addrofname), + iedCurr.ied.AddressOfNames + i*sizeof(efiCurr.addrofname) + sizeof(iedCurr.functions[ordinal].addrofname) - 1 + ); + + // Read the function name + imageLoader.readString(iedCurr.functions[ordinal].funcname, iedCurr.functions[ordinal].addrofname); + addOccupiedAddress(iedCurr.functions[ordinal].funcname, iedCurr.functions[ordinal].addrofname); + } + + std::swap(m_ied, iedCurr); + return ERROR_NONE; + } + /** * @param strFuncname Name of the function. * @param dwFuncAddr RVA of the function. diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 9e0e7c51b..ea791e234 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -184,7 +184,7 @@ uint32_t PeLib::ImageLoader::stringLength(uint32_t rva, uint32_t maxLength) cons { if(page.buffer[rva & (PELIB_PAGE_SIZE - 1)] == 0) { - return rva; + return (rva - rvaBegin); } } @@ -204,7 +204,7 @@ uint32_t PeLib::ImageLoader::readString(std::string & str, uint32_t rva, uint32_ uint32_t length = stringLength(rva, maxLength); // Allocate needeed size in the string - str.resize(length + 1); + str.resize(length); // Read the string from the image readImage((void *)str.data(), rva, length); @@ -215,7 +215,7 @@ uint32_t PeLib::ImageLoader::readPointer(uint32_t rva, uint64_t & pointerValue) { uint32_t bytesRead = 0; - switch(getPeFileBitability()) + switch(getImageBitability()) { case 64: if(readImage(&pointerValue, rva, sizeof(uint64_t)) == sizeof(uint64_t)) @@ -240,9 +240,9 @@ uint32_t PeLib::ImageLoader::readPointer(uint32_t rva, uint64_t & pointerValue) return 0; } -uint32_t PeLib::ImageLoader::pointerSize() const +uint32_t PeLib::ImageLoader::getPointerSize() const { - return getPeFileBitability() / 8; + return getImageBitability() / 8; } uint32_t PeLib::ImageLoader::dumpImage(const char * fileName) @@ -269,7 +269,7 @@ uint32_t PeLib::ImageLoader::dumpImage(const char * fileName) return bytesWritten; } -uint32_t PeLib::ImageLoader::getPeFileBitability() const +uint32_t PeLib::ImageLoader::getImageBitability() const { if(fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_AMD64 || fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_IA64) return 64; @@ -280,11 +280,21 @@ uint32_t PeLib::ImageLoader::getPeFileBitability() const return 0; } +std::uint64_t PeLib::ImageLoader::getOrdinalMask() const +{ + return (std::uint64_t)1 << (getImageBitability() - 1); +} + uint32_t PeLib::ImageLoader::getNtSignature() const { return ntSignature; } +uint32_t PeLib::ImageLoader::getMachine() const +{ + return fileHeader.Machine; +} + uint32_t PeLib::ImageLoader::getPointerToSymbolTable() const { return fileHeader.PointerToSymbolTable; @@ -300,6 +310,11 @@ uint64_t PeLib::ImageLoader::getImageBase() const return optionalHeader.ImageBase; } +std::uint32_t PeLib::ImageLoader::getAddressOfEntryPoint() const +{ + return optionalHeader.AddressOfEntryPoint; +} + uint32_t PeLib::ImageLoader::getSizeOfHeaders() const { return optionalHeader.SizeOfHeaders; @@ -390,7 +405,7 @@ int PeLib::ImageLoader::setLoaderError(PeLib::LoaderError ldrErr) return ERROR_NONE; } -PeLib::LoaderError PeLib::ImageLoader::loaderError() +PeLib::LoaderError PeLib::ImageLoader::loaderError() const { return ldrError; } @@ -485,8 +500,7 @@ int PeLib::ImageLoader::Load(std::istream & fs, std::streamoff fileOffset, bool // Read the entire file to memory. Note that under Windows // and under low memory condition, the underlying OS call (NtReadFile) // can fail on low memory. When that happens, fs.read will read less than - // required. We need to verify the number of bytes read - // and set the low memory condition flag + // required. We need to verify the number of bytes read and return the apropriate error code. fs.seekg(fileOffset); fs.read(reinterpret_cast(fileData.data()), fileSize2); if(fs.gcount() < (fileSize - fileOffset)) diff --git a/src/pelib/PeFile.cpp b/src/pelib/PeFile.cpp index 0c3c97454..33b17582f 100644 --- a/src/pelib/PeFile.cpp +++ b/src/pelib/PeFile.cpp @@ -60,6 +60,24 @@ namespace PeLib return m_mzh; } + /** + * @return A reference to the file's image loader. + **/ + + const ImageLoader & PeFile::imageLoader() const + { + return m_imageLoader; + } + + /** + * @return A reference to the file's image loader. + **/ + + ImageLoader & PeFile::imageLoader() + { + return m_imageLoader; + } + const RichHeader& PeFile::richHeader() const { return m_richheader; From e361360dc992842d0f740f836c8a182a9a097465 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Fri, 19 Jun 2020 10:02:26 +0200 Subject: [PATCH 05/34] ImageLoader: TLS Directory --- .../fileformat/file_format/pe/pe_template.h | 12 +- include/retdec/pelib/PeFile.h | 21 +- include/retdec/pelib/PeLibAux.h | 40 ++-- include/retdec/pelib/TlsDirectory.h | 206 +++++++++--------- 4 files changed, 130 insertions(+), 149 deletions(-) diff --git a/include/retdec/fileformat/file_format/pe/pe_template.h b/include/retdec/fileformat/file_format/pe/pe_template.h index 70269a0a6..68c0482db 100644 --- a/include/retdec/fileformat/file_format/pe/pe_template.h +++ b/include/retdec/fileformat/file_format/pe/pe_template.h @@ -734,7 +734,7 @@ template const PeLib::ResourceNode* peResourceTreeRoot(const PeLib::Re * @param tls Parser of TLS directory * @return StartAddressOfRawData of TLS directory */ -template unsigned long long peTlsStartAddressOfRawData(const PeLib::TlsDirectory &tls) +inline unsigned long long peTlsStartAddressOfRawData(const PeLib::TlsDirectory &tls) { return tls.getStartAddressOfRawData(); } @@ -744,7 +744,7 @@ template unsigned long long peTlsStartAddressOfRawData(const PeLib::Tl * @param tls Parser of TLS directory * @return EndAddressOfRawData of TLS directory */ -template unsigned long long peTlsEndAddressOfRawData(const PeLib::TlsDirectory &tls) +inline unsigned long long peTlsEndAddressOfRawData(const PeLib::TlsDirectory &tls) { return tls.getEndAddressOfRawData(); } @@ -754,7 +754,7 @@ template unsigned long long peTlsEndAddressOfRawData(const PeLib::TlsD * @param tls Parser of TLS directory * @return AddressOfIndex of TLS directory */ -template unsigned long long peTlsAddressOfIndex(const PeLib::TlsDirectory &tls) +inline unsigned long long peTlsAddressOfIndex(const PeLib::TlsDirectory &tls) { return tls.getAddressOfIndex(); } @@ -764,7 +764,7 @@ template unsigned long long peTlsAddressOfIndex(const PeLib::TlsDirect * @param tls Parser of TLS directory * @return AddressOfCallBacks of TLS directory */ -template unsigned long long peTlsAddressOfCallBacks(const PeLib::TlsDirectory &tls) +inline unsigned long long peTlsAddressOfCallBacks(const PeLib::TlsDirectory &tls) { return tls.getAddressOfCallBacks(); } @@ -774,7 +774,7 @@ template unsigned long long peTlsAddressOfCallBacks(const PeLib::TlsDi * @param tls Parser of TLS directory * @return SizeOfZeroFill of TLS directory */ -template unsigned long long peTlsSizeOfZeroFill(const PeLib::TlsDirectory &tls) +inline unsigned long long peTlsSizeOfZeroFill(const PeLib::TlsDirectory &tls) { return tls.getSizeOfZeroFill(); } @@ -784,7 +784,7 @@ template unsigned long long peTlsSizeOfZeroFill(const PeLib::TlsDirect * @param tls Parser of TLS directory * @return Characteristics of TLS directory */ -template unsigned long long peTlsCharacteristics(const PeLib::TlsDirectory &tls) +inline unsigned long long peTlsCharacteristics(const PeLib::TlsDirectory &tls) { return tls.getCharacteristics(); } diff --git a/include/retdec/pelib/PeFile.h b/include/retdec/pelib/PeFile.h index 1a58d15cd..238b2273e 100644 --- a/include/retdec/pelib/PeFile.h +++ b/include/retdec/pelib/PeFile.h @@ -163,16 +163,16 @@ namespace PeLib std::istream& m_iStream; PeHeader32_64 m_peh; ///< PE header of the current file. - ExportDirectory m_expdir; ///< Export directory of the current file. + ExportDirectory m_expdir; ///< Export directory of the current file. ImportDirectory m_impdir; ///< Import directory of the current file. BoundImportDirectory m_boundimpdir; ///< BoundImportDirectory of the current file. ResourceDirectoryT m_resdir; ///< ResourceDirectory of the current file. RelocationsDirectoryT m_relocs; ///< Relocations directory of the current file. ComHeaderDirectoryT m_comdesc; ///< COM+ descriptor directory of the current file. IatDirectory m_iat; ///< Import address table of the current file. - DebugDirectory m_debugdir; ///< Debug directory of the current file. - DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file. - TlsDirectory m_tlsdir; ///< TLS directory of the current file. + DebugDirectory m_debugdir; ///< Debug directory of the current file. + DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file. + TlsDirectory m_tlsdir; ///< TLS directory of the current file. public: /// Default constructor which exists only for the sake of allowing to construct files without filenames. @@ -285,9 +285,9 @@ namespace PeLib DelayImportDirectory & delayImports(); // EXPORT /// Accessor function for the TLS directory. - const TlsDirectory& tlsDir() const; + const TlsDirectory & tlsDir() const; /// Accessor function for the TLS directory. - TlsDirectory& tlsDir(); + TlsDirectory & tlsDir(); }; /** @@ -393,13 +393,13 @@ namespace PeLib } template - const TlsDirectory& PeFileT::tlsDir() const + const TlsDirectory & PeFileT::tlsDir() const { return m_tlsdir; } template - TlsDirectory& PeFileT::tlsDir() + TlsDirectory & PeFileT::tlsDir() { return m_tlsdir; } @@ -663,10 +663,9 @@ namespace PeLib template int PeFileT::readTlsDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 10 - && peHeader().getIddTlsRva() && peHeader().getIddTlsSize()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_TLS)) { - return tlsDir().read(m_iStream, peHeader()); + return tlsDir().read(m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index 628c511ff..d8dfb1dcd 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -1171,17 +1171,26 @@ namespace PeLib std::vector data; }; - template - struct PELIB_IMAGE_TLS_DIRECTORY_BASE + struct PELIB_IMAGE_TLS_DIRECTORY32 + { + std::uint32_t StartAddressOfRawData; + std::uint32_t EndAddressOfRawData; + std::uint32_t AddressOfIndex; + std::uint32_t AddressOfCallBacks; + std::uint32_t SizeOfZeroFill; + std::uint32_t Characteristics; + }; + + struct PELIB_IMAGE_TLS_DIRECTORY { - typename FieldSizes::VAR4_8 StartAddressOfRawData; - typename FieldSizes::VAR4_8 EndAddressOfRawData; - typename FieldSizes::VAR4_8 AddressOfIndex; - typename FieldSizes::VAR4_8 AddressOfCallBacks; + std::uint64_t StartAddressOfRawData; + std::uint64_t EndAddressOfRawData; + std::uint64_t AddressOfIndex; + std::uint64_t AddressOfCallBacks; std::uint32_t SizeOfZeroFill; std::uint32_t Characteristics; - PELIB_IMAGE_TLS_DIRECTORY_BASE() + PELIB_IMAGE_TLS_DIRECTORY() { StartAddressOfRawData = 0; EndAddressOfRawData = 0; @@ -1192,23 +1201,6 @@ namespace PeLib } }; - template - struct PELIB_IMAGE_TLS_DIRECTORY;// : public PELIB_IMAGE_TLS_DIRECTORY_BASE - - template<> - struct PELIB_IMAGE_TLS_DIRECTORY<32> : public PELIB_IMAGE_TLS_DIRECTORY_BASE<32> - { -// enum {size = 24}; - static unsigned int size(){return 24;} - }; - - template<> - struct PELIB_IMAGE_TLS_DIRECTORY<64> : public PELIB_IMAGE_TLS_DIRECTORY_BASE<64> - { -// enum {size = 40}; - static unsigned int size(){return 40;} - }; - std::uint32_t BytesToPages(std::uint32_t ByteSize); std::uint32_t AlignToSize(std::uint32_t ByteSize, std::uint32_t AlignSize); diff --git a/include/retdec/pelib/TlsDirectory.h b/include/retdec/pelib/TlsDirectory.h index 828a8fd15..6c9c27d5c 100644 --- a/include/retdec/pelib/TlsDirectory.h +++ b/include/retdec/pelib/TlsDirectory.h @@ -13,7 +13,7 @@ #ifndef TLSDIRECTORY_H #define TLSDIRECTORY_H -#include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { @@ -21,18 +21,15 @@ namespace PeLib /** * This class handles the TLS (Thread Local Storage) directory. **/ - template class TlsDirectory { private: - PELIB_IMAGE_TLS_DIRECTORY m_tls; ///< Structure that holds all information about the directory. - - void read(InputBuffer& inputbuffer); + PELIB_IMAGE_TLS_DIRECTORY m_tls; ///< Structure that holds all information about the directory. + std::size_t pointerSize; public: /// Reads a file's TLS directory. - int read(std::istream& inStream, const PeHeaderT &peHeader); // EXPORT - int read(unsigned char* buffer, unsigned int buffersize); // EXPORT + int read(ImageLoader & imageLoader); // EXPORT /// Rebuilds the TLS directory. void rebuild(std::vector& vBuffer) const; // EXPORT /// Returns the size of the TLS Directory. @@ -41,94 +38,76 @@ namespace PeLib int write(const std::string& strFilename, unsigned int dwOffset) const; // EXPORT /// Returns the StartAddressOfRawData value of the TLS header. - typename FieldSizes::VAR4_8 getStartAddressOfRawData() const; // EXPORT + std::uint64_t getStartAddressOfRawData() const; // EXPORT /// Returns the EndAddressOfRawData value of the TLS header. - typename FieldSizes::VAR4_8 getEndAddressOfRawData() const; // EXPORT + std::uint64_t getEndAddressOfRawData() const; // EXPORT /// Returns the AddressOfIndex value of the TLS header. - typename FieldSizes::VAR4_8 getAddressOfIndex() const; // EXPORT + std::uint64_t getAddressOfIndex() const; // EXPORT /// Returns the AddressOfCallBacks value of the TLS header. - typename FieldSizes::VAR4_8 getAddressOfCallBacks() const; // EXPORT + std::uint64_t getAddressOfCallBacks() const; // EXPORT /// Returns the SizeOfZeroFill value of the TLS header. std::uint32_t getSizeOfZeroFill() const; // EXPORT /// Returns the Characteristics value of the TLS header. std::uint32_t getCharacteristics() const; // EXPORT /// Sets the StartAddressOfRawData value of the TLS header. - void setStartAddressOfRawData(std::uint32_t dwValue); // EXPORT + void setStartAddressOfRawData(std::uint64_t value); // EXPORT /// Sets the EndAddressOfRawData value of the TLS header. - void setEndAddressOfRawData(std::uint32_t dwValue); // EXPORT + void setEndAddressOfRawData(std::uint64_t value); // EXPORT /// Sets the AddressOfIndex value of the TLS header. - void setAddressOfIndex(std::uint32_t dwValue); // EXPORT + void setAddressOfIndex(std::uint64_t value); // EXPORT /// Sets the AddressOfCallBacks value of the TLS header. - void setAddressOfCallBacks(std::uint32_t dwValue); // EXPORT + void setAddressOfCallBacks(std::uint64_t value); // EXPORT /// Sets the SizeOfZeroFill value of the TLS header. void setSizeOfZeroFill(std::uint32_t dwValue); // EXPORT /// Sets the Characteristics value of the TLS header. void setCharacteristics(std::uint32_t dwValue); // EXPORT }; - template - void TlsDirectory::read(InputBuffer& inputBuffer) - { - PELIB_IMAGE_TLS_DIRECTORY itdCurr; - - inputBuffer >> itdCurr.StartAddressOfRawData; - inputBuffer >> itdCurr.EndAddressOfRawData; - inputBuffer >> itdCurr.AddressOfIndex; - inputBuffer >> itdCurr.AddressOfCallBacks; - inputBuffer >> itdCurr.SizeOfZeroFill; - inputBuffer >> itdCurr.Characteristics; - - std::swap(itdCurr, m_tls); - } - - template - int TlsDirectory::read(unsigned char* buffer, unsigned int buffersize) - { - if (buffersize < PELIB_IMAGE_TLS_DIRECTORY::size()) - { - return ERROR_INVALID_FILE; - } - - std::vector vTlsDirectory(buffer, buffer + buffersize); - - InputBuffer ibBuffer(vTlsDirectory); - read(ibBuffer); - return ERROR_NONE; - } - /** * Reads a file's TLS directory. * @param inStream Input stream. * @param peHeader A valid PE header. **/ - template - int TlsDirectory::read(std::istream& inStream, const PeHeaderT &peHeader) + inline + int TlsDirectory::read(ImageLoader & imageLoader) { - IStreamWrapper inStream_w(inStream); + std::uint32_t rva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_TLS); + std::uint32_t size = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_TLS); + std::uint32_t sizeOfImage = imageLoader.getSizeOfImage(); + std::uint32_t bytesRead; + if((rva + size) >= sizeOfImage) + return ERROR_INVALID_FILE; - if (!inStream_w) + // Remember the pointer size + pointerSize = imageLoader.getPointerSize(); + + // Read the TLS directory from the image. Differentiate between 32-bit and 64-bit + if(imageLoader.getImageBitability() == 32) { - return ERROR_OPENING_FILE; + PELIB_IMAGE_TLS_DIRECTORY32 TlsDirectory32; + + // Read the 32-bit TLS directory structure + bytesRead = imageLoader.readImage(&TlsDirectory32, rva, sizeof(PELIB_IMAGE_TLS_DIRECTORY32)); + if(bytesRead != sizeof(PELIB_IMAGE_TLS_DIRECTORY32)) + return ERROR_INVALID_FILE; + + // Convert to 64-bit structure + m_tls.StartAddressOfRawData = TlsDirectory32.StartAddressOfRawData; + m_tls.EndAddressOfRawData = TlsDirectory32.EndAddressOfRawData; + m_tls.AddressOfIndex = TlsDirectory32.AddressOfIndex; + m_tls.AddressOfCallBacks = TlsDirectory32.AddressOfCallBacks; + m_tls.SizeOfZeroFill = TlsDirectory32.SizeOfZeroFill; + m_tls.Characteristics = TlsDirectory32.Characteristics; } - - std::uint64_t ulFileSize = fileSize(inStream_w); - - std::uint64_t uiOffset = peHeader.rvaToOffset(peHeader.getIddTlsRva()); - unsigned int uiSize = peHeader.getIddTlsSize(); - - if (ulFileSize < uiOffset + uiSize) + else { - return ERROR_INVALID_FILE; + // Read the 32-bit TLS directory structure + bytesRead = imageLoader.readImage(&m_tls, rva, sizeof(PELIB_IMAGE_TLS_DIRECTORY)); + if(bytesRead != sizeof(PELIB_IMAGE_TLS_DIRECTORY)) + return ERROR_INVALID_FILE; } - inStream_w.seekg(uiOffset, std::ios::beg); - - std::vector vTlsDirectory(uiSize); - inStream_w.read(reinterpret_cast(vTlsDirectory.data()), uiSize); - - InputBuffer ibBuffer{vTlsDirectory}; - read(ibBuffer); return ERROR_NONE; } @@ -136,17 +115,28 @@ namespace PeLib * Rebuilds the current TLS Directory. * @param vBuffer Buffer where the TLS directory will be written to. **/ - template - void TlsDirectory::rebuild(std::vector& vBuffer) const + inline + void TlsDirectory::rebuild(std::vector& vBuffer) const { - OutputBuffer obBuffer(vBuffer); - - obBuffer << m_tls.StartAddressOfRawData; - obBuffer << m_tls.EndAddressOfRawData; - obBuffer << m_tls.AddressOfIndex; - obBuffer << m_tls.AddressOfCallBacks; - obBuffer << m_tls.SizeOfZeroFill; - obBuffer << m_tls.Characteristics; + if(pointerSize == 32) + { + PELIB_IMAGE_TLS_DIRECTORY32 TlsDirectory32; + + TlsDirectory32.StartAddressOfRawData = (std::uint32_t)m_tls.StartAddressOfRawData; + TlsDirectory32.EndAddressOfRawData = (std::uint32_t)m_tls.EndAddressOfRawData; + TlsDirectory32.AddressOfIndex = (std::uint32_t)m_tls.AddressOfIndex; + TlsDirectory32.AddressOfCallBacks = (std::uint32_t)m_tls.AddressOfCallBacks; + TlsDirectory32.SizeOfZeroFill = m_tls.SizeOfZeroFill; + TlsDirectory32.Characteristics = m_tls.Characteristics; + + vBuffer.resize(sizeof(PELIB_IMAGE_TLS_DIRECTORY32)); + memcpy(vBuffer.data(), &TlsDirectory32, sizeof(PELIB_IMAGE_TLS_DIRECTORY32)); + } + else + { + vBuffer.resize(sizeof(PELIB_IMAGE_TLS_DIRECTORY)); + memcpy(vBuffer.data(), &m_tls, sizeof(PELIB_IMAGE_TLS_DIRECTORY)); + } } /** @@ -154,18 +144,18 @@ namespace PeLib * will always be 24. * @return Size in bytes. **/ - template - unsigned int TlsDirectory::size() const + inline + unsigned int TlsDirectory::size() const { - return PELIB_IMAGE_TLS_DIRECTORY::size(); + return (pointerSize == 32) ? sizeof(PELIB_IMAGE_TLS_DIRECTORY32) : sizeof(PELIB_IMAGE_TLS_DIRECTORY); } /** * @param strFilename Name of the file. * @param dwOffset File offset the TLS Directory will be written to. **/ - template - int TlsDirectory::write(const std::string& strFilename, unsigned int dwOffset) const + inline + int TlsDirectory::write(const std::string& strFilename, unsigned int dwOffset) const { std::fstream ofFile(strFilename.c_str(), std::ios_base::in); @@ -200,8 +190,8 @@ namespace PeLib /** * @return The StartAddressOfRawData value of the TLS directory. **/ - template - typename FieldSizes::VAR4_8 TlsDirectory::getStartAddressOfRawData() const + inline + std::uint64_t TlsDirectory::getStartAddressOfRawData() const { return m_tls.StartAddressOfRawData; } @@ -209,8 +199,8 @@ namespace PeLib /** * @return The EndAddressOfRawData value of the TLS directory. **/ - template - typename FieldSizes::VAR4_8 TlsDirectory::getEndAddressOfRawData() const + inline + std::uint64_t TlsDirectory::getEndAddressOfRawData() const { return m_tls.EndAddressOfRawData; } @@ -218,8 +208,8 @@ namespace PeLib /** * @return The AddressOfIndex value of the TLS directory. **/ - template - typename FieldSizes::VAR4_8 TlsDirectory::getAddressOfIndex() const + inline + std::uint64_t TlsDirectory::getAddressOfIndex() const { return m_tls.AddressOfIndex; } @@ -227,8 +217,8 @@ namespace PeLib /** * @return The AddressOfCallBacks value of the TLS directory. **/ - template - typename FieldSizes::VAR4_8 TlsDirectory::getAddressOfCallBacks() const + inline + std::uint64_t TlsDirectory::getAddressOfCallBacks() const { return m_tls.AddressOfCallBacks; } @@ -236,8 +226,8 @@ namespace PeLib /** * @return The SizeOfZeroFill value of the TLS directory. **/ - template - std::uint32_t TlsDirectory::getSizeOfZeroFill() const + inline + std::uint32_t TlsDirectory::getSizeOfZeroFill() const { return m_tls.SizeOfZeroFill; } @@ -245,8 +235,8 @@ namespace PeLib /** * @return The Characteristics value of the TLS directory. **/ - template - std::uint32_t TlsDirectory::getCharacteristics() const + inline + std::uint32_t TlsDirectory::getCharacteristics() const { return m_tls.Characteristics; } @@ -254,44 +244,44 @@ namespace PeLib /** * @param dwValue The new StartAddressOfRawData value of the TLS directory. **/ - template - void TlsDirectory::setStartAddressOfRawData(std::uint32_t dwValue) + inline + void TlsDirectory::setStartAddressOfRawData(std::uint64_t value) { - m_tls.StartAddressOfRawData = dwValue; + m_tls.StartAddressOfRawData = value; } /** * @param dwValue The new EndAddressOfRawData value of the TLS directory. **/ - template - void TlsDirectory::setEndAddressOfRawData(std::uint32_t dwValue) + inline + void TlsDirectory::setEndAddressOfRawData(std::uint64_t value) { - m_tls.EndAddressOfRawData = dwValue; + m_tls.EndAddressOfRawData = value; } /** * @param dwValue The new AddressOfIndex value of the TLS directory. **/ - template - void TlsDirectory::setAddressOfIndex(std::uint32_t dwValue) + inline + void TlsDirectory::setAddressOfIndex(std::uint64_t value) { - m_tls.AddressOfIndex = dwValue; + m_tls.AddressOfIndex = value; } /** * @param dwValue The new AddressOfCallBacks value of the TLS directory. **/ - template - void TlsDirectory::setAddressOfCallBacks(std::uint32_t dwValue) + inline + void TlsDirectory::setAddressOfCallBacks(std::uint64_t value) { - m_tls.AddressOfCallBacks = dwValue; + m_tls.AddressOfCallBacks = value; } /** * @param dwValue The new SizeOfZeroFill value of the TLS directory. **/ - template - void TlsDirectory::setSizeOfZeroFill(std::uint32_t dwValue) + inline + void TlsDirectory::setSizeOfZeroFill(std::uint32_t dwValue) { m_tls.SizeOfZeroFill = dwValue; } @@ -299,8 +289,8 @@ namespace PeLib /** * @param dwValue The new Characteristics value of the TLS directory. **/ - template - void TlsDirectory::setCharacteristics(std::uint32_t dwValue) + inline + void TlsDirectory::setCharacteristics(std::uint32_t dwValue) { m_tls.Characteristics = dwValue; } From 64a6d9e3cf110fda5c7b10d75c43d8f0f4de6cac Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Fri, 19 Jun 2020 17:12:18 +0200 Subject: [PATCH 06/34] ImageLoader: Resources --- .../fileformat/file_format/pe/pe_template.h | 6 +- include/retdec/pelib/ImageLoader.h | 3 + include/retdec/pelib/PeFile.h | 15 +- include/retdec/pelib/PeLibAux.h | 4 +- include/retdec/pelib/ResourceDirectory.h | 64 +----- src/pelib/ImageLoader.cpp | 48 +++- src/pelib/ResourceDirectory.cpp | 217 +++++++----------- 7 files changed, 148 insertions(+), 209 deletions(-) diff --git a/include/retdec/fileformat/file_format/pe/pe_template.h b/include/retdec/fileformat/file_format/pe/pe_template.h index 68c0482db..f64aafa75 100644 --- a/include/retdec/fileformat/file_format/pe/pe_template.h +++ b/include/retdec/fileformat/file_format/pe/pe_template.h @@ -714,7 +714,7 @@ inline bool peDebugEntryPointerToRawData(const PeLib::DebugDirectory &debug, uns * @param resources Parser of PE resource directory * @return Directory file offset */ -template unsigned long long peResourceDirectoryOffset(const PeLib::ResourceDirectoryT &resources) +inline unsigned long long peResourceDirectoryOffset(const PeLib::ResourceDirectory &resources) { return resources.getOffset(); } @@ -724,7 +724,7 @@ template unsigned long long peResourceDirectoryOffset(const PeLib::Res * @param resources Parser of PE resource directory * @return Directory tree root node */ -template const PeLib::ResourceNode* peResourceTreeRoot(const PeLib::ResourceDirectoryT &resources) +inline const PeLib::ResourceNode* peResourceTreeRoot(const PeLib::ResourceDirectory &resources) { return resources.getRoot(); } @@ -954,7 +954,7 @@ inline retdec::common::RangeContainer peDebugDirectoryOccupiedAdd * @param peResources Parser of PE resource directory * @return Occupied address ranges */ -template retdec::common::RangeContainer peResourceDirectoryOccupiedAddresses(const PeLib::ResourceDirectoryT &peResources) +inline retdec::common::RangeContainer peResourceDirectoryOccupiedAddresses(const PeLib::ResourceDirectory &peResources) { retdec::common::RangeContainer result; for (const auto& addresses : peResources.getOccupiedAddresses()) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 15bb24b8e..3e4fd1374 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -139,6 +139,8 @@ class ImageLoader std::uint32_t readPointer(std::uint32_t rva, std::uint64_t & pointerValue); std::uint32_t getPointerSize() const; + std::uint32_t readStringRc(std::string & str, std::uint32_t rva); + std::uint32_t dumpImage(const char * fileName); std::uint32_t getImageBitability() const; @@ -229,6 +231,7 @@ class ImageLoader std::uint32_t maxSectionCount; bool ntHeadersSizeCheck; // If true, the loader requires minimum size of NT headers bool sizeofImageMustMatch; // If true, the SizeOfImage must match virtual end of the last section + //bool copyWholeHeaderPage; // If true, then the image header is copied up to Section Alignment bool appContainerCheck; // If true, app container flag is tested in the optional header bool strictMode; // If true, the loader refuses corrupt images like Windows loader would do }; diff --git a/include/retdec/pelib/PeFile.h b/include/retdec/pelib/PeFile.h index 238b2273e..c4254b823 100644 --- a/include/retdec/pelib/PeFile.h +++ b/include/retdec/pelib/PeFile.h @@ -166,7 +166,7 @@ namespace PeLib ExportDirectory m_expdir; ///< Export directory of the current file. ImportDirectory m_impdir; ///< Import directory of the current file. BoundImportDirectory m_boundimpdir; ///< BoundImportDirectory of the current file. - ResourceDirectoryT m_resdir; ///< ResourceDirectory of the current file. + ResourceDirectory m_resdir; ///< ResourceDirectory of the current file. RelocationsDirectoryT m_relocs; ///< Relocations directory of the current file. ComHeaderDirectoryT m_comdesc; ///< COM+ descriptor directory of the current file. IatDirectory m_iat; ///< Import address table of the current file. @@ -255,9 +255,9 @@ namespace PeLib BoundImportDirectory & boundImpDir(); // EXPORT /// Accessor function for the resource directory. - const ResourceDirectoryT& resDir() const; + const ResourceDirectory & resDir() const; /// Accessor function for the resource directory. - ResourceDirectoryT& resDir(); // EXPORT + ResourceDirectory & resDir(); // EXPORT /// Accessor function for the relocations directory. const RelocationsDirectoryT& relocDir() const; @@ -462,7 +462,7 @@ namespace PeLib * @return A reference to the file's resource directory. **/ template - const ResourceDirectoryT& PeFileT::resDir() const + const ResourceDirectory & PeFileT::resDir() const { return m_resdir; } @@ -471,7 +471,7 @@ namespace PeLib * @return A reference to the file's resource directory. **/ template - ResourceDirectoryT& PeFileT::resDir() + ResourceDirectory & PeFileT::resDir() { return m_resdir; } @@ -616,10 +616,9 @@ namespace PeLib template int PeFileT::readResourceDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 3 - && peHeader().getIddResourceRva()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE)) { - return resDir().read(m_iStream, peHeader()); + return resDir().read(m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index d8dfb1dcd..525a8dd34 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -157,9 +157,9 @@ namespace PeLib const std::uint32_t PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; - const std::uint32_t PELIB_IMAGE_RESOURCE_NAME_IS_STRING = 0x80000000; - const std::uint32_t PELIB_IMAGE_RESOURCE_DATA_IS_DIRECTORY = 0x80000000; + const std::uint32_t PELIB_IMAGE_RESOURCE_NAME_IS_STRING = 0x80000000; + const std::uint32_t PELIB_IMAGE_RESOURCE_RVA_MASK = 0x7FFFFFFF; template struct PELIB_IMAGE_ORDINAL_FLAGS; diff --git a/include/retdec/pelib/ResourceDirectory.h b/include/retdec/pelib/ResourceDirectory.h index 42bd5738e..bef054c7a 100644 --- a/include/retdec/pelib/ResourceDirectory.h +++ b/include/retdec/pelib/ResourceDirectory.h @@ -17,12 +17,12 @@ #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { class ResourceElement; class ResourceDirectory; - template class ResourceDirectoryT; /// The class ResourceChild is used to store information about a resource node. class ResourceChild @@ -31,7 +31,7 @@ namespace PeLib friend class ResourceDirectory; friend class ResourceNode; friend class ResourceLeaf; - template friend class ResourceDirectoryT; + friend class ResourceDirectory; /// Stores name and offset of a resource node. PELIB_IMG_RES_DIR_ENTRY entry; @@ -105,7 +105,7 @@ namespace PeLib unsigned int uiElementRva; /// Reads the next resource element from the InputBuffer. - virtual int read(std::istream&, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, ResourceDirectory* resDir) = 0; + virtual int read(ImageLoader & imageLoader, std::uint32_t, std::uint32_t, std::uint32_t, ResourceDirectory* resDir) = 0; /// Writes the next resource element into the OutputBuffer. virtual void rebuild(OutputBuffer&, unsigned int, unsigned int, const std::string&) const = 0; /// Recalculates the tree for different RVA. @@ -132,7 +132,7 @@ namespace PeLib friend class ResourceChild; friend class ResourceDirectory; template friend struct fixNumberOfEntries; - template friend class ResourceDirectoryT; + friend class ResourceDirectory; private: /// The resource data. @@ -141,7 +141,7 @@ namespace PeLib PELIB_IMAGE_RESOURCE_DATA_ENTRY entry; protected: - int read(std::istream& inStream, unsigned int uiRsrcOffset, unsigned int uiOffset, unsigned int uiRva, unsigned int uiFileSize, unsigned int uiSizeOfImage, ResourceDirectory* resDir); + int read(ImageLoader & imageLoader, std::uint32_t uiRsrcRva, std::uint32_t uiOffset, std::uint32_t sizeOfImage, ResourceDirectory* resDir); /// Writes the next resource leaf into the OutputBuffer. void rebuild(OutputBuffer&, unsigned int uiOffset, unsigned int uiRva, const std::string&) const; /// Recalculates the tree for different RVA. @@ -190,7 +190,7 @@ namespace PeLib friend class ResourceChild; friend class ResourceDirectory; template friend struct fixNumberOfEntries; - template friend class ResourceDirectoryT; + friend class ResourceDirectory; /// The node's children. std::vector children; @@ -199,7 +199,7 @@ namespace PeLib protected: /// Reads the next resource node. - int read(std::istream& inStream, unsigned int uiRsrcOffset, unsigned int uiOffset, unsigned int uiRva, unsigned int uiFileSize, unsigned int uiSizeOfImage, ResourceDirectory* resDir); + int read(ImageLoader & imageLoader, std::uint32_t uiRsrcRva, std::uint32_t uiOffset, std::uint32_t sizeOfImage, ResourceDirectory* resDir); /// Writes the next resource node into the OutputBuffer. void rebuild(OutputBuffer&, unsigned int uiOffset, unsigned int uiRva, const std::string&) const; /// Recalculates the tree for different RVA. @@ -401,6 +401,9 @@ namespace PeLib /// Destructor virtual ~ResourceDirectory() = default; + /// Reads the resource directory from a file. + int read(ImageLoader & imageLoader); + ResourceNode* getRoot(); const ResourceNode* getRoot() const; @@ -776,53 +779,6 @@ namespace PeLib return ERROR_NONE; } - - template - class ResourceDirectoryT : public ResourceDirectory - { - public: - /// Reads the resource directory from a file. - int read(std::istream& inStream, const PeHeaderT& peHeader); - }; - - /** - * Reads the resource directory from a file. - * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA - * calculations need to be done. - **/ - template - int ResourceDirectoryT::read( - std::istream& inStream, - const PeHeaderT& peHeader) - { - unsigned int uiResDirRva = peHeader.getIddResourceRva(); - unsigned int uiOffset = peHeader.rvaToOffset(uiResDirRva); - - m_resourceNodeOffsets.clear(); - m_readOffset = uiOffset; - if (!uiOffset) - { - return ERROR_INVALID_FILE; - } - - IStreamWrapper inStream_w(inStream); - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - std::uint64_t ulFileSize = fileSize(inStream_w); - if (ulFileSize < uiOffset) - { - return ERROR_INVALID_FILE; - } - - inStream_w.seekg(uiOffset, std::ios::beg); - - return m_rnRoot.read(inStream_w, uiOffset, 0, uiResDirRva, ulFileSize, peHeader.getSizeOfImage(), this); - } } #endif diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index ea791e234..388a20824 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -61,6 +61,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) // By default, set the most benevolent settings sizeofImageMustMatch = false; + //copyWholeHeaderPage = false; ntHeadersSizeCheck = false; appContainerCheck = false; maxSectionCount = 255; @@ -71,6 +72,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) case LoaderModeWindowsXP: maxSectionCount = PE_MAX_SECTION_COUNT_XP; sizeofImageMustMatch = true; + //copyWholeHeaderPage = true; break; case LoaderModeWindows7: @@ -244,7 +246,33 @@ uint32_t PeLib::ImageLoader::getPointerSize() const { return getImageBitability() / 8; } - + +uint32_t PeLib::ImageLoader::readStringRc(std::string & str, std::uint32_t rva) +{ + std::vector wideString; + uint32_t bytesToRead; + uint32_t charsRead; + uint16_t length = 0; + + // Read the length of the string from the image + readImage(&length, rva, sizeof(uint16_t)); + rva += sizeof(uint16_t); + + // Allocate enough space + bytesToRead = length * sizeof(uint16_t); + wideString.resize(length); + + // Read the entire string from the image + charsRead = readImage(wideString.data(), rva, bytesToRead) / sizeof(uint16_t); + str.resize(charsRead); + + // Convert the UTF-16 string to ANSI. Note that this is not the proper way to do it, + // but it's the same way how retdec-fileinfo.exe always did it, so we keep it that way + for(uint32_t i = 0; i < charsRead; i++) + str[i] = wideString[i]; + return charsRead; +} + uint32_t PeLib::ImageLoader::dumpImage(const char * fileName) { // Create the file for dumping @@ -1056,6 +1084,7 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) int PeLib::ImageLoader::captureImageSections(std::vector & fileData) { uint32_t virtualAddress = 0; + uint32_t sizeOfHeaders = optionalHeader.SizeOfHeaders; uint32_t sizeOfImage; // Reserve the image size, aligned up to the page size @@ -1065,8 +1094,16 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) // Section-based mapping / file-based mapping if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE) { + // Note: Under Windows XP, the sample below contained the whole PAGE_SIZE + // in the mapped image header. SizeOfHeaders = 0xC00. I haven't figured our why. + // Doesn't happen in Windows 7+ and it's not subject to low-memory or heavy-load, + // aka also happens when just a single image is loaded. + // Sample: 1669f0220f1f74523390fe5b61ea09d6e2e4e798ab294c93d0a20900a3c5a52a + //if(copyWholeHeaderPage) + // sizeOfHeaders = AlignToSize(sizeOfHeaders, optionalHeader.SectionAlignment); + // Capture the file header - virtualAddress = captureImageSection(fileData, virtualAddress, optionalHeader.SizeOfHeaders, 0, optionalHeader.SizeOfHeaders, PELIB_IMAGE_SCN_MEM_READ, true); + virtualAddress = captureImageSection(fileData, virtualAddress, sizeOfHeaders, 0, sizeOfHeaders, PELIB_IMAGE_SCN_MEM_READ, true); if(virtualAddress == 0) return ERROR_INVALID_FILE; @@ -1569,10 +1606,9 @@ void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & Ima // Read the image page readImage(singlePage, rva, sizeof(singlePage)); - // Check for difference - // Note that if this is done in a debugger (e.g. Visual Studio) and PDB is available, - // it might place breakpoint to the position of __crt_debugger_hook, which will cause - // this memcmp return difference. + // Windows: Under low memory condition and heavy load, there may be STATUS_IN_PAGE_ERROR + // exception thrown when touching the mapped image. For that reason, + // this function must be framed by __try/__except in caller if(memcmp(winImageData, singlePage, PELIB_PAGE_SIZE)) { mismatchOffset = getMismatchOffset(winImageData, singlePage, rva, PELIB_PAGE_SIZE); diff --git a/src/pelib/ResourceDirectory.cpp b/src/pelib/ResourceDirectory.cpp index 70eb4d58b..3d503a22b 100644 --- a/src/pelib/ResourceDirectory.cpp +++ b/src/pelib/ResourceDirectory.cpp @@ -302,75 +302,48 @@ namespace PeLib /** * Reads the next resource leaf from the input file. - * @param inStream An input stream. - * @param uiRsrcOffset Offset of resource directory in the file. + * @param imageLoader An image loaded into the ImageLoader parser + * @param uiRsrcRva RVA of the beginning of the resource directory. * @param uiOffset Offset of the resource leaf that's to be read. - * @param uiRva RVA of the beginning of the resource directory. - * @param uiFileSize Size of the input file. * @param uiSizeOfImage Size of the image. * @param resDir Resource directory. **/ int ResourceLeaf::read( - std::istream& inStream, - unsigned int uiRsrcOffset, - unsigned int uiOffset, - unsigned int uiRva, - unsigned int uiFileSize, - unsigned int /* uiSizeOfImage */, + ImageLoader & imageLoader, + std::uint32_t uiRsrcRva, + std::uint32_t uiOffset, + std::uint32_t sizeOfImage, ResourceDirectory* resDir) { - IStreamWrapper inStream_w(inStream); - // Invalid leaf. - if (uiRsrcOffset + uiOffset + PELIB_IMAGE_RESOURCE_DATA_ENTRY::size() > fileSize(inStream_w)) + std::uint32_t uiRva = uiRsrcRva + uiOffset; + if(uiRva > sizeOfImage) { return ERROR_INVALID_FILE; } - uiElementRva = uiOffset + uiRva; - - std::vector vResourceDataEntry(PELIB_IMAGE_RESOURCE_DATA_ENTRY::size()); - inStream_w.seekg(uiRsrcOffset + uiOffset, std::ios_base::beg); - inStream_w.read(reinterpret_cast(vResourceDataEntry.data()), PELIB_IMAGE_RESOURCE_DATA_ENTRY::size()); - - InputBuffer inpBuffer(vResourceDataEntry); - - inpBuffer >> entry.OffsetToData; - inpBuffer >> entry.Size; - inpBuffer >> entry.CodePage; - inpBuffer >> entry.Reserved; - - resDir->addOccupiedAddressRange(uiElementRva, uiElementRva + PELIB_IMAGE_RESOURCE_DATA_ENTRY::size() - 1); + // Load the resource data entry + imageLoader.readImage(&entry, uiRva, sizeof(PELIB_IMAGE_RESOURCE_DATA_ENTRY)); + resDir->addOccupiedAddressRange(uiRva, uiRva + PELIB_IMAGE_RESOURCE_DATA_ENTRY::size() - 1); + // Clear the resource data m_data.clear(); - unsigned int uiEntrySize = std::min(entry.Size, uiFileSize); - - // No data. - if (!(entry.OffsetToData - uiRva + entry.Size)) - { - return ERROR_NONE; - } - // Invalid leaf. - else if (uiRsrcOffset + (entry.OffsetToData - uiRva) + uiEntrySize > uiFileSize) - { - return ERROR_NONE; - } - else if (entry.OffsetToData < uiRva) - { + // No data or invalid leaf + if(entry.OffsetToData >= sizeOfImage || entry.OffsetToData + entry.Size > sizeOfImage) return ERROR_NONE; - } - m_data.resize(uiEntrySize); + // Data pointing before resource directory? + if((uiRsrcRva + entry.OffsetToData) < uiRsrcRva) + return ERROR_NONE; - inStream_w.seekg(uiRsrcOffset + (entry.OffsetToData - uiRva), std::ios_base::beg); - inStream_w.read(reinterpret_cast(m_data.data()), uiEntrySize); - - if (uiEntrySize > 0) - { - resDir->addOccupiedAddressRange(entry.OffsetToData, entry.OffsetToData + uiEntrySize - 1); - } + // Load the resource data + m_data.resize(entry.Size); + imageLoader.readImage(m_data.data(), entry.OffsetToData, entry.Size); + // Add the data range to the occupied map + if(entry.Size > 0) + resDir->addOccupiedAddressRange(entry.OffsetToData, entry.OffsetToData + entry.Size - 1); return ERROR_NONE; } @@ -648,90 +621,66 @@ namespace PeLib /** * Reads the next resource node from the input file. - * @param inStream An input stream. - * @param uiRsrcOffset Offset of resource directory in the file. + * @param imageLoader An input stream. + * @param uiRsrcRva RVA of the beginning of the resource directory. * @param uiOffset Offset of the resource node that's to be read. - * @param uiRva RVA of the beginning of the resource directory. - * @param uiFileSize Size of the input file. * @param uiSizeOfImage Size of the image. * @param resDir Resource directory. **/ int ResourceNode::read( - std::istream& inStream, - unsigned int uiRsrcOffset, - unsigned int uiOffset, - unsigned int uiRva, - unsigned int uiFileSize, - unsigned int uiSizeOfImage, + ImageLoader & imageLoader, + std::uint32_t uiRsrcRva, + std::uint32_t uiOffset, + std::uint32_t sizeOfImage, ResourceDirectory* resDir) { - IStreamWrapper inStream_w(inStream); - - // Not enough space to be a valid node. - if (!resDir || uiRsrcOffset + uiOffset + PELIB_IMAGE_RESOURCE_DIRECTORY::size() > fileSize(inStream_w)) + // Enough space to be a valid node? + std::uint32_t uiRva = uiRsrcRva + uiOffset; + if(uiRva > sizeOfImage) { return ERROR_INVALID_FILE; } - uiElementRva = uiOffset + uiRva; - - std::vector vResourceDirectory(PELIB_IMAGE_RESOURCE_DIRECTORY::size()); - inStream_w.seekg(uiRsrcOffset + uiOffset, std::ios_base::beg); - inStream_w.read(reinterpret_cast(vResourceDirectory.data()), PELIB_IMAGE_RESOURCE_DIRECTORY::size()); - - InputBuffer inpBuffer(vResourceDirectory); - - inpBuffer >> header.Characteristics; - inpBuffer >> header.TimeDateStamp; - inpBuffer >> header.MajorVersion; - inpBuffer >> header.MinorVersion; - inpBuffer >> header.NumberOfNamedEntries; - inpBuffer >> header.NumberOfIdEntries; + // Read the resource node header + imageLoader.readImage(&header, uiRva, PELIB_IMAGE_RESOURCE_DIRECTORY::size()); + // Add the total number of entries to the occupied range unsigned int uiNumberOfEntries = header.NumberOfNamedEntries + header.NumberOfIdEntries; - - resDir->addOccupiedAddressRange(uiElementRva, uiElementRva + PELIB_IMAGE_RESOURCE_DIRECTORY::size() - 1); + resDir->addOccupiedAddressRange(uiRva, uiRva + PELIB_IMAGE_RESOURCE_DIRECTORY::size() - 1); + uiRva += PELIB_IMAGE_RESOURCE_DIRECTORY::size(); // Windows loader check (PspLocateInPEManifest -> LdrpResGetResourceDirectory): // If the total number of resource entries goes beyond the image, the file is refused to run // Sample: 6318b0a1b57fc70bce5314aefb6cb06c90b7991afeae4e91ffc05ee0c88947d7 - // However, such sample can still be executed in Windows XP - based emulator - if ((uiRva + (uiNumberOfEntries * PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size())) > uiSizeOfImage) + // However, such sample can still be executed in WinXP-based emulator + if ((uiRva + (uiNumberOfEntries * PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size())) > sizeOfImage) { resDir->setLoaderError(LDR_ERROR_RSRC_OVER_END_OF_IMAGE); return ERROR_NONE; } - // Not enough space to be a valid node. - if (uiRsrcOffset + uiOffset + PELIB_IMAGE_RESOURCE_DIRECTORY::size() + uiNumberOfEntries * PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size() > fileSize(inStream_w)) - { - return ERROR_INVALID_FILE; - } - - std::vector vResourceChildren(uiNumberOfEntries * PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size()); - inStream_w.read(reinterpret_cast(vResourceChildren.data()), uiNumberOfEntries * PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size()); - InputBuffer childInpBuffer(vResourceChildren); - + // Load all entries to the vector + std::vector vResourceChildren(uiNumberOfEntries); resDir->insertNodeOffset(uiOffset); + if (uiNumberOfEntries > 0) { - resDir->addOccupiedAddressRange( - uiElementRva + PELIB_IMAGE_RESOURCE_DIRECTORY::size(), - uiElementRva + PELIB_IMAGE_RESOURCE_DIRECTORY::size() + uiNumberOfEntries * PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size() - 1 - ); + resDir->addOccupiedAddressRange(uiRva, uiRva + uiNumberOfEntries * PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size() - 1); } - for (unsigned int i = 0; i < uiNumberOfEntries; ++i) + for (unsigned int i = 0; i < uiNumberOfEntries; i++) { ResourceChild rc; - childInpBuffer >> rc.entry.irde.Name; - childInpBuffer >> rc.entry.irde.OffsetToData; + int childError; - // If the resource entry goes out of the image, then the image is claimed as corrupt by + imageLoader.readImage(&rc.entry.irde, uiRva, PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size()); + uiRva += PELIB_IMAGE_RESOURCE_DIRECTORY_ENTRY::size(); + + // If the resource name goes out of the image, then the image is claimed as corrupt by // Windows loader check (PspLocateInPEManifest -> LdrpResGetResourceDirectory) - if(rc.entry.irde.Name & 0x80000000) + if(rc.entry.irde.Name & PELIB_IMAGE_RESOURCE_NAME_IS_STRING) { - if((rc.entry.irde.Name & 0x7FFFFFFF) > uiSizeOfImage) + if((rc.entry.irde.Name & PELIB_IMAGE_RESOURCE_RVA_MASK) > sizeOfImage) { resDir->setLoaderError(LDR_ERROR_RSRC_NAME_OUT_OF_IMAGE); } @@ -739,10 +688,10 @@ namespace PeLib // Check whether the resource data/subdirectory goes out of the image { - if((rc.entry.irde.OffsetToData & 0x7FFFFFFF) > uiSizeOfImage) + if((rc.entry.irde.OffsetToData & PELIB_IMAGE_RESOURCE_RVA_MASK) > sizeOfImage) { // Is it a subdirectory? - if(rc.entry.irde.OffsetToData & 0x80000000) + if(rc.entry.irde.OffsetToData & PELIB_IMAGE_RESOURCE_DATA_IS_DIRECTORY) { resDir->setLoaderError(LDR_ERROR_RSRC_SUBDIR_OUT_OF_IMAGE); return ERROR_NONE; @@ -754,47 +703,25 @@ namespace PeLib } } - unsigned int lastPos = inStream_w.tellg(); - if (rc.entry.irde.Name & PELIB_IMAGE_RESOURCE_NAME_IS_STRING) { // Enough space to read string length? - if ((rc.entry.irde.Name & ~PELIB_IMAGE_RESOURCE_NAME_IS_STRING) + 2 < fileSize(inStream_w)) + if ((rc.entry.irde.Name & PELIB_IMAGE_RESOURCE_RVA_MASK) + 2 < sizeOfImage) { - unsigned int uiNameOffset = rc.entry.irde.Name & ~PELIB_IMAGE_RESOURCE_NAME_IS_STRING; - if (uiRsrcOffset + uiNameOffset + sizeof(std::uint16_t) > fileSize(inStream_w)) + // Check whether we have enough space to read at least one character + unsigned int uiNameOffset = rc.entry.irde.Name & PELIB_IMAGE_RESOURCE_RVA_MASK; + if (uiRva + uiNameOffset + sizeof(std::uint16_t) > sizeOfImage) { return ERROR_INVALID_FILE; } - inStream_w.seekg(uiRsrcOffset + uiNameOffset, std::ios_base::beg); - - std::uint16_t len; - inStream_w.read(reinterpret_cast(&len), sizeof(std::uint16_t)); - - // Enough space to read string? - if (uiRsrcOffset + uiNameOffset + 2 * len > fileSize(inStream_w)) - { - return ERROR_INVALID_FILE; - } - - // jk: This construction is incorrect on 64bit systems - // wchar_t c; - std::uint16_t c; - for (std::uint16_t ii=0; ii(&c), sizeof(std::uint16_t)); - rc.entry.wstrName += c; - } + // Read the resource name + imageLoader.readStringRc(rc.entry.wstrName, uiRsrcRva + uiNameOffset); } - - inStream_w.seekg(lastPos, std::ios_base::beg); } - const auto value = (rc.entry.irde.OffsetToData & PELIB_IMAGE_RESOURCE_DATA_IS_DIRECTORY) ? - (rc.entry.irde.OffsetToData & ~PELIB_IMAGE_RESOURCE_DATA_IS_DIRECTORY) : rc.entry.irde.OffsetToData; // Detect cycles to prevent infinite recursion. - if (resDir->hasNodeOffset(value)) + if (resDir->hasNodeOffset(rc.entry.irde.OffsetToData & PELIB_IMAGE_RESOURCE_RVA_MASK)) { return ERROR_NONE; } @@ -808,13 +735,14 @@ namespace PeLib rc.child = new ResourceLeaf; } - if (rc.child->read(inStream_w, uiRsrcOffset, value, uiRva, uiFileSize, uiSizeOfImage, resDir) != ERROR_NONE) + // Read the child node + childError = rc.child->read(imageLoader, uiRsrcRva, rc.entry.irde.OffsetToData & PELIB_IMAGE_RESOURCE_RVA_MASK, sizeOfImage, resDir); + if (childError != ERROR_NONE) { - return ERROR_INVALID_FILE; + return childError; } children.push_back(rc); - inStream_w.seekg(lastPos, std::ios_base::beg); } return ERROR_NONE; @@ -1084,6 +1012,23 @@ namespace PeLib return &m_rnRoot; } + /** + * Reads the resource directory from a file. + * @param imageLoader image loader + **/ + int ResourceDirectory::read(ImageLoader & imageLoader) + { + std::uint32_t resDirRva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE); + std::uint32_t sizeOfImage = imageLoader.getSizeOfImage(); + + if(resDirRva >= sizeOfImage) + { + return ERROR_INVALID_FILE; + } + + return m_rnRoot.read(imageLoader, resDirRva, 0, sizeOfImage, this); + } + /** * Returns the root node of the resource directory. * @return Root node of the resource directory. From f68df78ae792f646e2c44208a4009e038d3a767a Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Mon, 22 Jun 2020 09:40:32 +0200 Subject: [PATCH 07/34] ImageLoader : Relocations + COM directory --- .../fileformat/file_format/pe/pe_template.h | 6 +- include/retdec/pelib/ComHeaderDirectory.h | 49 +---------- include/retdec/pelib/ImageLoader.h | 2 + include/retdec/pelib/PeFile.h | 52 +++++------ include/retdec/pelib/RelocationsDirectory.h | 59 ++----------- src/fileformat/file_format/pe/pe_format.cpp | 10 ++- src/pelib/ComHeaderDirectory.cpp | 50 ++++------- src/pelib/ImageLoader.cpp | 10 +++ src/pelib/RelocationsDirectory.cpp | 88 +++++++++++-------- 9 files changed, 123 insertions(+), 203 deletions(-) diff --git a/include/retdec/fileformat/file_format/pe/pe_template.h b/include/retdec/fileformat/file_format/pe/pe_template.h index f64aafa75..e6fca4d7f 100644 --- a/include/retdec/fileformat/file_format/pe/pe_template.h +++ b/include/retdec/fileformat/file_format/pe/pe_template.h @@ -794,7 +794,7 @@ inline unsigned long long peTlsCharacteristics(const PeLib::TlsDirectory &tls) * @param comHeader Parser of PE COM/CLR directory * @return Parsed CLR header */ -template std::unique_ptr peGetClrHeader(const PeLib::ComHeaderDirectoryT &comHeader) +inline std::unique_ptr peGetClrHeader(const PeLib::ComHeaderDirectory &comHeader) { auto clrHeader = std::make_unique(); clrHeader->setHeaderSize(comHeader.getSizeOfHeader()); @@ -824,7 +824,7 @@ template std::unique_ptr peGetClrHeader(const PeLib::ComHea * @param relocs Parser of PE relocation directory * @return Number of relocations */ -template unsigned long long peNumberOfRelocations(const PeLib::RelocationsDirectoryT &relocs) +inline unsigned long long peNumberOfRelocations(const PeLib::RelocationsDirectory &relocs) { return relocs.calcNumberOfRelocations(); } @@ -835,7 +835,7 @@ template unsigned long long peNumberOfRelocations(const PeLib::Relocat * @param index Relocation data index * @return Number of relocation data */ -template unsigned long long peNumberOfRelocationData(const PeLib::RelocationsDirectoryT &relocs, unsigned long long index) +inline unsigned long long peNumberOfRelocationData(const PeLib::RelocationsDirectory &relocs, unsigned long long index) { return relocs.calcNumberOfRelocationData(index); } diff --git a/include/retdec/pelib/ComHeaderDirectory.h b/include/retdec/pelib/ComHeaderDirectory.h index 34d96ce3b..76ad1b8dc 100644 --- a/include/retdec/pelib/ComHeaderDirectory.h +++ b/include/retdec/pelib/ComHeaderDirectory.h @@ -13,7 +13,7 @@ #ifndef COMHEADERDIRECTORY_H #define COMHEADERDIRECTORY_H -#include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { @@ -27,13 +27,11 @@ namespace PeLib protected: PELIB_IMAGE_COR20_HEADER m_ichComHeader; ///< The COM+ descriptor. - void read(InputBuffer& inputbuffer); - public: virtual ~ComHeaderDirectory() = default; /// Read a file's COM+ runtime descriptor directory. - int read(unsigned char* buffer, unsigned int buffersize); // EXPORT + int read(ImageLoader & imageLoader); // EXPORT /// Rebuild the COM+ descriptor. void rebuild(std::vector& vBuffer) const; // EXPORT /// Returns the size of the current COM+ descriptor. @@ -119,48 +117,5 @@ namespace PeLib /// Change the COM+ descriptor's ManagedNativeHeader (Size) value. void setManagedNativeHeaderSize(std::uint32_t dwValue); // EXPORT }; - - template - class ComHeaderDirectoryT : public ComHeaderDirectory - { - public: - /// Read a file's COM+ runtime descriptor directory. - int read(std::istream& inStream, const PeHeaderT& peHeader); // EXPORT - }; - - /** - * Reads a file's COM+ descriptor. - * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. - **/ - template - int ComHeaderDirectoryT::read(std::istream& inStream, const PeHeaderT& peHeader) - { - IStreamWrapper inStream_w(inStream); - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - std::uint64_t ulFileSize = fileSize(inStream_w); - - unsigned int uiOffset = peHeader.rvaToOffset(peHeader.getIddComHeaderRva()); - unsigned int uiSize = peHeader.getIddComHeaderSize(); - - if (ulFileSize < uiOffset + uiSize) - { - return ERROR_INVALID_FILE; - } - - inStream_w.seekg(uiOffset, std::ios::beg); - - std::vector vComDescDirectory(uiSize); - inStream_w.read(reinterpret_cast(vComDescDirectory.data()), uiSize); - - InputBuffer ibBuffer{vComDescDirectory}; - ComHeaderDirectory::read(ibBuffer); - return ERROR_NONE; - } } #endif diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 3e4fd1374..da41a409a 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -154,6 +154,8 @@ class ImageLoader std::uint32_t getSizeOfHeaders() const; std::uint32_t getSizeOfImage() const; std::uint32_t getSizeOfImageAligned() const; + std::uint32_t getSectionAlignment() const; + std::uint32_t getFileAlignment() const; std::uint32_t getDataDirRva(std::size_t dataDirIndex) const; std::uint32_t getDataDirSize(std::size_t dataDirIndex) const; std::uint32_t getFileOffsetFromRva(std::uint32_t rva) const; diff --git a/include/retdec/pelib/PeFile.h b/include/retdec/pelib/PeFile.h index c4254b823..3fabcde06 100644 --- a/include/retdec/pelib/PeFile.h +++ b/include/retdec/pelib/PeFile.h @@ -167,8 +167,8 @@ namespace PeLib ImportDirectory m_impdir; ///< Import directory of the current file. BoundImportDirectory m_boundimpdir; ///< BoundImportDirectory of the current file. ResourceDirectory m_resdir; ///< ResourceDirectory of the current file. - RelocationsDirectoryT m_relocs; ///< Relocations directory of the current file. - ComHeaderDirectoryT m_comdesc; ///< COM+ descriptor directory of the current file. + RelocationsDirectory m_relocs; ///< Relocations directory of the current file. + ComHeaderDirectory m_comdesc; ///< COM+ descriptor directory of the current file. IatDirectory m_iat; ///< Import address table of the current file. DebugDirectory m_debugdir; ///< Debug directory of the current file. DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file. @@ -260,14 +260,14 @@ namespace PeLib ResourceDirectory & resDir(); // EXPORT /// Accessor function for the relocations directory. - const RelocationsDirectoryT& relocDir() const; + const RelocationsDirectory & relocDir() const; /// Accessor function for the relocations directory. - RelocationsDirectoryT& relocDir(); // EXPORT + RelocationsDirectory & relocDir(); // EXPORT /// Accessor function for the COM+ descriptor directory. - const ComHeaderDirectoryT& comDir() const; + const ComHeaderDirectory & comDir() const; /// Accessor function for the COM+ descriptor directory. - ComHeaderDirectoryT& comDir(); // EXPORT + ComHeaderDirectory & comDir(); // EXPORT /// Accessor function for the IAT directory. const IatDirectory & iatDir() const; @@ -480,7 +480,7 @@ namespace PeLib * @return A reference to the file's relocations directory. **/ template - const RelocationsDirectoryT& PeFileT::relocDir() const + const RelocationsDirectory & PeFileT::relocDir() const { return m_relocs; } @@ -489,7 +489,7 @@ namespace PeLib * @return A reference to the file's relocations directory. **/ template - RelocationsDirectoryT& PeFileT::relocDir() + RelocationsDirectory & PeFileT::relocDir() { return m_relocs; } @@ -498,7 +498,7 @@ namespace PeLib * @return A reference to the file's COM+ descriptor directory. **/ template - const ComHeaderDirectoryT& PeFileT::comDir() const + const ComHeaderDirectory & PeFileT::comDir() const { return m_comdesc; } @@ -507,7 +507,7 @@ namespace PeLib * @return A reference to the file's COM+ descriptor directory. **/ template - ComHeaderDirectoryT& PeFileT::comDir() + ComHeaderDirectory & PeFileT::comDir() { return m_comdesc; } @@ -626,14 +626,11 @@ namespace PeLib template int PeFileT::readSecurityDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 5 - && peHeader().getIddSecurityRva() - && peHeader().getIddSecuritySize()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY)) { - return securityDir().read( - m_iStream, - peHeader().getIddSecurityRva(), - peHeader().getIddSecuritySize()); + return securityDir().read(m_iStream, + m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY), + m_imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY)); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } @@ -641,10 +638,9 @@ namespace PeLib template int PeFileT::readRelocationsDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 6 - && peHeader().getIddBaseRelocRva() && peHeader().getIddBaseRelocSize()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC)) { - return relocDir().read(m_iStream, peHeader()); + return relocDir().read(m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } @@ -703,10 +699,10 @@ namespace PeLib template int PeFileT::readComHeaderDirectory() { - if (peHeader().calcNumberOfRvaAndSizes() >= 15 - && peHeader().getIddComHeaderRva() && peHeader().getIddComHeaderSize()) + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) && + m_imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)) { - return comDir().read(m_iStream, peHeader()); + return comDir().read(m_imageLoader); } return ERROR_DIRECTORY_DOES_NOT_EXIST; } @@ -751,14 +747,14 @@ namespace PeLib LoaderError PeFileT::checkForInMemoryLayout(LoaderError ldrError) const { std::uint64_t ulFileSize = fileSize(m_iStream); - std::uint64_t sizeOfImage = peHeader().getSizeOfImage(); + std::uint64_t sizeOfImage = m_imageLoader.getSizeOfImage(); // The file size must be greater or equal to SizeOfImage if(ulFileSize >= sizeOfImage) { - std::uint32_t sectionAlignment = peHeader().getSectionAlignment(); - std::uint32_t fileAlignment = peHeader().getFileAlignment(); - std::uint32_t sizeOfHeaders = peHeader().getSizeOfHeaders(); + std::uint32_t sectionAlignment = m_imageLoader.getSectionAlignment(); + std::uint32_t fileAlignment = m_imageLoader.getFileAlignment(); + std::uint32_t sizeOfHeaders = m_imageLoader.getSizeOfHeaders(); // SectionAlignment must be greater than file alignment if(sectionAlignment >= PELIB_PAGE_SIZE && sectionAlignment > fileAlignment) @@ -770,7 +766,7 @@ namespace PeLib // Read the entire after-header-data ByteBuffer headerData(headerDataSize); - m_iStream.seekg(peHeader().getSizeOfHeaders(), std::ios::beg); + m_iStream.seekg(sizeOfHeaders, std::ios::beg); m_iStream.read(reinterpret_cast(headerData.data()), headerDataSize); // Check whether there are zeros only. If yes, we consider diff --git a/include/retdec/pelib/RelocationsDirectory.h b/include/retdec/pelib/RelocationsDirectory.h index 6b973ba4d..7dc5f0834 100644 --- a/include/retdec/pelib/RelocationsDirectory.h +++ b/include/retdec/pelib/RelocationsDirectory.h @@ -13,7 +13,7 @@ #ifndef RELOCATIONSDIRECTORY_H #define RELOCATIONSDIRECTORY_H -#include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { @@ -27,13 +27,14 @@ namespace PeLib std::vector m_vRelocations; ///< Used to store the relocation data. LoaderError m_ldrError; /// Error detected by the import table parser - void read(InputBuffer& inputbuffer, unsigned int uiSize, unsigned int sizeOfImage); - public: /// Constructor and destructor RelocationsDirectory(); virtual ~RelocationsDirectory() = default; + /// Read a file's relocations directory. + int read(ImageLoader & imageLoader); // EXPORT + /// Retrieve the loader error LoaderError loaderError() const; void setLoaderError(LoaderError ldrError); @@ -44,7 +45,7 @@ namespace PeLib unsigned int calcNumberOfRelocationData(unsigned int ulRelocation) const; // EXPORT /// Read a file's relocations directory. - int read(const unsigned char* buffer, unsigned int buffersize, unsigned int sizeOfImage); // EXPORT + void read(const std::uint8_t * data, std::uint32_t uiSize, std::uint32_t sizeOfImage); /// Returns the size of the relocations directory. unsigned int size() const; // EXPORT @@ -71,56 +72,6 @@ namespace PeLib void removeRelocation(unsigned int index); // EXPORT void removeRelocationData(unsigned int relocindex, unsigned int dataindex); // EXPORT }; - - template - class RelocationsDirectoryT : public RelocationsDirectory - { - public: - /// Read a file's relocations directory. - int read(std::istream& inStream, const PeHeaderT& peHeader); // EXPORT - }; - - template - int RelocationsDirectoryT::read( - std::istream& inStream, - const PeHeaderT& peHeader) - { - IStreamWrapper inStream_w(inStream); - std::uint64_t ulFileSize = fileSize(inStream_w); - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - unsigned int uiOffset = peHeader.rvaToOffset(peHeader.getIddBaseRelocRva()); - unsigned int uiSize = peHeader.getIddBaseRelocSize(); - - // Check whether the relocations are out of the image - if(uiOffset == std::numeric_limits::max()) - { - RelocationsDirectory::setLoaderError(LDR_ERROR_RELOCATIONS_OUT_OF_IMAGE); - return ERROR_INVALID_FILE; - } - - // If uiSize is big enough it can overflow after addition with uiOffset, ulFileSize < uiOffset + uiSize can be true, - // even though it should be false. - if (uiSize > ulFileSize || (uiOffset + uiSize) > ulFileSize) - { - RelocationsDirectory::setLoaderError(LDR_ERROR_RELOCATIONS_OUT_OF_IMAGE); - return ERROR_INVALID_FILE; - } - - inStream_w.seekg(uiOffset, std::ios::beg); - - std::vector vRelocDirectory(uiSize); - inStream_w.read(reinterpret_cast(vRelocDirectory.data()), uiSize); - - InputBuffer ibBuffer{vRelocDirectory}; - RelocationsDirectory::read(ibBuffer, uiSize, (unsigned int)peHeader.getSizeOfImage()); - - return ERROR_NONE; - } } #endif diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index a3766fb08..f87573134 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -610,8 +610,14 @@ void PeFormat::initStructures(const std::string & dllListFile) // Fill-in the loader error info from PE file initLoaderErrorInfo(); - //mzHeader = file->mzHeader(); + // Create an instance of PeFormatParser32/PeFormatParser64 + if(file->imageLoader().getImageBitability() == 64) + formatParser = new PeFormatParser64(this, static_cast*>(file)); + else + formatParser = new PeFormatParser32(this, static_cast*>(file)); + /* + //mzHeader = file->mzHeader(); if (auto *f32 = isPe32()) { peHeader32 = &(f32->peHeader()); @@ -620,8 +626,8 @@ void PeFormat::initStructures(const std::string & dllListFile) else if (auto *f64 = isPe64()) { peHeader64 = &(f64->peHeader()); - formatParser = new PeFormatParser64(this, static_cast*>(file)); } + */ } catch(...) {} diff --git a/src/pelib/ComHeaderDirectory.cpp b/src/pelib/ComHeaderDirectory.cpp index 60476cb4e..2e27aa8ee 100644 --- a/src/pelib/ComHeaderDirectory.cpp +++ b/src/pelib/ComHeaderDirectory.cpp @@ -15,44 +15,28 @@ namespace PeLib { - void ComHeaderDirectory::read(InputBuffer& inputbuffer) - { - PELIB_IMAGE_COR20_HEADER ichCurr; - - inputbuffer >> ichCurr.cb; - inputbuffer >> ichCurr.MajorRuntimeVersion; - inputbuffer >> ichCurr.MinorRuntimeVersion; - inputbuffer >> ichCurr.MetaData.VirtualAddress; - inputbuffer >> ichCurr.MetaData.Size; - inputbuffer >> ichCurr.Flags; - inputbuffer >> ichCurr.EntryPointToken; - inputbuffer >> ichCurr.Resources.VirtualAddress; - inputbuffer >> ichCurr.Resources.Size; - inputbuffer >> ichCurr.StrongNameSignature.VirtualAddress; - inputbuffer >> ichCurr.StrongNameSignature.Size; - inputbuffer >> ichCurr.CodeManagerTable.VirtualAddress; - inputbuffer >> ichCurr.CodeManagerTable.Size; - inputbuffer >> ichCurr.VTableFixups.VirtualAddress; - inputbuffer >> ichCurr.VTableFixups.Size; - inputbuffer >> ichCurr.ExportAddressTableJumps.VirtualAddress; - inputbuffer >> ichCurr.ExportAddressTableJumps.Size; - inputbuffer >> ichCurr.ManagedNativeHeader.VirtualAddress; - inputbuffer >> ichCurr.ManagedNativeHeader.Size; - - std::swap(ichCurr, m_ichComHeader); - } - - int ComHeaderDirectory::read(unsigned char* buffer, unsigned int buffersize) - { - if (buffersize < PELIB_IMAGE_COR20_HEADER::size()) + /** + * Reads a file's COM+ descriptor. + * @param inStream Input stream. + * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. + **/ + + int ComHeaderDirectory::read(ImageLoader & imageLoader) + { + std::uint32_t rva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR); + std::uint32_t size = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR); + std::uint32_t sizeOfImage = imageLoader.getSizeOfImage(); + if(rva >= sizeOfImage || (rva + size) > sizeOfImage) { return ERROR_INVALID_FILE; } - std::vector vComDescDirectory(buffer, buffer + buffersize); + // Read the COM header as-is + if(imageLoader.readImage(&m_ichComHeader, rva, size) != size) + { + return ERROR_INVALID_FILE; + } - InputBuffer ibBuffer(vComDescDirectory); - read(ibBuffer); return ERROR_NONE; } diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 388a20824..361379fc1 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -358,6 +358,16 @@ uint32_t PeLib::ImageLoader::getSizeOfImageAligned() const return AlignToSize(optionalHeader.SizeOfImage, PELIB_PAGE_SIZE); } +uint32_t PeLib::ImageLoader::getSectionAlignment() const +{ + return optionalHeader.SectionAlignment; +} + +uint32_t PeLib::ImageLoader::getFileAlignment() const +{ + return optionalHeader.FileAlignment; +} + uint32_t PeLib::ImageLoader::getDataDirRva(size_t dataDirIndex) const { // The data directory must be present there diff --git a/src/pelib/RelocationsDirectory.cpp b/src/pelib/RelocationsDirectory.cpp index 271c5ead7..c59eb7048 100644 --- a/src/pelib/RelocationsDirectory.cpp +++ b/src/pelib/RelocationsDirectory.cpp @@ -21,6 +21,28 @@ namespace PeLib RelocationsDirectory::RelocationsDirectory() : m_ldrError(LDR_ERROR_NONE) {} + int RelocationsDirectory::read(ImageLoader & imageLoader) + { + std::uint32_t rva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC); + std::uint32_t size = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC); + std::uint32_t sizeOfImage = imageLoader.getSizeOfImage(); + + // Check for relocations out of image + if(rva >= sizeOfImage || (rva + size) > sizeOfImage) + { + RelocationsDirectory::setLoaderError(LDR_ERROR_RELOCATIONS_OUT_OF_IMAGE); + return ERROR_INVALID_FILE; + } + + // Read the entire relocation directory from the image + std::vector vRelocDirectory(size); + imageLoader.readImage(vRelocDirectory.data(), rva, size); + + // Parse the relocations directory + read(vRelocDirectory.data(), size, sizeOfImage); + return ERROR_NONE; + } + /** * Get the error that was detected during parsing of relocations **/ @@ -43,24 +65,29 @@ namespace PeLib m_vRelocations[ulRelocation].vRelocData[ulDataNumber] = wData; } - void RelocationsDirectory::read(InputBuffer& inputbuffer, unsigned int uiSize, unsigned int sizeOfImage) + void RelocationsDirectory::read(const std::uint8_t * data, std::uint32_t uiSize, std::uint32_t sizeOfImage) { - std::vector vCurrReloc; - unsigned int offset = 0; + const std::uint8_t * dataEnd = data + uiSize; + + // Clear the current relocations + m_vRelocations.clear(); - // The entire relocation block consists of these parts: - // 1) IMG_BASE_RELOC followed by array of USHORTs. - // 2) IMG_BASE_RELOC followed by array of USHORTs - // and so on, up to uiSize - while((offset + PELIB_IMAGE_SIZEOF_BASE_RELOCATION) < uiSize) + // The entire relocation block looks like this: + // * PELIB_IMAGE_BASE_RELOCATION (header of block) + // * array of relocation entry, each has 2 bytes + // * PELIB_IMAGE_BASE_RELOCATION (header of next block) + // * array of relocation entry, each has 2 bytes + // ... and so on, up to uiSize + while((data + PELIB_IMAGE_SIZEOF_BASE_RELOCATION) < dataEnd) { + const PELIB_IMAGE_BASE_RELOCATION * pRelocBlock = (const PELIB_IMAGE_BASE_RELOCATION *)data; IMG_BASE_RELOC ibrCurr; - // Retrieve the single IMG_BASE_RELOC entry. - // Note that SizeOfBlock contains size of IMG_BASE_RELOC itself + // Retrieve the single PELIB_IMAGE_BASE_RELOCATION entry. + // Note that SizeOfBlock contains size of PELIB_IMAGE_BASE_RELOCATION itself // plus sizes of all subsequent fixup entries - inputbuffer >> ibrCurr.ibrRelocation.VirtualAddress; - inputbuffer >> ibrCurr.ibrRelocation.SizeOfBlock; + ibrCurr.ibrRelocation.VirtualAddress = pRelocBlock->VirtualAddress; + ibrCurr.ibrRelocation.SizeOfBlock = pRelocBlock->SizeOfBlock; // Verify whether the base virtual address is within the image if(ibrCurr.ibrRelocation.VirtualAddress > sizeOfImage) @@ -68,35 +95,35 @@ namespace PeLib setLoaderError(LDR_ERROR_RELOC_BLOCK_INVALID_VA); break; } - if((offset + ibrCurr.ibrRelocation.SizeOfBlock) > uiSize) + if((data + ibrCurr.ibrRelocation.SizeOfBlock) > dataEnd) { setLoaderError(LDR_ERROR_RELOC_BLOCK_INVALID_LENGTH); break; } // Move the offset by the size of relocation block structure - offset += PELIB_IMAGE_SIZEOF_BASE_RELOCATION; + data += PELIB_IMAGE_SIZEOF_BASE_RELOCATION; // Prevent underflow caused by size smaller than PELIB_IMAGE_SIZEOF_BASE_RELOCATION. // Example: \retdec-regression-tests\tools\fileinfo\detection\packers\securom\sample_securom_003.dat if(ibrCurr.ibrRelocation.SizeOfBlock >= PELIB_IMAGE_SIZEOF_BASE_RELOCATION) { // Get the number of fixup entries - unsigned int numberOfEntries = (ibrCurr.ibrRelocation.SizeOfBlock - PELIB_IMAGE_SIZEOF_BASE_RELOCATION) / sizeof(uint16_t); - for (unsigned int i = 0; i < numberOfEntries; i++) - { - uint16_t typeAndOffset; + const std::uint16_t * typeAndOffsets = (const std::uint16_t *)(pRelocBlock + 1); + std::uint32_t numberOfEntries = (ibrCurr.ibrRelocation.SizeOfBlock - PELIB_IMAGE_SIZEOF_BASE_RELOCATION) / sizeof(uint16_t); + for (std::uint32_t i = 0; i < numberOfEntries; i++) + { // Read the type and offset - if(inputbuffer.get() + sizeof(uint16_t) > uiSize) + if((data + sizeof(std::uint16_t)) > dataEnd) break; - inputbuffer >> typeAndOffset; + uint16_t typeAndOffset = typeAndOffsets[i]; // Verify the type and offset switch(typeAndOffset >> 12) { case PELIB_IMAGE_REL_BASED_HIGHADJ: // This relocation entry occupies two entries - offset += sizeof(uint16_t); + data += sizeof(uint16_t); // No break here! case PELIB_IMAGE_REL_BASED_ABSOLUTE: @@ -118,24 +145,13 @@ namespace PeLib // Push the relocation entry to the list ibrCurr.vRelocData.push_back(typeAndOffset); - offset += sizeof(uint16_t); + data += sizeof(uint16_t); } - vCurrReloc.push_back(ibrCurr); + + // Push the data to the relocations vector + m_vRelocations.push_back(ibrCurr); } } - - std::swap(vCurrReloc, m_vRelocations); - } - - // TODO: Return value is wrong if buffer was too small. - int RelocationsDirectory::read(const unsigned char* buffer, unsigned int buffersize, unsigned int sizeOfImage) - { - std::vector vRelocDirectory(buffer, buffer + buffersize); - - InputBuffer ibBuffer(vRelocDirectory); - read(ibBuffer, buffersize, sizeOfImage); - - return ERROR_NONE; } unsigned int RelocationsDirectory::size() const From 6405bd9d28c554b3ebc8371d5a6f4a7f3f9614c2 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 24 Jun 2020 15:11:30 +0200 Subject: [PATCH 08/34] ImageLoader: Regression Tests 1 --- .../fileformat/file_format/pe/pe_format.h | 11 +- .../file_format/pe/pe_format_parser.h | 646 ++++++++++++++ .../pe/pe_format_parser/pe_format_parser.h | 99 --- .../pe/pe_format_parser/pe_format_parser32.h | 95 -- .../pe/pe_format_parser/pe_format_parser64.h | 95 -- .../fileformat/file_format/pe/pe_template.h | 17 +- include/retdec/pelib/BoundImportDirectory.h | 1 - include/retdec/pelib/DelayImportDirectory.h | 1 - include/retdec/pelib/IatDirectory.h | 1 - include/retdec/pelib/ImageLoader.h | 174 +++- include/retdec/pelib/ImportDirectory.h | 7 +- include/retdec/pelib/MzHeader.h | 2 + include/retdec/pelib/PeFile.h | 827 +++--------------- include/retdec/pelib/PeHeader.h | 2 + include/retdec/pelib/PeLibAux.h | 56 +- include/retdec/pelib/ResourceDirectory.h | 1 - include/retdec/pelib/SecurityDirectory.h | 2 - src/cpdetect/heuristics/pe_heuristics.cpp | 8 +- src/fileformat/CMakeLists.txt | 3 - src/fileformat/file_format/pe/pe_format.cpp | 55 +- .../pe/pe_format_parser/pe_format_parser.cpp | 241 ----- .../pe_format_parser/pe_format_parser32.cpp | 369 -------- .../pe_format_parser/pe_format_parser64.cpp | 369 -------- src/fileformat/utils/format_detection.cpp | 37 +- src/fileinfo/CMakeLists.txt | 5 +- src/fileinfo/file_detector/pe_detector.cpp | 14 +- src/fileinfo/file_detector/pe_detector.h | 2 +- .../file_information_types/file_section.cpp | 2 +- .../file_information_types/file_section.h | 2 +- src/fileinfo/file_wrapper/pe/pe_template.h | 74 -- src/fileinfo/file_wrapper/pe/pe_wrapper.cpp | 220 ----- src/fileinfo/file_wrapper/pe/pe_wrapper.h | 41 - .../pe_wrapper_parser/pe_wrapper_parser.cpp | 35 - .../pe/pe_wrapper_parser/pe_wrapper_parser.h | 34 - .../pe_wrapper_parser/pe_wrapper_parser32.cpp | 32 - .../pe_wrapper_parser/pe_wrapper_parser32.h | 33 - .../pe_wrapper_parser/pe_wrapper_parser64.cpp | 32 - .../pe_wrapper_parser/pe_wrapper_parser64.h | 33 - src/pelib/CMakeLists.txt | 2 - src/pelib/ComHeaderDirectory.cpp | 2 +- src/pelib/ImageLoader.cpp | 472 +++++----- src/pelib/PeFile.cpp | 447 +++++++++- src/pelib/PeLibAux.cpp | 114 --- src/pelib/RelocationsDirectory.cpp | 2 +- src/pelib/ResourceDirectory.cpp | 5 +- src/unpackertool/plugins/mpress/mpress.cpp | 56 +- src/unpackertool/plugins/mpress/mpress.h | 2 +- .../plugins/upx/pe/pe_upx_stub.cpp | 54 +- src/unpackertool/plugins/upx/pe/pe_upx_stub.h | 4 +- src/unpackertool/plugins/upx/upx_stub.cpp | 8 +- 50 files changed, 1750 insertions(+), 3096 deletions(-) create mode 100644 include/retdec/fileformat/file_format/pe/pe_format_parser.h delete mode 100644 include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h delete mode 100644 include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.h delete mode 100644 include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.h delete mode 100644 src/fileformat/file_format/pe/pe_format_parser/pe_format_parser.cpp delete mode 100644 src/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.cpp delete mode 100644 src/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.cpp delete mode 100644 src/fileinfo/file_wrapper/pe/pe_template.h delete mode 100644 src/fileinfo/file_wrapper/pe/pe_wrapper.cpp delete mode 100644 src/fileinfo/file_wrapper/pe/pe_wrapper.h delete mode 100644 src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.cpp delete mode 100644 src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.h delete mode 100644 src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.cpp delete mode 100644 src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.h delete mode 100644 src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.cpp delete mode 100644 src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.h diff --git a/include/retdec/fileformat/file_format/pe/pe_format.h b/include/retdec/fileformat/file_format/pe/pe_format.h index 140f1aae2..25f7d2de6 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format.h +++ b/include/retdec/fileformat/file_format/pe/pe_format.h @@ -8,7 +8,7 @@ #define RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_H #include "retdec/fileformat/file_format/file_format.h" -#include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h" +#include "retdec/fileformat/file_format/pe/pe_format_parser.h" #include "retdec/fileformat/types/dotnet_headers/blob_stream.h" #include "retdec/fileformat/types/dotnet_headers/guid_stream.h" #include "retdec/fileformat/types/dotnet_headers/metadata_stream.h" @@ -32,7 +32,6 @@ class PeFormat : public FileFormat { private: PeFormatParser *formatParser; ///< parser of PE file - PeLib::MzHeader mzHeader; ///< MZ header std::unique_ptr clrHeader; ///< .NET CLR header std::unique_ptr metadataHeader; ///< .NET metadata header std::unique_ptr metadataStream; ///< .NET metadata stream @@ -123,9 +122,7 @@ class PeFormat : public FileFormat void scanForOptHeaderAnomalies(); /// @} protected: - PeLib::PeFile *file; ///< PeLib representation of PE file - PeLib::PeHeaderT<32> *peHeader32; ///< header of 32-bit PE file - PeLib::PeHeaderT<64> *peHeader64; ///< header of 64-bit PE file + PeLib::PeFileT *file; ///< PeLib representation of PE file public: PeFormat(const std::string & pathToFile, const std::string & dllListFile, LoadFlags loadFlags = LoadFlags::NONE); PeFormat(std::istream &inputStream, LoadFlags loadFlags = LoadFlags::NONE); @@ -162,7 +159,7 @@ class PeFormat : public FileFormat /// @name Detection methods /// @{ - const PeLib::MzHeader & getMzHeader() const; + const PeLib::ImageLoader & getImageLoader() const; std::size_t getMzHeaderSize() const; std::size_t getOptionalHeaderSize() const; std::size_t getPeHeaderOffset() const; @@ -191,8 +188,6 @@ class PeFormat : public FileFormat bool dllListFailedToLoad() const; bool initDllList(const std::string & dllListFile); - PeLib::PeFile32* isPe32() const; - PeLib::PeFile64* isPe64() const; bool isDotNet() const; bool isPackedDotNet() const; bool isVisualBasic(unsigned long long &version) const; diff --git a/include/retdec/fileformat/file_format/pe/pe_format_parser.h b/include/retdec/fileformat/file_format/pe/pe_format_parser.h new file mode 100644 index 000000000..102d40a13 --- /dev/null +++ b/include/retdec/fileformat/file_format/pe/pe_format_parser.h @@ -0,0 +1,646 @@ +/** + * @file include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h + * @brief Definition of PeFormatParser class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER_H +#define RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER_H + +#include "retdec/common/range.h" +#include "retdec/utils/alignment.h" +#include "retdec/utils/string.h" +#include "retdec/fileformat/fftypes.h" +#include "retdec/pelib/PeLib.h" + +namespace retdec { +namespace fileformat { + +class FileFormat; + +class PeFormatParser +{ + protected: + + const FileFormat *inputFile; ///< pointer to input file + PeLib::PeFileT *peFile; ///< 32-bit PE file + + public: + + PeFormatParser(const FileFormat *fInputFile, PeLib::PeFileT *inputPeFile) : inputFile(fInputFile), peFile(inputPeFile) + {} + + virtual ~PeFormatParser() = default; + + /// @name Detection methods + /// @{ + + std::uint32_t getPointerSize() const + { + return peFile->imageLoader().getPointerSize(); + } + + std::uint32_t getPeHeaderOffset() const + { + return peFile->imageLoader().getPeHeaderOffset(); + } + + std::uint32_t getDeclaredNumberOfSections() const + { + return peFile->imageLoader().getFileHeader().NumberOfSections; + } + + std::uint32_t getStoredNumberOfSections() const + { + return peFile->imageLoader().getNumberOfSections(); + } + + std::uint32_t getMachineType() const + { + return peFile->imageLoader().getMachine(); + } + + std::uint64_t getImageBaseAddress() const + { + return peFile->imageLoader().getImageBase(); + } + + std::uint32_t getCoffSymbolTableOffset() const + { + return peFile->imageLoader().getPointerToSymbolTable(); + } + + std::uint32_t getNumberOfCoffSymbols() const + { + return peFile->imageLoader().getNumberOfSymbols(); + } + + std::uint32_t getMajorLinkerVersion() const + { + return peFile->imageLoader().getOptionalHeader().MajorLinkerVersion; + } + + std::uint32_t getMinorLinkerVersion() const + { + return peFile->imageLoader().getOptionalHeader().MinorLinkerVersion; + } + + std::uint32_t getFileFlags() const + { + return peFile->imageLoader().getFileHeader().Characteristics; + } + + std::uint32_t getTimeStamp() const + { + return peFile->imageLoader().getFileHeader().TimeDateStamp; + } + + std::uint32_t getOptionalHeaderSize() const + { + return peFile->imageLoader().getFileHeader().SizeOfOptionalHeader; + } + + bool isSizeOfHeaderMultipleOfFileAlignment() const + { + std::uint64_t remainder; + return retdec::utils::isAligned(peFile->imageLoader().getSizeOfHeaders(), + peFile->imageLoader().getFileAlignment(), + remainder); + } + + std::uint32_t getFileAlignment() const + { + return peFile->imageLoader().getFileAlignment(); + } + + std::uint32_t getSectionAlignment() const + { + return peFile->imageLoader().getSectionAlignment(); + } + + std::uint32_t getSizeOfHeaders() const + { + return peFile->imageLoader().getSizeOfHeaders(); + } + + std::uint32_t getSizeOfImage() const + { + return peFile->imageLoader().getSizeOfImage(); + } + + std::uint32_t getChecksum() const + { + return peFile->imageLoader().getOptionalHeader().CheckSum; + } + + std::uint64_t getSizeOfStackReserve() const + { + return peFile->imageLoader().getOptionalHeader().SizeOfStackReserve; + } + + std::uint64_t getSizeOfStackCommit() const + { + return peFile->imageLoader().getOptionalHeader().SizeOfStackCommit; + } + + std::uint64_t getSizeOfHeapReserve() const + { + return peFile->imageLoader().getOptionalHeader().SizeOfHeapReserve; + } + + std::uint64_t getSizeOfHeapCommit() const + { + return peFile->imageLoader().getOptionalHeader().SizeOfHeapCommit; + } + + std::uint32_t getSizeOfPeSignature() const + { + return sizeof(std::uint32_t); + } + + std::uint32_t getLoadedSizeOfNtHeaders() const + { + return peFile->imageLoader().getFileHeader().SizeOfOptionalHeader; + } + + std::uint32_t getAllocatedSizeOfNtHeaders() const + { + return peFile->imageLoader().getFileHeader().SizeOfOptionalHeader; + } + + std::uint32_t getDeclaredNumberOfDataDirectories() const + { + return peFile->imageLoader().getOptionalHeader().NumberOfRvaAndSizes; + } + + std::uint32_t getStoredNumberOfDataDirectories() const + { + std::uint32_t numberOfRvaAndSizes = peFile->imageLoader().getOptionalHeader().NumberOfRvaAndSizes; + return std::min(numberOfRvaAndSizes, PeLib::PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES); + } + + std::uint32_t getNumberOfImportedLibraries() const + { + return peFile->impDir().getNumberOfFiles(PeLib::OLDDIR); + } + + std::uint32_t getNumberOfDelayImportedLibraries() const + { + return peFile->delayImports().getNumberOfFiles(); + } + + bool isDll() const + { + return (peFile->imageLoader().getCharacteristics() & PeLib::PELIB_IMAGE_FILE_DLL); + } + + bool getEpAddress(std::uint64_t & epAddress) const + { + std::uint64_t imageBase = peFile->imageLoader().getImageBase(); + std::uint32_t entryPoint = peFile->imageLoader().getOptionalHeader().AddressOfEntryPoint; + + epAddress = imageBase + entryPoint; + return true; + } + + bool getEpOffset(std::uint64_t & epOffset) const + { + std::uint32_t entryPoint = peFile->imageLoader().getOptionalHeader().AddressOfEntryPoint; + epOffset = peFile->imageLoader().getFileOffsetFromRva(entryPoint); + + return (epOffset != UINT32_MAX); + } + + bool getSectionType(const PeLib::PELIB_SECTION_HEADER * pSectionHeader, PeCoffSection::Type & secType) const + { + std::uint32_t Characteristics = pSectionHeader->Characteristics; + + if(Characteristics & (PeLib::PELIB_IMAGE_SCN_CNT_CODE | PeLib::PELIB_IMAGE_SCN_MEM_EXECUTE)) + { + secType = PeCoffSection::Type::CODE; + } + else if(Characteristics & PeLib::PELIB_IMAGE_SCN_CNT_UNINITIALIZED_DATA) + { + secType = PeCoffSection::Type::BSS; + } + else if(Characteristics & PeLib::PELIB_IMAGE_SCN_MEM_DISCARDABLE && retdec::utils::startsWith(pSectionHeader->getName(), ".debug_")) + { + secType = PeCoffSection::Type::DEBUG; + } + else if(Characteristics & PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA) + { + secType = (!(Characteristics & PeLib::PELIB_IMAGE_SCN_MEM_WRITE)) ? PeCoffSection::Type::CONST_DATA : PeCoffSection::Type::DATA; + } + else if(Characteristics & PeLib::PELIB_IMAGE_SCN_LNK_INFO) + { + secType = PeCoffSection::Type::INFO; + } + else + { + secType = PeCoffSection::Type::UNDEFINED_SEC_SEG; + } + + return true; + } + + bool getSection(std::size_t secIndex, PeCoffSection §ion) const + { + const PeLib::PELIB_SECTION_HEADER * pSectionHeader; + PeCoffSection::Type sectionType; + PeLib::ImageLoader & imageLoader = peFile->imageLoader(); + std::string sectionName; + + // Retrieve the section header. If the function returns nullptr, then there is no such section + if((pSectionHeader = imageLoader.getSectionHeader(secIndex)) == nullptr) + return false; + if(!getSectionType(pSectionHeader, sectionType)) + return false; + + section.setName(pSectionHeader->getName()); + section.setType(sectionType); + section.setIndex(secIndex); + section.setOffset(imageLoader.getRealPointerToRawData(secIndex)); + section.setSizeInFile(pSectionHeader->SizeOfRawData); + section.setSizeInMemory(pSectionHeader->VirtualSize); + section.setAddress(pSectionHeader->VirtualAddress ? imageLoader.getImageBase() + pSectionHeader->VirtualAddress : 0); + section.setMemory(section.getAddress()); + section.setPeCoffFlags(pSectionHeader->Characteristics); + section.load(inputFile); + return true; + } + + bool getDllFlags(unsigned long long & dllFlags) const + { + if(peFile->imageLoader().getCharacteristics() & PeLib::PELIB_IMAGE_FILE_DLL) + { + dllFlags = peFile->imageLoader().getCharacteristics(); + return true; + } + + return false; + } + + bool getDataDirectoryRelative(unsigned long long index, unsigned long long &relAddr, unsigned long long &size) const + { + relAddr = peFile->imageLoader().getDataDirRva(index); + size = peFile->imageLoader().getDataDirSize(index); + return (relAddr != 0); + } + + bool getDataDirectoryAbsolute(unsigned long long index, unsigned long long &absAddr, unsigned long long &size) const + { + if(getDataDirectoryRelative(index, absAddr, size)) + { + absAddr += peFile->imageLoader().getImageBase(); + return true; + } + + return false; + } + + bool getImportedLibraryFileName(std::uint32_t index, std::string &fileName) const + { + const auto & imports = peFile->impDir(); + + if(index >= imports.getNumberOfFiles(PeLib::OLDDIR)) + return false; + + fileName = imports.getFileName(index, PeLib::OLDDIR); + return true; + } + + bool getDelayImportedLibraryFileName(unsigned long long index, std::string &fileName) const + { + const auto & delayImports = peFile->delayImports(); + + if(index >= delayImports.getNumberOfFiles()) + return false; + + fileName = delayImports.getFile(index)->Name; + return true; + } + + std::unique_ptr getImport(unsigned long long fileIndex, unsigned long long importIndex) const + { + const PeLib::ImportDirectory & peImports = peFile->impDir(); + const auto ordinalMask = peFile->imageLoader().getOrdinalMask(); + const auto bits = peFile->imageLoader().getImageBitability(); + + if(fileIndex >= peImports.getNumberOfFiles(PeLib::OLDDIR) || + importIndex >= peImports.getNumberOfFunctions(fileIndex, PeLib::OLDDIR)) + { + return nullptr; + } + + auto isOrdinalNumberValid = true; + unsigned long long ordinalNumber = peImports.getFunctionHint(fileIndex, importIndex, PeLib::OLDDIR); + if(!ordinalNumber) + { + const auto firstThunk = peImports.getFirstThunk(fileIndex, importIndex, PeLib::OLDDIR); + const auto originalFirstThunk = peImports.getOriginalFirstThunk(fileIndex, importIndex, PeLib::OLDDIR); + if(firstThunk & ordinalMask) + { + ordinalNumber = firstThunk - ordinalMask; + } + else if(originalFirstThunk & ordinalMask) + { + ordinalNumber = originalFirstThunk - ordinalMask; + } + else + { + isOrdinalNumberValid = false; + } + } + + auto import = std::make_unique(PeImportFlag::None); + if(isOrdinalNumberValid) + { + import->setOrdinalNumber(ordinalNumber); + } + else + { + import->invalidateOrdinalNumber(); + } + import->setName(peImports.getFunctionName(fileIndex, importIndex, PeLib::OLDDIR)); + import->setAddress(peFile->imageLoader().getImageBase() + peImports.getFirstThunk(fileIndex, PeLib::OLDDIR) + importIndex * (bits / 8)); + import->setLibraryIndex(fileIndex); + return import; + } + + std::unique_ptr getDelayImport(unsigned long long fileIndex, unsigned long long importIndex) const + { + const PeLib::DelayImportDirectory & delayImports = peFile->delayImports(); + const auto *library = delayImports.getFile(fileIndex); + + if(!library) + { + return nullptr; + } + + const auto *function = library->getFunction(importIndex); + if(!function) + { + return nullptr; + } + + auto import = std::make_unique(PeImportFlag::Delayed); + import->setName(function->fname); + import->setAddress(peFile->imageLoader().getImageBase() + function->address); + import->setLibraryIndex(fileIndex); + import->invalidateOrdinalNumber(); + if(library->ordinalNumbersAreValid() && function->hint != 0) + { + import->setOrdinalNumber(function->hint); + } + + return import; + } + + std::uint32_t getNumberOfExportedFunctions() const + { + return peFile->expDir().calcNumberOfFunctions(); + } + + bool getExportedFunction(unsigned long long index, Export& exportedFunction) const + { + const PeLib::ExportDirectory & exports = peFile->expDir(); + const PeLib::ImageLoader & imageLoader = peFile->imageLoader(); + + if (index >= exports.calcNumberOfFunctions()) + { + return false; + } + + exportedFunction.setAddress(exports.getAddressOfFunction(index) + imageLoader.getImageBase()); + exportedFunction.setOrdinalNumber(exports.getFunctionOrdinal(index)); + exportedFunction.setName(exports.getFunctionName(index)); + return true; + } + + std::uint32_t getNumberOfDebugEntries() const + { + return peFile->debugDir().calcNumberOfEntries(); + } + + bool getDebugEntryData(unsigned long long index, std::vector& data) const + { + const PeLib::DebugDirectory & debug = peFile->debugDir(); + + if (index < debug.calcNumberOfEntries()) + { + data = debug.getData(index); + return true; + } + + return false; + } + + bool getDebugEntryTimeDateStamp(unsigned long long index, unsigned long long& timeDateStamp) const + { + const PeLib::DebugDirectory & debug = peFile->debugDir(); + + if (index < debug.calcNumberOfEntries()) + { + timeDateStamp = debug.getTimeDateStamp(index); + return true; + } + + return false; + } + + bool getDebugEntryPointerToRawData(unsigned long long index, unsigned long long& pointerToRawData) const + { + const PeLib::DebugDirectory & debug = peFile->debugDir(); + + if (index < debug.calcNumberOfEntries()) + { + pointerToRawData = debug.getPointerToRawData(index); + return true; + } + + return false; + } + + std::uint32_t getResourceDirectoryOffset() const + { + return peFile->resDir().getOffset(); + } + + const PeLib::ResourceNode* getResourceTreeRoot() const + { + return peFile->resDir().getRoot(); + } + + std::uint64_t getTlsStartAddressOfRawData() const + { + return peFile->tlsDir().getStartAddressOfRawData(); + } + + std::uint64_t getTlsEndAddressOfRawData() const + { + return peFile->tlsDir().getEndAddressOfRawData(); + } + + std::uint64_t getTlsAddressOfIndex() const + { + return peFile->tlsDir().getAddressOfIndex(); + } + + std::uint64_t getTlsAddressOfCallBacks() const + { + return peFile->tlsDir().getAddressOfCallBacks(); + } + + std::uint32_t getTlsSizeOfZeroFill() const + { + return peFile->tlsDir().getSizeOfZeroFill(); + } + + std::uint32_t getTlsCharacteristics() const + { + return peFile->tlsDir().getCharacteristics(); + } + + std::unique_ptr getClrHeader() const + { + const auto & comHeader = peFile->comDir(); + auto clrHeader = std::make_unique(); + + clrHeader->setHeaderSize(comHeader.getSizeOfHeader()); + clrHeader->setMajorRuntimeVersion(comHeader.getMajorRuntimeVersion()); + clrHeader->setMinorRuntimeVersion(comHeader.getMinorRuntimeVersion()); + clrHeader->setMetadataDirectoryAddress(comHeader.getMetaDataVa()); + clrHeader->setMetadataDirectorySize(comHeader.getMetaDataSize()); + clrHeader->setFlags(comHeader.getFlags()); + clrHeader->setEntryPointToken(comHeader.getEntryPointToken()); + clrHeader->setResourcesAddress(comHeader.getResourcesVa()); + clrHeader->setResourcesSize(comHeader.getResourcesSize()); + clrHeader->setStrongNameSignatureAddress(comHeader.getStrongNameSignatureVa()); + clrHeader->setStrongNameSignatureSize(comHeader.getStrongNameSignatureSize()); + clrHeader->setCodeManagerTableAddress(comHeader.getCodeManagerTableVa()); + clrHeader->setCodeManagerTableSize(comHeader.getCodeManagerTableSize()); + clrHeader->setVTableFixupsDirectoryAddress(comHeader.getVTableFixupsVa()); + clrHeader->setVTableFixupsDirectorySize(comHeader.getVTableFixupsSize()); + clrHeader->setExportAddressTableAddress(comHeader.getExportAddressTableJumpsVa()); + clrHeader->setExportAddressTableSize(comHeader.getExportAddressTableJumpsSize()); + clrHeader->setPrecompileHeaderAddress(comHeader.getManagedNativeHeaderVa()); + clrHeader->setPrecompileHeaderSize(comHeader.getManagedNativeHeaderSize()); + return clrHeader; + } + + std::uint32_t getNumberOfRelocations() const + { + return peFile->relocDir().calcNumberOfRelocations(); + } + + std::uint32_t getNumberOfRelocationData(std::uint32_t index) const + { + return peFile->relocDir().calcNumberOfRelocationData(index); + } + + std::uint64_t getChecksumFileOffset() const + { + return peFile->imageLoader().getChecksumFileOffset(); + } + + std::uint64_t getSecurityDirFileOffset() const + { + return peFile->imageLoader().getSecurityDirFileOffset(); + } + + std::uint32_t getSecurityDirRva() const + { + return peFile->imageLoader().getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY); + } + + std::uint32_t getSecurityDirSize() const + { + return peFile->imageLoader().getDataDirSize(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY); + } + + retdec::common::RangeContainer getImportDirectoryOccupiedAddresses() const + { + retdec::common::RangeContainer result; + const auto & peImports = peFile->impDir(); + + for (const auto& addresses : peImports.getOccupiedAddresses()) + { + try + { + result.insert(addresses.first, addresses.second); + } + catch (const retdec::common::InvalidRangeException&) + { + continue; + } + } + + return result; + } + + retdec::common::RangeContainer getExportDirectoryOccupiedAddresses() const + { + retdec::common::RangeContainer result; + const auto & peExports = peFile->expDir(); + + for (const auto& addresses : peExports.getOccupiedAddresses()) + { + try + { + result.insert(addresses.first, addresses.second); + } + catch (const retdec::common::InvalidRangeException&) + { + continue; + } + } + + return result; + } + + retdec::common::RangeContainer getDebugDirectoryOccupiedAddresses() const + { + retdec::common::RangeContainer result; + const auto & peDebug = peFile->debugDir(); + + for (const auto& addresses : peDebug.getOccupiedAddresses()) + { + try + { + result.insert(addresses.first, addresses.second); + } + catch (const retdec::common::InvalidRangeException&) + { + continue; + } + } + + return result; + } + + retdec::common::RangeContainer getResourceDirectoryOccupiedAddresses() const + { + retdec::common::RangeContainer result; + const auto & peResources = peFile->resDir(); + + for (const auto& addresses : peResources.getOccupiedAddresses()) + { + try + { + result.insert(addresses.first, addresses.second); + } + catch (const retdec::common::InvalidRangeException&) + { + continue; + } + } + + return result; + } + +}; + +} // namespace fileformat +} // namespace retdec + +#endif diff --git a/include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h b/include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h deleted file mode 100644 index 8c5f4d200..000000000 --- a/include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h - * @brief Definition of PeFormatParser class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER_H -#define RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER_H - -#include "retdec/common/range.h" -#include "retdec/fileformat/fftypes.h" -#include "retdec/pelib/PeLib.h" - -namespace retdec { -namespace fileformat { - -class FileFormat; - -class PeFormatParser -{ - protected: - const FileFormat *inputFile; ///< pointer to input file - public: - PeFormatParser(const FileFormat *fInputFile); - virtual ~PeFormatParser() = default; - - /// @name Detection methods - /// @{ - virtual unsigned long long getDeclaredNumberOfSections() const = 0; - virtual unsigned long long getStoredNumberOfSections() const = 0; - virtual unsigned long long getMachineType() const = 0; - virtual unsigned long long getImageBaseAddress() const = 0; - virtual unsigned long long getCoffSymbolTableOffset() const = 0; - virtual unsigned long long getNumberOfCoffSymbols() const = 0; - virtual unsigned long long getMajorLinkerVersion() const = 0; - virtual unsigned long long getMinorLinkerVersion() const = 0; - virtual unsigned long long getFileFlags() const = 0; - virtual unsigned long long getTimeStamp() const = 0; - virtual unsigned long long getOptionalHeaderSize() const = 0; - virtual bool isSizeOfHeaderMultipleOfFileAlignment() const = 0; - virtual unsigned long long getFileAlignment() const = 0; - virtual unsigned long long getSectionAlignment() const = 0; - virtual unsigned long long getSizeOfHeaders() const = 0; - virtual unsigned long long getSizeOfImage() const = 0; - virtual unsigned long long getChecksum() const = 0; - virtual unsigned long long getSizeOfStackReserve() const = 0; - virtual unsigned long long getSizeOfStackCommit() const = 0; - virtual unsigned long long getSizeOfHeapReserve() const = 0; - virtual unsigned long long getSizeOfHeapCommit() const = 0; - virtual unsigned long long getSizeOfPeSignature() const = 0; - virtual unsigned long long getLoadedSizeOfNtHeaders() const = 0; - virtual unsigned long long getAllocatedSizeOfNtHeaders() const = 0; - virtual unsigned long long getDeclaredNumberOfDataDirectories() const = 0; - virtual unsigned long long getStoredNumberOfDataDirectories() const = 0; - virtual unsigned long long getNumberOfImportedLibraries() const = 0; - virtual unsigned long long getNumberOfDelayImportedLibraries() const = 0; - virtual bool isDll() const = 0; - virtual bool getEpAddress(unsigned long long &epAddress) const = 0; - virtual bool getEpOffset(unsigned long long &epOffset) const = 0; - virtual bool getSection(unsigned long long secIndex, PeCoffSection §ion) const = 0; - virtual bool getDllFlags(unsigned long long &dllFlags) const = 0; - virtual bool getDataDirectoryRelative(unsigned long long index, unsigned long long &relAddr, unsigned long long &size) const = 0; - virtual bool getDataDirectoryAbsolute(unsigned long long index, unsigned long long &absAddr, unsigned long long &size) const = 0; - virtual bool getImportedLibraryFileName(unsigned long long index, std::string &fileName) const = 0; - virtual bool getDelayImportedLibraryFileName(unsigned long long index, std::string &fileName) const = 0; - virtual std::unique_ptr getImport(unsigned long long fileIndex, unsigned long long importIndex) const = 0; - virtual std::unique_ptr getDelayImport(unsigned long long fileIndex, unsigned long long importIndex) const = 0; - virtual unsigned long long getNumberOfExportedFunctions() const = 0; - virtual bool getExportedFunction(unsigned long long index, Export& exportedFunction) const = 0; - virtual unsigned long long getNumberOfDebugEntries() const = 0; - virtual bool getDebugEntryData(unsigned long long index, std::vector& data) const = 0; - virtual bool getDebugEntryTimeDateStamp(unsigned long long index, unsigned long long& timeDateStamp) const = 0; - virtual bool getDebugEntryPointerToRawData(unsigned long long index, unsigned long long& pointerToRawData) const = 0; - virtual unsigned long long getResourceDirectoryOffset() const = 0; - virtual const PeLib::ResourceNode* getResourceTreeRoot() const = 0; - virtual unsigned long long getTlsStartAddressOfRawData() const = 0; - virtual unsigned long long getTlsEndAddressOfRawData() const = 0; - virtual unsigned long long getTlsAddressOfIndex() const = 0; - virtual unsigned long long getTlsAddressOfCallBacks() const = 0; - virtual unsigned long long getTlsSizeOfZeroFill() const = 0; - virtual unsigned long long getTlsCharacteristics() const = 0; - virtual std::unique_ptr getClrHeader() const = 0; - virtual unsigned long long getNumberOfRelocations() const = 0; - virtual unsigned long long getNumberOfRelocationData(unsigned long long index) const = 0; - virtual unsigned long long getChecksumFileOffset() const = 0; - virtual unsigned long long getSecurityDirFileOffset() const = 0; - virtual unsigned long long getSecurityDirRva() const = 0; - virtual unsigned long long getSecurityDirSize() const = 0; - virtual retdec::common::RangeContainer getImportDirectoryOccupiedAddresses() const = 0; - virtual retdec::common::RangeContainer getExportDirectoryOccupiedAddresses() const = 0; - virtual retdec::common::RangeContainer getDebugDirectoryOccupiedAddresses() const = 0; - virtual retdec::common::RangeContainer getResourceDirectoryOccupiedAddresses() const = 0; - /// @} -}; - -} // namespace fileformat -} // namespace retdec - -#endif diff --git a/include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.h b/include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.h deleted file mode 100644 index 0a359d94d..000000000 --- a/include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @file include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.h - * @brief Definition of PeFormatParser32 class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER32_H -#define RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER32_H - -#include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h" - -namespace retdec { -namespace fileformat { - -class PeFormatParser32 : public PeFormatParser -{ - private: - PeLib::PeFileT<32> *peFile; ///< 32-bit PE file - PeLib::PeHeaderT<32> &peHeader; ///< header of 32-bit PE file - public: - PeFormatParser32(const FileFormat *fInputFile, PeLib::PeFileT<32> *peFile32); - - /// @name Detection methods - /// @{ - virtual unsigned long long getDeclaredNumberOfSections() const override; - virtual unsigned long long getStoredNumberOfSections() const override; - virtual unsigned long long getMachineType() const override; - virtual unsigned long long getImageBaseAddress() const override; - virtual unsigned long long getCoffSymbolTableOffset() const override; - virtual unsigned long long getNumberOfCoffSymbols() const override; - virtual unsigned long long getMajorLinkerVersion() const override; - virtual unsigned long long getMinorLinkerVersion() const override; - virtual unsigned long long getFileFlags() const override; - virtual unsigned long long getTimeStamp() const override; - virtual unsigned long long getOptionalHeaderSize() const override; - virtual bool isSizeOfHeaderMultipleOfFileAlignment() const override; - virtual unsigned long long getFileAlignment() const override; - virtual unsigned long long getSectionAlignment() const override; - virtual unsigned long long getSizeOfHeaders() const override; - virtual unsigned long long getSizeOfImage() const override; - virtual unsigned long long getChecksum() const override; - virtual unsigned long long getSizeOfStackReserve() const override; - virtual unsigned long long getSizeOfStackCommit() const override; - virtual unsigned long long getSizeOfHeapReserve() const override; - virtual unsigned long long getSizeOfHeapCommit() const override; - virtual unsigned long long getSizeOfPeSignature() const override; - virtual unsigned long long getLoadedSizeOfNtHeaders() const override; - virtual unsigned long long getAllocatedSizeOfNtHeaders() const override; - virtual unsigned long long getDeclaredNumberOfDataDirectories() const override; - virtual unsigned long long getStoredNumberOfDataDirectories() const override; - virtual unsigned long long getNumberOfImportedLibraries() const override; - virtual unsigned long long getNumberOfDelayImportedLibraries() const override; - virtual bool isDll() const override; - virtual bool getEpAddress(unsigned long long &epAddress) const override; - virtual bool getEpOffset(unsigned long long &epOffset) const override; - virtual bool getSection(unsigned long long secIndex, PeCoffSection §ion) const override; - virtual bool getDllFlags(unsigned long long &dllFlags) const override; - virtual bool getDataDirectoryRelative(unsigned long long index, unsigned long long &relAddr, unsigned long long &size) const override; - virtual bool getDataDirectoryAbsolute(unsigned long long index, unsigned long long &absAddr, unsigned long long &size) const override; - virtual bool getImportedLibraryFileName(unsigned long long index, std::string &fileName) const override; - virtual bool getDelayImportedLibraryFileName(unsigned long long index, std::string &fileName) const override; - virtual std::unique_ptr getImport(unsigned long long fileIndex, unsigned long long importIndex) const override; - virtual std::unique_ptr getDelayImport(unsigned long long fileIndex, unsigned long long importIndex) const override; - virtual unsigned long long getNumberOfExportedFunctions() const override; - virtual bool getExportedFunction(unsigned long long index, Export& exportedFunction) const override; - virtual unsigned long long getNumberOfDebugEntries() const override; - virtual bool getDebugEntryData(unsigned long long index, std::vector& data) const override; - virtual bool getDebugEntryTimeDateStamp(unsigned long long index, unsigned long long& timeDateStamp) const override; - virtual bool getDebugEntryPointerToRawData(unsigned long long index, unsigned long long& pointerToRawData) const override; - virtual unsigned long long getResourceDirectoryOffset() const override; - virtual const PeLib::ResourceNode* getResourceTreeRoot() const override; - virtual unsigned long long getTlsStartAddressOfRawData() const override; - virtual unsigned long long getTlsEndAddressOfRawData() const override; - virtual unsigned long long getTlsAddressOfIndex() const override; - virtual unsigned long long getTlsAddressOfCallBacks() const override; - virtual unsigned long long getTlsSizeOfZeroFill() const override; - virtual unsigned long long getTlsCharacteristics() const override; - virtual std::unique_ptr getClrHeader() const override; - virtual unsigned long long getNumberOfRelocations() const override; - virtual unsigned long long getNumberOfRelocationData(unsigned long long index) const override; - virtual unsigned long long getChecksumFileOffset() const override; - virtual unsigned long long getSecurityDirFileOffset() const override; - virtual unsigned long long getSecurityDirRva() const override; - virtual unsigned long long getSecurityDirSize() const override; - virtual retdec::common::RangeContainer getImportDirectoryOccupiedAddresses() const override; - virtual retdec::common::RangeContainer getExportDirectoryOccupiedAddresses() const override; - virtual retdec::common::RangeContainer getDebugDirectoryOccupiedAddresses() const override; - virtual retdec::common::RangeContainer getResourceDirectoryOccupiedAddresses() const override; - /// @} -}; - -} // namespace fileformat -} // namespace retdec - -#endif diff --git a/include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.h b/include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.h deleted file mode 100644 index 68332dd7c..000000000 --- a/include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @file include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.h - * @brief Definition of PeFormatParser64 class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER64_H -#define RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER64_H - -#include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h" - -namespace retdec { -namespace fileformat { - -class PeFormatParser64 : public PeFormatParser -{ - private: - PeLib::PeFileT<64> *peFile; ///< 64-bit PE file - PeLib::PeHeaderT<64> &peHeader; ///< header of 64-bit PE file - public: - PeFormatParser64(const FileFormat *fInputFile, PeLib::PeFileT<64> *peFile64); - - /// @name Detection methods - /// @{ - virtual unsigned long long getDeclaredNumberOfSections() const override; - virtual unsigned long long getStoredNumberOfSections() const override; - virtual unsigned long long getMachineType() const override; - virtual unsigned long long getImageBaseAddress() const override; - virtual unsigned long long getCoffSymbolTableOffset() const override; - virtual unsigned long long getNumberOfCoffSymbols() const override; - virtual unsigned long long getMajorLinkerVersion() const override; - virtual unsigned long long getMinorLinkerVersion() const override; - virtual unsigned long long getFileFlags() const override; - virtual unsigned long long getTimeStamp() const override; - virtual unsigned long long getOptionalHeaderSize() const override; - virtual bool isSizeOfHeaderMultipleOfFileAlignment() const override; - virtual unsigned long long getFileAlignment() const override; - virtual unsigned long long getSectionAlignment() const override; - virtual unsigned long long getSizeOfHeaders() const override; - virtual unsigned long long getSizeOfImage() const override; - virtual unsigned long long getChecksum() const override; - virtual unsigned long long getSizeOfStackReserve() const override; - virtual unsigned long long getSizeOfStackCommit() const override; - virtual unsigned long long getSizeOfHeapReserve() const override; - virtual unsigned long long getSizeOfHeapCommit() const override; - virtual unsigned long long getSizeOfPeSignature() const override; - virtual unsigned long long getLoadedSizeOfNtHeaders() const override; - virtual unsigned long long getAllocatedSizeOfNtHeaders() const override; - virtual unsigned long long getDeclaredNumberOfDataDirectories() const override; - virtual unsigned long long getStoredNumberOfDataDirectories() const override; - virtual unsigned long long getNumberOfImportedLibraries() const override; - virtual unsigned long long getNumberOfDelayImportedLibraries() const override; - virtual bool isDll() const override; - virtual bool getEpAddress(unsigned long long &epAddress) const override; - virtual bool getEpOffset(unsigned long long &epOffset) const override; - virtual bool getSection(unsigned long long secIndex, PeCoffSection §ion) const override; - virtual bool getDllFlags(unsigned long long &dllFlags) const override; - virtual bool getDataDirectoryRelative(unsigned long long index, unsigned long long &relAddr, unsigned long long &size) const override; - virtual bool getDataDirectoryAbsolute(unsigned long long index, unsigned long long &absAddr, unsigned long long &size) const override; - virtual bool getImportedLibraryFileName(unsigned long long index, std::string &fileName) const override; - virtual bool getDelayImportedLibraryFileName(unsigned long long index, std::string &fileName) const override; - virtual std::unique_ptr getImport(unsigned long long fileIndex, unsigned long long importIndex) const override; - virtual std::unique_ptr getDelayImport(unsigned long long fileIndex, unsigned long long importIndex) const override; - virtual unsigned long long getNumberOfExportedFunctions() const override; - virtual bool getExportedFunction(unsigned long long index, Export& exportedFunction) const override; - virtual unsigned long long getNumberOfDebugEntries() const override; - virtual bool getDebugEntryData(unsigned long long index, std::vector& data) const override; - virtual bool getDebugEntryTimeDateStamp(unsigned long long index, unsigned long long& timeDateStamp) const override; - virtual bool getDebugEntryPointerToRawData(unsigned long long index, unsigned long long& pointerToRawData) const override; - virtual unsigned long long getResourceDirectoryOffset() const override; - virtual const PeLib::ResourceNode* getResourceTreeRoot() const override; - virtual unsigned long long getTlsStartAddressOfRawData() const override; - virtual unsigned long long getTlsEndAddressOfRawData() const override; - virtual unsigned long long getTlsAddressOfIndex() const override; - virtual unsigned long long getTlsAddressOfCallBacks() const override; - virtual unsigned long long getTlsSizeOfZeroFill() const override; - virtual unsigned long long getTlsCharacteristics() const override; - virtual std::unique_ptr getClrHeader() const override; - virtual unsigned long long getNumberOfRelocations() const override; - virtual unsigned long long getNumberOfRelocationData(unsigned long long index) const override; - virtual unsigned long long getChecksumFileOffset() const override; - virtual unsigned long long getSecurityDirFileOffset() const override; - virtual unsigned long long getSecurityDirRva() const override; - virtual unsigned long long getSecurityDirSize() const override; - virtual retdec::common::RangeContainer getImportDirectoryOccupiedAddresses() const override; - virtual retdec::common::RangeContainer getExportDirectoryOccupiedAddresses() const override; - virtual retdec::common::RangeContainer getDebugDirectoryOccupiedAddresses() const override; - virtual retdec::common::RangeContainer getResourceDirectoryOccupiedAddresses() const override; - /// @} -}; - -} // namespace fileformat -} // namespace retdec - -#endif diff --git a/include/retdec/fileformat/file_format/pe/pe_template.h b/include/retdec/fileformat/file_format/pe/pe_template.h index e6fca4d7f..1140ef0a8 100644 --- a/include/retdec/fileformat/file_format/pe/pe_template.h +++ b/include/retdec/fileformat/file_format/pe/pe_template.h @@ -20,6 +20,8 @@ #include "retdec/fileformat/types/sec_seg/pe_coff_section.h" #include "retdec/fileformat/types/sec_seg/section.h" +#error Removed. Do not use. + namespace retdec { namespace fileformat { @@ -382,7 +384,7 @@ template unsigned long long peEpOffset(const PeLib::PeHeaderT &p * @param sectionIndex Index of section (indexed from 0) * @return @c true if section index is valid and section is detected, @c false otherwise */ -template bool peSectionWithIndex(const FileFormat *inputFile, const PeLib::PeHeaderT &peHeader, PeCoffSection §ion, unsigned long long sectionIndex) +inline bool peSectionWithIndex(const FileFormat *inputFile, const PeLib::PeHeaderT &peHeader, PeCoffSection §ion, unsigned long long sectionIndex) { std::string sectionName; PeCoffSection::Type sectionType; @@ -433,9 +435,9 @@ template bool peDllFlags(const PeLib::PeHeaderT &peHeader, unsig * * If method returns @c false, @a relAddr and @a size are left unchanged. */ -template bool peDataDirectoryRelative(const PeLib::PeHeaderT &peHeader, unsigned long long &relAddr, unsigned long long &size, unsigned long long index) +inline bool peDataDirectoryRelative(const ImageLoader & imageLoader, unsigned long long &relAddr, unsigned long long &size, unsigned long long index) { - if(index >= peNumberOfStoredDataDirectories(peHeader)) + if(index >= imageLoader.getOptionalHeader().NumberOfRvaAndSizes) { return false; } @@ -459,14 +461,9 @@ template bool peDataDirectoryRelative(const PeLib::PeHeaderT &pe * * If function returns @c false, @a absAddr and @a size are left unchanged. */ -template bool peDataDirectoryAbsolute(const PeLib::PeHeaderT &peHeader, unsigned long long &absAddr, unsigned long long &size, unsigned long long index) +template bool peDataDirectoryAbsolute(const ImageLoader & imageLoader, unsigned long long &absAddr, unsigned long long &size, unsigned long long index) { - if(index >= peNumberOfStoredDataDirectories(peHeader)) - { - return false; - } - - absAddr = peHeader.getImageDataDirectoryRva(index); + absAddr = imageLoader.getDataDirRva(index); if(absAddr) { absAddr += peHeader.getImageBase(); diff --git a/include/retdec/pelib/BoundImportDirectory.h b/include/retdec/pelib/BoundImportDirectory.h index 3e43dee5e..74e898168 100644 --- a/include/retdec/pelib/BoundImportDirectory.h +++ b/include/retdec/pelib/BoundImportDirectory.h @@ -13,7 +13,6 @@ #ifndef BOUNDIMPORTDIRECTORY_H #define BOUNDIMPORTDIRECTORY_H -#include "retdec/pelib/PeHeader.h" #include "retdec/pelib/PeLibAux.h" #include "retdec/pelib/ImageLoader.h" diff --git a/include/retdec/pelib/DelayImportDirectory.h b/include/retdec/pelib/DelayImportDirectory.h index e8e207975..a5bc9b21c 100644 --- a/include/retdec/pelib/DelayImportDirectory.h +++ b/include/retdec/pelib/DelayImportDirectory.h @@ -8,7 +8,6 @@ #define DELAY_IMPORT_DIRECTORY_H #include "retdec/pelib/PeLibInc.h" -#include "retdec/pelib/PeHeader.h" #include "retdec/pelib/ImageLoader.h" namespace PeLib diff --git a/include/retdec/pelib/IatDirectory.h b/include/retdec/pelib/IatDirectory.h index 06abfd8ab..9edf35dbf 100644 --- a/include/retdec/pelib/IatDirectory.h +++ b/include/retdec/pelib/IatDirectory.h @@ -14,7 +14,6 @@ #define IATDIRECTORY_H #include "retdec/pelib/PeLibInc.h" -#include "retdec/pelib/PeHeader.h" #include "retdec/pelib/ImageLoader.h" namespace PeLib diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index da41a409a..c4791b231 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -134,37 +134,157 @@ class ImageLoader std::uint32_t writeImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead); std::uint32_t readString(std::string & str, std::uint32_t rva, std::uint32_t maxLength = 65535); + std::uint32_t readStringRc(std::string & str, std::uint32_t rva); + std::uint32_t readStringRaw(std::vector & fileData, std::string & str, std::size_t offset); std::uint32_t stringLength(std::uint32_t rva, std::uint32_t maxLength = 65535) const; std::uint32_t readPointer(std::uint32_t rva, std::uint64_t & pointerValue); std::uint32_t getPointerSize() const; - std::uint32_t readStringRc(std::string & str, std::uint32_t rva); + bool getSectionName(std::size_t sectionIndex, std::string & sectionName); std::uint32_t dumpImage(const char * fileName); std::uint32_t getImageBitability() const; - std::uint64_t getOrdinalMask() const; - std::uint32_t getNtSignature() const; - std::uint32_t getMachine() const; - std::uint32_t getPointerToSymbolTable() const; - std::uint32_t getNumberOfSymbols() const; - std::uint64_t getImageBase() const; - std::uint32_t getAddressOfEntryPoint() const; - std::uint32_t getSizeOfHeaders() const; - std::uint32_t getSizeOfImage() const; - std::uint32_t getSizeOfImageAligned() const; - std::uint32_t getSectionAlignment() const; - std::uint32_t getFileAlignment() const; - std::uint32_t getDataDirRva(std::size_t dataDirIndex) const; - std::uint32_t getDataDirSize(std::size_t dataDirIndex) const; + std::uint32_t getFileOffsetFromRva(std::uint32_t rva) const; + std::uint32_t getRealPointerToRawData(std::size_t sectionIndex) const; std::uint32_t getImageProtection(std::uint32_t characteristics) const; + bool setDataDirectory(std::uint32_t index, std::uint32_t rva, std::uint32_t size); + + const PELIB_IMAGE_DOS_HEADER & getDosHeader() const + { + return dosHeader; + } + + const PELIB_IMAGE_FILE_HEADER & getFileHeader() const + { + return fileHeader; + } + + const PELIB_IMAGE_OPTIONAL_HEADER & getOptionalHeader() const + { + return optionalHeader; + } + + const PELIB_SECTION_HEADER * getSectionHeader(std::size_t sectionIndex) const + { + return (sectionIndex < sections.size()) ? §ions[sectionIndex] : nullptr; + } + + std::uint64_t getOrdinalMask() const + { + return (uint64_t)1 << (getImageBitability() - 1); + } + + std::uint32_t getPeHeaderOffset() const + { + return dosHeader.e_lfanew; + } + + std::uint32_t getNtSignature() const + { + return ntSignature; + } + + std::uint32_t getMachine() const + { + return fileHeader.Machine; + } + + std::uint32_t getPointerToSymbolTable() const + { + return fileHeader.PointerToSymbolTable; + } + + std::uint32_t getNumberOfSymbols() const + { + return fileHeader.NumberOfSymbols; + } + + std::uint32_t getLoadedNumberOfSections() const + { + return fileHeader.NumberOfSections; + } + + std::uint32_t getNumberOfSections() const + { + return sections.size(); + } + + std::uint32_t getMagic() const + { + return optionalHeader.Magic; + } + + std::uint64_t getImageBase() const + { + return optionalHeader.ImageBase; + } + + std::uint32_t getAddressOfEntryPoint() const + { + return optionalHeader.AddressOfEntryPoint; + } + + std::uint32_t getSizeOfHeaders() const + { + return optionalHeader.SizeOfHeaders; + } + + std::uint32_t getSizeOfImage() const + { + return optionalHeader.SizeOfImage; + } + + std::uint32_t getSizeOfImageAligned() const + { + return AlignToSize(optionalHeader.SizeOfImage, PELIB_PAGE_SIZE); + } + + std::uint32_t getSectionAlignment() const + { + return optionalHeader.SectionAlignment; + } + + std::uint32_t getFileAlignment() const + { + return optionalHeader.FileAlignment; + } + + std::uint32_t getCharacteristics() const + { + return optionalHeader.DllCharacteristics; + } + + std::uint32_t getChecksumFileOffset() const + { + return checkSumFileOffset; + } + + std::uint32_t getSecurityDirFileOffset() const + { + return securityDirFileOffset; + } + + std::uint32_t getDataDirRva(std::size_t dataDirIndex) const + { + // The data directory must be present there + return (optionalHeader.NumberOfRvaAndSizes > dataDirIndex) ? optionalHeader.DataDirectory[dataDirIndex].VirtualAddress : 0; + } + + std::uint32_t getDataDirSize(std::size_t dataDirIndex) const + { + // The data directory must be present there + return (optionalHeader.NumberOfRvaAndSizes > dataDirIndex) ? optionalHeader.DataDirectory[dataDirIndex].Size : 0; + } + int setLoaderError(LoaderError ldrErr); LoaderError loaderError() const; - // Testing function + // Testing functions + std::size_t getMismatchOffset(void * buffer1, void * buffer2, std::uint32_t rva, std::size_t length); void compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & ImageCompare, void * imageData, std::uint32_t imageSize); protected: @@ -174,23 +294,26 @@ class ImageLoader static void readFromPage(PELIB_FILE_PAGE & page, void * buffer, size_t offsetInPage, size_t bytesInPage); static void writeToPage(PELIB_FILE_PAGE & page, void * buffer, size_t offsetInPage, size_t bytesInPage); std::uint32_t readWriteImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead, READWRITE ReadWrite); + std::uint32_t readWriteImageFile(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead, bool bReadOperation); bool processImageRelocations(std::uint64_t oldImageBase, std::uint64_t getImageBase, std::uint32_t VirtualAddress, std::uint32_t Size); void writeNewImageBase(std::uint64_t newImageBase); int captureDosHeader(std::vector & fileData); int captureNtHeaders(std::vector & fileData); + int captureSectionName(std::vector & fileData, std::string & sectionName, const std::uint8_t * name); int captureSectionHeaders(std::vector & fileData); int captureImageSections(std::vector & fileData); - int captureOptionalHeader32(std::uint8_t * filePtr, std::uint8_t * fileEnd); - int captureOptionalHeader64(std::uint8_t * filePtr, std::uint8_t * fileEnd); + int captureOptionalHeader32(std::uint8_t * fileData, std::uint8_t * filePtr, std::uint8_t * fileEnd); + int captureOptionalHeader64(std::uint8_t * fileData, std::uint8_t * filePtr, std::uint8_t * fileEnd); int verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_t fileSize); int verifyDosHeader(std::istream & fs, std::streamoff fileOffset, std::size_t fileSize); int loadImageAsIs(std::vector & fileData); - std::size_t getMismatchOffset(void * buffer1, void * buffer2, std::uint32_t rva, std::size_t length); + // Use sizeof(PELIB_OPTIONAL_HEADER32) or sizeof(PELIB_OPTIONAL_HEADER64) as parameter + std::uint32_t getRealSizeOfOptionalHeader(std::uint32_t nominalSize); std::uint32_t captureImageSection(std::vector & fileData, std::uint32_t virtualAddress, @@ -207,6 +330,11 @@ class ImageLoader bool isRvaOfSectionHeaderPointerToRawData(uint32_t rva); bool isLegacyImageArchitecture(std::uint16_t Machine); bool checkForBadAppContainer(); + + // isImageLoadable returns true if the image is OK and can be mapped by NtCreateSection(SEC_IMAGE). + // This does NOT mean that the image is executable by CreateProcess - more checks are done, + // like resource integrity or relocation table correctness. + bool isImageLoadable(); bool isImageMappedOk(); static std::uint32_t AlignToSize(std::uint32_t ByteSize, std::uint32_t AlignSize) @@ -221,9 +349,9 @@ class ImageLoader static uint8_t ImageProtectionArray[16]; - std::vector sections; // Vector of section headers + std::vector sections; // Vector of section headers std::vector pages; // PE file pages as if mapped - std::vector imageAsIs; // Loaded content of the image in case it couldn't have been mapped + std::vector rawFileData; // Loaded content of the image in case it couldn't have been mapped PELIB_IMAGE_DOS_HEADER dosHeader; // Loaded DOS header PELIB_IMAGE_FILE_HEADER fileHeader; // Loaded NT file header PELIB_IMAGE_OPTIONAL_HEADER optionalHeader; // 32/64-bit optional header @@ -231,11 +359,11 @@ class ImageLoader std::uint32_t ntSignature; std::uint32_t loaderMode; std::uint32_t maxSectionCount; + std::uint32_t checkSumFileOffset; // File offset of the image checksum + std::uint32_t securityDirFileOffset; // File offset of security directory bool ntHeadersSizeCheck; // If true, the loader requires minimum size of NT headers bool sizeofImageMustMatch; // If true, the SizeOfImage must match virtual end of the last section - //bool copyWholeHeaderPage; // If true, then the image header is copied up to Section Alignment bool appContainerCheck; // If true, app container flag is tested in the optional header - bool strictMode; // If true, the loader refuses corrupt images like Windows loader would do }; } // namespace PeLib diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index e5490ce07..be198abca 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -16,7 +16,7 @@ #include #include "retdec/pelib/PeLibAux.h" -#include "retdec/pelib/PeHeader.h" +#include "retdec/pelib/ImageLoader.h" namespace PeLib { @@ -500,8 +500,9 @@ namespace PeLib inline std::uint32_t ImportDirectory::getNumberOfFiles(currdir cdDir) const { - if (cdDir == OLDDIR) return static_cast(m_vOldiid.size()); - else return static_cast(m_vNewiid.size()); + std::size_t numFiles = (cdDir == OLDDIR) ? m_vOldiid.size() : m_vNewiid.size(); + + return static_cast(numFiles); } /** diff --git a/include/retdec/pelib/MzHeader.h b/include/retdec/pelib/MzHeader.h index d55f54e36..6abd3a88b 100644 --- a/include/retdec/pelib/MzHeader.h +++ b/include/retdec/pelib/MzHeader.h @@ -13,6 +13,8 @@ #ifndef MZHEADER_H #define MZHEADER_H +#error Bla + #include "retdec/pelib/PeLibInc.h" namespace PeLib diff --git a/include/retdec/pelib/PeFile.h b/include/retdec/pelib/PeFile.h index 3fabcde06..c58fdadbd 100644 --- a/include/retdec/pelib/PeFile.h +++ b/include/retdec/pelib/PeFile.h @@ -14,8 +14,6 @@ #define PEFILE_H #include "retdec/pelib/PeLibInc.h" -#include "retdec/pelib/MzHeader.h" -#include "retdec/pelib/PeHeader.h" #include "retdec/pelib/ImageLoader.h" #include "retdec/pelib/ImportDirectory.h" #include "retdec/pelib/ExportDirectory.h" @@ -33,38 +31,6 @@ namespace PeLib { - class PeFile32; - class PeFile64; - - /** - * Visitor base class for PeFiles. - **/ - class PeFileVisitor - { - public: - virtual void callback(PeFile32 &file){(void) file; /* avoid warning about unused parameter */} - virtual void callback(PeFile64 &file){(void) file; /* avoid warning about unused parameter */} - virtual ~PeFileVisitor(){} - }; - - /** - * Traits class that's used to decide of what type the PeHeader in a PeFile is. - **/ - template - struct PeFile_Traits; - - template<> - struct PeFile_Traits<32> - { - typedef PeHeader32 PeHeader32_64; - }; - - template<> - struct PeFile_Traits<64> - { - typedef PeHeader64 PeHeader32_64; - }; - /** * This class represents the common structures of PE and PE+ files. **/ @@ -72,7 +38,6 @@ namespace PeLib { protected: std::string m_filename; ///< Name of the current file. - MzHeader m_mzh; ///< MZ header of the current file. ImageLoader m_imageLoader; RichHeader m_richheader; ///< Rich header of the current file. CoffSymbolTable m_coffsymtab; ///< Symbol table of the current file. @@ -83,18 +48,10 @@ namespace PeLib /// Returns the name of the current file. virtual std::string getFileName() const = 0; // EXPORT /// Changes the name of the current file. - virtual void setFileName(std::string strFilename) = 0; // EXPORT - - virtual void visit(PeFileVisitor &v) = 0; + virtual void setFileName(const std::string & strFilename) = 0; // EXPORT - /// Reads the basic headers needed to process the file - virtual int loadPeHeaders(ByteBuffer & fileData) = 0; - /// Reads the MZ header of the current file from disc. - virtual int readMzHeader() = 0; // EXPORT /// Reads the export directory of the current file from disc. virtual int readExportDirectory() = 0; // EXPORT - /// Reads the PE header of the current file from disc. - virtual int readPeHeader() = 0; // EXPORT /// Reads the import directory of the current file from disc. virtual int readImportDirectory() = 0; // EXPORT /// Reads the bound import directory of the current file from disc. @@ -124,11 +81,6 @@ namespace PeLib virtual unsigned int getBits() const = 0; - /// Accessor function for the MZ header. - const MzHeader& mzHeader() const; - /// Accessor function for the MZ header. - MzHeader& mzHeader(); // EXPORT - /// Accessor function for the image loader const ImageLoader & imageLoader() const; /// Accessor function for the MZ header. @@ -153,673 +105,134 @@ namespace PeLib /** * This class implements the common structures of PE and PE+ files. **/ - template class PeFileT : public PeFile { - typedef typename PeFile_Traits::PeHeader32_64 PeHeader32_64; - private: - std::ifstream m_ifStream; - std::istream& m_iStream; - - PeHeader32_64 m_peh; ///< PE header of the current file. - ExportDirectory m_expdir; ///< Export directory of the current file. - ImportDirectory m_impdir; ///< Import directory of the current file. - BoundImportDirectory m_boundimpdir; ///< BoundImportDirectory of the current file. - ResourceDirectory m_resdir; ///< ResourceDirectory of the current file. - RelocationsDirectory m_relocs; ///< Relocations directory of the current file. - ComHeaderDirectory m_comdesc; ///< COM+ descriptor directory of the current file. - IatDirectory m_iat; ///< Import address table of the current file. - DebugDirectory m_debugdir; ///< Debug directory of the current file. - DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file. - TlsDirectory m_tlsdir; ///< TLS directory of the current file. - - public: - /// Default constructor which exists only for the sake of allowing to construct files without filenames. - PeFileT(); - - virtual ~PeFileT() {} - - /// Initializes a PeFile with a filename - explicit PeFileT(const std::string& strFilename); - PeFileT(std::istream& stream); - - /// Returns the name of the current file. - std::string getFileName() const; - /// Changes the name of the current file. - void setFileName(std::string strFilename); - - /// Reads the basic headers needed to process the file - int loadPeHeaders(ByteBuffer & fileData); - /// Reads the MZ header of the current file from disc. - int readMzHeader() ; - /// Reads the export directory of the current file from disc. - int readExportDirectory() ; - /// Reads the PE header of the current file from disc. - int readPeHeader() ; - /// Reads the import directory of the current file from disc. - int readImportDirectory() ; - /// Reads the bound import directory of the current file from disc. - int readBoundImportDirectory() ; - /// Reads the resource directory of the current file from disc. - int readResourceDirectory() ; - /// Reads the relocations directory of the current file from disc. - int readRelocationsDirectory() ; - /// Reads the COM+ descriptor directory of the current file from disc. - int readComHeaderDirectory() ; - /// Reads the IAT directory of the current file from disc. - int readIatDirectory() ; - /// Reads the Debug directory of the current file. - int readDebugDirectory() ; - /// Reads the TLS directory of the current file. - int readTlsDirectory() ; - /// Reads rich header of the current file. - int readRichHeader(std::size_t offset, std::size_t size, bool ignoreInvalidKey = false) ; - /// Reads the COFF symbol table of the current file. - int readCoffSymbolTable(ByteBuffer & fileData); - /// Reads delay import directory of the current file. - int readDelayImportDirectory() ; - /// Reads the security directory of the current file. - int readSecurityDirectory() ; - /// Checks the entry point code - LoaderError checkEntryPointErrors() const; - LoaderError checkForInMemoryLayout(LoaderError ldrError) const; + std::ifstream m_ifStream; ///< Valid if we opened the file stream ourself + std::istream& m_iStream; ///< Can also reference m_ifStream - /// Returns a loader error, if there was any - LoaderError loaderError() const; - - unsigned int getBits() const - { - return bits; - } - - /// Accessor function for the PE header. - const PeHeader32_64& peHeader() const; - /// Accessor function for the PE header. - PeHeader32_64& peHeader(); - - /// Accessor function for the export directory. - const ExportDirectory & expDir() const; - /// Accessor function for the export directory. - ExportDirectory & expDir(); // EXPORT - - /// Accessor function for the import directory. - const ImportDirectory & impDir() const; - /// Accessor function for the import directory. - ImportDirectory & impDir(); - - /// Accessor function for the bound import directory. - const BoundImportDirectory & boundImpDir() const; - /// Accessor function for the bound import directory. - BoundImportDirectory & boundImpDir(); // EXPORT - - /// Accessor function for the resource directory. - const ResourceDirectory & resDir() const; - /// Accessor function for the resource directory. - ResourceDirectory & resDir(); // EXPORT - - /// Accessor function for the relocations directory. - const RelocationsDirectory & relocDir() const; - /// Accessor function for the relocations directory. - RelocationsDirectory & relocDir(); // EXPORT - - /// Accessor function for the COM+ descriptor directory. - const ComHeaderDirectory & comDir() const; - /// Accessor function for the COM+ descriptor directory. - ComHeaderDirectory & comDir(); // EXPORT - - /// Accessor function for the IAT directory. - const IatDirectory & iatDir() const; - /// Accessor function for the IAT directory. - IatDirectory & iatDir(); // EXPORT - - /// Accessor function for the debug directory. - const DebugDirectory & debugDir() const; - /// Accessor function for the debug directory. - DebugDirectory & debugDir(); // EXPORT - - /// Accessor function for the delay import directory. - const DelayImportDirectory & delayImports() const; - /// Accessor function for the delay import directory. - DelayImportDirectory & delayImports(); // EXPORT - - /// Accessor function for the TLS directory. - const TlsDirectory & tlsDir() const; - /// Accessor function for the TLS directory. - TlsDirectory & tlsDir(); - }; + ExportDirectory m_expdir; ///< Export directory of the current file. + ImportDirectory m_impdir; ///< Import directory of the current file. + BoundImportDirectory m_boundimpdir; ///< BoundImportDirectory of the current file. + ResourceDirectory m_resdir; ///< ResourceDirectory of the current file. + RelocationsDirectory m_relocs; ///< Relocations directory of the current file. + ComHeaderDirectory m_comdesc; ///< COM+ descriptor directory of the current file. + IatDirectory m_iat; ///< Import address table of the current file. + DebugDirectory m_debugdir; ///< Debug directory of the current file. + DelayImportDirectory m_delayimpdir; ///< Delay import directory of the current file. + TlsDirectory m_tlsdir; ///< TLS directory of the current file. - /** - * This class is the main class for handling PE files. - **/ - class PeFile32 : public PeFileT<32> - { - public: - /// Default constructor which exists only for the sake of allowing to construct files without filenames. - PeFile32(); - - /// Initializes a PeFile with a filename - explicit PeFile32(const std::string& strFlename); - PeFile32(std::istream& stream); - virtual void visit(PeFileVisitor &v) { v.callback( *this ); } - }; - - /** - * This class is the main class for handling PE+ files. - **/ - class PeFile64 : public PeFileT<64> - { public: - /// Default constructor which exists only for the sake of allowing to construct files without filenames. - PeFile64(); - /// Initializes a PeFile with a filename - explicit PeFile64(const std::string& strFlename); - PeFile64(std::istream& stream); - virtual void visit(PeFileVisitor &v) { v.callback( *this ); } + PeFileT(const std::string& strFileName); + PeFileT(std::istream& stream); + PeFileT(); /// Default constructor which exists only for the sake of allowing to construct files without filenames. + virtual ~PeFileT() {} + + /// Load the PE file using the already-open stream + int loadPeHeaders(bool loadHeadersOnly = false); + + /// Alternate load - can be used when the data are already loaded to memory to prevent duplicating large buffers + int loadPeHeaders(ByteBuffer & fileData, bool loadHeadersOnly = false); + + /// returns PEFILE64 or PEFILE32 + int getFileType() const; + + /// Returns the name of the current file. + std::string getFileName() const; + /// Changes the name of the current file. + void setFileName(const std::string & strFilename); + + /// Reads the export directory of the current file from disc. + int readExportDirectory() ; + /// Reads the import directory of the current file from disc. + int readImportDirectory() ; + /// Reads the bound import directory of the current file from disc. + int readBoundImportDirectory() ; + /// Reads the resource directory of the current file from disc. + int readResourceDirectory() ; + /// Reads the relocations directory of the current file from disc. + int readRelocationsDirectory() ; + /// Reads the COM+ descriptor directory of the current file from disc. + int readComHeaderDirectory() ; + /// Reads the IAT directory of the current file from disc. + int readIatDirectory() ; + /// Reads the Debug directory of the current file. + int readDebugDirectory() ; + /// Reads the TLS directory of the current file. + int readTlsDirectory() ; + /// Reads rich header of the current file. + int readRichHeader(std::size_t offset, std::size_t size, bool ignoreInvalidKey = false) ; + /// Reads the COFF symbol table of the current file. + int readCoffSymbolTable(ByteBuffer & fileData); + /// Reads delay import directory of the current file. + int readDelayImportDirectory() ; + /// Reads the security directory of the current file. + int readSecurityDirectory() ; + + /// Checks the entry point code + LoaderError checkEntryPointErrors() const; + LoaderError checkForInMemoryLayout(LoaderError ldrError) const; + + /// Returns a loader error, if there was any + LoaderError loaderError() const; + + unsigned int getBits() const + { + return m_imageLoader.getImageBitability(); + } + + /// Accessor function for the export directory. + const ExportDirectory & expDir() const; + /// Accessor function for the export directory. + ExportDirectory & expDir(); // EXPORT + + /// Accessor function for the import directory. + const ImportDirectory & impDir() const; + /// Accessor function for the import directory. + ImportDirectory & impDir(); + + /// Accessor function for the bound import directory. + const BoundImportDirectory & boundImpDir() const; + /// Accessor function for the bound import directory. + BoundImportDirectory & boundImpDir(); // EXPORT + + /// Accessor function for the resource directory. + const ResourceDirectory & resDir() const; + /// Accessor function for the resource directory. + ResourceDirectory & resDir(); // EXPORT + + /// Accessor function for the relocations directory. + const RelocationsDirectory & relocDir() const; + /// Accessor function for the relocations directory. + RelocationsDirectory & relocDir(); // EXPORT + + /// Accessor function for the COM+ descriptor directory. + const ComHeaderDirectory & comDir() const; + /// Accessor function for the COM+ descriptor directory. + ComHeaderDirectory & comDir(); // EXPORT + + /// Accessor function for the IAT directory. + const IatDirectory & iatDir() const; + /// Accessor function for the IAT directory. + IatDirectory & iatDir(); // EXPORT + + /// Accessor function for the debug directory. + const DebugDirectory & debugDir() const; + /// Accessor function for the debug directory. + DebugDirectory & debugDir(); // EXPORT + + /// Accessor function for the delay import directory. + const DelayImportDirectory & delayImports() const; + /// Accessor function for the delay import directory. + DelayImportDirectory & delayImports(); // EXPORT + + /// Accessor function for the TLS directory. + const TlsDirectory & tlsDir() const; + /// Accessor function for the TLS directory. + TlsDirectory & tlsDir(); }; - - //typedef PeFileT<32> PeFile32; - //typedef PeFileT<64> PeFile64; - - /** - * @param strFilename Name of the current file. - **/ - template - PeFileT::PeFileT(const std::string& strFilename) : - m_iStream(m_ifStream) - { - m_filename = strFilename; - m_ifStream.open(m_filename, std::ifstream::binary); - } - - /** - * @param stream Input stream. - **/ - - template - PeFileT::PeFileT(std::istream& stream) : - m_iStream(stream) - { - } - - template - PeFileT::PeFileT() : - m_iStream(m_ifStream) - { - } - - template - int PeFileT::readPeHeader() - { - return peHeader().read(m_iStream, mzHeader().getAddressOfPeHeader(), mzHeader()); - } - - /** - * @return A reference to the file's PE header. - **/ - template - const typename PeFile_Traits::PeHeader32_64& PeFileT::peHeader() const - { - return m_peh; - } - - /** - * @return A reference to the file's PE header. - **/ - template - typename PeFile_Traits::PeHeader32_64& PeFileT::peHeader() - { - return m_peh; - } - - /** - * @return A reference to the file's import directory. - **/ - template - const ImportDirectory & PeFileT::impDir() const - { - return m_impdir; - } - - /** - * @return A reference to the file's import directory. - **/ - template - ImportDirectory & PeFileT::impDir() - { - return m_impdir; - } - - template - const TlsDirectory & PeFileT::tlsDir() const - { - return m_tlsdir; - } - - template - TlsDirectory & PeFileT::tlsDir() - { - return m_tlsdir; - } - - /** - * @return A reference to the file's delay import directory. - **/ - template - const DelayImportDirectory & PeFileT::delayImports() const - { - return m_delayimpdir; - } - - /** - * @return A reference to the file's delay import directory. - **/ - template - DelayImportDirectory & PeFileT::delayImports() - { - return m_delayimpdir; - } - - /** - * @return A reference to the file's export directory. - **/ - template - const ExportDirectory & PeFileT::expDir() const - { - return m_expdir; - } - - /** - * @return A reference to the file's export directory. - **/ - template - ExportDirectory & PeFileT::expDir() - { - return m_expdir; - } - - /** - * @return A reference to the file's bound import directory. - **/ - template - const BoundImportDirectory & PeFileT::boundImpDir() const - { - return m_boundimpdir; - } - - /** - * @return A reference to the file's bound import directory. - **/ - template - BoundImportDirectory & PeFileT::boundImpDir() - { - return m_boundimpdir; - } - - /** - * @return A reference to the file's resource directory. - **/ - template - const ResourceDirectory & PeFileT::resDir() const - { - return m_resdir; - } - - /** - * @return A reference to the file's resource directory. - **/ - template - ResourceDirectory & PeFileT::resDir() - { - return m_resdir; - } - - /** - * @return A reference to the file's relocations directory. - **/ - template - const RelocationsDirectory & PeFileT::relocDir() const - { - return m_relocs; - } - - /** - * @return A reference to the file's relocations directory. - **/ - template - RelocationsDirectory & PeFileT::relocDir() - { - return m_relocs; - } - - /** - * @return A reference to the file's COM+ descriptor directory. - **/ - template - const ComHeaderDirectory & PeFileT::comDir() const - { - return m_comdesc; - } - - /** - * @return A reference to the file's COM+ descriptor directory. - **/ - template - ComHeaderDirectory & PeFileT::comDir() - { - return m_comdesc; - } - - template - const IatDirectory & PeFileT::iatDir() const - { - return m_iat; - } - - template - IatDirectory & PeFileT::iatDir() - { - return m_iat; - } - - template - const DebugDirectory & PeFileT::debugDir() const - { - return m_debugdir; - } - - template - DebugDirectory & PeFileT::debugDir() - { - return m_debugdir; - } - - /** - * @return Filename of the current file. - **/ - template - std::string PeFileT::getFileName() const - { - return m_filename; - } - - /** - * @param strFilename New filename. - **/ - template - void PeFileT::setFileName(std::string strFilename) - { - m_filename = strFilename; - if (m_ifStream.is_open()) - { - m_ifStream.close(); - } - m_ifStream.open(m_filename, std::ifstream::binary); - } - - template - int PeFileT::loadPeHeaders(ByteBuffer & fileData) - { - return m_imageLoader.Load(fileData); - } - - template - int PeFileT::readMzHeader() - { - return mzHeader().read(m_iStream); - } - - template - int PeFileT::readRichHeader( - std::size_t offset, - std::size_t size, - bool ignoreInvalidKey) - { - return richHeader().read(m_iStream, offset, size, ignoreInvalidKey); - } - - template - int PeFileT::readCoffSymbolTable(ByteBuffer & fileData) - { - if(m_imageLoader.getPointerToSymbolTable() && m_imageLoader.getNumberOfSymbols()) - { - return coffSymTab().read( - fileData, - m_imageLoader.getPointerToSymbolTable(), - m_imageLoader.getNumberOfSymbols() * PELIB_IMAGE_SIZEOF_COFF_SYMBOL); - } - return ERROR_COFF_SYMBOL_TABLE_DOES_NOT_EXIST; - } - - template - int PeFileT::readExportDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT)) - { - return expDir().read(m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readImportDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT)) - { - return impDir().read(m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readResourceDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE)) - { - return resDir().read(m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readSecurityDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY)) - { - return securityDir().read(m_iStream, - m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY), - m_imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY)); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readRelocationsDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC)) - { - return relocDir().read(m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readDebugDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG)) - { - return debugDir().read(m_iStream, m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readTlsDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_TLS)) - { - return tlsDir().read(m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readBoundImportDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)) - { - return boundImpDir().read(m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readIatDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IAT)) - { - return iatDir().read(m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readDelayImportDirectory() - { - // Note: Delay imports can have arbitrary size and Windows loader will still load them - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)) - { - return delayImports().read(m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - int PeFileT::readComHeaderDirectory() - { - if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) && - m_imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)) - { - return comDir().read(m_imageLoader); - } - return ERROR_DIRECTORY_DOES_NOT_EXIST; - } - - template - LoaderError PeFileT::checkEntryPointErrors() const - { - ImageLoader & imgLoader = const_cast(m_imageLoader); - std::uint32_t addressOfEntryPoint = m_imageLoader.getAddressOfEntryPoint(); - std::uint32_t sizeOfImage = m_imageLoader.getSizeOfImage(); - - if(addressOfEntryPoint >= sizeOfImage) - { - return LDR_ERROR_ENTRY_POINT_OUT_OF_IMAGE; - } - - // Only check PE files compiled for i386 or x64 processors. - if (m_imageLoader.getMachine() == PELIB_IMAGE_FILE_MACHINE_I386 || m_imageLoader.getMachine() == PELIB_IMAGE_FILE_MACHINE_AMD64) - { - std::uint64_t entryPointCode[2] = {0, 0}; - - // Check if 16 bytes of code are available in the file - if ((addressOfEntryPoint + sizeof(entryPointCode)) < sizeOfImage) - { - // Read the entry point code - imgLoader.readImage(entryPointCode, addressOfEntryPoint, sizeof(entryPointCode)); - - // Zeroed instructions at entry point map either to "add [eax], al" (i386) or "add [rax], al" (AMD64). - // Neither of these instructions makes sense on the entry point. We check 16 bytes of the entry point, - // in order to make sure it's really a corruption. - if ((entryPointCode[0] | entryPointCode[1]) == 0) - { - return LDR_ERROR_ENTRY_POINT_ZEROED; - } - } - } - - return LDR_ERROR_NONE; - } - - template - LoaderError PeFileT::checkForInMemoryLayout(LoaderError ldrError) const - { - std::uint64_t ulFileSize = fileSize(m_iStream); - std::uint64_t sizeOfImage = m_imageLoader.getSizeOfImage(); - - // The file size must be greater or equal to SizeOfImage - if(ulFileSize >= sizeOfImage) - { - std::uint32_t sectionAlignment = m_imageLoader.getSectionAlignment(); - std::uint32_t fileAlignment = m_imageLoader.getFileAlignment(); - std::uint32_t sizeOfHeaders = m_imageLoader.getSizeOfHeaders(); - - // SectionAlignment must be greater than file alignment - if(sectionAlignment >= PELIB_PAGE_SIZE && sectionAlignment > fileAlignment) - { - // SizeOfHeaders must be smaller than SectionAlignment - if(sizeOfHeaders < sectionAlignment) - { - std::size_t headerDataSize = sectionAlignment - sizeOfHeaders; - - // Read the entire after-header-data - ByteBuffer headerData(headerDataSize); - m_iStream.seekg(sizeOfHeaders, std::ios::beg); - m_iStream.read(reinterpret_cast(headerData.data()), headerDataSize); - - // Check whether there are zeros only. If yes, we consider - // the file to be an in-memory image - if(std::all_of(headerData.begin(), headerData.end(), [](char item) { return item == 0; })) - ldrError = LDR_ERROR_INMEMORY_IMAGE; - } - } - } - - return ldrError; - } - - // Returns an error code indicating loader problem. We check every part of the PE file - // for possible loader problem. If anything wrong was found, we report it - template - LoaderError PeFileT::loaderError() const - { - // Check for problems in image loader - LoaderError ldrError = imageLoader().loaderError(); - - // Check the loader error - if (ldrError == LDR_ERROR_NONE) - ldrError = coffSymTab().loaderError(); - - // Check errors in import directory - if (ldrError == LDR_ERROR_NONE) - ldrError = impDir().loaderError(); - - // Check errors in resource directory - if (ldrError == LDR_ERROR_NONE) - ldrError = resDir().loaderError(); - - // Check errors in relocations directory - if (ldrError == LDR_ERROR_NONE) - ldrError = relocDir().loaderError(); - - // Check errors in security directory - if (ldrError == LDR_ERROR_NONE) - ldrError = securityDir().loaderError(); - - // Check errors in entry point - if (ldrError == LDR_ERROR_NONE) - ldrError = checkEntryPointErrors(); - - // If there was a loaded error, we'll check whether - // the file can't actually be an in-memory version - if(ldrError != LDR_ERROR_NONE) - ldrError = checkForInMemoryLayout(ldrError); - - // Nothing wrond found - return ldrError; - } } #endif diff --git a/include/retdec/pelib/PeHeader.h b/include/retdec/pelib/PeHeader.h index fd25faf27..c0f6789e8 100644 --- a/include/retdec/pelib/PeHeader.h +++ b/include/retdec/pelib/PeHeader.h @@ -19,6 +19,8 @@ #include "retdec/pelib/PeLibAux.h" #include "retdec/pelib/MzHeader.h" +#error Bla + namespace PeLib { class PeHeader diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index 525a8dd34..e29bdb0b9 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -131,9 +131,12 @@ namespace PeLib typedef std::vector ByteBuffer; - enum {PEFILE32 = 32, + enum + { + PEFILE32 = 32, PEFILE64 = 64, - PEFILE_UNKNOWN = 0}; + PEFILE_UNKNOWN = 0 + }; const std::uint16_t PELIB_IMAGE_DOS_SIGNATURE = 0x5A4D; @@ -802,7 +805,7 @@ namespace PeLib const unsigned int PELIB_IMAGE_SIZEOF_SHORT_NAME = 8; const unsigned int PELIB_IMAGE_SIZEOF_MAX_NAME = 1024; - struct PELIB_IMAGE_SECTION_HEADER_BASE + struct PELIB_IMAGE_SECTION_HEADER { std::uint8_t Name[PELIB_IMAGE_SIZEOF_SHORT_NAME]; std::uint32_t VirtualSize; @@ -816,31 +819,19 @@ namespace PeLib std::uint32_t Characteristics; }; - - struct PELIB_IMAGE_SECTION_HEADER : public PELIB_IMAGE_SECTION_HEADER_BASE + struct PELIB_SECTION_HEADER : public PELIB_IMAGE_SECTION_HEADER { - std::string StringTableName; - - PELIB_IMAGE_SECTION_HEADER() + const std::string & getName() const { - memset(Name, 0, sizeof(Name)); - VirtualSize = 0; - VirtualAddress = 0; - SizeOfRawData = 0; - PointerToRawData = 0; - PointerToRelocations = 0; - PointerToLinenumbers = 0; - NumberOfRelocations = 0; - NumberOfLinenumbers = 0; - Characteristics = 0; - StringTableName = ""; + return sectionName; } - static inline std::size_t size() { return sizeof(PELIB_IMAGE_SECTION_HEADER); } + static const std::size_t size() + { + return sizeof(PELIB_IMAGE_SECTION_HEADER); + } - bool biggerFileOffset(const PELIB_IMAGE_SECTION_HEADER& ish) const; - bool biggerVirtualAddress(const PELIB_IMAGE_SECTION_HEADER& ish) const; - bool isFullNameSet() const; + std::string sectionName; }; struct PELIB_IMAGE_THUNK_DATA @@ -853,17 +844,6 @@ namespace PeLib } }; - template - struct PELIB_VAR_SIZE - { - typename FieldSizes::VAR4_8 Value; - - PELIB_VAR_SIZE() - { - Value = 0; - } - }; - struct PELIB_IMAGE_IMPORT_DESCRIPTOR { std::uint32_t OriginalFirstThunk; @@ -1220,14 +1200,6 @@ namespace PeLib const char * getLoaderErrorString(LoaderError ldrError, bool userFriendly = false); bool getLoaderErrorLoadableAnyway(LoaderError ldrError); - /// Determines if a file is a 32bit or 64bit PE file. - unsigned int getFileType(const std::string strFilename); - unsigned int getFileType(std::istream& stream); - - /// Opens a PE file. - PeFile* openPeFile(const std::string& strFilename); - PeFile* openPeFile(std::istream& stream); - /* enum MzHeader_Field {e_magic, e_cblp, e_cp, e_crlc, e_cparhdr, e_minalloc, e_maxalloc, e_ss, e_sp, e_csum, e_ip, e_cs, e_lfarlc, e_ovno, e_res, e_oemid, e_oeminfo, e_res2, e_lfanew}; diff --git a/include/retdec/pelib/ResourceDirectory.h b/include/retdec/pelib/ResourceDirectory.h index bef054c7a..c81745810 100644 --- a/include/retdec/pelib/ResourceDirectory.h +++ b/include/retdec/pelib/ResourceDirectory.h @@ -16,7 +16,6 @@ #include #include "retdec/pelib/PeLibInc.h" -#include "retdec/pelib/PeHeader.h" #include "retdec/pelib/ImageLoader.h" namespace PeLib diff --git a/include/retdec/pelib/SecurityDirectory.h b/include/retdec/pelib/SecurityDirectory.h index 5b5ff1fbf..178f86d8e 100644 --- a/include/retdec/pelib/SecurityDirectory.h +++ b/include/retdec/pelib/SecurityDirectory.h @@ -7,8 +7,6 @@ #ifndef SECURITYDIRECTORY_H #define SECURITYDIRECTORY_H -#include "retdec/pelib/PeHeader.h" - namespace PeLib { class SecurityDirectory diff --git a/src/cpdetect/heuristics/pe_heuristics.cpp b/src/cpdetect/heuristics/pe_heuristics.cpp index 8e22f5c95..596b52d99 100644 --- a/src/cpdetect/heuristics/pe_heuristics.cpp +++ b/src/cpdetect/heuristics/pe_heuristics.cpp @@ -504,11 +504,11 @@ void PeHeuristics::getMorphineHeuristics() */ void PeHeuristics::getStarForceHeuristics() { - const PeLib::MzHeader & mzHeader = peParser.getMzHeader(); + const PeLib::ImageLoader & imageLoader = peParser.getImageLoader(); const auto epSection = toolInfo.epSection.getIndex(); - uint32_t e_lfanew = mzHeader.getAddressOfPeHeader(); - uint16_t e_cblp = mzHeader.getBytesOnLastPage(); - uint16_t e_cp = mzHeader.getPagesInFile(); + uint32_t e_lfanew = imageLoader.getDosHeader().e_lfanew; + uint16_t e_cblp = imageLoader.getDosHeader().e_cblp; + uint16_t e_cp = imageLoader.getDosHeader().e_cp; if (noOfSections >= 4) { diff --git a/src/fileformat/CMakeLists.txt b/src/fileformat/CMakeLists.txt index 175255d25..9d8f06373 100644 --- a/src/fileformat/CMakeLists.txt +++ b/src/fileformat/CMakeLists.txt @@ -64,9 +64,6 @@ add_library(fileformat STATIC types/note_section/elf_notes.cpp types/note_section/elf_core.cpp types/tls_info/tls_info.cpp - file_format/pe/pe_format_parser/pe_format_parser64.cpp - file_format/pe/pe_format_parser/pe_format_parser.cpp - file_format/pe/pe_format_parser/pe_format_parser32.cpp file_format/pe/pe_format.cpp file_format/pe/pe_dll_list.cpp file_format/coff/coff_format.cpp diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index f87573134..1479c25ed 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -22,8 +22,7 @@ #include "retdec/utils/string.h" #include "retdec/utils/dynamic_buffer.h" #include "retdec/fileformat/file_format/pe/pe_format.h" -#include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.h" -#include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.h" +#include "retdec/fileformat/file_format/pe/pe_format_parser.h" #include "retdec/fileformat/types/dotnet_headers/metadata_tables.h" #include "retdec/fileformat/types/dotnet_types/dotnet_type_reconstructor.h" #include "retdec/fileformat/types/visual_basic/visual_basic_structures.h" @@ -576,15 +575,13 @@ void PeFormat::initLoaderErrorInfo() void PeFormat::initStructures(const std::string & dllListFile) { formatParser = nullptr; - peHeader32 = nullptr; - peHeader64 = nullptr; errorLoadingDllList = false; // If we got an override list of dependency DLLs, we load them into the map initDllList(dllListFile); stateIsValid = false; - file = new PeFile64(fileStream); + file = new PeFileT(fileStream); if (file) { try @@ -592,8 +589,6 @@ void PeFormat::initStructures(const std::string & dllListFile) if(file->loadPeHeaders(bytes) == ERROR_NONE) stateIsValid = true; - //file->readMzHeader(); - //file->readPeHeader(); file->readCoffSymbolTable(bytes); file->readImportDirectory(); file->readIatDirectory(); @@ -611,23 +606,7 @@ void PeFormat::initStructures(const std::string & dllListFile) initLoaderErrorInfo(); // Create an instance of PeFormatParser32/PeFormatParser64 - if(file->imageLoader().getImageBitability() == 64) - formatParser = new PeFormatParser64(this, static_cast*>(file)); - else - formatParser = new PeFormatParser32(this, static_cast*>(file)); - - /* - //mzHeader = file->mzHeader(); - if (auto *f32 = isPe32()) - { - peHeader32 = &(f32->peHeader()); - formatParser = new PeFormatParser32(this, static_cast*>(file)); - } - else if (auto *f64 = isPe64()) - { - peHeader64 = &(f64->peHeader()); - } - */ + formatParser = new PeFormatParser(this, file); } catch(...) {} @@ -3003,7 +2982,7 @@ std::size_t PeFormat::getBytesPerWord() const case PELIB_IMAGE_FILE_MACHINE_R3000_LITTLE: return 4; case PELIB_IMAGE_FILE_MACHINE_R4000: - return (isPe64() ? 8 : 4); + return formatParser->getPointerSize(); case PELIB_IMAGE_FILE_MACHINE_R10000: return 8; case PELIB_IMAGE_FILE_MACHINE_WCEMIPSV2: @@ -3026,7 +3005,7 @@ std::size_t PeFormat::getBytesPerWord() const // Architecture::POWERPC case PELIB_IMAGE_FILE_MACHINE_POWERPC: case PELIB_IMAGE_FILE_MACHINE_POWERPCFP: - return (isPe64() ? 8 : 4); + return formatParser->getPointerSize(); // unsupported architecture default: @@ -3159,7 +3138,7 @@ std::size_t PeFormat::getSectionTableOffset() const std::size_t PeFormat::getSectionTableEntrySize() const { - return PELIB_IMAGE_SECTION_HEADER::size(); + return sizeof(PELIB_IMAGE_SECTION_HEADER); } std::size_t PeFormat::getSegmentTableOffset() const @@ -3172,13 +3151,9 @@ std::size_t PeFormat::getSegmentTableEntrySize() const return 0; } -/** - * Get reference to MZ header - * @return Reference to MZ header - */ -const PeLib::MzHeader & PeFormat::getMzHeader() const +const PeLib::ImageLoader & PeFormat::getImageLoader() const { - return mzHeader; + return file->imageLoader(); } /** @@ -3187,7 +3162,7 @@ const PeLib::MzHeader & PeFormat::getMzHeader() const */ std::size_t PeFormat::getMzHeaderSize() const { - return mzHeader.size(); + return sizeof(PELIB_IMAGE_DOS_HEADER); } /** @@ -3208,7 +3183,7 @@ std::size_t PeFormat::getOptionalHeaderSize() const */ std::size_t PeFormat::getPeHeaderOffset() const { - return mzHeader.getAddressOfPeHeader(); + return formatParser->getPeHeaderOffset(); } /** @@ -3426,16 +3401,6 @@ bool PeFormat::initDllList(const std::string & dllListFile) return true; } -PeLib::PeFile32* PeFormat::isPe32() const -{ - return dynamic_cast(file); -} - -PeLib::PeFile64* PeFormat::isPe64() const -{ - return dynamic_cast(file); -} - /** * Check if input file contains CIL/.NET code * @return @c true if input file contains CIL/.NET code, @c false otherwise diff --git a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser.cpp b/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser.cpp deleted file mode 100644 index 15e3b3525..000000000 --- a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/** - * @file src/fileformat/file_format/pe/pe_format_parser/pe_format_parser.cpp - * @brief Methods of PeFormatParser class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h" - -namespace retdec { -namespace fileformat { - -/** - * Constructor - * @param fInputFile Pointer to input file - */ -PeFormatParser::PeFormatParser(const FileFormat *fInputFile) : inputFile(fInputFile) -{ - -} - -/** - * @fn unsigned long long PeFormatParser::getDeclaredNumberOfSections() const - * Get declared number of sections in file - * @return Declared number of sections in file - */ - -/** - * @fn unsigned long long PeFormatParser::getStoredNumberOfSections() const - * Get stored number of sections in file - * @return Stored number of sections in file - */ - -/** - * @fn unsigned long long PeFormatParser::getMachineType() const - * Get code of target architecture - * @return Code of target architecture - */ - -/** - * @fn unsigned long long PeFormatParser::getImageBaseAddress() const - * Get image base address - * @return Image base address - */ - -/** - * @fn unsigned long long PeFormatParser::getCoffSymbolTableOffset() const - * Get offset of COFF symbol table - * @return Offset of COFF symbol table - */ - -/** - * @fn unsigned long long PeFormatParser::getNumberOfCoffSymbols() const - * Get number of symbols in COFF symbol table - * @return Number of symbols in COFF symbol table - */ - -/** - * @fn unsigned long long PeFormatParser::getMajorLinkerVersion() const - * Get major version of used linker - * @return Major version of used linker - */ - -/** - * @fn unsigned long long PeFormatParser::getMinorLinkerVersion() const - * Get minor version of used linker - * @return Minor version of used linker - */ - -/** - * @fn unsigned long long PeFormatParser::getFileFlags() const - * Get file flags - * @return File flags as number - */ - -/** - * @fn unsigned long long PeFormatParser::getTimeStamp() const - * Get time stamp - * @return Time stamp of file - */ - -/** - * @fn unsigned long long PeFormatParser::getOptionalHeaderSize() const - * Get size of optional header - * @return Size of optional header - */ - -/** - * @fn unsigned long long PeFormatParser::getChecksum() const - * Get file checksum - * @return File checksum - */ - -/** - * @fn unsigned long long PeFormatParser::getSizeOfStackReserve() const - * Get size of the stack to reserve - * @return Size of the stack to reserve - */ - -/** - * @fn unsigned long long PeFormatParser::getSizeOfStackCommit() const - * Get size of the stack to commit - * @return Size of the stack to commit - */ - -/** - * @fn unsigned long long PeFormatParser::getSizeOfHeapReserve() const - * Get size of the local heap space to reserve - * @return Size of the local heap space to reserve - */ - -/** - * @fn unsigned long long PeFormatParser::getSizeOfHeapCommit() const - * Get size of the local heap space to commit - * @return Size of the local heap space to commit - */ - -/** - * @fn unsigned long long PeFormatParser::getSizeOfPeSignature() const - * Get size of the PE signature - * @return Size of the PE signature - */ - -/** - * @fn unsigned long long PeFormatParser::getLoadedSizeOfNtHeaders() const - * Get real loaded size of the NT headers (PE file signature + - * COFF file header + optional header + data directories) - * @return Loaded size of the NT headers - */ - -/** - * @fn unsigned long long PeFormatParser::getAllocatedSizeOfNtHeaders() const - * Get allocated size of the NT headers (PE file signature + - * COFF file header + optional header + data directories) - * @return Allocated size of the NT headers - */ - -/** - * @fn unsigned long long PeFormatParser::getDeclaredNumberOfDataDirectories() const - * Get declared number of data-directory entries - * @return Declared number of data-directory entries - */ - -/** - * @fn unsigned long long PeFormatParser::getStoredNumberOfDataDirectories() const - * Get stored number of data-directory entries in input file - * @return Stored number of data-directory entries in input file - */ - -/** - * @fn unsigned long long PeFormatParser::getNumberOfImportedLibraries() const - * Get number of imported libraries - * @return Number of imported DLL files - */ - -/** - * @fn unsigned long long PeFormatParser::getNumberOfDelayImportedLibraries() const - * Get number of delay imported libraries - * @return Number of delay imported DLL files - */ - -/** - * @fn bool PeFormatParser::isDll() const - * @return @c true if file is dynamic linked library, @c false otherwise - */ - -/** - * @fn bool PeFormatParser::getEpAddress(unsigned long long &epAddress) const - * Get virtual address of entry point - * @param epAddress Into this parameter the resulting number is stored - * @return @c true if file has entry point and entry point address was successfully detected, - * @c false otherwise - * - * If file has no associated entry point, @a epAddress is left unchanged - */ - -/** - * @fn bool PeFormatParser::getEpOffset(unsigned long long &epOffset) const - * Get offset of entry point - * @param epOffset Into this parameter the resulting number is stored - * @return @c true if file has entry point and entry point offset was successfully detected, - * @c false otherwise - * - * If file has no associated entry point, @a epOffset is left unchanged - */ - -/** - * @fn bool PeFormatParser::getSection(unsigned long long secIndex, PeCoffSection §ion) const - * Get information about section with index @a secIndex - * @param secIndex Index of section (indexed from 0) - * @param section Into this parameter is stored information about section - * @return @c true if section index is valid and section is detected, @c false otherwise - */ - -/** - * @fn bool PeFormatParser::getDllFlags(unsigned long long &dllFlags) const - * Get DLL flags - * @param dllFlags Into this parameter DLL flags will be stored - * @return @c true if file is DLL and flags are successfully detected, @c false otherwise - * - * If file is not DLL, @a dllFlags is left unchanged - */ - -/** - * @fn bool PeFormatParser::getDataDirectoryRelative(unsigned long long index, unsigned long long &relAddr, unsigned long long &size) const - * Get information about data directory - * @param index Index of selected directory - * @param relAddr Into this parameter is stored relative virtual address of directory - * @param size Into this parameter is stored size of directory - * @return @c true if index of selected directory is valid, @c false otherwise - * - * If method returns @c false, @a relAddr and @a size are left unchanged. - */ - -/** - * @fn bool PeFormatParser::getDataDirectoryAbsolute(unsigned long long index, unsigned long long &absAddr, unsigned long long &size) const - * Get information about data directory - * @param index Index of selected directory - * @param absAddr Into this parameter is stored absolute virtual address of directory - * @param size Into this parameter is stored size of directory - * @return @c true if index of selected directory is valid, @c false otherwise - * - * If method returns @c false, @a absAddr and @a size are left unchanged. - */ - -/** - * @fn bool PeFormatParser::getImportedLibraryFileName(unsigned long long index, std::string &fileName) const - * Get file name of imported library - * @param index Index of selected library (indexed from 0) - * @param fileName Into this parameter is stored name of selected library - * @return @c true if index of selected directory is valid, @c false otherwise - */ - -/** - * @fn std::unique_ptr PeFormatParser::getImport(unsigned long long fileIndex, unsigned long long importIndex) const - * @param fileIndex Index of selected library (indexed from 0) - * @param importIndex Index of selected import in selected library (indexed from 0) - * @return Newly created import if index of library and index of import are valid, @c nullptr otherwise - */ - -} // namespace fileformat -} // namespace retdec diff --git a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.cpp b/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.cpp deleted file mode 100644 index 959483a3d..000000000 --- a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/** - * @file src/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.cpp - * @brief Methods of PeFormatParser32 class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "retdec/fileformat/file_format/file_format.h" -#include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.h" -#include "retdec/fileformat/file_format/pe/pe_template.h" - -using namespace PeLib; - -namespace retdec { -namespace fileformat { - -/** - * Constructor - * @param fInputFile Pointer to input file - * @param peFile32 32-bit PE file - */ -PeFormatParser32::PeFormatParser32(const FileFormat *fInputFile, PeLib::PeFileT<32> *peFile32) : PeFormatParser(fInputFile), - peFile(peFile32), peHeader(peFile32->peHeader()) -{ - -} - -unsigned long long PeFormatParser32::getDeclaredNumberOfSections() const -{ - return peDeclaredNumberOfSections(peHeader); -} - -unsigned long long PeFormatParser32::getStoredNumberOfSections() const -{ - return peStoredNumberOfSections(peHeader); -} - -unsigned long long PeFormatParser32::getMachineType() const -{ - return peHeader.getMachine(); -} - -unsigned long long PeFormatParser32::getImageBaseAddress() const -{ - return peImageBase(peHeader); -} - -unsigned long long PeFormatParser32::getCoffSymbolTableOffset() const -{ - return peCoffSymbolTableOffset(peHeader); -} - -unsigned long long PeFormatParser32::getNumberOfCoffSymbols() const -{ - return peNumberOfCoffSymbols(peHeader); -} - -unsigned long long PeFormatParser32::getMajorLinkerVersion() const -{ - return peMajorLinkerVersion(peHeader); -} - -unsigned long long PeFormatParser32::getMinorLinkerVersion() const -{ - return peMinorLinkerVersion(peHeader); -} - -unsigned long long PeFormatParser32::getFileFlags() const -{ - return peFileFlags(peHeader); -} - -unsigned long long PeFormatParser32::getTimeStamp() const -{ - return peTimeStamp(peHeader); -} - -unsigned long long PeFormatParser32::getOptionalHeaderSize() const -{ - return peSizeOfOptionalHeader(peHeader); -} - -bool PeFormatParser32::isSizeOfHeaderMultipleOfFileAlignment() const -{ - return peIsSizeOfHeaderMultipleOfFileAlignment(peHeader); -} - -unsigned long long PeFormatParser32::getFileAlignment() const -{ - return peFileAlignment(peHeader); -} - -unsigned long long PeFormatParser32::getSectionAlignment() const -{ - return peSectionAlignment(peHeader); -} - -unsigned long long PeFormatParser32::getSizeOfHeaders() const -{ - return peSizeOfHeaders(peHeader); -} - -unsigned long long PeFormatParser32::getSizeOfImage() const -{ - return peSizeOfImage(peHeader); -} - -unsigned long long PeFormatParser32::getChecksum() const -{ - return peChecksum(peHeader); -} - -unsigned long long PeFormatParser32::getSizeOfStackReserve() const -{ - return peSizeOfStackReserve(peHeader); -} - -unsigned long long PeFormatParser32::getSizeOfStackCommit() const -{ - return peSizeOfStackCommit(peHeader); -} - -unsigned long long PeFormatParser32::getSizeOfHeapReserve() const -{ - return peSizeOfHeapReserve(peHeader); -} - -unsigned long long PeFormatParser32::getSizeOfHeapCommit() const -{ - return peSizeOfHeapCommit(peHeader); -} - -unsigned long long PeFormatParser32::getSizeOfPeSignature() const -{ - return peSizeOfPeSignature(peHeader); -} - -unsigned long long PeFormatParser32::getLoadedSizeOfNtHeaders() const -{ - return peLoadedSizeOfNtHeaders(peHeader); -} - -unsigned long long PeFormatParser32::getAllocatedSizeOfNtHeaders() const -{ - return peAllocatedSizeOfNtHeaders(peHeader); -} - -unsigned long long PeFormatParser32::getDeclaredNumberOfDataDirectories() const -{ - return peNumberOfDeclaredDataDirectories(peHeader); -} - -unsigned long long PeFormatParser32::getStoredNumberOfDataDirectories() const -{ - return peNumberOfStoredDataDirectories(peHeader); -} - -unsigned long long PeFormatParser32::getNumberOfImportedLibraries() const -{ - return peNumberOfImportedLibraries(peFile->impDir()); -} - -unsigned long long PeFormatParser32::getNumberOfDelayImportedLibraries() const -{ - return peNumberOfDelayImportedLibraries(peFile->delayImports()); -} - -bool PeFormatParser32::isDll() const -{ - return peIsDll(peHeader); -} - -bool PeFormatParser32::getEpAddress(unsigned long long &epAddress) const -{ - const auto addr = peEpAddress(peHeader); - // file has no entry point - if(!addr && !peEpOffset(peHeader)) - { - return false; - } - - epAddress = addr + peImageBase(peHeader); - return true; -} - -bool PeFormatParser32::getEpOffset(unsigned long long &epOffset) const -{ - unsigned long long epAddress = 0; - if(!getEpAddress(epAddress)) - { - return false; - } - - const auto offset = peEpOffset(peHeader); - if(offset == std::numeric_limits::max()) - { - return false; - } - - epOffset = offset; - return true; -} - -bool PeFormatParser32::getSection(unsigned long long secIndex, PeCoffSection §ion) const -{ - return peSectionWithIndex(inputFile, peHeader, section, secIndex); -} - -bool PeFormatParser32::getDllFlags(unsigned long long &dllFlags) const -{ - return peDllFlags(peHeader, dllFlags); -} - -bool PeFormatParser32::getDataDirectoryRelative(unsigned long long index, unsigned long long &relAddr, unsigned long long &size) const -{ - return peDataDirectoryRelative(peHeader, relAddr, size, index); -} - -bool PeFormatParser32::getDataDirectoryAbsolute(unsigned long long index, unsigned long long &absAddr, unsigned long long &size) const -{ - return peDataDirectoryAbsolute(peHeader, absAddr, size, index); -} - -bool PeFormatParser32::getImportedLibraryFileName(unsigned long long index, std::string &fileName) const -{ - return peImportedLibraryFileName(peFile->impDir(), fileName, index); -} - -bool PeFormatParser32::getDelayImportedLibraryFileName(unsigned long long index, std::string &fileName) const -{ - return peDelayImportedLibraryFileName(peFile->delayImports(), fileName, index); -} - -std::unique_ptr PeFormatParser32::getImport(unsigned long long fileIndex, unsigned long long importIndex) const -{ - return peImport(peHeader, peFile->impDir(), fileIndex, importIndex); -} - -std::unique_ptr PeFormatParser32::getDelayImport(unsigned long long fileIndex, unsigned long long importIndex) const -{ - return peDelayImport(peHeader, peFile->delayImports(), fileIndex, importIndex); -} - -unsigned long long PeFormatParser32::getNumberOfExportedFunctions() const -{ - return peNumberOfExportedFunctions(peFile->expDir()); -} - -bool PeFormatParser32::getExportedFunction(unsigned long long index, Export& exportedFunction) const -{ - return peExportedFunction(peHeader, peFile->expDir(), index, exportedFunction); -} - -unsigned long long PeFormatParser32::getNumberOfDebugEntries() const -{ - return peNumberOfDebugEntries(peFile->debugDir()); -} - -bool PeFormatParser32::getDebugEntryData(unsigned long long index, std::vector& data) const -{ - return peDebugEntryData(peFile->debugDir(), index, data); -} - -bool PeFormatParser32::getDebugEntryTimeDateStamp(unsigned long long index, unsigned long long& timeDateStamp) const -{ - return peDebugEntryTimeDateStamp(peFile->debugDir(), index, timeDateStamp); -} - -bool PeFormatParser32::getDebugEntryPointerToRawData(unsigned long long index, unsigned long long& pointerToRawData) const -{ - return peDebugEntryPointerToRawData(peFile->debugDir(), index, pointerToRawData); -} - -unsigned long long PeFormatParser32::getResourceDirectoryOffset() const -{ - return peResourceDirectoryOffset(peFile->resDir()); -} - -const PeLib::ResourceNode* PeFormatParser32::getResourceTreeRoot() const -{ - return peResourceTreeRoot(peFile->resDir()); -} - -unsigned long long PeFormatParser32::getTlsStartAddressOfRawData() const -{ - return peTlsStartAddressOfRawData(peFile->tlsDir()); -} - -unsigned long long PeFormatParser32::getTlsEndAddressOfRawData() const -{ - return peTlsEndAddressOfRawData(peFile->tlsDir()); -} - -unsigned long long PeFormatParser32::getTlsAddressOfIndex() const -{ - return peTlsAddressOfIndex(peFile->tlsDir()); -} - -unsigned long long PeFormatParser32::getTlsAddressOfCallBacks() const -{ - return peTlsAddressOfCallBacks(peFile->tlsDir()); -} - -unsigned long long PeFormatParser32::getTlsSizeOfZeroFill() const -{ - return peTlsSizeOfZeroFill(peFile->tlsDir()); -} - -unsigned long long PeFormatParser32::getTlsCharacteristics() const -{ - return peTlsCharacteristics(peFile->tlsDir()); -} - -std::unique_ptr PeFormatParser32::getClrHeader() const -{ - return peGetClrHeader(peFile->comDir()); -} - -unsigned long long PeFormatParser32::getNumberOfRelocations() const -{ - return peNumberOfRelocations(peFile->relocDir()); -} - -unsigned long long PeFormatParser32::getNumberOfRelocationData(unsigned long long index) const -{ - return peNumberOfRelocationData(peFile->relocDir(), index); -} - -unsigned long long PeFormatParser32::getChecksumFileOffset() const -{ - return peChecksumFileOffset(peHeader); -} - -unsigned long long PeFormatParser32::getSecurityDirFileOffset() const -{ - return peSecurityDirFileOffset(peHeader); -} - -unsigned long long PeFormatParser32::getSecurityDirRva() const -{ - return peSecurityDirRva(peHeader); -} - -unsigned long long PeFormatParser32::getSecurityDirSize() const -{ - return peSecurityDirSize(peHeader); -} - -retdec::common::RangeContainer PeFormatParser32::getImportDirectoryOccupiedAddresses() const -{ - return peImportDirectoryOccupiedAddresses(peFile->impDir()); -} - -retdec::common::RangeContainer PeFormatParser32::getExportDirectoryOccupiedAddresses() const -{ - return peExportDirectoryOccupiedAddresses(peFile->expDir()); -} - -retdec::common::RangeContainer PeFormatParser32::getDebugDirectoryOccupiedAddresses() const -{ - return peDebugDirectoryOccupiedAddresses(peFile->debugDir()); -} - -retdec::common::RangeContainer PeFormatParser32::getResourceDirectoryOccupiedAddresses() const -{ - return peResourceDirectoryOccupiedAddresses(peFile->resDir()); -} - -} // namespace fileformat -} // namespace retdec diff --git a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.cpp b/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.cpp deleted file mode 100644 index 75da5ec60..000000000 --- a/src/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/** - * @file src/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.cpp - * @brief Methods of PeFormatParser64 class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "retdec/fileformat/file_format/file_format.h" -#include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.h" -#include "retdec/fileformat/file_format/pe/pe_template.h" - -using namespace PeLib; - -namespace retdec { -namespace fileformat { - -/** - * Constructor - * @param fInputFile Pointer to input file - * @param peFile64 64-bit PE file - */ -PeFormatParser64::PeFormatParser64(const FileFormat *fInputFile, PeLib::PeFileT<64> *peFile64) : PeFormatParser(fInputFile), - peFile(peFile64), peHeader(peFile64->peHeader()) -{ - -} - -unsigned long long PeFormatParser64::getDeclaredNumberOfSections() const -{ - return peDeclaredNumberOfSections(peHeader); -} - -unsigned long long PeFormatParser64::getStoredNumberOfSections() const -{ - return peStoredNumberOfSections(peHeader); -} - -unsigned long long PeFormatParser64::getMachineType() const -{ - return peHeader.getMachine(); -} - -unsigned long long PeFormatParser64::getImageBaseAddress() const -{ - return peImageBase(peHeader); -} - -unsigned long long PeFormatParser64::getCoffSymbolTableOffset() const -{ - return peCoffSymbolTableOffset(peHeader); -} - -unsigned long long PeFormatParser64::getNumberOfCoffSymbols() const -{ - return peNumberOfCoffSymbols(peHeader); -} - -unsigned long long PeFormatParser64::getMajorLinkerVersion() const -{ - return peMajorLinkerVersion(peHeader); -} - -unsigned long long PeFormatParser64::getMinorLinkerVersion() const -{ - return peMinorLinkerVersion(peHeader); -} - -unsigned long long PeFormatParser64::getFileFlags() const -{ - return peFileFlags(peHeader); -} - -unsigned long long PeFormatParser64::getTimeStamp() const -{ - return peTimeStamp(peHeader); -} - -unsigned long long PeFormatParser64::getOptionalHeaderSize() const -{ - return peSizeOfOptionalHeader(peHeader); -} - -bool PeFormatParser64::isSizeOfHeaderMultipleOfFileAlignment() const -{ - return peIsSizeOfHeaderMultipleOfFileAlignment(peHeader); -} - -unsigned long long PeFormatParser64::getFileAlignment() const -{ - return peFileAlignment(peHeader); -} - -unsigned long long PeFormatParser64::getSectionAlignment() const -{ - return peSectionAlignment(peHeader); -} - -unsigned long long PeFormatParser64::getSizeOfHeaders() const -{ - return peSizeOfHeaders(peHeader); -} - -unsigned long long PeFormatParser64::getSizeOfImage() const -{ - return peSizeOfImage(peHeader); -} - -unsigned long long PeFormatParser64::getChecksum() const -{ - return peChecksum(peHeader); -} - -unsigned long long PeFormatParser64::getSizeOfStackReserve() const -{ - return peSizeOfStackReserve(peHeader); -} - -unsigned long long PeFormatParser64::getSizeOfStackCommit() const -{ - return peSizeOfStackCommit(peHeader); -} - -unsigned long long PeFormatParser64::getSizeOfHeapReserve() const -{ - return peSizeOfHeapReserve(peHeader); -} - -unsigned long long PeFormatParser64::getSizeOfHeapCommit() const -{ - return peSizeOfHeapCommit(peHeader); -} - -unsigned long long PeFormatParser64::getSizeOfPeSignature() const -{ - return peSizeOfPeSignature(peHeader); -} - -unsigned long long PeFormatParser64::getLoadedSizeOfNtHeaders() const -{ - return peLoadedSizeOfNtHeaders(peHeader); -} - -unsigned long long PeFormatParser64::getAllocatedSizeOfNtHeaders() const -{ - return peAllocatedSizeOfNtHeaders(peHeader); -} - -unsigned long long PeFormatParser64::getDeclaredNumberOfDataDirectories() const -{ - return peNumberOfDeclaredDataDirectories(peHeader); -} - -unsigned long long PeFormatParser64::getStoredNumberOfDataDirectories() const -{ - return peNumberOfStoredDataDirectories(peHeader); -} - -unsigned long long PeFormatParser64::getNumberOfImportedLibraries() const -{ - return peNumberOfImportedLibraries(peFile->impDir()); -} - -unsigned long long PeFormatParser64::getNumberOfDelayImportedLibraries() const -{ - return peNumberOfDelayImportedLibraries(peFile->delayImports()); -} - -bool PeFormatParser64::isDll() const -{ - return peIsDll(peHeader); -} - -bool PeFormatParser64::getEpAddress(unsigned long long &epAddress) const -{ - const auto addr = peEpAddress(peHeader); - // file has no entry point - if(!addr && !peEpOffset(peHeader)) - { - return false; - } - - epAddress = addr + peImageBase(peHeader); - return true; -} - -bool PeFormatParser64::getEpOffset(unsigned long long &epOffset) const -{ - unsigned long long epAddress = 0; - if(!getEpAddress(epAddress)) - { - return false; - } - - const auto offset = peEpOffset(peHeader); - if(offset == std::numeric_limits::max()) - { - return false; - } - - epOffset = offset; - return true; -} - -bool PeFormatParser64::getSection(unsigned long long secIndex, PeCoffSection §ion) const -{ - return peSectionWithIndex(inputFile, peHeader, section, secIndex); -} - -bool PeFormatParser64::getDllFlags(unsigned long long &dllFlags) const -{ - return peDllFlags(peHeader, dllFlags); -} - -bool PeFormatParser64::getDataDirectoryRelative(unsigned long long index, unsigned long long &relAddr, unsigned long long &size) const -{ - return peDataDirectoryRelative(peHeader, relAddr, size, index); -} - -bool PeFormatParser64::getDataDirectoryAbsolute(unsigned long long index, unsigned long long &absAddr, unsigned long long &size) const -{ - return peDataDirectoryAbsolute(peHeader, absAddr, size, index); -} - -bool PeFormatParser64::getImportedLibraryFileName(unsigned long long index, std::string &fileName) const -{ - return peImportedLibraryFileName(peFile->impDir(), fileName, index); -} - -bool PeFormatParser64::getDelayImportedLibraryFileName(unsigned long long index, std::string &fileName) const -{ - return peDelayImportedLibraryFileName(peFile->delayImports(), fileName, index); -} - -std::unique_ptr PeFormatParser64::getImport(unsigned long long fileIndex, unsigned long long importIndex) const -{ - return peImport(peHeader, peFile->impDir(), fileIndex, importIndex); -} - -std::unique_ptr PeFormatParser64::getDelayImport(unsigned long long fileIndex, unsigned long long importIndex) const -{ - return peDelayImport(peHeader, peFile->delayImports(), fileIndex, importIndex); -} - -unsigned long long PeFormatParser64::getNumberOfExportedFunctions() const -{ - return peNumberOfExportedFunctions(peFile->expDir()); -} - -bool PeFormatParser64::getExportedFunction(unsigned long long index, Export &exportedFunction) const -{ - return peExportedFunction(peHeader, peFile->expDir(), index, exportedFunction); -} - -unsigned long long PeFormatParser64::getNumberOfDebugEntries() const -{ - return peNumberOfDebugEntries(peFile->debugDir()); -} - -bool PeFormatParser64::getDebugEntryData(unsigned long long index, std::vector& data) const -{ - return peDebugEntryData(peFile->debugDir(), index, data); -} - -bool PeFormatParser64::getDebugEntryTimeDateStamp(unsigned long long index, unsigned long long& timeDateStamp) const -{ - return peDebugEntryTimeDateStamp(peFile->debugDir(), index, timeDateStamp); -} - -bool PeFormatParser64::getDebugEntryPointerToRawData(unsigned long long index, unsigned long long& pointerToRawData) const -{ - return peDebugEntryPointerToRawData(peFile->debugDir(), index, pointerToRawData); -} - -unsigned long long PeFormatParser64::getResourceDirectoryOffset() const -{ - return peResourceDirectoryOffset(peFile->resDir()); -} - -const PeLib::ResourceNode* PeFormatParser64::getResourceTreeRoot() const -{ - return peResourceTreeRoot(peFile->resDir()); -} - -unsigned long long PeFormatParser64::getTlsStartAddressOfRawData() const -{ - return peTlsStartAddressOfRawData(peFile->tlsDir()); -} - -unsigned long long PeFormatParser64::getTlsEndAddressOfRawData() const -{ - return peTlsEndAddressOfRawData(peFile->tlsDir()); -} - -unsigned long long PeFormatParser64::getTlsAddressOfIndex() const -{ - return peTlsAddressOfIndex(peFile->tlsDir()); -} - -unsigned long long PeFormatParser64::getTlsAddressOfCallBacks() const -{ - return peTlsAddressOfCallBacks(peFile->tlsDir()); -} - -unsigned long long PeFormatParser64::getTlsSizeOfZeroFill() const -{ - return peTlsSizeOfZeroFill(peFile->tlsDir()); -} - -unsigned long long PeFormatParser64::getTlsCharacteristics() const -{ - return peTlsCharacteristics(peFile->tlsDir()); -} - -std::unique_ptr PeFormatParser64::getClrHeader() const -{ - return peGetClrHeader(peFile->comDir()); -} - -unsigned long long PeFormatParser64::getNumberOfRelocations() const -{ - return peNumberOfRelocations(peFile->relocDir()); -} - -unsigned long long PeFormatParser64::getNumberOfRelocationData(unsigned long long index) const -{ - return peNumberOfRelocationData(peFile->relocDir(), index); -} - -unsigned long long PeFormatParser64::getChecksumFileOffset() const -{ - return peChecksumFileOffset(peHeader); -} - -unsigned long long PeFormatParser64::getSecurityDirFileOffset() const -{ - return peSecurityDirFileOffset(peHeader); -} - -unsigned long long PeFormatParser64::getSecurityDirRva() const -{ - return peSecurityDirRva(peHeader); -} - -unsigned long long PeFormatParser64::getSecurityDirSize() const -{ - return peSecurityDirSize(peHeader); -} - -retdec::common::RangeContainer PeFormatParser64::getImportDirectoryOccupiedAddresses() const -{ - return peImportDirectoryOccupiedAddresses(peFile->impDir()); -} - -retdec::common::RangeContainer PeFormatParser64::getExportDirectoryOccupiedAddresses() const -{ - return peExportDirectoryOccupiedAddresses(peFile->expDir()); -} - -retdec::common::RangeContainer PeFormatParser64::getDebugDirectoryOccupiedAddresses() const -{ - return peDebugDirectoryOccupiedAddresses(peFile->debugDir()); -} - -retdec::common::RangeContainer PeFormatParser64::getResourceDirectoryOccupiedAddresses() const -{ - return peResourceDirectoryOccupiedAddresses(peFile->resDir()); -} - -} // namespace fileformat -} // namespace retdec diff --git a/src/fileformat/utils/format_detection.cpp b/src/fileformat/utils/format_detection.cpp index d63c4c24b..704ffe5b8 100644 --- a/src/fileformat/utils/format_detection.cpp +++ b/src/fileformat/utils/format_detection.cpp @@ -128,44 +128,9 @@ bool isPe(std::istream& stream) { // Create instance of the ImageLoader with most benevolent flags ImageLoader imgLoader(0); - bool bIsPe = false; // Load the image from stream. Only load headers. - if(imgLoader.Load(stream, 0, true) == ERROR_NONE) - bIsPe = (imgLoader.getNtSignature() == PELIB_IMAGE_NT_SIGNATURE); - return bIsPe; - -/* - resetStream(stream); - - std::unique_ptr file(openPeFile(stream)); - if(!file) - { - return false; - } - - std::uint32_t signature = 0; - try - { - file->readMzHeader(); - file->readPeHeader(); - switch(getFileType(stream)) - { - case PEFILE32: - signature = static_cast*>(file.get())->peHeader().getNtSignature(); - break; - case PEFILE64: - signature = static_cast*>(file.get())->peHeader().getNtSignature(); - break; - default:; - } - } catch(...) - { - return false; - } - - return signature == 0x4550 || signature == 0x50450000; -*/ + return (imgLoader.Load(stream, 0, true) == ERROR_NONE); } /** diff --git a/src/fileinfo/CMakeLists.txt b/src/fileinfo/CMakeLists.txt index 6681c35ae..f93573954 100644 --- a/src/fileinfo/CMakeLists.txt +++ b/src/fileinfo/CMakeLists.txt @@ -100,10 +100,7 @@ add_executable(fileinfo file_wrapper/coff_wrapper.cpp file_wrapper/elf_wrapper.cpp file_wrapper/macho_wrapper.cpp - file_wrapper/pe/pe_wrapper.cpp - file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.cpp - file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.cpp - file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.cpp + file_wrapper/pe_wrapper.cpp fileinfo.cpp pattern_detector/pattern_detector.cpp ) diff --git a/src/fileinfo/file_detector/pe_detector.cpp b/src/fileinfo/file_detector/pe_detector.cpp index 13502235e..21a3f959d 100644 --- a/src/fileinfo/file_detector/pe_detector.cpp +++ b/src/fileinfo/file_detector/pe_detector.cpp @@ -355,13 +355,15 @@ void PeDetector::getVisualBasicInfo() void PeDetector::detectFileClass() { - if (peParser->isPe32()) + switch(peParser->getBits()) { - fileInfo.setFileClass("32-bit"); - } - else if (peParser->isPe64()) - { - fileInfo.setFileClass("64-bit"); + case 64: + fileInfo.setFileClass("64-bit"); + break; + + case 32: + fileInfo.setFileClass("32-bit"); + break; } } diff --git a/src/fileinfo/file_detector/pe_detector.h b/src/fileinfo/file_detector/pe_detector.h index 76a4a796d..4b0588fae 100644 --- a/src/fileinfo/file_detector/pe_detector.h +++ b/src/fileinfo/file_detector/pe_detector.h @@ -8,7 +8,7 @@ #define FILEINFO_FILE_DETECTOR_PE_DETECTOR_H #include "fileinfo/file_detector/file_detector.h" -#include "fileinfo/file_wrapper/pe/pe_wrapper.h" +#include "fileinfo/file_wrapper/pe_wrapper.h" namespace retdec { namespace fileinfo { diff --git a/src/fileinfo/file_information/file_information_types/file_section.cpp b/src/fileinfo/file_information/file_information_types/file_section.cpp index 69bc0715d..d96c7aa30 100644 --- a/src/fileinfo/file_information/file_information_types/file_section.cpp +++ b/src/fileinfo/file_information/file_information_types/file_section.cpp @@ -258,7 +258,7 @@ void FileSection::getFlagsDescriptors(std::vector &desc, std::vecto * Set section name * @param name Section name */ -void FileSection::setName(std::string name) +void FileSection::setName(const std::string & name) { sectionName = name; } diff --git a/src/fileinfo/file_information/file_information_types/file_section.h b/src/fileinfo/file_information/file_information_types/file_section.h index 4e024196c..ded8a0738 100644 --- a/src/fileinfo/file_information/file_information_types/file_section.h +++ b/src/fileinfo/file_information/file_information_types/file_section.h @@ -77,7 +77,7 @@ class FileSection /// @name Setters /// @{ - void setName(std::string name); + void setName(const std::string & name); void setType(std::string type); void setCrc32(std::string sectionCrc32); void setMd5(std::string sectionMd5); diff --git a/src/fileinfo/file_wrapper/pe/pe_template.h b/src/fileinfo/file_wrapper/pe/pe_template.h deleted file mode 100644 index 0a1d39b3a..000000000 --- a/src/fileinfo/file_wrapper/pe/pe_template.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file src/fileinfo/file_wrapper/pe/pe_template.h - * @brief Template functions for PE files. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef FILEINFO_FILE_WRAPPER_PE_PE_TEMPLATE_H -#define FILEINFO_FILE_WRAPPER_PE_PE_TEMPLATE_H - -#include "retdec/fileformat/file_format/pe/pe_template_aux.h" -#include "fileinfo/file_information/file_information_types/file_section.h" - -namespace retdec { -namespace fileinfo { - -/** - * Get status of file - * @param peHeader PE reader - * @return Status of file ("PE32", "ROM image", "PE32+" or empty string if status of file is unknown) - */ -template std::string peFileStatus(const PeLib::PeHeaderT &peHeader) -{ - switch(peHeader.getMagic()) - { - case 0x10B: - return "PE32"; - case 0x107: - return "ROM image"; - case 0x20B: - return "PE32+"; - default: - return ""; - } -} - -/** - * Get information about section with index @a sectionIndex - * @param peHeader PE reader - * @param section Class for save information about section - * @param sectionIndex Index of section (indexed from 0) - * @return @c true if section index is valid and section was detected, @c false otherwise - * - * Only flag values and size are set. Function does not set flags descriptors or their abbreviations. - * Previously set descriptors and abbreviations are deleted. - */ -template bool peSectionWithIndex(const PeLib::PeHeaderT &peHeader, FileSection §ion, unsigned long long sectionIndex) -{ - std::string sectionName; - if(!retdec::fileformat::peSectionName(peHeader, sectionName, sectionIndex)) - { - return false; - } - const unsigned long long sectionFlagsSize = 32; - - section.setIndex(sectionIndex); - section.setName(sectionName); - section.setStartAddress(peHeader.getVirtualAddress(sectionIndex) + peHeader.getImageBase()); - section.setSizeInMemory(peHeader.getVirtualSize(sectionIndex)); - section.setOffset(peHeader.getPointerToRawData(sectionIndex)); - section.setSizeInFile(peHeader.getSizeOfRawData(sectionIndex)); - section.setRelocationsOffset(peHeader.getPointerToRelocations(sectionIndex)); - section.setNumberOfRelocations(peHeader.getNumberOfRelocations(sectionIndex)); - section.setLineNumbersOffset(peHeader.getPointerToLinenumbers(sectionIndex)); - section.setNumberOfLineNumbers(peHeader.getNumberOfLinenumbers(sectionIndex)); - section.setFlagsSize(sectionFlagsSize); - section.setFlags(peHeader.getCharacteristics(sectionIndex)); - section.clearFlagsDescriptors(); - return true; -} - -} // namespace fileinfo -} // namespace retdec - -#endif diff --git a/src/fileinfo/file_wrapper/pe/pe_wrapper.cpp b/src/fileinfo/file_wrapper/pe/pe_wrapper.cpp deleted file mode 100644 index e64ed34ec..000000000 --- a/src/fileinfo/file_wrapper/pe/pe_wrapper.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper.cpp - * @brief Methods of PeWrapper class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "retdec/utils/array.h" -#include "retdec/utils/conversion.h" -#include "fileinfo/file_wrapper/pe/pe_wrapper.h" -#include "fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.h" -#include "fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.h" - -using namespace retdec::utils; -using namespace PeLib; -using namespace retdec::fileformat; - -namespace retdec { -namespace fileinfo { - -namespace -{ - -const std::string directories[] = {"Export table", "Import table", "Resource table", "Exception table", - "Certificate Table", "Relocation table", "Debug directory", - "Architecture directory", "Global pointer directory", "TLS Table", - "Load configuration table", "Bound import table", - "Import address table", "Delay import descriptor", - "CLR runtime header", "Reserved"}; - -/** - * Get type of data directory - * @param dirIndex Directory index - * @return Directory type of empty string if index of directory is not valid - */ -std::string getDirectoryType(unsigned long long dirIndex) -{ - return (dirIndex < arraySize(directories) ? directories[dirIndex] : ""); -} - -/** - * Get link to symbol section - * @param link Link to section in number representation - * @return Link to section in string representation - */ -std::string getSymbolLinkToSection(std::uint16_t link) -{ - if(!link) - { - return "UNDEFINED"; - } - else if(link == std::numeric_limits::max()) - { - return "ABSOLUTE"; - } - else if(link == std::numeric_limits::max() - 1) - { - return "DEBUG"; - } - - return std::to_string(link - 1); -} - -/** - * Get type of symbol - * @param type Type of symbol in number representation - * @return Type of symbol in string representation - */ -std::string getSymbolType(std::uint8_t type) -{ - if(type < 0x10) - { - return "SIMPLE"; - } - else if(type < 0x20) - { - return "POINTER"; - } - else if(type < 0x30) - { - return "FUNCTION"; - } - else if(type < 0x40) - { - return "ARRAY"; - } - - return ""; -} - -} // anonymous namespace - -/** - * Constructor - * @param pathToFile Path to PE binary file - * @param dllListFile Path to text file containing list of OS DLLs - * @param loadFlags Load flags - */ -PeWrapper::PeWrapper( - const std::string & pathToFile, - const std::string & dllListFile, - retdec::fileformat::LoadFlags loadFlags) - : PeFormat(pathToFile, dllListFile, loadFlags), wrapperParser(nullptr) -{ - if (isPe32()) - { - wrapperParser = new PeWrapperParser32(*peHeader32); - } - else if (isPe64()) - { - wrapperParser = new PeWrapperParser64(*peHeader64); - } - else - { - stateIsValid = false; - return; - } -} - -/** - * Destructor - */ -PeWrapper::~PeWrapper() -{ - delete wrapperParser; -} - -/** - * Get type of binary file - * @return Type of binary file (e.g. DLL) - */ -std::string PeWrapper::getTypeOfFile() const -{ - return isDll() ? "DLL" : "Executable file"; -} - -/** - * Get type of PE file (e.g. "PE32" or "PE32+") - * @return Type of PE file - */ -std::string PeWrapper::getPeType() const -{ - return wrapperParser->getPeType(); -} - -/** - * Get information about data directory - * @param dirIndex Index of directory (indexed from 0) - * @param directory Instance of class for save information about data directory - * @return @c true if section index is valid and section is detected, @c false otherwise - */ -bool PeWrapper::getDataDirectory(unsigned long long dirIndex, DataDirectory &directory) const -{ - unsigned long long absAddr, size; - if(!getDataDirectoryAbsolute(dirIndex, absAddr, size)) - { - return false; - } - - directory.setAddress(absAddr); - directory.setSize(size); - directory.setType(getDirectoryType(dirIndex)); - return true; -} - -/** - * Get information about file section - * @param secIndex Index of section (indexed from 0) - * @param section Instance of class for save information about file section - * @return @c true if section index is valid and section is detected, @c false otherwise - */ -bool PeWrapper::getFileSection(unsigned long long secIndex, FileSection §ion) const -{ - auto result = wrapperParser->getSection(secIndex, section); - section.setCrc32(""); - section.setMd5(""); - section.setSha256(""); - unsigned long long index; - if(strToNum(section.getIndexStr(), index)) - { - const auto *auxSec = getSection(index); - if(auxSec) - { - double entropy; - if(auxSec->getEntropy(entropy)) - { - section.setEntropy(entropy); - } - section.setCrc32(auxSec->getCrc32()); - section.setMd5(auxSec->getMd5()); - section.setSha256(auxSec->getSha256()); - } - } - - return result; -} - -/** - * Get one symbol from COFF symbol table - * @param index Index of symbol - * @param symbol Instance of class for save information about symbol - * @return @c true if symbol index is valid and symbol is detected, @c false otherwise - */ -bool PeWrapper::getCoffSymbol(unsigned long long index, Symbol &symbol) const -{ - const CoffSymbolTable &symTab = file->coffSymTab(); - if(index >= symTab.getNumberOfStoredSymbols()) - { - return false; - } - - symbol.setIndex(symTab.getSymbolIndex(index)); - symbol.setName(symTab.getSymbolName(index)); - symbol.setValue(symTab.getSymbolValue(index)); - symbol.setLinkToSection(getSymbolLinkToSection(symTab.getSymbolSectionNumber(index))); - symbol.setType(getSymbolType(symTab.getSymbolTypeComplex(index))); - return true; -} - -} // namespace fileinfo -} // namespace retdec diff --git a/src/fileinfo/file_wrapper/pe/pe_wrapper.h b/src/fileinfo/file_wrapper/pe/pe_wrapper.h deleted file mode 100644 index f423a2e93..000000000 --- a/src/fileinfo/file_wrapper/pe/pe_wrapper.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper.h - * @brief Definition of PeWrapper class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_H -#define FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_H - -#include "retdec/fileformat/file_format/pe/pe_format.h" -#include "fileinfo/file_information/file_information_types/symbol_table/symbol.h" -#include "fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.h" - -namespace retdec { -namespace fileinfo { - -/** - * Wrapper for parsing PE files - */ -class PeWrapper : public retdec::fileformat::PeFormat -{ - private: - PeWrapperParser *wrapperParser = nullptr; ///< parser of PE file - public: - PeWrapper(const std::string & pathToFile, const std::string & dllListFile, retdec::fileformat::LoadFlags loadFlags); - virtual ~PeWrapper() override; - - /// @name Detection methods - /// { - std::string getTypeOfFile() const; - std::string getPeType() const; - bool getDataDirectory(unsigned long long dirIndex, DataDirectory &directory) const; - bool getFileSection(unsigned long long secIndex, FileSection §ion) const; - bool getCoffSymbol(unsigned long long index, Symbol &symbol) const; - /// } -}; - -} // namespace fileinfo -} // namespace retdec - -#endif diff --git a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.cpp b/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.cpp deleted file mode 100644 index 4caecb018..000000000 --- a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.cpp - * @brief Methods of PeWrapperParser class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.h" - -namespace retdec { -namespace fileinfo { - -/** - * Constructor - */ -PeWrapperParser::PeWrapperParser() -{ - -} - -/** - * @fn std::string PeWrapperParser::getPeType() const - * Get type of PE file (e.g. "PE32" or "PE32+") - * @return Type of PE file - */ - -/** - * @fn bool PeWrapperParser::getSection(const unsigned long long secIndex, FileSection §ion) const - * Get information about file section - * @param secIndex Index of section (indexed from 0) - * @param section Instance of class for save information about file section - * @return @c true if section index is valid and section is detected, @c false otherwise - */ - -} // namespace fileinfo -} // namespace retdec diff --git a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.h b/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.h deleted file mode 100644 index fd92b44fb..000000000 --- a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.h - * @brief Definition of PeWrapperParser class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_PARSER_PE_WRAPPER_PARSER_H -#define FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_PARSER_PE_WRAPPER_PARSER_H - -#include - -#include "fileinfo/file_information/file_information_types/data_directory.h" -#include "fileinfo/file_information/file_information_types/file_section.h" - -namespace retdec { -namespace fileinfo { - -class PeWrapperParser -{ - public: - PeWrapperParser(); - virtual ~PeWrapperParser() = default; - - /// @name Detection methods - /// @{ - virtual std::string getPeType() const = 0; - virtual bool getSection(const unsigned long long secIndex, FileSection §ion) const = 0; - /// @} -}; - -} // namespace fileinfo -} // namespace retdec - -#endif diff --git a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.cpp b/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.cpp deleted file mode 100644 index 82caebd5b..000000000 --- a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.cpp - * @brief Methods of PeWrapperParser32 class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "fileinfo/file_wrapper/pe/pe_template.h" -#include "fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.h" - -namespace retdec { -namespace fileinfo { - -/** - * Constructor - */ -PeWrapperParser32::PeWrapperParser32(PeLib::PeHeaderT<32> peHeader32) : PeWrapperParser(), peHeader(peHeader32) -{ - -} - -std::string PeWrapperParser32::getPeType() const -{ - return peFileStatus(peHeader); -} - -bool PeWrapperParser32::getSection(const unsigned long long secIndex, FileSection §ion) const -{ - return peSectionWithIndex(peHeader, section, secIndex); -} - -} // namespace fileinfo -} // namespace retdec diff --git a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.h b/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.h deleted file mode 100644 index f46cc0863..000000000 --- a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser32.h - * @brief Definition of PeWrapperParser32 class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_PARSER_PE_WRAPPER_PARSER32_H -#define FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_PARSER_PE_WRAPPER_PARSER32_H - -#include "fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.h" -#include "retdec/pelib/PeLib.h" - -namespace retdec { -namespace fileinfo { - -class PeWrapperParser32 : public PeWrapperParser -{ - private: - PeLib::PeHeaderT<32> peHeader; ///< header of 32-bit PE file - public: - PeWrapperParser32(PeLib::PeHeaderT<32> peHeader32); - - /// @name Detection methods - /// @{ - virtual std::string getPeType() const override; - virtual bool getSection(const unsigned long long secIndex, FileSection §ion) const override; - /// @} -}; - -} // namespace fileinfo -} // namespace retdec - -#endif diff --git a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.cpp b/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.cpp deleted file mode 100644 index d0362f00a..000000000 --- a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.cpp - * @brief Methods of PeWrapperParser64 class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "fileinfo/file_wrapper/pe/pe_template.h" -#include "fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.h" - -namespace retdec { -namespace fileinfo { - -/** - * Constructor - */ -PeWrapperParser64::PeWrapperParser64(PeLib::PeHeaderT<64> peHeader64) : PeWrapperParser(), peHeader(peHeader64) -{ - -} - -std::string PeWrapperParser64::getPeType() const -{ - return peFileStatus(peHeader); -} - -bool PeWrapperParser64::getSection(const unsigned long long secIndex, FileSection §ion) const -{ - return peSectionWithIndex(peHeader, section, secIndex); -} - -} // namespace fileinfo -} // namespace retdec diff --git a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.h b/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.h deleted file mode 100644 index 4e30c72a0..000000000 --- a/src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser64.h - * @brief Definition of PeWrapperParser64 class. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_PARSER_PE_WRAPPER_PARSER64_H -#define FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_PARSER_PE_WRAPPER_PARSER64_H - -#include "fileinfo/file_wrapper/pe/pe_wrapper_parser/pe_wrapper_parser.h" -#include "retdec/pelib/PeLib.h" - -namespace retdec { -namespace fileinfo { - -class PeWrapperParser64 : public PeWrapperParser -{ - private: - PeLib::PeHeaderT<64> peHeader; ///< header of 64-bit PE file - public: - PeWrapperParser64(PeLib::PeHeaderT<64> peHeader64); - - /// @name Detection methods - /// @{ - virtual std::string getPeType() const override; - virtual bool getSection(const unsigned long long secIndex, FileSection §ion) const override; - /// @} -}; - -} // namespace fileinfo -} // namespace retdec - -#endif diff --git a/src/pelib/CMakeLists.txt b/src/pelib/CMakeLists.txt index 29362a932..cae97560d 100644 --- a/src/pelib/CMakeLists.txt +++ b/src/pelib/CMakeLists.txt @@ -8,10 +8,8 @@ add_library(pelib STATIC IatDirectory.cpp ImageLoader.cpp InputBuffer.cpp - MzHeader.cpp OutputBuffer.cpp PeFile.cpp - PeHeader.cpp PeLibAux.cpp RelocationsDirectory.cpp ResourceDirectory.cpp diff --git a/src/pelib/ComHeaderDirectory.cpp b/src/pelib/ComHeaderDirectory.cpp index 2e27aa8ee..45ad4a8a2 100644 --- a/src/pelib/ComHeaderDirectory.cpp +++ b/src/pelib/ComHeaderDirectory.cpp @@ -32,7 +32,7 @@ namespace PeLib } // Read the COM header as-is - if(imageLoader.readImage(&m_ichComHeader, rva, size) != size) + if(imageLoader.readImage(&m_ichComHeader, rva, sizeof(PELIB_IMAGE_COR20_HEADER)) != size) { return ERROR_INVALID_FILE; } diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 361379fc1..1d00590b1 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -56,12 +56,13 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) memset(&dosHeader, 0, sizeof(PELIB_IMAGE_DOS_HEADER)); memset(&fileHeader, 0, sizeof(PELIB_IMAGE_FILE_HEADER)); memset(&optionalHeader, 0, sizeof(PELIB_IMAGE_OPTIONAL_HEADER)); + checkSumFileOffset = 0; + securityDirFileOffset = 0; ntSignature = 0; ldrError = LDR_ERROR_NONE; // By default, set the most benevolent settings sizeofImageMustMatch = false; - //copyWholeHeaderPage = false; ntHeadersSizeCheck = false; appContainerCheck = false; maxSectionCount = 255; @@ -143,12 +144,27 @@ bool PeLib::ImageLoader::relocateImage(uint64_t newImageBase) uint32_t PeLib::ImageLoader::readImage(void * buffer, uint32_t rva, uint32_t bytesToRead) { - return readWriteImage(buffer, rva, bytesToRead, readFromPage); + // If the image was properly mapped, perform an image-read operation + if(rawFileData.size() == 0) + return readWriteImage(buffer, rva, bytesToRead, readFromPage); + + // If the image loader was unable to map the image, we provide fallback method + // by translating the RVA to file offset. Note that in some cases, this methos + // may produce unwanted results. + // Example: If export directory is at the end of section, it will be padded by zeros by the loader, + // but in the on-disk version, next section will follow. + return readWriteImageFile(buffer, rva, bytesToRead, true); } -uint32_t PeLib::ImageLoader::writeImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead) +uint32_t PeLib::ImageLoader::writeImage(void * buffer, uint32_t rva, uint32_t bytesToRead) { - return readWriteImage(buffer, rva, bytesToRead, writeToPage); + // If the image was properly mapped, perform an image-read operation + if(rawFileData.size() == 0) + return readWriteImage(buffer, rva, bytesToRead, writeToPage); + + // If the image loader was unable to map the image, we provide fallback method + // by translating the RVA to file offset. + return readWriteImageFile(buffer, rva, bytesToRead, false); } uint32_t PeLib::ImageLoader::stringLength(uint32_t rva, uint32_t maxLength) const @@ -247,7 +263,7 @@ uint32_t PeLib::ImageLoader::getPointerSize() const return getImageBitability() / 8; } -uint32_t PeLib::ImageLoader::readStringRc(std::string & str, std::uint32_t rva) +uint32_t PeLib::ImageLoader::readStringRc(std::string & str, uint32_t rva) { std::vector wideString; uint32_t bytesToRead; @@ -273,6 +289,23 @@ uint32_t PeLib::ImageLoader::readStringRc(std::string & str, std::uint32_t rva) return charsRead; } +uint32_t PeLib::ImageLoader::readStringRaw(std::vector & fileData, std::string & str, size_t offset) +{ + uint32_t length = 0; + + if(offset < fileData.size()) + { + // Prepare buffer for string + length = strlen(reinterpret_cast(fileData.data() + offset)); + str.resize(length); + + // Copy the string + memcpy(const_cast(str.data()), fileData.data() + offset, length); + } + + return length; +} + uint32_t PeLib::ImageLoader::dumpImage(const char * fileName) { // Create the file for dumping @@ -308,79 +341,7 @@ uint32_t PeLib::ImageLoader::getImageBitability() const return 0; } -std::uint64_t PeLib::ImageLoader::getOrdinalMask() const -{ - return (std::uint64_t)1 << (getImageBitability() - 1); -} - -uint32_t PeLib::ImageLoader::getNtSignature() const -{ - return ntSignature; -} - -uint32_t PeLib::ImageLoader::getMachine() const -{ - return fileHeader.Machine; -} - -uint32_t PeLib::ImageLoader::getPointerToSymbolTable() const -{ - return fileHeader.PointerToSymbolTable; -} - -uint32_t PeLib::ImageLoader::getNumberOfSymbols() const -{ - return fileHeader.NumberOfSymbols; -} - -uint64_t PeLib::ImageLoader::getImageBase() const -{ - return optionalHeader.ImageBase; -} - -std::uint32_t PeLib::ImageLoader::getAddressOfEntryPoint() const -{ - return optionalHeader.AddressOfEntryPoint; -} - -uint32_t PeLib::ImageLoader::getSizeOfHeaders() const -{ - return optionalHeader.SizeOfHeaders; -} - -uint32_t PeLib::ImageLoader::getSizeOfImage() const -{ - return optionalHeader.SizeOfImage; -} - -uint32_t PeLib::ImageLoader::getSizeOfImageAligned() const -{ - return AlignToSize(optionalHeader.SizeOfImage, PELIB_PAGE_SIZE); -} - -uint32_t PeLib::ImageLoader::getSectionAlignment() const -{ - return optionalHeader.SectionAlignment; -} - -uint32_t PeLib::ImageLoader::getFileAlignment() const -{ - return optionalHeader.FileAlignment; -} - -uint32_t PeLib::ImageLoader::getDataDirRva(size_t dataDirIndex) const -{ - // The data directory must be present there - return (optionalHeader.NumberOfRvaAndSizes > dataDirIndex) ? optionalHeader.DataDirectory[dataDirIndex].VirtualAddress : 0; -} - -uint32_t PeLib::ImageLoader::getDataDirSize(size_t dataDirIndex) const -{ - // The data directory must be present there - return (optionalHeader.NumberOfRvaAndSizes > dataDirIndex) ? optionalHeader.DataDirectory[dataDirIndex].Size : 0; -} - -uint32_t PeLib::ImageLoader::getFileOffsetFromRva(std::uint32_t rva) const +uint32_t PeLib::ImageLoader::getFileOffsetFromRva(uint32_t rva) const { // If we have sections loaded, then we calculate the file offset from section headers if(sections.size()) @@ -398,7 +359,7 @@ uint32_t PeLib::ImageLoader::getFileOffsetFromRva(std::uint32_t rva) const { // Make sure we round the pointer to raw data down to PELIB_SECTOR_SIZE. // In case when PointerToRawData is less than 0x200, it maps to the header! - return sectHdr.PointerToRawData & ~(PELIB_SECTOR_SIZE - 1); + return (sectHdr.PointerToRawData & ~(PELIB_SECTOR_SIZE - 1)) + (rva - sectionRvaStart); } } } @@ -407,11 +368,31 @@ uint32_t PeLib::ImageLoader::getFileOffsetFromRva(std::uint32_t rva) const return (rva < optionalHeader.SizeOfHeaders) ? rva : UINT32_MAX; } - // The rva maps directly to the fille offset + // The rva maps directly to the file offset return rva; } -uint32_t PeLib::ImageLoader::getImageProtection(std::uint32_t sectionCharacteristics) const +bool PeLib::ImageLoader::setDataDirectory(std::uint32_t index, std::uint32_t rva, std::uint32_t size) +{ + // Make sure that there is enough data directory entries + if(optionalHeader.NumberOfRvaAndSizes < index) + optionalHeader.NumberOfRvaAndSizes = index; + + // Set the data directory entry + optionalHeader.DataDirectory[index].VirtualAddress = rva; + optionalHeader.DataDirectory[index].Size = size; + return true; +} + +std::uint32_t PeLib::ImageLoader::getRealPointerToRawData(std::size_t sectionIndex) const +{ + if(sectionIndex >= sections.size()) + return UINT32_MAX; + + return sections[sectionIndex].PointerToRawData & ~(PELIB_SECTOR_SIZE - 1); +} + +uint32_t PeLib::ImageLoader::getImageProtection(uint32_t sectionCharacteristics) const { uint32_t Index = 0; @@ -478,7 +459,7 @@ int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOn try { // If there was no detected image error, map the image as if Windows loader would do - if(ldrError == LDR_ERROR_NONE || ldrError == LDR_ERROR_FILE_IS_CUT_LOADABLE) + if(isImageLoadable()) { fileError = captureImageSections(fileData); } @@ -506,6 +487,10 @@ int PeLib::ImageLoader::Load(std::istream & fs, std::streamoff fileOffset, bool size_t fileSize2; int fileError; + // We need to reset the stream's error state for cases where the file size is too small + // Sample: retdec-regression-tests\tools\fileinfo\bugs\exotic-pe-files\shutd0wn97.ex + fs.clear(); + // Get the file size fs.seekg(0, std::ios::end); fileSize = fs.tellg(); @@ -624,6 +609,29 @@ uint32_t PeLib::ImageLoader::readWriteImage(void * buffer, uint32_t rva, uint32_ return bytesRead; } +uint32_t PeLib::ImageLoader::readWriteImageFile(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead, bool bReadOperation) +{ + uint32_t fileOffset = getFileOffsetFromRva(rva); + + // Make sure we won't read/write past the end of the data + if(fileOffset > rawFileData.size()) + return 0; + if((fileOffset + bytesToRead) > rawFileData.size()) + bytesToRead = (uint32_t)(rawFileData.size() - fileOffset); + + // Read the data + if(bytesToRead != 0) + { + if(bReadOperation) + memcpy(buffer, rawFileData.data() + fileOffset, bytesToRead); + else + memcpy(rawFileData.data() + fileOffset, buffer, bytesToRead); + } + + // Return the number of bytes read/written + return bytesToRead; +} + bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t newImageBase, uint32_t VirtualAddress, uint32_t Size) { uint64_t difference = (newImageBase - oldImageBase); @@ -770,7 +778,7 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t return true; } -void PeLib::ImageLoader::writeNewImageBase(std::uint64_t newImageBase) +void PeLib::ImageLoader::writeNewImageBase(uint64_t newImageBase) { uint32_t offset = dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER); @@ -778,20 +786,22 @@ void PeLib::ImageLoader::writeNewImageBase(std::uint64_t newImageBase) if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { PELIB_IMAGE_OPTIONAL_HEADER64 header64{}; + uint32_t sizeOfOptionalHeader = getRealSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER64)); - readImage(&header64, offset, fileHeader.SizeOfOptionalHeader); + readImage(&header64, offset, sizeOfOptionalHeader); header64.ImageBase = newImageBase; - writeImage(&header64, offset, fileHeader.SizeOfOptionalHeader); + writeImage(&header64, offset, sizeOfOptionalHeader); } // 32-bit images if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { PELIB_IMAGE_OPTIONAL_HEADER32 header32{}; + uint32_t sizeOfOptionalHeader = getRealSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER32)); - readImage(&header32, offset, fileHeader.SizeOfOptionalHeader); + readImage(&header32, offset, sizeOfOptionalHeader); header32.ImageBase = (uint32_t)newImageBase; - writeImage(&header32, offset, fileHeader.SizeOfOptionalHeader); + writeImage(&header32, offset, sizeOfOptionalHeader); } } @@ -815,6 +825,7 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) uint8_t * filePtr = fileBegin + dosHeader.e_lfanew; uint8_t * fileEnd = fileBegin + fileData.size(); size_t ntHeaderSize; + uint16_t optionalHeaderMagic = PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC; // Windows 7 or newer require that the file size is greater or equal to sizeof(IMAGE_NT_HEADERS) // Note that 64-bit kernel requires this to be sizeof(IMAGE_NT_HEADERS64) @@ -829,7 +840,7 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) // Capture the NT signature if((filePtr + sizeof(uint32_t)) >= fileEnd) setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); - ntSignature = *(reinterpret_cast(filePtr)); + ntSignature = *(uint32_t *)(filePtr); // Check the NT signature if(ntSignature != PELIB_IMAGE_NT_SIGNATURE) @@ -858,11 +869,14 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) if((dosHeader.e_lfanew + ntHeaderSize) < dosHeader.e_lfanew) setLoaderError(LDR_ERROR_NTHEADER_OFFSET_OVERFLOW); - // Capture optional header - if(fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_I386) - captureOptionalHeader32(filePtr, fileEnd); + // Capture optional header. Note that we need to parse it + // according to IMAGE_OPTIONAL_HEADER::Magic + if((filePtr + sizeof(uint16_t)) < fileEnd) + optionalHeaderMagic = *(uint16_t *)(filePtr); + if(optionalHeaderMagic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) + captureOptionalHeader64(fileBegin, filePtr, fileEnd); else - captureOptionalHeader64(filePtr, fileEnd); + captureOptionalHeader32(fileBegin, filePtr, fileEnd); // Performed by Windows 10 (nt!MiVerifyImageHeader): // Sample: 04d3577d1b6309a0032d4c4c1252c55416a09bb617aebafe512fffbdd4f08f18 @@ -930,6 +944,42 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) return ERROR_NONE; } +int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std::string & sectionName, const std::uint8_t * Name) +{ + uint32_t stringTableOffset; + uint32_t stringTableIndex = 0; + + // If the section name is in format of "/12345", then the section name is actually in the symbol table + // Sample: 2e9c671b8a0411f2b397544b368c44d7f095eb395779de0ad1ac946914dfa34c + if(fileHeader.PointerToSymbolTable != 0 && Name[0] == '/') + { + // Get the offset of the string table + stringTableOffset = fileHeader.PointerToSymbolTable + fileHeader.NumberOfSymbols * PELIB_IMAGE_SIZEOF_COFF_SYMBOL; + + // Convert the index from string to number + for (size_t i = 1; i < PELIB_IMAGE_SIZEOF_SHORT_NAME && isdigit(Name[i]); i++) + stringTableIndex = (stringTableIndex * 10) + (Name[i] - '0'); + + // Get the section name + readStringRaw(fileData, sectionName, stringTableOffset + stringTableIndex); + } + else + { + // We do not want the trailing zeros to be included in the section name. + size_t length; + + // Calculate the length of the section name. It is not zero terminated and has maximum size of 8. + for(length = 0; length < PELIB_IMAGE_SIZEOF_SHORT_NAME && Name[length] != 0; length++); + + // The section name is directly in the section header. + // It has fixed length and must not be necessarily terminated with zero. + sectionName.resize(length); + memcpy(const_cast(sectionName.data()), Name, length); + } + + return ERROR_NONE; +} + int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) { uint8_t * fileBegin = fileData.data(); @@ -972,12 +1022,12 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) // Read and verify all section headers for(uint16_t i = 0; i < fileHeader.NumberOfSections; i++) { - PELIB_IMAGE_SECTION_HEADER_BASE sectHdr{}; + PELIB_SECTION_HEADER sectHdr{}; // Capture one section header - if((filePtr + sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)) > fileEnd) + if((filePtr + sizeof(PELIB_IMAGE_SECTION_HEADER)) > fileEnd) break; - memcpy(§Hdr, filePtr, sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)); + memcpy(§Hdr, filePtr, sizeof(PELIB_IMAGE_SECTION_HEADER)); uint32_t PointerToRawData = (sectHdr.SizeOfRawData != 0) ? sectHdr.PointerToRawData : 0; uint32_t EndOfRawData = PointerToRawData + sectHdr.SizeOfRawData; @@ -1025,7 +1075,7 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) if(i == fileHeader.NumberOfSections - 1 && sectHdr.SizeOfRawData != 0) { if((sectHdr.PointerToRawData + sectHdr.SizeOfRawData) > fileData.size()) - setLoaderError(LDR_ERROR_INVALID_SECTION_RAWSIZE); + setLoaderError(LDR_ERROR_FILE_IS_CUT); } NextVirtualAddress += NumberOfSectionPTEs * PELIB_PAGE_SIZE; @@ -1033,13 +1083,16 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) // Check for raw data beyond end-of-file // Note that Windows loader doesn't check this on files that are mapped as single section. - // We will do that nontheless, because we want to know that a file is cut. + // We will do that nonetheless, because we want to know that a file is cut. if (PointerToRawData != 0 && (fileBegin + EndOfRawData) > fileEnd) bRawDataBeyondEOF = true; + // Resolve the section name + captureSectionName(fileData, sectHdr.sectionName, sectHdr.Name); + // Insert the header to the list sections.push_back(sectHdr); - filePtr += sizeof(PELIB_IMAGE_SECTION_HEADER_BASE); + filePtr += sizeof(PELIB_IMAGE_SECTION_HEADER); } // Verify the image size. Note that this check is no longer performed by Windows 10 @@ -1055,7 +1108,9 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) // Did we detect a trimmed file? if (bRawDataBeyondEOF) { - bool bFileLoadable = false; + // Track the state of loadability of the cut file. Some files can still be loadable. + // Example: bd149478739e660b032e4454057ce8d3e18dfbb6d1677c6ecdcc3aa59b36c8d9 + bool bCutButLoadable = false; // Special exception: Even if cut, the file is still loadable // if the last section is in the file range. This is because @@ -1064,25 +1119,25 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) { if (!sections.empty()) { - PELIB_IMAGE_SECTION_HEADER_BASE & lastSection = sections.back(); + PELIB_IMAGE_SECTION_HEADER & lastSection = sections.back(); uint32_t PointerToRawData = (lastSection.SizeOfRawData != 0) ? lastSection.PointerToRawData : 0; uint32_t EndOfRawData = PointerToRawData + lastSection.SizeOfRawData; if ((lastSection.SizeOfRawData == 0) || (fileBegin + EndOfRawData) <= fileEnd) { setLoaderError(LDR_ERROR_FILE_IS_CUT_LOADABLE); - bFileLoadable = true; + bCutButLoadable = true; } } } else { setLoaderError(LDR_ERROR_FILE_IS_CUT_LOADABLE); - bFileLoadable = true; + bCutButLoadable = true; } // If the file is not loadable, set the "file is cut" error - if (bFileLoadable == false) + if (bCutButLoadable == false) { setLoaderError(LDR_ERROR_FILE_IS_CUT); } @@ -1157,83 +1212,26 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) // Windows loader patches PointerToRawData to zero, including the mapped image. // Tested on Windows XP and Windows 10. uint32_t rva = dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; - for(size_t i = 0; i < sections.size(); i++, rva += sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)) + for(size_t i = 0; i < sections.size(); i++, rva += sizeof(PELIB_IMAGE_SECTION_HEADER)) { - PELIB_IMAGE_SECTION_HEADER_BASE sectHdr{}; + PELIB_IMAGE_SECTION_HEADER sectHdr{}; // Read the section from the header. This is necessary, as for some files, // section headers are not contained in the image. // Example: c8b31a912d91407a834071268366eb404d5e771b8281fdde301e15a8a82bf01b - readImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)); + readImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER)); // Patch PointerToRawData to zero, if SizeOfRawData is zero. if(sectHdr.PointerToRawData != 0 && sectHdr.SizeOfRawData == 0) { sectHdr.PointerToRawData = 0; - writeImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER_BASE)); + writeImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER)); } } return ERROR_NONE; } -int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * filePtr, uint8_t * fileEnd) -{ - PELIB_IMAGE_OPTIONAL_HEADER32 optionalHeader32{}; - uint32_t sizeOfOptionalHeader = fileHeader.SizeOfOptionalHeader; - uint32_t numberOfRvaAndSizes; - - // Capture optional header - if((filePtr + sizeOfOptionalHeader) > fileEnd) - return setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); - if(sizeOfOptionalHeader > sizeof(PELIB_IMAGE_OPTIONAL_HEADER32)) - sizeOfOptionalHeader = sizeof(PELIB_IMAGE_OPTIONAL_HEADER32); - memcpy(&optionalHeader32, filePtr, sizeOfOptionalHeader); - - // Verify whether it's 32-bit optional header - if(optionalHeader32.Magic != PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) - return setLoaderError(LDR_ERROR_NO_OPTHDR_MAGIC); - - // Convert 32-bit optional header to common optional header - optionalHeader.Magic = optionalHeader32.Magic; - optionalHeader.MajorLinkerVersion = optionalHeader32.MajorLinkerVersion; - optionalHeader.MinorLinkerVersion = optionalHeader32.MinorLinkerVersion; - optionalHeader.SizeOfCode = optionalHeader32.SizeOfCode; - optionalHeader.SizeOfInitializedData = optionalHeader32.SizeOfInitializedData; - optionalHeader.SizeOfUninitializedData = optionalHeader32.SizeOfUninitializedData; - optionalHeader.AddressOfEntryPoint = optionalHeader32.AddressOfEntryPoint; - optionalHeader.BaseOfCode = optionalHeader32.BaseOfCode; - optionalHeader.BaseOfData = optionalHeader32.BaseOfData; - optionalHeader.ImageBase = optionalHeader32.ImageBase; - optionalHeader.SectionAlignment = optionalHeader32.SectionAlignment; - optionalHeader.FileAlignment = optionalHeader32.FileAlignment; - optionalHeader.MajorOperatingSystemVersion = optionalHeader32.MajorOperatingSystemVersion; - optionalHeader.MinorOperatingSystemVersion = optionalHeader32.MinorOperatingSystemVersion; - optionalHeader.MajorImageVersion = optionalHeader32.MajorImageVersion; - optionalHeader.MinorImageVersion = optionalHeader32.MinorImageVersion; - optionalHeader.MajorSubsystemVersion = optionalHeader32.MajorSubsystemVersion; - optionalHeader.MinorSubsystemVersion = optionalHeader32.MinorSubsystemVersion; - optionalHeader.Win32VersionValue = optionalHeader32.Win32VersionValue; - optionalHeader.SizeOfImage = optionalHeader32.SizeOfImage; - optionalHeader.SizeOfHeaders = optionalHeader32.SizeOfHeaders; - optionalHeader.CheckSum = optionalHeader32.CheckSum; - optionalHeader.Subsystem = optionalHeader32.Subsystem; - optionalHeader.DllCharacteristics = optionalHeader32.DllCharacteristics; - optionalHeader.SizeOfStackReserve = optionalHeader32.SizeOfStackReserve; - optionalHeader.SizeOfStackCommit = optionalHeader32.SizeOfStackCommit; - optionalHeader.SizeOfHeapReserve = optionalHeader32.SizeOfHeapReserve; - optionalHeader.SizeOfHeapCommit = optionalHeader32.SizeOfHeapCommit; - optionalHeader.LoaderFlags = optionalHeader32.LoaderFlags; - optionalHeader.NumberOfRvaAndSizes = optionalHeader32.NumberOfRvaAndSizes; - - // Copy data directories - if((numberOfRvaAndSizes = optionalHeader32.NumberOfRvaAndSizes) > PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES) - numberOfRvaAndSizes = PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES; - memcpy(optionalHeader.DataDirectory, optionalHeader32.DataDirectory, sizeof(PELIB_IMAGE_DATA_DIRECTORY) * numberOfRvaAndSizes); - - return ERROR_NONE; -} - int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, size_t fileSize) { if(hdr.e_magic != PELIB_IMAGE_DOS_SIGNATURE) @@ -1246,7 +1244,7 @@ int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, size_t fil return ERROR_NONE; } -int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, std::size_t fileSize) +int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, size_t fileSize) { PELIB_IMAGE_DOS_HEADER tempDosHeader; int fileError; @@ -1270,21 +1268,20 @@ int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOf int PeLib::ImageLoader::loadImageAsIs(std::vector & fileData) { - imageAsIs = fileData; + rawFileData = fileData; return ERROR_NONE; } -int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * filePtr, uint8_t * fileEnd) +int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * fileBegin, uint8_t * filePtr, uint8_t * fileEnd) { PELIB_IMAGE_OPTIONAL_HEADER64 optionalHeader64{}; - uint32_t sizeOfOptionalHeader = fileHeader.SizeOfOptionalHeader; + uint32_t sizeOfOptionalHeader = getRealSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER64)); uint32_t numberOfRvaAndSizes; - // Capture optional header + // Capture optional header. Note that IMAGE_FILE_HEADER::SizeOfOptionalHeader + // is not used by the Windows loader to actually verify its size if((filePtr + sizeOfOptionalHeader) > fileEnd) return setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); - if(sizeOfOptionalHeader > sizeof(PELIB_IMAGE_OPTIONAL_HEADER64)) - sizeOfOptionalHeader = sizeof(PELIB_IMAGE_OPTIONAL_HEADER64); memcpy(&optionalHeader64, filePtr, sizeOfOptionalHeader); // Verify whether it's 64-bit optional header @@ -1327,33 +1324,76 @@ int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * filePtr, uint8_t * fil numberOfRvaAndSizes = PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES; memcpy(optionalHeader.DataDirectory, optionalHeader64.DataDirectory, sizeof(PELIB_IMAGE_DATA_DIRECTORY) * numberOfRvaAndSizes); + // Remember the offset of the checksum field + checkSumFileOffset = (filePtr - fileBegin) + offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, CheckSum); + securityDirFileOffset = (filePtr - fileBegin) + offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) + (sizeof(PELIB_IMAGE_DATA_DIRECTORY) * PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY); return ERROR_NONE; } -size_t PeLib::ImageLoader::getMismatchOffset(void * buffer1, void * buffer2, uint32_t rva, size_t length) +int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * fileBegin, uint8_t * filePtr, uint8_t * fileEnd) { - uint8_t * byteBuffer1 = reinterpret_cast(buffer1); - uint8_t * byteBuffer2 = reinterpret_cast(buffer2); + PELIB_IMAGE_OPTIONAL_HEADER32 optionalHeader32{}; + uint32_t sizeOfOptionalHeader = getRealSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER32)); + uint32_t numberOfRvaAndSizes; - for(size_t i = 0; i < length; i++) - { - if(byteBuffer1[i] != byteBuffer2[i]) - { - // Windows loader puts 0 in IMAGE_SECTION_HEADER::PointerToRawData - // if IMAGE_SECTION_HEADER::SizeOfRawData is also zero. - // However, on random samples, there seems to be the original value. - // This seems to happen randomly on some samples, often dissappears - // when the sample is copied to another location. - if(isRvaOfSectionHeaderPointerToRawData(rva + i)) - continue; + // Capture optional header. Note that IMAGE_FILE_HEADER::SizeOfOptionalHeader + // is not used by the Windows loader to actually verify its size + if((filePtr + sizeOfOptionalHeader) > fileEnd) + return setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); + memcpy(&optionalHeader32, filePtr, sizeOfOptionalHeader); - //for(int j = i & 0xFFFFFFF0; j < 0xD00; j++) - // printf("byteBuffer1[j]: %02x, byteBuffer2[j]: %02x\n", byteBuffer1[j], byteBuffer2[j]); - return i; - } - } + // Verify whether it's 32-bit optional header + if(optionalHeader32.Magic != PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) + return setLoaderError(LDR_ERROR_NO_OPTHDR_MAGIC); - return (size_t)(-1); + // Convert 32-bit optional header to common optional header + optionalHeader.Magic = optionalHeader32.Magic; + optionalHeader.MajorLinkerVersion = optionalHeader32.MajorLinkerVersion; + optionalHeader.MinorLinkerVersion = optionalHeader32.MinorLinkerVersion; + optionalHeader.SizeOfCode = optionalHeader32.SizeOfCode; + optionalHeader.SizeOfInitializedData = optionalHeader32.SizeOfInitializedData; + optionalHeader.SizeOfUninitializedData = optionalHeader32.SizeOfUninitializedData; + optionalHeader.AddressOfEntryPoint = optionalHeader32.AddressOfEntryPoint; + optionalHeader.BaseOfCode = optionalHeader32.BaseOfCode; + optionalHeader.BaseOfData = optionalHeader32.BaseOfData; + optionalHeader.ImageBase = optionalHeader32.ImageBase; + optionalHeader.SectionAlignment = optionalHeader32.SectionAlignment; + optionalHeader.FileAlignment = optionalHeader32.FileAlignment; + optionalHeader.MajorOperatingSystemVersion = optionalHeader32.MajorOperatingSystemVersion; + optionalHeader.MinorOperatingSystemVersion = optionalHeader32.MinorOperatingSystemVersion; + optionalHeader.MajorImageVersion = optionalHeader32.MajorImageVersion; + optionalHeader.MinorImageVersion = optionalHeader32.MinorImageVersion; + optionalHeader.MajorSubsystemVersion = optionalHeader32.MajorSubsystemVersion; + optionalHeader.MinorSubsystemVersion = optionalHeader32.MinorSubsystemVersion; + optionalHeader.Win32VersionValue = optionalHeader32.Win32VersionValue; + optionalHeader.SizeOfImage = optionalHeader32.SizeOfImage; + optionalHeader.SizeOfHeaders = optionalHeader32.SizeOfHeaders; + optionalHeader.CheckSum = optionalHeader32.CheckSum; + optionalHeader.Subsystem = optionalHeader32.Subsystem; + optionalHeader.DllCharacteristics = optionalHeader32.DllCharacteristics; + optionalHeader.SizeOfStackReserve = optionalHeader32.SizeOfStackReserve; + optionalHeader.SizeOfStackCommit = optionalHeader32.SizeOfStackCommit; + optionalHeader.SizeOfHeapReserve = optionalHeader32.SizeOfHeapReserve; + optionalHeader.SizeOfHeapCommit = optionalHeader32.SizeOfHeapCommit; + optionalHeader.LoaderFlags = optionalHeader32.LoaderFlags; + optionalHeader.NumberOfRvaAndSizes = optionalHeader32.NumberOfRvaAndSizes; + + // Copy data directories + if((numberOfRvaAndSizes = optionalHeader32.NumberOfRvaAndSizes) > PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES) + numberOfRvaAndSizes = PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES; + memcpy(optionalHeader.DataDirectory, optionalHeader32.DataDirectory, sizeof(PELIB_IMAGE_DATA_DIRECTORY) * numberOfRvaAndSizes); + + // Remember the offset of the checksum field + checkSumFileOffset = (filePtr - fileBegin) + offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, CheckSum); + securityDirFileOffset = (filePtr - fileBegin) + offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory) + (sizeof(PELIB_IMAGE_DATA_DIRECTORY) * PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY); + return ERROR_NONE; +} + +std::uint32_t PeLib::ImageLoader::getRealSizeOfOptionalHeader(std::uint32_t nominalSize) +{ + if(0 < fileHeader.SizeOfOptionalHeader && fileHeader.SizeOfOptionalHeader < nominalSize) + nominalSize = fileHeader.SizeOfOptionalHeader; + return nominalSize; } uint32_t PeLib::ImageLoader::captureImageSection( @@ -1498,7 +1538,7 @@ bool PeLib::ImageLoader::isGoodMappedPage(uint32_t rva) return (pages[pageIndex].isInvalidPage == false); } -bool PeLib::ImageLoader::isZeroPage(std::uint32_t rva) +bool PeLib::ImageLoader::isZeroPage(uint32_t rva) { uint32_t pageIndex = (rva / PELIB_PAGE_SIZE); @@ -1515,7 +1555,7 @@ bool PeLib::ImageLoader::isRvaOfSectionHeaderPointerToRawData(uint32_t rva) for(size_t i = 0; i < sections.size(); i++) { // Get the reference to the section header - PELIB_IMAGE_SECTION_HEADER_BASE & sectHdr = sections[i]; + PELIB_IMAGE_SECTION_HEADER & sectHdr = sections[i]; // Must be a section with SizeOfRawData = 0 if(sectHdr.SizeOfRawData == 0) @@ -1525,8 +1565,8 @@ bool PeLib::ImageLoader::isRvaOfSectionHeaderPointerToRawData(uint32_t rva) sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader + - i * sizeof(PELIB_IMAGE_SECTION_HEADER_BASE) + - 0x14; // FIELD_OFFSET(PELIB_IMAGE_SECTION_HEADER_BASE, PointerToRawData) + i * sizeof(PELIB_IMAGE_SECTION_HEADER) + + 0x14; // FIELD_OFFSET(PELIB_IMAGE_SECTION_HEADER, PointerToRawData) if(rvaOfLastSectionPointerToRawData <= rva && rva < rvaOfLastSectionPointerToRawData + sizeof(uint32_t)) return true; @@ -1537,7 +1577,7 @@ bool PeLib::ImageLoader::isRvaOfSectionHeaderPointerToRawData(uint32_t rva) } // MiIsLegacyImageArchitecture from Windows 10 -bool PeLib::ImageLoader::isLegacyImageArchitecture(std::uint16_t Machine) +bool PeLib::ImageLoader::isLegacyImageArchitecture(uint16_t Machine) { if(Machine == PELIB_IMAGE_FILE_MACHINE_I386) return true; @@ -1565,10 +1605,18 @@ bool PeLib::ImageLoader::checkForBadAppContainer() return false; } +// Returns true if the image is OK and can be mapped by NtCreateSection(SEC_IMAGE). +// This does NOT mean that the image is executable by CreateProcess - more checks are done, +// like resource integrity or relocation table correctness. +bool PeLib::ImageLoader::isImageLoadable() +{ + return (ldrError == LDR_ERROR_NONE || ldrError == LDR_ERROR_FILE_IS_CUT_LOADABLE); +} + bool PeLib::ImageLoader::isImageMappedOk() { // If there was loader error, we didn't map the image - if(ldrError != LDR_ERROR_NONE && ldrError != LDR_ERROR_FILE_IS_CUT_LOADABLE) + if(!isImageLoadable()) return false; if(pages.size() == 0) return false; @@ -1576,9 +1624,35 @@ bool PeLib::ImageLoader::isImageMappedOk() } //----------------------------------------------------------------------------- -// Testing function +// Testing functions + +size_t PeLib::ImageLoader::getMismatchOffset(void * buffer1, void * buffer2, uint32_t rva, size_t length) +{ + uint8_t * byteBuffer1 = reinterpret_cast(buffer1); + uint8_t * byteBuffer2 = reinterpret_cast(buffer2); + + for(size_t i = 0; i < length; i++) + { + if(byteBuffer1[i] != byteBuffer2[i]) + { + // Windows loader puts 0 in IMAGE_SECTION_HEADER::PointerToRawData + // if IMAGE_SECTION_HEADER::SizeOfRawData is also zero. + // However, on random samples, there seems to be the original value. + // This seems to happen randomly on some samples, often dissappears + // when the sample is copied to another location. + if(isRvaOfSectionHeaderPointerToRawData(rva + i)) + continue; + + //for(int j = i & 0xFFFFFFF0; j < 0xD00; j++) + // printf("byteBuffer1[j]: %02x, byteBuffer2[j]: %02x\n", byteBuffer1[j], byteBuffer2[j]); + return i; + } + } + + return (size_t)(-1); +} -void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & ImageCompare, void * imageDataPtr, std::uint32_t imageSize) +void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & ImageCompare, void * imageDataPtr, uint32_t imageSize) { uint8_t * winImageData = reinterpret_cast(imageDataPtr); uint8_t * winImageEnd = winImageData + imageSize; diff --git a/src/pelib/PeFile.cpp b/src/pelib/PeFile.cpp index 33b17582f..965544013 100644 --- a/src/pelib/PeFile.cpp +++ b/src/pelib/PeFile.cpp @@ -14,50 +14,47 @@ namespace PeLib { - PeFile::~PeFile() + PeFileT::PeFileT(const std::string& strFileName) : m_iStream(m_ifStream) { + setFileName(strFileName); } - PeFile32::PeFile32() : PeFileT<32>() - { - } + PeFileT::PeFileT(std::istream& stream) : m_iStream(stream) + {} - PeFile32::PeFile32(const std::string& strFlename) : PeFileT<32>(strFlename) - { - } + PeFileT::PeFileT() : m_iStream(m_ifStream) + {} - PeFile32::PeFile32(std::istream& stream) : PeFileT<32>(stream) - { - } + PeFile::~PeFile() + {} - PeFile64::PeFile64() : PeFileT<64>() + int PeFileT::loadPeHeaders(bool loadHeadersOnly) { + return m_imageLoader.Load(m_iStream, loadHeadersOnly); } - PeFile64::PeFile64(const std::string& strFlename) : PeFileT<64>(strFlename) + int PeFileT::loadPeHeaders(ByteBuffer & fileData, bool loadHeadersOnly) { + return m_imageLoader.Load(fileData, loadHeadersOnly); } - PeFile64::PeFile64(std::istream& stream) : PeFileT<64>(stream) + /// returns PEFILE64 or PEFILE32 + int PeFileT::getFileType() const { - } + std::uint16_t machine = m_imageLoader.getMachine(); + std::uint16_t magic = m_imageLoader.getMagic(); - /** - * @return A reference to the file's MZ header. - **/ + if((machine == PELIB_IMAGE_FILE_MACHINE_AMD64 || machine == PELIB_IMAGE_FILE_MACHINE_IA64) && magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + return PEFILE64; + } - const MzHeader& PeFile::mzHeader() const - { - return m_mzh; - } - - /** - * @return A reference to the file's MZ header. - **/ + if(machine == PELIB_IMAGE_FILE_MACHINE_I386 && magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + return PEFILE32; + } - MzHeader& PeFile::mzHeader() - { - return m_mzh; + return PEFILE_UNKNOWN; } /** @@ -107,4 +104,398 @@ namespace PeLib { return m_secdir; } + + /** + * @return A reference to the file's import directory. + **/ + const ImportDirectory & PeFileT::impDir() const + { + return m_impdir; + } + + /** + * @return A reference to the file's import directory. + **/ + ImportDirectory & PeFileT::impDir() + { + return m_impdir; + } + + const TlsDirectory & PeFileT::tlsDir() const + { + return m_tlsdir; + } + + TlsDirectory & PeFileT::tlsDir() + { + return m_tlsdir; + } + + /** + * @return A reference to the file's delay import directory. + **/ + const DelayImportDirectory & PeFileT::delayImports() const + { + return m_delayimpdir; + } + + /** + * @return A reference to the file's delay import directory. + **/ + DelayImportDirectory & PeFileT::delayImports() + { + return m_delayimpdir; + } + + /** + * @return A reference to the file's export directory. + **/ + const ExportDirectory & PeFileT::expDir() const + { + return m_expdir; + } + + /** + * @return A reference to the file's export directory. + **/ + ExportDirectory & PeFileT::expDir() + { + return m_expdir; + } + + /** + * @return A reference to the file's bound import directory. + **/ + const BoundImportDirectory & PeFileT::boundImpDir() const + { + return m_boundimpdir; + } + + /** + * @return A reference to the file's bound import directory. + **/ + BoundImportDirectory & PeFileT::boundImpDir() + { + return m_boundimpdir; + } + + /** + * @return A reference to the file's resource directory. + **/ + const ResourceDirectory & PeFileT::resDir() const + { + return m_resdir; + } + + /** + * @return A reference to the file's resource directory. + **/ + ResourceDirectory & PeFileT::resDir() + { + return m_resdir; + } + + /** + * @return A reference to the file's relocations directory. + **/ + const RelocationsDirectory & PeFileT::relocDir() const + { + return m_relocs; + } + + /** + * @return A reference to the file's relocations directory. + **/ + RelocationsDirectory & PeFileT::relocDir() + { + return m_relocs; + } + + /** + * @return A reference to the file's COM+ descriptor directory. + **/ + const ComHeaderDirectory & PeFileT::comDir() const + { + return m_comdesc; + } + + /** + * @return A reference to the file's COM+ descriptor directory. + **/ + ComHeaderDirectory & PeFileT::comDir() + { + return m_comdesc; + } + + const IatDirectory & PeFileT::iatDir() const + { + return m_iat; + } + + IatDirectory & PeFileT::iatDir() + { + return m_iat; + } + + const DebugDirectory & PeFileT::debugDir() const + { + return m_debugdir; + } + + DebugDirectory & PeFileT::debugDir() + { + return m_debugdir; + } + + /** + * @return Filename of the current file. + **/ + std::string PeFileT::getFileName() const + { + return m_filename; + } + + /** + * @param strFilename New filename. + **/ + void PeFileT::setFileName(const std::string & strFilename) + { + m_filename = strFilename; + if (m_ifStream.is_open()) + { + m_ifStream.close(); + } + m_ifStream.open(m_filename, std::ifstream::binary); + } + + int PeFileT::readRichHeader(std::size_t offset, std::size_t size, bool ignoreInvalidKey) + { + return richHeader().read(m_iStream, offset, size, ignoreInvalidKey); + } + + int PeFileT::readCoffSymbolTable(ByteBuffer & fileData) + { + if(m_imageLoader.getPointerToSymbolTable() && m_imageLoader.getNumberOfSymbols()) + { + return coffSymTab().read( + fileData, + m_imageLoader.getPointerToSymbolTable(), + m_imageLoader.getNumberOfSymbols() * PELIB_IMAGE_SIZEOF_COFF_SYMBOL); + } + return ERROR_COFF_SYMBOL_TABLE_DOES_NOT_EXIST; + } + + int PeFileT::readExportDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT)) + { + return expDir().read(m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readImportDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT)) + { + return impDir().read(m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readResourceDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE)) + { + return resDir().read(m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readSecurityDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY)) + { + return securityDir().read(m_iStream, + m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY), + m_imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY)); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readRelocationsDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC)) + { + return relocDir().read(m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readDebugDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG)) + { + return debugDir().read(m_iStream, m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readTlsDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_TLS)) + { + return tlsDir().read(m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readBoundImportDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)) + { + return boundImpDir().read(m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readIatDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IAT)) + { + return iatDir().read(m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readDelayImportDirectory() + { + // Note: Delay imports can have arbitrary size and Windows loader will still load them + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)) + { + return delayImports().read(m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + int PeFileT::readComHeaderDirectory() + { + if(m_imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) && + m_imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)) + { + return comDir().read(m_imageLoader); + } + return ERROR_DIRECTORY_DOES_NOT_EXIST; + } + + LoaderError PeFileT::checkEntryPointErrors() const + { + ImageLoader & imgLoader = const_cast(m_imageLoader); + std::uint32_t addressOfEntryPoint = m_imageLoader.getAddressOfEntryPoint(); + std::uint32_t sizeOfImage = m_imageLoader.getSizeOfImageAligned(); + + if(addressOfEntryPoint >= sizeOfImage) + { + return LDR_ERROR_ENTRY_POINT_OUT_OF_IMAGE; + } + + // Only check PE files compiled for i386 or x64 processors. + if (m_imageLoader.getMachine() == PELIB_IMAGE_FILE_MACHINE_I386 || m_imageLoader.getMachine() == PELIB_IMAGE_FILE_MACHINE_AMD64) + { + std::uint64_t entryPointCode[2] = {0, 0}; + + // Check if 16 bytes of code are available in the file + if ((addressOfEntryPoint + sizeof(entryPointCode)) < sizeOfImage) + { + // Read the entry point code + imgLoader.readImage(entryPointCode, addressOfEntryPoint, sizeof(entryPointCode)); + + // Zeroed instructions at entry point map either to "add [eax], al" (i386) or "add [rax], al" (AMD64). + // Neither of these instructions makes sense on the entry point. We check 16 bytes of the entry point, + // in order to make sure it's really a corruption. + if ((entryPointCode[0] | entryPointCode[1]) == 0) + { + return LDR_ERROR_ENTRY_POINT_ZEROED; + } + } + } + + return LDR_ERROR_NONE; + } + + LoaderError PeFileT::checkForInMemoryLayout(LoaderError ldrError) const + { + std::uint64_t ulFileSize = fileSize(m_iStream); + std::uint64_t sizeOfImage = m_imageLoader.getSizeOfImage(); + + // The file size must be greater or equal to SizeOfImage + if(ulFileSize >= sizeOfImage) + { + std::uint32_t sectionAlignment = m_imageLoader.getSectionAlignment(); + std::uint32_t fileAlignment = m_imageLoader.getFileAlignment(); + std::uint32_t sizeOfHeaders = m_imageLoader.getSizeOfHeaders(); + + // SectionAlignment must be greater than file alignment + if(sectionAlignment >= PELIB_PAGE_SIZE && sectionAlignment > fileAlignment) + { + // SizeOfHeaders must be smaller than SectionAlignment + if(sizeOfHeaders < sectionAlignment) + { + std::size_t headerDataSize = sectionAlignment - sizeOfHeaders; + + // Read the entire after-header-data + ByteBuffer headerData(headerDataSize); + m_iStream.seekg(sizeOfHeaders, std::ios::beg); + m_iStream.read(reinterpret_cast(headerData.data()), headerDataSize); + + // Check whether there are zeros only. If yes, we consider + // the file to be an in-memory image + if(std::all_of(headerData.begin(), headerData.end(), [](char item) { return item == 0; })) + ldrError = LDR_ERROR_INMEMORY_IMAGE; + } + } + } + + return ldrError; + } + + // Returns an error code indicating loader problem. We check every part of the PE file + // for possible loader problem. If anything wrong was found, we report it + LoaderError PeFileT::loaderError() const + { + // Check for problems in image loader + LoaderError ldrError = imageLoader().loaderError(); + + // Check the loader error + if (ldrError == LDR_ERROR_NONE) + ldrError = coffSymTab().loaderError(); + + // Check errors in import directory + if (ldrError == LDR_ERROR_NONE) + ldrError = impDir().loaderError(); + + // Check errors in resource directory + if (ldrError == LDR_ERROR_NONE) + ldrError = resDir().loaderError(); + + // Check errors in relocations directory + if (ldrError == LDR_ERROR_NONE) + ldrError = relocDir().loaderError(); + + // Check errors in security directory + if (ldrError == LDR_ERROR_NONE) + ldrError = securityDir().loaderError(); + + // Check errors in entry point + if (ldrError == LDR_ERROR_NONE) + ldrError = checkEntryPointErrors(); + + // If there was a loaded error, we'll check whether + // the file can't actually be an in-memory version + if(ldrError != LDR_ERROR_NONE) + ldrError = checkForInMemoryLayout(ldrError); + + // Nothing wrond found + return ldrError; + } } diff --git a/src/pelib/PeLibAux.cpp b/src/pelib/PeLibAux.cpp index 39220fed9..8fca2217b 100644 --- a/src/pelib/PeLibAux.cpp +++ b/src/pelib/PeLibAux.cpp @@ -121,21 +121,6 @@ namespace PeLib return all.end(); } - bool PELIB_IMAGE_SECTION_HEADER::biggerFileOffset(const PELIB_IMAGE_SECTION_HEADER& ish) const - { - return PointerToRawData < ish.PointerToRawData; - } - - bool PELIB_IMAGE_SECTION_HEADER::biggerVirtualAddress(const PELIB_IMAGE_SECTION_HEADER& ish) const - { - return VirtualAddress < ish.VirtualAddress; - } - - bool PELIB_IMAGE_SECTION_HEADER::isFullNameSet() const - { - return !StringTableName.empty(); - } - unsigned int alignOffset(unsigned int uiOffset, unsigned int uiAlignment) { if (!uiAlignment) return uiAlignment; @@ -408,105 +393,6 @@ namespace PeLib return isEqualNc(this->funcname, strFunctionName); } - unsigned int getFileType(PeFile32& pef) - { - // Attempt to read the DOS file header. - if (pef.readMzHeader() != ERROR_NONE) - { - return PEFILE_UNKNOWN; - } - - // Verify the DOS header - if (!pef.mzHeader().isValid()) - { - return PEFILE_UNKNOWN; - } - - // Read PE header. Note that at this point, we read the header as if - // it was 32-bit PE file. - if (pef.readPeHeader() != ERROR_NONE) - { - return PEFILE_UNKNOWN; - } - - std::uint16_t machine = pef.peHeader().getMachine(); - std::uint16_t magic = pef.peHeader().getMagic(); - - // jk2012-02-20: make the PEFILE32 be the default return value - if ((machine == PELIB_IMAGE_FILE_MACHINE_AMD64 - || machine == PELIB_IMAGE_FILE_MACHINE_IA64) - && magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - return PEFILE64; - } - else - { - return PEFILE32; - } - } - - /** - * @param strFilename Name of a file. - * @return Either PEFILE32, PEFILE64 or PEFILE_UNKNOWN - **/ - unsigned int getFileType(const std::string strFilename) - { - PeFile32 pef(strFilename); - return getFileType(pef); - } - - /** - * @param stream Input stream. - * @return Either PEFILE32, PEFILE64 or PEFILE_UNKNOWN - **/ - unsigned int getFileType(std::istream& stream) - { - PeFile32 pef(stream); - return getFileType(pef); - } - - /** - * Opens a PE file. The return type is either PeFile32 or PeFile64 object. If an error occurs the return - * value is 0. - * @param strFilename Name of a file. - * @return Either a PeFile32 object, a PeFil64 object or 0. - **/ - PeFile* openPeFile(const std::string& strFilename) - { - unsigned int type = getFileType(strFilename); - - if (type == PEFILE32) - { - return new PeFile32(strFilename); - } - else if (type == PEFILE64) - { - return new PeFile64(strFilename); - } - else - { - return nullptr; - } - } - - PeFile* openPeFile(std::istream& stream) - { - unsigned int type = getFileType(stream); - - if (type == PEFILE32) - { - return new PeFile32(stream); - } - else if (type == PEFILE64) - { - return new PeFile64(stream); - } - else - { - return nullptr; - } - } - std::size_t PELIB_IMAGE_BOUND_DIRECTORY::size() const { unsigned int size = 0; diff --git a/src/pelib/RelocationsDirectory.cpp b/src/pelib/RelocationsDirectory.cpp index c59eb7048..f7f03013d 100644 --- a/src/pelib/RelocationsDirectory.cpp +++ b/src/pelib/RelocationsDirectory.cpp @@ -28,7 +28,7 @@ namespace PeLib std::uint32_t sizeOfImage = imageLoader.getSizeOfImage(); // Check for relocations out of image - if(rva >= sizeOfImage || (rva + size) > sizeOfImage) + if(rva >= sizeOfImage || (rva + size) < rva || (rva + size) > sizeOfImage) { RelocationsDirectory::setLoaderError(LDR_ERROR_RELOCATIONS_OUT_OF_IMAGE); return ERROR_INVALID_FILE; diff --git a/src/pelib/ResourceDirectory.cpp b/src/pelib/ResourceDirectory.cpp index 3d503a22b..b884bfd78 100644 --- a/src/pelib/ResourceDirectory.cpp +++ b/src/pelib/ResourceDirectory.cpp @@ -637,12 +637,11 @@ namespace PeLib // Enough space to be a valid node? std::uint32_t uiRva = uiRsrcRva + uiOffset; if(uiRva > sizeOfImage) - { return ERROR_INVALID_FILE; - } // Read the resource node header - imageLoader.readImage(&header, uiRva, PELIB_IMAGE_RESOURCE_DIRECTORY::size()); + if(imageLoader.readImage(&header, uiRva, PELIB_IMAGE_RESOURCE_DIRECTORY::size()) != PELIB_IMAGE_RESOURCE_DIRECTORY::size()) + return ERROR_INVALID_FILE; // Add the total number of entries to the occupied range unsigned int uiNumberOfEntries = header.NumberOfNamedEntries + header.NumberOfIdEntries; diff --git a/src/unpackertool/plugins/mpress/mpress.cpp b/src/unpackertool/plugins/mpress/mpress.cpp index bfe7bd7b0..90fe4d01d 100644 --- a/src/unpackertool/plugins/mpress/mpress.cpp +++ b/src/unpackertool/plugins/mpress/mpress.cpp @@ -18,6 +18,7 @@ #include "unpackertool/plugins/mpress/mpress_exceptions.h" #include "retdec/fileformat/fileformat.h" +#include "retdec/pelib/PeFile.h" using namespace retdec::utils; using namespace retdec::unpacker; @@ -78,20 +79,17 @@ void MpressPlugin::prepare() if (!_file) throw UnsupportedFileException(); - if (!_file->getFileFormat()->isPe()) + _peFile = new PeLib::PeFileT(getStartupArguments()->inputFile); + if(_peFile->loadPeHeaders() != PeLib::ERROR_NONE) throw UnsupportedFileException(); // We currently don't support PE32+ as the decompiler doesn't support them anyways - if (!static_cast(_file->getFileFormat())->isPe32()) + if (_peFile->imageLoader().getImageBitability() != 32) throw UnsupportedFileException(); if (!_file->getEpSegment()) throw NoEntryPointException(); - _peFile = static_cast(PeLib::openPeFile(getStartupArguments()->inputFile)); - _peFile->readMzHeader(); - _peFile->readPeHeader(); - // Detect the version of the used MPRESS packer and the compression used if (detectUnpackerStubVersion() == MPRESS_UNPACKER_STUB_UNKNOWN) throw UnsupportedStubException(); @@ -268,6 +266,7 @@ void MpressPlugin::fixJumpsAndCalls(DynamicBuffer& buffer) void MpressPlugin::fixImportsAndEp(DynamicBuffer& buffer) { + /* // At the offset from EP is written EIP relative offset of fix import stub // Fix import stub is then located at the + offset + // This stub was packed together with code and data in .MPRESS1 section and also contains hints for import table rebuild @@ -278,7 +277,7 @@ void MpressPlugin::fixImportsAndEp(DynamicBuffer& buffer) std::uint32_t importHints = fixStubAddr + mpressFixStubData[_fixStub].importHintsOffset + buffer.read(fixStubAddr + mpressFixStubData[_fixStub].importHintsOffset); // Go through MPRESS import hints and fill the import directory - std::int32_t destOffset = _peFile->peHeader().getVirtualAddress(_packedContentSect->getSecSeg()->getIndex()) + importHints; + std::int32_t destOffset = _peFile->imageLoader().getVirtualAddress(_packedContentSect->getSecSeg()->getIndex()) + importHints; std::int32_t lowestDestOffset = std::numeric_limits::max(); std::int32_t highestDestOffset = 0; std::int32_t destOffsetDiff; @@ -333,27 +332,26 @@ void MpressPlugin::fixImportsAndEp(DynamicBuffer& buffer) // Fix the import directory and import address directory addresses // Since ILT is lost we need to make them from scratch in the whole new section // Ensure the .imports section will be large enough, resize if there are more data - std::uint32_t importSectSize = _peFile->impDir().size() & ~(_peFile->peHeader().getFileAlignment() - 1); - if (_peFile->impDir().size() & (_peFile->peHeader().getFileAlignment() - 1)) - importSectSize += _peFile->peHeader().getFileAlignment(); - _peFile->peHeader().addSection(".imports", importSectSize); - _peFile->peHeader().setCharacteristics(_peFile->peHeader().calcNumberOfSections() - 1, PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA); - _peFile->peHeader().setIddImportRva(_peFile->peHeader().getVirtualAddress(_peFile->peHeader().calcNumberOfSections() - 1)); - _peFile->peHeader().setIddImportSize(importSectSize); - _peFile->peHeader().makeValid(_peFile->mzHeader().size()); + std::uint32_t fileAlignment = _peFile->imageLoader().getFileAlignment(); + std::uint32_t importSectSize = _peFile->impDir().size() & ~(fileAlignment - 1); + std::uint32_t newSectionIndex; + + if (_peFile->impDir().size() & (fileAlignment - 1)) + importSectSize += fileAlignment; + //PeLib::PELIB_SECTION_HEADER & newSection = _peFile->imageLoader().addSection(".imports", importSectSize); + + //newSection.Characteristics = PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA; + _peFile->imageLoader().setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT, _peFile->imageLoader().getVirtualAddress(newSectionIndex), importSectSize); // IAT needs to be put at the desired offset std::uint32_t iatOffset = lowestDestOffset; - _peFile->peHeader().setIddIatRva(iatOffset); - _peFile->peHeader().setIddIatSize(highestDestOffset + 4 - lowestDestOffset); - _peFile->peHeader().makeValid(_peFile->mzHeader().size()); + _peFile->imageLoader().setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IAT, iatOffset, highestDestOffset + 4 - lowestDestOffset); // Offset to OEP is stored at the offset from the // This offset is addressed from the + offset - std::uint32_t oepOffset = _peFile->peHeader().getVirtualAddress(_packedContentSect->getSecSeg()->getIndex()) + fixStubAddr + + std::uint32_t oepOffset = _peFile->imageLoader().getVirtualAddress(_packedContentSect->getSecSeg()->getIndex()) + fixStubAddr + mpressFixStubData[_fixStub].importHintsOffset + buffer.read(fixStubAddr + mpressFixStubData[_fixStub].oepOffset); - _peFile->peHeader().setAddressOfEntryPoint(oepOffset); - _peFile->peHeader().makeValid(_peFile->mzHeader().size()); + //_peFile->imageLoader().setAddressOfEntryPoint(oepOffset); // Finally, get rid of the fix imports stub as it is going to mess up frontend analysis in the unpacked section // At the end we add 16 because of 4 bytes directly belonging to the importHintsOffset and additional 12 bytes used @@ -365,6 +363,7 @@ void MpressPlugin::fixImportsAndEp(DynamicBuffer& buffer) _iatSize = highestDestOffset + 4 - lowestDestOffset; _oepVa = oepOffset; _importHintsOffset = importHints; + */ } void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) @@ -372,7 +371,7 @@ void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) std::uint32_t fixStubOffset = getFixStub(); std::uint32_t dataFlags = PeLib::PELIB_IMAGE_SCN_MEM_WRITE | PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA; std::uint32_t codeFlags = dataFlags | PeLib::PELIB_IMAGE_SCN_CNT_CODE | PeLib::PELIB_IMAGE_SCN_MEM_EXECUTE; - + /* // Remove the .MPRESS2 section as the getEpSection()->getIndex() will be shifted by newly created // sections and we can do it safely here //_peFile->peHeader().removeSection(_file->getEpSection()->getIndex()); @@ -484,10 +483,12 @@ void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) } _peFile->peHeader().makeValid(_peFile->mzHeader().size()); + */ } void MpressPlugin::trailingBytesAnalysis(const DynamicBuffer& buffer) { + /* // Analysis of the trailing bytes of the section // 64 bytes at the every section alignment multiple are checked, if they are all 0, the new section is probably here so it is created // Only code section left after this function is the one containing the OEP, the code will execute even if some of the code is in data sections @@ -555,6 +556,7 @@ void MpressPlugin::trailingBytesAnalysis(const DynamicBuffer& buffer) section++; startOffset = offset; } + */ } void MpressPlugin::fixRelocations() @@ -583,9 +585,9 @@ void MpressPlugin::fixRelocations() // Set the base relocation directory in the new file // All relocations are here undamaged so we are good with this std::uint32_t relocRva = relocRvaBuffer.read(0); - _peFile->peHeader().setIddBaseRelocRva(relocRva); - _peFile->peHeader().setIddBaseRelocSize(relocSize); - _peFile->peHeader().makeValid(_peFile->mzHeader().size()); + //_peFile->peHeader().setIddBaseRelocRva(relocRva); + //_peFile->peHeader().setIddBaseRelocSize(relocSize); + //_peFile->peHeader().makeValid(_peFile->mzHeader().size()); } MpressUnpackerStub MpressPlugin::detectUnpackerStubVersion() @@ -635,6 +637,7 @@ MpressFixStub MpressPlugin::detectFixStubVersion(DynamicBuffer& unpackedContent) void MpressPlugin::saveFile(const std::string& fileName, DynamicBuffer& content) { + /* // Removes the file if it already exists std::remove(fileName.c_str()); @@ -679,6 +682,7 @@ void MpressPlugin::saveFile(const std::string& fileName, DynamicBuffer& content) outputFile.seekp(_peFile->peHeader().getPointerToRawData(_packedContentSect->getSecSeg()->getIndex()), std::ios_base::beg); outputFile.write(reinterpret_cast(content.getRawBuffer()), content.getRealDataSize()); outputFile.close(); + */ } void MpressPlugin::copySectionFromOriginalFile(std::uint32_t origSectIndex, const std::string& newFileName, std::uint32_t newSectIndex) @@ -686,7 +690,7 @@ void MpressPlugin::copySectionFromOriginalFile(std::uint32_t origSectIndex, cons const retdec::loader::Segment* seg = _file->getSegment(origSectIndex); std::vector bytes; seg->getBytes(bytes); - _peFile->peHeader().writeSectionData(newFileName, newSectIndex, bytes); + //_peFile->peHeader().writeSectionData(newFileName, newSectIndex, bytes); } } // namespace mpress diff --git a/src/unpackertool/plugins/mpress/mpress.h b/src/unpackertool/plugins/mpress/mpress.h index 95fbf5093..ea117eb51 100644 --- a/src/unpackertool/plugins/mpress/mpress.h +++ b/src/unpackertool/plugins/mpress/mpress.h @@ -89,7 +89,7 @@ class MpressPlugin : public Plugin void copySectionFromOriginalFile(std::uint32_t origSectIndex, const std::string& newFileName, std::uint32_t newSectIndex); std::unique_ptr _file; - PeLib::PeFile32* _peFile; + PeLib::PeFileT * _peFile; MpressUnpackerStub _unpackerStub; MpressFixStub _fixStub; const retdec::loader::Segment* _packedContentSect; diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp index 6fc147186..7a87994ac 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp @@ -182,7 +182,7 @@ template void PeUpxStub::unpack(const std::string& outputFile) // Detect auxiliary stubs detectUnfilter(unpackingStub); - +/* std::string inputFilePath = _file->getFileFormat()->getPathToFile(); PeLib::PeFile* peFile = PeLib::openPeFile(inputFilePath); _newPeFile = static_cast(peFile); @@ -250,6 +250,7 @@ template void PeUpxStub::unpack(const std::string& outputFile) // Save the output to the file saveFile(outputFile, unpackedData); + */ } /** @@ -425,6 +426,7 @@ template void PeUpxStub::unpackData(DynamicBuffer& unpackedData */ template void PeUpxStub::readPackedFileILT(DynamicBuffer& ilt) { +/* // We don't use PeLib for reading ILT because it is going to populate impDir(), but we want to it to build it all ourselves manually std::vector iltBytes; const retdec::loader::Segment* importsSection = _file->getSegmentFromAddress(_newPeFile->peHeader().getIddImportRva() + _newPeFile->peHeader().getImageBase()); @@ -437,6 +439,7 @@ template void PeUpxStub::readPackedFileILT(DynamicBuffer& ilt) _newPeFile->peHeader().getIddImportSize()); ilt = DynamicBuffer(iltBytes, _file->getFileFormat()->getEndianness()); + */ } /** @@ -448,6 +451,7 @@ template void PeUpxStub::readPackedFileILT(DynamicBuffer& ilt) */ template void PeUpxStub::fixSizeOfSections(const DynamicBuffer& unpackedData) { + /* // Always make sure that UPX0 points to same raw pointer as UPX1 before we process sections // This allows us to use much more simpler algorithm, than calculating with all possible positions of UPX0 _newPeFile->peHeader().setPointerToRawData(0, _newPeFile->peHeader().getPointerToRawData(1)); @@ -491,6 +495,7 @@ template void PeUpxStub::fixSizeOfSections(const DynamicBuffer& _newPeFile->peHeader().removeSection(_file->getEpSegment()->getSecSeg()->getIndex()); _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + */ } /** @@ -559,7 +564,7 @@ template UpxExtraData PeUpxStub::parseExtraData(DynamicBuffer& std::uint32_t sizeOfOptionalHeader = (bits == 64) ? sizeof(PeLib::PELIB_IMAGE_OPTIONAL_HEADER64) : sizeof(PeLib::PELIB_IMAGE_OPTIONAL_HEADER32); std::uint32_t dataDirectoriesStart = sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size() + sizeOfOptionalHeader; std::uint32_t sectionHeadersStart = dataDirectoriesStart + numberOfDirectories * PeLib::PELIB_IMAGE_DATA_DIRECTORY::size(); - std::uint32_t sectionHeadersEnd = sectionHeadersStart + PeLib::PELIB_IMAGE_SECTION_HEADER::size() * numberOfSections; + std::uint32_t sectionHeadersEnd = sectionHeadersStart + sizeof(PeLib::PELIB_IMAGE_SECTION_HEADER) * numberOfSections; // Check overflow if (originalHeaderOffset + sectionHeadersEnd < originalHeaderOffset) @@ -613,8 +618,8 @@ template void PeUpxStub::fixPeHeader(const DynamicBuffer& origi std::uint32_t sizeOfCode = originalHeader.read(sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size() + 0x04); std::uint32_t baseOfCode = originalHeader.read(sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size() + 0x14); - _newPeFile->peHeader().setSizeOfCode(sizeOfCode); - _newPeFile->peHeader().setBaseOfCode(baseOfCode); + //_newPeFile->peHeader().setSizeOfCode(sizeOfCode); + //_newPeFile->peHeader().setBaseOfCode(baseOfCode); } /** @@ -624,11 +629,13 @@ template void PeUpxStub::fixPeHeader(const DynamicBuffer& origi */ template void PeUpxStub::unfilterData(DynamicBuffer& unpackedData) { + /* std::uint32_t startOffset = _newPeFile->peHeader().getBaseOfCode() - _newPeFile->peHeader().getVirtualAddress(0); std::uint32_t size = _newPeFile->peHeader().getSizeOfCode(); if (!Unfilter::run(unpackedData, _filterId, _filterParam, _filterCount, startOffset, size)) throw UnsupportedFilterException(_filterId); + */ } /** @@ -640,6 +647,7 @@ template void PeUpxStub::unfilterData(DynamicBuffer& unpackedDa */ template void PeUpxStub::fixImports(const DynamicBuffer& unpackedData, const UpxExtraData& extraData, const DynamicBuffer& ilt) { + /* if (extraData.getImportsOffset() == 0) { _newPeFile->peHeader().setIddImportRva(0); @@ -716,6 +724,7 @@ template void PeUpxStub::fixImports(const DynamicBuffer& unpack _newPeFile->peHeader().setIddIatRva(lowestFirstThunk); _newPeFile->peHeader().setIddIatSize(4); // @todo Probably set proper size??? _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + */ } /** @@ -730,6 +739,7 @@ template void PeUpxStub::fixImports(const DynamicBuffer& unpack */ template void PeUpxStub::fixRelocations(DynamicBuffer& unpackedData, const UpxExtraData& extraData) { + /* if (extraData.getRelocationsOffset() == 0) return; @@ -769,6 +779,7 @@ template void PeUpxStub::fixRelocations(DynamicBuffer& unpacked // Rewrite the relocated address unpackedData.write(relocAddr, addr); } + */ } /** @@ -779,6 +790,7 @@ template void PeUpxStub::fixRelocations(DynamicBuffer& unpacked */ template void PeUpxStub::fixTls(const DynamicBuffer& originalHeader) { + /* // Make sure there is enough data directories _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_TLS) + 1)); _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); @@ -797,6 +809,7 @@ template void PeUpxStub::fixTls(const DynamicBuffer& originalHe throw InvalidDataDirectoryException("TLS"); upx_plugin->log("Original TLS directory found at RVA 0x", std::hex, tlsRva, " with size 0x", tlsSize, std::dec, "."); + */ } /** @@ -809,10 +822,10 @@ template void PeUpxStub::fixOep(const DynamicBuffer& originalHe // At the oepOffset is operand of JMP instruction, so the address is relative to the jump instruction // We need to take the address of the JMP instruction + its size and add this relative address // Everything needs to be calculated in virtual addresses, not RVAs since we don't want to get into negative numbers - _newPeFile->peHeader().setAddressOfEntryPoint(originalHeader.read(0x28)); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + //_newPeFile->peHeader().setAddressOfEntryPoint(originalHeader.read(0x28)); + //_newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); - upx_plugin->log("Original entry point address set to 0x", std::hex, _newPeFile->peHeader().getAddressOfEntryPoint(), std::dec, "."); + //upx_plugin->log("Original entry point address set to 0x", std::hex, _newPeFile->peHeader().getAddressOfEntryPoint(), std::dec, "."); } /** @@ -823,6 +836,8 @@ template void PeUpxStub::fixOep(const DynamicBuffer& originalHe */ template void PeUpxStub::fixExports(const DynamicBuffer& originalHeader) { + /* + // Assumption is that exports are compressed _exportsCompressed = true; @@ -907,6 +922,7 @@ template void PeUpxStub::fixExports(const DynamicBuffer& origin _newPeFile->expDir().addFunction(name, exportsData.read(exportsAddressesOffset + i * 4)); _newPeFile->expDir().setFunctionOrdinal(i, exportsData.read(exportsOrdinalsOffset + i * 2)); } + */ } /** @@ -917,6 +933,7 @@ template void PeUpxStub::fixExports(const DynamicBuffer& origin */ template void PeUpxStub::fixLoadConfiguration(const DynamicBuffer& originalHeader) { + /* // Make sure there is enough data directories _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) + 1)); _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); @@ -935,6 +952,7 @@ template void PeUpxStub::fixLoadConfiguration(const DynamicBuff throw InvalidDataDirectoryException("Load configuration"); upx_plugin->log("Original load configuration directory found at RVA 0x", std::hex, loadConfigRva, " with size 0x", loadConfigSize, std::dec, "."); + */ } /** @@ -948,6 +966,7 @@ template void PeUpxStub::fixLoadConfiguration(const DynamicBuff */ template void PeUpxStub::fixResources(const DynamicBuffer& unpackedData, const DynamicBuffer& originalHeader) { +/* // Make sure there is enough data directories _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE) + 1)); _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); @@ -1000,6 +1019,7 @@ template void PeUpxStub::fixResources(const DynamicBuffer& unpa _newPeFile->peHeader().setIddResourceRva(newRsrcRva); _newPeFile->peHeader().setIddResourceSize(newRsrcRva); _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + */ } /** @@ -1010,6 +1030,7 @@ template void PeUpxStub::fixResources(const DynamicBuffer& unpa */ template void PeUpxStub::fixSectionHeaders(const DynamicBuffer& originalHeader) { + /* std::uint16_t numberOfSections = originalHeader.read(6); std::uint32_t numberOfDirectories = originalHeader.read(PeUpxStubTraits::NumberOfRvaAndSizesOffset); std::uint32_t sectionHeadersOffset = PeUpxStubTraits::ExportsDirectoryRvaOffset + numberOfDirectories * 8; @@ -1082,6 +1103,7 @@ template void PeUpxStub::fixSectionHeaders(const DynamicBuffer& _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); } } + */ } /** @@ -1090,6 +1112,7 @@ template void PeUpxStub::fixSectionHeaders(const DynamicBuffer& */ template void PeUpxStub::fixCoffSymbolTable() { +/* _coffSymbolTable.clear(); // MinGW files use COFF symbols even though it shouldn't be used for EXEs @@ -1119,6 +1142,7 @@ template void PeUpxStub::fixCoffSymbolTable() else upx_plugin->log("Packed file seems to be truncated. Not copying DWARF debug info."); } + */ } /** @@ -1126,6 +1150,7 @@ template void PeUpxStub::fixCoffSymbolTable() */ template void PeUpxStub::fixCertificates() { + /* // Make sure there is enough data directories _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY) + 1)); _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); @@ -1155,6 +1180,7 @@ template void PeUpxStub::fixCertificates() } _newPeFile->peHeader().setIddSecurityRva(securityOffset); + */ } /** @@ -1188,6 +1214,7 @@ template void PeUpxStub::cutHintsData(DynamicBuffer& unpackedDa */ template void PeUpxStub::saveFile(const std::string& outputFile, DynamicBuffer& unpackedData) { + /* // Remove the file if it already exists std::remove(outputFile.c_str()); @@ -1247,6 +1274,7 @@ template void PeUpxStub::saveFile(const std::string& outputFile outputFileHandle.seekp(0, std::ios::end); retdec::utils::writeFile(outputFileHandle, overlay, outputFileHandle.tellp()); } + */ } /** @@ -1360,14 +1388,14 @@ template void PeUpxStub::loadResources(PeLib::ResourceNode* roo std::vector data; if (leaf->getOffsetToData() < uncompressedRsrcRva) { - std::uint32_t dataOffset = leaf->getOffsetToData() - _newPeFile->peHeader().vaToRva(_file->getSegment(0)->getAddress()); - if (dataOffset >= unpackedData.getRealDataSize()) - throw InvalidDataDirectoryException("Resources"); + //std::uint32_t dataOffset = leaf->getOffsetToData() - _newPeFile->peHeader().vaToRva(_file->getSegment(0)->getAddress()); + //if (dataOffset >= unpackedData.getRealDataSize()) + // throw InvalidDataDirectoryException("Resources"); - if (dataOffset + leaf->getSize() >= unpackedData.getRealDataSize()) - throw InvalidDataDirectoryException("Resources"); + //if (dataOffset + leaf->getSize() >= unpackedData.getRealDataSize()) + // throw InvalidDataDirectoryException("Resources"); - data = DynamicBuffer(unpackedData, dataOffset, leaf->getSize()).getBuffer(); + //data = DynamicBuffer(unpackedData, dataOffset, leaf->getSize()).getBuffer(); } else { diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h index 64f8f2acd..5e81706fb 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h @@ -69,7 +69,7 @@ template struct PeUpxStubTraits {}; template <> struct PeUpxStubTraits<32> { using AddressType = std::uint32_t; ///< Type with default word size. - using PeLibFileType = PeLib::PeFile32; + using PeLibFileType = PeLib::PeFileT; static const std::uint16_t HeaderMagic = PeLib::PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC; ///< PE magic header. static const std::uint32_t NumberOfRvaAndSizesOffset = 0x74; ///< Offset in PE header to directories count. @@ -89,7 +89,7 @@ template <> struct PeUpxStubTraits<32> template <> struct PeUpxStubTraits<64> { using AddressType = std::uint32_t; ///< Type with default word size. - using PeLibFileType = PeLib::PeFile64; ///< Type of PE file. + using PeLibFileType = PeLib::PeFileT; ///< Type of PE file. static const std::uint16_t HeaderMagic = PeLib::PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC; ///< PE magic header. static const std::uint32_t NumberOfRvaAndSizesOffset = 0x84; ///< Offset in PE header to directories count. diff --git a/src/unpackertool/plugins/upx/upx_stub.cpp b/src/unpackertool/plugins/upx/upx_stub.cpp index 921a1db83..3b7413391 100644 --- a/src/unpackertool/plugins/upx/upx_stub.cpp +++ b/src/unpackertool/plugins/upx/upx_stub.cpp @@ -286,10 +286,10 @@ std::shared_ptr UpxStub::_createStubImpl(retdec::loader::Image* file, c } case retdec::fileformat::Format::PE: { - if (static_cast(file->getFileFormat())->isPe32()) - stub = new PeUpxStub<32>(file, stubData, capturedData, std::move(decompressor), metadata); - else - stub = new PeUpxStub<64>(file, stubData, capturedData, std::move(decompressor), metadata); + //if (static_cast(file->getFileFormat())->isPe32()) + // stub = new PeUpxStub<32>(file, stubData, capturedData, std::move(decompressor), metadata); + //else + // stub = new PeUpxStub<64>(file, stubData, capturedData, std::move(decompressor), metadata); break; } case retdec::fileformat::Format::MACHO: From e7701d3dec9bb694b3d17a9db04f03f8b8dd4ead Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Fri, 26 Jun 2020 23:40:13 +0200 Subject: [PATCH 09/34] ImageLoader: Last regression test remaining to solve --- include/retdec/pelib/ImageLoader.h | 30 +- include/retdec/pelib/ImportDirectory.h | 47 +- include/retdec/pelib/PeLibAux.h | 4 +- .../types/import_table/import_table.cpp | 15 +- src/fileinfo/file_detector/pe_detector.cpp | 2 +- src/pelib/IatDirectory.cpp | 2 +- src/pelib/ImageLoader.cpp | 551 +++++++++++++----- src/pelib/PeFile.cpp | 2 +- src/pelib/RelocationsDirectory.cpp | 2 +- 9 files changed, 446 insertions(+), 209 deletions(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index c4791b231..76d2b1f47 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -29,8 +29,7 @@ enum : std::uint32_t LoaderModeWindows7 = 0x61, // Behavior equal to Windows 7 LoaderModeWindows10 = 0xA0, // Behavior equal to Windows 10 WindowsVerMask = 0x0FFF, // Mask for extracting the operating system - StrictMode = 0x1000, // Strict mode. Refuse to load images that are cut - SecImageNoExecute = 0x2000, // As if the image was loaded with SEC_IMAGE_NO_EXECUTE + LoaderMode64BitWindows = 0x1000, // Emulate 64-bit system }; //----------------------------------------------------------------------------- @@ -135,14 +134,12 @@ class ImageLoader std::uint32_t readString(std::string & str, std::uint32_t rva, std::uint32_t maxLength = 65535); std::uint32_t readStringRc(std::string & str, std::uint32_t rva); - std::uint32_t readStringRaw(std::vector & fileData, std::string & str, std::size_t offset); + std::uint32_t readStringRaw(std::vector & fileData, std::string & str, std::size_t offset, std::size_t maxLength = 65535); std::uint32_t stringLength(std::uint32_t rva, std::uint32_t maxLength = 65535) const; std::uint32_t readPointer(std::uint32_t rva, std::uint64_t & pointerValue); std::uint32_t getPointerSize() const; - bool getSectionName(std::size_t sectionIndex, std::string & sectionName); - std::uint32_t dumpImage(const char * fileName); std::uint32_t getImageBitability() const; @@ -208,6 +205,11 @@ class ImageLoader return fileHeader.NumberOfSections; } + std::uint32_t getCharacteristics() const + { + return fileHeader.Characteristics; + } + std::uint32_t getNumberOfSections() const { return sections.size(); @@ -253,11 +255,6 @@ class ImageLoader return optionalHeader.FileAlignment; } - std::uint32_t getCharacteristics() const - { - return optionalHeader.DllCharacteristics; - } - std::uint32_t getChecksumFileOffset() const { return checkSumFileOffset; @@ -296,6 +293,7 @@ class ImageLoader std::uint32_t readWriteImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead, READWRITE ReadWrite); std::uint32_t readWriteImageFile(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead, bool bReadOperation); + bool processImageRelocation_IA64_IMM64(std::uint32_t fixupAddress, std::uint64_t difference); bool processImageRelocations(std::uint64_t oldImageBase, std::uint64_t getImageBase, std::uint32_t VirtualAddress, std::uint32_t Size); void writeNewImageBase(std::uint64_t newImageBase); @@ -312,9 +310,6 @@ class ImageLoader int loadImageAsIs(std::vector & fileData); - // Use sizeof(PELIB_OPTIONAL_HEADER32) or sizeof(PELIB_OPTIONAL_HEADER64) as parameter - std::uint32_t getRealSizeOfOptionalHeader(std::uint32_t nominalSize); - std::uint32_t captureImageSection(std::vector & fileData, std::uint32_t virtualAddress, std::uint32_t virtualSize, @@ -329,13 +324,16 @@ class ImageLoader bool isRvaOfSectionHeaderPointerToRawData(uint32_t rva); bool isLegacyImageArchitecture(std::uint16_t Machine); + bool checkForValid64BitMachine(); + bool checkForValid32BitMachine(); bool checkForBadAppContainer(); // isImageLoadable returns true if the image is OK and can be mapped by NtCreateSection(SEC_IMAGE). // This does NOT mean that the image is executable by CreateProcess - more checks are done, // like resource integrity or relocation table correctness. - bool isImageLoadable(); - bool isImageMappedOk(); + bool isImageLoadable() const; + bool isImageMappedOk() const; + bool isValidImageBlock(std::uint32_t Rva, std::uint32_t Size) const; static std::uint32_t AlignToSize(std::uint32_t ByteSize, std::uint32_t AlignSize) { @@ -364,6 +362,8 @@ class ImageLoader bool ntHeadersSizeCheck; // If true, the loader requires minimum size of NT headers bool sizeofImageMustMatch; // If true, the SizeOfImage must match virtual end of the last section bool appContainerCheck; // If true, app container flag is tested in the optional header + bool is64BitWindows; // If true, we simulate 64-bit Windows + bool loadArmImages; // If true, image loader will load ARM binaries }; } // namespace PeLib diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index be198abca..b27a441ff 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -151,19 +151,19 @@ namespace PeLib int write(const std::string& strFilename, unsigned int uiOffset, unsigned int uiRva); // EXPORT /// Returns the FirstThunk value of a function. - std::uint32_t getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber - void setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber + std::uint64_t getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber + void setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint64_t value); // EXPORT _byNumber /// Returns the OriginalFirstThunk value of a function. - std::uint32_t getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber - void setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value); // EXPORT + std::uint64_t getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber + void setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint64_t value); // EXPORT -// std::uint32_t getFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); -// std::uint32_t getOriginalFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); +// std::uint64_t getFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); +// std::uint64_t getOriginalFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); /// Returns the FirstThunk value of a file. - std::uint32_t getFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName + std::uint64_t getFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the OriginalFirstThunk value of a file. - std::uint32_t getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName + std::uint64_t getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the ForwarderChain value of a file. std::uint32_t getForwarderChain(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName std::uint32_t getRvaOfName(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName @@ -171,11 +171,11 @@ namespace PeLib std::uint32_t getTimeDateStamp(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the FirstThunk value of a file. - std::uint32_t getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT - void setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber_function + std::uint64_t getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT + void setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint64_t value); // EXPORT _byNumber_function /// Returns the OriginalFirstThunk value of a file. - std::uint32_t getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT - void setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber_function + std::uint64_t getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT + void setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint64_t value); // EXPORT _byNumber_function /// Returns the ForwarderChain value of a file. std::uint32_t getForwarderChain(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT _byNumber void setForwarderChain(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber_function @@ -533,6 +533,7 @@ namespace PeLib std::uint32_t rvaBegin = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT); std::uint32_t rva = rvaBegin; + m_ordinalMask = imageLoader.getOrdinalMask(); m_thunkSize = imageLoader.getPointerSize(); m_ldrError = LDR_ERROR_NONE; @@ -586,7 +587,7 @@ namespace PeLib } // Retrieve the library name from the image as ASCIIZ string - imageLoader.readString(iidCurr.name, iidCurr.impdesc.Name); + imageLoader.readString(iidCurr.name, iidCurr.impdesc.Name, IMPORT_LIBRARY_MAX_LENGTH); // Ignore too large import directories // Sample: CCE461B6EB23728BA3B8A97B9BE84C0FB9175DB31B9949E64144198AB3F702CE, # of impdesc 0x6253 (invalid) @@ -1028,7 +1029,7 @@ namespace PeLib * @return FirstThunk value of an imported file. **/ inline - std::uint32_t ImportDirectory::getFirstThunk(const std::string& strFilename, currdir cdDir) const + std::uint64_t ImportDirectory::getFirstThunk(const std::string& strFilename, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1046,7 +1047,7 @@ namespace PeLib * @return OriginalFirstThunk value of an imported file. **/ inline - std::uint32_t ImportDirectory::getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const + std::uint64_t ImportDirectory::getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1113,7 +1114,7 @@ namespace PeLib * @return FirstThunk value of an imported file. **/ inline - std::uint32_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const + std::uint64_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1126,7 +1127,7 @@ namespace PeLib } inline - void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value) + void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint64_t value) { if (cdDir == OLDDIR) { @@ -1144,7 +1145,7 @@ namespace PeLib * @return OriginalFirstThunk value of an imported file. **/ inline - std::uint32_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const + std::uint64_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1157,7 +1158,7 @@ namespace PeLib } inline - void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value) + void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint64_t value) { if (cdDir == OLDDIR) { @@ -1265,14 +1266,14 @@ namespace PeLib * @return FirstThunk value of an imported function. **/ inline - std::uint32_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const + std::uint64_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const { if (cdDir == OLDDIR) return m_vOldiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal; else return m_vNewiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal; } inline - void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value) + void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint64_t value) { if (cdDir == OLDDIR) m_vOldiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal = value; else m_vNewiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal = value; @@ -1285,7 +1286,7 @@ namespace PeLib * @return OriginalFirstThunk value of an imported function. **/ inline - std::uint32_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const + std::uint64_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1305,7 +1306,7 @@ namespace PeLib } inline - void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value) + void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint64_t value) { if (cdDir == OLDDIR) m_vOldiid[dwFilenr].originalfirstthunk[dwFuncnr].itd.Ordinal = value; else m_vNewiid[dwFilenr].originalfirstthunk[dwFuncnr].itd.Ordinal = value; diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index e29bdb0b9..2e5b64f04 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -146,6 +146,8 @@ namespace PeLib const std::uint32_t PELIB_SIZE_64KB = 0x10000; + const std::uint32_t PELIB_SIZE_10MB = 0xA00000; + const std::uint32_t PELIB_IMAGE_NT_SIGNATURE = 0x00004550; const std::uint32_t PELIB_MM_SIZE_OF_LARGEST_IMAGE = 0x77000000; @@ -350,7 +352,7 @@ namespace PeLib PELIB_IMAGE_REL_BASED_HIGHLOW = 3, PELIB_IMAGE_REL_BASED_HIGHADJ = 4, PELIB_IMAGE_REL_BASED_MIPS_JMPADDR = 5, - PELIB_IMAGE_REL_BASED_MIPS_JMPADDR16 = 9, + PELIB_IMAGE_REL_BASED_IA64_IMM64 = 9, PELIB_IMAGE_REL_BASED_DIR64 = 10 }; diff --git a/src/fileformat/types/import_table/import_table.cpp b/src/fileformat/types/import_table/import_table.cpp index d602e8211..a03740cb2 100644 --- a/src/fileformat/types/import_table/import_table.cpp +++ b/src/fileformat/types/import_table/import_table.cpp @@ -802,10 +802,17 @@ void ImportTable::computeHashes() impHashBytes.push_back(static_cast(',')); } - for(const auto c : std::string(libName + "." + funcName)) - { - impHashBytes.push_back(static_cast(c)); - } + // Append the bytes of the import name to the hash bytes vector + // Note that this is faster than the previous char-to-char concatenating + std::string libAndFunc = libName + "." + funcName; + std::size_t oldSize = impHashBytes.size(); + impHashBytes.resize(oldSize + libAndFunc.size()); + memcpy(impHashBytes.data() + oldSize, libAndFunc.data(), libAndFunc.size()); + + //for(const auto c : std::string()) + //{ + // impHashBytes.push_back(static_cast(c)); + //} } if (impHashBytes.size() == 0) diff --git a/src/fileinfo/file_detector/pe_detector.cpp b/src/fileinfo/file_detector/pe_detector.cpp index 21a3f959d..53a05dfdf 100644 --- a/src/fileinfo/file_detector/pe_detector.cpp +++ b/src/fileinfo/file_detector/pe_detector.cpp @@ -82,7 +82,7 @@ void PeDetector::getFileFlags() "aggressively trim working set", "application can handle addresses larger than 2 GB", "reversed endianness", - "computer supports 32-bit std::uint16_ts", + "computer supports 32-bit words", "debugging information was removed", "copy image from removable media", "copy image from network", diff --git a/src/pelib/IatDirectory.cpp b/src/pelib/IatDirectory.cpp index 712efac6e..1a788e7e8 100644 --- a/src/pelib/IatDirectory.cpp +++ b/src/pelib/IatDirectory.cpp @@ -24,7 +24,7 @@ namespace PeLib const std::uint32_t * itemArray = reinterpret_cast(buffer); // Resize the IAT vector to contain all items - std::size_t itemCount = buffersize / sizeof(std::uint8_t); + std::size_t itemCount = buffersize / sizeof(std::uint32_t); m_vIat.clear(); // Read the items, one-by-one, until we find a zero value diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 1d00590b1..ce93c5267 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -48,6 +48,15 @@ uint8_t PeLib::ImageLoader::ImageProtectionArray[16] = PELIB_PAGE_EXECUTE_READWRITE }; +//----------------------------------------------------------------------------- +// Returns the fixed size of optional header (without Data Directories) + +template +std::uint32_t getCopySizeOfOptionalHeader() +{ + return offsetof(OPT_HDR, DataDirectory); +} + //----------------------------------------------------------------------------- // Constructor and destructor @@ -66,6 +75,8 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) ntHeadersSizeCheck = false; appContainerCheck = false; maxSectionCount = 255; + is64BitWindows = (loaderFlags & LoaderMode64BitWindows) ? true : false; + loadArmImages = true; // Resolve os-specific restrictions switch(loaderMode = (loaderFlags & WindowsVerMask)) @@ -73,19 +84,21 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) case LoaderModeWindowsXP: maxSectionCount = PE_MAX_SECTION_COUNT_XP; sizeofImageMustMatch = true; - //copyWholeHeaderPage = true; + loadArmImages = false; break; case LoaderModeWindows7: maxSectionCount = PE_MAX_SECTION_COUNT_7; ntHeadersSizeCheck = true; sizeofImageMustMatch = true; + loadArmImages = false; break; case LoaderModeWindows10: maxSectionCount = PE_MAX_SECTION_COUNT_7; ntHeadersSizeCheck = true; appContainerCheck = true; + loadArmImages = true; break; } } @@ -105,7 +118,11 @@ bool PeLib::ImageLoader::relocateImage(uint64_t newImageBase) // Only relocate the image if the image base is different if(newImageBase != optionalHeader.ImageBase) { - // If relocations are stripped, there is no relocation + // If the image was not properly mapped, don't even try. + if(pages.size() == 0) + return false; + + // If relocations are stripped, do nothing if(fileHeader.Characteristics & PELIB_IMAGE_FILE_RELOCS_STRIPPED) return false; @@ -131,9 +148,9 @@ bool PeLib::ImageLoader::relocateImage(uint64_t newImageBase) if(VirtualAddress == 0 || Size == 0) return false; - // Resolve case when the reloc block is too big - if((VirtualAddress + Size) > getSizeOfImage()) - Size = getSizeOfImage() - VirtualAddress; + // Do not relocate images with weird or invalid relocation table + if(!isValidImageBlock(VirtualAddress, Size)) + return false; // Perform relocations result = processImageRelocations(optionalHeader.ImageBase, newImageBase, VirtualAddress, Size); @@ -171,49 +188,71 @@ uint32_t PeLib::ImageLoader::stringLength(uint32_t rva, uint32_t maxLength) cons { uint32_t rvaBegin = rva; uint32_t rvaEnd = rva + maxLength; + uint32_t length = 0; - // Check the last possible address where we read - if(rvaEnd > getSizeOfImageAligned()) - rvaEnd = getSizeOfImageAligned(); - - // Is the offset within the image? - if(rva < rvaEnd) + // Is the image mapped OK? + if(pages.size()) { - size_t pageIndex = rva / PELIB_PAGE_SIZE; + // Check the last possible address where we read + if(rvaEnd > getSizeOfImageAligned()) + rvaEnd = getSizeOfImageAligned(); - // The page index must be in range - if(pageIndex < pages.size()) + // Is the offset within the image? + if(rva < rvaEnd) { - while(rva < rvaEnd) - { - const PELIB_FILE_PAGE & page = pages[pageIndex]; - uint32_t rvaEndPage = (pageIndex + 1) * PELIB_PAGE_SIZE; - - // If zero page, means we found an RVA with zero - if(page.buffer.empty()) - return rva; + size_t pageIndex = rva / PELIB_PAGE_SIZE; - // Perhaps the last page loaded? - if(rvaEndPage > rvaEnd) - rvaEndPage = rvaEnd; - - // Try to find the zero byte on the page - for(; rva < rvaEndPage; rva++) + // The page index must be in range + if(pageIndex < pages.size()) + { + while(rva < rvaEnd) { - if(page.buffer[rva & (PELIB_PAGE_SIZE - 1)] == 0) - { - return (rva - rvaBegin); - } + const PELIB_FILE_PAGE & page = pages[pageIndex]; + const uint8_t * dataBegin; + const uint8_t * dataPtr; + uint32_t rvaEndPage = (pageIndex + 1) * PELIB_PAGE_SIZE; + + // If zero page, means we found an RVA with zero + if(page.buffer.empty()) + return rva; + dataBegin = dataPtr = page.buffer.data() + (rva & (PELIB_PAGE_SIZE - 1)); + + // Perhaps the last page loaded? + if(rvaEndPage > rvaEnd) + rvaEndPage = rvaEnd; + + // Try to find the zero byte on the page + dataPtr = (const uint8_t *)memchr(dataPtr, 0, (rvaEndPage - rva)); + if(dataPtr != nullptr) + return rva + (dataPtr - dataBegin) - rvaBegin; + rva = rvaEndPage; + + // Move pointers + pageIndex++; } - - // Move pointers - pageIndex++; } } + + // Return the length of the string + length = (rva - rvaBegin); + } + else + { + // Recalc the file offset to RVA + if((rva = getFileOffsetFromRva(rva)) < rawFileData.size()) + { + const uint8_t * stringPtr = rawFileData.data() + rva; + const uint8_t * stringEnd; + + length = rawFileData.size() - rva; + + stringEnd = (const uint8_t *)memchr(stringPtr, 0, length); + if(stringEnd != nullptr) + length = stringEnd - stringPtr; + } } - // Return the offset of the zero byte on the page - return rva - rvaBegin; + return length; } uint32_t PeLib::ImageLoader::readString(std::string & str, uint32_t rva, uint32_t maxLength) @@ -289,18 +328,30 @@ uint32_t PeLib::ImageLoader::readStringRc(std::string & str, uint32_t rva) return charsRead; } -uint32_t PeLib::ImageLoader::readStringRaw(std::vector & fileData, std::string & str, size_t offset) +uint32_t PeLib::ImageLoader::readStringRaw(std::vector & fileData, std::string & str, size_t offset, size_t maxLength) { - uint32_t length = 0; + size_t length = 0; if(offset < fileData.size()) { - // Prepare buffer for string - length = strlen(reinterpret_cast(fileData.data() + offset)); - str.resize(length); + uint8_t * stringBegin = fileData.data() + offset; + uint8_t * stringEnd; + + // Make sure we won't read past the end of the buffer + if((offset + maxLength) > fileData.size()) + maxLength = fileData.size() - offset; + + // Get the length of the string. Do not go beyond the maximum length + // Note that there is no guaratee that the string is zero terminated, so can't use strlen + // retdec-regression-tests\tools\fileinfo\bugs\issue-451-strange-section-names\4383fe67fec6ea6e44d2c7d075b9693610817edc68e8b2a76b2246b53b9186a1-unpacked + stringEnd = (uint8_t *)memchr(stringBegin, 0, maxLength); + if(stringEnd == nullptr) + stringEnd = stringBegin + maxLength; + length = stringEnd - stringBegin; // Copy the string - memcpy(const_cast(str.data()), fileData.data() + offset, length); + str.resize(length); + memcpy(const_cast(str.data()), stringBegin, length); } return length; @@ -332,10 +383,10 @@ uint32_t PeLib::ImageLoader::dumpImage(const char * fileName) uint32_t PeLib::ImageLoader::getImageBitability() const { - if(fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_AMD64 || fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_IA64) + if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) return 64; - if(fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_I386) + if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) return 32; return 0; @@ -632,6 +683,151 @@ uint32_t PeLib::ImageLoader::readWriteImageFile(void * buffer, std::uint32_t rva return bytesToRead; } +//----------------------------------------------------------------------------- +// Processes relocation entry for IA64 relocation bundle + +#define EMARCH_ENC_I17_IMM7B_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM7B_SIZE_X 7 +#define EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X 4 +#define EMARCH_ENC_I17_IMM7B_VAL_POS_X 0 + +#define EMARCH_ENC_I17_IMM9D_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM9D_SIZE_X 9 +#define EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X 18 +#define EMARCH_ENC_I17_IMM9D_VAL_POS_X 7 + +#define EMARCH_ENC_I17_IMM5C_INST_WORD_X 3 +#define EMARCH_ENC_I17_IMM5C_SIZE_X 5 +#define EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X 13 +#define EMARCH_ENC_I17_IMM5C_VAL_POS_X 16 + +#define EMARCH_ENC_I17_IC_INST_WORD_X 3 +#define EMARCH_ENC_I17_IC_SIZE_X 1 +#define EMARCH_ENC_I17_IC_INST_WORD_POS_X 12 +#define EMARCH_ENC_I17_IC_VAL_POS_X 21 + +#define EMARCH_ENC_I17_IMM41a_INST_WORD_X 1 +#define EMARCH_ENC_I17_IMM41a_SIZE_X 10 +#define EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X 14 +#define EMARCH_ENC_I17_IMM41a_VAL_POS_X 22 + +#define EMARCH_ENC_I17_IMM41b_INST_WORD_X 1 +#define EMARCH_ENC_I17_IMM41b_SIZE_X 8 +#define EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X 24 +#define EMARCH_ENC_I17_IMM41b_VAL_POS_X 32 + +#define EMARCH_ENC_I17_IMM41c_INST_WORD_X 2 +#define EMARCH_ENC_I17_IMM41c_SIZE_X 23 +#define EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X 0 +#define EMARCH_ENC_I17_IMM41c_VAL_POS_X 40 + +#define EMARCH_ENC_I17_SIGN_INST_WORD_X 3 +#define EMARCH_ENC_I17_SIGN_SIZE_X 1 +#define EMARCH_ENC_I17_SIGN_INST_WORD_POS_X 27 +#define EMARCH_ENC_I17_SIGN_VAL_POS_X 63 + +#define EXT_IMM64(Value, SourceValue32, Size, InstPos, ValPos) \ + Value |= (((uint64_t)((SourceValue32 >> InstPos) & (((uint64_t)1 << Size) - 1))) << ValPos) + +#define INS_IMM64(Value, TargetValue32, Size, InstPos, ValPos) \ + TargetValue32 = (TargetValue32 & ~(((1 << Size) - 1) << InstPos)) | \ + ((uint32_t)((((uint64_t)Value >> ValPos) & (((uint64_t)1 << Size) - 1))) << InstPos) + +bool PeLib::ImageLoader::processImageRelocation_IA64_IMM64(uint32_t fixupAddress, uint64_t difference) +{ + uint64_t Value64 = 0; + uint32_t BundleBlock[4]; + + // Align the fixup address to bundle address + fixupAddress = fixupAddress & ~0x0F; + + // Load the 4 32-bit values from the target + if(readImage(BundleBlock, fixupAddress, sizeof(BundleBlock)) != sizeof(BundleBlock)) + return false; + + // + // Extract the IMM64 from bundle + // + + EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM7B_INST_WORD_X], + EMARCH_ENC_I17_IMM7B_SIZE_X, + EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM7B_VAL_POS_X); + EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM9D_INST_WORD_X], + EMARCH_ENC_I17_IMM9D_SIZE_X, + EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM9D_VAL_POS_X); + EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM5C_INST_WORD_X], + EMARCH_ENC_I17_IMM5C_SIZE_X, + EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM5C_VAL_POS_X); + EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IC_INST_WORD_X], + EMARCH_ENC_I17_IC_SIZE_X, + EMARCH_ENC_I17_IC_INST_WORD_POS_X, + EMARCH_ENC_I17_IC_VAL_POS_X); + EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM41a_INST_WORD_X], + EMARCH_ENC_I17_IMM41a_SIZE_X, + EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41a_VAL_POS_X); + EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM41b_INST_WORD_X], + EMARCH_ENC_I17_IMM41b_SIZE_X, + EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41b_VAL_POS_X); + EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM41c_INST_WORD_X], + EMARCH_ENC_I17_IMM41c_SIZE_X, + EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41c_VAL_POS_X); + EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_SIGN_INST_WORD_X], + EMARCH_ENC_I17_SIGN_SIZE_X, + EMARCH_ENC_I17_SIGN_INST_WORD_POS_X, + EMARCH_ENC_I17_SIGN_VAL_POS_X); + // + // Update 64-bit address + // + + Value64 += difference; + + // + // Insert IMM64 into bundle + // + + INS_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM7B_INST_WORD_X], + EMARCH_ENC_I17_IMM7B_SIZE_X, + EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM7B_VAL_POS_X); + INS_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM9D_INST_WORD_X], + EMARCH_ENC_I17_IMM9D_SIZE_X, + EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM9D_VAL_POS_X); + INS_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM5C_INST_WORD_X], + EMARCH_ENC_I17_IMM5C_SIZE_X, + EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM5C_VAL_POS_X); + INS_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IC_INST_WORD_X], + EMARCH_ENC_I17_IC_SIZE_X, + EMARCH_ENC_I17_IC_INST_WORD_POS_X, + EMARCH_ENC_I17_IC_VAL_POS_X); + INS_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM41a_INST_WORD_X], + EMARCH_ENC_I17_IMM41a_SIZE_X, + EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41a_VAL_POS_X); + INS_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM41b_INST_WORD_X], + EMARCH_ENC_I17_IMM41b_SIZE_X, + EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41b_VAL_POS_X); + INS_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM41c_INST_WORD_X], + EMARCH_ENC_I17_IMM41c_SIZE_X, + EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41c_VAL_POS_X); + INS_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_SIGN_INST_WORD_X], + EMARCH_ENC_I17_SIGN_SIZE_X, + EMARCH_ENC_I17_SIGN_INST_WORD_POS_X, + EMARCH_ENC_I17_SIGN_VAL_POS_X); + + // Write the bundle block back to the image + return (writeImage(BundleBlock, fixupAddress, sizeof(BundleBlock)) == sizeof(BundleBlock)); +} + bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t newImageBase, uint32_t VirtualAddress, uint32_t Size) { uint64_t difference = (newImageBase - oldImageBase); @@ -640,7 +836,8 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t uint8_t * buffer; // No not accept anything less than size of relocation block - if(Size < sizeof(PELIB_IMAGE_BASE_RELOCATION)) + // Also refuse to process suspiciously large relocation blocks + if(Size < sizeof(PELIB_IMAGE_BASE_RELOCATION) || Size > PELIB_SIZE_10MB) return false; // Allocate and read the relocation block @@ -657,6 +854,10 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t uint16_t * typeAndOffset = (uint16_t * )(pRelocBlock + 1); uint32_t numRelocations; + // Skip relocation blocks that have invalid values + if(!isValidImageBlock(pRelocBlock->VirtualAddress, pRelocBlock->SizeOfBlock)) + break; + // Skip relocation blocks which have invalid size in the header if(pRelocBlock->SizeOfBlock <= sizeof(PELIB_IMAGE_BASE_RELOCATION)) { @@ -664,7 +865,7 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t continue; } - // Windows loader seems to skip relocation blocks that go into a zero page + // Windows loader seems to skip relocation blocks that go into the 0-th page (the header) // Sample: e380e6968f1b431e245f811f94cef6a5b6e17fd7c90ef283338fa1959eb3c536 if(isZeroPage(pRelocBlock->VirtualAddress)) { @@ -759,6 +960,10 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t break; } + case PELIB_IMAGE_REL_BASED_IA64_IMM64: + processImageRelocation_IA64_IMM64(fixupAddress, difference); + break; + case PELIB_IMAGE_REL_BASED_ABSOLUTE: // Absolute - no fixup required. break; @@ -786,7 +991,7 @@ void PeLib::ImageLoader::writeNewImageBase(uint64_t newImageBase) if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { PELIB_IMAGE_OPTIONAL_HEADER64 header64{}; - uint32_t sizeOfOptionalHeader = getRealSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER64)); + uint32_t sizeOfOptionalHeader = getCopySizeOfOptionalHeader(); readImage(&header64, offset, sizeOfOptionalHeader); header64.ImageBase = newImageBase; @@ -797,7 +1002,7 @@ void PeLib::ImageLoader::writeNewImageBase(uint64_t newImageBase) if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { PELIB_IMAGE_OPTIONAL_HEADER32 header32{}; - uint32_t sizeOfOptionalHeader = getRealSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER32)); + uint32_t sizeOfOptionalHeader = getCopySizeOfOptionalHeader(); readImage(&header32, offset, sizeOfOptionalHeader); header32.ImageBase = (uint32_t)newImageBase; @@ -839,18 +1044,24 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) // Capture the NT signature if((filePtr + sizeof(uint32_t)) >= fileEnd) + { setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); - ntSignature = *(uint32_t *)(filePtr); + return ERROR_INVALID_FILE; + } // Check the NT signature - if(ntSignature != PELIB_IMAGE_NT_SIGNATURE) + if((ntSignature = *(uint32_t *)(filePtr)) != PELIB_IMAGE_NT_SIGNATURE) + { setLoaderError(LDR_ERROR_NO_NT_SIGNATURE); + return ERROR_INVALID_FILE; + } filePtr += sizeof(uint32_t); // Capture the file header - if((filePtr + sizeof(PELIB_IMAGE_FILE_HEADER)) >= fileEnd) + if((filePtr + sizeof(PELIB_IMAGE_FILE_HEADER)) < fileEnd) + memcpy(&fileHeader, filePtr, sizeof(PELIB_IMAGE_FILE_HEADER)); + else setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); - memcpy(&fileHeader, filePtr, sizeof(PELIB_IMAGE_FILE_HEADER)); // 7baebc6d9f2185fafa760c875ab1386f385a0b3fecf2e6ae339abb4d9ac58f3e if (fileHeader.Machine == 0 && fileHeader.SizeOfOptionalHeader == 0) @@ -871,90 +1082,89 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) // Capture optional header. Note that we need to parse it // according to IMAGE_OPTIONAL_HEADER::Magic - if((filePtr + sizeof(uint16_t)) < fileEnd) - optionalHeaderMagic = *(uint16_t *)(filePtr); - if(optionalHeaderMagic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) - captureOptionalHeader64(fileBegin, filePtr, fileEnd); - else - captureOptionalHeader32(fileBegin, filePtr, fileEnd); - - // Performed by Windows 10 (nt!MiVerifyImageHeader): - // Sample: 04d3577d1b6309a0032d4c4c1252c55416a09bb617aebafe512fffbdd4f08f18 - if(appContainerCheck && checkForBadAppContainer()) - setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE); - - // SizeOfHeaders must be nonzero if not a single subsection - if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE && optionalHeader.SizeOfHeaders == 0) - setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_ZERO); - - // File alignment must not be 0 - if(optionalHeader.FileAlignment == 0) - setLoaderError(LDR_ERROR_FILE_ALIGNMENT_ZERO); - - // File alignment must be a power of 2 - if(optionalHeader.FileAlignment & (optionalHeader.FileAlignment-1)) - setLoaderError(LDR_ERROR_FILE_ALIGNMENT_NOT_POW2); - - // Section alignment must not be 0 - if (optionalHeader.SectionAlignment == 0) - setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_ZERO); - - // Section alignment must be a power of 2 - if (optionalHeader.SectionAlignment & (optionalHeader.SectionAlignment - 1)) - setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_NOT_POW2); - - if (optionalHeader.SectionAlignment < optionalHeader.FileAlignment) - setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_TOO_SMALL); - - // Check for images with "super-section": FileAlignment must be equal to SectionAlignment - if ((optionalHeader.FileAlignment & 511) && (optionalHeader.SectionAlignment != optionalHeader.FileAlignment)) - setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_INVALID); - - // Check for largest image - if(optionalHeader.SizeOfImage > PELIB_MM_SIZE_OF_LARGEST_IMAGE) - setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_TOO_BIG); - - // Check for 32-bit images - if (optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC && fileHeader.Machine != PELIB_IMAGE_FILE_MACHINE_I386) - setLoaderError(LDR_ERROR_INVALID_MACHINE32); - - // Check for 64-bit images - if (optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - if (fileHeader.Machine != PELIB_IMAGE_FILE_MACHINE_AMD64 && fileHeader.Machine != PELIB_IMAGE_FILE_MACHINE_IA64) - setLoaderError(LDR_ERROR_INVALID_MACHINE64); - } - - // Check the size of image - if(optionalHeader.SizeOfHeaders > optionalHeader.SizeOfImage) - setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); - - // On 64-bit Windows, size of optional header must be properly aligned to 8-byte boundary - if (fileHeader.SizeOfOptionalHeader & (sizeof(uint64_t) - 1)) - setLoaderError(LDR_ERROR_SIZE_OF_OPTHDR_NOT_ALIGNED); - - // Set the size of image - if(BytesToPages(optionalHeader.SizeOfImage) == 0) - setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_ZERO); - - // Check for proper alignment of the image base - if(optionalHeader.ImageBase & (PELIB_SIZE_64KB - 1)) - setLoaderError(LDR_ERROR_IMAGE_BASE_NOT_ALIGNED); - - return ERROR_NONE; +if((filePtr + sizeof(uint16_t)) < fileEnd) + optionalHeaderMagic = *(uint16_t *)(filePtr); +if(optionalHeaderMagic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) +captureOptionalHeader64(fileBegin, filePtr, fileEnd); +else +captureOptionalHeader32(fileBegin, filePtr, fileEnd); + +// Performed by Windows 10 (nt!MiVerifyImageHeader): +// Sample: 04d3577d1b6309a0032d4c4c1252c55416a09bb617aebafe512fffbdd4f08f18 +if(appContainerCheck && checkForBadAppContainer()) +setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE); + +// SizeOfHeaders must be nonzero if not a single subsection +if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE && optionalHeader.SizeOfHeaders == 0) +setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_ZERO); + +// File alignment must not be 0 +if(optionalHeader.FileAlignment == 0) +setLoaderError(LDR_ERROR_FILE_ALIGNMENT_ZERO); + +// File alignment must be a power of 2 +if(optionalHeader.FileAlignment & (optionalHeader.FileAlignment-1)) +setLoaderError(LDR_ERROR_FILE_ALIGNMENT_NOT_POW2); + +// Section alignment must not be 0 +if(optionalHeader.SectionAlignment == 0) +setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_ZERO); + +// Section alignment must be a power of 2 +if(optionalHeader.SectionAlignment & (optionalHeader.SectionAlignment - 1)) +setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_NOT_POW2); + +if(optionalHeader.SectionAlignment < optionalHeader.FileAlignment) + setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_TOO_SMALL); + +// Check for images with "super-section": FileAlignment must be equal to SectionAlignment +if((optionalHeader.FileAlignment & 511) && (optionalHeader.SectionAlignment != optionalHeader.FileAlignment)) +setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_INVALID); + +// Check for largest image +if(optionalHeader.SizeOfImage > PELIB_MM_SIZE_OF_LARGEST_IMAGE) +setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_TOO_BIG); + +// Check for 32-bit images +if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC && checkForValid32BitMachine() == false) +setLoaderError(LDR_ERROR_INVALID_MACHINE32); + +// Check for 64-bit images +if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC && checkForValid64BitMachine() == false) +setLoaderError(LDR_ERROR_INVALID_MACHINE64); + +// Check the size of image +if(optionalHeader.SizeOfHeaders > optionalHeader.SizeOfImage) +setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); + +// On 64-bit Windows, size of optional header must be properly aligned to 8-byte boundary +if(is64BitWindows && (fileHeader.SizeOfOptionalHeader & 0x07)) +setLoaderError(LDR_ERROR_SIZE_OF_OPTHDR_NOT_ALIGNED); + +// Set the size of image +if(BytesToPages(optionalHeader.SizeOfImage) == 0) +setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_ZERO); + +// Check for proper alignment of the image base +if(optionalHeader.ImageBase & (PELIB_SIZE_64KB - 1)) +setLoaderError(LDR_ERROR_IMAGE_BASE_NOT_ALIGNED); + +return ERROR_NONE; } -int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std::string & sectionName, const std::uint8_t * Name) +int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std::string & sectionName, const std::uint8_t * Name) { - uint32_t stringTableOffset; - uint32_t stringTableIndex = 0; + size_t length = 0; // If the section name is in format of "/12345", then the section name is actually in the symbol table // Sample: 2e9c671b8a0411f2b397544b368c44d7f095eb395779de0ad1ac946914dfa34c + // Since retdec's regression tests doesn't like these, we skip this feature + /* if(fileHeader.PointerToSymbolTable != 0 && Name[0] == '/') { // Get the offset of the string table - stringTableOffset = fileHeader.PointerToSymbolTable + fileHeader.NumberOfSymbols * PELIB_IMAGE_SIZEOF_COFF_SYMBOL; + uint32_t stringTableOffset = fileHeader.PointerToSymbolTable + fileHeader.NumberOfSymbols * PELIB_IMAGE_SIZEOF_COFF_SYMBOL; + uint32_t stringTableIndex = 0; // Convert the index from string to number for (size_t i = 1; i < PELIB_IMAGE_SIZEOF_SHORT_NAME && isdigit(Name[i]); i++) @@ -962,21 +1172,22 @@ int PeLib::ImageLoader::captureSectionName(std::vector & fileData, // Get the section name readStringRaw(fileData, sectionName, stringTableOffset + stringTableIndex); + return ERROR_NONE; } - else + */ + + // The section name is directly in the section header. + // It has fixed length and must not be necessarily terminated with zero. + // Historically, PELIB copies the name of the section WITHOUT zero chars, + // even if the zero chars are in the middle. Aka ".text\0\0X" results in ".textX" + sectionName.clear(); + for(size_t i = 0; i < PELIB_IMAGE_SIZEOF_SHORT_NAME; i++) { - // We do not want the trailing zeros to be included in the section name. - size_t length; - - // Calculate the length of the section name. It is not zero terminated and has maximum size of 8. - for(length = 0; length < PELIB_IMAGE_SIZEOF_SHORT_NAME && Name[length] != 0; length++); - - // The section name is directly in the section header. - // It has fixed length and must not be necessarily terminated with zero. - sectionName.resize(length); - memcpy(const_cast(sectionName.data()), Name, length); + if(Name[i]) + { + sectionName += Name[i]; + } } - return ERROR_NONE; } @@ -1266,7 +1477,7 @@ int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOf return (ldrError == LDR_ERROR_E_LFANEW_OUT_OF_FILE) ? ERROR_INVALID_FILE : ERROR_NONE; } -int PeLib::ImageLoader::loadImageAsIs(std::vector & fileData) +int PeLib::ImageLoader::loadImageAsIs(std::vector & fileData) { rawFileData = fileData; return ERROR_NONE; @@ -1275,13 +1486,13 @@ int PeLib::ImageLoader::loadImageAsIs(std::vector & fileData) int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * fileBegin, uint8_t * filePtr, uint8_t * fileEnd) { PELIB_IMAGE_OPTIONAL_HEADER64 optionalHeader64{}; - uint32_t sizeOfOptionalHeader = getRealSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER64)); + uint32_t sizeOfOptionalHeader = sizeof(PELIB_IMAGE_OPTIONAL_HEADER64); uint32_t numberOfRvaAndSizes; // Capture optional header. Note that IMAGE_FILE_HEADER::SizeOfOptionalHeader - // is not used by the Windows loader to actually verify its size + // is not taken into account by the Windows loader - it simply assumes that the entire optional header is present if((filePtr + sizeOfOptionalHeader) > fileEnd) - return setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); + sizeOfOptionalHeader = (uint32_t)(fileEnd - filePtr); memcpy(&optionalHeader64, filePtr, sizeOfOptionalHeader); // Verify whether it's 64-bit optional header @@ -1333,13 +1544,13 @@ int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * fileBegin, uint8_t * f int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * fileBegin, uint8_t * filePtr, uint8_t * fileEnd) { PELIB_IMAGE_OPTIONAL_HEADER32 optionalHeader32{}; - uint32_t sizeOfOptionalHeader = getRealSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER32)); + uint32_t sizeOfOptionalHeader = sizeof(PELIB_IMAGE_OPTIONAL_HEADER32); uint32_t numberOfRvaAndSizes; // Capture optional header. Note that IMAGE_FILE_HEADER::SizeOfOptionalHeader - // is not used by the Windows loader to actually verify its size + // is not taken into account by the Windows loader - it simply assumes that the entire optional header is present if((filePtr + sizeOfOptionalHeader) > fileEnd) - return setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); + sizeOfOptionalHeader = (uint32_t)(fileEnd - filePtr); memcpy(&optionalHeader32, filePtr, sizeOfOptionalHeader); // Verify whether it's 32-bit optional header @@ -1389,13 +1600,6 @@ int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * fileBegin, uint8_t * f return ERROR_NONE; } -std::uint32_t PeLib::ImageLoader::getRealSizeOfOptionalHeader(std::uint32_t nominalSize) -{ - if(0 < fileHeader.SizeOfOptionalHeader && fileHeader.SizeOfOptionalHeader < nominalSize) - nominalSize = fileHeader.SizeOfOptionalHeader; - return nominalSize; -} - uint32_t PeLib::ImageLoader::captureImageSection( std::vector & fileData, uint32_t virtualAddress, @@ -1533,18 +1737,14 @@ bool PeLib::ImageLoader::isGoodMappedPage(uint32_t rva) { uint32_t pageIndex = (rva / PELIB_PAGE_SIZE); - if(pageIndex > pages.size()) - return false; - return (pages[pageIndex].isInvalidPage == false); + return (pageIndex < pages.size()) ? !pages[pageIndex].isInvalidPage : false; } bool PeLib::ImageLoader::isZeroPage(uint32_t rva) { uint32_t pageIndex = (rva / PELIB_PAGE_SIZE); - if(pageIndex > pages.size()) - return false; - return (pages[pageIndex].isZeroPage); + return (pageIndex < pages.size()) ? pages[pageIndex].isZeroPage : false; } bool PeLib::ImageLoader::isRvaOfSectionHeaderPointerToRawData(uint32_t rva) @@ -1586,6 +1786,22 @@ bool PeLib::ImageLoader::isLegacyImageArchitecture(uint16_t Machine) return false; } +bool PeLib::ImageLoader::checkForValid64BitMachine() +{ + // Since Windows 10, image loader will load 64-bit ARM images + if(loadArmImages && fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_ARM64) + return true; + return (fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_AMD64 || fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_IA64); +} + +bool PeLib::ImageLoader::checkForValid32BitMachine() +{ + // Since Windows 10, image loader will load 32-bit ARM images + if(loadArmImages && fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_ARMNT) + return true; + return (fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_I386); +} + // Windows 10: For IMAGE_FILE_MACHINE_I386 and IMAGE_FILE_MACHINE_AMD64, // if (Characteristics & IMAGE_FILE_RELOCS_STRIPPED) and (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER), // MiVerifyImageHeader returns STATUS_INVALID_IMAGE_FORMAT. @@ -1608,12 +1824,12 @@ bool PeLib::ImageLoader::checkForBadAppContainer() // Returns true if the image is OK and can be mapped by NtCreateSection(SEC_IMAGE). // This does NOT mean that the image is executable by CreateProcess - more checks are done, // like resource integrity or relocation table correctness. -bool PeLib::ImageLoader::isImageLoadable() +bool PeLib::ImageLoader::isImageLoadable() const { return (ldrError == LDR_ERROR_NONE || ldrError == LDR_ERROR_FILE_IS_CUT_LOADABLE); } -bool PeLib::ImageLoader::isImageMappedOk() +bool PeLib::ImageLoader::isImageMappedOk() const { // If there was loader error, we didn't map the image if(!isImageLoadable()) @@ -1623,6 +1839,17 @@ bool PeLib::ImageLoader::isImageMappedOk() return true; } +bool PeLib::ImageLoader::isValidImageBlock(std::uint32_t Rva, std::uint32_t Size) const +{ + if(Rva >= optionalHeader.SizeOfImage || Size >= optionalHeader.SizeOfImage) + return false; + if((Rva + Size) < Rva) + return false; + if((Rva + Size) > optionalHeader.SizeOfImage) + return false; + return true; +} + //----------------------------------------------------------------------------- // Testing functions diff --git a/src/pelib/PeFile.cpp b/src/pelib/PeFile.cpp index 965544013..6736180db 100644 --- a/src/pelib/PeFile.cpp +++ b/src/pelib/PeFile.cpp @@ -429,7 +429,7 @@ namespace PeLib std::uint64_t sizeOfImage = m_imageLoader.getSizeOfImage(); // The file size must be greater or equal to SizeOfImage - if(ulFileSize >= sizeOfImage) + if(ulFileSize >= sizeOfImage && m_imageLoader.getNumberOfSections() != 0) { std::uint32_t sectionAlignment = m_imageLoader.getSectionAlignment(); std::uint32_t fileAlignment = m_imageLoader.getFileAlignment(); diff --git a/src/pelib/RelocationsDirectory.cpp b/src/pelib/RelocationsDirectory.cpp index f7f03013d..5906d6dc5 100644 --- a/src/pelib/RelocationsDirectory.cpp +++ b/src/pelib/RelocationsDirectory.cpp @@ -131,7 +131,7 @@ namespace PeLib case PELIB_IMAGE_REL_BASED_LOW: case PELIB_IMAGE_REL_BASED_HIGHLOW: case PELIB_IMAGE_REL_BASED_MIPS_JMPADDR: - case PELIB_IMAGE_REL_BASED_MIPS_JMPADDR16: + case PELIB_IMAGE_REL_BASED_IA64_IMM64: case PELIB_IMAGE_REL_BASED_DIR64: // This is a correct relocation entry. Lower 12 bits contains From 175fa6cc5761a2635b23229de3506d3861dd401a Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Mon, 29 Jun 2020 13:12:18 +0200 Subject: [PATCH 10/34] ImageLoader: Finalizing --- .../fileformat/file_format/pe/pe_format.h | 1 + .../file_format/pe/pe_format_parser.h | 10 +++ .../fileformat/types/symbol_table/symbol.h | 4 +- .../fileformat/types/tls_info/tls_info.h | 1 + include/retdec/pelib/CoffSymbolTable.h | 2 +- include/retdec/pelib/ImportDirectory.h | 27 +++++++- include/retdec/pelib/PeLibAux.h | 1 + include/retdec/pelib/TlsDirectory.h | 34 ++++++++++ src/fileformat/file_format/pe/pe_format.cpp | 68 +++++++++---------- .../types/import_table/import_table.cpp | 31 +++++---- src/fileformat/types/symbol_table/symbol.cpp | 4 +- src/fileformat/types/tls_info/tls_info.cpp | 9 +++ src/pelib/CoffSymbolTable.cpp | 2 +- src/pelib/PeFile.cpp | 26 ++++--- src/unpackertool/plugins/upx/upx_stub.cpp | 8 +-- 15 files changed, 156 insertions(+), 72 deletions(-) diff --git a/include/retdec/fileformat/file_format/pe/pe_format.h b/include/retdec/fileformat/file_format/pe/pe_format.h index 25f7d2de6..4c4bed7c2 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format.h +++ b/include/retdec/fileformat/file_format/pe/pe_format.h @@ -163,6 +163,7 @@ class PeFormat : public FileFormat std::size_t getMzHeaderSize() const; std::size_t getOptionalHeaderSize() const; std::size_t getPeHeaderOffset() const; + std::size_t getImageBitability() const; std::size_t getCoffSymbolTableOffset() const; std::size_t getNumberOfCoffSymbols() const; std::size_t getSizeOfStringTable() const; diff --git a/include/retdec/fileformat/file_format/pe/pe_format_parser.h b/include/retdec/fileformat/file_format/pe/pe_format_parser.h index 102d40a13..3fed5402b 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format_parser.h +++ b/include/retdec/fileformat/file_format/pe/pe_format_parser.h @@ -45,6 +45,11 @@ class PeFormatParser return peFile->imageLoader().getPeHeaderOffset(); } + std::uint32_t getImageBitability() const + { + return peFile->imageLoader().getImageBitability(); + } + std::uint32_t getDeclaredNumberOfSections() const { return peFile->imageLoader().getFileHeader().NumberOfSections; @@ -486,6 +491,11 @@ class PeFormatParser return peFile->tlsDir().getAddressOfIndex(); } + const std::vector & getCallbacks() const + { + return peFile->tlsDir().getCallbacks(); + } + std::uint64_t getTlsAddressOfCallBacks() const { return peFile->tlsDir().getAddressOfCallBacks(); diff --git a/include/retdec/fileformat/types/symbol_table/symbol.h b/include/retdec/fileformat/types/symbol_table/symbol.h index e9b39cc1f..4f75c187c 100644 --- a/include/retdec/fileformat/types/symbol_table/symbol.h +++ b/include/retdec/fileformat/types/symbol_table/symbol.h @@ -93,8 +93,8 @@ class Symbol /// @name Setters /// @{ - void setName(std::string symbolName); - void setOriginalName(std::string symbolOriginalName); + void setName(const std::string & symbolName); + void setOriginalName(const std::string & symbolOriginalName); void setType(Symbol::Type symbolType); void setUsageType(Symbol::UsageType symbolUsageType); void setIndex(unsigned long long symbolIndex); diff --git a/include/retdec/fileformat/types/tls_info/tls_info.h b/include/retdec/fileformat/types/tls_info/tls_info.h index 17655a2c2..6b091c629 100644 --- a/include/retdec/fileformat/types/tls_info/tls_info.h +++ b/include/retdec/fileformat/types/tls_info/tls_info.h @@ -52,6 +52,7 @@ class TlsInfo void setCallBacksAddr(std::uint64_t cbAddr); void setZeroFillSize(std::uint32_t zFill); void setCharacteristics(std::uint32_t chars); + void setCallBacks(const std::vector & callbacks); /// @} /// @name Other methods diff --git a/include/retdec/pelib/CoffSymbolTable.h b/include/retdec/pelib/CoffSymbolTable.h index 00677ad79..da30f0e58 100644 --- a/include/retdec/pelib/CoffSymbolTable.h +++ b/include/retdec/pelib/CoffSymbolTable.h @@ -36,7 +36,7 @@ namespace PeLib std::size_t getSizeOfStringTable() const; std::size_t getNumberOfStoredSymbols() const; std::uint32_t getSymbolIndex(std::size_t ulSymbol) const; - std::string getSymbolName(std::size_t ulSymbol) const; + const std::string & getSymbolName(std::size_t ulSymbol) const; std::uint32_t getSymbolValue(std::size_t ulSymbol) const; std::uint16_t getSymbolSectionNumber(std::size_t ulSymbol) const; std::uint8_t getSymbolTypeComplex(std::size_t ulSymbol) const; diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index b27a441ff..92fa03586 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -518,6 +518,27 @@ namespace PeLib else return static_cast(m_vNewiid[dwFilenr].firstthunk.size()); } + inline bool isInvalidOrdinal(std::uint64_t ordinal, std::uint64_t ordinalMask, std::uint64_t sizeOfImage) + { + // Check for invalid name + if((ordinal & ordinalMask) == 0) + { + // Any name RVA that goes out of image is considered invalid + if(ordinal >= sizeOfImage) + { + return true; + } + } + else + { + // Mask out the ordinal bit. Then, any ordinal must not be larger than 0xFFFF + ordinal = ordinal & ~ordinalMask; + return (ordinal >> 0x10) != 0; + } + + return false; + } + /** * Read an import directory from a file. * \todo Check if streams failed. @@ -648,7 +669,9 @@ namespace PeLib // Check samples that have import name out of the image // Sample: CCE461B6EB23728BA3B8A97B9BE84C0FB9175DB31B9949E64144198AB3F702CE - if ((tdCurr.itd.Ordinal & OrdinalMask) == 0 && (tdCurr.itd.Ordinal >= SizeOfImage)) + // Import by ordinal must be lower-word only; any ordinal that is greater than 0xFFFF is invalid. + // Sample: 7CE5BB5CA99B3570514AF03782545D41213A77A0F93D4AAC8269823A8D3A58EF + if(isInvalidOrdinal(tdCurr.itd.Ordinal, OrdinalMask, SizeOfImage)) { setLoaderError(LDR_ERROR_IMPDIR_NAME_RVA_INVALID); break; @@ -709,7 +732,7 @@ namespace PeLib // Check samples that have import name out of the image // Sample: CCE461B6EB23728BA3B8A97B9BE84C0FB9175DB31B9949E64144198AB3F702CE - // if ((tdCurr.itd.Ordinal & OrdinalMask) == 0 && (tdCurr.itd.Ordinal >= SizeOfImage)) + //if(isInvalidOrdinal(tdCurr.itd.Ordinal, OrdinalMask, SizeOfImage)) // break; vOldIidCurr[i].firstthunk.push_back(tdCurr); diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index 2e5b64f04..926ed0d35 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -152,6 +152,7 @@ namespace PeLib const std::uint32_t PELIB_MM_SIZE_OF_LARGEST_IMAGE = 0x77000000; + const std::uint32_t PELIB_MAX_TLS_CALLBACKS = 0x100; // Maximum number of processed TLS callbacks const std::uint32_t PELIB_MAX_IMPORT_DLLS = 0x100; // Maximum number of imported DLLs we consider OK const std::uint32_t PELIB_MAX_IMPORTED_FUNCTIONS = 0x1000; // Maximum number of exported functions (per DLL) that we support const std::uint32_t PELIB_MAX_EXPORTED_FUNCTIONS = 0x1000; // Maximum number of exported functions that we support diff --git a/include/retdec/pelib/TlsDirectory.h b/include/retdec/pelib/TlsDirectory.h index 6c9c27d5c..3c02fc034 100644 --- a/include/retdec/pelib/TlsDirectory.h +++ b/include/retdec/pelib/TlsDirectory.h @@ -25,6 +25,7 @@ namespace PeLib { private: PELIB_IMAGE_TLS_DIRECTORY m_tls; ///< Structure that holds all information about the directory. + std::vector m_Callbacks; std::size_t pointerSize; public: @@ -37,6 +38,8 @@ namespace PeLib /// Writes the TLS directory to a file. int write(const std::string& strFilename, unsigned int dwOffset) const; // EXPORT + /// Returns vector of TLS callbacks + const std::vector & getCallbacks() const; /// Returns the StartAddressOfRawData value of the TLS header. std::uint64_t getStartAddressOfRawData() const; // EXPORT /// Returns the EndAddressOfRawData value of the TLS header. @@ -72,10 +75,12 @@ namespace PeLib inline int TlsDirectory::read(ImageLoader & imageLoader) { + std::uint64_t imageBase = imageLoader.getImageBase(); std::uint32_t rva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_TLS); std::uint32_t size = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_TLS); std::uint32_t sizeOfImage = imageLoader.getSizeOfImage(); std::uint32_t bytesRead; + if((rva + size) >= sizeOfImage) return ERROR_INVALID_FILE; @@ -108,6 +113,26 @@ namespace PeLib return ERROR_INVALID_FILE; } + // If there is non-zero address of callbacks, we try to read at least one pointer to know + // if there are TLS callbacks + if(imageBase < m_tls.AddressOfCallBacks && m_tls.AddressOfCallBacks < (imageBase + sizeOfImage)) + { + std::uint32_t rva = (std::uint32_t)(m_tls.AddressOfCallBacks - imageBase); + + for(std::uint32_t i = 0; i < PELIB_MAX_TLS_CALLBACKS; i++) + { + std::uint64_t AddressOfCallBack = 0; + + if(imageLoader.readPointer(rva, AddressOfCallBack) == 0) + break; + if(AddressOfCallBack == 0) + break; + + m_Callbacks.push_back(AddressOfCallBack); + rva += pointerSize; + } + } + return ERROR_NONE; } @@ -187,6 +212,15 @@ namespace PeLib return ERROR_NONE; } + /** + * @return The vector of TLS callbacks + **/ + inline + const std::vector & TlsDirectory::getCallbacks() const + { + return m_Callbacks; + } + /** * @return The StartAddressOfRawData value of the TLS directory. **/ diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index 1479c25ed..913067918 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -1387,7 +1387,7 @@ void PeFormat::loadSections() */ void PeFormat::loadSymbols() { - const auto symTab = file->coffSymTab(); + const auto & symTab = file->coffSymTab(); auto *table = new SymbolTable(); for(std::size_t i = 0, e = symTab.getNumberOfStoredSymbols(); i < e; ++i) @@ -1783,35 +1783,40 @@ void PeFormat::loadCertificates() // We always take the first one, there are no additional certificate tables in PE auto certBytes = securityDir.getCertificate(0); + auto certSize = certBytes.size(); + PKCS7 *p7 = NULL; + BIO *bio; - BIO *bio = BIO_new(BIO_s_mem()); - if(!bio) - { - return; - } - - if(BIO_reset(bio) != 1) + // Create the BIO object and extract certificate from it + if((bio = BIO_new(BIO_s_mem())) != NULL) { + if(BIO_reset(bio) == 1) + { + if(BIO_write(bio, certBytes.data(), certSize) == certSize) + { + p7 = d2i_PKCS7_bio(bio, nullptr); + } + } BIO_free(bio); - return; } - if(BIO_write(bio, certBytes.data(), static_cast(certBytes.size())) != static_cast(certBytes.size())) + // Make sure that the PKCS7 structure is valid + if(!p7) { - BIO_free(bio); return; } - PKCS7 *p7 = d2i_PKCS7_bio(bio, nullptr); - if(!p7) + // Make sure that the PKCS7 data is valid + if(!PKCS7_type_is_data(p7)) { - BIO_free(bio); + PKCS7_free(p7); return; } // Find signer of the application and store its serial number. X509 *signerCert = nullptr; X509 *counterSignerCert = nullptr; + STACK_OF(X509) *certs = p7->d.sign->cert; STACK_OF(X509) *signers = PKCS7_get0_signers(p7, certs, 0); @@ -1849,7 +1854,6 @@ void PeFormat::loadCertificates() // If we have no signer and countersigner, there must be something really bad if(!signerCert && !counterSignerCert) { - BIO_free(bio); return; } @@ -1934,7 +1938,6 @@ void PeFormat::loadCertificates() } PKCS7_free(p7); - BIO_free(bio); } /** @@ -1958,25 +1961,7 @@ void PeFormat::loadTlsInformation() auto callBacksAddr = formatParser->getTlsAddressOfCallBacks(); tlsInfo->setCallBacksAddr(callBacksAddr); - const auto &allBytes = getBytes(); - DynamicBuffer structContent(allBytes); - - unsigned long long callBacksOffset; - if (getOffsetFromAddress(callBacksOffset, callBacksAddr)) - { - while (allBytes.size() >= callBacksOffset + sizeof(std::uint32_t)) - { - auto cbAddr = structContent.read(callBacksOffset); - callBacksOffset += sizeof(std::uint32_t); - - if (cbAddr == 0) - { - break; - } - - tlsInfo->addCallBack(cbAddr); - } - } + tlsInfo->setCallBacks(formatParser->getCallbacks()); } /** @@ -3186,6 +3171,19 @@ std::size_t PeFormat::getPeHeaderOffset() const return formatParser->getPeHeaderOffset(); } +/** +* Get image bitability +* @return 32=32-bit image, 64=64-bit image +* +* In some cases (e.g. FSG packer), offset of PE signature may be inside MZ header and +* therefore this method may return lesser number that method @a getMzHeaderSize(). +*/ +std::size_t PeFormat::getImageBitability() const +{ + return formatParser->getImageBitability(); +} + + /** * Get offset of COFF symbol table * @return Offset of COFF symbol table diff --git a/src/fileformat/types/import_table/import_table.cpp b/src/fileformat/types/import_table/import_table.cpp index a03740cb2..9a88f04e5 100644 --- a/src/fileformat/types/import_table/import_table.cpp +++ b/src/fileformat/types/import_table/import_table.cpp @@ -8,6 +8,7 @@ #include "retdec/utils/conversion.h" #include "retdec/utils/string.h" #include "retdec/fileformat/utils/crypto.h" +#include "retdec/pelib/PeLibAux.h" #include "retdec/fileformat/types/import_table/import_table.h" using namespace retdec::utils; @@ -762,7 +763,13 @@ ImportTable::importsIterator ImportTable::end() const */ void ImportTable::computeHashes() { - std::vector impHashBytes; + std::string impHashBytes; + + // Prevent endless reallocations by reserving space in the import data blob + // The blob format is DllName1.SymbolName1[,DllName2.SymbolName2[,DllName3.SymbolName3]] + impHashBytes.reserve(imports.size() * (PeLib::IMPORT_LIBRARY_MAX_LENGTH + PeLib::IMPORT_LIBRARY_MAX_LENGTH + 2)); + + // Enumerate imports and append them to the import data blob for (const auto& import : imports) { if(!import->isUsedForImphash()) @@ -770,6 +777,7 @@ void ImportTable::computeHashes() continue; } + // Get library name and import name auto libName = toLower(getLibrary(import->getLibraryIndex())); auto funcName = toLower(import->getName()); @@ -798,16 +806,13 @@ void ImportTable::computeHashes() // Yara adds comma if there are multiple imports if(!impHashBytes.empty()) - { - impHashBytes.push_back(static_cast(',')); - } + impHashBytes.append(1, ','); // Append the bytes of the import name to the hash bytes vector // Note that this is faster than the previous char-to-char concatenating - std::string libAndFunc = libName + "." + funcName; - std::size_t oldSize = impHashBytes.size(); - impHashBytes.resize(oldSize + libAndFunc.size()); - memcpy(impHashBytes.data() + oldSize, libAndFunc.data(), libAndFunc.size()); + impHashBytes.append(libName); + impHashBytes.append(1, '.'); + impHashBytes.append(funcName); //for(const auto c : std::string()) //{ @@ -815,14 +820,12 @@ void ImportTable::computeHashes() //} } - if (impHashBytes.size() == 0) + if (impHashBytes.size()) { - return; + impHashCrc32 = retdec::crypto::getCrc32((const uint8_t *)impHashBytes.data(), impHashBytes.size()); + impHashMd5 = retdec::crypto::getMd5((const uint8_t *)impHashBytes.data(), impHashBytes.size()); + impHashSha256 = retdec::crypto::getSha256((const uint8_t *)impHashBytes.data(), impHashBytes.size()); } - - impHashCrc32 = getCrc32(impHashBytes.data(), impHashBytes.size()); - impHashMd5 = getMd5(impHashBytes.data(), impHashBytes.size()); - impHashSha256 = getSha256(impHashBytes.data(), impHashBytes.size()); } /** diff --git a/src/fileformat/types/symbol_table/symbol.cpp b/src/fileformat/types/symbol_table/symbol.cpp index b4ba628bd..ea6f03e36 100644 --- a/src/fileformat/types/symbol_table/symbol.cpp +++ b/src/fileformat/types/symbol_table/symbol.cpp @@ -272,7 +272,7 @@ bool Symbol::getLinkToSection(unsigned long long §ionIndex) const * Set symbol name * @param symbolName Symbol name */ -void Symbol::setName(std::string symbolName) +void Symbol::setName(const std::string & symbolName) { name = symbolName; } @@ -281,7 +281,7 @@ void Symbol::setName(std::string symbolName) * Set original name of symbol * @param symbolOriginalName Original name of symbol */ -void Symbol::setOriginalName(std::string symbolOriginalName) +void Symbol::setOriginalName(const std::string & symbolOriginalName) { originalName = symbolOriginalName; } diff --git a/src/fileformat/types/tls_info/tls_info.cpp b/src/fileformat/types/tls_info/tls_info.cpp index 1f17296e0..dce8b7dce 100644 --- a/src/fileformat/types/tls_info/tls_info.cpp +++ b/src/fileformat/types/tls_info/tls_info.cpp @@ -150,6 +150,15 @@ void TlsInfo::setCallBacksAddr(std::uint64_t cbAddr) callBacksAddrValid = true; } +/** +* Set array of callbacks +* @param cbAddr address of callbacks to set +*/ +void TlsInfo::setCallBacks(const std::vector & callbacks) +{ + callBacks = callbacks; +} + /** * Set zero fill size * @param zFill zero fill size to set diff --git a/src/pelib/CoffSymbolTable.cpp b/src/pelib/CoffSymbolTable.cpp index 21ac93f9b..a3095ba1f 100644 --- a/src/pelib/CoffSymbolTable.cpp +++ b/src/pelib/CoffSymbolTable.cpp @@ -156,7 +156,7 @@ namespace PeLib return symbolTable[ulSymbol].Index; } - std::string CoffSymbolTable::getSymbolName(std::size_t ulSymbol) const + const std::string & CoffSymbolTable::getSymbolName(std::size_t ulSymbol) const { return symbolTable[ulSymbol].Name; } diff --git a/src/pelib/PeFile.cpp b/src/pelib/PeFile.cpp index 6736180db..7c1f35a3f 100644 --- a/src/pelib/PeFile.cpp +++ b/src/pelib/PeFile.cpp @@ -402,20 +402,24 @@ namespace PeLib // Only check PE files compiled for i386 or x64 processors. if (m_imageLoader.getMachine() == PELIB_IMAGE_FILE_MACHINE_I386 || m_imageLoader.getMachine() == PELIB_IMAGE_FILE_MACHINE_AMD64) { - std::uint64_t entryPointCode[2] = {0, 0}; - - // Check if 16 bytes of code are available in the file - if ((addressOfEntryPoint + sizeof(entryPointCode)) < sizeOfImage) + // Only if there are no TLS callbacks + if(m_tlsdir.getCallbacks().size() == 0) { - // Read the entry point code - imgLoader.readImage(entryPointCode, addressOfEntryPoint, sizeof(entryPointCode)); + std::uint64_t entryPointCode[2] = {0, 0}; - // Zeroed instructions at entry point map either to "add [eax], al" (i386) or "add [rax], al" (AMD64). - // Neither of these instructions makes sense on the entry point. We check 16 bytes of the entry point, - // in order to make sure it's really a corruption. - if ((entryPointCode[0] | entryPointCode[1]) == 0) + // Check if 16 bytes of code are available in the file + if ((addressOfEntryPoint + sizeof(entryPointCode)) < sizeOfImage) { - return LDR_ERROR_ENTRY_POINT_ZEROED; + // Read the entry point code + imgLoader.readImage(entryPointCode, addressOfEntryPoint, sizeof(entryPointCode)); + + // Zeroed instructions at entry point map either to "add [eax], al" (i386) or "add [rax], al" (AMD64). + // Neither of these instructions makes sense on the entry point. We check 16 bytes of the entry point, + // in order to make sure it's really a corruption. + if ((entryPointCode[0] | entryPointCode[1]) == 0) + { + return LDR_ERROR_ENTRY_POINT_ZEROED; + } } } } diff --git a/src/unpackertool/plugins/upx/upx_stub.cpp b/src/unpackertool/plugins/upx/upx_stub.cpp index 3b7413391..281d4439e 100644 --- a/src/unpackertool/plugins/upx/upx_stub.cpp +++ b/src/unpackertool/plugins/upx/upx_stub.cpp @@ -286,10 +286,10 @@ std::shared_ptr UpxStub::_createStubImpl(retdec::loader::Image* file, c } case retdec::fileformat::Format::PE: { - //if (static_cast(file->getFileFormat())->isPe32()) - // stub = new PeUpxStub<32>(file, stubData, capturedData, std::move(decompressor), metadata); - //else - // stub = new PeUpxStub<64>(file, stubData, capturedData, std::move(decompressor), metadata); + if (static_cast(file->getFileFormat())->getImageBitability() == 32) + stub = new PeUpxStub<32>(file, stubData, capturedData, std::move(decompressor), metadata); + else + stub = new PeUpxStub<64>(file, stubData, capturedData, std::move(decompressor), metadata); break; } case retdec::fileformat::Format::MACHO: From a7640da8cc0610a6979ec293c5b2c2bf42614da7 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Mon, 29 Jun 2020 14:10:47 +0200 Subject: [PATCH 11/34] ImageLoader: Regression tests passed --- src/fileformat/file_format/pe/pe_format.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index 913067918..90b30711a 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -1806,8 +1806,8 @@ void PeFormat::loadCertificates() return; } - // Make sure that the PKCS7 data is valid - if(!PKCS7_type_is_data(p7)) + //// Make sure that the PKCS7 data is valid + if(!PKCS7_type_is_signed(p7)) { PKCS7_free(p7); return; From 6fcafecad9f6ebb93256d059c2fa35d11b9abdd8 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 30 Jun 2020 22:55:29 +0200 Subject: [PATCH 12/34] ImageLoader: Tests OK --- .../file_format/pe/pe_format_parser.h | 13 +- .../retdec/fileformat/types/sec_seg/sec_seg.h | 3 + include/retdec/pelib/DelayImportDirectory.h | 6 +- include/retdec/pelib/ImageLoader.h | 20 ++ include/retdec/pelib/PeLibAux.h | 1 + src/fileformat/file_format/pe/pe_format.cpp | 6 +- src/fileformat/types/sec_seg/sec_seg.cpp | 20 +- src/fileinfo/file_wrapper/pe_wrapper.cpp | 234 ++++++++++++++++++ src/fileinfo/file_wrapper/pe_wrapper.h | 48 ++++ src/pelib/CoffSymbolTable.cpp | 2 +- src/pelib/ImageLoader.cpp | 170 +++++++------ 11 files changed, 436 insertions(+), 87 deletions(-) create mode 100644 src/fileinfo/file_wrapper/pe_wrapper.cpp create mode 100644 src/fileinfo/file_wrapper/pe_wrapper.h diff --git a/include/retdec/fileformat/file_format/pe/pe_format_parser.h b/include/retdec/fileformat/file_format/pe/pe_format_parser.h index 3fed5402b..cecccfe05 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format_parser.h +++ b/include/retdec/fileformat/file_format/pe/pe_format_parser.h @@ -180,8 +180,7 @@ class PeFormatParser std::uint32_t getStoredNumberOfDataDirectories() const { - std::uint32_t numberOfRvaAndSizes = peFile->imageLoader().getOptionalHeader().NumberOfRvaAndSizes; - return std::min(numberOfRvaAndSizes, PeLib::PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES); + return peFile->imageLoader().getRealNumberOfDataDirectories(); } std::uint32_t getNumberOfImportedLibraries() const @@ -204,16 +203,17 @@ class PeFormatParser std::uint64_t imageBase = peFile->imageLoader().getImageBase(); std::uint32_t entryPoint = peFile->imageLoader().getOptionalHeader().AddressOfEntryPoint; + // Do not report zero entry point on DLLs epAddress = imageBase + entryPoint; - return true; + return (entryPoint != 0 || isDll() == false); } bool getEpOffset(std::uint64_t & epOffset) const { std::uint32_t entryPoint = peFile->imageLoader().getOptionalHeader().AddressOfEntryPoint; - epOffset = peFile->imageLoader().getFileOffsetFromRva(entryPoint); - return (epOffset != UINT32_MAX); + epOffset = peFile->imageLoader().getFileOffsetFromRva(entryPoint); + return (entryPoint != 0 || isDll() == false) && (epOffset != UINT32_MAX); } bool getSectionType(const PeLib::PELIB_SECTION_HEADER * pSectionHeader, PeCoffSection::Type & secType) const @@ -265,6 +265,7 @@ class PeFormatParser section.setType(sectionType); section.setIndex(secIndex); section.setOffset(imageLoader.getRealPointerToRawData(secIndex)); + section.setUnfixedOffset(pSectionHeader->PointerToRawData); section.setSizeInFile(pSectionHeader->SizeOfRawData); section.setSizeInMemory(pSectionHeader->VirtualSize); section.setAddress(pSectionHeader->VirtualAddress ? imageLoader.getImageBase() + pSectionHeader->VirtualAddress : 0); @@ -278,7 +279,7 @@ class PeFormatParser { if(peFile->imageLoader().getCharacteristics() & PeLib::PELIB_IMAGE_FILE_DLL) { - dllFlags = peFile->imageLoader().getCharacteristics(); + dllFlags = peFile->imageLoader().getOptionalHeader().DllCharacteristics; return true; } diff --git a/include/retdec/fileformat/types/sec_seg/sec_seg.h b/include/retdec/fileformat/types/sec_seg/sec_seg.h index 4ae650d67..78f31daa3 100644 --- a/include/retdec/fileformat/types/sec_seg/sec_seg.h +++ b/include/retdec/fileformat/types/sec_seg/sec_seg.h @@ -43,6 +43,7 @@ class SecSeg Type type = Type::UNDEFINED_SEC_SEG; ///< type unsigned long long index = 0; ///< index unsigned long long offset = 0; ///< start offset in file + unsigned long long unfixedOffset = 0; ///< start offset in file (from section header, unfixed) unsigned long long fileSize = 0; ///< size in file unsigned long long address = 0; ///< start address in memory unsigned long long memorySize = 0; ///< size in memory @@ -90,6 +91,7 @@ class SecSeg SecSeg::Type getType() const; unsigned long long getIndex() const; unsigned long long getOffset() const; + unsigned long long getUnfixedOffset() const; unsigned long long getEndOffset() const; unsigned long long getSizeInFile() const; unsigned long long getLoadedSize() const; @@ -134,6 +136,7 @@ class SecSeg void setType(SecSeg::Type sType); void setIndex(unsigned long long sIndex); void setOffset(unsigned long long sOffset); + void setUnfixedOffset(unsigned long long sUnfixedOffset); void setSizeInFile(unsigned long long sFileSize); void setAddress(unsigned long long sAddress); void setSizeInMemory(unsigned long long sMemorySize); diff --git a/include/retdec/pelib/DelayImportDirectory.h b/include/retdec/pelib/DelayImportDirectory.h index a5bc9b21c..7d2c5565a 100644 --- a/include/retdec/pelib/DelayImportDirectory.h +++ b/include/retdec/pelib/DelayImportDirectory.h @@ -202,9 +202,9 @@ namespace PeLib } // Convert function address to RVA, if needed - if((rec.delayedImport.Attributes & PELIB_DELAY_ATTRIBUTE_V2) == 0) - funcAddress = normalizeDelayImportValue(imageBase, funcAddress); - function.address = normalizeDelayImportValue(imageBase, funcAddress); + if(imageBase <= funcAddress && funcAddress < imageBase + sizeOfImage) + funcAddress -= imageBase; + function.address = funcAddress; // Insert the function to the list rec.addFunction(function); diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 76d2b1f47..51a3a5e58 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -260,6 +260,11 @@ class ImageLoader return checkSumFileOffset; } + std::uint32_t getRealNumberOfDataDirectories() const + { + return realNumberOfRvaAndSizes; + } + std::uint32_t getSecurityDirFileOffset() const { return securityDirFileOffset; @@ -277,6 +282,15 @@ class ImageLoader return (optionalHeader.NumberOfRvaAndSizes > dataDirIndex) ? optionalHeader.DataDirectory[dataDirIndex].Size : 0; } + std::uint64_t getVirtualAddressMasked(std::uint32_t rva) + { + std::uint64_t virtualAddress = getImageBase() + rva; + + if(getImageBitability() == 32) + virtualAddress = virtualAddress & 0xFFFFFFFF; + return virtualAddress; + } + int setLoaderError(LoaderError ldrErr); LoaderError loaderError() const; @@ -345,6 +359,11 @@ class ImageLoader return (ByteSize >> PELIB_PAGE_SIZE_SHIFT) + ((ByteSize & (PELIB_PAGE_SIZE - 1)) != 0); } + static std::uint64_t signExtend32To64(std::uint32_t value32) + { + return (std::uint64_t)(std::int64_t)(std::int32_t)value32; + } + static uint8_t ImageProtectionArray[16]; std::vector sections; // Vector of section headers @@ -357,6 +376,7 @@ class ImageLoader std::uint32_t ntSignature; std::uint32_t loaderMode; std::uint32_t maxSectionCount; + std::uint32_t realNumberOfRvaAndSizes; // Real present number of RVA and sizes std::uint32_t checkSumFileOffset; // File offset of the image checksum std::uint32_t securityDirFileOffset; // File offset of security directory bool ntHeadersSizeCheck; // If true, the loader requires minimum size of NT headers diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index 926ed0d35..9d5391e9f 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef _MSC_VER // Reduces number of warnings under MS Visual Studio from ~100000 to zero #pragma warning(disable:4267) // C4267: 'initializing': conversion from 'size_t' to '_Ty2', possible loss of data diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index 90b30711a..7519d9fdd 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -3644,7 +3644,9 @@ void PeFormat::scanForSectionAnomalies(unsigned anamaliesLimit) { std::size_t nSecs = getDeclaredNumberOfSections(); + unsigned long long imageBase; unsigned long long epAddr; + if (getEpAddress(epAddr)) { auto *epSec = dynamic_cast(getEpSection()); @@ -3670,9 +3672,7 @@ void PeFormat::scanForSectionAnomalies(unsigned anamaliesLimit) else { // scan EP outside mapped sections - anomalies.emplace_back( - "EpOutsideSections", "Entry point is outside of mapped sections" - ); + anomalies.emplace_back("EpOutsideSections", "Entry point is outside of mapped sections"); } } diff --git a/src/fileformat/types/sec_seg/sec_seg.cpp b/src/fileformat/types/sec_seg/sec_seg.cpp index b6b4b271e..4d44bfb24 100644 --- a/src/fileformat/types/sec_seg/sec_seg.cpp +++ b/src/fileformat/types/sec_seg/sec_seg.cpp @@ -261,6 +261,15 @@ unsigned long long SecSeg::getOffset() const return offset; } +/** +* Get unfixed, original-from-section-header offset +* @return Offset +*/ +unsigned long long SecSeg::getUnfixedOffset() const +{ + return unfixedOffset; +} + /** * Get end offset * @return End offset of section or segment in file @@ -468,7 +477,16 @@ void SecSeg::setIndex(unsigned long long sIndex) */ void SecSeg::setOffset(unsigned long long sOffset) { - offset = sOffset; + unfixedOffset = offset = sOffset; +} + +/** +* Set real (unfixed) offset to the raw section data +* @param sRealOffset Offset +*/ +void SecSeg::setUnfixedOffset(unsigned long long sUnfixedOffset) +{ + unfixedOffset = sUnfixedOffset; } /** diff --git a/src/fileinfo/file_wrapper/pe_wrapper.cpp b/src/fileinfo/file_wrapper/pe_wrapper.cpp new file mode 100644 index 000000000..c6fb4348c --- /dev/null +++ b/src/fileinfo/file_wrapper/pe_wrapper.cpp @@ -0,0 +1,234 @@ +/** + * @file src/fileinfo/file_wrapper/pe/pe_wrapper.cpp + * @brief Methods of PeWrapper class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/utils/array.h" +#include "retdec/utils/conversion.h" +#include "retdec/pelib/pefile.h" +#include "fileinfo/file_wrapper/pe_wrapper.h" + +using namespace retdec::utils; +using namespace PeLib; +using namespace retdec::fileformat; + +namespace retdec { +namespace fileinfo { + +namespace +{ + +const std::string directories[] = {"Export table", "Import table", "Resource table", "Exception table", + "Certificate Table", "Relocation table", "Debug directory", + "Architecture directory", "Global pointer directory", "TLS Table", + "Load configuration table", "Bound import table", + "Import address table", "Delay import descriptor", + "CLR runtime header", "Reserved"}; + +/** + * Get type of data directory + * @param dirIndex Directory index + * @return Directory type of empty string if index of directory is not valid + */ +std::string getDirectoryType(unsigned long long dirIndex) +{ + return (dirIndex < arraySize(directories) ? directories[dirIndex] : ""); +} + +/** + * Get link to symbol section + * @param link Link to section in number representation + * @return Link to section in string representation + */ +std::string getSymbolLinkToSection(std::uint16_t link) +{ + if(!link) + { + return "UNDEFINED"; + } + else if(link == std::numeric_limits::max()) + { + return "ABSOLUTE"; + } + else if(link == std::numeric_limits::max() - 1) + { + return "DEBUG"; + } + + return std::to_string(link - 1); +} + +/** + * Get type of symbol + * @param type Type of symbol in number representation + * @return Type of symbol in string representation + */ +std::string getSymbolType(std::uint8_t type) +{ + if(type < 0x10) + { + return "SIMPLE"; + } + else if(type < 0x20) + { + return "POINTER"; + } + else if(type < 0x30) + { + return "FUNCTION"; + } + else if(type < 0x40) + { + return "ARRAY"; + } + + return ""; +} + +} // anonymous namespace + +/** + * Constructor + * @param pathToFile Path to PE binary file + * @param dllListFile Path to text file containing list of OS DLLs + * @param loadFlags Load flags + */ +PeWrapper::PeWrapper( + const std::string & pathToFile, + const std::string & dllListFile, + retdec::fileformat::LoadFlags loadFlags) + : PeFormat(pathToFile, dllListFile, loadFlags) +{} + +/** + * Destructor + */ +PeWrapper::~PeWrapper() +{} + +/** + * Get type of binary file + * @return Type of binary file (e.g. DLL) + */ +std::string PeWrapper::getTypeOfFile() const +{ + return isDll() ? "DLL" : "Executable file"; +} + +/** + * Get type of PE file (e.g. "PE32" or "PE32+") + * @return Type of PE file + */ +std::string PeWrapper::getPeType() const +{ + switch(file->imageLoader().getMagic()) + { + case PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC: + return "PE32"; + case PELIB_IMAGE_ROM_OPTIONAL_HDR_MAGIC: + return "ROM image"; + case PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC: + return "PE32+"; + default: + return ""; + } +} + +/** + * Get information about data directory + * @param dirIndex Index of directory (indexed from 0) + * @param directory Instance of class for save information about data directory + * @return @c true if section index is valid and section is detected, @c false otherwise + */ +bool PeWrapper::getDataDirectory(unsigned long long dirIndex, DataDirectory &directory) const +{ + ImageLoader & imageLoader = file->imageLoader(); + std::uint64_t virtualAddress; + + if(dirIndex >= imageLoader.getOptionalHeader().NumberOfRvaAndSizes) + return false; + + if((virtualAddress = imageLoader.getDataDirRva(dirIndex)) != 0) + virtualAddress += imageLoader.getImageBase(); + directory.setAddress(virtualAddress); + directory.setSize(imageLoader.getDataDirSize(dirIndex)); + directory.setType(getDirectoryType(dirIndex)); + return true; +} + +/** + * Get information about file section + * @param secIndex Index of section (indexed from 0) + * @param section Instance of class for save information about file section + * @return @c true if section index is valid and section is detected, @c false otherwise + */ +bool PeWrapper::getFileSection(unsigned long long secIndex, FileSection §ion) const +{ + const PELIB_SECTION_HEADER * pSectionHeader; + ImageLoader & imageLoader = file->imageLoader(); + std::string sectionName; + + // Retrieve the section header. If the function returns nullptr, then there is no such section + if((pSectionHeader = imageLoader.getSectionHeader(secIndex)) == nullptr) + return false; + + section.setIndex(secIndex); + section.setName(pSectionHeader->getName()); + section.setStartAddress(imageLoader.getVirtualAddressMasked(pSectionHeader->VirtualAddress)); + section.setSizeInMemory(pSectionHeader->VirtualSize); + section.setOffset(imageLoader.getRealPointerToRawData(secIndex)); + section.setSizeInFile(pSectionHeader->SizeOfRawData); + section.setRelocationsOffset(pSectionHeader->PointerToRelocations); + section.setNumberOfRelocations(pSectionHeader->NumberOfRelocations); + section.setLineNumbersOffset(pSectionHeader->PointerToLinenumbers); + section.setNumberOfLineNumbers(pSectionHeader->NumberOfLinenumbers); + section.setFlagsSize(0x20); + section.setFlags(pSectionHeader->Characteristics); + section.clearFlagsDescriptors(); + + section.setCrc32(""); + section.setMd5(""); + section.setSha256(""); + unsigned long long index; + + const auto *auxSec = getSection(secIndex); + if(auxSec) + { + double entropy; + if(auxSec->getEntropy(entropy)) + { + section.setEntropy(entropy); + } + section.setCrc32(auxSec->getCrc32()); + section.setMd5(auxSec->getMd5()); + section.setSha256(auxSec->getSha256()); + } + + return true; +} + +/** + * Get one symbol from COFF symbol table + * @param index Index of symbol + * @param symbol Instance of class for save information about symbol + * @return @c true if symbol index is valid and symbol is detected, @c false otherwise + */ +bool PeWrapper::getCoffSymbol(unsigned long long index, Symbol &symbol) const +{ + const CoffSymbolTable &symTab = file->coffSymTab(); + if(index >= symTab.getNumberOfStoredSymbols()) + { + return false; + } + + symbol.setIndex(symTab.getSymbolIndex(index)); + symbol.setName(symTab.getSymbolName(index)); + symbol.setValue(symTab.getSymbolValue(index)); + symbol.setLinkToSection(getSymbolLinkToSection(symTab.getSymbolSectionNumber(index))); + symbol.setType(getSymbolType(symTab.getSymbolTypeComplex(index))); + return true; +} + +} // namespace fileinfo +} // namespace retdec diff --git a/src/fileinfo/file_wrapper/pe_wrapper.h b/src/fileinfo/file_wrapper/pe_wrapper.h new file mode 100644 index 000000000..0815800aa --- /dev/null +++ b/src/fileinfo/file_wrapper/pe_wrapper.h @@ -0,0 +1,48 @@ +/** + * @file src/fileinfo/file_wrapper/pe/pe_wrapper.h + * @brief Definition of PeWrapper class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_H +#define FILEINFO_FILE_WRAPPER_PE_PE_WRAPPER_H + +#include "retdec/fileformat/file_format/pe/pe_format.h" +#include "fileinfo/file_information/file_information_types/symbol_table/symbol.h" +#include "fileinfo/file_information/file_information_types/data_directory.h" +#include "fileinfo/file_information/file_information_types/file_section.h" + +namespace retdec { +namespace fileinfo { + +/** + * Wrapper for parsing PE files + */ + +class PeLib::PeFileT; + +class PeWrapper : public retdec::fileformat::PeFormat +{ + public: + PeWrapper(const std::string & pathToFile, const std::string & dllListFile, retdec::fileformat::LoadFlags loadFlags); + virtual ~PeWrapper() override; + + std::uint32_t getBits() + { + return file->getBits(); + } + + /// @name Detection methods + /// { + std::string getTypeOfFile() const; + std::string getPeType() const; + bool getDataDirectory(unsigned long long dirIndex, DataDirectory &directory) const; + bool getFileSection(unsigned long long secIndex, FileSection §ion) const; + bool getCoffSymbol(unsigned long long index, Symbol &symbol) const; + /// } +}; + +} // namespace fileinfo +} // namespace retdec + +#endif diff --git a/src/pelib/CoffSymbolTable.cpp b/src/pelib/CoffSymbolTable.cpp index a3095ba1f..535376c64 100644 --- a/src/pelib/CoffSymbolTable.cpp +++ b/src/pelib/CoffSymbolTable.cpp @@ -114,7 +114,7 @@ namespace PeLib if (stringTableSize > ulFileSize || uiOffset + stringTableSize > ulFileSize) { - stringTableSize = (ulFileSize - uiOffset); + stringTableSize = (ulFileSize - uiOffset) + 4; } // read string table diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index ce93c5267..45eff8b47 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -67,6 +67,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) memset(&optionalHeader, 0, sizeof(PELIB_IMAGE_OPTIONAL_HEADER)); checkSumFileOffset = 0; securityDirFileOffset = 0; + realNumberOfRvaAndSizes = 0; ntSignature = 0; ldrError = LDR_ERROR_NONE; @@ -395,7 +396,7 @@ uint32_t PeLib::ImageLoader::getImageBitability() const uint32_t PeLib::ImageLoader::getFileOffsetFromRva(uint32_t rva) const { // If we have sections loaded, then we calculate the file offset from section headers - if(sections.size()) + if(sections.size() && optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE) { // Check whether the rva goes into any section for(auto & sectHdr : sections) @@ -403,14 +404,15 @@ uint32_t PeLib::ImageLoader::getFileOffsetFromRva(uint32_t rva) const // Only if the pointer to raw data is not zero if(sectHdr.PointerToRawData != 0 && sectHdr.SizeOfRawData != 0) { - uint32_t sectionRvaStart = sectHdr.VirtualAddress; + uint32_t realPointerToRawData = sectHdr.PointerToRawData & ~(PELIB_SECTOR_SIZE - 1); + uint32_t sectionRvaStart = AlignToSize(sectHdr.VirtualAddress, optionalHeader.SectionAlignment); uint32_t virtualSize = (sectHdr.VirtualSize != 0) ? sectHdr.VirtualSize : sectHdr.SizeOfRawData; if(sectionRvaStart <= rva && rva < (sectionRvaStart + virtualSize)) { // Make sure we round the pointer to raw data down to PELIB_SECTOR_SIZE. // In case when PointerToRawData is less than 0x200, it maps to the header! - return (sectHdr.PointerToRawData & ~(PELIB_SECTOR_SIZE - 1)) + (rva - sectionRvaStart); + return realPointerToRawData + (rva - sectionRvaStart); } } } @@ -439,6 +441,8 @@ std::uint32_t PeLib::ImageLoader::getRealPointerToRawData(std::size_t sectionInd { if(sectionIndex >= sections.size()) return UINT32_MAX; + if(optionalHeader.SectionAlignment < PELIB_PAGE_SIZE) + return sections[sectionIndex].PointerToRawData; return sections[sectionIndex].PointerToRawData & ~(PELIB_SECTOR_SIZE - 1); } @@ -1064,9 +1068,9 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); // 7baebc6d9f2185fafa760c875ab1386f385a0b3fecf2e6ae339abb4d9ac58f3e - if (fileHeader.Machine == 0 && fileHeader.SizeOfOptionalHeader == 0) + if(fileHeader.Machine == 0 && fileHeader.SizeOfOptionalHeader == 0) setLoaderError(LDR_ERROR_FILE_HEADER_INVALID); - if (!(fileHeader.Characteristics & PELIB_IMAGE_FILE_EXECUTABLE_IMAGE)) + if(!(fileHeader.Characteristics & PELIB_IMAGE_FILE_EXECUTABLE_IMAGE)) setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE); filePtr += sizeof(PELIB_IMAGE_FILE_HEADER); @@ -1082,74 +1086,74 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) // Capture optional header. Note that we need to parse it // according to IMAGE_OPTIONAL_HEADER::Magic -if((filePtr + sizeof(uint16_t)) < fileEnd) - optionalHeaderMagic = *(uint16_t *)(filePtr); -if(optionalHeaderMagic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) -captureOptionalHeader64(fileBegin, filePtr, fileEnd); -else -captureOptionalHeader32(fileBegin, filePtr, fileEnd); - -// Performed by Windows 10 (nt!MiVerifyImageHeader): -// Sample: 04d3577d1b6309a0032d4c4c1252c55416a09bb617aebafe512fffbdd4f08f18 -if(appContainerCheck && checkForBadAppContainer()) -setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE); - -// SizeOfHeaders must be nonzero if not a single subsection -if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE && optionalHeader.SizeOfHeaders == 0) -setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_ZERO); - -// File alignment must not be 0 -if(optionalHeader.FileAlignment == 0) -setLoaderError(LDR_ERROR_FILE_ALIGNMENT_ZERO); - -// File alignment must be a power of 2 -if(optionalHeader.FileAlignment & (optionalHeader.FileAlignment-1)) -setLoaderError(LDR_ERROR_FILE_ALIGNMENT_NOT_POW2); - -// Section alignment must not be 0 -if(optionalHeader.SectionAlignment == 0) -setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_ZERO); - -// Section alignment must be a power of 2 -if(optionalHeader.SectionAlignment & (optionalHeader.SectionAlignment - 1)) -setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_NOT_POW2); - -if(optionalHeader.SectionAlignment < optionalHeader.FileAlignment) - setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_TOO_SMALL); - -// Check for images with "super-section": FileAlignment must be equal to SectionAlignment -if((optionalHeader.FileAlignment & 511) && (optionalHeader.SectionAlignment != optionalHeader.FileAlignment)) -setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_INVALID); - -// Check for largest image -if(optionalHeader.SizeOfImage > PELIB_MM_SIZE_OF_LARGEST_IMAGE) -setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_TOO_BIG); - -// Check for 32-bit images -if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC && checkForValid32BitMachine() == false) -setLoaderError(LDR_ERROR_INVALID_MACHINE32); - -// Check for 64-bit images -if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC && checkForValid64BitMachine() == false) -setLoaderError(LDR_ERROR_INVALID_MACHINE64); - -// Check the size of image -if(optionalHeader.SizeOfHeaders > optionalHeader.SizeOfImage) -setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); - -// On 64-bit Windows, size of optional header must be properly aligned to 8-byte boundary -if(is64BitWindows && (fileHeader.SizeOfOptionalHeader & 0x07)) -setLoaderError(LDR_ERROR_SIZE_OF_OPTHDR_NOT_ALIGNED); - -// Set the size of image -if(BytesToPages(optionalHeader.SizeOfImage) == 0) -setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_ZERO); - -// Check for proper alignment of the image base -if(optionalHeader.ImageBase & (PELIB_SIZE_64KB - 1)) -setLoaderError(LDR_ERROR_IMAGE_BASE_NOT_ALIGNED); - -return ERROR_NONE; + if((filePtr + sizeof(uint16_t)) < fileEnd) + optionalHeaderMagic = *(uint16_t *)(filePtr); + if(optionalHeaderMagic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) + captureOptionalHeader64(fileBegin, filePtr, fileEnd); + else + captureOptionalHeader32(fileBegin, filePtr, fileEnd); + + // Performed by Windows 10 (nt!MiVerifyImageHeader): + // Sample: 04d3577d1b6309a0032d4c4c1252c55416a09bb617aebafe512fffbdd4f08f18 + if(appContainerCheck && checkForBadAppContainer()) + setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE); + + // SizeOfHeaders must be nonzero if not a single subsection + if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE && optionalHeader.SizeOfHeaders == 0) + setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_ZERO); + + // File alignment must not be 0 + if(optionalHeader.FileAlignment == 0) + setLoaderError(LDR_ERROR_FILE_ALIGNMENT_ZERO); + + // File alignment must be a power of 2 + if(optionalHeader.FileAlignment & (optionalHeader.FileAlignment-1)) + setLoaderError(LDR_ERROR_FILE_ALIGNMENT_NOT_POW2); + + // Section alignment must not be 0 + if(optionalHeader.SectionAlignment == 0) + setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_ZERO); + + // Section alignment must be a power of 2 + if(optionalHeader.SectionAlignment & (optionalHeader.SectionAlignment - 1)) + setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_NOT_POW2); + + if(optionalHeader.SectionAlignment < optionalHeader.FileAlignment) + setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_TOO_SMALL); + + // Check for images with "super-section": FileAlignment must be equal to SectionAlignment + if((optionalHeader.FileAlignment & 511) && (optionalHeader.SectionAlignment != optionalHeader.FileAlignment)) + setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_INVALID); + + // Check for largest image + if(optionalHeader.SizeOfImage > PELIB_MM_SIZE_OF_LARGEST_IMAGE) + setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_TOO_BIG); + + // Check for 32-bit images + if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC && checkForValid32BitMachine() == false) + setLoaderError(LDR_ERROR_INVALID_MACHINE32); + + // Check for 64-bit images + if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC && checkForValid64BitMachine() == false) + setLoaderError(LDR_ERROR_INVALID_MACHINE64); + + // Check the size of image + if(optionalHeader.SizeOfHeaders > optionalHeader.SizeOfImage) + setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); + + // On 64-bit Windows, size of optional header must be properly aligned to 8-byte boundary + if(is64BitWindows && (fileHeader.SizeOfOptionalHeader & 0x07)) + setLoaderError(LDR_ERROR_SIZE_OF_OPTHDR_NOT_ALIGNED); + + // Set the size of image + if(BytesToPages(optionalHeader.SizeOfImage) == 0) + setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_ZERO); + + // Check for proper alignment of the image base + if(optionalHeader.ImageBase & (PELIB_SIZE_64KB - 1)) + setLoaderError(LDR_ERROR_IMAGE_BASE_NOT_ALIGNED); + + return ERROR_NONE; } int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std::string & sectionName, const std::uint8_t * Name) @@ -1486,6 +1490,7 @@ int PeLib::ImageLoader::loadImageAsIs(std::vector & fileData) int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * fileBegin, uint8_t * filePtr, uint8_t * fileEnd) { PELIB_IMAGE_OPTIONAL_HEADER64 optionalHeader64{}; + uint8_t * dataDirectoryPtr; uint32_t sizeOfOptionalHeader = sizeof(PELIB_IMAGE_OPTIONAL_HEADER64); uint32_t numberOfRvaAndSizes; @@ -1535,6 +1540,15 @@ int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * fileBegin, uint8_t * f numberOfRvaAndSizes = PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES; memcpy(optionalHeader.DataDirectory, optionalHeader64.DataDirectory, sizeof(PELIB_IMAGE_DATA_DIRECTORY) * numberOfRvaAndSizes); + // Cut the real number of data directory entries by the file size + dataDirectoryPtr = filePtr + offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory); + if(dataDirectoryPtr < fileEnd) + { + if((dataDirectoryPtr + numberOfRvaAndSizes * sizeof(PELIB_IMAGE_DATA_DIRECTORY)) > fileEnd) + numberOfRvaAndSizes = (fileEnd - dataDirectoryPtr + sizeof(PELIB_IMAGE_DATA_DIRECTORY) - 1) / sizeof(PELIB_IMAGE_DATA_DIRECTORY); + } + realNumberOfRvaAndSizes = numberOfRvaAndSizes; + // Remember the offset of the checksum field checkSumFileOffset = (filePtr - fileBegin) + offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, CheckSum); securityDirFileOffset = (filePtr - fileBegin) + offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) + (sizeof(PELIB_IMAGE_DATA_DIRECTORY) * PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY); @@ -1544,6 +1558,7 @@ int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * fileBegin, uint8_t * f int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * fileBegin, uint8_t * filePtr, uint8_t * fileEnd) { PELIB_IMAGE_OPTIONAL_HEADER32 optionalHeader32{}; + uint8_t * dataDirectoryPtr; uint32_t sizeOfOptionalHeader = sizeof(PELIB_IMAGE_OPTIONAL_HEADER32); uint32_t numberOfRvaAndSizes; @@ -1594,6 +1609,15 @@ int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * fileBegin, uint8_t * f numberOfRvaAndSizes = PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES; memcpy(optionalHeader.DataDirectory, optionalHeader32.DataDirectory, sizeof(PELIB_IMAGE_DATA_DIRECTORY) * numberOfRvaAndSizes); + // Cut the real number of data directory entries by the file size + dataDirectoryPtr = filePtr + offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + if(dataDirectoryPtr < fileEnd) + { + if((dataDirectoryPtr + numberOfRvaAndSizes * sizeof(PELIB_IMAGE_DATA_DIRECTORY)) > fileEnd) + numberOfRvaAndSizes = (fileEnd - dataDirectoryPtr + sizeof(PELIB_IMAGE_DATA_DIRECTORY) - 1) / sizeof(PELIB_IMAGE_DATA_DIRECTORY); + } + realNumberOfRvaAndSizes = numberOfRvaAndSizes; + // Remember the offset of the checksum field checkSumFileOffset = (filePtr - fileBegin) + offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, CheckSum); securityDirFileOffset = (filePtr - fileBegin) + offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory) + (sizeof(PELIB_IMAGE_DATA_DIRECTORY) * PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY); From cbc761e99521200d9aa8c9578a15f20f5ec7e89c Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 1 Jul 2020 09:51:19 +0200 Subject: [PATCH 13/34] ImageLoader: Complete --- include/retdec/pelib/ImageLoader.h | 9 +++++- src/pelib/ImageLoader.cpp | 52 +++++++++++++++++++++--------- src/pelib/PeLibAux.cpp | 12 +++---- 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 51a3a5e58..04928a320 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -134,7 +134,7 @@ class ImageLoader std::uint32_t readString(std::string & str, std::uint32_t rva, std::uint32_t maxLength = 65535); std::uint32_t readStringRc(std::string & str, std::uint32_t rva); - std::uint32_t readStringRaw(std::vector & fileData, std::string & str, std::size_t offset, std::size_t maxLength = 65535); + std::uint32_t readStringRaw(std::vector & fileData, std::string & str, std::size_t offset, std::size_t maxLength = 65535, bool mustBePrintable = false, bool mustNotBeTooLong = false); std::uint32_t stringLength(std::uint32_t rva, std::uint32_t maxLength = 65535) const; std::uint32_t readPointer(std::uint32_t rva, std::uint64_t & pointerValue); @@ -364,6 +364,13 @@ class ImageLoader return (std::uint64_t)(std::int64_t)(std::int32_t)value32; } + // Anti-assert feature. Debug version of isprint in MS Visual C++ asserts + // when the character is not EOF or is >= 255 + bool isPrintableChar(int ch) + { + return ((EOF <= ch) && (ch <= 255)) ? isprint(ch) : false; + } + static uint8_t ImageProtectionArray[16]; std::vector sections; // Vector of section headers diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 45eff8b47..b23d7760d 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -329,7 +329,7 @@ uint32_t PeLib::ImageLoader::readStringRc(std::string & str, uint32_t rva) return charsRead; } -uint32_t PeLib::ImageLoader::readStringRaw(std::vector & fileData, std::string & str, size_t offset, size_t maxLength) +uint32_t PeLib::ImageLoader::readStringRaw(std::vector & fileData, std::string & str, size_t offset, size_t maxLength, bool mustBePrintable, bool mustNotBeTooLong) { size_t length = 0; @@ -347,12 +347,30 @@ uint32_t PeLib::ImageLoader::readStringRaw(std::vector & fileData, std: // retdec-regression-tests\tools\fileinfo\bugs\issue-451-strange-section-names\4383fe67fec6ea6e44d2c7d075b9693610817edc68e8b2a76b2246b53b9186a1-unpacked stringEnd = (uint8_t *)memchr(stringBegin, 0, maxLength); if(stringEnd == nullptr) + { + // No zero terminator means that the string is limited by max length + if(mustNotBeTooLong) + return 0; stringEnd = stringBegin + maxLength; - length = stringEnd - stringBegin; + } // Copy the string + length = stringEnd - stringBegin; str.resize(length); memcpy(const_cast(str.data()), stringBegin, length); + + // Ignore strings that contain non-printable chars + if(mustBePrintable) + { + for(auto oneChar : str) + { + if(isPrintableChar(oneChar) == false) + { + str.clear(); + return 0; + } + } + } } return length; @@ -387,16 +405,14 @@ uint32_t PeLib::ImageLoader::getImageBitability() const if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) return 64; - if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) - return 32; - - return 0; + // Default: 32-bit image + return 32; } uint32_t PeLib::ImageLoader::getFileOffsetFromRva(uint32_t rva) const { // If we have sections loaded, then we calculate the file offset from section headers - if(sections.size() && optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE) + if(sections.size()) { // Check whether the rva goes into any section for(auto & sectHdr : sections) @@ -404,10 +420,17 @@ uint32_t PeLib::ImageLoader::getFileOffsetFromRva(uint32_t rva) const // Only if the pointer to raw data is not zero if(sectHdr.PointerToRawData != 0 && sectHdr.SizeOfRawData != 0) { - uint32_t realPointerToRawData = sectHdr.PointerToRawData & ~(PELIB_SECTOR_SIZE - 1); - uint32_t sectionRvaStart = AlignToSize(sectHdr.VirtualAddress, optionalHeader.SectionAlignment); + uint32_t realPointerToRawData = sectHdr.PointerToRawData; + uint32_t sectionRvaStart = sectHdr.VirtualAddress; uint32_t virtualSize = (sectHdr.VirtualSize != 0) ? sectHdr.VirtualSize : sectHdr.SizeOfRawData; + // For multi-section images, real pointer to raw data is aligned down to sector size + if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE) + realPointerToRawData = realPointerToRawData & ~(PELIB_SECTOR_SIZE - 1); + if(optionalHeader.SectionAlignment != 0) + sectionRvaStart = AlignToSize(sectHdr.VirtualAddress, optionalHeader.SectionAlignment); + + // Is the RVA inside that section? if(sectionRvaStart <= rva && rva < (sectionRvaStart + virtualSize)) { // Make sure we round the pointer to raw data down to PELIB_SECTOR_SIZE. @@ -1162,8 +1185,6 @@ int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std: // If the section name is in format of "/12345", then the section name is actually in the symbol table // Sample: 2e9c671b8a0411f2b397544b368c44d7f095eb395779de0ad1ac946914dfa34c - // Since retdec's regression tests doesn't like these, we skip this feature - /* if(fileHeader.PointerToSymbolTable != 0 && Name[0] == '/') { // Get the offset of the string table @@ -1175,10 +1196,9 @@ int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std: stringTableIndex = (stringTableIndex * 10) + (Name[i] - '0'); // Get the section name - readStringRaw(fileData, sectionName, stringTableOffset + stringTableIndex); - return ERROR_NONE; + if(readStringRaw(fileData, sectionName, stringTableOffset + stringTableIndex, PELIB_IMAGE_SIZEOF_MAX_NAME, true, true) != 0) + return ERROR_NONE; } - */ // The section name is directly in the section header. // It has fixed length and must not be necessarily terminated with zero. @@ -1568,9 +1588,9 @@ int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * fileBegin, uint8_t * f sizeOfOptionalHeader = (uint32_t)(fileEnd - filePtr); memcpy(&optionalHeader32, filePtr, sizeOfOptionalHeader); - // Verify whether it's 32-bit optional header + // Note: Do not fail if there's no magic value for 32-bit optional header if(optionalHeader32.Magic != PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) - return setLoaderError(LDR_ERROR_NO_OPTHDR_MAGIC); + setLoaderError(LDR_ERROR_NO_OPTHDR_MAGIC); // Convert 32-bit optional header to common optional header optionalHeader.Magic = optionalHeader32.Magic; diff --git a/src/pelib/PeLibAux.cpp b/src/pelib/PeLibAux.cpp index 8fca2217b..4418c64be 100644 --- a/src/pelib/PeLibAux.cpp +++ b/src/pelib/PeLibAux.cpp @@ -64,12 +64,12 @@ namespace PeLib {"LDR_ERROR_FILE_IS_CUT_LOADABLE", "The PE file is cut, but loadable", true}, // Import directory detected errors - {"LDR_ERROR_IMPDIR_OUT_OF_FILE", "Offset of the import directory is out of the file" }, - {"LDR_ERROR_IMPDIR_CUT", "Import directory is cut" }, - {"LDR_ERROR_IMPDIR_COUNT_EXCEEDED", "Number of import descriptors exceeds maximum" }, - {"LDR_ERROR_IMPDIR_NAME_RVA_INVALID", "RVA of the import name is invalid" }, - {"LDR_ERROR_IMPDIR_THUNK_RVA_INVALID", "RVA of the import thunk is invalid" }, - {"LDR_ERROR_IMPDIR_IMPORT_COUNT_EXCEEDED", "Number of imported functions exceeds maximum" }, + {"LDR_ERROR_IMPDIR_OUT_OF_FILE", "Offset of the import directory is out of the file", true }, + {"LDR_ERROR_IMPDIR_CUT", "Import directory is cut", true }, + {"LDR_ERROR_IMPDIR_COUNT_EXCEEDED", "Number of import descriptors exceeds maximum", true }, + {"LDR_ERROR_IMPDIR_NAME_RVA_INVALID", "RVA of the import name is invalid", true }, + {"LDR_ERROR_IMPDIR_THUNK_RVA_INVALID", "RVA of the import thunk is invalid", true }, + {"LDR_ERROR_IMPDIR_IMPORT_COUNT_EXCEEDED", "Number of imported functions exceeds maximum", true }, // Resource directory detected errors {"LDR_ERROR_RSRC_OVER_END_OF_IMAGE", "Array of resource directory entries goes beyond end of the image", true }, From f5c6c352c44c424df714e3de550730eb287df4c9 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 1 Jul 2020 15:12:37 +0200 Subject: [PATCH 14/34] Linux build: Removed _cdecl --- include/retdec/pelib/ImageLoader.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 04928a320..ddd4a2a60 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -45,8 +45,8 @@ enum PELIB_COMPARE_RESULT : std::uint32_t ImagesDifferentPageValue, // There is a different value at a certain offset }; -typedef bool (_cdecl * PFN_VERIFY_ADDRESS)(void * ptr, size_t length); -typedef bool (_cdecl * PFN_COMPARE_CALLBACK)(size_t BytesCompared, size_t BytesTotal); +typedef bool (*PFN_VERIFY_ADDRESS)(void * ptr, size_t length); +typedef bool (*PFN_COMPARE_CALLBACK)(size_t BytesCompared, size_t BytesTotal); struct PELIB_IMAGE_COMPARE { From b1989bd0893d0f2a6280f6ae76056feb820d3b5a Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 1 Jul 2020 21:04:52 +0200 Subject: [PATCH 15/34] Linux Build: reference solved --- src/fileformat/file_format/pe/pe_format.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index 7519d9fdd..3ea4b3f3a 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -3060,12 +3060,28 @@ bool PeFormat::getImageBaseAddress(unsigned long long &imageBase) const bool PeFormat::getEpAddress(unsigned long long &result) const { - return formatParser->getEpAddress(result); + std::uint64_t tempResult = 0; + + if(formatParser->getEpAddress(tempResult)) + { + result = tempResult; + return true; + } + + return false; } bool PeFormat::getEpOffset(unsigned long long &epOffset) const { - return formatParser->getEpOffset(epOffset); + std::uint64_t tempResult = 0; + + if(formatParser->getEpOffset(tempResult)) + { + epOffset = tempResult; + return true; + } + + return false; } Architecture PeFormat::getTargetArchitecture() const From 1bd2fa6186d70fb09967139f06cc7be02eded8cc Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Thu, 2 Jul 2020 06:31:00 +0200 Subject: [PATCH 16/34] Linux Build --- .../file_format/pe/pe_format_parser.h | 1 - .../retdec/fileformat/types/sec_seg/sec_seg.h | 3 --- include/retdec/pelib/BoundImportDirectory.h | 1 + include/retdec/pelib/CoffSymbolTable.h | 2 +- include/retdec/pelib/PeLibAux.h | 5 ----- include/retdec/pelib/PeLibInc.h | 2 ++ src/fileformat/types/sec_seg/sec_seg.cpp | 20 +------------------ src/fileinfo/file_wrapper/pe_wrapper.cpp | 2 +- src/pelib/CoffSymbolTable.cpp | 2 -- 9 files changed, 6 insertions(+), 32 deletions(-) diff --git a/include/retdec/fileformat/file_format/pe/pe_format_parser.h b/include/retdec/fileformat/file_format/pe/pe_format_parser.h index cecccfe05..27c1f5183 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format_parser.h +++ b/include/retdec/fileformat/file_format/pe/pe_format_parser.h @@ -265,7 +265,6 @@ class PeFormatParser section.setType(sectionType); section.setIndex(secIndex); section.setOffset(imageLoader.getRealPointerToRawData(secIndex)); - section.setUnfixedOffset(pSectionHeader->PointerToRawData); section.setSizeInFile(pSectionHeader->SizeOfRawData); section.setSizeInMemory(pSectionHeader->VirtualSize); section.setAddress(pSectionHeader->VirtualAddress ? imageLoader.getImageBase() + pSectionHeader->VirtualAddress : 0); diff --git a/include/retdec/fileformat/types/sec_seg/sec_seg.h b/include/retdec/fileformat/types/sec_seg/sec_seg.h index 78f31daa3..4ae650d67 100644 --- a/include/retdec/fileformat/types/sec_seg/sec_seg.h +++ b/include/retdec/fileformat/types/sec_seg/sec_seg.h @@ -43,7 +43,6 @@ class SecSeg Type type = Type::UNDEFINED_SEC_SEG; ///< type unsigned long long index = 0; ///< index unsigned long long offset = 0; ///< start offset in file - unsigned long long unfixedOffset = 0; ///< start offset in file (from section header, unfixed) unsigned long long fileSize = 0; ///< size in file unsigned long long address = 0; ///< start address in memory unsigned long long memorySize = 0; ///< size in memory @@ -91,7 +90,6 @@ class SecSeg SecSeg::Type getType() const; unsigned long long getIndex() const; unsigned long long getOffset() const; - unsigned long long getUnfixedOffset() const; unsigned long long getEndOffset() const; unsigned long long getSizeInFile() const; unsigned long long getLoadedSize() const; @@ -136,7 +134,6 @@ class SecSeg void setType(SecSeg::Type sType); void setIndex(unsigned long long sIndex); void setOffset(unsigned long long sOffset); - void setUnfixedOffset(unsigned long long sUnfixedOffset); void setSizeInFile(unsigned long long sFileSize); void setAddress(unsigned long long sAddress); void setSizeInMemory(unsigned long long sMemorySize); diff --git a/include/retdec/pelib/BoundImportDirectory.h b/include/retdec/pelib/BoundImportDirectory.h index 74e898168..e142f462b 100644 --- a/include/retdec/pelib/BoundImportDirectory.h +++ b/include/retdec/pelib/BoundImportDirectory.h @@ -13,6 +13,7 @@ #ifndef BOUNDIMPORTDIRECTORY_H #define BOUNDIMPORTDIRECTORY_H +#include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/PeLibAux.h" #include "retdec/pelib/ImageLoader.h" diff --git a/include/retdec/pelib/CoffSymbolTable.h b/include/retdec/pelib/CoffSymbolTable.h index da30f0e58..dcc882bcb 100644 --- a/include/retdec/pelib/CoffSymbolTable.h +++ b/include/retdec/pelib/CoffSymbolTable.h @@ -7,7 +7,7 @@ #ifndef COFFSYMBOLTABLE_H #define COFFSYMBOLTABLE_H -#include +#include "retdec/pelib/PeLibInc.h" namespace PeLib { diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index 9d5391e9f..d3d6a23b6 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -14,8 +14,6 @@ #define PELIBAUX_H #include -#include -#include #include #ifdef _MSC_VER // Reduces number of warnings under MS Visual Studio from ~100000 to zero @@ -23,9 +21,6 @@ #pragma warning(disable:4244) // C4244: 'argument': conversion from 'uint64_t' to 'unsigned int', possible loss of data #endif -#include "retdec/pelib/OutputBuffer.h" -#include "retdec/pelib/InputBuffer.h" - //get rid of duplicate windows.h definitions #ifdef ERROR_NONE #undef ERROR_NONE diff --git a/include/retdec/pelib/PeLibInc.h b/include/retdec/pelib/PeLibInc.h index 4d6cfe14d..8213b3fff 100644 --- a/include/retdec/pelib/PeLibInc.h +++ b/include/retdec/pelib/PeLibInc.h @@ -21,6 +21,8 @@ #include #include +#include "retdec/pelib/InputBuffer.h" +#include "retdec/pelib/OutputBuffer.h" #include "retdec/pelib/PeLibAux.h" #endif diff --git a/src/fileformat/types/sec_seg/sec_seg.cpp b/src/fileformat/types/sec_seg/sec_seg.cpp index 4d44bfb24..b6b4b271e 100644 --- a/src/fileformat/types/sec_seg/sec_seg.cpp +++ b/src/fileformat/types/sec_seg/sec_seg.cpp @@ -261,15 +261,6 @@ unsigned long long SecSeg::getOffset() const return offset; } -/** -* Get unfixed, original-from-section-header offset -* @return Offset -*/ -unsigned long long SecSeg::getUnfixedOffset() const -{ - return unfixedOffset; -} - /** * Get end offset * @return End offset of section or segment in file @@ -477,16 +468,7 @@ void SecSeg::setIndex(unsigned long long sIndex) */ void SecSeg::setOffset(unsigned long long sOffset) { - unfixedOffset = offset = sOffset; -} - -/** -* Set real (unfixed) offset to the raw section data -* @param sRealOffset Offset -*/ -void SecSeg::setUnfixedOffset(unsigned long long sUnfixedOffset) -{ - unfixedOffset = sUnfixedOffset; + offset = sOffset; } /** diff --git a/src/fileinfo/file_wrapper/pe_wrapper.cpp b/src/fileinfo/file_wrapper/pe_wrapper.cpp index c6fb4348c..b5e58e918 100644 --- a/src/fileinfo/file_wrapper/pe_wrapper.cpp +++ b/src/fileinfo/file_wrapper/pe_wrapper.cpp @@ -6,7 +6,7 @@ #include "retdec/utils/array.h" #include "retdec/utils/conversion.h" -#include "retdec/pelib/pefile.h" +#include "retdec/pelib/PeFile.h" #include "fileinfo/file_wrapper/pe_wrapper.h" using namespace retdec::utils; diff --git a/src/pelib/CoffSymbolTable.cpp b/src/pelib/CoffSymbolTable.cpp index 535376c64..53a83f96d 100644 --- a/src/pelib/CoffSymbolTable.cpp +++ b/src/pelib/CoffSymbolTable.cpp @@ -4,8 +4,6 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include - #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/CoffSymbolTable.h" From 2c8bdc3b9f68750c9323055d96bc4c7b462956e1 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Thu, 2 Jul 2020 19:32:36 +0200 Subject: [PATCH 17/34] Commiting all changes to cloud --- src/pelib/ImageLoader.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index b23d7760d..e2ae69501 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -1181,8 +1181,6 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std::string & sectionName, const std::uint8_t * Name) { - size_t length = 0; - // If the section name is in format of "/12345", then the section name is actually in the symbol table // Sample: 2e9c671b8a0411f2b397544b368c44d7f095eb395779de0ad1ac946914dfa34c if(fileHeader.PointerToSymbolTable != 0 && Name[0] == '/') From c1e403afa1c86ca7c5c0661a71b8d5be6db6b8e8 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Sat, 4 Jul 2020 22:58:14 +0200 Subject: [PATCH 18/34] Solved the mystery of image header mapping under Windows XP --- include/retdec/pelib/ImageLoader.h | 14 +++++++----- src/pelib/ImageLoader.cpp | 35 ++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index ddd4a2a60..0415f8ab0 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -46,15 +46,17 @@ enum PELIB_COMPARE_RESULT : std::uint32_t }; typedef bool (*PFN_VERIFY_ADDRESS)(void * ptr, size_t length); -typedef bool (*PFN_COMPARE_CALLBACK)(size_t BytesCompared, size_t BytesTotal); +typedef bool (*PFN_COMPARE_CALLBACK)(struct PELIB_IMAGE_COMPARE * pImgCompare, size_t BytesCompared, size_t BytesTotal); struct PELIB_IMAGE_COMPARE { - PFN_VERIFY_ADDRESS PfnVerifyAddress; // Custom function for verifying memory address - PFN_COMPARE_CALLBACK PfnCompareCallback; // Custom function for calling compare callback + PFN_VERIFY_ADDRESS PfnVerifyAddress; // Custom function for verifying memory address + PFN_COMPARE_CALLBACK PfnCompareCallback; // Custom function for calling compare callback PELIB_COMPARE_RESULT compareResult; - const char * dumpIfNotEqual; // If non-NULL, the image will be dumped into that file - std::uint32_t differenceOffset; + const char * szFileName; // Current file being compared (plain name) + const char * dumpIfNotEqual; // If non-NULL, the image will be dumped into that file if different + std::uint32_t differenceOffset; // If compareResult is ImagesDifferentPageValue, this contains offset of the difference + std::uint32_t startTickCount; // GetTickCount value at the start of image testing }; //----------------------------------------------------------------------------- @@ -340,6 +342,7 @@ class ImageLoader bool isLegacyImageArchitecture(std::uint16_t Machine); bool checkForValid64BitMachine(); bool checkForValid32BitMachine(); + bool checkForSectionTablesWithinHeader(std::uint32_t e_lfanew); bool checkForBadAppContainer(); // isImageLoadable returns true if the image is OK and can be mapped by NtCreateSection(SEC_IMAGE). @@ -390,6 +393,7 @@ class ImageLoader bool sizeofImageMustMatch; // If true, the SizeOfImage must match virtual end of the last section bool appContainerCheck; // If true, app container flag is tested in the optional header bool is64BitWindows; // If true, we simulate 64-bit Windows + bool headerSizeCheck; // If true, image loader will imitate Windows XP header size check bool loadArmImages; // If true, image loader will load ARM binaries }; diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index e2ae69501..988685df5 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -77,6 +77,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) appContainerCheck = false; maxSectionCount = 255; is64BitWindows = (loaderFlags & LoaderMode64BitWindows) ? true : false; + headerSizeCheck = false; loadArmImages = true; // Resolve os-specific restrictions @@ -85,6 +86,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) case LoaderModeWindowsXP: maxSectionCount = PE_MAX_SECTION_COUNT_XP; sizeofImageMustMatch = true; + headerSizeCheck = true; loadArmImages = false; break; @@ -406,7 +408,7 @@ uint32_t PeLib::ImageLoader::getImageBitability() const return 64; // Default: 32-bit image - return 32; + return 32; } uint32_t PeLib::ImageLoader::getFileOffsetFromRva(uint32_t rva) const @@ -1195,7 +1197,7 @@ int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std: // Get the section name if(readStringRaw(fileData, sectionName, stringTableOffset + stringTableIndex, PELIB_IMAGE_SIZEOF_MAX_NAME, true, true) != 0) - return ERROR_NONE; + return ERROR_NONE; } // The section name is directly in the section header. @@ -1392,13 +1394,13 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) // Section-based mapping / file-based mapping if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE) { - // Note: Under Windows XP, the sample below contained the whole PAGE_SIZE - // in the mapped image header. SizeOfHeaders = 0xC00. I haven't figured our why. - // Doesn't happen in Windows 7+ and it's not subject to low-memory or heavy-load, - // aka also happens when just a single image is loaded. + // Note: Under Windows XP, the loader maps the entire page of the image header + // if the condition in checkForSectionTablesWithinHeader() turns out to be true. + // Windows 7+ uses correct size check. // Sample: 1669f0220f1f74523390fe5b61ea09d6e2e4e798ab294c93d0a20900a3c5a52a - //if(copyWholeHeaderPage) - // sizeOfHeaders = AlignToSize(sizeOfHeaders, optionalHeader.SectionAlignment); + // (Any sample with 4 sections and IMAGE_DOS_HEADER::e_lfanew >= 0x724 will do) + if(headerSizeCheck && checkForSectionTablesWithinHeader(dosHeader.e_lfanew)) + sizeOfHeaders = AlignToSize(sizeOfHeaders, optionalHeader.SectionAlignment); // Capture the file header virtualAddress = captureImageSection(fileData, virtualAddress, sizeOfHeaders, 0, sizeOfHeaders, PELIB_IMAGE_SCN_MEM_READ, true); @@ -1863,6 +1865,21 @@ bool PeLib::ImageLoader::checkForBadAppContainer() return false; } +// Weirdly incorrect check performed by Windows XP's MiCreateImageFileMap. +bool PeLib::ImageLoader::checkForSectionTablesWithinHeader(uint32_t e_lfanew) +{ + uint32_t OffsetToSectionTable = sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; + uint32_t NumberOfSubsections = fileHeader.NumberOfSections; + uint32_t NtHeaderSize = PELIB_PAGE_SIZE - e_lfanew; + + // If this condition is true, then the image header contains data up fo SizeofHeaders + // If not, the image header contains the entire page. + if((e_lfanew + OffsetToSectionTable + (NumberOfSubsections + 1) * sizeof(PELIB_IMAGE_SECTION_HEADER)) <= NtHeaderSize) + return false; + + return true; +} + // Returns true if the image is OK and can be mapped by NtCreateSection(SEC_IMAGE). // This does NOT mean that the image is executable by CreateProcess - more checks are done, // like resource integrity or relocation table correctness. @@ -1950,7 +1967,7 @@ void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & Ima // If we have a compare callback, call it if(ImageCompare.PfnCompareCallback != nullptr) { - ImageCompare.PfnCompareCallback(rva, imageSize); + ImageCompare.PfnCompareCallback(&ImageCompare, rva, imageSize); } // Both are accessible -> Compare the page From b93025865c309afaff95fda290fdb094beeb498a Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Thu, 9 Jul 2020 16:23:53 +0200 Subject: [PATCH 19/34] Unpackers: UPX (progress) --- include/retdec/pelib/ImageLoader.h | 30 +- src/fileinfo/fileinfo.cpp | 2 +- src/pelib/ImageLoader.cpp | 305 +++++++++++++----- .../plugins/upx/pe/pe_upx_stub.cpp | 100 +++--- src/unpackertool/plugins/upx/pe/pe_upx_stub.h | 2 +- 5 files changed, 313 insertions(+), 126 deletions(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 0415f8ab0..caa90c461 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -32,6 +32,16 @@ enum : std::uint32_t LoaderMode64BitWindows = 0x1000, // Emulate 64-bit system }; +//----------------------------------------------------------------------------- +// Enum for ImageLoader::getFieldOffset() + +enum PELIB_MEMBER_TYPE : std::uint32_t +{ + OPTHDR_sizeof, + OPTHDR_NumberOfRvaAndSizes, + OPTHDR_DataDirectory, +}; + //----------------------------------------------------------------------------- // Support structure for one PE image compare result @@ -150,6 +160,8 @@ class ImageLoader std::uint32_t getRealPointerToRawData(std::size_t sectionIndex) const; std::uint32_t getImageProtection(std::uint32_t characteristics) const; + std::uint32_t getFieldOffset(PELIB_MEMBER_TYPE field) const; + bool setDataDirectory(std::uint32_t index, std::uint32_t rva, std::uint32_t size); const PELIB_IMAGE_DOS_HEADER & getDosHeader() const @@ -182,6 +194,11 @@ class ImageLoader return dosHeader.e_lfanew; } + void setPeHeaderOffset(std::uint32_t new_e_lfanew) + { + dosHeader.e_lfanew = new_e_lfanew; + } + std::uint32_t getNtSignature() const { return ntSignature; @@ -293,6 +310,13 @@ class ImageLoader return virtualAddress; } + // Image manipulation + void setSizeOfCode(std::uint32_t sizeOfCode, std::uint32_t baseOfCode = UINT32_MAX); + void setSectionVirtualData(std::size_t sectionIndex, std::uint32_t VirtualAddress, std::uint32_t VirtualSize = UINT32_MAX); + void setSectionRawData(std::size_t sectionIndex, std::uint32_t PointerToRawData, std::uint32_t SizeOfRawData = UINT32_MAX); + int removeSection(std::size_t sectionIndex); + void makeValid(); + int setLoaderError(LoaderError ldrErr); LoaderError loaderError() const; @@ -309,6 +333,7 @@ class ImageLoader std::uint32_t readWriteImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead, READWRITE ReadWrite); std::uint32_t readWriteImageFile(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead, bool bReadOperation); + void processSectionHeader(PELIB_IMAGE_SECTION_HEADER * pSectionHeader); bool processImageRelocation_IA64_IMM64(std::uint32_t fixupAddress, std::uint64_t difference); bool processImageRelocations(std::uint64_t oldImageBase, std::uint64_t getImageBase, std::uint32_t VirtualAddress, std::uint32_t Size); void writeNewImageBase(std::uint64_t newImageBase); @@ -338,13 +363,13 @@ class ImageLoader bool isGoodMappedPage(std::uint32_t rva); bool isZeroPage(std::uint32_t rva); - bool isRvaOfSectionHeaderPointerToRawData(uint32_t rva); + bool isSectionHeaderPointerToRawData(uint32_t rva); bool isLegacyImageArchitecture(std::uint16_t Machine); bool checkForValid64BitMachine(); bool checkForValid32BitMachine(); bool checkForSectionTablesWithinHeader(std::uint32_t e_lfanew); bool checkForBadAppContainer(); - + // isImageLoadable returns true if the image is OK and can be mapped by NtCreateSection(SEC_IMAGE). // This does NOT mean that the image is executable by CreateProcess - more checks are done, // like resource integrity or relocation table correctness. @@ -389,6 +414,7 @@ class ImageLoader std::uint32_t realNumberOfRvaAndSizes; // Real present number of RVA and sizes std::uint32_t checkSumFileOffset; // File offset of the image checksum std::uint32_t securityDirFileOffset; // File offset of security directory + std::uint32_t ssiImageAlignment32; // Alignment of signle-section images under 32-bit OS bool ntHeadersSizeCheck; // If true, the loader requires minimum size of NT headers bool sizeofImageMustMatch; // If true, the SizeOfImage must match virtual end of the last section bool appContainerCheck; // If true, app container flag is tested in the optional header diff --git a/src/fileinfo/fileinfo.cpp b/src/fileinfo/fileinfo.cpp index 5a8b52aa8..2f268e70b 100644 --- a/src/fileinfo/fileinfo.cpp +++ b/src/fileinfo/fileinfo.cpp @@ -523,5 +523,5 @@ int main(int argc, char* argv[]) } delete fileDetector; - return isFatalError(res) ? static_cast(res) : static_cast(ReturnCode::OK); + return isFatalError(res) ? static_cast(res) : static_cast(ReturnCode::OK); } diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 988685df5..7f4113326 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -72,6 +72,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) ldrError = LDR_ERROR_NONE; // By default, set the most benevolent settings + ssiImageAlignment32 = PELIB_PAGE_SIZE; sizeofImageMustMatch = false; ntHeadersSizeCheck = false; appContainerCheck = false; @@ -80,10 +81,11 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) headerSizeCheck = false; loadArmImages = true; - // Resolve os-specific restrictions + // Resolve version-specific restrictions switch(loaderMode = (loaderFlags & WindowsVerMask)) { case LoaderModeWindowsXP: + ssiImageAlignment32 = PELIB_SECTOR_SIZE; maxSectionCount = PE_MAX_SECTION_COUNT_XP; sizeofImageMustMatch = true; headerSizeCheck = true; @@ -91,6 +93,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) break; case LoaderModeWindows7: + ssiImageAlignment32 = 1; // SECTOR_SIZE when the image is loaded from network media maxSectionCount = PE_MAX_SECTION_COUNT_7; ntHeadersSizeCheck = true; sizeofImageMustMatch = true; @@ -98,6 +101,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) break; case LoaderModeWindows10: + ssiImageAlignment32 = 1; maxSectionCount = PE_MAX_SECTION_COUNT_7; ntHeadersSizeCheck = true; appContainerCheck = true; @@ -211,8 +215,8 @@ uint32_t PeLib::ImageLoader::stringLength(uint32_t rva, uint32_t maxLength) cons while(rva < rvaEnd) { const PELIB_FILE_PAGE & page = pages[pageIndex]; - const uint8_t * dataBegin; - const uint8_t * dataPtr; + const uint8_t * dataBegin; + const uint8_t * dataPtr; uint32_t rvaEndPage = (pageIndex + 1) * PELIB_PAGE_SIZE; // If zero page, means we found an RVA with zero @@ -246,7 +250,7 @@ uint32_t PeLib::ImageLoader::stringLength(uint32_t rva, uint32_t maxLength) cons { const uint8_t * stringPtr = rawFileData.data() + rva; const uint8_t * stringEnd; - + length = rawFileData.size() - rva; stringEnd = (const uint8_t *)memchr(stringPtr, 0, length); @@ -450,6 +454,28 @@ uint32_t PeLib::ImageLoader::getFileOffsetFromRva(uint32_t rva) const return rva; } +std::uint32_t PeLib::ImageLoader::getFieldOffset(PELIB_MEMBER_TYPE field) const +{ + std::uint32_t imageBitability = getImageBitability(); + std::uint32_t fieldOffset; + + switch (field) + { + case OPTHDR_sizeof: + return (imageBitability == 64) ? sizeof(PELIB_IMAGE_OPTIONAL_HEADER64) : sizeof(PELIB_IMAGE_OPTIONAL_HEADER32); + + case OPTHDR_NumberOfRvaAndSizes: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, NumberOfRvaAndSizes) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, NumberOfRvaAndSizes); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset; + + case OPTHDR_DataDirectory: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset; + } + + return UINT32_MAX; +} + bool PeLib::ImageLoader::setDataDirectory(std::uint32_t index, std::uint32_t rva, std::uint32_t size) { // Make sure that there is enough data directory entries @@ -476,21 +502,126 @@ uint32_t PeLib::ImageLoader::getImageProtection(uint32_t sectionCharacteristics) { uint32_t Index = 0; - if (sectionCharacteristics & PELIB_IMAGE_SCN_MEM_EXECUTE) + if(sectionCharacteristics & PELIB_IMAGE_SCN_MEM_EXECUTE) Index |= 1; - if (sectionCharacteristics & PELIB_IMAGE_SCN_MEM_READ) + if(sectionCharacteristics & PELIB_IMAGE_SCN_MEM_READ) Index |= 2; - if (sectionCharacteristics & PELIB_IMAGE_SCN_MEM_WRITE) + if(sectionCharacteristics & PELIB_IMAGE_SCN_MEM_WRITE) Index |= 4; - if (sectionCharacteristics & PELIB_IMAGE_SCN_MEM_SHARED) + if(sectionCharacteristics & PELIB_IMAGE_SCN_MEM_SHARED) Index |= 8; return ImageProtectionArray[Index]; } +//----------------------------------------------------------------------------- +// Manipulation with section data + +void PeLib::ImageLoader::setSizeOfCode(uint32_t sizeOfCode, uint32_t baseOfCode) +{ + if(sizeOfCode != UINT32_MAX) + optionalHeader.SizeOfCode = sizeOfCode; + if(baseOfCode != UINT32_MAX) + optionalHeader.BaseOfCode = baseOfCode; +} + +void PeLib::ImageLoader::setSectionVirtualData(size_t sectionIndex, uint32_t VirtualAddress, uint32_t VirtualSize) +{ + if(sectionIndex < sections.size()) + { + PELIB_SECTION_HEADER & section = sections[sectionIndex]; + + if(VirtualAddress != UINT32_MAX) + section.VirtualAddress = VirtualAddress; + if(VirtualSize != UINT32_MAX) + section.VirtualSize = VirtualSize; + } +} + +void PeLib::ImageLoader::setSectionRawData(size_t sectionIndex, uint32_t PointerToRawData, uint32_t SizeOfRawData) +{ + if(sectionIndex < sections.size()) + { + PELIB_SECTION_HEADER & section = sections[sectionIndex]; + + if(PointerToRawData != UINT32_MAX) + section.PointerToRawData = PointerToRawData; + if(SizeOfRawData != UINT32_MAX) + section.SizeOfRawData = SizeOfRawData; + } +} + +int PeLib::ImageLoader::removeSection(size_t sectionIndex) +{ + if(sectionIndex >= getNumberOfSections()) + return ERROR_ENTRY_NOT_FOUND; + + const PELIB_SECTION_HEADER * pSectionHeader = getSectionHeader(sectionIndex); + uint32_t virtualDiff = pSectionHeader->VirtualSize; + uint32_t rawDiff = pSectionHeader->SizeOfRawData; + + for (size_t i = sectionIndex + 1; i < getNumberOfSections(); ++i) + { + pSectionHeader = getSectionHeader(i); + + setSectionVirtualData(i, pSectionHeader->VirtualAddress - virtualDiff); + setSectionRawData(i, pSectionHeader->PointerToRawData - rawDiff); + } + + sections.erase(sections.begin() + sectionIndex); + return ERROR_NONE; +} + +void PeLib::ImageLoader::makeValid() +{ + uint32_t imageBitability = getImageBitability(); + uint32_t sizeOfHeaders; + uint32_t sizeOfImage; + uint32_t dwOffsetDiff; + uint32_t alignment; + + // Fix the NT signature + ntSignature = PELIB_IMAGE_NT_SIGNATURE; // 'PE' + + // Fix the IMAGE_FILE_HEADER + fileHeader.Machine = (imageBitability == 64) ? PELIB_IMAGE_FILE_MACHINE_AMD64 : PELIB_IMAGE_FILE_MACHINE_I386; + fileHeader.NumberOfSections = (std::uint16_t)sections.size(); + fileHeader.SizeOfOptionalHeader = getFieldOffset(OPTHDR_sizeof); + fileHeader.Characteristics = (fileHeader.Characteristics != 0) ? fileHeader.Characteristics : PELIB_IMAGE_FILE_EXECUTABLE_IMAGE | PELIB_IMAGE_FILE_32BIT_MACHINE; + + // Fix the IMAGE_OPTIONAL_HEADER + optionalHeader.Magic = (imageBitability == 64) ? PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC : PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC; + optionalHeader.NumberOfRvaAndSizes = PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES; + + alignment = AlignToSize(optionalHeader.SectionAlignment, PELIB_PAGE_SIZE); + optionalHeader.SectionAlignment = (alignment != 0) ? alignment : PELIB_PAGE_SIZE; + + alignment = AlignToSize(optionalHeader.FileAlignment, PELIB_SECTOR_SIZE); + optionalHeader.FileAlignment = (alignment != 0) ? alignment : PELIB_SECTOR_SIZE; + + sizeOfHeaders = dosHeader.e_lfanew + sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader + fileHeader.NumberOfSections * sizeof(PELIB_IMAGE_SECTION_HEADER); + optionalHeader.SizeOfHeaders = sizeOfHeaders = AlignToSize(sizeOfHeaders, optionalHeader.FileAlignment); + + sizeOfImage = AlignToSize(optionalHeader.SizeOfHeaders, optionalHeader.SectionAlignment); + dwOffsetDiff = sizeOfHeaders - getSectionHeader(0)->PointerToRawData; + for(uint16_t i = 0; i < fileHeader.NumberOfSections; i++) + { + const PELIB_SECTION_HEADER * pSectionHeader = getSectionHeader(i); + + sizeOfImage += AlignToSize(pSectionHeader->VirtualSize, optionalHeader.SectionAlignment); + + // If the size of headers changed, we need to move all section data further + if(dwOffsetDiff) + setSectionRawData(i, pSectionHeader->PointerToRawData + dwOffsetDiff); + } + + // Fixup the size of image + optionalHeader.SizeOfImage = AlignToSize(sizeOfImage, optionalHeader.SectionAlignment); +} + //----------------------------------------------------------------------------- // Loader error @@ -515,7 +646,7 @@ PeLib::LoaderError PeLib::ImageLoader::loaderError() const int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOnly) { int fileError; - + // Check and capture DOS header fileError = captureDosHeader(fileData); if(fileError != ERROR_NONE) @@ -712,7 +843,44 @@ uint32_t PeLib::ImageLoader::readWriteImageFile(void * buffer, std::uint32_t rva return bytesToRead; } -//----------------------------------------------------------------------------- +// +// There is a specific piece of code in MiParseImageSectionHeaders (see below). +// Note that this is done on the raw image data *BEFORE* the image is mapped to sections +// Causes map difference on this sample: 2e26926a701df980fb56e5905a93bf2d7ba6981ccabc81cf251b3c0ed6afdc26 +// * SizeOfHeaders: 0x1000 +// * PointerToRawData section[1]: 0x0200 - this actually points to the IMAGE_SECTION_HEADER of section[3] +// Because the PointerToRawData of section[3] is set to zero, the RVA 0xA014 is also set to zero +// +// The code is here: +// +// // +// // Fix for Borland linker problem. The SizeOfRawData can +// // be a zero, but the PointerToRawData is not zero. +// // Set it to zero. +// // +// +// if(SectionTableEntry->SizeOfRawData == 0) { +// SectionTableEntry->PointerToRawData = 0; +// } +// + +void PeLib::ImageLoader::processSectionHeader(PELIB_IMAGE_SECTION_HEADER * pSectionHeader) +{ + // Note: Retdec's regression tests don't like it, because they require section headers to have original data + // Also signature verification stops working if we modify the original data + if(loaderMode != 0) + { + // Fix the section header. Note that this will modify the data in the on-disk version + // of the image. Any section that will become mapped to this section header + // will have the corresponding DWORD zeroed, as expected. + if(pSectionHeader->PointerToRawData != 0 && pSectionHeader->SizeOfRawData == 0) + { + pSectionHeader->PointerToRawData = 0; + } + } +} + +//----------------------------------------------------------------------------- // Processes relocation entry for IA64 relocation bundle #define EMARCH_ENC_I17_IMM7B_INST_WORD_X 3 @@ -778,7 +946,7 @@ bool PeLib::ImageLoader::processImageRelocation_IA64_IMM64(uint32_t fixupAddress // Extract the IMM64 from bundle // - EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM7B_INST_WORD_X], + EXT_IMM64(Value64, BundleBlock[EMARCH_ENC_I17_IMM7B_INST_WORD_X], EMARCH_ENC_I17_IMM7B_SIZE_X, EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X, EMARCH_ENC_I17_IMM7B_VAL_POS_X); @@ -976,7 +1144,7 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t break; } - case PELIB_IMAGE_REL_BASED_MIPS_JMPADDR: // Relocate a MIPS jump address. + case PELIB_IMAGE_REL_BASED_MIPS_JMPADDR: // Relocate a MIPS jump address. { uint32_t fixupValue = 0; @@ -993,7 +1161,7 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t processImageRelocation_IA64_IMM64(fixupAddress, difference); break; - case PELIB_IMAGE_REL_BASED_ABSOLUTE: // Absolute - no fixup required. + case PELIB_IMAGE_REL_BASED_ABSOLUTE: // Absolute - no fixup required. break; default: @@ -1235,13 +1403,13 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) bool SingleSubsection = (optionalHeader.SectionAlignment < PELIB_PAGE_SIZE); // Verify the image - if (!SingleSubsection) + if(!SingleSubsection) { // Some extra checks done by the loader - if ((optionalHeader.SizeOfHeaders + (optionalHeader.SectionAlignment - 1)) < optionalHeader.SizeOfHeaders) + if((optionalHeader.SizeOfHeaders + (optionalHeader.SectionAlignment - 1)) < optionalHeader.SizeOfHeaders) setLoaderError(LDR_ERROR_SECTION_HEADERS_OVERFLOW); - if (NumberOfSectionPTEs > NumberOfPTEs) + if(NumberOfSectionPTEs > NumberOfPTEs) setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); // Update the virtual address @@ -1264,26 +1432,30 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) break; memcpy(§Hdr, filePtr, sizeof(PELIB_IMAGE_SECTION_HEADER)); + // Fix the section header *in the source data*. We need to do that *after* the section header was loaded + processSectionHeader((PELIB_IMAGE_SECTION_HEADER *)filePtr); + + // Parse the section headers and check for corruptions uint32_t PointerToRawData = (sectHdr.SizeOfRawData != 0) ? sectHdr.PointerToRawData : 0; uint32_t EndOfRawData = PointerToRawData + sectHdr.SizeOfRawData; uint32_t VirtualSize = (sectHdr.VirtualSize != 0) ? sectHdr.VirtualSize : sectHdr.SizeOfRawData; // Overflow check - if ((PointerToRawData + sectHdr.SizeOfRawData) < PointerToRawData) + if((PointerToRawData + sectHdr.SizeOfRawData) < PointerToRawData) setLoaderError(LDR_ERROR_RAW_DATA_OVERFLOW); // Verify the image - if (SingleSubsection) + if(SingleSubsection) { // If the image is mapped as single subsection, // then the virtual values must match raw values - if ((sectHdr.VirtualAddress != PointerToRawData) || sectHdr.SizeOfRawData < VirtualSize) + if((sectHdr.VirtualAddress != PointerToRawData) || sectHdr.SizeOfRawData < VirtualSize) setLoaderError(LDR_ERROR_SECTION_SIZE_MISMATCH); } else { // Check the virtual address of the section - if (NextVirtualAddress != sectHdr.VirtualAddress) + if(NextVirtualAddress != sectHdr.VirtualAddress) setLoaderError(LDR_ERROR_INVALID_SECTION_VA); // Check the end of the section @@ -1291,18 +1463,18 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) setLoaderError(LDR_ERROR_INVALID_SECTION_VSIZE); // Check section size - if ((VirtualSize + (PELIB_PAGE_SIZE - 1)) <= VirtualSize) + if((VirtualSize + (PELIB_PAGE_SIZE - 1)) <= VirtualSize) setLoaderError(LDR_ERROR_INVALID_SECTION_VSIZE); // Calculate number of PTEs in the section NumberOfSectionPTEs = AlignToSize(VirtualSize, optionalHeader.SectionAlignment) / PELIB_PAGE_SIZE; - if (NumberOfSectionPTEs > NumberOfPTEs) + if(NumberOfSectionPTEs > NumberOfPTEs) setLoaderError(LDR_ERROR_INVALID_SECTION_VSIZE); NumberOfPTEs -= NumberOfSectionPTEs; // Check end of the raw data for the section - if (((PointerToRawData + sectHdr.SizeOfRawData + FileAlignmentMask) & ~FileAlignmentMask) < PointerToRawData) + if(((PointerToRawData + sectHdr.SizeOfRawData + FileAlignmentMask) & ~FileAlignmentMask) < PointerToRawData) setLoaderError(LDR_ERROR_INVALID_SECTION_RAWSIZE); // On last section, size of raw data must not go after the end of the file @@ -1319,7 +1491,7 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) // Check for raw data beyond end-of-file // Note that Windows loader doesn't check this on files that are mapped as single section. // We will do that nonetheless, because we want to know that a file is cut. - if (PointerToRawData != 0 && (fileBegin + EndOfRawData) > fileEnd) + if(PointerToRawData != 0 && (fileBegin + EndOfRawData) > fileEnd) bRawDataBeyondEOF = true; // Resolve the section name @@ -1334,14 +1506,14 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) if(sizeofImageMustMatch) { uint32_t ThresholdNumberOfPTEs = (SingleSubsection == false) ? (optionalHeader.SectionAlignment / PELIB_PAGE_SIZE) : 1; - if (NumberOfPTEs >= ThresholdNumberOfPTEs) + if(NumberOfPTEs >= ThresholdNumberOfPTEs) { setLoaderError(LDR_ERROR_INVALID_SIZE_OF_IMAGE); } } // Did we detect a trimmed file? - if (bRawDataBeyondEOF) + if(bRawDataBeyondEOF) { // Track the state of loadability of the cut file. Some files can still be loadable. // Example: bd149478739e660b032e4454057ce8d3e18dfbb6d1677c6ecdcc3aa59b36c8d9 @@ -1352,13 +1524,13 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) // the PE loader in Windows only cares about whether the last section is in the file range if(SingleSubsection == false) { - if (!sections.empty()) + if(!sections.empty()) { PELIB_IMAGE_SECTION_HEADER & lastSection = sections.back(); uint32_t PointerToRawData = (lastSection.SizeOfRawData != 0) ? lastSection.PointerToRawData : 0; uint32_t EndOfRawData = PointerToRawData + lastSection.SizeOfRawData; - if ((lastSection.SizeOfRawData == 0) || (fileBegin + EndOfRawData) <= fileEnd) + if((lastSection.SizeOfRawData == 0) || (fileBegin + EndOfRawData) <= fileEnd) { setLoaderError(LDR_ERROR_FILE_IS_CUT_LOADABLE); bCutButLoadable = true; @@ -1372,7 +1544,7 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) } // If the file is not loadable, set the "file is cut" error - if (bCutButLoadable == false) + if(bCutButLoadable == false) { setLoaderError(LDR_ERROR_FILE_IS_CUT); } @@ -1385,15 +1557,15 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) { uint32_t virtualAddress = 0; uint32_t sizeOfHeaders = optionalHeader.SizeOfHeaders; - uint32_t sizeOfImage; - - // Reserve the image size, aligned up to the page size - sizeOfImage = AlignToSize(optionalHeader.SizeOfImage, PELIB_PAGE_SIZE); - pages.resize(sizeOfImage / PELIB_PAGE_SIZE); + uint32_t sizeOfImage = optionalHeader.SizeOfImage; // Section-based mapping / file-based mapping if(optionalHeader.SectionAlignment >= PELIB_PAGE_SIZE) { + // Reserve the image size, aligned up to the page size + sizeOfImage = AlignToSize(sizeOfImage, PELIB_PAGE_SIZE); + pages.resize(sizeOfImage / PELIB_PAGE_SIZE); + // Note: Under Windows XP, the loader maps the entire page of the image header // if the condition in checkForSectionTablesWithinHeader() turns out to be true. // Windows 7+ uses correct size check. @@ -1437,33 +1609,25 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) } else { + // 64-bit Windows always align single-section images to page size. + // 32-bit Windows: + // * Windows XP: sector size + // * Windows 7 : sector size (network files) or no align (local files) + // * Windows 10: no align + // If the image is smaller than one page, it is aligned to one page + sizeOfImage = AlignToSize(sizeOfImage, ssiImageAlignment32); + if(is64BitWindows) + sizeOfImage = AlignToSize(sizeOfImage, PELIB_PAGE_SIZE); + if(sizeOfImage < PELIB_PAGE_SIZE) + sizeOfImage = PELIB_PAGE_SIZE; + pages.resize((sizeOfImage + PELIB_PAGE_SIZE - 1) / PELIB_PAGE_SIZE); + // Capture the file as-is virtualAddress = captureImageSection(fileData, 0, sizeOfImage, 0, sizeOfImage, PELIB_IMAGE_SCN_MEM_WRITE | PELIB_IMAGE_SCN_MEM_READ | PELIB_IMAGE_SCN_MEM_EXECUTE, true); if(virtualAddress == 0) return ERROR_INVALID_FILE; } - // If a section has SizeOfRawData equal to 0, - // Windows loader patches PointerToRawData to zero, including the mapped image. - // Tested on Windows XP and Windows 10. - uint32_t rva = dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; - for(size_t i = 0; i < sections.size(); i++, rva += sizeof(PELIB_IMAGE_SECTION_HEADER)) - { - PELIB_IMAGE_SECTION_HEADER sectHdr{}; - - // Read the section from the header. This is necessary, as for some files, - // section headers are not contained in the image. - // Example: c8b31a912d91407a834071268366eb404d5e771b8281fdde301e15a8a82bf01b - readImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER)); - - // Patch PointerToRawData to zero, if SizeOfRawData is zero. - if(sectHdr.PointerToRawData != 0 && sectHdr.SizeOfRawData == 0) - { - sectHdr.PointerToRawData = 0; - writeImage(§Hdr, rva, sizeof(PELIB_IMAGE_SECTION_HEADER)); - } - } - return ERROR_NONE; } @@ -1705,7 +1869,7 @@ uint32_t PeLib::ImageLoader::captureImageSection( if(getImageProtection(characteristics) != PELIB_PAGE_NOACCESS) { // If the pointerToRawData is less than SECTOR_SIZE, it will contain file header in it. - // However, if the pointerToRawData contains 0, then the + // However, if the pointerToRawData contains 0, then the if(pointerToRawData || isImageHeader) { // Fill all pages that contain data @@ -1791,12 +1955,13 @@ bool PeLib::ImageLoader::isZeroPage(uint32_t rva) return (pageIndex < pages.size()) ? pages[pageIndex].isZeroPage : false; } -bool PeLib::ImageLoader::isRvaOfSectionHeaderPointerToRawData(uint32_t rva) +bool PeLib::ImageLoader::isSectionHeaderPointerToRawData(uint32_t fileOffset) { - uint32_t rvaOfLastSectionPointerToRawData; + uint32_t fileOffsetToSectionHeader = dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; + uint32_t fileOffsetOfPointerToRawData; // If there is at least one section - for(size_t i = 0; i < sections.size(); i++) + for(size_t i = 0; i < sections.size(); i++, fileOffsetToSectionHeader += sizeof(PELIB_IMAGE_SECTION_HEADER)) { // Get the reference to the section header PELIB_IMAGE_SECTION_HEADER & sectHdr = sections[i]; @@ -1805,14 +1970,9 @@ bool PeLib::ImageLoader::isRvaOfSectionHeaderPointerToRawData(uint32_t rva) if(sectHdr.SizeOfRawData == 0) { // Calculate the RVA of the PointerToRawData variable in the last section - rvaOfLastSectionPointerToRawData = dosHeader.e_lfanew + - sizeof(uint32_t) + - sizeof(PELIB_IMAGE_FILE_HEADER) + - fileHeader.SizeOfOptionalHeader + - i * sizeof(PELIB_IMAGE_SECTION_HEADER) + - 0x14; // FIELD_OFFSET(PELIB_IMAGE_SECTION_HEADER, PointerToRawData) - - if(rvaOfLastSectionPointerToRawData <= rva && rva < rvaOfLastSectionPointerToRawData + sizeof(uint32_t)) + fileOffsetOfPointerToRawData = fileOffsetToSectionHeader + 0x14; // FIELD_OFFSET(PELIB_IMAGE_SECTION_HEADER, PointerToRawData) + + if(fileOffsetOfPointerToRawData <= fileOffset && fileOffset < fileOffsetOfPointerToRawData + sizeof(uint32_t)) return true; } } @@ -1847,7 +2007,7 @@ bool PeLib::ImageLoader::checkForValid32BitMachine() } // Windows 10: For IMAGE_FILE_MACHINE_I386 and IMAGE_FILE_MACHINE_AMD64, -// if (Characteristics & IMAGE_FILE_RELOCS_STRIPPED) and (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER), +// if(Characteristics & IMAGE_FILE_RELOCS_STRIPPED) and (DllCharacteristics & IMAGE_DLLCHARACTERISTICS_APPCONTAINER), // MiVerifyImageHeader returns STATUS_INVALID_IMAGE_FORMAT. bool PeLib::ImageLoader::checkForBadAppContainer() { @@ -1916,17 +2076,16 @@ size_t PeLib::ImageLoader::getMismatchOffset(void * buffer1, void * buffer2, uin { uint8_t * byteBuffer1 = reinterpret_cast(buffer1); uint8_t * byteBuffer2 = reinterpret_cast(buffer2); + uint32_t fileOffset = getFileOffsetFromRva(rva); for(size_t i = 0; i < length; i++) { if(byteBuffer1[i] != byteBuffer2[i]) { - // Windows loader puts 0 in IMAGE_SECTION_HEADER::PointerToRawData - // if IMAGE_SECTION_HEADER::SizeOfRawData is also zero. - // However, on random samples, there seems to be the original value. - // This seems to happen randomly on some samples, often dissappears + // Windows loader puts 0 in IMAGE_SECTION_HEADER::PointerToRawData if IMAGE_SECTION_HEADER::SizeOfRawData is also zero. + // However, this is somewhat random - depends on current memory condition, often dissappears // when the sample is copied to another location. - if(isRvaOfSectionHeaderPointerToRawData(rva + i)) + if(isSectionHeaderPointerToRawData(fileOffset + i)) continue; //for(int j = i & 0xFFFFFFF0; j < 0xD00; j++) diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp index 7a87994ac..8b7f1bd82 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp @@ -182,17 +182,16 @@ template void PeUpxStub::unpack(const std::string& outputFile) // Detect auxiliary stubs detectUnfilter(unpackingStub); -/* + + // Create new instance of a PeFileT class std::string inputFilePath = _file->getFileFormat()->getPathToFile(); - PeLib::PeFile* peFile = PeLib::openPeFile(inputFilePath); - _newPeFile = static_cast(peFile); + _newPeFile = new PeLib::PeFileT(inputFilePath); // Read MZ & PE headers - _newPeFile->readMzHeader(); - _newPeFile->readPeHeader(); + _newPeFile->loadPeHeaders(); // We won't copy the DOS program so let's just set the pointer to PE header right after MZ header - _newPeFile->mzHeader().setAddressOfPeHeader(_newPeFile->mzHeader().size()); + _newPeFile->imageLoader().setPeHeaderOffset(sizeof(PeLib::PELIB_IMAGE_DOS_HEADER)); // Perform unpacking DynamicBuffer unpackedData(_file->getFileFormat()->getEndianness()); @@ -250,7 +249,6 @@ template void PeUpxStub::unpack(const std::string& outputFile) // Save the output to the file saveFile(outputFile, unpackedData); - */ } /** @@ -426,20 +424,20 @@ template void PeUpxStub::unpackData(DynamicBuffer& unpackedData */ template void PeUpxStub::readPackedFileILT(DynamicBuffer& ilt) { -/* + const PeLib::ImageLoader imageLoader = _newPeFile->imageLoader(); + std::uint32_t importRva = imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT); + std::uint32_t importSize = imageLoader.getDataDirSize(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT); + // We don't use PeLib for reading ILT because it is going to populate impDir(), but we want to it to build it all ourselves manually std::vector iltBytes; - const retdec::loader::Segment* importsSection = _file->getSegmentFromAddress(_newPeFile->peHeader().getIddImportRva() + _newPeFile->peHeader().getImageBase()); + const retdec::loader::Segment* importsSection = _file->getSegmentFromAddress(importRva + imageLoader.getImageBase()); if (importsSection == nullptr) throw ImportNamesNotFoundException(); - importsSection->getBytes(iltBytes, - _newPeFile->peHeader().rvaToOffset(_newPeFile->peHeader().getIddImportRva()) - importsSection->getSecSeg()->getOffset(), - _newPeFile->peHeader().getIddImportSize()); + importsSection->getBytes(iltBytes, imageLoader.getFileOffsetFromRva(importRva) - importsSection->getSecSeg()->getOffset(), importSize); ilt = DynamicBuffer(iltBytes, _file->getFileFormat()->getEndianness()); - */ } /** @@ -451,33 +449,37 @@ template void PeUpxStub::readPackedFileILT(DynamicBuffer& ilt) */ template void PeUpxStub::fixSizeOfSections(const DynamicBuffer& unpackedData) { - /* + const PeLib::PELIB_IMAGE_SECTION_HEADER * pSectionHeader1; + const PeLib::PELIB_IMAGE_SECTION_HEADER * pSectionHeader; + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + std::uint32_t sectionIndex = _upx0Sect->getSecSeg()->getIndex(); + // Always make sure that UPX0 points to same raw pointer as UPX1 before we process sections // This allows us to use much more simpler algorithm, than calculating with all possible positions of UPX0 - _newPeFile->peHeader().setPointerToRawData(0, _newPeFile->peHeader().getPointerToRawData(1)); + pSectionHeader = imageLoader.getSectionHeader(1); + imageLoader.setSectionRawData(0, pSectionHeader->PointerToRawData); // Set the proper raw size for UPX0 section, thus moving pointer to raw data of all following sections - std::uint32_t diff = _newPeFile->peHeader().getVirtualSize(_upx0Sect->getSecSeg()->getIndex()) - _newPeFile->peHeader().getSizeOfRawData(_upx0Sect->getSecSeg()->getIndex()); - _newPeFile->peHeader().setSizeOfRawData(_upx0Sect->getSecSeg()->getIndex(), _newPeFile->peHeader().getVirtualSize(_upx0Sect->getSecSeg()->getIndex())); - for (std::uint32_t i = _upx0Sect->getSecSeg()->getIndex() + 1; i < _newPeFile->peHeader().calcNumberOfSections(); ++i) - _newPeFile->peHeader().setPointerToRawData(i, _newPeFile->peHeader().getPointerToRawData(i) + diff); + pSectionHeader = imageLoader.getSectionHeader(sectionIndex); + std::uint32_t diff = pSectionHeader->VirtualSize - pSectionHeader->SizeOfRawData; + imageLoader.setSectionRawData(sectionIndex, UINT32_MAX, pSectionHeader->VirtualSize); + for (std::uint32_t i = sectionIndex + 1; i < imageLoader.getNumberOfSections(); ++i) + imageLoader.setSectionRawData(i, imageLoader.getSectionHeader(i)->PointerToRawData + diff); // If the section UPX0 is lesser than all the unpacked data, we need to move boundaries of UPX0/UPX1 section // Since UPX0 and UPX1 have continuous address space, we can just resize UPX0 and shrink UPX1 - if (_newPeFile->peHeader().getVirtualSize(_upx0Sect->getSecSeg()->getIndex()) < unpackedData.getRealDataSize()) + if (pSectionHeader->VirtualSize < unpackedData.getRealDataSize()) { // Make sure the new size is section aligned - std::uint32_t newSize = retdec::utils::alignUp(unpackedData.getRealDataSize(), _newPeFile->peHeader().getSectionAlignment()); + std::uint32_t newSize = retdec::utils::alignUp(unpackedData.getRealDataSize(), imageLoader.getSectionAlignment()); + diff = newSize - pSectionHeader->VirtualSize; - diff = newSize - _newPeFile->peHeader().getVirtualSize(_upx0Sect->getSecSeg()->getIndex()); + imageLoader.setSectionVirtualData(sectionIndex, UINT32_MAX, pSectionHeader->VirtualSize + diff); + imageLoader.setSectionRawData(sectionIndex, UINT32_MAX, pSectionHeader->SizeOfRawData + diff); - _newPeFile->peHeader().setVirtualSize(_upx0Sect->getSecSeg()->getIndex(), _newPeFile->peHeader().getVirtualSize(_upx0Sect->getSecSeg()->getIndex()) + diff); - _newPeFile->peHeader().setSizeOfRawData(_upx0Sect->getSecSeg()->getIndex(), _newPeFile->peHeader().getSizeOfRawData(_upx0Sect->getSecSeg()->getIndex()) + diff); - - _newPeFile->peHeader().setVirtualAddress(_upx0Sect->getSecSeg()->getIndex() + 1, _newPeFile->peHeader().getVirtualAddress(_upx0Sect->getSecSeg()->getIndex() + 1) + diff); - _newPeFile->peHeader().setVirtualSize(_upx0Sect->getSecSeg()->getIndex() + 1, _newPeFile->peHeader().getVirtualSize(_upx0Sect->getSecSeg()->getIndex() + 1) - diff); - _newPeFile->peHeader().setPointerToRawData(_upx0Sect->getSecSeg()->getIndex() + 1, _newPeFile->peHeader().getPointerToRawData(_upx0Sect->getSecSeg()->getIndex() + 1) + diff); - _newPeFile->peHeader().setSizeOfRawData(_upx0Sect->getSecSeg()->getIndex() + 1, _newPeFile->peHeader().getSizeOfRawData(_upx0Sect->getSecSeg()->getIndex() + 1) - diff); + pSectionHeader1 = imageLoader.getSectionHeader(sectionIndex + 1); + imageLoader.setSectionVirtualData(sectionIndex + 1, pSectionHeader1->VirtualAddress + diff, pSectionHeader1->VirtualSize - diff); + imageLoader.setSectionRawData(sectionIndex + 1, pSectionHeader1->PointerToRawData + diff, pSectionHeader1->SizeOfRawData - diff); } // Remove UPX1 section @@ -490,12 +492,11 @@ template void PeUpxStub::fixSizeOfSections(const DynamicBuffer& unsigned long long upx2Size = _file->getSegment(_file->getEpSegment()->getSecSeg()->getIndex() + 1)->getSize(); _rvaShift += upx2Size; - _newPeFile->peHeader().removeSection(_file->getEpSegment()->getSecSeg()->getIndex() + 1); + imageLoader.removeSection(_file->getEpSegment()->getSecSeg()->getIndex() + 1); } - _newPeFile->peHeader().removeSection(_file->getEpSegment()->getSecSeg()->getIndex()); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); - */ + imageLoader.removeSection(_file->getEpSegment()->getSecSeg()->getIndex()); + imageLoader.makeValid(); } /** @@ -509,21 +510,24 @@ template void PeUpxStub::fixSizeOfSections(const DynamicBuffer& */ template UpxExtraData PeUpxStub::parseExtraData(DynamicBuffer& unpackedData, DynamicBuffer& originalHeader) { + std::uint32_t originalHeaderOffset = 0; + std::uint32_t optionalHeaderOffset = 0; + std::uint16_t expectedMagic = _newPeFile->imageLoader().getOptionalHeader().Magic; + // First we need to find original PE header. If we have metadata, we can easily find it using unpacked data size. // However, if we don't have, we need to use heuristic that looks in the last 1024 bytes (should be more than enough) // of the unpacked data and try to find PE header signature. - std::uint32_t originalHeaderOffset = 0; if (getUpxMetadata()->isDefined()) { originalHeaderOffset = unpackedData.read(getUpxMetadata()->getUnpackedDataSize() - 4); + optionalHeaderOffset = originalHeaderOffset + sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size(); // Check whether metadata are OK if (unpackedData.read(originalHeaderOffset) != PeLib::PELIB_IMAGE_NT_SIGNATURE) originalHeaderOffset = 0; // Check if we found PE header magic - if (unpackedData.read(originalHeaderOffset + sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size()) - != PeUpxStubTraits::HeaderMagic) + if (unpackedData.read(optionalHeaderOffset) != expectedMagic) originalHeaderOffset = 0; } @@ -537,8 +541,7 @@ template UpxExtraData PeUpxStub::parseExtraData(DynamicBuffer& continue; // Check if we found PE header magic - if (unpackedData.read(i + sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size()) - != PeUpxStubTraits::HeaderMagic) + if (unpackedData.read(i + sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size()) != expectedMagic) continue; originalHeaderOffset = i; @@ -549,20 +552,20 @@ template UpxExtraData PeUpxStub::parseExtraData(DynamicBuffer& // No original PE header found if (originalHeaderOffset == 0) throw OriginalHeaderNotFoundException(); + optionalHeaderOffset = originalHeaderOffset + sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size(); // No signature present if (unpackedData.read(originalHeaderOffset) != PeLib::PELIB_IMAGE_NT_SIGNATURE) throw OriginalHeaderCorruptedException(); // Check if we found PE header magic - if (unpackedData.read(originalHeaderOffset + sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size()) - != PeUpxStubTraits::HeaderMagic) + if (unpackedData.read(optionalHeaderOffset) != expectedMagic) throw OriginalHeaderCorruptedException(); + const PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); std::uint16_t numberOfSections = unpackedData.read(originalHeaderOffset + sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + 0x2); - std::uint32_t numberOfDirectories = unpackedData.read(originalHeaderOffset + PeUpxStubTraits::NumberOfRvaAndSizesOffset); - std::uint32_t sizeOfOptionalHeader = (bits == 64) ? sizeof(PeLib::PELIB_IMAGE_OPTIONAL_HEADER64) : sizeof(PeLib::PELIB_IMAGE_OPTIONAL_HEADER32); - std::uint32_t dataDirectoriesStart = sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size() + sizeOfOptionalHeader; + std::uint32_t numberOfDirectories = unpackedData.read(originalHeaderOffset + imageLoader.getFieldOffset(PeLib::OPTHDR_NumberOfRvaAndSizes)); + std::uint32_t dataDirectoriesStart = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory); std::uint32_t sectionHeadersStart = dataDirectoriesStart + numberOfDirectories * PeLib::PELIB_IMAGE_DATA_DIRECTORY::size(); std::uint32_t sectionHeadersEnd = sectionHeadersStart + sizeof(PeLib::PELIB_IMAGE_SECTION_HEADER) * numberOfSections; @@ -618,8 +621,7 @@ template void PeUpxStub::fixPeHeader(const DynamicBuffer& origi std::uint32_t sizeOfCode = originalHeader.read(sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size() + 0x04); std::uint32_t baseOfCode = originalHeader.read(sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + PeLib::PELIB_IMAGE_FILE_HEADER::size() + 0x14); - //_newPeFile->peHeader().setSizeOfCode(sizeOfCode); - //_newPeFile->peHeader().setBaseOfCode(baseOfCode); + _newPeFile->imageLoader().setSizeOfCode(sizeOfCode, baseOfCode); } /** @@ -629,13 +631,13 @@ template void PeUpxStub::fixPeHeader(const DynamicBuffer& origi */ template void PeUpxStub::unfilterData(DynamicBuffer& unpackedData) { - /* - std::uint32_t startOffset = _newPeFile->peHeader().getBaseOfCode() - _newPeFile->peHeader().getVirtualAddress(0); - std::uint32_t size = _newPeFile->peHeader().getSizeOfCode(); + const PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + const PeLib::PELIB_SECTION_HEADER * pSectionHeader = imageLoader.getSectionHeader(0); + std::uint32_t startOffset = imageLoader.getOptionalHeader().BaseOfCode - pSectionHeader->VirtualAddress; + std::uint32_t size = imageLoader.getOptionalHeader().SizeOfCode; if (!Unfilter::run(unpackedData, _filterId, _filterParam, _filterCount, startOffset, size)) throw UnsupportedFilterException(_filterId); - */ } /** diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h index 5e81706fb..b5d55f54e 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h @@ -155,7 +155,7 @@ template class PeUpxStub : public UpxStub const DynamicBuffer& uncompressedRsrcs, const DynamicBuffer& unpackedData, std::unordered_set& visitedNodes); std::uint8_t getPackingMethod(bool trustMetadata) const; - PeLibFileType* _newPeFile; ///< Unpacked output file. + PeLib::PeFileT * _newPeFile; ///< Unpacked output file. std::uint32_t _rvaShift; ///< Size of sections UPX1 and UPX2 which are deleted and virtual addresses are shifted. bool _exportsCompressed; ///< True if the exports are compressed in the packed file, otherwise false std::vector _coffSymbolTable; ///< COFF symbol table data if any exists. From c799cdd87a54698f69ac3ba355a9d1e9dcfd12da Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Fri, 10 Jul 2020 15:59:39 +0200 Subject: [PATCH 20/34] Unpackers: Progress --- include/retdec/pelib/ImageLoader.h | 27 +- include/retdec/pelib/ImportDirectory.h | 13 +- include/retdec/pelib/PeLibAux.h | 62 +++- src/pelib/ImageLoader.cpp | 204 +++++++++++--- .../plugins/upx/pe/pe_upx_stub.cpp | 266 ++++++++---------- 5 files changed, 376 insertions(+), 196 deletions(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index caa90c461..e49d1116a 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -40,6 +40,9 @@ enum PELIB_MEMBER_TYPE : std::uint32_t OPTHDR_sizeof, OPTHDR_NumberOfRvaAndSizes, OPTHDR_DataDirectory, + OPTHDR_DataDirectory_EXPORT_Rva, + OPTHDR_DataDirectory_RSRC_Rva, + OPTHDR_DataDirectory_CONFIG_Rva, }; //----------------------------------------------------------------------------- @@ -162,8 +165,6 @@ class ImageLoader std::uint32_t getFieldOffset(PELIB_MEMBER_TYPE field) const; - bool setDataDirectory(std::uint32_t index, std::uint32_t rva, std::uint32_t size); - const PELIB_IMAGE_DOS_HEADER & getDosHeader() const { return dosHeader; @@ -184,6 +185,11 @@ class ImageLoader return (sectionIndex < sections.size()) ? §ions[sectionIndex] : nullptr; } + PELIB_SECTION_HEADER * getSectionHeader(std::size_t sectionIndex) + { + return (sectionIndex < sections.size()) ? §ions[sectionIndex] : nullptr; + } + std::uint64_t getOrdinalMask() const { return (uint64_t)1 << (getImageBitability() - 1); @@ -311,10 +317,21 @@ class ImageLoader } // Image manipulation + void setPointerToSymbolTable(std::uint32_t pointerToSymbolTable); + void setCharacteristics(std::uint32_t characteristics); + void setAddressOfEntryPoint(std::uint32_t addressOfEntryPoint); void setSizeOfCode(std::uint32_t sizeOfCode, std::uint32_t baseOfCode = UINT32_MAX); - void setSectionVirtualData(std::size_t sectionIndex, std::uint32_t VirtualAddress, std::uint32_t VirtualSize = UINT32_MAX); - void setSectionRawData(std::size_t sectionIndex, std::uint32_t PointerToRawData, std::uint32_t SizeOfRawData = UINT32_MAX); - int removeSection(std::size_t sectionIndex); + void setDataDirectory(std::uint32_t entryIndex, std::uint32_t VirtualAddress, std::uint32_t Size = UINT32_MAX); + + PELIB_IMAGE_SECTION_HEADER * addSection(const char * name, std::uint32_t size); + void calcNewSectionAddresses(std::uint32_t & Rva, std::uint32_t & RawOffset); + void setSectionName(std::size_t sectionIndex, const char * newName); + void setSectionVirtualRange(std::size_t sectionIndex, std::uint32_t VirtualAddress, std::uint32_t VirtualSize = UINT32_MAX); + void setSectionRawDataRange(std::size_t sectionIndex, std::uint32_t PointerToRawData, std::uint32_t SizeOfRawData = UINT32_MAX); + void setSectionCharacteristics(std::size_t sectionIndex, std::uint32_t Characteristics); + int splitSection(std::size_t sectionIndex, const std::string & prevSectName, const std::string & nextSectName, std::uint32_t splitOffset); + void enlargeLastSection(std::uint32_t sectionSize); + int removeSection(std::size_t sizeIncrement); void makeValid(); int setLoaderError(LoaderError ldrErr); diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index 92fa03586..902d7c697 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -146,7 +146,7 @@ namespace PeLib /// Remove a function from the import directory. int removeFunction(const std::string& strFilename, std::uint16_t wHint); // EXPORT _byHint /// Returns the size of the current import directory. - unsigned int size() const; // EXPORT + unsigned int calculateSize(std::uint32_t pointerSize) const; // EXPORT /// Writes the import directory to a file. int write(const std::string& strFilename, unsigned int uiOffset, unsigned int uiRva); // EXPORT @@ -1035,15 +1035,18 @@ namespace PeLib } /** - * Returns the size of the import directory. + * Calculates size of import directory that would be written to a PE file. * @return Size of the import directory. **/ inline - unsigned int ImportDirectory::size() const + std::uint32_t ImportDirectory::calculateSize(std::uint32_t pointerSize) const { + std::uint32_t totalSize = 0; + // Only the descriptors of m_vOldiid must be rebuilt, not the data they point to. - return std::accumulate(m_vNewiid.begin(), m_vNewiid.end(), 0, accumulate) - + (m_vOldiid.size() + 1) * PELIB_IMAGE_IMPORT_DESCRIPTOR::size(); + for(const auto & element : m_vNewiid) + totalSize += element.calculateSize(pointerSize); + return totalSize + (m_vOldiid.size() + 1) * PELIB_IMAGE_IMPORT_DESCRIPTOR::size(); } /** diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index d3d6a23b6..18acc7de9 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -806,6 +806,20 @@ namespace PeLib struct PELIB_IMAGE_SECTION_HEADER { + PELIB_IMAGE_SECTION_HEADER() + { + memset(Name, 0, sizeof(Name)); + VirtualSize = 0; + VirtualAddress = 0; + SizeOfRawData = 0; + PointerToRawData = 0; + PointerToRelocations = 0; + PointerToLinenumbers = 0; + NumberOfRelocations = 0; + NumberOfLinenumbers = 0; + Characteristics = 0; + } + std::uint8_t Name[PELIB_IMAGE_SIZEOF_SHORT_NAME]; std::uint32_t VirtualSize; std::uint32_t VirtualAddress; @@ -820,11 +834,42 @@ namespace PeLib struct PELIB_SECTION_HEADER : public PELIB_IMAGE_SECTION_HEADER { + void setName(const char * newName) + { + // Copy the name to the fixed_length name + memset(Name, 0, PELIB_IMAGE_SIZEOF_SHORT_NAME); + for(std::size_t i = 0; i < PELIB_IMAGE_SIZEOF_SHORT_NAME; i++) + { + if(newName[i] == 0) + break; + Name[i] = newName[i]; + } + + // Also put it to the string + sectionName = newName; + } + const std::string & getName() const { return sectionName; } + void setVirtualRange(std::uint32_t newVirtualAddress, std::uint32_t newVirtualSize) + { + if(newVirtualAddress != UINT32_MAX) + VirtualAddress = newVirtualAddress; + if(newVirtualSize != UINT32_MAX) + VirtualSize = newVirtualSize; + } + + void setRawDataRange(std::uint32_t newPointerToRawData, std::uint32_t newSizeOfRawData) + { + if(newPointerToRawData != UINT32_MAX) + PointerToRawData = newPointerToRawData; + if(newSizeOfRawData != UINT32_MAX) + SizeOfRawData = newSizeOfRawData; + } + static const std::size_t size() { return sizeof(PELIB_IMAGE_SECTION_HEADER); @@ -1059,6 +1104,11 @@ namespace PeLib { return isEqualNc(fname, strFunctionName); } + + std::uint32_t calculateSize(std::uint32_t pointerSize) const + { + return pointerSize + fname.size() + 1 + sizeof(hint); + } }; struct PELIB_DELAY_IMPORT @@ -1086,14 +1136,14 @@ namespace PeLib /// All first thunk value of an imported DLL. std::vector firstthunk; - inline std::size_t size() const + inline std::uint32_t calculateSize(std::uint32_t pointerSize) const { - return sizeof(PELIB_IMAGE_IMPORT_DESCRIPTOR) + // descriptor - name.size() + 1 + // dllname - sizeof(PELIB_THUNK_DATA) * originalfirstthunk.size() + // thunks (PeLib uses only one thunk) - sizeof(PELIB_IMAGE_THUNK_DATA); // zero-termination - } + std::uint32_t totalSize = sizeof(PELIB_IMAGE_IMPORT_DESCRIPTOR) + name.size() + 1; // descriptor + dllname + for(const auto & element : originalfirstthunk) + totalSize += element.calculateSize(pointerSize); + return totalSize + pointerSize; // Add zero-termination + } bool operator==(std::string strFilename) const { diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 7f4113326..f01fa4dca 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -52,7 +52,7 @@ uint8_t PeLib::ImageLoader::ImageProtectionArray[16] = // Returns the fixed size of optional header (without Data Directories) template -std::uint32_t getCopySizeOfOptionalHeader() +uint32_t getCopySizeOfOptionalHeader() { return offsetof(OPT_HDR, DataDirectory); } @@ -454,10 +454,10 @@ uint32_t PeLib::ImageLoader::getFileOffsetFromRva(uint32_t rva) const return rva; } -std::uint32_t PeLib::ImageLoader::getFieldOffset(PELIB_MEMBER_TYPE field) const +uint32_t PeLib::ImageLoader::getFieldOffset(PELIB_MEMBER_TYPE field) const { - std::uint32_t imageBitability = getImageBitability(); - std::uint32_t fieldOffset; + uint32_t imageBitability = getImageBitability(); + uint32_t fieldOffset; switch (field) { @@ -471,24 +471,24 @@ std::uint32_t PeLib::ImageLoader::getFieldOffset(PELIB_MEMBER_TYPE field) const case OPTHDR_DataDirectory: fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset; - } - return UINT32_MAX; -} + case OPTHDR_DataDirectory_EXPORT_Rva: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT * sizeof(PELIB_IMAGE_DATA_DIRECTORY); -bool PeLib::ImageLoader::setDataDirectory(std::uint32_t index, std::uint32_t rva, std::uint32_t size) -{ - // Make sure that there is enough data directory entries - if(optionalHeader.NumberOfRvaAndSizes < index) - optionalHeader.NumberOfRvaAndSizes = index; + case OPTHDR_DataDirectory_RSRC_Rva: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE * sizeof(PELIB_IMAGE_DATA_DIRECTORY); - // Set the data directory entry - optionalHeader.DataDirectory[index].VirtualAddress = rva; - optionalHeader.DataDirectory[index].Size = size; - return true; + case OPTHDR_DataDirectory_CONFIG_Rva: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG * sizeof(PELIB_IMAGE_DATA_DIRECTORY); + } + + return UINT32_MAX; } -std::uint32_t PeLib::ImageLoader::getRealPointerToRawData(std::size_t sectionIndex) const +uint32_t PeLib::ImageLoader::getRealPointerToRawData(size_t sectionIndex) const { if(sectionIndex >= sections.size()) return UINT32_MAX; @@ -520,6 +520,21 @@ uint32_t PeLib::ImageLoader::getImageProtection(uint32_t sectionCharacteristics) //----------------------------------------------------------------------------- // Manipulation with section data +void PeLib::ImageLoader::setPointerToSymbolTable(uint32_t pointerToSymbolTable) +{ + fileHeader.PointerToSymbolTable = pointerToSymbolTable; +} + +void PeLib::ImageLoader::setCharacteristics(uint32_t characteristics) +{ + fileHeader.Characteristics = characteristics; +} + +void PeLib::ImageLoader::setAddressOfEntryPoint(uint32_t addressOfEntryPoint) +{ + optionalHeader.AddressOfEntryPoint = addressOfEntryPoint; +} + void PeLib::ImageLoader::setSizeOfCode(uint32_t sizeOfCode, uint32_t baseOfCode) { if(sizeOfCode != UINT32_MAX) @@ -528,29 +543,144 @@ void PeLib::ImageLoader::setSizeOfCode(uint32_t sizeOfCode, uint32_t baseOfCode) optionalHeader.BaseOfCode = baseOfCode; } -void PeLib::ImageLoader::setSectionVirtualData(size_t sectionIndex, uint32_t VirtualAddress, uint32_t VirtualSize) +void PeLib::ImageLoader::setDataDirectory(uint32_t entryIndex, uint32_t VirtualAddress, uint32_t Size) { - if(sectionIndex < sections.size()) + if(entryIndex < PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES) { - PELIB_SECTION_HEADER & section = sections[sectionIndex]; + // Make sure there is enough entries + if(entryIndex >= optionalHeader.NumberOfRvaAndSizes) + optionalHeader.NumberOfRvaAndSizes = entryIndex + 1; if(VirtualAddress != UINT32_MAX) - section.VirtualAddress = VirtualAddress; - if(VirtualSize != UINT32_MAX) - section.VirtualSize = VirtualSize; + optionalHeader.DataDirectory[entryIndex].VirtualAddress = VirtualAddress; + if(Size != UINT32_MAX) + optionalHeader.DataDirectory[entryIndex].Size = Size; } } -void PeLib::ImageLoader::setSectionRawData(size_t sectionIndex, uint32_t PointerToRawData, uint32_t SizeOfRawData) +PeLib::PELIB_IMAGE_SECTION_HEADER * PeLib::ImageLoader::addSection(const char * name, uint32_t sectionSize) +{ + if(optionalHeader.FileAlignment == 0) + return nullptr; + if(optionalHeader.SectionAlignment == 0) + return nullptr; + if(sections.size() >= UINT16_MAX) + return nullptr; + + // Calculate the new RVA and file offset + std::uint32_t Rva = 0; + std::uint32_t Raw = 0; + calcNewSectionAddresses(Rva, Raw); + + // Create new section + PELIB_SECTION_HEADER SectHdr; + SectHdr.setName(name); + SectHdr.setVirtualRange(Rva, AlignToSize(sectionSize, optionalHeader.SectionAlignment)); + SectHdr.setRawDataRange(Raw, AlignToSize(sectionSize, optionalHeader.FileAlignment)); + SectHdr.Characteristics = PELIB_IMAGE_SCN_MEM_WRITE | PELIB_IMAGE_SCN_MEM_READ | PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA | PELIB_IMAGE_SCN_CNT_CODE; + sections.push_back(SectHdr); + + // Return the header of the last section + return getSectionHeader(sections.size() - 1); +} + +void PeLib::ImageLoader::calcNewSectionAddresses(uint32_t & Rva, std::uint32_t & RawOffset) +{ + uint32_t NewRawOffset = optionalHeader.SizeOfHeaders; + uint32_t NewRva = optionalHeader.SizeOfHeaders; + + for(const auto & section : sections) + { + if((section.VirtualAddress + section.VirtualSize) > NewRva) + NewRva = section.VirtualAddress + section.VirtualSize; + if((section.PointerToRawData + section.SizeOfRawData) > NewRawOffset) + NewRawOffset = section.PointerToRawData + section.SizeOfRawData; + } + + RawOffset = AlignToSize(NewRawOffset, optionalHeader.FileAlignment); + Rva = AlignToSize(NewRva, optionalHeader.SectionAlignment); +} + +void PeLib::ImageLoader::setSectionName(std::size_t sectionIndex, const char * newName) +{ + if(sectionIndex < sections.size()) + { + sections[sectionIndex].setName(newName); + } +} + +void PeLib::ImageLoader::setSectionVirtualRange(size_t sectionIndex, uint32_t VirtualAddress, uint32_t VirtualSize) +{ + if(sectionIndex < sections.size()) + { + sections[sectionIndex].setVirtualRange(VirtualAddress, VirtualSize); + } +} + +void PeLib::ImageLoader::setSectionRawDataRange(size_t sectionIndex, uint32_t PointerToRawData, uint32_t SizeOfRawData) { if(sectionIndex < sections.size()) { - PELIB_SECTION_HEADER & section = sections[sectionIndex]; + sections[sectionIndex].setRawDataRange(PointerToRawData, SizeOfRawData); + } +} + +void PeLib::ImageLoader::setSectionCharacteristics(size_t sectionIndex, uint32_t Characteristics) +{ + if(sectionIndex < sections.size()) + { + sections[sectionIndex].Characteristics = Characteristics; + } +} + +int PeLib::ImageLoader::splitSection(size_t sectionIndex, const std::string & prevSectName, const std::string & nextSectName, uint32_t splitOffset) +{ + if(!optionalHeader.FileAlignment) + return PeLib::ERROR_NO_FILE_ALIGNMENT; + if(!optionalHeader.SectionAlignment) + return PeLib::ERROR_NO_SECTION_ALIGNMENT; + + // Index needs to be in the range <0, NUMBER OF SECTIONS) + if(sectionIndex > sections.size()) + return PeLib::ERROR_ENTRY_NOT_FOUND; + + // Offset at which the section is going to be split must be multiple of section alignment + if(splitOffset & (getSectionAlignment() - 1)) + return PeLib::ERROR_NOT_ENOUGH_SPACE; + + // Do not allow to split if the offset of split is greater than the size of the section + // Nor do allow the section with size 0 to be created + if(splitOffset >= getSectionHeader(sectionIndex)->VirtualSize) + return PeLib::ERROR_NOT_ENOUGH_SPACE; + + // Move every section located after the inserted section by one position + sections.resize(sections.size() + 1); + for(int i = sections.size() - 2; i >= sectionIndex + 1; --i) + sections[i + 1] = sections[i]; + + uint32_t originalSize = getSectionHeader(sectionIndex)->SizeOfRawData; + + // Setup the first of the new sections + setSectionName(sectionIndex, prevSectName.c_str()); + setSectionRawDataRange(sectionIndex, UINT32_MAX, splitOffset); + setSectionVirtualRange(sectionIndex, UINT32_MAX, splitOffset); + + // Setup the second of the new sections + setSectionName(sectionIndex + 1, nextSectName.c_str()); + setSectionRawDataRange(sectionIndex + 1, sections[sectionIndex].PointerToRawData + splitOffset, originalSize - splitOffset); + setSectionVirtualRange(sectionIndex + 1, sections[sectionIndex].VirtualAddress + splitOffset, originalSize - splitOffset); + setSectionCharacteristics(sectionIndex + 1, PeLib::PELIB_IMAGE_SCN_MEM_WRITE | PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA | PeLib::PELIB_IMAGE_SCN_CNT_CODE); + return PeLib::ERROR_NONE; +} + +void PeLib::ImageLoader::enlargeLastSection(uint32_t sizeIncrement) +{ + if(sections.size()) + { + auto & lastSection = sections[sections.size() - 1]; - if(PointerToRawData != UINT32_MAX) - section.PointerToRawData = PointerToRawData; - if(SizeOfRawData != UINT32_MAX) - section.SizeOfRawData = SizeOfRawData; + lastSection.VirtualSize = lastSection.SizeOfRawData = AlignToSize(lastSection.SizeOfRawData + sizeIncrement, getFileAlignment()); + optionalHeader.SizeOfImage = lastSection.VirtualAddress + lastSection.VirtualSize; } } @@ -567,8 +697,8 @@ int PeLib::ImageLoader::removeSection(size_t sectionIndex) { pSectionHeader = getSectionHeader(i); - setSectionVirtualData(i, pSectionHeader->VirtualAddress - virtualDiff); - setSectionRawData(i, pSectionHeader->PointerToRawData - rawDiff); + setSectionVirtualRange(i, pSectionHeader->VirtualAddress - virtualDiff); + setSectionRawDataRange(i, pSectionHeader->PointerToRawData - rawDiff); } sections.erase(sections.begin() + sectionIndex); @@ -588,7 +718,7 @@ void PeLib::ImageLoader::makeValid() // Fix the IMAGE_FILE_HEADER fileHeader.Machine = (imageBitability == 64) ? PELIB_IMAGE_FILE_MACHINE_AMD64 : PELIB_IMAGE_FILE_MACHINE_I386; - fileHeader.NumberOfSections = (std::uint16_t)sections.size(); + fileHeader.NumberOfSections = (uint16_t)sections.size(); fileHeader.SizeOfOptionalHeader = getFieldOffset(OPTHDR_sizeof); fileHeader.Characteristics = (fileHeader.Characteristics != 0) ? fileHeader.Characteristics : PELIB_IMAGE_FILE_EXECUTABLE_IMAGE | PELIB_IMAGE_FILE_32BIT_MACHINE; @@ -615,7 +745,7 @@ void PeLib::ImageLoader::makeValid() // If the size of headers changed, we need to move all section data further if(dwOffsetDiff) - setSectionRawData(i, pSectionHeader->PointerToRawData + dwOffsetDiff); + setSectionRawDataRange(i, pSectionHeader->PointerToRawData + dwOffsetDiff); } // Fixup the size of image @@ -820,7 +950,7 @@ uint32_t PeLib::ImageLoader::readWriteImage(void * buffer, uint32_t rva, uint32_ return bytesRead; } -uint32_t PeLib::ImageLoader::readWriteImageFile(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead, bool bReadOperation) +uint32_t PeLib::ImageLoader::readWriteImageFile(void * buffer, uint32_t rva, uint32_t bytesToRead, bool bReadOperation) { uint32_t fileOffset = getFileOffsetFromRva(rva); @@ -1349,7 +1479,7 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) return ERROR_NONE; } -int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std::string & sectionName, const std::uint8_t * Name) +int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std::string & sectionName, const uint8_t * Name) { // If the section name is in format of "/12345", then the section name is actually in the symbol table // Sample: 2e9c671b8a0411f2b397544b368c44d7f095eb395779de0ad1ac946914dfa34c @@ -1425,7 +1555,7 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) // Read and verify all section headers for(uint16_t i = 0; i < fileHeader.NumberOfSections; i++) { - PELIB_SECTION_HEADER sectHdr{}; + PELIB_SECTION_HEADER sectHdr; // Capture one section header if((filePtr + sizeof(PELIB_IMAGE_SECTION_HEADER)) > fileEnd) @@ -2058,7 +2188,7 @@ bool PeLib::ImageLoader::isImageMappedOk() const return true; } -bool PeLib::ImageLoader::isValidImageBlock(std::uint32_t Rva, std::uint32_t Size) const +bool PeLib::ImageLoader::isValidImageBlock(uint32_t Rva, uint32_t Size) const { if(Rva >= optionalHeader.SizeOfImage || Size >= optionalHeader.SizeOfImage) return false; diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp index 8b7f1bd82..904abf61e 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp @@ -457,14 +457,14 @@ template void PeUpxStub::fixSizeOfSections(const DynamicBuffer& // Always make sure that UPX0 points to same raw pointer as UPX1 before we process sections // This allows us to use much more simpler algorithm, than calculating with all possible positions of UPX0 pSectionHeader = imageLoader.getSectionHeader(1); - imageLoader.setSectionRawData(0, pSectionHeader->PointerToRawData); + imageLoader.setSectionRawDataRange(0, pSectionHeader->PointerToRawData); // Set the proper raw size for UPX0 section, thus moving pointer to raw data of all following sections pSectionHeader = imageLoader.getSectionHeader(sectionIndex); std::uint32_t diff = pSectionHeader->VirtualSize - pSectionHeader->SizeOfRawData; - imageLoader.setSectionRawData(sectionIndex, UINT32_MAX, pSectionHeader->VirtualSize); + imageLoader.setSectionRawDataRange(sectionIndex, UINT32_MAX, pSectionHeader->VirtualSize); for (std::uint32_t i = sectionIndex + 1; i < imageLoader.getNumberOfSections(); ++i) - imageLoader.setSectionRawData(i, imageLoader.getSectionHeader(i)->PointerToRawData + diff); + imageLoader.setSectionRawDataRange(i, imageLoader.getSectionHeader(i)->PointerToRawData + diff); // If the section UPX0 is lesser than all the unpacked data, we need to move boundaries of UPX0/UPX1 section // Since UPX0 and UPX1 have continuous address space, we can just resize UPX0 and shrink UPX1 @@ -474,12 +474,12 @@ template void PeUpxStub::fixSizeOfSections(const DynamicBuffer& std::uint32_t newSize = retdec::utils::alignUp(unpackedData.getRealDataSize(), imageLoader.getSectionAlignment()); diff = newSize - pSectionHeader->VirtualSize; - imageLoader.setSectionVirtualData(sectionIndex, UINT32_MAX, pSectionHeader->VirtualSize + diff); - imageLoader.setSectionRawData(sectionIndex, UINT32_MAX, pSectionHeader->SizeOfRawData + diff); + imageLoader.setSectionVirtualRange(sectionIndex, UINT32_MAX, pSectionHeader->VirtualSize + diff); + imageLoader.setSectionRawDataRange(sectionIndex, UINT32_MAX, pSectionHeader->SizeOfRawData + diff); pSectionHeader1 = imageLoader.getSectionHeader(sectionIndex + 1); - imageLoader.setSectionVirtualData(sectionIndex + 1, pSectionHeader1->VirtualAddress + diff, pSectionHeader1->VirtualSize - diff); - imageLoader.setSectionRawData(sectionIndex + 1, pSectionHeader1->PointerToRawData + diff, pSectionHeader1->SizeOfRawData - diff); + imageLoader.setSectionVirtualRange(sectionIndex + 1, pSectionHeader1->VirtualAddress + diff, pSectionHeader1->VirtualSize - diff); + imageLoader.setSectionRawDataRange(sectionIndex + 1, pSectionHeader1->PointerToRawData + diff, pSectionHeader1->SizeOfRawData - diff); } // Remove UPX1 section @@ -487,12 +487,13 @@ template void PeUpxStub::fixSizeOfSections(const DynamicBuffer& _rvaShift = upx1Size; // Not every file has UPX2 section - if (_file->getSegment(_file->getEpSegment()->getSecSeg()->getIndex() + 1) != nullptr) + sectionIndex = _file->getEpSegment()->getSecSeg()->getIndex() + 1; + if (_file->getSegment(sectionIndex) != nullptr) { - unsigned long long upx2Size = _file->getSegment(_file->getEpSegment()->getSecSeg()->getIndex() + 1)->getSize(); + unsigned long long upx2Size = _file->getSegment(sectionIndex)->getSize(); _rvaShift += upx2Size; - imageLoader.removeSection(_file->getEpSegment()->getSecSeg()->getIndex() + 1); + imageLoader.removeSection(sectionIndex); } imageLoader.removeSection(_file->getEpSegment()->getSecSeg()->getIndex()); @@ -649,18 +650,15 @@ template void PeUpxStub::unfilterData(DynamicBuffer& unpackedDa */ template void PeUpxStub::fixImports(const DynamicBuffer& unpackedData, const UpxExtraData& extraData, const DynamicBuffer& ilt) { - /* + PeLib::PELIB_IMAGE_SECTION_HEADER * pSectionHeader; + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + if (extraData.getImportsOffset() == 0) { - _newPeFile->peHeader().setIddImportRva(0); - _newPeFile->peHeader().setIddImportSize(0); + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT, 0, 0); return; } - // Make sure there is enough data directories - _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IAT) + 1)); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); - if (unpackedData.getRealDataSize() <= extraData.getImportsOffset()) throw InvalidDataDirectoryException("Imports"); @@ -681,7 +679,7 @@ template void PeUpxStub::fixImports(const DynamicBuffer& unpack // ILT is read for the library name std::string libraryName = ilt.readString(iltOffset); - std::uint32_t firstThunk = importHints.read(readPos) + _newPeFile->peHeader().getVirtualAddress(_upx0Sect->getSecSeg()->getIndex()); + std::uint32_t firstThunk = importHints.read(readPos) + imageLoader.getSectionHeader(_upx0Sect->getSecSeg()->getIndex())->VirtualAddress; lowestFirstThunk = std::min(lowestFirstThunk, firstThunk); readPos += 4; @@ -708,25 +706,34 @@ template void PeUpxStub::fixImports(const DynamicBuffer& unpack } // Sets the proper FirstThunk for new record in import directory - if (_newPeFile->impDir().getFileIndex(libraryName, PeLib::NEWDIR) != static_cast(-1)) - _newPeFile->impDir().setFirstThunk(_newPeFile->impDir().getFileIndex(libraryName, PeLib::NEWDIR), PeLib::NEWDIR, firstThunk); + std::uint32_t fileIndex = _newPeFile->impDir().getFileIndex(libraryName, PeLib::NEWDIR); + if (fileIndex != static_cast(-1)) + _newPeFile->impDir().setFirstThunk(fileIndex, PeLib::NEWDIR, firstThunk); iltOffset = importHints.read(readPos); readPos += 4; } // Align the size of the impots to the file alignment to properly create the new section - std::uint32_t importSectSize = retdec::utils::alignUp(_newPeFile->impDir().size(), _newPeFile->peHeader().getFileAlignment()); + std::uint32_t pointerSize = imageLoader.getPointerSize(); + std::uint32_t importSectSize = retdec::utils::alignUp(_newPeFile->impDir().calculateSize(pointerSize), imageLoader.getFileAlignment()); // Create the .imports section after all other sections with the ILT - _newPeFile->peHeader().addSection("gu_idata", importSectSize); - _newPeFile->peHeader().setCharacteristics(_newPeFile->peHeader().calcNumberOfSections() - 1, PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA); - _newPeFile->peHeader().setIddImportRva(_newPeFile->peHeader().getVirtualAddress(_newPeFile->peHeader().calcNumberOfSections() - 1)); - _newPeFile->peHeader().setIddImportSize(importSectSize); - _newPeFile->peHeader().setIddIatRva(lowestFirstThunk); - _newPeFile->peHeader().setIddIatSize(4); // @todo Probably set proper size??? - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); - */ + pSectionHeader = imageLoader.addSection("gu_idata", importSectSize); + if(pSectionHeader != nullptr) + { + // Set the section characteristics + pSectionHeader->Characteristics = PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA; + + // Setup the import data directory + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT, pSectionHeader->VirtualAddress, importSectSize); + + // Setup the IAT. @todo Probably set proper size??? + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IAT, lowestFirstThunk, 4); + + // Make sure that the image loader is valid + imageLoader.makeValid(); + } } /** @@ -741,7 +748,6 @@ template void PeUpxStub::fixImports(const DynamicBuffer& unpack */ template void PeUpxStub::fixRelocations(DynamicBuffer& unpackedData, const UpxExtraData& extraData) { - /* if (extraData.getRelocationsOffset() == 0) return; @@ -749,17 +755,13 @@ template void PeUpxStub::fixRelocations(DynamicBuffer& unpacked throw InvalidDataDirectoryException("Relocations"); DynamicBuffer relocHints = DynamicBuffer(unpackedData, extraData.getRelocationsOffset(), unpackedData.getRealDataSize() - extraData.getRelocationsOffset()); - - // Make sure there is enough data directories - _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC) + 1)); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + std::uint32_t upx0sectionRVA = imageLoader.getSectionHeader(_upx0Sect->getSecSeg()->getIndex())->VirtualAddress; // We will solve relocations in place, so all relocations will be fixed statically and app will be marked as RELOCS_STRIPPED // This way, it is not going to be relocated and we don't have to repair the whole reloc directory - _newPeFile->peHeader().setCharacteristics(_newPeFile->peHeader().getCharacteristics() | PeLib::PELIB_IMAGE_FILE_RELOCS_STRIPPED); - _newPeFile->peHeader().setIddBaseRelocRva(0); - _newPeFile->peHeader().setIddBaseRelocSize(0); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + imageLoader.setCharacteristics(imageLoader.getCharacteristics() | PeLib::PELIB_IMAGE_FILE_RELOCS_STRIPPED); + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC, 0, 0); std::uint32_t readPos = 0; std::uint32_t hint; @@ -776,12 +778,11 @@ template void PeUpxStub::fixRelocations(DynamicBuffer& unpacked std::uint32_t relocAddr = unpackedData.read(addr, extraData.areRelocationsBigEndian() ? Endianness::BIG : unpackedData.getEndianness()); // Add virtual address base of unpacked data section to get the absolute address - relocAddr += _newPeFile->peHeader().getImageBase() + _newPeFile->peHeader().getVirtualAddress(_upx0Sect->getSecSeg()->getIndex()); + relocAddr += imageLoader.getImageBase() + upx0sectionRVA; // Rewrite the relocated address unpackedData.write(relocAddr, addr); } - */ } /** @@ -792,26 +793,21 @@ template void PeUpxStub::fixRelocations(DynamicBuffer& unpacked */ template void PeUpxStub::fixTls(const DynamicBuffer& originalHeader) { - /* - // Make sure there is enough data directories - _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_TLS) + 1)); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); // Read original TLS data directory std::uint32_t tlsRva = originalHeader.read(PeUpxStubTraits::TlsDirectoryRvaOffset); std::uint32_t tlsSize = originalHeader.read(PeUpxStubTraits::TlsDirectorySizeOffset); - _newPeFile->peHeader().setIddTlsRva(tlsRva); - _newPeFile->peHeader().setIddTlsSize(tlsSize); + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_TLS, tlsRva, tlsSize); if (tlsRva == 0) return; - if (tlsRva >= _newPeFile->peHeader().getSizeOfImage()) + if (tlsRva >= imageLoader.getSizeOfImage()) throw InvalidDataDirectoryException("TLS"); upx_plugin->log("Original TLS directory found at RVA 0x", std::hex, tlsRva, " with size 0x", tlsSize, std::dec, "."); - */ } /** @@ -821,13 +817,13 @@ template void PeUpxStub::fixTls(const DynamicBuffer& originalHe */ template void PeUpxStub::fixOep(const DynamicBuffer& originalHeader) { + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + // At the oepOffset is operand of JMP instruction, so the address is relative to the jump instruction // We need to take the address of the JMP instruction + its size and add this relative address // Everything needs to be calculated in virtual addresses, not RVAs since we don't want to get into negative numbers - //_newPeFile->peHeader().setAddressOfEntryPoint(originalHeader.read(0x28)); - //_newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); - - //upx_plugin->log("Original entry point address set to 0x", std::hex, _newPeFile->peHeader().getAddressOfEntryPoint(), std::dec, "."); + imageLoader.setAddressOfEntryPoint(originalHeader.read(0x28)); + upx_plugin->log("Original entry point address set to 0x", std::hex, imageLoader.getAddressOfEntryPoint(), std::dec, "."); } /** @@ -838,37 +834,32 @@ template void PeUpxStub::fixOep(const DynamicBuffer& originalHe */ template void PeUpxStub::fixExports(const DynamicBuffer& originalHeader) { - /* + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + std::uint32_t exportDirOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_EXPORT_Rva); // Assumption is that exports are compressed _exportsCompressed = true; - // Make sure there is enough data directories - _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT) + 1)); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); - // Read original exports data directory - std::uint32_t exportsRva = std::min(originalHeader.read(PeUpxStubTraits::ExportsDirectoryRvaOffset), _newPeFile->peHeader().getIddExportRva()); - std::uint32_t exportsSize = std::min(originalHeader.read(PeUpxStubTraits::ExportsDirectorySizeOffset), _newPeFile->peHeader().getIddExportSize()); - std::uint32_t oldExportsRva =_newPeFile->peHeader().getIddExportRva(); + std::uint32_t exportsRva = std::min(originalHeader.read(exportDirOffset), imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT)); + std::uint32_t exportsSize = std::min(originalHeader.read(exportDirOffset + 4), imageLoader.getDataDirSize(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT)); + std::uint32_t oldExportsRva = imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT); // Set proper RVA and size for export directory - _newPeFile->peHeader().setIddExportRva(exportsRva); - _newPeFile->peHeader().setIddExportSize(exportsSize); - + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT, exportsRva, exportsSize); if ((exportsRva == 0) || (exportsRva == oldExportsRva)) return; // If we got here, we know that exports are not compressed _exportsCompressed = false; - if (exportsRva >= _newPeFile->peHeader().getSizeOfImage()) + if (exportsRva >= imageLoader.getSizeOfImage()) throw InvalidDataDirectoryException("Exports"); upx_plugin->log("Original exports directory found at RVA 0x", std::hex, exportsRva, " with size 0x", exportsSize, std::dec, "."); // Calculate the offset of exports in UPX2 section - std::uint32_t exportsVa = _newPeFile->peHeader().rvaToVa(oldExportsRva); + std::uint32_t exportsVa = (std::uint32_t)(imageLoader.getImageBase() + oldExportsRva); const retdec::loader::Segment* exportsSection = _file->getSegmentFromAddress(exportsVa); if (exportsSection == nullptr) throw InvalidDataDirectoryException("Exports"); @@ -897,20 +888,20 @@ template void PeUpxStub::fixExports(const DynamicBuffer& origin _newPeFile->expDir().setAddressOfNameOrdinals(0); // This value doesn't matter, PeLib will put it into its own position // Load the export directory name (this is usually library name) - std::uint32_t exportsNameOffset = _newPeFile->peHeader().rvaToVa(exportsData.read(12)) - exportsSection->getAddress() - exportsOffset; + std::uint32_t exportsNameOffset = imageLoader.getImageBase() + exportsData.read(12) - exportsSection->getAddress() - exportsOffset; _newPeFile->expDir().setNameString(exportsData.readString(exportsNameOffset)); // Calculate the offset of function addresses, function names and ordinals - std::uint32_t exportsAddressesOffset = _newPeFile->peHeader().rvaToVa(exportsData.read(28)) - exportsSection->getAddress() - exportsOffset; - std::uint32_t exportsNamesOffset = _newPeFile->peHeader().rvaToVa(exportsData.read(32)) - exportsSection->getAddress() - exportsOffset; - std::uint32_t exportsOrdinalsOffset = _newPeFile->peHeader().rvaToVa(exportsData.read(36)) - exportsSection->getAddress() - exportsOffset; + std::uint32_t exportsAddressesOffset = imageLoader.getImageBase() + exportsData.read(28) - exportsSection->getAddress() - exportsOffset; + std::uint32_t exportsNamesOffset = imageLoader.getImageBase() + exportsData.read(32) - exportsSection->getAddress() - exportsOffset; + std::uint32_t exportsOrdinalsOffset = imageLoader.getImageBase() + exportsData.read(36) - exportsSection->getAddress() - exportsOffset; for (std::uint32_t i = 0; i < _newPeFile->expDir().getNumberOfFunctions(); ++i) { if (exportsNamesOffset + i * 4 >= exportsData.getRealDataSize()) throw InvalidDataDirectoryException("Exports"); // Calculate the offset of name - std::uint32_t nameOffset = _newPeFile->peHeader().rvaToVa(exportsData.read(exportsNamesOffset + i * 4)) - exportsSection->getAddress() - exportsOffset; + std::uint32_t nameOffset = imageLoader.getImageBase() + exportsData.read(exportsNamesOffset + i * 4) - exportsSection->getAddress() - exportsOffset; if (nameOffset >= exportsData.getRealDataSize()) throw InvalidDataDirectoryException("Exports"); @@ -924,7 +915,6 @@ template void PeUpxStub::fixExports(const DynamicBuffer& origin _newPeFile->expDir().addFunction(name, exportsData.read(exportsAddressesOffset + i * 4)); _newPeFile->expDir().setFunctionOrdinal(i, exportsData.read(exportsOrdinalsOffset + i * 2)); } - */ } /** @@ -935,26 +925,21 @@ template void PeUpxStub::fixExports(const DynamicBuffer& origin */ template void PeUpxStub::fixLoadConfiguration(const DynamicBuffer& originalHeader) { - /* - // Make sure there is enough data directories - _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) + 1)); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + std::uint32_t configDirOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_CONFIG_Rva); // Read original Load Configuration data directory - std::uint32_t loadConfigRva = originalHeader.read(PeUpxStubTraits::LoadConfigDirectoryRvaOffset); - std::uint32_t loadConfigSize = originalHeader.read(PeUpxStubTraits::LoadConfigDirectorySizeOffset); - - _newPeFile->peHeader().setIddLoadConfigRva(loadConfigRva); - _newPeFile->peHeader().setIddLoadConfigSize(loadConfigSize); + std::uint32_t loadConfigRva = originalHeader.read(configDirOffset); + std::uint32_t loadConfigSize = originalHeader.read(configDirOffset + 4); + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, loadConfigRva, loadConfigSize); if (loadConfigRva == 0) return; - if (loadConfigRva >= _newPeFile->peHeader().getSizeOfImage()) + if (loadConfigRva >= imageLoader.getSizeOfImage()) throw InvalidDataDirectoryException("Load configuration"); upx_plugin->log("Original load configuration directory found at RVA 0x", std::hex, loadConfigRva, " with size 0x", loadConfigSize, std::dec, "."); - */ } /** @@ -968,26 +953,25 @@ template void PeUpxStub::fixLoadConfiguration(const DynamicBuff */ template void PeUpxStub::fixResources(const DynamicBuffer& unpackedData, const DynamicBuffer& originalHeader) { -/* - // Make sure there is enough data directories - _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE) + 1)); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + PeLib::PELIB_IMAGE_SECTION_HEADER * pSectionHeader; + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + std::uint32_t rsrcDirOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_RSRC_Rva); // Check whether file contains resources - std::uint32_t uncompressedRsrcRva = _newPeFile->peHeader().getIddResourceRva(); - std::uint32_t uncompressedRsrcSize = _newPeFile->peHeader().getIddResourceSize(); + std::uint32_t uncompressedRsrcRva = imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE); + std::uint32_t uncompressedRsrcSize = imageLoader.getDataDirSize(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE); if (uncompressedRsrcRva == 0) return; // Read original resources directory - std::uint32_t compressedRsrcRva = originalHeader.read(PeUpxStubTraits::RsrcsDirectoryRvaOffset); - std::uint32_t compressedRsrcSize = std::max(uncompressedRsrcSize, originalHeader.read(PeUpxStubTraits::RsrcsDirectorySizeOffset)); + std::uint32_t compressedRsrcRva = originalHeader.read(rsrcDirOffset); + std::uint32_t compressedRsrcSize = std::max(uncompressedRsrcSize, originalHeader.read(rsrcDirOffset + 4)); // AVG Samples: There are cases when resource directory RVA is 0, but the binary can still be unpacked by copying uncompressed rsrc RVA if (compressedRsrcRva == 0) compressedRsrcRva = uncompressedRsrcRva - _rvaShift; - if (compressedRsrcRva >= _newPeFile->peHeader().getSizeOfImage()) + if (compressedRsrcRva >= imageLoader.getSizeOfImage()) throw InvalidDataDirectoryException("Resources"); upx_plugin->log("Original resources directory found at RVA 0x", std::hex, compressedRsrcRva, " with size 0x", compressedRsrcSize, std::dec, "."); @@ -1005,23 +989,24 @@ template void PeUpxStub::fixResources(const DynamicBuffer& unpa std::unordered_set visitedNodes; loadResources(_newPeFile->resDir().getRoot(), 0, uncompressedRsrcRva, compressedRsrcRva, uncompressedRsrcs, unpackedData, visitedNodes); - - _newPeFile->peHeader().addSection("gu_rsrcs", _newPeFile->peHeader().getSectionAlignment()); - _newPeFile->peHeader().setCharacteristics(_newPeFile->peHeader().calcNumberOfSections() - 1, PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA); - - // After we have loaded resources, we need to set proper addresses - // The reason for this is that some samples can have overlapped compressed and uncompressed resources (their RVAs) - // Instead of just finding conflicts and moving nodes around in the resource tree, it is much more easier for us to just - // simulate writing of the resource tree and calculate new offsets for every single node - std::uint32_t newRsrcRva = _newPeFile->peHeader().getVirtualAddress(_newPeFile->peHeader().calcNumberOfSections() - 1); - std::uint32_t newRsrcSize = 0; - _newPeFile->resDir().recalculate(newRsrcSize, newRsrcRva); - - _newPeFile->peHeader().enlargeLastSection(newRsrcSize); - _newPeFile->peHeader().setIddResourceRva(newRsrcRva); - _newPeFile->peHeader().setIddResourceSize(newRsrcRva); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); - */ + + pSectionHeader = imageLoader.addSection("gu_rsrcs", imageLoader.getSectionAlignment()); + if(pSectionHeader != nullptr) + { + pSectionHeader->Characteristics = PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA; + + // After we have loaded resources, we need to set proper addresses + // The reason for this is that some samples can have overlapped compressed and uncompressed resources (their RVAs) + // Instead of just finding conflicts and moving nodes around in the resource tree, it is much more easier for us to just + // simulate writing of the resource tree and calculate new offsets for every single node + std::uint32_t newRsrcRva = pSectionHeader->VirtualAddress; + std::uint32_t newRsrcSize = 0; + _newPeFile->resDir().recalculate(newRsrcSize, newRsrcRva); + + imageLoader.enlargeLastSection(newRsrcSize); + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE, newRsrcRva, newRsrcSize); + imageLoader.makeValid(); + } } /** @@ -1032,18 +1017,18 @@ template void PeUpxStub::fixResources(const DynamicBuffer& unpa */ template void PeUpxStub::fixSectionHeaders(const DynamicBuffer& originalHeader) { - /* + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); std::uint16_t numberOfSections = originalHeader.read(6); - std::uint32_t numberOfDirectories = originalHeader.read(PeUpxStubTraits::NumberOfRvaAndSizesOffset); - std::uint32_t sectionHeadersOffset = PeUpxStubTraits::ExportsDirectoryRvaOffset + numberOfDirectories * 8; - std::uint32_t sectionHeadersEnd = sectionHeadersOffset + PeLib::PELIB_IMAGE_SECTION_HEADER::size() * numberOfSections; + std::uint32_t numberOfDirectories = originalHeader.read(imageLoader.getFieldOffset(PeLib::OPTHDR_NumberOfRvaAndSizes)); + std::uint32_t sectionHeadersOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_EXPORT_Rva) + numberOfDirectories * 8; + std::uint32_t sectionHeadersEnd = sectionHeadersOffset + sizeof(PeLib::PELIB_IMAGE_SECTION_HEADER) * numberOfSections; std::uint32_t readPos = sectionHeadersOffset; std::vector newSectionHeaders; while (readPos < sectionHeadersEnd) { // If there is not enough data for section header from readPos, this is not valid section header and just end - if (readPos + PeLib::PELIB_IMAGE_SECTION_HEADER::size() > originalHeader.getRealDataSize()) + if (readPos + sizeof(PeLib::PELIB_IMAGE_SECTION_HEADER) > originalHeader.getRealDataSize()) break; PeLib::PELIB_IMAGE_SECTION_HEADER newSectionHeader; @@ -1063,7 +1048,7 @@ template void PeUpxStub::fixSectionHeaders(const DynamicBuffer& newSectionHeader.VirtualSize = originalHeader.read(readPos + 8); newSectionHeader.SizeOfRawData = originalHeader.read(readPos + 16); newSectionHeader.Characteristics = originalHeader.read(readPos + 36); - readPos += PeLib::PELIB_IMAGE_SECTION_HEADER::size(); + readPos += sizeof(PeLib::PELIB_IMAGE_SECTION_HEADER); newSectionHeaders.push_back(newSectionHeader); } @@ -1086,26 +1071,26 @@ template void PeUpxStub::fixSectionHeaders(const DynamicBuffer& std::string nextSectName = std::string(reinterpret_cast(newSectionHeaders[index + 1].Name), PeLib::PELIB_IMAGE_SIZEOF_SHORT_NAME); // Align the size to the section alignment, since we have to split at the multiples of section alignment - std::uint32_t splitOffset = newSectionHeaders[index].VirtualSize & ~(_newPeFile->peHeader().getSectionAlignment() - 1); - if (newSectionHeaders[index].VirtualSize & (_newPeFile->peHeader().getSectionAlignment() - 1)) - splitOffset += _newPeFile->peHeader().getSectionAlignment(); + std::uint32_t splitOffset = newSectionHeaders[index].VirtualSize & ~(imageLoader.getSectionAlignment() - 1); + if (newSectionHeaders[index].VirtualSize & (imageLoader.getSectionAlignment() - 1)) + splitOffset += imageLoader.getSectionAlignment(); // If split offset would make one section with 0 size, then don't split, just end // This solves problem if the UPX0 overlaps to UPX1 so much, that it covers some section - if (splitOffset != _newPeFile->peHeader().getVirtualSize(_upx0Sect->getSecSeg()->getIndex() + index)) + std::size_t sectionIndex = _upx0Sect->getSecSeg()->getIndex() + index; + if (splitOffset != imageLoader.getSectionHeader(sectionIndex)->VirtualSize) { - if (_newPeFile->peHeader().splitSection(_upx0Sect->getSecSeg()->getIndex() + index, prevSectName, nextSectName, splitOffset) != PeLib::ERROR_NONE) + if (imageLoader.splitSection(sectionIndex, prevSectName, nextSectName, splitOffset) != PeLib::ERROR_NONE) throw OriginalHeaderCorruptedException(); } else - _newPeFile->peHeader().setSectionName(_upx0Sect->getSecSeg()->getIndex() + index + 1, nextSectName); + imageLoader.setSectionName(sectionIndex + 1, nextSectName.c_str()); - _newPeFile->peHeader().setCharacteristics(_upx0Sect->getSecSeg()->getIndex() + index, newSectionHeaders[index].Characteristics); - _newPeFile->peHeader().setCharacteristics(_upx0Sect->getSecSeg()->getIndex() + index + 1, newSectionHeaders[index + 1].Characteristics); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + imageLoader.setSectionCharacteristics(sectionIndex, newSectionHeaders[index].Characteristics); + imageLoader.setSectionCharacteristics(sectionIndex + 1, newSectionHeaders[index + 1].Characteristics); + imageLoader.makeValid(); } } - */ } /** @@ -1114,11 +1099,12 @@ template void PeUpxStub::fixSectionHeaders(const DynamicBuffer& */ template void PeUpxStub::fixCoffSymbolTable() { -/* + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + _coffSymbolTable.clear(); // MinGW files use COFF symbols even though it shouldn't be used for EXEs - if (_newPeFile->peHeader().getPointerToSymbolTable() > 0) // Check whether COFF symbol table exists + if (imageLoader.getPointerToSymbolTable() > 0) // Check whether COFF symbol table exists { upx_plugin->log("Detected COFF symbol table. Packed file may contain DWARF debug info."); @@ -1135,16 +1121,15 @@ template void PeUpxStub::fixCoffSymbolTable() inputFileHandle.close(); // Calculate the offset where to write COFF symbols in unpacked file by calculating raw sizes of all sections in unpacked file - std::uint32_t newSymbolTablePointer = _newPeFile->peHeader().getPointerToRawData(0); - for (std::uint32_t i = 0; i < _newPeFile->peHeader().calcNumberOfSections(); ++i) - newSymbolTablePointer += _newPeFile->peHeader().getSizeOfRawData(i); + std::uint32_t newSymbolTablePointer = imageLoader.getSectionHeader(0)->PointerToRawData; + for (std::uint32_t i = 0; i < imageLoader.getNumberOfSections(); ++i) + newSymbolTablePointer += imageLoader.getSectionHeader(i)->SizeOfRawData; - _newPeFile->peHeader().setPointerToSymbolTable(newSymbolTablePointer); + imageLoader.setPointerToSymbolTable(newSymbolTablePointer); } else upx_plugin->log("Packed file seems to be truncated. Not copying DWARF debug info."); } - */ } /** @@ -1152,15 +1137,11 @@ template void PeUpxStub::fixCoffSymbolTable() */ template void PeUpxStub::fixCertificates() { - /* - // Make sure there is enough data directories - _newPeFile->peHeader().setNumberOfRvaAndSizes(std::max(_newPeFile->peHeader().calcNumberOfRvaAndSizes(), static_cast(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY) + 1)); - _newPeFile->peHeader().makeValid(_newPeFile->mzHeader().size()); + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); // Read original Load Configuration data directory - std::uint32_t securityOffset = _newPeFile->peHeader().getIddSecurityRva(); - std::uint32_t securitySize = _newPeFile->peHeader().getIddSecuritySize(); - + std::uint32_t securityOffset = imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY); + std::uint32_t securitySize = imageLoader.getDataDirSize(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY); if (securityOffset == 0) return; @@ -1174,15 +1155,14 @@ template void PeUpxStub::fixCertificates() // summing all raw sizes of sections in the unpacked files and add COFF symbol table size. if (securityOffset > 0) { - securityOffset = offsetDist + _newPeFile->peHeader().getPointerToRawData(0); - for (std::uint32_t i = 0; i < _newPeFile->peHeader().calcNumberOfSections(); ++i) - securityOffset += _newPeFile->peHeader().getSizeOfRawData(i); + securityOffset = offsetDist + imageLoader.getSectionHeader(0)->PointerToRawData; + for (std::uint32_t i = 0; i < imageLoader.getNumberOfSections(); ++i) + securityOffset += imageLoader.getSectionHeader(i)->SizeOfRawData; securityOffset += static_cast(_coffSymbolTable.size()); } - _newPeFile->peHeader().setIddSecurityRva(securityOffset); - */ + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY, securityOffset, securitySize); } /** From eefe6c6f41eb076652237f91e50848fc151f6ad7 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Mon, 13 Jul 2020 15:14:34 +0200 Subject: [PATCH 21/34] Unpacker: UPX complete --- include/retdec/pelib/ImageLoader.h | 8 + include/retdec/pelib/ImportDirectory.h | 95 +++++--- src/pelib/ImageLoader.cpp | 230 +++++++++++++++++- .../plugins/upx/pe/pe_upx_stub.cpp | 58 +++-- src/unpackertool/plugins/upx/pe/pe_upx_stub.h | 2 +- 5 files changed, 323 insertions(+), 70 deletions(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index e49d1116a..a6d6dd478 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -38,6 +38,7 @@ enum : std::uint32_t enum PELIB_MEMBER_TYPE : std::uint32_t { OPTHDR_sizeof, + OPTHDR_sizeof_fixed, OPTHDR_NumberOfRvaAndSizes, OPTHDR_DataDirectory, OPTHDR_DataDirectory_EXPORT_Rva, @@ -142,6 +143,9 @@ class ImageLoader int Load(std::istream & fs, std::streamoff fileOffset = 0, bool loadHeadersOnly = false); int Load(const char * fileName, bool loadHeadersOnly = false); + int Save(std::ostream & fs, std::streamoff fileOffset = 0, bool saveHeadersOnly = false); + int Save(const char * fileName, bool saveHeadersOnly = false); + bool relocateImage(std::uint64_t newImageBase); std::uint32_t readImage(void * buffer, std::uint32_t rva, std::uint32_t bytesToRead); @@ -159,6 +163,7 @@ class ImageLoader std::uint32_t getImageBitability() const; + std::uint32_t vaToRva(std::uint64_t VirtualAddress) const; std::uint32_t getFileOffsetFromRva(std::uint32_t rva) const; std::uint32_t getRealPointerToRawData(std::size_t sectionIndex) const; std::uint32_t getImageProtection(std::uint32_t characteristics) const; @@ -356,9 +361,12 @@ class ImageLoader void writeNewImageBase(std::uint64_t newImageBase); int captureDosHeader(std::vector & fileData); + int saveDosHeader(std::ostream & fs, std::streamoff fileOffset); int captureNtHeaders(std::vector & fileData); + int saveNtHeaders(std::ostream & fs, std::streamoff fileOffset); int captureSectionName(std::vector & fileData, std::string & sectionName, const std::uint8_t * name); int captureSectionHeaders(std::vector & fileData); + int saveSectionHeaders(std::ostream & fs, std::streamoff fileOffset); int captureImageSections(std::vector & fileData); int captureOptionalHeader32(std::uint8_t * fileData, std::uint8_t * filePtr, std::uint8_t * fileEnd); int captureOptionalHeader64(std::uint8_t * fileData, std::uint8_t * filePtr, std::uint8_t * fileEnd); diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index 902d7c697..636838361 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -137,6 +137,8 @@ namespace PeLib std::uint32_t getNumberOfFunctions(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT /// Read a file's import directory. int read(ImageLoader & imageLoader); // EXPORT + /// Writes pointer to the buffer (32-bit or 64-bit) + void writePointer(OutputBuffer & obBuffer, std::uint64_t pointerValue); /// Rebuild the import directory. void rebuild(std::vector& vBuffer, std::uint32_t dwRva, bool fixEntries = true); // EXPORT /// Remove a file from the import directory. @@ -148,22 +150,24 @@ namespace PeLib /// Returns the size of the current import directory. unsigned int calculateSize(std::uint32_t pointerSize) const; // EXPORT /// Writes the import directory to a file. - int write(const std::string& strFilename, unsigned int uiOffset, unsigned int uiRva); // EXPORT + int write(const std::string& strFilename, std::uint32_t uiOffset, std::uint32_t uiRva, std::uint32_t pointerSize); // EXPORT + /// Updates the pointer size for the import directory + void setPointerSize(std::uint32_t pointerSize); /// Returns the FirstThunk value of a function. - std::uint64_t getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber - void setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint64_t value); // EXPORT _byNumber + std::uint32_t getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber + void setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber /// Returns the OriginalFirstThunk value of a function. - std::uint64_t getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber - void setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint64_t value); // EXPORT + std::uint32_t getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const; // EXPORT _byNumber + void setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value); // EXPORT // std::uint64_t getFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); // std::uint64_t getOriginalFirstThunk(const std::string& strFilename, const std::string& strFuncname, currdir cdDir) const throw (PeLibException); /// Returns the FirstThunk value of a file. - std::uint64_t getFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName + std::uint32_t getFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the OriginalFirstThunk value of a file. - std::uint64_t getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName + std::uint32_t getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the ForwarderChain value of a file. std::uint32_t getForwarderChain(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName std::uint32_t getRvaOfName(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName @@ -171,11 +175,11 @@ namespace PeLib std::uint32_t getTimeDateStamp(const std::string& strFilename, currdir cdDir) const; // EXPORT _byName /// Returns the FirstThunk value of a file. - std::uint64_t getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT - void setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint64_t value); // EXPORT _byNumber_function + std::uint32_t getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT + void setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber_function /// Returns the OriginalFirstThunk value of a file. - std::uint64_t getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT - void setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint64_t value); // EXPORT _byNumber_function + std::uint32_t getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT + void setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber_function /// Returns the ForwarderChain value of a file. std::uint32_t getForwarderChain(std::uint32_t dwFilenr, currdir cdDir) const; // EXPORT _byNumber void setForwarderChain(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value); // EXPORT _byNumber_function @@ -539,6 +543,18 @@ namespace PeLib return false; } + /** + * Updates pointer size for import directory + * @param inStream Input stream. + * @param peHeader A valid PE header. + **/ + + inline void ImportDirectory::setPointerSize(std::uint32_t pointerSize) + { + m_thunkSize = pointerSize; + m_ordinalMask = (uint64_t)1 << ((pointerSize * 8) - 1); + } + /** * Read an import directory from a file. * \todo Check if streams failed. @@ -554,8 +570,7 @@ namespace PeLib std::uint32_t rvaBegin = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT); std::uint32_t rva = rvaBegin; - m_ordinalMask = imageLoader.getOrdinalMask(); - m_thunkSize = imageLoader.getPointerSize(); + setPointerSize(imageLoader.getPointerSize()); m_ldrError = LDR_ERROR_NONE; // Verify whether the import directory is within the image @@ -787,6 +802,19 @@ namespace PeLib return ERROR_NONE; } + inline void ImportDirectory::writePointer(OutputBuffer & obBuffer, std::uint64_t pointerValue) + { + if(m_thunkSize == sizeof(std::uint32_t)) + { + std::uint32_t pointerValue32 = (std::uint32_t)pointerValue; + obBuffer << pointerValue32; + } + else + { + obBuffer << pointerValue; + } + } + /** * Rebuilds the import directory. * @param vBuffer Buffer the rebuilt import directory will be written to. @@ -869,28 +897,30 @@ namespace PeLib std::uint64_t uiPfunc = uiSizeofdescriptors + uiSizeofoft + uiSizeofdllnames + uiImprva; // Rebuild original first thunk - for (unsigned int i=0;i(m_vNewiid[i].originalfirstthunk[j].fname.size()) + 3; } - obBuffer << static_cast(0); + writePointer(obBuffer, 0); + //obBuffer << static_cast(0); } // Write dllnames into import directory - for (unsigned int i=0;i(m_vNewiid[i].name.size())+1); } @@ -999,7 +1029,7 @@ namespace PeLib * @param uiRva RVA which belongs to that file offset. **/ inline - int ImportDirectory::write(const std::string& strFilename, unsigned int uiOffset, unsigned int uiRva) + int ImportDirectory::write(const std::string& strFilename, std::uint32_t uiOffset, std::uint32_t uiRva, std::uint32_t pointerSize) { std::fstream ofFile(strFilename.c_str(), std::ios_base::in); @@ -1023,6 +1053,7 @@ namespace PeLib std::vector vBuffer; + setPointerSize(pointerSize); rebuild(vBuffer, uiRva); ofFile.write(reinterpret_cast(vBuffer.data()), vBuffer.size()); @@ -1055,7 +1086,7 @@ namespace PeLib * @return FirstThunk value of an imported file. **/ inline - std::uint64_t ImportDirectory::getFirstThunk(const std::string& strFilename, currdir cdDir) const + std::uint32_t ImportDirectory::getFirstThunk(const std::string& strFilename, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1073,7 +1104,7 @@ namespace PeLib * @return OriginalFirstThunk value of an imported file. **/ inline - std::uint64_t ImportDirectory::getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const + std::uint32_t ImportDirectory::getOriginalFirstThunk(const std::string& strFilename, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1140,7 +1171,7 @@ namespace PeLib * @return FirstThunk value of an imported file. **/ inline - std::uint64_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const + std::uint32_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1153,7 +1184,7 @@ namespace PeLib } inline - void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint64_t value) + void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) { @@ -1171,7 +1202,7 @@ namespace PeLib * @return OriginalFirstThunk value of an imported file. **/ inline - std::uint64_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const + std::uint32_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1184,7 +1215,7 @@ namespace PeLib } inline - void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint64_t value) + void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) { @@ -1292,14 +1323,14 @@ namespace PeLib * @return FirstThunk value of an imported function. **/ inline - std::uint64_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const + std::uint32_t ImportDirectory::getFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const { if (cdDir == OLDDIR) return m_vOldiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal; else return m_vNewiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal; } inline - void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint64_t value) + void ImportDirectory::setFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) m_vOldiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal = value; else m_vNewiid[dwFilenr].firstthunk[dwFuncnr].itd.Ordinal = value; @@ -1312,7 +1343,7 @@ namespace PeLib * @return OriginalFirstThunk value of an imported function. **/ inline - std::uint64_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const + std::uint32_t ImportDirectory::getOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir) const { if (cdDir == OLDDIR) { @@ -1332,7 +1363,7 @@ namespace PeLib } inline - void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint64_t value) + void ImportDirectory::setOriginalFirstThunk(std::uint32_t dwFilenr, std::uint32_t dwFuncnr, currdir cdDir, std::uint32_t value) { if (cdDir == OLDDIR) m_vOldiid[dwFilenr].originalfirstthunk[dwFuncnr].itd.Ordinal = value; else m_vNewiid[dwFilenr].originalfirstthunk[dwFuncnr].itd.Ordinal = value; diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index f01fa4dca..7efe2bf20 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -48,15 +48,6 @@ uint8_t PeLib::ImageLoader::ImageProtectionArray[16] = PELIB_PAGE_EXECUTE_READWRITE }; -//----------------------------------------------------------------------------- -// Returns the fixed size of optional header (without Data Directories) - -template -uint32_t getCopySizeOfOptionalHeader() -{ - return offsetof(OPT_HDR, DataDirectory); -} - //----------------------------------------------------------------------------- // Constructor and destructor @@ -415,6 +406,14 @@ uint32_t PeLib::ImageLoader::getImageBitability() const return 32; } +uint32_t PeLib::ImageLoader::vaToRva(uint64_t VirtualAddress) const +{ + if(getImageBase() <= VirtualAddress && VirtualAddress < getImageBase() + optionalHeader.SizeOfImage) + return (uint32_t)(VirtualAddress - getImageBase()); + + return UINT32_MAX; +} + uint32_t PeLib::ImageLoader::getFileOffsetFromRva(uint32_t rva) const { // If we have sections loaded, then we calculate the file offset from section headers @@ -464,6 +463,9 @@ uint32_t PeLib::ImageLoader::getFieldOffset(PELIB_MEMBER_TYPE field) const case OPTHDR_sizeof: return (imageBitability == 64) ? sizeof(PELIB_IMAGE_OPTIONAL_HEADER64) : sizeof(PELIB_IMAGE_OPTIONAL_HEADER32); + case OPTHDR_sizeof_fixed: + return (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + case OPTHDR_NumberOfRvaAndSizes: fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, NumberOfRvaAndSizes) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, NumberOfRvaAndSizes); return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset; @@ -885,6 +887,69 @@ int PeLib::ImageLoader::Load(const char * fileName, bool loadHeadersOnly) return Load(fs, loadHeadersOnly); } +//----------------------------------------------------------------------------- +// Interface for saving to file + +int PeLib::ImageLoader::Save(std::ostream & fs, std::streamoff fileOffset, bool saveHeadersOnly) +{ + std::streamoff fileSize; + int fileError; + + // Check and capture DOS header + fileError = saveDosHeader(fs, fileOffset); + if(fileError != ERROR_NONE) + return fileError; + + // Check and capture NT headers + fileError = saveNtHeaders(fs, fileOffset + dosHeader.e_lfanew); + if(fileError != ERROR_NONE) + return fileError; + + // Check and capture section headers + fileOffset = fileOffset + dosHeader.e_lfanew + sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; + fileError = saveSectionHeaders(fs, fileOffset); + if(fileError != ERROR_NONE) + return fileError; + + // Write zeros to the rest of the file, up to size of image + if(saveHeadersOnly == false) + { + // Get the curent file offset and file size + fileOffset += sections.size() * sizeof(PELIB_IMAGE_SECTION_HEADER); + fileSize = fileOffset; + + // Estimate the file size with data + for(const auto & section : sections) + { + if(section.SizeOfRawData != 0) + { + if((section.PointerToRawData + section.SizeOfRawData) > fileSize) + fileSize = section.PointerToRawData + section.SizeOfRawData; + } + } + + // Shall we write data to the file? + if(fileSize > fileOffset) + { + std::vector ZeroBuffer(fileSize - fileOffset); + + fs.seekp(fileOffset, std::ios::beg); + fs.write(ZeroBuffer.data(), ZeroBuffer.size()); + } + } + + return ERROR_NONE; +} + +int PeLib::ImageLoader::Save(const char * fileName, bool saveHeadersOnly) +{ + std::ofstream fs(fileName, std::ifstream::out | std::ifstream::binary); + if(!fs.is_open()) + return ERROR_OPENING_FILE; + + return Save(fs, 0, saveHeadersOnly); +} + //----------------------------------------------------------------------------- // Protected functions @@ -1318,7 +1383,7 @@ void PeLib::ImageLoader::writeNewImageBase(uint64_t newImageBase) if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { PELIB_IMAGE_OPTIONAL_HEADER64 header64{}; - uint32_t sizeOfOptionalHeader = getCopySizeOfOptionalHeader(); + uint32_t sizeOfOptionalHeader = offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory); readImage(&header64, offset, sizeOfOptionalHeader); header64.ImageBase = newImageBase; @@ -1329,7 +1394,7 @@ void PeLib::ImageLoader::writeNewImageBase(uint64_t newImageBase) if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { PELIB_IMAGE_OPTIONAL_HEADER32 header32{}; - uint32_t sizeOfOptionalHeader = getCopySizeOfOptionalHeader(); + uint32_t sizeOfOptionalHeader = offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); readImage(&header32, offset, sizeOfOptionalHeader); header32.ImageBase = (uint32_t)newImageBase; @@ -1351,6 +1416,16 @@ int PeLib::ImageLoader::captureDosHeader(std::vector & fileData) return verifyDosHeader(dosHeader, fileData.size()); } +int PeLib::ImageLoader::saveDosHeader(std::ostream & fs, std::streamoff fileOffset) +{ + // Move to the required file offset + fs.seekp(fileOffset, std::ios::beg); + + // Write DOS header as-is + fs.write(reinterpret_cast(&dosHeader), sizeof(PELIB_IMAGE_DOS_HEADER)); + return ERROR_NONE; +} + int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) { uint8_t * fileBegin = fileData.data(); @@ -1479,6 +1554,115 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) return ERROR_NONE; } +int PeLib::ImageLoader::saveNtHeaders(std::ostream & fs, std::streamoff fileOffset) +{ + // Calculate the size of the optional header. Any version of PE file, + // 32 or 64-bit, must have this field set to a correct value. + uint32_t sizeOfOptionalHeader = getFieldOffset(OPTHDR_sizeof_fixed) + optionalHeader.NumberOfRvaAndSizes * sizeof(PELIB_IMAGE_DATA_DIRECTORY); + + // Move to the required file offset + fs.seekp(fileOffset, std::ios::beg); + + // Write the NT signature + fs.write(reinterpret_cast(&ntSignature), sizeof(ntSignature)); + + // Write the file header + fileHeader.SizeOfOptionalHeader = sizeOfOptionalHeader; + fileHeader.NumberOfSections = (uint16_t)sections.size(); + fs.write(reinterpret_cast(&fileHeader), sizeof(PELIB_IMAGE_FILE_HEADER)); + + // Write the optional header. Note that we need to distinguish 32-bit and 64-bit header + if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + PELIB_IMAGE_OPTIONAL_HEADER32 optionalHeader32; + + // Verify some of the data to make sure they are able to convert to 32-bit values + if((optionalHeader.ImageBase >> 0x20) != 0) + return ERROR_INVALID_FILE; + if((optionalHeader.SizeOfStackReserve >> 0x20) != 0) + return ERROR_INVALID_FILE; + if((optionalHeader.SizeOfHeapReserve >> 0x20) != 0) + return ERROR_INVALID_FILE; + + // Convert the optional header to 32-bit variant + optionalHeader32.Magic = optionalHeader.Magic; + optionalHeader32.MajorLinkerVersion = optionalHeader.MajorLinkerVersion; + optionalHeader32.MinorLinkerVersion = optionalHeader.MinorLinkerVersion; + optionalHeader32.SizeOfCode = optionalHeader.SizeOfCode; + optionalHeader32.SizeOfInitializedData = optionalHeader.SizeOfInitializedData; + optionalHeader32.SizeOfUninitializedData = optionalHeader.SizeOfUninitializedData; + optionalHeader32.AddressOfEntryPoint = optionalHeader.AddressOfEntryPoint; + optionalHeader32.BaseOfCode = optionalHeader.BaseOfCode; + optionalHeader32.BaseOfData = optionalHeader.BaseOfData; + optionalHeader32.ImageBase = (uint32_t)optionalHeader.ImageBase; + optionalHeader32.SectionAlignment = optionalHeader.SectionAlignment; + optionalHeader32.FileAlignment = optionalHeader.FileAlignment; + optionalHeader32.MajorOperatingSystemVersion = optionalHeader.MajorOperatingSystemVersion; + optionalHeader32.MinorOperatingSystemVersion = optionalHeader.MinorOperatingSystemVersion; + optionalHeader32.MajorImageVersion = optionalHeader.MajorImageVersion; + optionalHeader32.MinorImageVersion = optionalHeader.MinorImageVersion; + optionalHeader32.MajorSubsystemVersion = optionalHeader.MajorSubsystemVersion; + optionalHeader32.MinorSubsystemVersion = optionalHeader.MinorSubsystemVersion; + optionalHeader32.Win32VersionValue = optionalHeader.Win32VersionValue; + optionalHeader32.SizeOfImage = optionalHeader.SizeOfImage; + optionalHeader32.SizeOfHeaders = optionalHeader.SizeOfHeaders; + optionalHeader32.CheckSum = optionalHeader.CheckSum; + optionalHeader32.Subsystem = optionalHeader.Subsystem; + optionalHeader32.DllCharacteristics = optionalHeader.DllCharacteristics; + optionalHeader32.SizeOfStackReserve = (uint32_t)optionalHeader.SizeOfStackReserve; + optionalHeader32.SizeOfStackCommit = (uint32_t)optionalHeader.SizeOfStackCommit; + optionalHeader32.SizeOfHeapReserve = (uint32_t)optionalHeader.SizeOfHeapReserve; + optionalHeader32.SizeOfHeapCommit = (uint32_t)optionalHeader.SizeOfHeapCommit; + optionalHeader32.LoaderFlags = optionalHeader.LoaderFlags; + optionalHeader32.NumberOfRvaAndSizes = optionalHeader.NumberOfRvaAndSizes; + memcpy(&optionalHeader32.DataDirectory, &optionalHeader.DataDirectory, sizeof(optionalHeader.DataDirectory)); + + // Write to file + fs.write(reinterpret_cast(&optionalHeader32), sizeOfOptionalHeader); + } + else + { + PELIB_IMAGE_OPTIONAL_HEADER64 optionalHeader64; + + // Convert the optional header to 64-bit variant + optionalHeader64.Magic = optionalHeader.Magic; + optionalHeader64.MajorLinkerVersion = optionalHeader.MajorLinkerVersion; + optionalHeader64.MinorLinkerVersion = optionalHeader.MinorLinkerVersion; + optionalHeader64.SizeOfCode = optionalHeader.SizeOfCode; + optionalHeader64.SizeOfInitializedData = optionalHeader.SizeOfInitializedData; + optionalHeader64.SizeOfUninitializedData = optionalHeader.SizeOfUninitializedData; + optionalHeader64.AddressOfEntryPoint = optionalHeader.AddressOfEntryPoint; + optionalHeader64.BaseOfCode = optionalHeader.BaseOfCode; + optionalHeader64.ImageBase = optionalHeader.ImageBase; + optionalHeader64.SectionAlignment = optionalHeader.SectionAlignment; + optionalHeader64.FileAlignment = optionalHeader.FileAlignment; + optionalHeader64.MajorOperatingSystemVersion = optionalHeader.MajorOperatingSystemVersion; + optionalHeader64.MinorOperatingSystemVersion = optionalHeader.MinorOperatingSystemVersion; + optionalHeader64.MajorImageVersion = optionalHeader.MajorImageVersion; + optionalHeader64.MinorImageVersion = optionalHeader.MinorImageVersion; + optionalHeader64.MajorSubsystemVersion = optionalHeader.MajorSubsystemVersion; + optionalHeader64.MinorSubsystemVersion = optionalHeader.MinorSubsystemVersion; + optionalHeader64.Win32VersionValue = optionalHeader.Win32VersionValue; + optionalHeader64.SizeOfImage = optionalHeader.SizeOfImage; + optionalHeader64.SizeOfHeaders = optionalHeader.SizeOfHeaders; + optionalHeader64.CheckSum = optionalHeader.CheckSum; + optionalHeader64.Subsystem = optionalHeader.Subsystem; + optionalHeader64.DllCharacteristics = optionalHeader.DllCharacteristics; + optionalHeader64.SizeOfStackReserve = optionalHeader.SizeOfStackReserve; + optionalHeader64.SizeOfStackCommit = optionalHeader.SizeOfStackCommit; + optionalHeader64.SizeOfHeapReserve = optionalHeader.SizeOfHeapReserve; + optionalHeader64.SizeOfHeapCommit = optionalHeader.SizeOfHeapCommit; + optionalHeader64.LoaderFlags = optionalHeader.LoaderFlags; + optionalHeader64.NumberOfRvaAndSizes = optionalHeader.NumberOfRvaAndSizes; + memcpy(&optionalHeader64.DataDirectory, &optionalHeader.DataDirectory, sizeof(optionalHeader64.DataDirectory)); + + // Write to file + fs.write(reinterpret_cast(&optionalHeader64), sizeOfOptionalHeader); + } + + return ERROR_NONE; +} + int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std::string & sectionName, const uint8_t * Name) { // If the section name is in format of "/12345", then the section name is actually in the symbol table @@ -1683,6 +1867,30 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) return ERROR_NONE; } +int PeLib::ImageLoader::saveSectionHeaders(std::ostream & fs, std::streamoff fileOffset) +{ + PELIB_IMAGE_SECTION_HEADER * pHeaders; + size_t sectionCount = sections.size(); + size_t index = 0; + + if((pHeaders = new PELIB_IMAGE_SECTION_HEADER[sectionCount]) != nullptr) + { + // Populate the array with section headers + for(const auto & section : sections) + { + memcpy(pHeaders + index, section.Name, sizeof(PELIB_IMAGE_SECTION_HEADER)); + index++; + } + + // Write the section headers to file + fs.seekp(fileOffset, std::ios::beg); + fs.write(reinterpret_cast(pHeaders), sectionCount * sizeof(PELIB_IMAGE_SECTION_HEADER)); + delete[] pHeaders; + } + + return ERROR_NONE; +} + int PeLib::ImageLoader::captureImageSections(std::vector & fileData) { uint32_t virtualAddress = 0; diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp index 904abf61e..dc316edd8 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp @@ -1196,29 +1196,34 @@ template void PeUpxStub::cutHintsData(DynamicBuffer& unpackedDa */ template void PeUpxStub::saveFile(const std::string& outputFile, DynamicBuffer& unpackedData) { - /* + PeLib::PELIB_IMAGE_SECTION_HEADER * pSectionHeader; + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + std::uint32_t Rva; + // Remove the file if it already exists std::remove(outputFile.c_str()); - _newPeFile->mzHeader().write(outputFile, 0); - _newPeFile->peHeader().write(outputFile, _newPeFile->mzHeader().size()); - _newPeFile->peHeader().writeSections(outputFile); + // Write the DOS header, PE headers and section headers + pSectionHeader = imageLoader.getSectionHeader(_upx0Sect->getSecSeg()->getIndex()); + imageLoader.Save(outputFile.c_str()); - if (_newPeFile->peHeader().getIddImportRva() != 0) + // Save the import directory + if((Rva = imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT)) != 0) { - _newPeFile->impDir().write(outputFile, _newPeFile->peHeader().rvaToOffset(_newPeFile->peHeader().getIddImportRva()), _newPeFile->peHeader().getIddImportRva()); + std::uint32_t VirtualAddress = pSectionHeader->VirtualAddress; + + _newPeFile->impDir().write(outputFile, imageLoader.getFileOffsetFromRva(Rva), Rva, imageLoader.getPointerSize()); // OrignalFirstThunk-s are known only after the impDir is written into the file // We then need to read it function by function and set the contents of IAT to be same as ILT // If it isn't, the windows loader refuses to load the executable file - for (std::uint32_t fileIndex = 0; fileIndex < _newPeFile->impDir().getNumberOfFiles(PeLib::OLDDIR); ++fileIndex) + for(std::uint32_t fileIndex = 0; fileIndex < _newPeFile->impDir().getNumberOfFiles(PeLib::OLDDIR); ++fileIndex) { - AddressType destOffset = _newPeFile->impDir().getFirstThunk(fileIndex, PeLib::OLDDIR) - - _newPeFile->peHeader().getVirtualAddress(_upx0Sect->getSecSeg()->getIndex()); + std::uint32_t destOffset = _newPeFile->impDir().getFirstThunk(fileIndex, PeLib::OLDDIR) - VirtualAddress; - for (std::uint32_t funcIndex = 0; funcIndex < _newPeFile->impDir().getNumberOfFunctions(fileIndex, PeLib::OLDDIR); ++funcIndex, destOffset += 4) + for(std::uint32_t funcIndex = 0; funcIndex < _newPeFile->impDir().getNumberOfFunctions(fileIndex, PeLib::OLDDIR); ++funcIndex, destOffset += 4) { - unpackedData.write(_newPeFile->impDir().getOriginalFirstThunk(fileIndex, funcIndex, PeLib::OLDDIR), destOffset); + unpackedData.write(_newPeFile->impDir().getOriginalFirstThunk(fileIndex, funcIndex, PeLib::OLDDIR), destOffset); } } } @@ -1226,20 +1231,21 @@ template void PeUpxStub::saveFile(const std::string& outputFile // Write the unpacked content to the packed content section // Use regular file as we will write more sections at once std::fstream outputFileHandle(outputFile, std::ios::binary | std::ios::out | std::ios::in); - retdec::utils::writeFile(outputFileHandle, unpackedData.getBuffer(), _newPeFile->peHeader().getPointerToRawData(_upx0Sect->getSecSeg()->getIndex())); + retdec::utils::writeFile(outputFileHandle, unpackedData.getBuffer(), pSectionHeader->PointerToRawData); + // If there were COFF symbols in the original file, write them also to the new one if (!_coffSymbolTable.empty()) - retdec::utils::writeFile(outputFileHandle, _coffSymbolTable, _newPeFile->peHeader().getPointerToSymbolTable()); + retdec::utils::writeFile(outputFileHandle, _coffSymbolTable, imageLoader.getPointerToSymbolTable()); outputFileHandle.close(); - + // Write resources at the end, because they would be rewritten by unpackedData which have them zeroed - if (_newPeFile->peHeader().getIddResourceRva() != 0) - _newPeFile->resDir().write(outputFile, _newPeFile->peHeader().rvaToOffset(_newPeFile->peHeader().getIddResourceRva()), _newPeFile->peHeader().getIddResourceRva()); + if((Rva = imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE)) != 0) + _newPeFile->resDir().write(outputFile, imageLoader.getFileOffsetFromRva(Rva), Rva); - // Write exportss at the end, because they would be rewritten by unpackedData which have them zeroed + // Write exports at the end, because they would be rewritten by unpackedData which have them zeroed // Write them only when exports are not compressed - if ((_newPeFile->peHeader().getIddExportRva() != 0) && !_exportsCompressed) - _newPeFile->expDir().write(outputFile, _newPeFile->peHeader().rvaToOffset(_newPeFile->peHeader().getIddExportRva()), _newPeFile->peHeader().getIddExportRva()); + if((Rva = imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT)) != 0 && !_exportsCompressed) + _newPeFile->expDir().write(outputFile, imageLoader.getFileOffsetFromRva(Rva), Rva); // Copy file overlay if any if (_file->getFileFormat()->getDeclaredFileLength() < _file->getFileFormat()->getLoadedFileLength()) @@ -1256,7 +1262,6 @@ template void PeUpxStub::saveFile(const std::string& outputFile outputFileHandle.seekp(0, std::ios::end); retdec::utils::writeFile(outputFileHandle, overlay, outputFileHandle.tellp()); } - */ } /** @@ -1370,14 +1375,15 @@ template void PeUpxStub::loadResources(PeLib::ResourceNode* roo std::vector data; if (leaf->getOffsetToData() < uncompressedRsrcRva) { - //std::uint32_t dataOffset = leaf->getOffsetToData() - _newPeFile->peHeader().vaToRva(_file->getSegment(0)->getAddress()); - //if (dataOffset >= unpackedData.getRealDataSize()) - // throw InvalidDataDirectoryException("Resources"); + PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + std::uint32_t dataOffset = leaf->getOffsetToData() - imageLoader.vaToRva(_file->getSegment(0)->getAddress()); + if (dataOffset >= unpackedData.getRealDataSize()) + throw InvalidDataDirectoryException("Resources"); - //if (dataOffset + leaf->getSize() >= unpackedData.getRealDataSize()) - // throw InvalidDataDirectoryException("Resources"); + if (dataOffset + leaf->getSize() >= unpackedData.getRealDataSize()) + throw InvalidDataDirectoryException("Resources"); - //data = DynamicBuffer(unpackedData, dataOffset, leaf->getSize()).getBuffer(); + data = DynamicBuffer(unpackedData, dataOffset, leaf->getSize()).getBuffer(); } else { diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h index b5d55f54e..a73f98593 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h @@ -38,7 +38,7 @@ class UpxExtraData public: UpxExtraData() : _importsOffset(0), _relocsOffset(0), _originalHeaderOffset(0), _relocsBigEndian(false) {} UpxExtraData(const UpxExtraData& extraData) - : _importsOffset(extraData._importsOffset), _relocsOffset(extraData._relocsOffset), _relocsBigEndian(extraData._relocsBigEndian) {} + : _importsOffset(extraData._importsOffset), _relocsOffset(extraData._relocsOffset), _originalHeaderOffset(extraData._originalHeaderOffset), _relocsBigEndian(extraData._relocsBigEndian) {} std::uint32_t getImportsOffset() const { return _importsOffset; } void setImportsOffset(std::uint32_t importsOffset) { _importsOffset = importsOffset; } From ee063ba042f7f4d4b427f0c365797e62e3f1dff5 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 14 Jul 2020 10:01:23 +0200 Subject: [PATCH 22/34] Unpacker: MPRESS complete --- include/retdec/pelib/ImageLoader.h | 2 + src/pelib/ImageLoader.cpp | 18 ++ src/unpackertool/plugins/mpress/mpress.cpp | 158 ++++++++++-------- .../plugins/upx/pe/pe_upx_stub.cpp | 5 +- src/unpackertool/plugins/upx/pe/pe_upx_stub.h | 49 +----- 5 files changed, 109 insertions(+), 123 deletions(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index a6d6dd478..0347f4949 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -43,6 +43,7 @@ enum PELIB_MEMBER_TYPE : std::uint32_t OPTHDR_DataDirectory, OPTHDR_DataDirectory_EXPORT_Rva, OPTHDR_DataDirectory_RSRC_Rva, + OPTHDR_DataDirectory_TLS_Rva, OPTHDR_DataDirectory_CONFIG_Rva, }; @@ -167,6 +168,7 @@ class ImageLoader std::uint32_t getFileOffsetFromRva(std::uint32_t rva) const; std::uint32_t getRealPointerToRawData(std::size_t sectionIndex) const; std::uint32_t getImageProtection(std::uint32_t characteristics) const; + std::size_t getSectionIndexByRva(std::uint32_t Rva) const; std::uint32_t getFieldOffset(PELIB_MEMBER_TYPE field) const; diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 7efe2bf20..33e726db4 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -482,6 +482,10 @@ uint32_t PeLib::ImageLoader::getFieldOffset(PELIB_MEMBER_TYPE field) const fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE * sizeof(PELIB_IMAGE_DATA_DIRECTORY); + case OPTHDR_DataDirectory_TLS_Rva: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_TLS * sizeof(PELIB_IMAGE_DATA_DIRECTORY); + case OPTHDR_DataDirectory_CONFIG_Rva: fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG * sizeof(PELIB_IMAGE_DATA_DIRECTORY); @@ -519,6 +523,20 @@ uint32_t PeLib::ImageLoader::getImageProtection(uint32_t sectionCharacteristics) return ImageProtectionArray[Index]; } +size_t PeLib::ImageLoader::getSectionIndexByRva(uint32_t Rva) const +{ + std::size_t sectionIndex = 0; + + for(const auto & section : sections) + { + if(section.VirtualAddress <= Rva && Rva < AlignToSize(section.VirtualAddress + section.VirtualSize, optionalHeader.SectionAlignment)) + return sectionIndex; + sectionIndex++; + } + + return SIZE_MAX; +} + //----------------------------------------------------------------------------- // Manipulation with section data diff --git a/src/unpackertool/plugins/mpress/mpress.cpp b/src/unpackertool/plugins/mpress/mpress.cpp index 90fe4d01d..0551540c6 100644 --- a/src/unpackertool/plugins/mpress/mpress.cpp +++ b/src/unpackertool/plugins/mpress/mpress.cpp @@ -266,7 +266,9 @@ void MpressPlugin::fixJumpsAndCalls(DynamicBuffer& buffer) void MpressPlugin::fixImportsAndEp(DynamicBuffer& buffer) { - /* + PeLib::ImageLoader & imageLoader = _peFile->imageLoader(); + std::uint32_t pointerSize = imageLoader.getPointerSize(); + // At the offset from EP is written EIP relative offset of fix import stub // Fix import stub is then located at the + offset + // This stub was packed together with code and data in .MPRESS1 section and also contains hints for import table rebuild @@ -277,7 +279,7 @@ void MpressPlugin::fixImportsAndEp(DynamicBuffer& buffer) std::uint32_t importHints = fixStubAddr + mpressFixStubData[_fixStub].importHintsOffset + buffer.read(fixStubAddr + mpressFixStubData[_fixStub].importHintsOffset); // Go through MPRESS import hints and fill the import directory - std::int32_t destOffset = _peFile->imageLoader().getVirtualAddress(_packedContentSect->getSecSeg()->getIndex()) + importHints; + std::int32_t destOffset = imageLoader.getSectionHeader(_packedContentSect->getSecSeg()->getIndex())->VirtualAddress + importHints; std::int32_t lowestDestOffset = std::numeric_limits::max(); std::int32_t highestDestOffset = 0; std::int32_t destOffsetDiff; @@ -332,26 +334,28 @@ void MpressPlugin::fixImportsAndEp(DynamicBuffer& buffer) // Fix the import directory and import address directory addresses // Since ILT is lost we need to make them from scratch in the whole new section // Ensure the .imports section will be large enough, resize if there are more data - std::uint32_t fileAlignment = _peFile->imageLoader().getFileAlignment(); - std::uint32_t importSectSize = _peFile->impDir().size() & ~(fileAlignment - 1); + std::uint32_t fileAlignment = imageLoader.getFileAlignment(); + std::uint32_t importFileSize = _peFile->impDir().calculateSize(pointerSize); + std::uint32_t importSectSize = importFileSize & ~(fileAlignment - 1); std::uint32_t newSectionIndex; - if (_peFile->impDir().size() & (fileAlignment - 1)) + if (importFileSize & (fileAlignment - 1)) importSectSize += fileAlignment; - //PeLib::PELIB_SECTION_HEADER & newSection = _peFile->imageLoader().addSection(".imports", importSectSize); + PeLib::PELIB_IMAGE_SECTION_HEADER * pNewSection = imageLoader.addSection(".imports", importSectSize); - //newSection.Characteristics = PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA; - _peFile->imageLoader().setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT, _peFile->imageLoader().getVirtualAddress(newSectionIndex), importSectSize); + pNewSection->Characteristics = PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA; + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT, pNewSection->VirtualAddress, importSectSize); // IAT needs to be put at the desired offset std::uint32_t iatOffset = lowestDestOffset; - _peFile->imageLoader().setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IAT, iatOffset, highestDestOffset + 4 - lowestDestOffset); + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IAT, iatOffset, highestDestOffset + 4 - lowestDestOffset); + imageLoader.makeValid(); // Offset to OEP is stored at the offset from the // This offset is addressed from the + offset - std::uint32_t oepOffset = _peFile->imageLoader().getVirtualAddress(_packedContentSect->getSecSeg()->getIndex()) + fixStubAddr + + std::uint32_t oepOffset = imageLoader.getSectionHeader(_packedContentSect->getSecSeg()->getIndex())->VirtualAddress + fixStubAddr + mpressFixStubData[_fixStub].importHintsOffset + buffer.read(fixStubAddr + mpressFixStubData[_fixStub].oepOffset); - //_peFile->imageLoader().setAddressOfEntryPoint(oepOffset); + imageLoader.setAddressOfEntryPoint(oepOffset); // Finally, get rid of the fix imports stub as it is going to mess up frontend analysis in the unpacked section // At the end we add 16 because of 4 bytes directly belonging to the importHintsOffset and additional 12 bytes used @@ -363,37 +367,46 @@ void MpressPlugin::fixImportsAndEp(DynamicBuffer& buffer) _iatSize = highestDestOffset + 4 - lowestDestOffset; _oepVa = oepOffset; _importHintsOffset = importHints; - */ } void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) { + PeLib::PELIB_IMAGE_SECTION_HEADER * packedContectSection; + PeLib::PELIB_IMAGE_SECTION_HEADER * entryPointSection; + PeLib::ImageLoader & imageLoader = _peFile->imageLoader(); + std::size_t packedContentSectionIndex = _packedContentSect->getSecSeg()->getIndex(); + std::uint32_t sectionAlignment = imageLoader.getSectionAlignment(); std::uint32_t fixStubOffset = getFixStub(); std::uint32_t dataFlags = PeLib::PELIB_IMAGE_SCN_MEM_WRITE | PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA; std::uint32_t codeFlags = dataFlags | PeLib::PELIB_IMAGE_SCN_CNT_CODE | PeLib::PELIB_IMAGE_SCN_MEM_EXECUTE; - /* + + // Get pointer to entry point section and also section with packed content + packedContectSection = imageLoader.getSectionHeader(packedContentSectionIndex); + entryPointSection = imageLoader.getSectionHeader(_file->getEpSegment()->getSecSeg()->getIndex()); + // Remove the .MPRESS2 section as the getEpSection()->getIndex() will be shifted by newly created // sections and we can do it safely here //_peFile->peHeader().removeSection(_file->getEpSection()->getIndex()); // @todo There is some problem with removing a section and valid PE file in some cases - _peFile->peHeader().setCharacteristics(_file->getEpSegment()->getSecSeg()->getIndex(), dataFlags); + entryPointSection->Characteristics = dataFlags; // Resize packed content section so we can put unpacked content into it - size_t diff = buffer.getRealDataSize() - _peFile->peHeader().getSizeOfRawData(_packedContentSect->getSecSeg()->getIndex()); - _peFile->peHeader().setSizeOfRawData(_packedContentSect->getSecSeg()->getIndex(), buffer.getRealDataSize()); - for (size_t i = _packedContentSect->getSecSeg()->getIndex() + 1; i < _peFile->peHeader().calcNumberOfSections(); ++i) + size_t diff = buffer.getRealDataSize() - packedContectSection->SizeOfRawData; + packedContectSection->SizeOfRawData = buffer.getRealDataSize(); + + for (size_t i = _packedContentSect->getSecSeg()->getIndex() + 1; i < imageLoader.getNumberOfSections(); ++i) { - auto ii = static_cast(i); - auto tmp = _peFile->peHeader().getPointerToRawData(ii) + diff; - _peFile->peHeader().setPointerToRawData(ii, static_cast(tmp)); + PeLib::PELIB_IMAGE_SECTION_HEADER * tempSection = imageLoader.getSectionHeader(i); + + tempSection->PointerToRawData = tempSection->PointerToRawData + diff; } // Here we will split the big unpacked section into the more data sections and try to locate the code section as much as possible // We will use import hints, IAT, fix stub address and OEP to locate the original sections // We know that hints and fix stub are located at the end of original sections // We also know that IAT is its own section - std::uint32_t oepOffset = _oepVa - _peFile->peHeader().getVirtualAddress(_packedContentSect->getSecSeg()->getIndex()); - std::uint32_t iatOffset = (_iatVa & ~(_peFile->peHeader().getSectionAlignment() - 1)) - _peFile->peHeader().getVirtualAddress(_packedContentSect->getSecSeg()->getIndex()); + std::uint32_t oepOffset = _oepVa - packedContectSection->VirtualAddress; + std::uint32_t iatOffset = (_iatVa & ~(sectionAlignment - 1)) - packedContectSection->VirtualAddress; // We will need this as all other heuristics are based on the shrinking of .text section std::uint32_t moveOffset = 0; @@ -402,16 +415,16 @@ void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) if (_importHintsOffset < oepOffset) { // Split the section into .data0|.text - if (_peFile->peHeader().splitSection(_packedContentSect->getSecSeg()->getIndex(), ".data0", ".text", - (_importHintsOffset & ~(_peFile->peHeader().getSectionAlignment() - 1)) + _peFile->peHeader().getSectionAlignment()) == 0) + if (imageLoader.splitSection(packedContentSectionIndex, ".data0", ".text", + (_importHintsOffset & ~(sectionAlignment - 1)) + sectionAlignment) == 0) { - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex(), dataFlags); - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex() + 1, codeFlags); + imageLoader.getSectionHeader(packedContentSectionIndex)->Characteristics = dataFlags; + imageLoader.getSectionHeader(packedContentSectionIndex+1)->Characteristics = codeFlags; _addedSectionCount++; // We will need this as all other heuristics are based on the shrinking of .text section // We need to subtract this from every split offset calculation - moveOffset = _peFile->peHeader().getSizeOfRawData(_packedContentSect->getSecSeg()->getIndex()); + moveOffset = imageLoader.getSectionHeader(packedContentSectionIndex)->SizeOfRawData; } // We don't mind if IAT is at the beginning of the data, since it is treated properly as data @@ -419,13 +432,14 @@ void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) if (_importHintsOffset < iatOffset && iatOffset < oepOffset) { // Split the layout into .data0|.data2|.text - if (_peFile->peHeader().splitSection(_packedContentSect->getSecSeg()->getIndex() + 1, ".data2", ".text", - ((iatOffset + _iatSize) & ~(_peFile->peHeader().getSectionAlignment() - 1)) + _peFile->peHeader().getSectionAlignment() - moveOffset) == 0) + if (imageLoader.splitSection(packedContentSectionIndex + 1, ".data2", ".text", + ((iatOffset + _iatSize) & ~(sectionAlignment - 1)) + sectionAlignment - moveOffset) == 0) { - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex() + 1, dataFlags); - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex() + 2, codeFlags); + imageLoader.getSectionHeader(packedContentSectionIndex + 1)->Characteristics = dataFlags; + imageLoader.getSectionHeader(packedContentSectionIndex + 2)->Characteristics = codeFlags; _addedSectionCount++; - moveOffset += _peFile->peHeader().getSizeOfRawData(_packedContentSect->getSecSeg()->getIndex() + 1); + + moveOffset += imageLoader.getSectionHeader(packedContentSectionIndex + 1)->SizeOfRawData; } } @@ -434,11 +448,11 @@ void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) if (fixStubOffset > oepOffset) { // Split into .data0|.text|.data1 or .data0|.data2|.text|.data1 - if (_peFile->peHeader().splitSection(_packedContentSect->getSecSeg()->getIndex() + _addedSectionCount, ".text", ".data1", - (fixStubOffset & ~(_peFile->peHeader().getSectionAlignment() - 1)) + _peFile->peHeader().getSectionAlignment() - moveOffset) == 0) + if (imageLoader.splitSection(packedContentSectionIndex + _addedSectionCount, ".text", ".data1", + (fixStubOffset & ~(sectionAlignment - 1)) + sectionAlignment - moveOffset) == 0) { - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex() + _addedSectionCount, codeFlags); - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex() + _addedSectionCount + 1, dataFlags); + imageLoader.getSectionHeader(packedContentSectionIndex + _addedSectionCount)->Characteristics = codeFlags; + imageLoader.getSectionHeader(packedContentSectionIndex + _addedSectionCount + 1)->Characteristics = dataFlags; _addedSectionCount++; } } @@ -447,11 +461,11 @@ void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) else { // Split into .text|.data0 - if (_peFile->peHeader().splitSection(_packedContentSect->getSecSeg()->getIndex(), ".text", ".data0", - (_importHintsOffset & ~(_peFile->peHeader().getSectionAlignment() - 1)) + _peFile->peHeader().getSectionAlignment()) == 0) + if (imageLoader.splitSection(packedContentSectionIndex, ".text", ".data0", + (_importHintsOffset & ~(sectionAlignment - 1)) + sectionAlignment) == 0) { - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex(), codeFlags); - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex() + 1, dataFlags); + imageLoader.getSectionHeader(packedContentSectionIndex)->Characteristics = codeFlags; + imageLoader.getSectionHeader(packedContentSectionIndex + 1)->Characteristics = dataFlags; _addedSectionCount++; } @@ -459,11 +473,11 @@ void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) if (oepOffset < iatOffset && iatOffset < _importHintsOffset) { // Split into .text|.data2|.data0 - if (_peFile->peHeader().splitSection(_packedContentSect->getSecSeg()->getIndex(), ".text", ".data2", - (iatOffset + _iatSize) & ~(_peFile->peHeader().getSectionAlignment() - 1)) == 0) + if (imageLoader.splitSection(packedContentSectionIndex, ".text", ".data2", + (iatOffset + _iatSize) & ~(sectionAlignment - 1)) == 0) { - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex(), codeFlags); - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex() + 1, dataFlags); + imageLoader.getSectionHeader(packedContentSectionIndex)->Characteristics = codeFlags; + imageLoader.getSectionHeader(packedContentSectionIndex + 1)->Characteristics = dataFlags; _addedSectionCount++; } } @@ -472,32 +486,33 @@ void MpressPlugin::offsetAnalysis(const DynamicBuffer& buffer) if (fixStubOffset < oepOffset) { // Split into .data1|.text|.data0 or .data1|.text|.data2|.data0 - if (_peFile->peHeader().splitSection(_packedContentSect->getSecSeg()->getIndex(), ".data1", ".text", - (fixStubOffset & ~(_peFile->peHeader().getSectionAlignment() - 1)) + _peFile->peHeader().getSectionAlignment()) == 0) + if (imageLoader.splitSection(packedContentSectionIndex, ".data1", ".text", + (fixStubOffset & ~(sectionAlignment - 1)) + sectionAlignment) == 0) { - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex(), dataFlags); - _peFile->peHeader().setCharacteristics(_packedContentSect->getSecSeg()->getIndex() + 1, codeFlags); + imageLoader.getSectionHeader(packedContentSectionIndex)->Characteristics = dataFlags; + imageLoader.getSectionHeader(packedContentSectionIndex + 1)->Characteristics = codeFlags; _addedSectionCount++; } } } - _peFile->peHeader().makeValid(_peFile->mzHeader().size()); - */ + imageLoader.makeValid(); } void MpressPlugin::trailingBytesAnalysis(const DynamicBuffer& buffer) { - /* // Analysis of the trailing bytes of the section // 64 bytes at the every section alignment multiple are checked, if they are all 0, the new section is probably here so it is created // Only code section left after this function is the one containing the OEP, the code will execute even if some of the code is in data sections // and decompiler will take care of this in front-end instruction decoder - std::uint32_t sectionAlignment = _peFile->peHeader().getSectionAlignment(); - std::uint32_t section = _peFile->peHeader().getSectionWithRva(_peFile->peHeader().getAddressOfEntryPoint()); - std::uint32_t startOffset = _peFile->peHeader().getPointerToRawData(section) - _peFile->peHeader().getPointerToRawData(_packedContentSect->getSecSeg()->getIndex()); - std::uint32_t endOffset = startOffset + _peFile->peHeader().getSizeOfRawData(section); - std::uint32_t oepOffset = _peFile->peHeader().getAddressOfEntryPoint() - _peFile->peHeader().getVirtualAddress(_packedContentSect->getSecSeg()->getIndex()); + PeLib::ImageLoader & imageLoader = _peFile->imageLoader(); + PeLib::PELIB_IMAGE_SECTION_HEADER * packedContentSection = imageLoader.getSectionHeader(_packedContentSect->getSecSeg()->getIndex()); + std::size_t section = imageLoader.getSectionIndexByRva(imageLoader.getAddressOfEntryPoint()); + PeLib::PELIB_IMAGE_SECTION_HEADER * entryPointSection = imageLoader.getSectionHeader(section); + std::uint32_t sectionAlignment = imageLoader.getSectionAlignment(); + std::uint32_t startOffset = entryPointSection->PointerToRawData - packedContentSection->PointerToRawData; + std::uint32_t endOffset = startOffset + entryPointSection->SizeOfRawData; + std::uint32_t oepOffset = imageLoader.getAddressOfEntryPoint() - packedContentSection->VirtualAddress; // Used to build the section names std::uint32_t nameCounter = 3; @@ -539,7 +554,7 @@ void MpressPlugin::trailingBytesAnalysis(const DynamicBuffer& buffer) flags[0] = PeLib::PELIB_IMAGE_SCN_MEM_WRITE | PeLib::PELIB_IMAGE_SCN_MEM_READ | PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA; flags[1] = flags[0] | PeLib::PELIB_IMAGE_SCN_MEM_EXECUTE | PeLib::PELIB_IMAGE_SCN_CNT_CODE; } - // OEP doesn't lie in neither of these two parts, this can happen if .text section was already created and we are analysis the rest after that + // OEP doesn't lie in neither of these two parts, this can happen if .text section was already created and we are analyzing the rest after that else { ssFirst << ".data" << nameCounter++; @@ -548,21 +563,21 @@ void MpressPlugin::trailingBytesAnalysis(const DynamicBuffer& buffer) flags[1] = flags[0]; } - _peFile->peHeader().splitSection(section, ssFirst.str(), ssSecond.str(), offset - startOffset); - _peFile->peHeader().setCharacteristics(section, flags[0]); - _peFile->peHeader().setCharacteristics(section + 1, flags[1]); - _peFile->peHeader().makeValid(_peFile->mzHeader().size()); + imageLoader.splitSection(section, ssFirst.str(), ssSecond.str(), offset - startOffset); + imageLoader.getSectionHeader(section)->Characteristics = flags[0]; + imageLoader.getSectionHeader(section + 1)->Characteristics = flags[1]; + imageLoader.makeValid(); _addedSectionCount++; section++; startOffset = offset; } - */ } void MpressPlugin::fixRelocations() { // We will only manipulate this section as all information are stored here const retdec::loader::Segment* epSegment = _file->getEpSegment(); + PeLib::ImageLoader & imageLoader = _peFile->imageLoader(); // Calculate the offset of EP in EP section unsigned long long epAddress; @@ -585,9 +600,7 @@ void MpressPlugin::fixRelocations() // Set the base relocation directory in the new file // All relocations are here undamaged so we are good with this std::uint32_t relocRva = relocRvaBuffer.read(0); - //_peFile->peHeader().setIddBaseRelocRva(relocRva); - //_peFile->peHeader().setIddBaseRelocSize(relocSize); - //_peFile->peHeader().makeValid(_peFile->mzHeader().size()); + imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC, relocRva, relocSize); } MpressUnpackerStub MpressPlugin::detectUnpackerStubVersion() @@ -637,14 +650,13 @@ MpressFixStub MpressPlugin::detectFixStubVersion(DynamicBuffer& unpackedContent) void MpressPlugin::saveFile(const std::string& fileName, DynamicBuffer& content) { - /* + PeLib::ImageLoader & imageLoader = _peFile->imageLoader(); + // Removes the file if it already exists std::remove(fileName.c_str()); // Headers - _peFile->mzHeader().write(fileName, 0); - _peFile->peHeader().write(fileName, _peFile->mzHeader().size()); - _peFile->peHeader().writeSections(fileName); + imageLoader.Save(fileName.c_str()); // Copy the section bytes from original file for the sections preceding the packed section for (std::uint32_t index = 0; index < _packedContentSect->getSecSeg()->getIndex(); ++index) @@ -659,7 +671,8 @@ void MpressPlugin::saveFile(const std::string& fileName, DynamicBuffer& content) copySectionFromOriginalFile(index, fileName, index + _addedSectionCount); // Write content of new import section - _peFile->impDir().write(fileName, _peFile->peHeader().rvaToOffset(_peFile->peHeader().getIddImportRva()), _peFile->peHeader().getIddImportRva()); + std::uint32_t Rva = imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT); + _peFile->impDir().write(fileName, imageLoader.getFileOffsetFromRva(Rva), Rva, imageLoader.getPointerSize()); // After this all we need to update the IAT with the contents of ILT // since Import Directory in PeLib is built after the write to the file @@ -667,7 +680,7 @@ void MpressPlugin::saveFile(const std::string& fileName, DynamicBuffer& content) { auto tmp = static_cast(fileIndex); auto w = static_cast(_packedContentSect->getSecSeg()->getIndex()); - size_t destOffset = _peFile->impDir().getFirstThunk(tmp, PeLib::OLDDIR) - _peFile->peHeader().getVirtualAddress(w); + size_t destOffset = _peFile->impDir().getFirstThunk(tmp, PeLib::OLDDIR) - imageLoader.getSectionHeader(w)->VirtualAddress; for (size_t funcIndex = 0; funcIndex < _peFile->impDir().getNumberOfFunctions(tmp, PeLib::OLDDIR); ++funcIndex, destOffset += 4) { content.write( @@ -679,10 +692,9 @@ void MpressPlugin::saveFile(const std::string& fileName, DynamicBuffer& content) // Write the unpacked content to the packed content section // Use regular file as we will write more sections at once std::fstream outputFile(fileName, std::ios::binary | std::ios::out | std::ios::in); - outputFile.seekp(_peFile->peHeader().getPointerToRawData(_packedContentSect->getSecSeg()->getIndex()), std::ios_base::beg); + outputFile.seekp(imageLoader.getSectionHeader(_packedContentSect->getSecSeg()->getIndex())->PointerToRawData, std::ios_base::beg); outputFile.write(reinterpret_cast(content.getRawBuffer()), content.getRealDataSize()); outputFile.close(); - */ } void MpressPlugin::copySectionFromOriginalFile(std::uint32_t origSectIndex, const std::string& newFileName, std::uint32_t newSectIndex) diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp index dc316edd8..f49c61e55 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp @@ -794,10 +794,11 @@ template void PeUpxStub::fixRelocations(DynamicBuffer& unpacked template void PeUpxStub::fixTls(const DynamicBuffer& originalHeader) { PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); + std::uint32_t tlsDirOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_TLS_Rva); // Read original TLS data directory - std::uint32_t tlsRva = originalHeader.read(PeUpxStubTraits::TlsDirectoryRvaOffset); - std::uint32_t tlsSize = originalHeader.read(PeUpxStubTraits::TlsDirectorySizeOffset); + std::uint32_t tlsRva = originalHeader.read(tlsDirOffset); + std::uint32_t tlsSize = originalHeader.read(tlsDirOffset + 4); imageLoader.setDataDirectory(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_TLS, tlsRva, tlsSize); diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h index a73f98593..60445be50 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h @@ -58,60 +58,13 @@ class UpxExtraData bool _relocsBigEndian; }; -/** - * Base PE UPX traits structure. - */ -template struct PeUpxStubTraits {}; - -/** - * Specialized traits for PE32. - */ -template <> struct PeUpxStubTraits<32> -{ - using AddressType = std::uint32_t; ///< Type with default word size. - using PeLibFileType = PeLib::PeFileT; - - static const std::uint16_t HeaderMagic = PeLib::PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC; ///< PE magic header. - static const std::uint32_t NumberOfRvaAndSizesOffset = 0x74; ///< Offset in PE header to directories count. - static const std::uint32_t TlsDirectoryRvaOffset = 0xC0; ///< Offset to TLS RVA. - static const std::uint32_t TlsDirectorySizeOffset = 0xC4; ///< Offset to TLS size. - static const std::uint32_t ExportsDirectoryRvaOffset = 0x78; ///< Offset to exports RVA. - static const std::uint32_t ExportsDirectorySizeOffset = 0x7C; ///< Offset to exports size. - static const std::uint32_t LoadConfigDirectoryRvaOffset = 0xC8; ///< Offset to load configuration RVA. - static const std::uint32_t LoadConfigDirectorySizeOffset = 0xCC; ///< Offset to load configuration size. - static const std::uint32_t RsrcsDirectoryRvaOffset = 0x88; ///< Offset to resources RVA. - static const std::uint32_t RsrcsDirectorySizeOffset = 0x8C; ///< Offset to resources size. -}; - -/** - * Specialized traits for PE32+. - */ -template <> struct PeUpxStubTraits<64> -{ - using AddressType = std::uint32_t; ///< Type with default word size. - using PeLibFileType = PeLib::PeFileT; ///< Type of PE file. - - static const std::uint16_t HeaderMagic = PeLib::PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC; ///< PE magic header. - static const std::uint32_t NumberOfRvaAndSizesOffset = 0x84; ///< Offset in PE header to directories count. - static const std::uint32_t TlsDirectoryRvaOffset = 0xD0; ///< Offset to TLS RVA. - static const std::uint32_t TlsDirectorySizeOffset = 0xD4; ///< Offset to TLS size. - static const std::uint32_t ExportsDirectoryRvaOffset = 0x88; ///< Offset to exports RVA. - static const std::uint32_t ExportsDirectorySizeOffset = 0x8C; ///< Offset to exports size. - static const std::uint32_t LoadConfigDirectoryRvaOffset = 0xD8; ///< Offset to load configuration RVA. - static const std::uint32_t LoadConfigDirectorySizeOffset = 0xDC; ///< Offset to load configuration size. - static const std::uint32_t RsrcsDirectoryRvaOffset = 0x98; ///< Offset to resources RVA. - static const std::uint32_t RsrcsDirectorySizeOffset = 0x9C; ///< Offset to resources size. -}; - /** * Basic unpacking stub class for unpacking files in PE format. */ template class PeUpxStub : public UpxStub { - using AddressType = typename PeUpxStubTraits::AddressType; - using PeLibFileType = typename PeUpxStubTraits::PeLibFileType; + public: -public: PeUpxStub(retdec::loader::Image* inputFile, const UpxStubData* stubData, const DynamicBuffer& stubCapturedData, std::unique_ptr decompressor, const UpxMetadata& metadata); From 020ff9b1b709d457fb6db97a9e9f15e0e2039227 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 14 Jul 2020 10:51:46 +0200 Subject: [PATCH 23/34] Make linux-doxygen build happy --- .../retdec/fileformat/file_format/pe/pe_template.h | 4 ++-- include/retdec/pelib/ImportDirectory.h | 5 ++--- include/retdec/pelib/TlsDirectory.h | 11 +++++------ src/fileformat/types/tls_info/tls_info.cpp | 2 +- src/pelib/BoundImportDirectory.cpp | 10 ++++++++-- src/pelib/ComHeaderDirectory.cpp | 3 +-- src/pelib/DebugDirectory.cpp | 2 +- src/pelib/ImageLoader.cpp | 10 +++++----- src/pelib/ResourceDirectory.cpp | 6 +++--- 9 files changed, 28 insertions(+), 25 deletions(-) diff --git a/include/retdec/fileformat/file_format/pe/pe_template.h b/include/retdec/fileformat/file_format/pe/pe_template.h index 1140ef0a8..6e6781983 100644 --- a/include/retdec/fileformat/file_format/pe/pe_template.h +++ b/include/retdec/fileformat/file_format/pe/pe_template.h @@ -427,7 +427,7 @@ template bool peDllFlags(const PeLib::PeHeaderT &peHeader, unsig /** * Get information about data directory - * @param peHeader Parser of PE header + * @param imageLoader Reference to a valid PE image loader * @param relAddr Into this parameter is stored relative virtual address of directory * @param size Into this parameter is stored size of directory * @param index Index of selected directory @@ -449,7 +449,7 @@ inline bool peDataDirectoryRelative(const ImageLoader & imageLoader, unsigned lo /** * Get information about data directory - * @param peHeader Parser of PE header + * @param imageLoader Reference to a valid PE image loader * @param absAddr Into this parameter is stored absolute virtual address of directory * @param size Into this parameter is stored size of directory * @param index Index of selected directory diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index 636838361..4c1824b86 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -199,7 +199,7 @@ namespace PeLib * OriginalFirstThunk is valid if it has value higher than file alignment and its RVA can be translated to some offset in the file. * * @param impDesc Import descriptor. - * @param peHeader PE header. + * @param imageLoader Reference to image loader. * * @return True if valid, otherwise false. */ @@ -558,8 +558,7 @@ namespace PeLib /** * Read an import directory from a file. * \todo Check if streams failed. - * @param inStream Input stream. - * @param peHeader A valid PE header. + * @param imageLoader A valid PE loader. **/ inline int ImportDirectory::read(ImageLoader & imageLoader) diff --git a/include/retdec/pelib/TlsDirectory.h b/include/retdec/pelib/TlsDirectory.h index 3c02fc034..d8eccfe9a 100644 --- a/include/retdec/pelib/TlsDirectory.h +++ b/include/retdec/pelib/TlsDirectory.h @@ -69,8 +69,7 @@ namespace PeLib /** * Reads a file's TLS directory. - * @param inStream Input stream. - * @param peHeader A valid PE header. + * @param imageLoader Referenve to a valid PE image loader. **/ inline int TlsDirectory::read(ImageLoader & imageLoader) @@ -276,7 +275,7 @@ namespace PeLib } /** - * @param dwValue The new StartAddressOfRawData value of the TLS directory. + * @param value The new StartAddressOfRawData value of the TLS directory. **/ inline void TlsDirectory::setStartAddressOfRawData(std::uint64_t value) @@ -285,7 +284,7 @@ namespace PeLib } /** - * @param dwValue The new EndAddressOfRawData value of the TLS directory. + * @param value The new EndAddressOfRawData value of the TLS directory. **/ inline void TlsDirectory::setEndAddressOfRawData(std::uint64_t value) @@ -294,7 +293,7 @@ namespace PeLib } /** - * @param dwValue The new AddressOfIndex value of the TLS directory. + * @param value The new AddressOfIndex value of the TLS directory. **/ inline void TlsDirectory::setAddressOfIndex(std::uint64_t value) @@ -303,7 +302,7 @@ namespace PeLib } /** - * @param dwValue The new AddressOfCallBacks value of the TLS directory. + * @param value The new AddressOfCallBacks value of the TLS directory. **/ inline void TlsDirectory::setAddressOfCallBacks(std::uint64_t value) diff --git a/src/fileformat/types/tls_info/tls_info.cpp b/src/fileformat/types/tls_info/tls_info.cpp index dce8b7dce..9efe4a557 100644 --- a/src/fileformat/types/tls_info/tls_info.cpp +++ b/src/fileformat/types/tls_info/tls_info.cpp @@ -152,7 +152,7 @@ void TlsInfo::setCallBacksAddr(std::uint64_t cbAddr) /** * Set array of callbacks -* @param cbAddr address of callbacks to set +* @param callbacks address of callbacks to set */ void TlsInfo::setCallBacks(const std::vector & callbacks) { diff --git a/src/pelib/BoundImportDirectory.cpp b/src/pelib/BoundImportDirectory.cpp index e71d26aab..1c784a341 100644 --- a/src/pelib/BoundImportDirectory.cpp +++ b/src/pelib/BoundImportDirectory.cpp @@ -77,6 +77,13 @@ namespace PeLib return static_cast(m_vIbd.size()); } + /** + * Searches for the first instance of a module with the given modulename. + * @param inpBuffer Reference to the input buffer + * @param data source data + * @param dwSize length of the source data + * @return ERROR_NONE if success, otherwise an error code. + **/ int BoundImportDirectory::read(InputBuffer& inpBuffer, unsigned char* data, unsigned int dwSize) { std::vector currentDirectory; @@ -158,8 +165,7 @@ namespace PeLib /** * Reads the BoundImport directory from a PE file. - * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. + * @param imageLoader Reference to the image loader **/ int BoundImportDirectory::read(ImageLoader & imageLoader) { diff --git a/src/pelib/ComHeaderDirectory.cpp b/src/pelib/ComHeaderDirectory.cpp index 45ad4a8a2..ff40af3ee 100644 --- a/src/pelib/ComHeaderDirectory.cpp +++ b/src/pelib/ComHeaderDirectory.cpp @@ -17,8 +17,7 @@ namespace PeLib { /** * Reads a file's COM+ descriptor. - * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. + * @param imageLoader Reference to the valid PE image loader **/ int ComHeaderDirectory::read(ImageLoader & imageLoader) diff --git a/src/pelib/DebugDirectory.cpp b/src/pelib/DebugDirectory.cpp index 8066bf9b8..7aa1443db 100644 --- a/src/pelib/DebugDirectory.cpp +++ b/src/pelib/DebugDirectory.cpp @@ -17,7 +17,7 @@ namespace PeLib { /** * @param inStream Input stream. - * @param peHeader A valid PE header which is necessary because some RVA calculations need to be done. + * @param imageLoader A valid image loader reference which is necessary because some RVA calculations need to be done. **/ int DebugDirectory::read(std::istream& inStream, ImageLoader & imageLoader) diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 33e726db4..85dbb3b80 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -588,8 +588,8 @@ PeLib::PELIB_IMAGE_SECTION_HEADER * PeLib::ImageLoader::addSection(const char * return nullptr; // Calculate the new RVA and file offset - std::uint32_t Rva = 0; - std::uint32_t Raw = 0; + uint32_t Rva = 0; + uint32_t Raw = 0; calcNewSectionAddresses(Rva, Raw); // Create new section @@ -604,7 +604,7 @@ PeLib::PELIB_IMAGE_SECTION_HEADER * PeLib::ImageLoader::addSection(const char * return getSectionHeader(sections.size() - 1); } -void PeLib::ImageLoader::calcNewSectionAddresses(uint32_t & Rva, std::uint32_t & RawOffset) +void PeLib::ImageLoader::calcNewSectionAddresses(uint32_t & Rva, uint32_t & RawOffset) { uint32_t NewRawOffset = optionalHeader.SizeOfHeaders; uint32_t NewRva = optionalHeader.SizeOfHeaders; @@ -793,7 +793,7 @@ PeLib::LoaderError PeLib::ImageLoader::loaderError() const //----------------------------------------------------------------------------- // Interface for loading files -int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOnly) +int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOnly) { int fileError; @@ -1987,7 +1987,7 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) return ERROR_NONE; } -int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, size_t fileSize) +int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_t fileSize) { if(hdr.e_magic != PELIB_IMAGE_DOS_SIGNATURE) return ERROR_INVALID_FILE; diff --git a/src/pelib/ResourceDirectory.cpp b/src/pelib/ResourceDirectory.cpp index b884bfd78..7e8d9b5e6 100644 --- a/src/pelib/ResourceDirectory.cpp +++ b/src/pelib/ResourceDirectory.cpp @@ -305,7 +305,7 @@ namespace PeLib * @param imageLoader An image loaded into the ImageLoader parser * @param uiRsrcRva RVA of the beginning of the resource directory. * @param uiOffset Offset of the resource leaf that's to be read. - * @param uiSizeOfImage Size of the image. + * @param sizeOfImage Size of the image. * @param resDir Resource directory. **/ int ResourceLeaf::read( @@ -621,10 +621,10 @@ namespace PeLib /** * Reads the next resource node from the input file. - * @param imageLoader An input stream. + * @param imageLoader An image loaded into the ImageLoader parser * @param uiRsrcRva RVA of the beginning of the resource directory. * @param uiOffset Offset of the resource node that's to be read. - * @param uiSizeOfImage Size of the image. + * @param sizeOfImage Size of the image. * @param resDir Resource directory. **/ int ResourceNode::read( From 608c2d08ba3a2a36313d9d304d94aae535a23bc1 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 14 Jul 2020 12:09:54 +0200 Subject: [PATCH 24/34] Fixing Mac build --- include/retdec/pelib/ImportDirectory.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index 4c1824b86..a50966fdd 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -14,6 +14,7 @@ #define IMPORTDIRECTORY_H #include +#include #include "retdec/pelib/PeLibAux.h" #include "retdec/pelib/ImageLoader.h" From e33bc6e41fb42560b3ac025a69d8aef8f6806821 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 14 Jul 2020 12:21:15 +0200 Subject: [PATCH 25/34] Fixing doxygen build --- include/retdec/fileformat/file_format/pe/pe_format_parser.h | 2 +- include/retdec/pelib/ImportDirectory.h | 4 ++-- src/fileformat/file_format/file_format.cpp | 4 ++-- src/fileinfo/file_wrapper/pe_wrapper.cpp | 2 +- src/fileinfo/file_wrapper/pe_wrapper.h | 2 +- src/pelib/ImageLoader.cpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/retdec/fileformat/file_format/pe/pe_format_parser.h b/include/retdec/fileformat/file_format/pe/pe_format_parser.h index 27c1f5183..fb721bfeb 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format_parser.h +++ b/include/retdec/fileformat/file_format/pe/pe_format_parser.h @@ -1,5 +1,5 @@ /** - * @file include/retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser.h + * @file include/retdec/fileformat/file_format/pe/pe_format_parser.h * @brief Definition of PeFormatParser class. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index a50966fdd..57c57ffa6 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -546,8 +546,7 @@ namespace PeLib /** * Updates pointer size for import directory - * @param inStream Input stream. - * @param peHeader A valid PE header. + * @param pointerSize Size of the pointer (4 or 8 bytes). **/ inline void ImportDirectory::setPointerSize(std::uint32_t pointerSize) @@ -1027,6 +1026,7 @@ namespace PeLib * @param strFilename Name of the file. * @param uiOffset File Offset of the new import directory. * @param uiRva RVA which belongs to that file offset. + * @param pointerSize Size of the pointer (4 bytes or 8 bytes) **/ inline int ImportDirectory::write(const std::string& strFilename, std::uint32_t uiOffset, std::uint32_t uiRva, std::uint32_t pointerSize) diff --git a/src/fileformat/file_format/file_format.cpp b/src/fileformat/file_format/file_format.cpp index eec2b9e8c..a7aaa715b 100644 --- a/src/fileformat/file_format/file_format.cpp +++ b/src/fileformat/file_format/file_format.cpp @@ -2061,8 +2061,8 @@ bool FileFormat::get8ByteOffset(std::uint64_t offset, std::uint64_t &res, retdec /** * Get long double from the specified offset - * If system has 80-bit (10-std::uint8_t) long double, copy data directly. - * Else convert 80-bit (10-std::uint8_t) long double into 64-bit (8-std::uint8_t) double. + * If system has 80-bit (10 - uint8_t) long double, copy data directly. + * Else convert 80-bit (10 - uint8_t) long double into 64-bit (8 - uint8_t) double. * @param offset Offset to get double from * @param res Result double * @return Status of operation (@c true if all is OK, @c false otherwise) diff --git a/src/fileinfo/file_wrapper/pe_wrapper.cpp b/src/fileinfo/file_wrapper/pe_wrapper.cpp index b5e58e918..f7c8688f8 100644 --- a/src/fileinfo/file_wrapper/pe_wrapper.cpp +++ b/src/fileinfo/file_wrapper/pe_wrapper.cpp @@ -1,5 +1,5 @@ /** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper.cpp + * @file src/fileinfo/file_wrapper/pe_wrapper.cpp * @brief Methods of PeWrapper class. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/src/fileinfo/file_wrapper/pe_wrapper.h b/src/fileinfo/file_wrapper/pe_wrapper.h index 0815800aa..1121dcd9e 100644 --- a/src/fileinfo/file_wrapper/pe_wrapper.h +++ b/src/fileinfo/file_wrapper/pe_wrapper.h @@ -1,5 +1,5 @@ /** - * @file src/fileinfo/file_wrapper/pe/pe_wrapper.h + * @file src/fileinfo/file_wrapper/pe_wrapper.h * @brief Definition of PeWrapper class. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 85dbb3b80..03a4b3d9e 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -1999,7 +1999,7 @@ int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_ return ERROR_NONE; } -int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, size_t fileSize) +int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, std::size_t fileSize) { PELIB_IMAGE_DOS_HEADER tempDosHeader; int fileError; From 0f8bbbbc3d680046bc33029f2630dbdfef921ffc Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 14 Jul 2020 12:42:03 +0200 Subject: [PATCH 26/34] Fixing Mac build --- src/pelib/RichHeader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pelib/RichHeader.cpp b/src/pelib/RichHeader.cpp index 3b87ea253..1202d1d45 100644 --- a/src/pelib/RichHeader.cpp +++ b/src/pelib/RichHeader.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/RichHeader.h" From b69710082b1c47756e9a2847c2a16a0617204fbf Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 14 Jul 2020 13:25:13 +0200 Subject: [PATCH 27/34] Cleaning up --- src/fileinfo/file_wrapper/pe_wrapper.cpp | 2 +- src/fileinfo/file_wrapper/pe_wrapper.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/fileinfo/file_wrapper/pe_wrapper.cpp b/src/fileinfo/file_wrapper/pe_wrapper.cpp index f7c8688f8..19236386e 100644 --- a/src/fileinfo/file_wrapper/pe_wrapper.cpp +++ b/src/fileinfo/file_wrapper/pe_wrapper.cpp @@ -124,7 +124,7 @@ std::string PeWrapper::getPeType() const { switch(file->imageLoader().getMagic()) { - case PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC: + case PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC: return "PE32"; case PELIB_IMAGE_ROM_OPTIONAL_HDR_MAGIC: return "ROM image"; diff --git a/src/fileinfo/file_wrapper/pe_wrapper.h b/src/fileinfo/file_wrapper/pe_wrapper.h index 1121dcd9e..76259e7ea 100644 --- a/src/fileinfo/file_wrapper/pe_wrapper.h +++ b/src/fileinfo/file_wrapper/pe_wrapper.h @@ -19,8 +19,6 @@ namespace fileinfo { * Wrapper for parsing PE files */ -class PeLib::PeFileT; - class PeWrapper : public retdec::fileformat::PeFormat { public: From 5f7954652f365bab7ebc596b89d5a43d259929f9 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 15 Jul 2020 07:36:25 +0200 Subject: [PATCH 28/34] Cleaning up --- include/retdec/pelib/ImageLoader.h | 14 +- include/retdec/pelib/MzHeader.h | 164 -- include/retdec/pelib/PeHeader.h | 3208 ---------------------------- src/pelib/ImageLoader.cpp | 64 +- src/pelib/MzHeader.cpp | 637 ------ src/pelib/PeHeader.cpp | 94 - 6 files changed, 41 insertions(+), 4140 deletions(-) delete mode 100644 include/retdec/pelib/MzHeader.h delete mode 100644 include/retdec/pelib/PeHeader.h delete mode 100644 src/pelib/MzHeader.cpp delete mode 100644 src/pelib/PeHeader.cpp diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 0347f4949..5fa01f546 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -21,15 +21,15 @@ namespace PeLib { //----------------------------------------------------------------------------- -// Enum for Windows loader emulation +// Enum for Windows build numbers enum : std::uint32_t { - LoaderModeWindowsXP = 0x51, // Behavior equal to Windows XP - LoaderModeWindows7 = 0x61, // Behavior equal to Windows 7 - LoaderModeWindows10 = 0xA0, // Behavior equal to Windows 10 - WindowsVerMask = 0x0FFF, // Mask for extracting the operating system - LoaderMode64BitWindows = 0x1000, // Emulate 64-bit system + BuildNumberXP = 2600, // Behavior equal to Windows XP + BuildNumber7 = 7601, // Behavior equal to Windows 7 + BuildNumber10 = 10240, // Behavior equal to Windows 10 + BuildNumberMask = 0x0FFFF, // Mask for extracting the operating system + BuildNumber64Bit = 0x10000, // Emulate 64-bit system }; //----------------------------------------------------------------------------- @@ -436,7 +436,7 @@ class ImageLoader PELIB_IMAGE_OPTIONAL_HEADER optionalHeader; // 32/64-bit optional header LoaderError ldrError; std::uint32_t ntSignature; - std::uint32_t loaderMode; + std::uint32_t windowsBuildNumber; std::uint32_t maxSectionCount; std::uint32_t realNumberOfRvaAndSizes; // Real present number of RVA and sizes std::uint32_t checkSumFileOffset; // File offset of the image checksum diff --git a/include/retdec/pelib/MzHeader.h b/include/retdec/pelib/MzHeader.h deleted file mode 100644 index 6abd3a88b..000000000 --- a/include/retdec/pelib/MzHeader.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -* MzHeader.h - Part of the PeLib library. -* -* Copyright (c) 2004 - 2005 Sebastian Porst (webmaster@the-interweb.com) -* All rights reserved. -* -* This software is licensed under the zlib/libpng License. -* For more details see http://www.opensource.org/licenses/zlib-license.php -* or the license information file (license.htm) in the root directory -* of PeLib. -*/ - -#ifndef MZHEADER_H -#define MZHEADER_H - -#error Bla - -#include "retdec/pelib/PeLibInc.h" - -namespace PeLib -{ - /// Class that handles the MZ header of files. - /** - * This class can read and modify MZ headers. It provides set- and get functions to access - * all individual members of a MZ header. Furthermore it's possible to validate and rebuild - * MZ headers. - **/ - class MzHeader - { - private: - PELIB_IMAGE_DOS_HEADER m_idhHeader; ///< Stores all MZ header information. - std::string m_headerString; ///< MZ header in string representation. - LoaderError m_ldrError; - - /// Reads data from an InputBuffer into a MZ header struct. - void read(InputBuffer& ibBuffer); - - /// Offset of the MZ header in the original file. - unsigned int originalOffset; - - void setLoaderError(LoaderError ldrError); - - public: - - enum Field {e_magic, e_cblp, e_cp, e_crlc, e_cparhdr, e_minalloc, e_maxalloc, - e_ss, e_sp, e_csum, e_ip, e_cs, e_lfarlc, e_ovno, e_res, e_oemid, - e_oeminfo, e_res2, e_lfanew}; - - MzHeader(); - - /// Checks if the current MZ header is valid. - bool isValid() const; // EXPORT - - bool isValid(Field field) const; // EXPORT _field - - /// Returns loader error for the header - LoaderError loaderError() const; - - /// Corrects the current MZ header. - void makeValid(); // EXPORT - - void makeValid(Field field); // EXPORT _field - - /// Reads the MZ header of a file. - int read(std::istream& inStream); // EXPORT - - /// Reads the MZ header from a memory location. - int read(unsigned char* pcBuffer, unsigned int uiSize, unsigned int originalOffs = 0); // EXPORT _fromMemory - - /// Rebuild the MZ header. - void rebuild(std::vector& vBuffer) const; // EXPORT - - /// Returns the size of the current MZ header. - unsigned int size() const; // EXPORT - - /// Writes the current MZ header to offset 0 of a file. - int write(const std::string& strFilename, std::uint32_t dwOffset) const; // EXPORT - - /// Gets MZ header. - const PELIB_IMAGE_DOS_HEADER& getHeader() const; // EXPORT - /// Gets MZ header in string representation. - const std::string& getString() const; // EXPORT - - /// Gets the e_magic value of the MZ header. - std::uint16_t getMagicNumber() const; // EXPORT - /// Gets the e_cblp value of the MZ header. - std::uint16_t getBytesOnLastPage() const; // EXPORT - /// Gets the e_cp value of the MZ header. - std::uint16_t getPagesInFile() const; // EXPORT - /// Gets the e_crlc value of the MZ header. - std::uint16_t getRelocations() const; // EXPORT - /// Gets the e_cparhdr value of the MZ header. - std::uint16_t getSizeOfHeader() const; // EXPORT - /// Gets the e_minalloc value of the MZ header. - std::uint16_t getMinExtraParagraphs() const; // EXPORT - /// Gets the e_maxalloc value of the MZ header. - std::uint16_t getMaxExtraParagraphs() const; // EXPORT - /// Gets the e_ss value of the MZ header. - std::uint16_t getSsValue() const; // EXPORT - /// Gets the e_sp value of the MZ header. - std::uint16_t getSpValue() const; // EXPORT - /// Gets the e_csum value of the MZ header. - std::uint16_t getChecksum() const; // EXPORT - /// Gets the e_ip value of the MZ header. - std::uint16_t getIpValue() const; // EXPORT - /// Gets the e_cs value of the MZ header. - std::uint16_t getCsValue() const; // EXPORT - /// Gets the e_lfarlc value of the MZ header. - std::uint16_t getAddrOfRelocationTable() const; // EXPORT - /// Gets the e_ovnovalue of the MZ header. - std::uint16_t getOverlayNumber() const; // EXPORT - /// Gets the e_oemid value of the MZ header. - std::uint16_t getOemIdentifier() const; // EXPORT - /// Gets the e_oeminfo value of the MZ header. - std::uint16_t getOemInformation() const; // EXPORT - /// Gets the e_lfanew value of the MZ header. - std::uint32_t getAddressOfPeHeader() const; // EXPORT - /// Gets the e_res of the MZ header. - std::uint16_t getReservedWords1(unsigned int uiNr) const; // EXPORT - /// Gets the e_res2 of the MZ header. - std::uint16_t getReservedWords2(unsigned int uiNr) const; // EXPORT - - /// Sets the e_magic value of the MZ header. - void setMagicNumber(std::uint16_t wValue); // EXPORT - /// Sets the e_cblp value of the MZ header. - void setBytesOnLastPage(std::uint16_t wValue); // EXPORT - /// Sets the e_cp value of the MZ header. - void setPagesInFile(std::uint16_t wValue); // EXPORT - /// Sets the e_crlc value of the MZ header. - void setRelocations(std::uint16_t wValue); // EXPORT - /// Sets the e_cparhdr value of the MZ header. - void setSizeOfHeader(std::uint16_t wValue); // EXPORT - /// Sets the e_minalloc value of the MZ header. - void setMinExtraParagraphs(std::uint16_t wValue); // EXPORT - /// Sets the e_maxalloc value of the MZ header. - void setMaxExtraParagraphs(std::uint16_t wValue); // EXPORT - /// Sets the e_ss value of the MZ header. - void setSsValue(std::uint16_t wValue); // EXPORT - /// Sets the e_sp value of the MZ header. - void setSpValue(std::uint16_t wValue); // EXPORT - /// Sets the e_csum value of the MZ header. - void setChecksum(std::uint16_t wValue); // EXPORT - /// Sets the e_ip value of the MZ header. - void setIpValue(std::uint16_t wValue); // EXPORT - /// Sets the e_cs value of the MZ header. - void setCsValue(std::uint16_t wValue); // EXPORT - /// Sets the e_lfarlc value of the MZ header. - void setAddrOfRelocationTable(std::uint16_t wValue); // EXPORT - /// Sets the e_ovno value of the MZ header. - void setOverlayNumber(std::uint16_t wValue); // EXPORT - /// Sets the e_oemid value of the MZ header. - void setOemIdentifier(std::uint16_t wValue); // EXPORT - /// Sets the e_oeminfo value of the MZ header. - void setOemInformation(std::uint16_t wValue); // EXPORT - /// Sets the e_lfanew value of the MZ header. - void setAddressOfPeHeader(std::uint32_t dwValue); // EXPORT - /// Sets the e_res value of the MZ header. - void setReservedWords1(unsigned int uiNr, std::uint16_t wValue); // EXPORT - /// Sets the e_res2 value of the MZ header. - void setReservedWords2(unsigned int uiNr, std::uint16_t wValue); // EXPORT - }; -} - -#endif diff --git a/include/retdec/pelib/PeHeader.h b/include/retdec/pelib/PeHeader.h deleted file mode 100644 index c0f6789e8..000000000 --- a/include/retdec/pelib/PeHeader.h +++ /dev/null @@ -1,3208 +0,0 @@ -/* -* PeHeader.h - Part of the PeLib library. -* -* Copyright (c) 2004 - 2005 Sebastian Porst (webmaster@the-interweb.com) -* All rights reserved. -* -* This software is licensed under the zlib/libpng License. -* For more details see http://www.opensource.org/licenses/zlib-license.php -* or the license information file (license.htm) in the root directory -* of PeLib. -*/ - -#ifndef PEHEADER_H -#define PEHEADER_H - -#include -#include - -#include "retdec/pelib/PeLibAux.h" -#include "retdec/pelib/MzHeader.h" - -#error Bla - -namespace PeLib -{ - class PeHeader - { -// protected: -// virtual void readBaseOfData(InputBuffer& ibBuffer) = 0; -// virtual void rebuildBaseOfData(OutputBuffer& obBuffer) const = 0; - - public: - virtual ~PeHeader(){}; - }; - - /// Class that handles the PE header of files. - /** - * This class can read and modify PE headers. It provides set- and get functions to access - * all individual members of a PE header. Furthermore it's possible to validate and rebuild - * PE headers. A PE header includes the IMAGE_Nt_HEADERS and the section definitions of a PE file. - * \todo getIdReservedRva - **/ - template - class PeHeaderT : public PeHeader - { - private: - //void readBaseOfData(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS & header) const; - void rebuildBaseOfData(OutputBuffer& obBuffer) const; - - protected: - std::vector m_vIsh; ///< Stores section header information. - PELIB_IMAGE_NT_HEADERS_EX m_inthHeader; ///< Stores Nt header information. - MzHeader m_mzHeader; ///< Stored DOS header. - std::uint32_t m_uiOffset; ///< Equivalent to the value returned by #PeLib::MzHeader::getAddressOfPeHeader - LoaderError m_ldrError; - unsigned long m_checksumFileOffset; ///< File offset of checksum field in optional PE header - unsigned long m_secDirFileOffset; ///< File offset of security data directory - - void setLoaderError(LoaderError ldrError); - - public: - typedef typename FieldSizes::VAR4_8 VAR4_8; - - PeHeaderT() : m_uiOffset(0), m_checksumFileOffset(0), m_secDirFileOffset(0), m_ldrError(LDR_ERROR_NONE) - { - } - - LoaderError loaderError() const; - - /// Add a section to the header. - int addSection(const std::string& strName, std::uint32_t dwSize); // EXPORT - - // Splits a section into two. - int splitSection(std::uint16_t uiSectionnr, const std::string& first, const std::string& second, std::uint32_t dwSplitOffset); // EXPORT - - // Removes a section. - int removeSection(std::uint16_t uiSectionnr); // EXPORT - - unsigned int calcSizeOfImage() const; // EXPORT - - /// Returns the unused space after the header. - unsigned int calcSpaceAfterHeader() const; // EXPORT - - /// Returns the address of the physically first section (not the first defined section). - unsigned int calcStartOfCode() const; // EXPORT - - /// Calculates the offset for a new section of size uiSize. - unsigned int calcOffset() const; // EXPORT - - /// Calculates the Rva for a new section of size uiSize. - unsigned int calcRva() const; // EXPORT - - /// Returns the number of sections in the current file. - std::uint16_t calcNumberOfSections() const; // EXPORT - - void enlargeLastSection(unsigned int uiSize); // EXPORT - - /// Returns the section Id of the section that contains the offset. - std::uint16_t getSectionWithOffset(VAR4_8 dwOffset) const; // EXPORT - - /// Returns the number of the section which the given relative address points to. - std::uint16_t getSectionWithRva(VAR4_8 rva) const; // EXPORT - - bool isValid() const; // EXPORT - bool isValid(unsigned int foo) const; // EXPORT - - /// Corrects the current PE header. - void makeValid(std::uint32_t dwOffset); // EXPORT - - /// Converts a file offset to a relative virtual offset. - unsigned int offsetToRva(VAR4_8 dwOffset) const; // EXPORT - - /// Converts a file offset to a virtual address. - unsigned int offsetToVa(VAR4_8 dwOffset) const; // EXPORT - - /// Reads the PE header of a file. - int read( - std::istream& inStream, - unsigned int uiOffset, - const MzHeader &mzHeader); // EXPORT - - void readHeader(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS_EX& header); - void readDataDirectories( - std::istream& inStream, - unsigned int uiOffset, - PELIB_IMAGE_NT_HEADERS_EX& header); - std::vector readSections( - std::istream& inStream, - unsigned int uiOffset, - PELIB_IMAGE_NT_HEADERS_EX& header); - - /// Rebuilds the current PE header. - void rebuild(std::vector& vBuffer) const; // EXPORT - - // Checks whether RVA is valid for this image. - bool isValidRva(VAR4_8 dwRva) const; // EXPORT - - /// Converts a relative virtual address to a file offset. - VAR4_8 rvaToOffset(VAR4_8 dwRva) const; // EXPORT - VAR4_8 rvaToOffsetSpeculative(VAR4_8 dwRva) const; // EXPORT - - /// Converts a relative virtual address to a virtual address. - VAR4_8 rvaToVa(VAR4_8 dwRva) const; // EXPORT - - /// Calculates the size for the current PE header including all section definitions. - unsigned int size() const; - - VAR4_8 vaToRva(VAR4_8 dwRva) const; // EXPORT - VAR4_8 vaToOffset(VAR4_8 dwRva) const; // EXPORT - VAR4_8 vaToOffsetSpeculative(VAR4_8 dwRva) const; // EXPORT - - /// Save the PE header to a file. - int write(std::string strFilename, unsigned int uiOffset) const; // EXPORT - - /// Writes sections to a file. - int writeSections(const std::string& strFilename) const; // EXPORT - /// Overwrites a section with new data. - int writeSectionData(const std::string& strFilename, std::uint16_t wSecnr, const std::vector& vBuffer) const; // EXPORT - - /// Returns file offset of checksum field - unsigned int getChecksumFileOffset() const; // EXPORT - /// Returns file offset of security data directory - unsigned int getSecDirFileOffset() const; // EXPORT - -// header getters - /// Returns reference to NT headers. - const PELIB_IMAGE_NT_HEADERS_EX& getNtHeaders() const; // EXPORT - /// Returns the Signature value of the header. - std::uint32_t getNtSignature() const; // EXPORT - /// Returns the Machine value of the header. - std::uint16_t getMachine() const; // EXPORT - /// Returns the Sections value of the header. - std::uint16_t getNumberOfSections() const; // EXPORT - /// Returns the TimeDateStamp value of the header. - std::uint32_t getTimeDateStamp() const; // EXPORT - /// Returns the PointerToSymbolTable value of the header. - std::uint32_t getPointerToSymbolTable() const; // EXPORT - /// Returns the NumberOfSymbols value of the header. - std::uint32_t getNumberOfSymbols() const; // EXPORT - /// Returns the SizeOfOptionalHeader value of the header. - std::uint16_t getSizeOfOptionalHeader() const; // EXPORT - /// Returns the Characteristics value of the header. - std::uint16_t getCharacteristics() const; // EXPORT - - /// Returns the Magic value of the header. - std::uint16_t getMagic() const; // EXPORT - /// Returns the MajorLinkerVersion value of the header. - std::uint8_t getMajorLinkerVersion() const; // EXPORT - /// Returns the MinorLinkerVersion value of the header. - std::uint8_t getMinorLinkerVersion() const; // EXPORT - /// Returns the SizeOfCode value of the header. - std::uint32_t getSizeOfCode() const; // EXPORT - /// Returns the SizeOfInitializedData value of the header. - std::uint32_t getSizeOfInitializedData() const; // EXPORT - /// Returns the SizeOfUninitializedData value of the header. - std::uint32_t getSizeOfUninitializedData() const; // EXPORT - /// Returns the AddressOfEntryPoint value of the header. - std::uint32_t getAddressOfEntryPoint() const; // EXPORT - /// Returns the BaseOfCode value of the header. - std::uint32_t getBaseOfCode() const; // EXPORT - /// Returns the ImageBase value of the header. - VAR4_8 getImageBase() const; // EXPORT - /// Returns the SectionAlignment value of the header. - std::uint32_t getSectionAlignment() const; // EXPORT - /// Returns the FileAlignment value of the header. - std::uint32_t getFileAlignment() const; // EXPORT - /// Returns the MajorOperatingSystemVersion value of the header. - std::uint16_t getMajorOperatingSystemVersion() const; // EXPORT - /// Returns the MinorOperatingSystemVersion value of the header. - std::uint16_t getMinorOperatingSystemVersion() const; // EXPORT - /// Returns the MajorImageVersion value of the header. - std::uint16_t getMajorImageVersion() const; // EXPORT - /// Returns the MinorImageVersion value of the header. - std::uint16_t getMinorImageVersion() const; // EXPORT - /// Returns the MajorSubsystemVersion value of the header. - std::uint16_t getMajorSubsystemVersion() const; // EXPORT - /// Returns the MinorSubsystemVersion value of the header. - std::uint16_t getMinorSubsystemVersion() const; // EXPORT - /// Returns the Reserved1 value of the header. - std::uint32_t getWin32VersionValue() const; // EXPORT - /// Returns the SizeOfImage value of the header. - std::uint32_t getSizeOfImage() const; // EXPORT - /// Returns the SizeOfHeaders value of the header. - std::uint32_t getSizeOfHeaders() const; // EXPORT - /// Returns the CheckSum value of the header. - std::uint32_t getCheckSum() const; // EXPORT - /// Returns the Subsystem value of the header. - std::uint16_t getSubsystem() const; // EXPORT - /// Returns the DllCharacteristics value of the header. - std::uint16_t getDllCharacteristics() const; // EXPORT - /// Returns the SizeOfStackReserve value of the header. - VAR4_8 getSizeOfStackReserve() const; // EXPORT - /// Returns the SizeOfStackCommit value of the header. - VAR4_8 getSizeOfStackCommit() const; // EXPORT - /// Returns the SizeOfHeapReserve value of the header. - VAR4_8 getSizeOfHeapReserve() const; // EXPORT - /// Returns the SizeOfHeapCommit value of the header. - VAR4_8 getSizeOfHeapCommit() const; // EXPORT - /// Returns the LoaderFlags value of the header. - std::uint32_t getLoaderFlags() const; // EXPORT - /// Returns the NumberOfRvaAndSizes value of the header. - std::uint32_t getNumberOfRvaAndSizes() const; // EXPORT - std::uint32_t calcNumberOfRvaAndSizes() const; // EXPORT - - void addDataDirectory(); // EXPORT - void removeDataDirectory(std::uint32_t index); // EXPORT - -// image directory getters - /// Returns the relative virtual address of the image directory Export. - std::uint32_t getIddExportRva() const; // EXPORT - /// Returns the size of the image directory Export. - std::uint32_t getIddExportSize() const; // EXPORT - /// Returns the relative virtual address of the image directory Import. - std::uint32_t getIddImportRva() const; // EXPORT - /// Returns the size of the image directory Import. - std::uint32_t getIddImportSize() const; // EXPORT - /// Returns the relative virtual address of the image directory Resource. - std::uint32_t getIddResourceRva() const; // EXPORT - /// Returns the size of the image directory Resource. - std::uint32_t getIddResourceSize() const; // EXPORT - /// Returns the relative virtual address of the image directory Exception. - std::uint32_t getIddExceptionRva() const; // EXPORT - /// Returns the size of the image directory Exception. - std::uint32_t getIddExceptionSize() const; // EXPORT - /// Returns the relative virtual address of the image directory Security. - std::uint32_t getIddSecurityRva() const; // EXPORT - /// Returns the size of the image directory Security. - std::uint32_t getIddSecuritySize() const; // EXPORT - /// Returns the relative virtual address of the image directory Base Reloc. - std::uint32_t getIddBaseRelocRva() const; // EXPORT - /// Returns the size of the image directory Base Reloc. - std::uint32_t getIddBaseRelocSize() const; // EXPORT - /// Returns the relative virtual address of the image directory Debug. - std::uint32_t getIddDebugRva() const; // EXPORT - /// Returns the size of the image directory Debug. - std::uint32_t getIddDebugSize() const; // EXPORT - /// Returns the relative virtual address of the image directory Architecture. - std::uint32_t getIddArchitectureRva() const; // EXPORT - /// Returns the size of the image directory Architecture. - std::uint32_t getIddArchitectureSize() const; // EXPORT - /// Returns the relative virtual address of the image directory GlobalPtr. - std::uint32_t getIddGlobalPtrRva() const; // EXPORT - /// Returns the size of the image directory GlobalPtr. - std::uint32_t getIddGlobalPtrSize() const; // EXPORT - /// Returns the relative virtual address of the image directory Tls. - std::uint32_t getIddTlsRva() const; // EXPORT - /// Returns the size of the image directory Tls. - std::uint32_t getIddTlsSize() const; // EXPORT - /// Returns the relative virtual address of the image directory LoadConfig. - std::uint32_t getIddLoadConfigRva() const; // EXPORT - /// Returns the size of the image directory LoadConfig. - std::uint32_t getIddLoadConfigSize() const; // EXPORT - /// Returns the relative virtual address of the image directory BoundImport. - std::uint32_t getIddBoundImportRva() const; // EXPORT - /// Returns the size of the image directory BoundImport. - std::uint32_t getIddBoundImportSize() const; // EXPORT - /// Returns the relative virtual address of the image directory Iat. - std::uint32_t getIddIatRva() const; // EXPORT - /// Returns the size of the image directory Iat. - std::uint32_t getIddIatSize() const; // EXPORT - /// Returns the relative virtual address of the image directory DelayImport. - std::uint32_t getIddDelayImportRva() const; // EXPORT - /// Returns the size of the image directory DelayImport. - std::uint32_t getIddDelayImportSize() const; // EXPORT - /// Returns the relative virtual address of the image directory COM Descriptor. - std::uint32_t getIddComHeaderRva() const; // EXPORT - /// Returns the size of the image directory COM Descriptor. - std::uint32_t getIddComHeaderSize() const; // EXPORT - - /// Returns the relative virtual address of an image directory. - std::uint32_t getImageDataDirectoryRva(std::uint32_t dwDirectory) const; // EXPORT - /// Returns the size of an image directory. - std::uint32_t getImageDataDirectorySize(std::uint32_t dwDirectory) const; // EXPORT - - void setImageDataDirectoryRva(std::uint32_t dwDirectory, std::uint32_t value); // EXPORT - void setImageDataDirectorySize(std::uint32_t dwDirectory, std::uint32_t value); // EXPORT - -// section getters - /// Returns the name of a section. - std::string getSectionName(std::uint16_t uiSectionnr) const; // EXPORT - // Returns the name of a section stored in string table - std::string getSectionNameFromStringTable(std::uint16_t uiSectionnr) const; // EXPORT - /// Returns the virtual size of a section. - std::uint32_t getVirtualSize(std::uint16_t uiSectionnr) const; // EXPORT - /// Returns the virtual address of a section. - std::uint32_t getVirtualAddress(std::uint16_t uiSectionnr) const; // EXPORT - /// Returns the size of a section's raw data. - std::uint32_t getSizeOfRawData(std::uint16_t uiSectionnr) const; // EXPORT - /// Returns file offset of the data of a section. - std::uint32_t getPointerToRawData(std::uint16_t uiSectionnr) const; // EXPORT - /// Returns the rva of the relocations of a section. - std::uint32_t getPointerToRelocations(std::uint16_t uiSectionnr) const; // EXPORT - /// Returns the rva of the line numbers of a section. - std::uint32_t getPointerToLinenumbers(std::uint16_t uiSectionnr) const; // EXPORT - /// Returns the number of relocations of a section. - std::uint32_t getNumberOfRelocations(std::uint16_t uiSectionnr) const; // EXPORT - /// Returns the number of line numbers of a section. - std::uint32_t getNumberOfLinenumbers(std::uint16_t uiSectionnr) const; // EXPORT - /// Returns the characteristics of a section. - std::uint32_t getCharacteristics(std::uint16_t uiSectionnr) const; // EXPORT _section - -// header setters - /// Sets the Signature value of the header. - void setNtSignature(std::uint32_t value); // EXPORT - /// Sets the Machine value of the header. - void setMachine(std::uint16_t value); // EXPORT - /// Sets the Sections value of the header. - void setNumberOfSections(std::uint16_t value); // EXPORT - /// Sets the TimeDateStamp value of the header. - void setTimeDateStamp(std::uint32_t value); // EXPORT - /// Sets the PointerToSymbolTable value of the header. - void setPointerToSymbolTable(std::uint32_t value); // EXPORT - /// Sets the NumberOfSymbols value of the header. - void setNumberOfSymbols(std::uint32_t value); // EXPORT - /// Sets the SizeOfOptionalHeader value of the header. - void setSizeOfOptionalHeader(std::uint16_t value); // EXPORT - /// Sets the Characteristics value of the header. - void setCharacteristics(std::uint16_t value); // EXPORT _section - - /// Sets the Magic value of the header. - void setMagic(std::uint16_t value); // EXPORT - /// Sets the MajorLinkerVersion value of the header. - void setMajorLinkerVersion(std::uint8_t value); // EXPORT - /// Sets the MinorLinkerVersion value of the header. - void setMinorLinkerVersion(std::uint8_t value); // EXPORT - /// Sets the SizeOfCode value of the header. - void setSizeOfCode(std::uint32_t value); // EXPORT - /// Sets the SizeOfInitializedData value of the header. - void setSizeOfInitializedData(std::uint32_t value); // EXPORT - /// Sets the SizeOfUninitializedData value of the header. - void setSizeOfUninitializedData(std::uint32_t value); // EXPORT - /// Sets the AddressOfEntryPoint value of the header. - void setAddressOfEntryPoint(std::uint32_t value); // EXPORT - /// Sets the BaseOfCode value of the header. - void setBaseOfCode(std::uint32_t value); // EXPORT - /// Sets the ImageBase value of the header. - void setImageBase(VAR4_8 value); // EXPORT - /// Sets the SectionAlignment value of the header. - void setSectionAlignment(std::uint32_t value); // EXPORT - /// Sets the FileAlignment value of the header. - void setFileAlignment(std::uint32_t value); // EXPORT - /// Sets the MajorOperatingSystemVersion value of the header. - void setMajorOperatingSystemVersion(std::uint16_t value); // EXPORT - /// Sets the MinorOperatingSystemVersion value of the header. - void setMinorOperatingSystemVersion(std::uint16_t value); // EXPORT - /// Sets the MajorImageVersion value of the header. - void setMajorImageVersion(std::uint16_t value); // EXPORT - /// Sets the MinorImageVersion value of the header. - void setMinorImageVersion(std::uint16_t value); // EXPORT - /// Sets the MajorSubsystemVersion value of the header. - void setMajorSubsystemVersion(std::uint16_t value); // EXPORT - /// Sets the MinorSubsystemVersion value of the header. - void setMinorSubsystemVersion(std::uint16_t value); // EXPORT - /// Sets the Reserved1 value of the header. - void setWin32VersionValue(std::uint32_t value); // EXPORT - /// Sets the SizeOfImage value of the header. - void setSizeOfImage(std::uint32_t value); // EXPORT - /// Sets the SizeOfHeaders value of the header. - void setSizeOfHeaders(std::uint32_t value); // EXPORT - /// Sets the CheckSum value of the header. - void setCheckSum(std::uint32_t value); // EXPORT - /// Sets the Subsystem value of the header. - void setSubsystem(std::uint16_t value); // EXPORT - /// Sets the DllCharacteristics value of the header. - void setDllCharacteristics(std::uint16_t value); // EXPORT - /// Sets the SizeOfStackReserve value of the header. - void setSizeOfStackReserve(VAR4_8 value); // EXPORT - /// Sets the SizeOfStackCommit value of the header. - void setSizeOfStackCommit(VAR4_8 value); // EXPORT - /// Sets the SizeOfHeapReserve value of the header. - void setSizeOfHeapReserve(VAR4_8 value); // EXPORT - /// Sets the SizeOfHeapCommit value of the header. - void setSizeOfHeapCommit(VAR4_8 value); // EXPORT - /// Sets the LoaderFlags value of the header. - void setLoaderFlags(std::uint32_t value); // EXPORT - /// Sets the NumberOfRvaAndSizes value of the header. - void setNumberOfRvaAndSizes(std::uint32_t value); // EXPORT - -// image directory getters - void setIddDebugRva(std::uint32_t dwValue); // EXPORT - void setIddDebugSize(std::uint32_t dwValue); // EXPORT - void setIddDelayImportRva(std::uint32_t dwValue); // EXPORT - void setIddDelayImportSize(std::uint32_t dwValue); // EXPORT - void setIddExceptionRva(std::uint32_t dwValue); // EXPORT - void setIddExceptionSize(std::uint32_t dwValue); // EXPORT - void setIddGlobalPtrRva(std::uint32_t dwValue); // EXPORT - void setIddGlobalPtrSize(std::uint32_t dwValue); // EXPORT - void setIddIatRva(std::uint32_t dwValue); // EXPORT - void setIddIatSize(std::uint32_t dwValue); // EXPORT - void setIddLoadConfigRva(std::uint32_t dwValue); // EXPORT - void setIddLoadConfigSize(std::uint32_t dwValue); // EXPORT - void setIddResourceRva(std::uint32_t dwValue); // EXPORT - void setIddResourceSize(std::uint32_t dwValue); // EXPORT - void setIddSecurityRva(std::uint32_t dwValue); // EXPORT - void setIddSecuritySize(std::uint32_t dwValue); // EXPORT - void setIddTlsRva(std::uint32_t dwValue); // EXPORT - void setIddTlsSize(std::uint32_t dwValue); // EXPORT - - void setIddImportRva(std::uint32_t dwValue); // EXPORT - void setIddImportSize(std::uint32_t dwValue); // EXPORT - void setIddExportRva(std::uint32_t dwValue); // EXPORT - void setIddExportSize(std::uint32_t dwValue); // EXPORT - - void setIddBaseRelocRva(std::uint32_t value); // EXPORT - void setIddBaseRelocSize(std::uint32_t value); // EXPORT - void setIddArchitectureRva(std::uint32_t value); // EXPORT - void setIddArchitectureSize(std::uint32_t value); // EXPORT - void setIddComHeaderRva(std::uint32_t value); // EXPORT - void setIddComHeaderSize(std::uint32_t value); // EXPORT - - /// Set the name of a section. - void setSectionName(std::uint16_t uiSectionnr, std::string strName); // EXPORT - /// Set the virtual size of a section. - void setVirtualSize(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT - /// Set the virtual address of a section. - void setVirtualAddress(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT - /// Set the size of raw data of a section. - void setSizeOfRawData(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT - /// Set the file offset of a section. - void setPointerToRawData(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT - /// Set the pointer to relocations of a section. - void setPointerToRelocations(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT - /// Set the pointer to linenumbers of a section. - void setPointerToLinenumbers(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT - /// Set the number of relocations a section. - void setNumberOfRelocations(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT - /// Set the number of linenumbers section. - void setNumberOfLinenumbers(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT - /// Set the characteristics of a section. - void setCharacteristics(std::uint16_t uiSectionnr, std::uint32_t dwValue); // EXPORT - }; - - class PeHeader32 : public PeHeaderT<32> - { - public: - /// Returns the BaseOfData value of the header. - std::uint32_t getBaseOfData() const; // EXPORT - /// Sets the BaseOfData value of the header. - void setBaseOfData(std::uint32_t value); // EXPORT - }; - - class PeHeader64 : public PeHeaderT<64> - { - }; - - template - void PeHeaderT::addDataDirectory() - { - m_inthHeader.dataDirectories.push_back(PELIB_IMAGE_DATA_DIRECTORY()); - } - - template - void PeHeaderT::removeDataDirectory(std::uint32_t index) - { - if (m_inthHeader.lastDirectoryIsIncomplete && index == m_inthHeader.dataDirectories.size() - 1) - { - m_inthHeader.lastDirectoryIsIncomplete = false; - } - m_inthHeader.dataDirectories.erase(m_inthHeader.dataDirectories.begin() + index); - } - - /** - * Adds a new section to the header. The physical and virtual address as well as the virtual - * size of the section will be determined automatically from the raw size. The section - * characteristics will be set to IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | - * IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_CNT_CODE. All other values will be set to 0. - * Note: It's important that if the current header's FileAlignment and/or SectionAlignment values are - * 0 this function will fail. - * @param strName Name of the new section. If this name is longer than 8 bytes only the first 8 bytes will be used. - * @param dwSize Physical size of the new section in bytes. - * \todo Better code that handles files with 0 sections. - **/ - template - int PeHeaderT::addSection(const std::string& strName, std::uint32_t dwSize) - { - unsigned int uiSecnr = calcNumberOfSections(); - - if (!getFileAlignment()) - { - return ERROR_NO_FILE_ALIGNMENT; - } - else if (!getSectionAlignment()) - { - return ERROR_NO_SECTION_ALIGNMENT; - } - - if (uiSecnr) // Always allow 1 section. - { - if (uiSecnr == 0xFFFF) - { - return ERROR_TOO_MANY_SECTIONS; - } - } - - std::uint32_t dwOffset = calcOffset(/*dwSize*/); - std::uint32_t dwRva = calcRva(/*dwSize*/); - - PELIB_IMAGE_SECTION_HEADER ishdCurr; - m_vIsh.push_back(ishdCurr); - - setSectionName(uiSecnr, strName); - setSizeOfRawData(uiSecnr, alignOffset(dwSize, getFileAlignment())); - setPointerToRawData(uiSecnr, dwOffset); - setVirtualSize(uiSecnr, alignOffset(dwSize, getSectionAlignment())); - setVirtualAddress(uiSecnr, dwRva); - setCharacteristics(uiSecnr, PELIB_IMAGE_SCN_MEM_WRITE | PELIB_IMAGE_SCN_MEM_READ | PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA | PELIB_IMAGE_SCN_CNT_CODE); - - return ERROR_NONE; - } - - /** - * Splits an existing section in the file on the two sections. Section can only be split on the multiple - * of section alignment. First of the new sections will inherit all the characteristics from the old section. - * Second section will be initialized with IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA - * | IMAGE_SCN_CNT_CODE. Virtual size will be modified on both sections to match the raw size in the file. - * @param uiSectionnr The index of the section to be split. - * @param first The name of the first of the newly created sections. - * @param second The name of the second of the newly created sections. - * @param dwSplitOffset File offset at which to split the section into two. - * @todo Add option to split any section without restrictions. - **/ - template - int PeHeaderT::splitSection(std::uint16_t uiSectionnr, const std::string& first, const std::string& second, std::uint32_t dwSplitOffset) - { - if (!getFileAlignment()) - { - return ERROR_NO_FILE_ALIGNMENT; - } - else if (!getSectionAlignment()) - { - return ERROR_NO_SECTION_ALIGNMENT; - } - - // Index needs to be in the range <0, NUMBER OF SECTIONS) - if (uiSectionnr > calcNumberOfSections()) - return ERROR_ENTRY_NOT_FOUND; - - // Offset at which the section is going to be split must be multiple of section alignment - if (dwSplitOffset & (getSectionAlignment() - 1)) - return ERROR_NOT_ENOUGH_SPACE; - - // Do not allow to split if the offset of split is greater than the size of the section - // Nor do allow the section with size 0 to be created - if (dwSplitOffset >= getVirtualSize(uiSectionnr)) - return ERROR_NOT_ENOUGH_SPACE; - - // Move every section located after the inserted section by one position - m_vIsh.resize(m_vIsh.size() + 1); - for (int i = calcNumberOfSections() - 2; i >= uiSectionnr + 1; --i) - m_vIsh[i + 1] = m_vIsh[i]; - - std::uint32_t originalSize = getSizeOfRawData(uiSectionnr); - - // Setup the first of the new sections - setSectionName(uiSectionnr, first); - setSizeOfRawData(uiSectionnr, dwSplitOffset); - setVirtualSize(uiSectionnr, dwSplitOffset); - - // Setup the second of the new sections - setSectionName(uiSectionnr + 1, second); - setPointerToRawData(uiSectionnr + 1, getPointerToRawData(uiSectionnr) + dwSplitOffset); - setSizeOfRawData(uiSectionnr + 1, originalSize - dwSplitOffset); - setVirtualAddress(uiSectionnr + 1, getVirtualAddress(uiSectionnr) + dwSplitOffset); - setVirtualSize(uiSectionnr + 1, originalSize - dwSplitOffset); - setCharacteristics(uiSectionnr + 1, PELIB_IMAGE_SCN_MEM_WRITE | PELIB_IMAGE_SCN_MEM_READ | PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA | PELIB_IMAGE_SCN_CNT_CODE); - - return ERROR_NONE; - } - - /** - * Removes the section from the file. All further sections will be moved in the file to fill - * the gap. Everything other remains untouched. - * @param uiSectionnr The index of the section to remove. - **/ - template - int PeHeaderT::removeSection(std::uint16_t uiSectionnr) - { - if (uiSectionnr >= calcNumberOfSections()) - return ERROR_ENTRY_NOT_FOUND; - - std::uint32_t rawDiff = getSizeOfRawData(uiSectionnr); - std::uint32_t virtualDiff = getVirtualSize(uiSectionnr); - for (int i = uiSectionnr + 1; i < calcNumberOfSections(); ++i) - { - setPointerToRawData(i, getPointerToRawData(i) - rawDiff); - setVirtualAddress(i, getVirtualAddress(i) - virtualDiff); - } - - m_vIsh.erase(m_vIsh.begin() + uiSectionnr); - return ERROR_NONE; - } - - /** - * Calculates a valid SizeOfImage value given the information from the current PE header. - * Note that this calculation works in Win2K but probably does not work in Win9X. I didn't test that though. - * @return Valid SizeOfImage value. - **/ - template - unsigned int PeHeaderT::calcSizeOfImage() const - { - // Major note here: It's possible for sections to exist with a Virtual Size of 0. - // That's why it's necessary to use std::max(Vsize, RawSize) here. - // An example for such a file is dbeng6.exe (made by Sybase). - // In this file each and every section has a VSize of 0 but it still runs. - - auto ishLastSection = std::max_element( - m_vIsh.begin(), - m_vIsh.end(), - [](const auto& i1, const auto& i2) { return i1.biggerVirtualAddress(i2); } - ); - - if (ishLastSection->VirtualSize != 0) return ishLastSection->VirtualAddress + ishLastSection->VirtualSize; - return ishLastSection->VirtualAddress + std::max(ishLastSection->VirtualSize, ishLastSection->SizeOfRawData); - } - - /** - * Calculates the space between the last std::uint8_t of the header and the first std::uint8_t that's used for something - * else (that's either the first section or an image directory). - * @return Unused space after the header. - * \todo There are PE files with sections beginning at offset 0. They - * need to be considered. - **/ - template - unsigned int PeHeaderT::calcSpaceAfterHeader() const - { - return (calcStartOfCode() > size() + m_uiOffset) ? calcStartOfCode() - (size() + m_uiOffset) : 0; - } - - /** - * Returns the first offset of the file that's actually used for something different than the header. - * That something is not necessarily code, it can be a data directory too. - * This offset can be the beginning of a section or the beginning of a directory. - * \todo Some optimizization is surely possible here. - * \todo There are PE files with sections beginning at offset 0. They - * need to be considered. Returning 0 for these files doesn't really make sense. - * So far these sections are disregarded. - **/ - template - unsigned int PeHeaderT::calcStartOfCode() const - { - unsigned int directories = calcNumberOfRvaAndSizes(); - VAR4_8 dwMinOffset = 0xFFFFFFFF; - if (directories >= 1 && getIddExportRva() && rvaToOffset(getIddExportRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddExportRva()); - if (directories >= 2 && getIddImportRva() && rvaToOffset(getIddImportRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddImportRva()); - if (directories >= 3 && getIddResourceRva() && rvaToOffset(getIddResourceRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddResourceRva()); - if (directories >= 4 && getIddExceptionRva() && rvaToOffset(getIddExceptionRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddExceptionRva()); - if (directories >= 5 && getIddSecurityRva() && rvaToOffset(getIddSecurityRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddSecurityRva()); - if (directories >= 6 && getIddBaseRelocRva() && rvaToOffset(getIddBaseRelocRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddBaseRelocRva()); - if (directories >= 7 && getIddDebugRva() && rvaToOffset(getIddDebugRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddDebugRva()); - if (directories >= 8 && getIddArchitectureRva() && rvaToOffset(getIddArchitectureRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddArchitectureRva()); - if (directories >= 9 && getIddGlobalPtrRva() && rvaToOffset(getIddGlobalPtrRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddGlobalPtrRva()); - if (directories >= 10 && getIddTlsRva() && rvaToOffset(getIddTlsRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddTlsRva()); - if (directories >= 11 && getIddLoadConfigRva() && rvaToOffset(getIddLoadConfigRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddLoadConfigRva()); - if (directories >= 12 && getIddBoundImportRva() && rvaToOffset(getIddBoundImportRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddBoundImportRva()); - if (directories >= 13 && getIddIatRva() && rvaToOffset(getIddIatRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddIatRva()); - if (directories >= 14 && getIddDelayImportRva() && rvaToOffset(getIddDelayImportRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddDelayImportRva()); - if (directories >= 15 && getIddComHeaderRva() && rvaToOffset(getIddComHeaderRva()) < dwMinOffset) dwMinOffset = rvaToOffset(getIddComHeaderRva()); - - for (std::uint16_t i=0;i - unsigned int PeHeaderT::calcOffset(/*unsigned int uiSize*/) const - { - unsigned int maxoffset = size(); - - for (std::uint16_t i=0;i maxoffset) maxoffset = getPointerToRawData(i) + getSizeOfRawData(i); - } - - return alignOffset(maxoffset, getFileAlignment()); - } - - /** - * Calculates the Rva for a new section. The Rva will already be aligned to the file's SectionAlignment. - * \todo uiSize isn't used yet. Will be used later on to search for caves. - * @return Aligned Rva. - **/ - template - unsigned int PeHeaderT::calcRva(/*unsigned int uiSize*/) const - { - // Major note here: It's possible for sections to exist with a Virtual Size of 0. - // That's why it's necessary to use std::max(Vsize, RawSize) here. - // An example for such a file is dbeng6.exe (made by Sybase). - // In this file each and every section has a VSize of 0 but it still runs. - - unsigned int maxoffset = size(); - for (std::uint16_t i=0;i maxoffset) maxoffset = getVirtualAddress(i) + std::max(getVirtualSize(i), getSizeOfRawData(i)); - } - - return alignOffset(maxoffset, getSectionAlignment()); - } - - /** - * Returns the number of currently defined sections. Note that this value can be different from the number - * of sections according to the header (see #PeLib::PeHeaderT::getNumberOfSections). - * @return Number of currently defined sections. - **/ - template - std::uint16_t PeHeaderT::calcNumberOfSections() const - { - return static_cast(m_vIsh.size()); - } - - /** - * Enlarges the physically last section in the file. - * @param uiSize Additional size that's added to the section's size. - **/ - template - void PeHeaderT::enlargeLastSection(unsigned int uiSize) - { - auto ishLastSection = std::max_element( - m_vIsh.begin(), - m_vIsh.end(), - [](const auto& i1, const auto& i2) { return i1.biggerFileOffset(i2); } - ); - unsigned int uiRawDataSize = alignOffset(ishLastSection->SizeOfRawData + uiSize, getFileAlignment()); - - ishLastSection->SizeOfRawData = uiRawDataSize; - ishLastSection->VirtualSize = ishLastSection->SizeOfRawData; - - setSizeOfImage(calcSizeOfImage()); - } - - /** - * Determines the section which contains the file offset. - * @param dwOffset File offset. - * @return Section Id of the section which contains the offset. - **/ - template - std::uint16_t PeHeaderT::getSectionWithOffset(VAR4_8 dwOffset) const - { - // Offset = 0 must be handled explicitly as there are files - // with sections that begin at offset 0, that means the section - // only exists in memory. - - if (!dwOffset) return std::numeric_limits::max(); - - for (std::uint16_t i=0;i dwOffset) return i; - } - - return std::numeric_limits::max(); - } - - /** - * Determines the section which contains the Rva. - * @param dwRva A relative virtual address. - * @return Section Id of the section which contains the Rva. - **/ - template - std::uint16_t PeHeaderT::getSectionWithRva(VAR4_8 dwRva) const - { - // Major note here: It's possible for sections to exist with a Virtual Size of 0. - // That's why it's necessary to use std::max(Vsize, RawSize) here. - // An example for such a file is dbeng6.exe (made by Sybase). - // In this file each and every section has a VSize of 0 but it still runs. - - std::uint16_t actIndex = 0; - bool detected = false; - - for (std::uint16_t i=0;i= getSizeOfRawData(i) ? getVirtualSize(i) : getSizeOfRawData(i); - if (getVirtualAddress(i) <= dwRva && getVirtualAddress(i) + max > dwRva) - { - std::uint32_t actMax = getVirtualSize(actIndex) >= getSizeOfRawData(actIndex) ? getVirtualSize(actIndex) : getSizeOfRawData(actIndex); - if (!detected || (getVirtualAddress(i) > getVirtualAddress(actIndex) || (getVirtualAddress(i) == getVirtualAddress(actIndex) && max < actMax))) - { - actIndex = i; - detected = true; - } - } - } - - return detected ? actIndex : - 1; - } - - /** - * Corrects all faulty values of the current PE header. The following values will be corrected: NtSignature, - * NumberOfSections, SizeOfOptionalHeader, FileAlignment (will be aligned to n*0x200), - * SectionAlignment (will be aligned to n*0x1000), NumberOfRvaAndSizes, SizeOfHeaders, SizeOfImage, - * Magic, Characteristics. - * @param dwOffset Beginning of PeHeader (see #PeLib::MzHeader::getAddressOfPeHeader). - * \todo 32bit and 64bit versions. - **/ - template - void PeHeaderT::makeValid(std::uint32_t dwOffset) - { - setNtSignature(PELIB_IMAGE_NT_SIGNATURE); // 'PE' - setNumberOfSections(calcNumberOfSections()); - setSizeOfOptionalHeader(sizeof(PELIB_IMAGE_OPTIONAL_HEADER) + calcNumberOfRvaAndSizes() * 8); - - if (getCharacteristics() == 0) - setCharacteristics(PELIB_IMAGE_FILE_EXECUTABLE_IMAGE | PELIB_IMAGE_FILE_32BIT_MACHINE); - - // 32 bits - if (x == 32) - { - setMachine(PELIB_IMAGE_FILE_MACHINE_I386); - setMagic(PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC); - } - // 64 bits - else if (x == 64) - { - setMachine(PELIB_IMAGE_FILE_MACHINE_AMD64); - setMagic(PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC); - } - - // setImageBase(0x01000000); - - // Align file and section alignment values - unsigned int dwAlignedOffset = alignOffset(getSectionAlignment(), 0x1000); - setSectionAlignment(dwAlignedOffset ? dwAlignedOffset : 0x1000); - - dwAlignedOffset = alignOffset(getFileAlignment(), 0x200); - setFileAlignment(dwAlignedOffset ? dwAlignedOffset : 0x200); - -// setMajorSubsystemVersion(4); -// setSubsystem(IMAGE_SUBSYSTEM_WINDOWS_GUI); - m_inthHeader.dataDirectories.resize(getNumberOfRvaAndSizes()); - - // Code below depends on code above. Don't change the order. - std::uint32_t dwSizeOfHeaders = alignOffset(dwOffset + size(), getFileAlignment()); - setSizeOfHeaders(dwSizeOfHeaders); - - std::uint32_t dwSizeOfImage = alignOffset(dwSizeOfHeaders, getSectionAlignment()); - - std::uint32_t dwOffsetDiff = dwSizeOfHeaders - getPointerToRawData(0); - for (int i=0;i - unsigned int PeHeaderT::offsetToRva(VAR4_8 dwOffset) const - { - if (dwOffset < calcStartOfCode()) return dwOffset; - - std::uint16_t uiSecnr = getSectionWithOffset(dwOffset); - - if (uiSecnr == 0xFFFF) return (unsigned int)-1; - - return getVirtualAddress(uiSecnr) + dwOffset - getPointerToRawData(uiSecnr); - } - - /** - * Converts a file offset to a virtual address. - * @param dwOffset File offset. - * @return Virtual Address. - **/ - template - unsigned int PeHeaderT::offsetToVa(VAR4_8 dwOffset) const - { - if (dwOffset < calcStartOfCode()) return getImageBase() + dwOffset; - - std::uint16_t uiSecnr = getSectionWithOffset(dwOffset); - - if (uiSecnr == 0xFFFF) return -1; - - return getImageBase() + getVirtualAddress(uiSecnr) + dwOffset - getPointerToRawData(uiSecnr); - } - - template - void PeHeaderT::readHeader(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS_EX& header) - { - ibBuffer >> header.Signature; - - ibBuffer >> header.FileHeader.Machine; - ibBuffer >> header.FileHeader.NumberOfSections; - ibBuffer >> header.FileHeader.TimeDateStamp; - ibBuffer >> header.FileHeader.PointerToSymbolTable; - ibBuffer >> header.FileHeader.NumberOfSymbols; - ibBuffer >> header.FileHeader.SizeOfOptionalHeader; - ibBuffer >> header.FileHeader.Characteristics; - ibBuffer >> header.OptionalHeader.Magic; - - ibBuffer >> header.OptionalHeader.MajorLinkerVersion; - ibBuffer >> header.OptionalHeader.MinorLinkerVersion; - ibBuffer >> header.OptionalHeader.SizeOfCode; - ibBuffer >> header.OptionalHeader.SizeOfInitializedData; - ibBuffer >> header.OptionalHeader.SizeOfUninitializedData; - ibBuffer >> header.OptionalHeader.AddressOfEntryPoint; - ibBuffer >> header.OptionalHeader.BaseOfCode; - //readBaseOfData(ibBuffer, header); - ibBuffer >> header.OptionalHeader.ImageBase; - ibBuffer >> header.OptionalHeader.SectionAlignment; - ibBuffer >> header.OptionalHeader.FileAlignment; - ibBuffer >> header.OptionalHeader.MajorOperatingSystemVersion; - ibBuffer >> header.OptionalHeader.MinorOperatingSystemVersion; - ibBuffer >> header.OptionalHeader.MajorImageVersion; - ibBuffer >> header.OptionalHeader.MinorImageVersion; - ibBuffer >> header.OptionalHeader.MajorSubsystemVersion; - ibBuffer >> header.OptionalHeader.MinorSubsystemVersion; - ibBuffer >> header.OptionalHeader.Win32VersionValue; - ibBuffer >> header.OptionalHeader.SizeOfImage; - ibBuffer >> header.OptionalHeader.SizeOfHeaders; - m_checksumFileOffset = m_uiOffset + ibBuffer.get(); - ibBuffer >> header.OptionalHeader.CheckSum; - ibBuffer >> header.OptionalHeader.Subsystem; - ibBuffer >> header.OptionalHeader.DllCharacteristics; - ibBuffer >> header.OptionalHeader.SizeOfStackReserve; - ibBuffer >> header.OptionalHeader.SizeOfStackCommit; - ibBuffer >> header.OptionalHeader.SizeOfHeapReserve; - ibBuffer >> header.OptionalHeader.SizeOfHeapCommit; - ibBuffer >> header.OptionalHeader.LoaderFlags; - ibBuffer >> header.OptionalHeader.NumberOfRvaAndSizes; - } - - template - void PeHeaderT::readDataDirectories( - std::istream& inStream, - unsigned int uiOffset, - PELIB_IMAGE_NT_HEADERS_EX& header) - { - IStreamWrapper inStream_w(inStream); - - std::uint64_t ulFileSize = fileSize(inStream_w); - inStream_w.seekg(uiOffset, std::ios::beg); - - std::vector iddBuffer(PELIB_IMAGE_DATA_DIRECTORY::size()); - PELIB_IMAGE_DATA_DIRECTORY idd; - - // There is no more than 16 directories in header, even though PE header declares more. - unsigned int uiNumberOfDirectories = std::min(header.OptionalHeader.NumberOfRvaAndSizes, 16u); - - for (unsigned int i = 0; i < uiNumberOfDirectories; i++) - { - if (uiOffset >= ulFileSize) - { - break; - } - - auto incomplete = false; - if (uiOffset + PELIB_IMAGE_DATA_DIRECTORY::size() > ulFileSize) - { - if (uiOffset + sizeof(idd.VirtualAddress) <= ulFileSize) - { - incomplete = true; - } - else - { - break; - } - } - - if (i == PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY) - m_secDirFileOffset = (unsigned long)inStream_w.tellg(); - - iddBuffer.resize(PELIB_IMAGE_DATA_DIRECTORY::size()); - inStream_w.read(reinterpret_cast(iddBuffer.data()), iddBuffer.size()); - - InputBuffer ibBuffer(iddBuffer); - ibBuffer >> idd.VirtualAddress; - ibBuffer >> idd.Size; - header.lastDirectoryIsIncomplete = incomplete; - - header.dataDirectories.push_back(idd); - - uiOffset += PELIB_IMAGE_DATA_DIRECTORY::size(); - } - } - - template - std::vector PeHeaderT::readSections( - std::istream& inStream, - unsigned int uiOffset, - PELIB_IMAGE_NT_HEADERS_EX& header) - { - IStreamWrapper inStream_w(inStream); - - const unsigned long long stringTableOffset = header.FileHeader.PointerToSymbolTable + header.FileHeader.NumberOfSymbols * PELIB_IMAGE_SIZEOF_COFF_SYMBOL; - std::vector vIshdCurr; - bool bRawDataBeyondEOF = false; - - std::vector ishBuffer(sizeof(PELIB_IMAGE_SECTION_HEADER)); - PELIB_IMAGE_SECTION_HEADER ishCurr; - std::uint64_t ulFileSize = fileSize(inStream_w); - - // Check overflow of the section headers - std::uint32_t SectionHdrOffset = MzHeader().e_lfanew + sizeof(std::uint32_t) + header.FileHeader.size() + header.FileHeader.SizeOfOptionalHeader; - if(SectionHdrOffset > (std::uint32_t)ulFileSize) - setLoaderError(LDR_ERROR_SECTION_HEADERS_OUT_OF_IMAGE); - - for (unsigned int i = 0; i < header.FileHeader.NumberOfSections; i++) - { - if (uiOffset + sizeof(PELIB_IMAGE_SECTION_HEADER) > ulFileSize) - break; - - // Clear error bits, because reading from symbol table might have failed. - inStream_w.clear(); - inStream_w.seekg(uiOffset, std::ios::beg); - inStream_w.read(reinterpret_cast(ishBuffer.data()), ishBuffer.size()); - InputBuffer ibBuffer(ishBuffer); - - ibBuffer.read(reinterpret_cast(ishCurr.Name), 8); - // get name from string table - if (ishCurr.Name[0] == '/') - { - unsigned long long stringTableIndex = 0; - - for (unsigned long long j = 1; j < 8 && isdigit(static_cast(ishCurr.Name[j])); ++j) - { - stringTableIndex *= 10; - stringTableIndex += ishCurr.Name[j] - '0'; - } - - if (stringTableOffset + stringTableIndex <= ulFileSize) - { - getStringFromFileOffset( - inStream_w, - ishCurr.StringTableName, - (std::size_t)(stringTableOffset + stringTableIndex), - PELIB_IMAGE_SIZEOF_MAX_NAME, - true, - true); - } - } - else - { - ishCurr.StringTableName.clear(); - } - ibBuffer >> ishCurr.VirtualSize; - ibBuffer >> ishCurr.VirtualAddress; - ibBuffer >> ishCurr.SizeOfRawData; - ibBuffer >> ishCurr.PointerToRawData; - ibBuffer >> ishCurr.PointerToRelocations; - ibBuffer >> ishCurr.PointerToLinenumbers; - ibBuffer >> ishCurr.NumberOfRelocations; - ibBuffer >> ishCurr.NumberOfLinenumbers; - ibBuffer >> ishCurr.Characteristics; - - // PointerToRawData is aligned down to 0x200 by the Windows loader. - // This is because the section is mapped to memory based on file sectors. - // This behavior is independent of the FileAlignment value - // and only happens when SectionAlignment is greater or equal to page size - if(header.OptionalHeader.SectionAlignment >= PELIB_PAGE_SIZE) - { - ishCurr.PointerToRawData = ishCurr.PointerToRawData & ~(PELIB_SECTOR_SIZE - 1); - } - - vIshdCurr.push_back(ishCurr); - - uiOffset += sizeof(PELIB_IMAGE_SECTION_HEADER); - } - - // Verify section headers - std::uint64_t NextVirtualAddress = header.OptionalHeader.ImageBase; - std::uint32_t NumberOfSectionPTEs = AlignToSize(header.OptionalHeader.SizeOfHeaders, header.OptionalHeader.SectionAlignment) / PELIB_PAGE_SIZE; - std::uint32_t NumberOfPTEs = BytesToPages(header.OptionalHeader.SizeOfImage); - std::uint32_t FileAlignmentMask = header.OptionalHeader.FileAlignment - 1; - bool SingleSubsection = (header.OptionalHeader.SectionAlignment < PELIB_PAGE_SIZE); - - // Verify the image - if (!SingleSubsection) - { - // Some extra checks done by the loader - if ((header.OptionalHeader.SizeOfHeaders + (header.OptionalHeader.SectionAlignment - 1)) < header.OptionalHeader.SizeOfHeaders) - setLoaderError(LDR_ERROR_SECTION_HEADERS_OVERFLOW); - - if (NumberOfSectionPTEs > NumberOfPTEs) - setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); - - // Update the virtual address - NextVirtualAddress += NumberOfSectionPTEs * PELIB_PAGE_SIZE; - NumberOfPTEs -= NumberOfSectionPTEs; - } - else - { - NumberOfSectionPTEs = AlignToSize(header.OptionalHeader.SizeOfImage, PELIB_PAGE_SIZE) / PELIB_PAGE_SIZE; - NumberOfPTEs -= NumberOfSectionPTEs; - } - - for (auto sectHdr : vIshdCurr) - { - std::uint32_t PointerToRawData = (sectHdr.SizeOfRawData != 0) ? sectHdr.PointerToRawData : 0; - std::uint32_t EndOfRawData = PointerToRawData + sectHdr.SizeOfRawData; - std::uint32_t VirtualSize = (sectHdr.VirtualSize != 0) ? sectHdr.VirtualSize : sectHdr.SizeOfRawData; - - // Overflow check - if ((PointerToRawData + sectHdr.SizeOfRawData) < PointerToRawData) - setLoaderError(LDR_ERROR_RAW_DATA_OVERFLOW); - - if (SingleSubsection) - { - // If the image is mapped as single subsection, - // then the virtual values must match raw values - if ((sectHdr.VirtualAddress != PointerToRawData) || sectHdr.SizeOfRawData < VirtualSize) - setLoaderError(LDR_ERROR_SECTION_SIZE_MISMATCH); - } - else - { - // Check the virtual address of the section - if (NextVirtualAddress != header.OptionalHeader.ImageBase + sectHdr.VirtualAddress) - { - setLoaderError(LDR_ERROR_INVALID_SECTION_VA); - } - - // Check section size - if ((VirtualSize + (PELIB_PAGE_SIZE - 1)) <= VirtualSize) - { - setLoaderError(LDR_ERROR_INVALID_SECTION_VSIZE); - } - - // Calculate number of PTEs in the section - NumberOfSectionPTEs = AlignToSize(VirtualSize, header.OptionalHeader.SectionAlignment) / PELIB_PAGE_SIZE; - if (NumberOfSectionPTEs > NumberOfPTEs) - { - setLoaderError(LDR_ERROR_INVALID_SECTION_VSIZE); - } - - NumberOfPTEs -= NumberOfSectionPTEs; - - // Check end of the raw data for the section - if (((PointerToRawData + sectHdr.SizeOfRawData + FileAlignmentMask) & ~FileAlignmentMask) < PointerToRawData) - { - setLoaderError(LDR_ERROR_INVALID_SECTION_RAWSIZE); - } - - NextVirtualAddress += NumberOfSectionPTEs * PELIB_PAGE_SIZE; - } - - // Check for raw data beyond end-of-file - // Note that Windows loader doesn't check this on files that are mapped as single section. - // We will do that nontheless, because we want to know that a file is cut. - if (PointerToRawData != 0 && EndOfRawData > (std::uint32_t)ulFileSize) - bRawDataBeyondEOF = true; - } - - // Verify the image size - std::uint32_t ThresholdNumberOfPTEs = (SingleSubsection == false) ? (header.OptionalHeader.SectionAlignment / PELIB_PAGE_SIZE) : 1; - if (NumberOfPTEs >= ThresholdNumberOfPTEs) - { - setLoaderError(LDR_ERROR_INVALID_SIZE_OF_IMAGE); - } - - // Did we detect a trimmed file? - if (bRawDataBeyondEOF) - { - bool bFileLoadable = false; - - // Special exception: Even if cut, the file is still loadable - // if the last section is in the file range. This is because - // the PE loader in Windows only cares about whether the last section is in the file range - if (!vIshdCurr.empty()) - { - PELIB_IMAGE_SECTION_HEADER & lastSection = vIshdCurr.back(); - std::uint32_t PointerToRawData = (lastSection.SizeOfRawData != 0) ? lastSection.PointerToRawData : 0; - std::uint32_t EndOfRawData = PointerToRawData + lastSection.SizeOfRawData; - - if ((lastSection.SizeOfRawData == 0) || (EndOfRawData <= (std::uint32_t)ulFileSize)) - { - setLoaderError(LDR_ERROR_FILE_IS_CUT_LOADABLE); - bFileLoadable = true; - } - } - - // If the file is not loadable, set the "file is cut" error - if (bFileLoadable == false) - { - setLoaderError(LDR_ERROR_FILE_IS_CUT); - } - } - return vIshdCurr; - } - - template - LoaderError PeHeaderT::loaderError() const - { - return m_ldrError; - } - - template - void PeHeaderT::setLoaderError(LoaderError ldrError) - { - // Do not override an existing loader error - if (m_ldrError == LDR_ERROR_NONE) - { - m_ldrError = ldrError; - } - } - - /** - * Reads the PE header from a file Note that this function does not verify if a file is actually a MZ file. - * For this purpose see #PeLib::PeHeaderT::isValid. The only check this function makes is a check to see if - * the file is large enough to be a PE header. If the data is valid doesn't matter. - * @param inStream Input stream. - * @param ntHeaderOffset File offset of PE header (see #PeLib::MzHeader::getAddressOfPeHeader). - * @param mzHeader Reference to MZ header. - **/ - template - int PeHeaderT::read( - std::istream& inStream, - unsigned int ntHeaderOffset, - const MzHeader &mzHeader) - { - IStreamWrapper inStream_w(inStream); - - m_mzHeader = mzHeader; - m_uiOffset = ntHeaderOffset; - PELIB_IMAGE_NT_HEADERS_EX header; - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - // Check the position of the NT header for integer overflow - if (ntHeaderOffset + header.size() < ntHeaderOffset) - setLoaderError(LDR_ERROR_NTHEADER_OFFSET_OVERFLOW); - if((std::uint64_t)ntHeaderOffset + header.size() > fileSize(inStream_w)) - setLoaderError(LDR_ERROR_NTHEADER_OUT_OF_FILE); - - std::vector vBuffer(header.size()); - - inStream_w.seekg(ntHeaderOffset, std::ios::beg); - inStream_w.read(reinterpret_cast(vBuffer.data()), static_cast(vBuffer.size())); - - InputBuffer ibBuffer(vBuffer); - - readHeader(ibBuffer, header); - - // Verify the NT signature - if (header.Signature != PeLib::PELIB_IMAGE_NT_SIGNATURE) - setLoaderError(LDR_ERROR_NO_NT_SIGNATURE); - - // 7baebc6d9f2185fafa760c875ab1386f385a0b3fecf2e6ae339abb4d9ac58f3e - if (header.FileHeader.Machine == 0 && header.FileHeader.SizeOfOptionalHeader == 0) - setLoaderError(LDR_ERROR_FILE_HEADER_INVALID); - - if (!(header.FileHeader.Characteristics & PeLib::PELIB_IMAGE_FILE_EXECUTABLE_IMAGE)) - setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE); - if (header.OptionalHeader.Magic != PeLib::PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC && - header.OptionalHeader.Magic != PeLib::PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) - setLoaderError(LDR_ERROR_NO_OPTHDR_MAGIC); - - // SizeOfHeaders must be nonzero if not a single subsection - if(header.OptionalHeader.SectionAlignment >= PELIB_PAGE_SIZE && header.OptionalHeader.SizeOfHeaders == 0) - setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_ZERO); - - // File alignment must not be 0 - if(header.OptionalHeader.FileAlignment == 0) - setLoaderError(LDR_ERROR_FILE_ALIGNMENT_ZERO); - - // File alignment must be a power of 2 - if(header.OptionalHeader.FileAlignment & (header.OptionalHeader.FileAlignment-1)) - setLoaderError(LDR_ERROR_FILE_ALIGNMENT_NOT_POW2); - - // Section alignment must not be 0 - if (header.OptionalHeader.SectionAlignment == 0) - setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_ZERO); - - // Section alignment must be a power of 2 - if (header.OptionalHeader.SectionAlignment & (header.OptionalHeader.SectionAlignment - 1)) - setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_NOT_POW2); - - if (header.OptionalHeader.SectionAlignment < header.OptionalHeader.FileAlignment) - setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_TOO_SMALL); - - // Check for images with "super-section": FileAlignment must be equal to SectionAlignment - if ((header.OptionalHeader.FileAlignment & 511) && (header.OptionalHeader.SectionAlignment != header.OptionalHeader.FileAlignment)) - setLoaderError(LDR_ERROR_SECTION_ALIGNMENT_INVALID); - - // Check for largest image - if(header.OptionalHeader.SizeOfImage > PELIB_MM_SIZE_OF_LARGEST_IMAGE) - setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_TOO_BIG); - - // Check for 32-bit images - if (header.OptionalHeader.Magic == PeLib::PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC && header.FileHeader.Machine != PeLib::PELIB_IMAGE_FILE_MACHINE_I386) - setLoaderError(LDR_ERROR_INVALID_MACHINE32); - - // Check for 64-bit images - if (header.OptionalHeader.Magic == PeLib::PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - if (header.FileHeader.Machine != PeLib::PELIB_IMAGE_FILE_MACHINE_AMD64 && header.FileHeader.Machine != PeLib::PELIB_IMAGE_FILE_MACHINE_IA64) - setLoaderError(LDR_ERROR_INVALID_MACHINE64); - } - - // Check the size of image - if(header.OptionalHeader.SizeOfHeaders > header.OptionalHeader.SizeOfImage) - setLoaderError(LDR_ERROR_SIZE_OF_HEADERS_INVALID); - - // On 64-bit Windows, size of optional header must be properly aligned to 8-std::uint8_t boundary - if (header.FileHeader.SizeOfOptionalHeader & (sizeof(std::uint64_t) - 1)) - setLoaderError(LDR_ERROR_SIZE_OF_OPTHDR_NOT_ALIGNED); - - // Set the size of image - if(BytesToPages(header.OptionalHeader.SizeOfImage) == 0) - setLoaderError(LDR_ERROR_SIZE_OF_IMAGE_ZERO); - - // Check for proper alignment of the image base - if(header.OptionalHeader.ImageBase & (PELIB_SIZE_64KB - 1)) - setLoaderError(LDR_ERROR_IMAGE_BASE_NOT_ALIGNED); - - // header now contains only Signature + File Header + Optional Header - readDataDirectories(inStream_w, ntHeaderOffset + header.size(), header); - - // Section headers begin at the offset of the optional header + SizeOfOptionalHeader - // We need to do this because section headers may be hidden in optional header - auto secHdrOff = ntHeaderOffset - + header.sizeOfSignature() - + PELIB_IMAGE_FILE_HEADER::size() - + header.FileHeader.SizeOfOptionalHeader; - m_vIsh = readSections(inStream_w, secHdrOff, header); - - std::swap(m_inthHeader, header); - - return ERROR_NONE; - } - - /** - * Rebuilds the PE header so that it can be written to a file. It's not guaranteed that the - * header will be valid. If you want to make sure that the header will be valid you - * must call #PeLib::PeHeaderT::makeValid first. - * @param vBuffer Buffer where the rebuilt header will be stored. - **/ - template - void PeHeaderT::rebuild(std::vector& vBuffer) const - { - OutputBuffer obBuffer(vBuffer); - - obBuffer << m_inthHeader.Signature; - - obBuffer << m_inthHeader.FileHeader.Machine; - obBuffer << m_inthHeader.FileHeader.NumberOfSections; - obBuffer << m_inthHeader.FileHeader.TimeDateStamp; - obBuffer << m_inthHeader.FileHeader.PointerToSymbolTable; - obBuffer << m_inthHeader.FileHeader.NumberOfSymbols; - obBuffer << m_inthHeader.FileHeader.SizeOfOptionalHeader; - obBuffer << m_inthHeader.FileHeader.Characteristics; - obBuffer << m_inthHeader.OptionalHeader.Magic; - obBuffer << m_inthHeader.OptionalHeader.MajorLinkerVersion; - obBuffer << m_inthHeader.OptionalHeader.MinorLinkerVersion; - obBuffer << m_inthHeader.OptionalHeader.SizeOfCode; - obBuffer << m_inthHeader.OptionalHeader.SizeOfInitializedData; - obBuffer << m_inthHeader.OptionalHeader.SizeOfUninitializedData; - obBuffer << m_inthHeader.OptionalHeader.AddressOfEntryPoint; - obBuffer << m_inthHeader.OptionalHeader.BaseOfCode; - rebuildBaseOfData(obBuffer); -// obBuffer << m_inthHeader.OptionalHeader.BaseOfData; - obBuffer << m_inthHeader.OptionalHeader.ImageBase; - obBuffer << m_inthHeader.OptionalHeader.SectionAlignment; - obBuffer << m_inthHeader.OptionalHeader.FileAlignment; - obBuffer << m_inthHeader.OptionalHeader.MajorOperatingSystemVersion; - obBuffer << m_inthHeader.OptionalHeader.MinorOperatingSystemVersion; - obBuffer << m_inthHeader.OptionalHeader.MajorImageVersion; - obBuffer << m_inthHeader.OptionalHeader.MinorImageVersion; - obBuffer << m_inthHeader.OptionalHeader.MajorSubsystemVersion; - obBuffer << m_inthHeader.OptionalHeader.MinorSubsystemVersion; - obBuffer << m_inthHeader.OptionalHeader.Win32VersionValue; - obBuffer << m_inthHeader.OptionalHeader.SizeOfImage; - obBuffer << m_inthHeader.OptionalHeader.SizeOfHeaders; - obBuffer << m_inthHeader.OptionalHeader.CheckSum; - obBuffer << m_inthHeader.OptionalHeader.Subsystem; - obBuffer << m_inthHeader.OptionalHeader.DllCharacteristics; - obBuffer << m_inthHeader.OptionalHeader.SizeOfStackReserve; - obBuffer << m_inthHeader.OptionalHeader.SizeOfStackCommit; - obBuffer << m_inthHeader.OptionalHeader.SizeOfHeapReserve; - obBuffer << m_inthHeader.OptionalHeader.SizeOfHeapCommit; - obBuffer << m_inthHeader.OptionalHeader.LoaderFlags; - obBuffer << m_inthHeader.OptionalHeader.NumberOfRvaAndSizes; - - // The 0x10 data directories - for (unsigned int i=0;i - bool PeHeaderT::isValidRva(VAR4_8 rva) const - { - if (rva >= getSizeOfImage()) - return false; - - // If there are no sections, the compare with size of image is sufficient. - if (calcNumberOfSections() == 0) - return true; - - // Everything under file alignment should be allowed. - if (rva < getFileAlignment()) - return true; - - for (std::uint16_t i = 0; i < calcNumberOfSections(); ++i) - { - // Sample 91DE52AB3F94A6372088DD843485414BA2B3734BDF58C4DE40DF3B50B4301C57: - // Section[0].VirtualAddress = 0x1000 - // Section[0].VirtualSize = 0x3428 (in fact 0x4000 due to section alignment) - // Section[0].SizeOfRawData = 0x3600 - // IMAGE_IMPORT_DESCRIPTOR[0]::Name is 0x44DE, which is evaluated as invalid if alignment is not taken into account - - std::uint32_t beginOfSection = getVirtualAddress(i); - std::uint32_t sizeOfSection = getVirtualSize(i); - - // Perform proper alignment on the section length - if (sizeOfSection == 0) - sizeOfSection = getSizeOfRawData(i); - sizeOfSection = AlignToSize(sizeOfSection, getSectionAlignment()); - - // OK if the RVA is within reach of the section - if (beginOfSection <= rva && rva < beginOfSection + sizeOfSection) - return true; - } - - return false; - } - - /** - * Converts a relative virtual offset to a file offset. - * @param dwRva A relative virtual offset. - * @return A file offset. - * \todo It's not always 0x1000. - **/ - template - typename FieldSizes::VAR4_8 PeHeaderT::rvaToOffset(VAR4_8 dwRva) const - { - // XXX: Not correct - if (dwRva < 0x1000) return dwRva; - - std::uint16_t uiSecnr = getSectionWithRva(dwRva); - - if (uiSecnr == 0xFFFF || dwRva > getVirtualAddress(uiSecnr) + getSizeOfRawData(uiSecnr)) - { - return std::numeric_limits::max(); - } - - if (getPointerToRawData(uiSecnr) < getFileAlignment()) - { - return 0 + dwRva - getVirtualAddress(uiSecnr); - } - - return getPointerToRawData(uiSecnr) + (dwRva - getVirtualAddress(uiSecnr)); - } - - template - typename FieldSizes::VAR4_8 PeHeaderT::rvaToOffsetSpeculative(VAR4_8 dwRva) const - { - const auto offset = rvaToOffset(dwRva); - if (offset != std::numeric_limits::max()) - { - return offset; - } - - const auto uiSecnr = getSectionWithRva(dwRva); - if (uiSecnr == 0xFFFF) - { - return std::numeric_limits::max(); - } - - if (getPointerToRawData(uiSecnr) < getFileAlignment()) - { - return 0 + dwRva - getVirtualAddress(uiSecnr); - } - - return getPointerToRawData(uiSecnr) + (dwRva - getVirtualAddress(uiSecnr)); - } - - /** - * Converts a relative virtual offset to a virtual offset. - * @param dwRva A relative virtual offset. - * @return A virtual offset. - **/ - template - typename FieldSizes::VAR4_8 PeHeaderT::rvaToVa(VAR4_8 dwRva) const - { - return getImageBase() + dwRva; - } - - /** - * Calculates the size of the current PE header. This includes the actual header and the section definitions. - * @return Size of the current PE header. - * \todo Better handling of files with less than 0x10 directories. - **/ - template - unsigned int PeHeaderT::size() const - { - return m_inthHeader.size() + getNumberOfSections() * PELIB_IMAGE_SECTION_HEADER::size(); - } - - // \todo Not sure if this works. - template - typename FieldSizes::VAR4_8 PeHeaderT::vaToRva(VAR4_8 dwRva) const - { - if (dwRva - getImageBase() < calcStartOfCode()) return dwRva - getImageBase(); - - if (getSectionWithRva(dwRva - getImageBase()) == 0xFFFF) return -1; - - return dwRva - getImageBase(); - } - - template - typename FieldSizes::VAR4_8 PeHeaderT::vaToOffset(VAR4_8 dwRva) const - { - return rvaToOffset(dwRva - getImageBase()); - } - - template - typename FieldSizes::VAR4_8 PeHeaderT::vaToOffsetSpeculative(VAR4_8 dwRva) const - { - return rvaToOffsetSpeculative(dwRva - getImageBase()); - } - - /** - * Saves the PE header to a file. Note that this only saves the header information, if you have added sections - * and want to save these to the file you have to call #PeLib::PeHeaderT::writeSections too. This function also - * does not verify if the PE header is correct. If you want to make sure that the current PE header is valid, - * call #PeLib::PeHeaderT::isValid and #PeLib::PeHeaderT::makeValid first. - * @param strFilename Filename of the file the header will be written to. - * @param uiOffset File offset the header will be written to. - **/ - template - int PeHeaderT::write(std::string strFilename, unsigned int uiOffset) const - { - std::fstream ofFile(strFilename.c_str(), std::ios_base::in); - - if (!ofFile) - { - ofFile.clear(); - ofFile.open(strFilename.c_str(), std::ios_base::out | std::ios_base::binary); - } - else - { - ofFile.close(); - ofFile.open(strFilename.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary); - } - - if (!ofFile) - { - return ERROR_OPENING_FILE; - } - - ofFile.seekp(uiOffset, std::ios::beg); - - std::vector vBuffer; - - rebuild(vBuffer); - - ofFile.write(reinterpret_cast(vBuffer.data()), static_cast(vBuffer.size())); - - ofFile.close(); - - return ERROR_NONE; - } - - /** - * Overwrites a section's data. - * @param strFilename Name of the file where the section will be written to. - * @param wSecnr Number of the section that will be written. - * @param vBuffer New data of the section. - **/ - template - int PeHeaderT::writeSectionData(const std::string& strFilename, std::uint16_t wSecnr, const std::vector& vBuffer) const - { - std::fstream ofFile(strFilename.c_str(), std::ios_base::in); - - if (!ofFile) - { - ofFile.clear(); - ofFile.open(strFilename.c_str(), std::ios_base::out | std::ios_base::binary); - } - else - { - ofFile.close(); - ofFile.open(strFilename.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary); - } - - if (!ofFile) - { - ofFile.clear(); - - return ERROR_OPENING_FILE; - } - - ofFile.seekp(getPointerToRawData(wSecnr), std::ios::beg); - - ofFile.write(reinterpret_cast(vBuffer.data()), std::min(static_cast(vBuffer.size()), getSizeOfRawData(wSecnr))); - - ofFile.close(); - - return ERROR_NONE; - } - - template - unsigned int PeHeaderT::getChecksumFileOffset() const - { - return m_checksumFileOffset; - } - - template - unsigned int PeHeaderT::getSecDirFileOffset() const - { - return m_secDirFileOffset; - } - - template - int PeHeaderT::writeSections(const std::string& strFilename) const - { - std::fstream ofFile(strFilename.c_str(), std::ios_base::in); - - if (!ofFile) - { - ofFile.clear(); - ofFile.open(strFilename.c_str(), std::ios_base::out | std::ios_base::binary); - } - else - { - ofFile.close(); - ofFile.open(strFilename.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary); - } - - if (!ofFile) - { - return ERROR_OPENING_FILE; - } - - std::uint64_t ulFileSize = fileSize(ofFile); - - for (int i=0;i vBuffer(uiToWrite); - ofFile.seekp(0, std::ios::end); - ofFile.write(vBuffer.data(), static_cast(vBuffer.size())); - ulFileSize = getPointerToRawData(i) + getSizeOfRawData(i); - } - } - - ofFile.close(); - - return ERROR_NONE; - } - - /** - * Returns reference to NT headers. - * @return Reference to NT headers. - **/ - template - const PELIB_IMAGE_NT_HEADERS_EX& PeHeaderT::getNtHeaders() const - { - return m_inthHeader; - } - - /** - * Returns the file's Nt signature. - * @return The Nt signature value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getNtSignature() const - { - return m_inthHeader.Signature; - } - - /** - * Returns the file's machine. - * @return The Machine value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getMachine() const - { - return m_inthHeader.FileHeader.Machine; - } - - /** - * Returns the file's number of sections as defined in the header. Note that this value can be different - * from the number of defined sections (see #PeLib::PeHeaderT::getNumberOfSections). - * @return The NumberOfSections value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getNumberOfSections() const - { - return m_inthHeader.FileHeader.NumberOfSections; - } - - /** - * Returns the file's TimeDateStamp. - * @return The TimeDateStamp value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getTimeDateStamp() const - { - return m_inthHeader.FileHeader.TimeDateStamp; - } - - /** - * Returns the relative virtual address of the file's symbol table. - * @return The PointerToSymbolTable value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getPointerToSymbolTable() const - { - return m_inthHeader.FileHeader.PointerToSymbolTable; - } - - /** - * Returns the number of symbols of the file's symbol table. - * @return The NumberOfSymbols value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getNumberOfSymbols() const - { - return m_inthHeader.FileHeader.NumberOfSymbols; - } - - /** - * Returns the size of optional header of the file. - * @return The SizeOfOptionalHeader value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getSizeOfOptionalHeader() const - { - return m_inthHeader.FileHeader.SizeOfOptionalHeader; - } - - /** - * @return The Characteristics value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getCharacteristics() const - { - return m_inthHeader.FileHeader.Characteristics; - } - - /** - * @return The Magic value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getMagic() const - { - return m_inthHeader.OptionalHeader.Magic; - } - - /** - * @return The MajorLinkerVersion value from the PE header. - **/ - template - std::uint8_t PeHeaderT::getMajorLinkerVersion() const - { - return m_inthHeader.OptionalHeader.MajorLinkerVersion; - } - - /** - * @return The MinorLinkerVersion value from the PE header. - **/ - template - std::uint8_t PeHeaderT::getMinorLinkerVersion() const - { - return m_inthHeader.OptionalHeader.MinorLinkerVersion; - } - - /** - * @return The SizeOfCode value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getSizeOfCode() const - { - return m_inthHeader.OptionalHeader.SizeOfCode; - } - - /** - * @return The SizeOfInitializedData value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getSizeOfInitializedData() const - { - return m_inthHeader.OptionalHeader.SizeOfInitializedData; - } - - /** - * @return The SizeOfUninitializedData value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getSizeOfUninitializedData() const - { - return m_inthHeader.OptionalHeader.SizeOfUninitializedData; - } - - /** - * @return The AddressOfEntryPoint value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getAddressOfEntryPoint() const - { - return m_inthHeader.OptionalHeader.AddressOfEntryPoint; - } - - /** - * @return The BaseOfCode value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getBaseOfCode() const - { - return m_inthHeader.OptionalHeader.BaseOfCode; - } - - /** - * @return The ImageBase value from the PE header. - **/ - template - typename FieldSizes::VAR4_8 PeHeaderT::getImageBase() const - { - return m_inthHeader.OptionalHeader.ImageBase; - } - - /** - * @return The SectionAlignment value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getSectionAlignment() const - { - return m_inthHeader.OptionalHeader.SectionAlignment; - } - - /** - * @return The FileAlignment value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getFileAlignment() const - { - return m_inthHeader.OptionalHeader.FileAlignment; - } - - /** - * @return The MajorOperatingSystemVersion value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getMajorOperatingSystemVersion() const - { - return m_inthHeader.OptionalHeader.MajorOperatingSystemVersion; - } - - /** - * @return The MinorOperatingSystemVersion value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getMinorOperatingSystemVersion() const - { - return m_inthHeader.OptionalHeader.MinorOperatingSystemVersion; - } - - /** - * @return The MajorImageVersion value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getMajorImageVersion() const - { - return m_inthHeader.OptionalHeader.MajorImageVersion; - } - - /** - * @return The MinorImageVersion value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getMinorImageVersion() const - { - return m_inthHeader.OptionalHeader.MinorImageVersion; - } - - /** - * @return The MajorSubsystemVersion value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getMajorSubsystemVersion() const - { - return m_inthHeader.OptionalHeader.MajorSubsystemVersion; - } - - /** - * @return The MinorSubsystemVersion value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getMinorSubsystemVersion() const - { - return m_inthHeader.OptionalHeader.MinorSubsystemVersion; - } - - /** - * @return The WinVersionValue value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getWin32VersionValue() const - { - return m_inthHeader.OptionalHeader.Win32VersionValue; - } - - /** - * @return The SizeOfImage value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getSizeOfImage() const - { - return m_inthHeader.OptionalHeader.SizeOfImage; - } - - /** - * @return The SizeOfHeaders value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getSizeOfHeaders() const - { - return m_inthHeader.OptionalHeader.SizeOfHeaders; - } - - /** - * @return The CheckSums value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getCheckSum() const - { - return m_inthHeader.OptionalHeader.CheckSum; - } - - /** - * @return The Subsystem value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getSubsystem() const - { - return m_inthHeader.OptionalHeader.Subsystem; - } - - /** - * @return The DllCharacteristics value from the PE header. - **/ - template - std::uint16_t PeHeaderT::getDllCharacteristics() const - { - return m_inthHeader.OptionalHeader.DllCharacteristics; - } - - /** - * @return The SizeOfStackReserve value from the PE header. - **/ - template - typename FieldSizes::VAR4_8 PeHeaderT::getSizeOfStackReserve() const - { - return m_inthHeader.OptionalHeader.SizeOfStackReserve; - } - - /** - * @return The SizeOfStackCommit value from the PE header. - **/ - template - typename FieldSizes::VAR4_8 PeHeaderT::getSizeOfStackCommit() const - { - return m_inthHeader.OptionalHeader.SizeOfStackCommit; - } - - /** - * @return The SizeOfHeapReserve value from the PE header. - **/ - template - typename FieldSizes::VAR4_8 PeHeaderT::getSizeOfHeapReserve() const - { - return m_inthHeader.OptionalHeader.SizeOfHeapReserve; - } - - /** - * @return The SizeOfHeapCommit value from the PE header. - **/ - template - typename FieldSizes::VAR4_8 PeHeaderT::getSizeOfHeapCommit() const - { - return m_inthHeader.OptionalHeader.SizeOfHeapCommit; - } - - /** - * @return The LoaderFlags value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getLoaderFlags() const - { - return m_inthHeader.OptionalHeader.LoaderFlags; - } - - /** - * @return The NumberOfRvaAndSizes value from the PE header. - **/ - template - std::uint32_t PeHeaderT::getNumberOfRvaAndSizes() const - { - return m_inthHeader.OptionalHeader.NumberOfRvaAndSizes; - } - - template - std::uint32_t PeHeaderT::calcNumberOfRvaAndSizes() const - { - return static_cast(m_inthHeader.dataDirectories.size()); - } - - /** - * Returns the relative virtual address of the current file's export directory. - * @return The Rva of the Export directory. - **/ - template - std::uint32_t PeHeaderT::getIddExportRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - } - - /** - * Returns the size of the current file's export directory. - * @return The sizeof the Export directory. - **/ - template - std::uint32_t PeHeaderT::getIddExportSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT].Size; - } - - /** - * Returns the relative virtual address of the current file's import directory. - * @return The Rva of the Import directory. - **/ - template - std::uint32_t PeHeaderT::getIddImportRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; - } - - /** - * Returns the size of the current file's import directory. - * @return The size of the Import directory. - **/ - template - std::uint32_t PeHeaderT::getIddImportSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT].Size; - } - - /** - * Returns the relative virtual address of the current file's resource directory. - * @return The Rva of the Resource directory. - **/ - template - std::uint32_t PeHeaderT::getIddResourceRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; - } - - /** - * Returns the size of the current file'resource resource directory. - * @return The size of the Resource directory. - **/ - template - std::uint32_t PeHeaderT::getIddResourceSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; - } - - /** - * Returns the relative virtual address of the current file's exception directory. - * @return The Rva of the Exception directory. - **/ - template - std::uint32_t PeHeaderT::getIddExceptionRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress; - } - - /** - * Returns the size of the current file's exception directory. - * @return The size of the Exception directory. - **/ - template - std::uint32_t PeHeaderT::getIddExceptionSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size; - } - - /** - * Returns the relative virtual address of the current file's security directory. - * @return The Rva of the Security directory. - **/ - template - std::uint32_t PeHeaderT::getIddSecurityRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress; - } - - /** - * Returns the size of the current file's security directory. - * @return The size of the Security directory. - **/ - template - std::uint32_t PeHeaderT::getIddSecuritySize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; - } - - /** - * Returns the relative virtual address of the current file's base reloc directory. - * @return The Rva of the Base Reloc directory. - **/ - template - std::uint32_t PeHeaderT::getIddBaseRelocRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; - } - - /** - * Returns the size of the current file's base reloc directory. - * @return The size of the Base Reloc directory. - **/ - template - std::uint32_t PeHeaderT::getIddBaseRelocSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; - } - - /** - * Returns the relative virtual address of the current file's debug directory. - * @return The Rva of the Debug directory. - **/ - template - std::uint32_t PeHeaderT::getIddDebugRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; - } - - /** - * Returns the size of the current file's debug directory. - * @return The size of the Debug directory. - **/ - template - std::uint32_t PeHeaderT::getIddDebugSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; - } - - /** - * Returns the relative virtual address of the current file's Architecture directory. - * @return The Rva of the Architecture directory. - **/ - template - std::uint32_t PeHeaderT::getIddArchitectureRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress; - } - - /** - * Returns the size of the current file's Architecture directory. - * @return The size of the Architecture directory. - **/ - template - std::uint32_t PeHeaderT::getIddArchitectureSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size; - } - - /** - * Returns the relative virtual address of the current file's global ptr directory. - * @return The Rva of the GlobalPtr directory. - **/ - template - std::uint32_t PeHeaderT::getIddGlobalPtrRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress; - } - - /** - * Returns the size of the current file's global ptr directory. - * @return The size of the GlobalPtr directory. - **/ - template - std::uint32_t PeHeaderT::getIddGlobalPtrSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size; - } - - /** - * Returns the relative virtual address of the current file's TLS directory. - * @return The Rva of the Tls directory. - **/ - template - std::uint32_t PeHeaderT::getIddTlsRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; - } - - /** - * Returns the size of the current file's TLS directory. - * @return The size of the Tls directory. - **/ - template - std::uint32_t PeHeaderT::getIddTlsSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_TLS].Size; - } - - /** - * Returns the relative virtual address of the current file's load config directory. - * @return The Rva of the LoadConfig directory. - **/ - template - std::uint32_t PeHeaderT::getIddLoadConfigRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress; - } - - /** - * Returns the size of the current file's load config directory. - * @return The size of the LoadConfig directory. - **/ - template - std::uint32_t PeHeaderT::getIddLoadConfigSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size; - } - - /** - * Returns the relative virtual address of the current file's bound import directory. - * @return The Rva of the BoundImport directory. - **/ - template - std::uint32_t PeHeaderT::getIddBoundImportRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress; - } - - /** - * Returns the size of the current file's bound import directory. - * @return The size of the BoundImport directory. - **/ - template - std::uint32_t PeHeaderT::getIddBoundImportSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size; - } - - /** - * Returns the relative virtual address of the current file's IAT directory. - * @return The Rva of the IAT directory. - **/ - template - std::uint32_t PeHeaderT::getIddIatRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; - } - - /** - * Returns the size of the current file's IAT directory. - * @return The size of the IAT directory. - **/ - template - std::uint32_t PeHeaderT::getIddIatSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IAT].Size; - } - - /** - * Returns the relative virtual address of the current file's Delay Import directory. - * @return The Rva of the DelayImport directory. - **/ - template - std::uint32_t PeHeaderT::getIddDelayImportRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress; - } - - /** - * Returns the size of the current file's Delay Import directory. - * @return The size of the DelayImport directory. - **/ - template - std::uint32_t PeHeaderT::getIddDelayImportSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size; - } - - /** - * Returns the relative virtual address of the current file's COM Descriptor directory. - * @return The Rva of the COM Descriptor directory. - **/ - template - std::uint32_t PeHeaderT::getIddComHeaderRva() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress; - } - - /** - * Returns the size of the current file's COM Descriptor directory. - * @return The Rva of the COM Descriptor directory. - **/ - template - std::uint32_t PeHeaderT::getIddComHeaderSize() const - { - return m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; - } - - /** - * Returns the relative virtual address of an image directory. - * @param dwDirectory The identifier of an image directory. - * @return The Rva of the image directory. - **/ - template - std::uint32_t PeHeaderT::getImageDataDirectoryRva(std::uint32_t dwDirectory) const - { - return m_inthHeader.dataDirectories[dwDirectory].VirtualAddress; - } - - template - void PeHeaderT::setImageDataDirectoryRva(std::uint32_t dwDirectory, std::uint32_t value) - { - m_inthHeader.dataDirectories[dwDirectory].VirtualAddress = value; - } - - /** - * Returns the size of an image directory. - * @param dwDirectory The identifier of an image directory. - * @return The size of the image directory. - **/ - template - std::uint32_t PeHeaderT::getImageDataDirectorySize(std::uint32_t dwDirectory) const - { - return m_inthHeader.dataDirectories[dwDirectory].Size; - } - - template - void PeHeaderT::setImageDataDirectorySize(std::uint32_t dwDirectory, std::uint32_t value) - { - m_inthHeader.dataDirectories[dwDirectory].Size = value; - } - - /** - * Returns the name of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The name of the section. - **/ - template - std::string PeHeaderT::getSectionName(std::uint16_t wSectionnr) const - { - std::string sectionName = ""; - - for (unsigned int i=0;i - std::string PeHeaderT::getSectionNameFromStringTable(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].StringTableName; - } - - /** - * Returns the virtual size of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The virtual size of the section. - **/ - template - std::uint32_t PeHeaderT::getVirtualSize(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].VirtualSize; - } - - /** - * Returns the relative virtual address of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The Rva of the section. - **/ - template - std::uint32_t PeHeaderT::getVirtualAddress(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].VirtualAddress; - } - - /** - * Returns the size of raw data of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The size of raw data of the section. - **/ - template - std::uint32_t PeHeaderT::getSizeOfRawData(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].SizeOfRawData; - } - - /** - * Returns the file offset of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The file offset of the section. - **/ - template - std::uint32_t PeHeaderT::getPointerToRawData(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].PointerToRawData; - } - - /** - * Returns the pointer to relocations of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The pointer to relocations of the section. - **/ - template - std::uint32_t PeHeaderT::getPointerToRelocations(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].PointerToRelocations; - } - - /** - * Returns the poiner to line numbers of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The pointer to line numbers of the section. - **/ - template - std::uint32_t PeHeaderT::getPointerToLinenumbers(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].PointerToLinenumbers; - } - - /** - * Returns the number of relocations of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The number of relocations of the section. - **/ - template - std::uint32_t PeHeaderT::getNumberOfRelocations(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].NumberOfRelocations; - } - - /** - * Returns the number of line numbers of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The number of line numbers of the section. - **/ - template - std::uint32_t PeHeaderT::getNumberOfLinenumbers(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].NumberOfLinenumbers; - } - - /** - * Returns the characteristics of the section which is specified by the parameter wSectionnr. - * @param wSectionnr Index of the section. - * @return The characteristics of the section. - **/ - template - std::uint32_t PeHeaderT::getCharacteristics(std::uint16_t wSectionnr) const - { - return m_vIsh[wSectionnr].Characteristics; - } - - /** - * Changes the file's Nt signature. - * @param dwValue New value. - **/ - template - void PeHeaderT::setNtSignature(std::uint32_t dwValue) - { - m_inthHeader.Signature = dwValue; - } - - /** - * Changes the file's Machine. - * @param wValue New value. - **/ - template - void PeHeaderT::setMachine(std::uint16_t wValue) - { - m_inthHeader.FileHeader.Machine = wValue; - } - - /** - * Changes the number of sections. - * @param wValue New value. - **/ - template - void PeHeaderT::setNumberOfSections(std::uint16_t wValue) - { - m_inthHeader.FileHeader.NumberOfSections = wValue; - } - - /** - * Changes the file's TimeDateStamp. - * @param dwValue New value. - **/ - template - void PeHeaderT::setTimeDateStamp(std::uint32_t dwValue) - { - m_inthHeader.FileHeader.TimeDateStamp = dwValue; - } - - /** - * Changes the file's PointerToSymbolTable. - * @param dwValue New value. - **/ - template - void PeHeaderT::setPointerToSymbolTable(std::uint32_t dwValue) - { - m_inthHeader.FileHeader.PointerToSymbolTable = dwValue; - } - - /** - * Changes the file's NumberOfSymbols. - * @param dwValue New value. - **/ - template - void PeHeaderT::setNumberOfSymbols(std::uint32_t dwValue) - { - m_inthHeader.FileHeader.NumberOfSymbols = dwValue; - } - - /** - * Changes the file's SizeOfOptionalHeader. - * @param wValue New value. - **/ - template - void PeHeaderT::setSizeOfOptionalHeader(std::uint16_t wValue) - { - m_inthHeader.FileHeader.SizeOfOptionalHeader = wValue; - } - - /** - * Changes the file's Characteristics. - * @param wValue New value. - **/ - template - void PeHeaderT::setCharacteristics(std::uint16_t wValue) - { - m_inthHeader.FileHeader.Characteristics = wValue; - } - - /** - * Changes the file's Magic. - * @param wValue New value. - **/ - template - void PeHeaderT::setMagic(std::uint16_t wValue) - { - m_inthHeader.OptionalHeader.Magic = wValue; - } - - /** - * Changes the file's MajorLinkerVersion. - * @param bValue New value. - **/ - template - void PeHeaderT::setMajorLinkerVersion(std::uint8_t bValue) - { - m_inthHeader.OptionalHeader.MajorLinkerVersion = bValue; - } - - /** - * Changes the file's MinorLinkerVersion. - * @param bValue New value. - **/ - template - void PeHeaderT::setMinorLinkerVersion(std::uint8_t bValue) - { - m_inthHeader.OptionalHeader.MinorLinkerVersion = bValue; - } - - /** - * Changes the file's SizeOfCode. - * @param dwValue New value. - **/ - template - void PeHeaderT::setSizeOfCode(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.SizeOfCode = dwValue; - } - - /** - * Changes the file's SizeOfInitializedData. - * @param dwValue New value. - **/ - template - void PeHeaderT::setSizeOfInitializedData(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.SizeOfInitializedData = dwValue; - } - - /** - * Changes the file's SizeOfUninitializedData. - * @param dwValue New value. - **/ - template - void PeHeaderT::setSizeOfUninitializedData(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.SizeOfUninitializedData = dwValue; - } - - /** - * Changes the file's AddressOfEntryPoint. - * @param dwValue New value. - **/ - template - void PeHeaderT::setAddressOfEntryPoint(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.AddressOfEntryPoint = dwValue; - } - - /** - * Changes the file's BaseOfCode. - * @param dwValue New value. - **/ - template - void PeHeaderT::setBaseOfCode(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.BaseOfCode = dwValue; - } - - /** - * Changes the file's ImageBase. - * @param value New value. - **/ - template - void PeHeaderT::setImageBase(typename FieldSizes::VAR4_8 dwValue) - { - m_inthHeader.OptionalHeader.ImageBase = dwValue; - } - - /** - * Changes the file's SectionAlignment. - * @param dwValue New value. - **/ - template - void PeHeaderT::setSectionAlignment(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.SectionAlignment = dwValue; - } - - /** - * Changes the file's FileAlignment. - * @param dwValue New value. - **/ - template - void PeHeaderT::setFileAlignment(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.FileAlignment = dwValue; - } - - /** - * Changes the file's MajorOperatingSystemVersion. - * @param wValue New value. - **/ - template - void PeHeaderT::setMajorOperatingSystemVersion(std::uint16_t wValue) - { - m_inthHeader.OptionalHeader.MajorOperatingSystemVersion = wValue; - } - - /** - * Changes the file's MinorOperatingSystemVersion. - * @param wValue New value. - **/ - template - void PeHeaderT::setMinorOperatingSystemVersion(std::uint16_t wValue) - { - m_inthHeader.OptionalHeader.MinorOperatingSystemVersion = wValue; - } - - /** - * Changes the file's MajorImageVersion. - * @param wValue New value. - **/ - template - void PeHeaderT::setMajorImageVersion(std::uint16_t wValue) - { - m_inthHeader.OptionalHeader.MajorImageVersion = wValue; - } - - /** - * Changes the file's MinorImageVersion. - * @param wValue New value. - **/ - template - void PeHeaderT::setMinorImageVersion(std::uint16_t wValue) - { - m_inthHeader.OptionalHeader.MinorImageVersion = wValue; - } - - /** - * Changes the file's MajorSubsystemVersion. - * @param wValue New value. - **/ - template - void PeHeaderT::setMajorSubsystemVersion(std::uint16_t wValue) - { - m_inthHeader.OptionalHeader.MajorSubsystemVersion = wValue; - } - - /** - * Changes the file's MinorSubsystemVersion. - * @param wValue New value. - **/ - template - void PeHeaderT::setMinorSubsystemVersion(std::uint16_t wValue) - { - m_inthHeader.OptionalHeader.MinorSubsystemVersion = wValue; - } - - /** - * Changes the file's Win32VersionValue. - * @param dwValue New value. - **/ - template - void PeHeaderT::setWin32VersionValue(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.Win32VersionValue = dwValue; - } - - /** - * Changes the file's SizeOfImage. - * @param dwValue New value. - **/ - template - void PeHeaderT::setSizeOfImage(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.SizeOfImage = dwValue; - } - - /** - * Changes the file's SizeOfHeaders. - * @param dwValue New value. - **/ - template - void PeHeaderT::setSizeOfHeaders(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.SizeOfHeaders = dwValue; - } - - /** - * Changes the file's CheckSum. - * @param dwValue New value. - **/ - template - void PeHeaderT::setCheckSum(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.CheckSum = dwValue; - } - - /** - * Changes the file's Subsystem. - * @param wValue New value. - **/ - template - void PeHeaderT::setSubsystem(std::uint16_t wValue) - { - m_inthHeader.OptionalHeader.Subsystem = wValue; - } - - /** - * Changes the file's DllCharacteristics. - * @param wValue New value. - **/ - template - void PeHeaderT::setDllCharacteristics(std::uint16_t wValue) - { - m_inthHeader.OptionalHeader.DllCharacteristics = wValue; - } - - /** - * Changes the file's SizeOfStackReserve. - * @param value New value. - **/ - template - void PeHeaderT::setSizeOfStackReserve(typename FieldSizes::VAR4_8 dwValue) - { - m_inthHeader.OptionalHeader.SizeOfStackReserve = dwValue; - } - - /** - * Changes the file's SizeOfStackCommit. - * @param value New value. - **/ - template - void PeHeaderT::setSizeOfStackCommit(typename FieldSizes::VAR4_8 dwValue) - { - m_inthHeader.OptionalHeader.SizeOfStackCommit = dwValue; - } - - /** - * Changes the file's SizeOfHeapReserve. - * @param value New value. - **/ - template - void PeHeaderT::setSizeOfHeapReserve(typename FieldSizes::VAR4_8 dwValue) - { - m_inthHeader.OptionalHeader.SizeOfHeapReserve = dwValue; - } - - /** - * Changes the file's SizeOfHeapCommit. - * @param value New value. - **/ - template - void PeHeaderT::setSizeOfHeapCommit(typename FieldSizes::VAR4_8 dwValue) - { - m_inthHeader.OptionalHeader.SizeOfHeapCommit = dwValue; - } - - /** - * Changes the file's LoaderFlags. - * @param dwValue New value. - **/ - template - void PeHeaderT::setLoaderFlags(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.LoaderFlags = dwValue; - } - - /** - * Changes the file's NumberOfRvaAndSizes. - * @param dwValue New value. - **/ - template - void PeHeaderT::setNumberOfRvaAndSizes(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.NumberOfRvaAndSizes = dwValue; - } - - template - void PeHeaderT::setIddDebugRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = dwValue; - } - - template - void PeHeaderT::setIddDebugSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = dwValue; - } - - template - void PeHeaderT::setIddDelayImportRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress = dwValue; - } - - template - void PeHeaderT::setIddDelayImportSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size = dwValue; - } - - template - void PeHeaderT::setIddExceptionRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = dwValue; - } - - template - void PeHeaderT::setIddExceptionSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = dwValue; - } - - template - void PeHeaderT::setIddGlobalPtrRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress = dwValue; - } - - template - void PeHeaderT::setIddGlobalPtrSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size = dwValue; - } - - template - void PeHeaderT::setIddIatRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dwValue; - } - - template - void PeHeaderT::setIddIatSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IAT].Size = dwValue; - } - - template - void PeHeaderT::setIddLoadConfigRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = dwValue; - } - - template - void PeHeaderT::setIddLoadConfigSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = dwValue; - } - - template - void PeHeaderT::setIddResourceRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = dwValue; - } - - template - void PeHeaderT::setIddResourceSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = dwValue; - } - - template - void PeHeaderT::setIddSecurityRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = dwValue; - } - - template - void PeHeaderT::setIddSecuritySize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_SECURITY].Size = dwValue; - } - - template - void PeHeaderT::setIddTlsRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = dwValue; - } - - template - void PeHeaderT::setIddTlsSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_TLS].Size = dwValue; - } - - /** - * Changes the rva of the file's export directory. - * @param dwValue New value. - **/ - template - void PeHeaderT::setIddExportRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = dwValue; - } - - /** - * Changes the size of the file's export directory. - * @param dwValue New value. - **/ - template - void PeHeaderT::setIddExportSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT].Size = dwValue; - } - - template - void PeHeaderT::setIddBaseRelocRva(std::uint32_t value) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = value; - } - - template - void PeHeaderT::setIddBaseRelocSize(std::uint32_t value) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = value; - } - - template - void PeHeaderT::setIddArchitectureRva(std::uint32_t value) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress = value; - } - - template - void PeHeaderT::setIddArchitectureSize(std::uint32_t value) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size = value; - } - - template - void PeHeaderT::setIddComHeaderRva(std::uint32_t value) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = value; - } - - template - void PeHeaderT::setIddComHeaderSize(std::uint32_t value) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = value; - } - - /** - * Changes the rva of the file's import directory. - * @param dwValue New value. - **/ - template - void PeHeaderT::setIddImportRva(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = dwValue; - } - - /** - * Changes the size of the file's import directory. - * @param dwValue New value. - **/ - template - void PeHeaderT::setIddImportSize(std::uint32_t dwValue) - { - m_inthHeader.dataDirectories[PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT].Size = dwValue; - } - - /** - * Changes the name of a section. - * @param wSectionnr Identifier of the section - * @param strName New name. - **/ - template - void PeHeaderT::setSectionName(std::uint16_t wSectionnr, std::string strName) - { - strncpy(reinterpret_cast(m_vIsh[wSectionnr].Name), strName.c_str(), sizeof(m_vIsh[wSectionnr].Name)); - } - - /** - * Changes the virtual size of a section. - * @param wSectionnr Identifier of the section - * @param dwValue New value. - **/ - template - void PeHeaderT::setVirtualSize(std::uint16_t wSectionnr, std::uint32_t dwValue) - { - m_vIsh[wSectionnr].VirtualSize = dwValue; - } - - /** - * Changes the virtual address of a section. - * @param wSectionnr Identifier of the section - * @param dwValue New value. - **/ - template - void PeHeaderT::setVirtualAddress(std::uint16_t wSectionnr, std::uint32_t dwValue) - { - m_vIsh[wSectionnr].VirtualAddress = dwValue; - } - - /** - * Changes the size of raw data of a section. - * @param wSectionnr Identifier of the section - * @param dwValue New value. - **/ - template - void PeHeaderT::setSizeOfRawData(std::uint16_t wSectionnr, std::uint32_t dwValue) - { - m_vIsh[wSectionnr].SizeOfRawData = dwValue; - } - - /** - * Changes the size of raw data of a section. - * @param wSectionnr Identifier of the section - * @param dwValue New value. - **/ - template - void PeHeaderT::setPointerToRawData(std::uint16_t wSectionnr, std::uint32_t dwValue) - { - m_vIsh[wSectionnr].PointerToRawData = dwValue; - } - - /** - * Changes the pointer to relocations of a section. - * @param wSectionnr Identifier of the section - * @param dwValue New value. - **/ - template - void PeHeaderT::setPointerToRelocations(std::uint16_t wSectionnr, std::uint32_t dwValue) - { - m_vIsh[wSectionnr].PointerToRelocations = dwValue; - } - - /** - * Changes the pointer to line numbers of a section. - * @param wSectionnr Identifier of the section - * @param dwValue New value. - **/ - template - void PeHeaderT::setPointerToLinenumbers(std::uint16_t wSectionnr, std::uint32_t dwValue) - { - m_vIsh[wSectionnr].PointerToLinenumbers = dwValue; - } - - /** - * Changes the number of relocations of a section. - * @param wSectionnr Identifier of the section - * @param dwValue New value. - **/ - template - void PeHeaderT::setNumberOfRelocations(std::uint16_t wSectionnr, std::uint32_t dwValue) - { - m_vIsh[wSectionnr].NumberOfRelocations = dwValue; - } - - /** - * Changes the number of line numbers of a section. - * @param wSectionnr Identifier of the section - * @param dwValue New value. - **/ - template - void PeHeaderT::setNumberOfLinenumbers(std::uint16_t wSectionnr, std::uint32_t dwValue) - { - m_vIsh[wSectionnr].NumberOfLinenumbers = dwValue; - } - - /** - * Changes the characteristics of a section. - * @param wSectionnr Identifier of the section - * @param dwValue New value. - **/ - template - void PeHeaderT::setCharacteristics(std::uint16_t wSectionnr, std::uint32_t dwValue) - { - m_vIsh[wSectionnr].Characteristics = dwValue; - } - -} - -#endif diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 03a4b3d9e..5415cc859 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -51,7 +51,7 @@ uint8_t PeLib::ImageLoader::ImageProtectionArray[16] = //----------------------------------------------------------------------------- // Constructor and destructor -PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) +PeLib::ImageLoader::ImageLoader(uint32_t versionInfo) { memset(&dosHeader, 0, sizeof(PELIB_IMAGE_DOS_HEADER)); memset(&fileHeader, 0, sizeof(PELIB_IMAGE_FILE_HEADER)); @@ -68,36 +68,40 @@ PeLib::ImageLoader::ImageLoader(uint32_t loaderFlags) ntHeadersSizeCheck = false; appContainerCheck = false; maxSectionCount = 255; - is64BitWindows = (loaderFlags & LoaderMode64BitWindows) ? true : false; + is64BitWindows = (versionInfo & BuildNumber64Bit) ? true : false; + windowsBuildNumber = (versionInfo & BuildNumberMask); headerSizeCheck = false; loadArmImages = true; - // Resolve version-specific restrictions - switch(loaderMode = (loaderFlags & WindowsVerMask)) + // Windows XP specific behaviors + if(BuildNumberXP <= windowsBuildNumber && windowsBuildNumber < BuildNumber7) { - case LoaderModeWindowsXP: - ssiImageAlignment32 = PELIB_SECTOR_SIZE; - maxSectionCount = PE_MAX_SECTION_COUNT_XP; - sizeofImageMustMatch = true; - headerSizeCheck = true; - loadArmImages = false; - break; + ssiImageAlignment32 = PELIB_SECTOR_SIZE; + maxSectionCount = PE_MAX_SECTION_COUNT_XP; + sizeofImageMustMatch = true; + headerSizeCheck = true; + loadArmImages = false; + } - case LoaderModeWindows7: - ssiImageAlignment32 = 1; // SECTOR_SIZE when the image is loaded from network media - maxSectionCount = PE_MAX_SECTION_COUNT_7; - ntHeadersSizeCheck = true; - sizeofImageMustMatch = true; - loadArmImages = false; - break; + // Windows 7 specific behaviors + else if(BuildNumber7 <= windowsBuildNumber && windowsBuildNumber < BuildNumber10) + { + ssiImageAlignment32 = 1; // SECTOR_SIZE when the image is loaded from network media + maxSectionCount = PE_MAX_SECTION_COUNT_7; + ntHeadersSizeCheck = true; + sizeofImageMustMatch = true; + loadArmImages = false; + } - case LoaderModeWindows10: - ssiImageAlignment32 = 1; - maxSectionCount = PE_MAX_SECTION_COUNT_7; - ntHeadersSizeCheck = true; - appContainerCheck = true; - loadArmImages = true; - break; + // Windows 10 specific behaviors + else if(BuildNumber10 <= windowsBuildNumber) + { + sizeofImageMustMatch = (windowsBuildNumber <= 17134); + ssiImageAlignment32 = 1; + maxSectionCount = PE_MAX_SECTION_COUNT_7; + ntHeadersSizeCheck = true; + appContainerCheck = true; + loadArmImages = true; } } @@ -675,7 +679,7 @@ int PeLib::ImageLoader::splitSection(size_t sectionIndex, const std::string & pr // Move every section located after the inserted section by one position sections.resize(sections.size() + 1); - for(int i = sections.size() - 2; i >= sectionIndex + 1; --i) + for(size_t i = sections.size() - 2; i >= sectionIndex + 1; --i) sections[i + 1] = sections[i]; uint32_t originalSize = getSectionHeader(sectionIndex)->SizeOfRawData; @@ -793,7 +797,7 @@ PeLib::LoaderError PeLib::ImageLoader::loaderError() const //----------------------------------------------------------------------------- // Interface for loading files -int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOnly) +int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOnly) { int fileError; @@ -1081,7 +1085,7 @@ void PeLib::ImageLoader::processSectionHeader(PELIB_IMAGE_SECTION_HEADER * pSect { // Note: Retdec's regression tests don't like it, because they require section headers to have original data // Also signature verification stops working if we modify the original data - if(loaderMode != 0) + if(windowsBuildNumber != 0) { // Fix the section header. Note that this will modify the data in the on-disk version // of the image. Any section that will become mapped to this section header @@ -1987,7 +1991,7 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) return ERROR_NONE; } -int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_t fileSize) +int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, size_t fileSize) { if(hdr.e_magic != PELIB_IMAGE_DOS_SIGNATURE) return ERROR_INVALID_FILE; @@ -1999,7 +2003,7 @@ int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_ return ERROR_NONE; } -int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, std::size_t fileSize) +int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, size_t fileSize) { PELIB_IMAGE_DOS_HEADER tempDosHeader; int fileError; diff --git a/src/pelib/MzHeader.cpp b/src/pelib/MzHeader.cpp deleted file mode 100644 index 21597ecaa..000000000 --- a/src/pelib/MzHeader.cpp +++ /dev/null @@ -1,637 +0,0 @@ -/* -* MzHeader.cpp - Part of the PeLib library. -* -* Copyright (c) 2004 - 2005 Sebastian Porst (webmaster@the-interweb.com) -* All rights reserved. -* -* This software is licensed under the zlib/libpng License. -* For more details see http://www.opensource.org/licenses/zlib-license.php -* or the license information file (license.htm) in the root directory -* of PeLib. -*/ - -#include - -#include "retdec/pelib/MzHeader.h" - -namespace PeLib -{ - /** - * Reads data from an InputBuffer into the struct that represents the MZ header. - * It's required that the size of the input buffer is at least as big as the - * size of a MZ header. Otherwise we get undefined behaviour. - * @param ibBuffer InputBuffer that holds the data. - * @return A non-zero value is returned if a problem occurred. - **/ - void MzHeader::read(InputBuffer& ibBuffer) - { - ibBuffer >> m_idhHeader.e_magic; - ibBuffer >> m_idhHeader.e_cblp; - ibBuffer >> m_idhHeader.e_cp; - ibBuffer >> m_idhHeader.e_crlc; - ibBuffer >> m_idhHeader.e_cparhdr; - ibBuffer >> m_idhHeader.e_minalloc; - ibBuffer >> m_idhHeader.e_maxalloc; - ibBuffer >> m_idhHeader.e_ss; - ibBuffer >> m_idhHeader.e_sp; - ibBuffer >> m_idhHeader.e_csum; - ibBuffer >> m_idhHeader.e_ip; - ibBuffer >> m_idhHeader.e_cs; - ibBuffer >> m_idhHeader.e_lfarlc; - ibBuffer >> m_idhHeader.e_ovno; - - for (unsigned int i=0;i> m_idhHeader.e_res[i]; - } - - ibBuffer >> m_idhHeader.e_oemid; - ibBuffer >> m_idhHeader.e_oeminfo; - - for (unsigned int i=0;i> m_idhHeader.e_res2[i]; - } - - ibBuffer >> m_idhHeader.e_lfanew; - } - - MzHeader::MzHeader(): originalOffset(0), m_ldrError() {} - - /** - * Tests if the currently loaded MZ header is a valid MZ header. - * Note that this function does not check if the address to the PE header is valid as this is not possible. - * Actually, the only thing this function checks is if the e_magic value is set to 0x5A4D (IMAGE_DOS_SIGNATURE). - * Everything else is not relevant for Windows 2000 and that's the system PeLib is focusing on for now. - * @return A boolean value that indicates if the MZ header is correct or not. - **/ - bool MzHeader::isValid() const - { - // The only thing that matters on Windows 2K is the e_magic value. The entire rest is for DOS compatibility. - return isValid(e_magic); - } - - bool MzHeader::isValid(Field f) const - { - if (f == e_magic) - { - return m_idhHeader.e_magic == PELIB_IMAGE_DOS_SIGNATURE; - } - else - { - return true; - } - } - - void MzHeader::setLoaderError(LoaderError ldrError) - { - // Do not override an existing loader error - if (m_ldrError == LDR_ERROR_NONE) - { - m_ldrError = ldrError; - } - } - - LoaderError MzHeader::loaderError() const - { - return m_ldrError; - } - - /** - * Corrects all erroneous values of the current MZ header. Note that this function does not correct the - * pointer to the PE header. - * Actually, the only thing this function corrects is the e_magic value. - * Everything else is not relevant for Windows 2000 and that's the system PeLib is focusing on for now. - **/ - void MzHeader::makeValid() - { - // The only thing that matters on Windows is the e_magic value. The entire rest is for DOS compatibility. - setMagicNumber(PELIB_IMAGE_DOS_SIGNATURE); - } - - void MzHeader::makeValid(Field f) - { - if (f == e_magic) - { - setMagicNumber(PELIB_IMAGE_DOS_SIGNATURE); - } - } - - /** - * Reads the MZ header from a file. Note that this function does not verify if a file is actually a MZ file. - * For this purpose see #PeLib::MzHeader::isValid. The reason for this is simple: Otherwise it might not - * be possible to load damaged PE files to repair them. - * @param inStream Input stream. - * @return A non-zero value is returned if a problem occurred. - **/ - int MzHeader::read(std::istream& inStream) - { - IStreamWrapper inStream_w(inStream); - - if (!inStream_w) - { - return ERROR_OPENING_FILE; - } - - std::uint64_t ulFileSize = fileSize(inStream_w); - if (ulFileSize < PELIB_IMAGE_DOS_HEADER::size()) - { - return ERROR_INVALID_FILE; - } - - // Windows loader refuses to load any file which is larger than 0xFFFFFFFF - if ((ulFileSize >> 32) != 0) - { - setLoaderError(LDR_ERROR_FILE_TOO_BIG); - } - - inStream_w.seekg(0, std::ios::beg); - - originalOffset = 0; - - std::vector vBuffer(PELIB_IMAGE_DOS_HEADER::size()); - inStream_w.read(reinterpret_cast(vBuffer.data()), static_cast(vBuffer.size())); - inStream_w.seekg(0, std::ios::beg); - m_headerString.clear(); - m_headerString.resize(PELIB_IMAGE_DOS_HEADER::size()); - inStream_w.read(&m_headerString[0], PELIB_IMAGE_DOS_HEADER::size()); - - InputBuffer ibBuffer(vBuffer); - read(ibBuffer); - - // For 64-bit systems, the e_lfanew must be aligned to 4 - if (m_idhHeader.e_lfanew & 3) - setLoaderError(LDR_ERROR_E_LFANEW_UNALIGNED); - - // The offset of PE header must not be out of file - if (m_idhHeader.e_lfanew > (std::uint32_t)ulFileSize) - setLoaderError(LDR_ERROR_E_LFANEW_OUT_OF_FILE); - - return ERROR_NONE; - } - - /** - * Reads the MZ header from memory. A pointer to a location in memory is passed and the data - * at this location is treated like a MZ header structure. The MZ header does not need to be valid. - * @param pcBuffer Pointer to a MZ header. - * @param uiSize Length of the buffer. - * @param originalOffs Offset of the MZ header in the original file to be saved. - * @return A non-zero value is returned if a problem occurred. - **/ - int MzHeader::read(unsigned char* pcBuffer, unsigned int uiSize, unsigned int originalOffs) - { - if (uiSize < PELIB_IMAGE_DOS_HEADER::size()) - { - return ERROR_INVALID_FILE; - } - - std::vector vBuffer(pcBuffer, pcBuffer + uiSize); - for (int i=0;i<0x40;i++) std::cout << std::hex << (int)vBuffer[i] << " "; - - originalOffset = originalOffs; - - InputBuffer ibBuffer(vBuffer); - read(ibBuffer); - return ERROR_NONE; - } - - /** - * Rebuilds the MZ header so that it can be written to a file. It's not guaranteed that the - * MZ header will be valid. If you want to make sure that the MZ header will be valid you - * must call #PeLib::MzHeader::makeValid first. - * @param vBuffer Buffer where the rebuilt MZ header will be stored. - **/ - void MzHeader::rebuild(std::vector& vBuffer) const - { - OutputBuffer obBuffer(vBuffer); - - obBuffer << m_idhHeader.e_magic; - obBuffer << m_idhHeader.e_cblp; - obBuffer << m_idhHeader.e_cp; - obBuffer << m_idhHeader.e_crlc; - obBuffer << m_idhHeader.e_cparhdr; - obBuffer << m_idhHeader.e_minalloc; - obBuffer << m_idhHeader.e_maxalloc; - obBuffer << m_idhHeader.e_ss; - obBuffer << m_idhHeader.e_sp; - obBuffer << m_idhHeader.e_csum; - obBuffer << m_idhHeader.e_ip; - obBuffer << m_idhHeader.e_cs; - obBuffer << m_idhHeader.e_lfarlc; - obBuffer << m_idhHeader.e_ovno; - - for (unsigned int i=0;i vBuffer; - - rebuild(vBuffer); - - ofFile.write(reinterpret_cast(vBuffer.data()), static_cast(vBuffer.size())); - - ofFile.close(); - - return ERROR_NONE; - } - - /** - * Returns the MZ header. - **/ - const PELIB_IMAGE_DOS_HEADER& MzHeader::getHeader() const - { - return m_idhHeader; - } - - /** - * Returns the MZ header in string representation. - **/ - const std::string& MzHeader::getString() const - { - return m_headerString; - } - - /** - * Returns the MZ header's e_magic value. - **/ - std::uint16_t MzHeader::getMagicNumber() const - { - return m_idhHeader.e_magic; - } - - /** - * Returns the MZ header's e_cblp value. - **/ - std::uint16_t MzHeader::getBytesOnLastPage() const - { - return m_idhHeader.e_cblp; - } - - /** - * Returns the MZ header's e_cp value. - **/ - std::uint16_t MzHeader::getPagesInFile() const - { - return m_idhHeader.e_cp; - } - - /** - * Returns the MZ header's e_crlc value. - **/ - std::uint16_t MzHeader::getRelocations() const - { - return m_idhHeader.e_crlc; - } - - /** - * Returns the MZ header's e_cparhdr value. - **/ - std::uint16_t MzHeader::getSizeOfHeader() const - { - return m_idhHeader.e_cparhdr; - } - - /** - * Returns the MZ header's e_minalloc value. - **/ - std::uint16_t MzHeader::getMinExtraParagraphs() const - { - return m_idhHeader.e_minalloc; - } - - /** - * Returns the MZ header's e_maxalloc value. - **/ - std::uint16_t MzHeader::getMaxExtraParagraphs() const - { - return m_idhHeader.e_maxalloc; - } - - /** - * Returns the MZ header's e_ss value. - **/ - std::uint16_t MzHeader::getSsValue() const - { - return m_idhHeader.e_ss; - } - - /** - * Returns the MZ header's e_sp value. - **/ - std::uint16_t MzHeader::getSpValue() const - { - return m_idhHeader.e_sp; - } - - /** - * Returns the MZ header's e_csum value. - **/ - std::uint16_t MzHeader::getChecksum() const - { - return m_idhHeader.e_csum; - } - - /** - * Returns the MZ header's e_ip value. - **/ - std::uint16_t MzHeader::getIpValue() const - { - return m_idhHeader.e_ip; - } - - /** - * Returns the MZ header's e_cs value. - **/ - std::uint16_t MzHeader::getCsValue() const - { - return m_idhHeader.e_cs; - } - - /** - * Returns the MZ header's e_lfarlc value. - **/ - std::uint16_t MzHeader::getAddrOfRelocationTable() const - { - return m_idhHeader.e_lfarlc; - } - - /** - * Returns the MZ header's e_ovno value. - **/ - std::uint16_t MzHeader::getOverlayNumber() const - { - return m_idhHeader.e_ovno; - } - - /** - * Returns the MZ header's e_oemid value. - **/ - std::uint16_t MzHeader::getOemIdentifier() const - { - return m_idhHeader.e_oemid; - } - - /** - * Returns the MZ header's e_oeminfo value. - **/ - std::uint16_t MzHeader::getOemInformation() const - { - return m_idhHeader.e_oeminfo; - } - - /** - * Returns the MZ header's e_lfanew value. - **/ - std::uint32_t MzHeader::getAddressOfPeHeader() const - { - return m_idhHeader.e_lfanew; - } - - /** - * Returns the MZ header's e_res[uiNr] value. If the parameter uiNr is out of range - * you will get undefined behaviour. - * @param uiNr The index of the std::uint16_t in the e_res array (valid range: 0-3) - **/ - std::uint16_t MzHeader::getReservedWords1(unsigned int uiNr) const - { - return m_idhHeader.e_res[uiNr]; - } - - /** - * Returns the MZ header's e_res2[uiNr] value. If the parameter uiNr is out of range - * you will get undefined behaviour. - * @param uiNr The index of the std::uint16_t in the e_res array (valid range: 0-9) - **/ - std::uint16_t MzHeader::getReservedWords2(unsigned int uiNr) const - { - return m_idhHeader.e_res2[uiNr]; - } - - /** - * Sets the MZ header's e_magic value. - * @param wValue The new value of e_magic. - **/ - void MzHeader::setMagicNumber(std::uint16_t wValue) - { - m_idhHeader.e_magic = wValue; - } - - /** - * Sets the MZ header's e_cblp value. - * @param wValue The new value of e_cblp. - **/ - void MzHeader::setBytesOnLastPage(std::uint16_t wValue) - { - m_idhHeader.e_cblp = wValue; - } - - /** - * Sets the MZ header's e_cp value. - * @param wValue The new value of e_cp. - **/ - void MzHeader::setPagesInFile(std::uint16_t wValue) - { - m_idhHeader.e_cp = wValue; - } - - /** - * Sets the MZ header's e_crlc value. - * @param wValue The new value of e_crlc. - **/ - void MzHeader::setRelocations(std::uint16_t wValue) - { - m_idhHeader.e_crlc = wValue; - } - - /** - * Sets the MZ header's e_cparhdr value. - * @param wValue The new value of e_cparhdr. - **/ - void MzHeader::setSizeOfHeader(std::uint16_t wValue) - { - m_idhHeader.e_cparhdr = wValue; - } - - /** - * Sets the MZ header's e_minalloc value. - * @param wValue The new value of e_minalloc. - **/ - void MzHeader::setMinExtraParagraphs(std::uint16_t wValue) - { - m_idhHeader.e_minalloc = wValue; - } - - /** - * Sets the MZ header's e_maxalloc value. - * @param wValue The new value of e_maxalloc. - **/ - void MzHeader::setMaxExtraParagraphs(std::uint16_t wValue) - { - m_idhHeader.e_maxalloc = wValue; - } - - /** - * Sets the MZ header's e_ss value. - * @param wValue The new value of e_ss. - **/ - void MzHeader::setSsValue(std::uint16_t wValue) - { - m_idhHeader.e_ss = wValue; - } - - /** - * Sets the MZ header's e_sp value. - * @param wValue The new value of e_sp. - **/ - void MzHeader::setSpValue(std::uint16_t wValue) - { - m_idhHeader.e_sp = wValue; - } - - /** - * Sets the MZ header's e_csum value. - * @param wValue The new value of e_csum. - **/ - void MzHeader::setChecksum(std::uint16_t wValue) - { - m_idhHeader.e_csum = wValue; - } - - /** - * Sets the MZ header's e_ip value. - * @param wValue The new value of e_ip. - **/ - void MzHeader::setIpValue(std::uint16_t wValue) - { - m_idhHeader.e_ip = wValue; - } - - /** - * Sets the MZ header's e_cs value. - * @param wValue The new value of e_cs. - **/ - void MzHeader::setCsValue(std::uint16_t wValue) - { - m_idhHeader.e_cs = wValue; - } - - /** - * Sets the MZ header's e_lfarlc value. - * @param wValue The new value of e_lfarlc. - **/ - void MzHeader::setAddrOfRelocationTable(std::uint16_t wValue) - { - m_idhHeader.e_lfarlc = wValue; - } - - /** - * Sets the MZ header's e_ovno value. - * @param wValue The new value of e_ovno. - **/ - void MzHeader::setOverlayNumber(std::uint16_t wValue) - { - m_idhHeader.e_ovno = wValue; - } - - /** - * Sets the MZ header's e_oemid value. - * @param wValue The new value of e_oemid. - **/ - void MzHeader::setOemIdentifier(std::uint16_t wValue) - { - m_idhHeader.e_oemid = wValue; - } - - /** - * Sets the MZ header's e_oeminfo value. - * @param wValue The new value of e_oeminfo. - **/ - void MzHeader::setOemInformation(std::uint16_t wValue) - { - m_idhHeader.e_oeminfo = wValue; - } - - /** - * Sets the MZ header's e_lfanew value. - * @param lValue The new value of e_lfanew. - **/ - void MzHeader::setAddressOfPeHeader(std::uint32_t lValue) - { - m_idhHeader.e_lfanew = lValue; - } - - /** - * Sets the MZ header's e_res[uiNr] value. If the parameter uiNr is out of range - * you will get undefined behaviour. - * @param uiNr The index of the std::uint16_t in the e_res array (valid range: 0-3) - * @param wValue The new value of e_res[nr]. - **/ - void MzHeader::setReservedWords1(unsigned int uiNr, std::uint16_t wValue) - { - m_idhHeader.e_res[uiNr] = wValue; - } - - /** - * Sets the MZ header's e_res2[uiNr] value. If the parameter uiNr is out of range - * you will get undefined behaviour. - * @param uiNr The index of the std::uint16_t in the e_res2 array (valid range: 0-9) - * @param wValue The new value of e_res[nr]. - **/ - void MzHeader::setReservedWords2(unsigned int uiNr, std::uint16_t wValue) - { - m_idhHeader.e_res2[uiNr] = wValue; - } - -} diff --git a/src/pelib/PeHeader.cpp b/src/pelib/PeHeader.cpp deleted file mode 100644 index feac20520..000000000 --- a/src/pelib/PeHeader.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -* PeHeader.cpp - Part of the PeLib library. -* -* Copyright (c) 2004 - 2005 Sebastian Porst (webmaster@the-interweb.com) -* All rights reserved. -* -* This software is licensed under the zlib/libpng License. -* For more details see http://www.opensource.org/licenses/zlib-license.php -* or the license information file (license.htm) in the root directory -* of PeLib. -*/ - -#include "retdec/pelib/PeLibInc.h" -#include "retdec/pelib/PeHeader.h" - -namespace PeLib -{ - /* - template<> - void PeHeaderT<32>::readBaseOfData(InputBuffer& ibBuffer, PELIB_IMAGE_NT_HEADERS & header) const - { - ibBuffer >> header.OptionalHeader.BaseOfData; - } - - template<> - void PeHeaderT<64>::readBaseOfData(InputBuffer&, PELIB_IMAGE_NT_HEADERS &) const - { - } - */ - - template<> - void PeHeaderT<32>::rebuildBaseOfData(OutputBuffer& obBuffer) const - { - obBuffer << m_inthHeader.OptionalHeader.BaseOfData; - } - - template<> - void PeHeaderT<64>::rebuildBaseOfData(OutputBuffer&) const - { - } - - template<> - bool PeHeaderT<32>::isValid() const - { - return true; - } - - template<> - bool PeHeaderT<64>::isValid() const - { - return true; - } - - template<> - bool PeHeaderT<32>::isValid(unsigned int pehf) const - { - (void) pehf; /* avoid warning about unused parameter */ - /* - if (pehf == NtSignature) - { - return m_inthHeader.Signature == IMAGE_NT_SIGNATURE; - } - else if (pehf == NumberOfSections) - { - return getNumberOfSections() == calcNumberOfSections(); - } */ - return false; - } - - template<> - bool PeHeaderT<64>::isValid(unsigned int pehf) const - { - (void) pehf; /* avoid warning about unused parameter */ - return false; - } - - /** - * @return The BaseOfData value from the PE header. - **/ - std::uint32_t PeHeader32::getBaseOfData() const - { - return m_inthHeader.OptionalHeader.BaseOfData; - } - - /** - * Changes the file's BaseOfData. - * @param dwValue New value. - **/ - void PeHeader32::setBaseOfData(std::uint32_t dwValue) - { - m_inthHeader.OptionalHeader.BaseOfData = dwValue; - } - -} From bc459cf0d098b9745d6fce93dd8a03395d430822 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 15 Jul 2020 09:29:11 +0200 Subject: [PATCH 29/34] Fixing doxugen build regression --- src/pelib/ImageLoader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 5415cc859..f13ed401e 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -797,7 +797,7 @@ PeLib::LoaderError PeLib::ImageLoader::loaderError() const //----------------------------------------------------------------------------- // Interface for loading files -int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOnly) +int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOnly) { int fileError; @@ -1991,7 +1991,7 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) return ERROR_NONE; } -int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, size_t fileSize) +int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_t fileSize) { if(hdr.e_magic != PELIB_IMAGE_DOS_SIGNATURE) return ERROR_INVALID_FILE; @@ -2003,7 +2003,7 @@ int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, size_t fil return ERROR_NONE; } -int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, size_t fileSize) +int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, std::size_t fileSize) { PELIB_IMAGE_DOS_HEADER tempDosHeader; int fileError; From d12edc6bba16925fa96f8deda16e75f090c76e41 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 15 Jul 2020 09:32:23 +0200 Subject: [PATCH 30/34] cosmetic --- src/pelib/ImageLoader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index f13ed401e..18cb49934 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -74,7 +74,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t versionInfo) loadArmImages = true; // Windows XP specific behaviors - if(BuildNumberXP <= windowsBuildNumber && windowsBuildNumber < BuildNumber7) + if(BuildNumberXP <= windowsBuildNumber && windowsBuildNumber < BuildNumberVista) { ssiImageAlignment32 = PELIB_SECTOR_SIZE; maxSectionCount = PE_MAX_SECTION_COUNT_XP; @@ -84,7 +84,7 @@ PeLib::ImageLoader::ImageLoader(uint32_t versionInfo) } // Windows 7 specific behaviors - else if(BuildNumber7 <= windowsBuildNumber && windowsBuildNumber < BuildNumber10) + else if(BuildNumberVista <= windowsBuildNumber && windowsBuildNumber < BuildNumber10) { ssiImageAlignment32 = 1; // SECTOR_SIZE when the image is loaded from network media maxSectionCount = PE_MAX_SECTION_COUNT_7; @@ -529,7 +529,7 @@ uint32_t PeLib::ImageLoader::getImageProtection(uint32_t sectionCharacteristics) size_t PeLib::ImageLoader::getSectionIndexByRva(uint32_t Rva) const { - std::size_t sectionIndex = 0; + size_t sectionIndex = 0; for(const auto & section : sections) { From 321d444837313604d38158bd19220e7b26b4de3e Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 15 Jul 2020 10:28:21 +0200 Subject: [PATCH 31/34] Fixing build --- include/retdec/pelib/ImageLoader.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 5fa01f546..fab7e072c 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -26,7 +26,8 @@ namespace PeLib { enum : std::uint32_t { BuildNumberXP = 2600, // Behavior equal to Windows XP - BuildNumber7 = 7601, // Behavior equal to Windows 7 + BuildNumberVista = 6000, // Behavior equal to Windows Vista (SP0 = 6000, SP1 = 6001, SP2 = 6002) + BuildNumber7 = 7600, // Behavior equal to Windows 7 (SP0 = 7600, SP1 = 7601) BuildNumber10 = 10240, // Behavior equal to Windows 10 BuildNumberMask = 0x0FFFF, // Mask for extracting the operating system BuildNumber64Bit = 0x10000, // Emulate 64-bit system From 25fefe2c706b6ac0164de452637472ae3d5a892f Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Wed, 15 Jul 2020 15:11:42 +0200 Subject: [PATCH 32/34] Final version ImageLoader also testes on Windows Vista and Windows 8/8.1 --- include/retdec/pelib/ImageLoader.h | 1 + src/pelib/ImageLoader.cpp | 49 +++++++++++++++--------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index fab7e072c..494e663fc 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -28,6 +28,7 @@ enum : std::uint32_t BuildNumberXP = 2600, // Behavior equal to Windows XP BuildNumberVista = 6000, // Behavior equal to Windows Vista (SP0 = 6000, SP1 = 6001, SP2 = 6002) BuildNumber7 = 7600, // Behavior equal to Windows 7 (SP0 = 7600, SP1 = 7601) + BuildNumber8 = 9200, // Behavior equal to Windows 8 BuildNumber10 = 10240, // Behavior equal to Windows 10 BuildNumberMask = 0x0FFFF, // Mask for extracting the operating system BuildNumber64Bit = 0x10000, // Emulate 64-bit system diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index 18cb49934..bab620abc 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -73,35 +73,30 @@ PeLib::ImageLoader::ImageLoader(uint32_t versionInfo) headerSizeCheck = false; loadArmImages = true; - // Windows XP specific behaviors - if(BuildNumberXP <= windowsBuildNumber && windowsBuildNumber < BuildNumberVista) + // If the caller specified a Windows build, then we configure version-specific behavior + if(windowsBuildNumber != 0) { - ssiImageAlignment32 = PELIB_SECTOR_SIZE; - maxSectionCount = PE_MAX_SECTION_COUNT_XP; - sizeofImageMustMatch = true; - headerSizeCheck = true; - loadArmImages = false; - } + // Single-section images are aligned to zector in Windows XP + // Note that Windows 8-10 do this somewhat randomly; the same image is mapped differently when in different folders + ssiImageAlignment32 = (BuildNumberXP <= windowsBuildNumber && windowsBuildNumber < BuildNumberVista) ? PELIB_SECTOR_SIZE : 1; - // Windows 7 specific behaviors - else if(BuildNumberVista <= windowsBuildNumber && windowsBuildNumber < BuildNumber10) - { - ssiImageAlignment32 = 1; // SECTOR_SIZE when the image is loaded from network media - maxSectionCount = PE_MAX_SECTION_COUNT_7; - ntHeadersSizeCheck = true; - sizeofImageMustMatch = true; - loadArmImages = false; - } + // Max section count is smaller in Windows XP + maxSectionCount = (BuildNumberXP <= windowsBuildNumber && windowsBuildNumber < BuildNumberVista) ? PE_MAX_SECTION_COUNT_XP : PE_MAX_SECTION_COUNT_7; - // Windows 10 specific behaviors - else if(BuildNumber10 <= windowsBuildNumber) - { + // Weird check in Windows XP: See checkForSectionTablesWithinHeader + headerSizeCheck = (BuildNumberXP <= windowsBuildNumber && windowsBuildNumber < BuildNumberVista); + + // Beginning with Windows Vista, the file size must be >= sizeof(IMAGE_NT_HEADERS) + ntHeadersSizeCheck = (BuildNumberVista <= windowsBuildNumber); + + // Beginning with Windows 8, ARM images can also be loader + loadArmImages = (windowsBuildNumber >= BuildNumber8); + + // Windows 10 perform check for bad app container apps + appContainerCheck = (windowsBuildNumber >= BuildNumber10); + + // After build 17134, SizeOfImage can also be greater than virtual end of the last section sizeofImageMustMatch = (windowsBuildNumber <= 17134); - ssiImageAlignment32 = 1; - maxSectionCount = PE_MAX_SECTION_COUNT_7; - ntHeadersSizeCheck = true; - appContainerCheck = true; - loadArmImages = true; } } @@ -1726,6 +1721,10 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) uint8_t * fileEnd = fileBegin + fileData.size(); bool bRawDataBeyondEOF = false; + // If there are no sections, then we're done + if(fileHeader.NumberOfSections == 0) + return ERROR_NONE; + // Check whether the sections are within the file filePtr = fileBegin + dosHeader.e_lfanew + sizeof(uint32_t) + sizeof(PELIB_IMAGE_FILE_HEADER) + fileHeader.SizeOfOptionalHeader; if(filePtr > fileEnd) From fcfcea1fe384840fb15755041bcf65242e35df8a Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Thu, 16 Jul 2020 09:30:22 +0200 Subject: [PATCH 33/34] Post-apocalypse fix after OpenSSL has been removed --- src/fileformat/file_format/pe/pe_format.cpp | 1 - src/fileformat/types/import_table/import_table.cpp | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index 3ea4b3f3a..2e115489b 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -30,7 +30,6 @@ #include "retdec/fileformat/utils/conversions.h" #include "retdec/fileformat/utils/crypto.h" #include "retdec/fileformat/utils/file_io.h" -#include "retdec/crypto/crypto.h" #include "retdec/pelib/ImageLoader.h" using namespace retdec::utils; diff --git a/src/fileformat/types/import_table/import_table.cpp b/src/fileformat/types/import_table/import_table.cpp index 9a88f04e5..c7edb0ced 100644 --- a/src/fileformat/types/import_table/import_table.cpp +++ b/src/fileformat/types/import_table/import_table.cpp @@ -822,9 +822,9 @@ void ImportTable::computeHashes() if (impHashBytes.size()) { - impHashCrc32 = retdec::crypto::getCrc32((const uint8_t *)impHashBytes.data(), impHashBytes.size()); - impHashMd5 = retdec::crypto::getMd5((const uint8_t *)impHashBytes.data(), impHashBytes.size()); - impHashSha256 = retdec::crypto::getSha256((const uint8_t *)impHashBytes.data(), impHashBytes.size()); + impHashCrc32 = getCrc32((const uint8_t *)impHashBytes.data(), impHashBytes.size()); + impHashMd5 = getMd5((const uint8_t *)impHashBytes.data(), impHashBytes.size()); + impHashSha256 = getSha256((const uint8_t *)impHashBytes.data(), impHashBytes.size()); } } From 1aca22f37edcaf179ba2416fff56870f0eb0e090 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 21 Jul 2020 13:33:54 +0200 Subject: [PATCH 34/34] Changes requested in review --- .../fileformat/file_format/pe/pe_format.h | 2 +- .../file_format/pe/pe_format_parser.h | 10 +- .../fileformat/file_format/pe/pe_template.h | 975 ------------------ include/retdec/pelib/BoundImportDirectory.h | 4 +- include/retdec/pelib/CoffSymbolTable.h | 4 +- include/retdec/pelib/ComHeaderDirectory.h | 4 +- include/retdec/pelib/DebugDirectory.h | 4 +- include/retdec/pelib/DelayImportDirectory.h | 4 +- include/retdec/pelib/ExportDirectory.h | 4 +- include/retdec/pelib/IatDirectory.h | 4 +- include/retdec/pelib/ImageLoader.h | 98 +- include/retdec/pelib/ImportDirectory.h | 4 +- include/retdec/pelib/InputBuffer.h | 4 +- include/retdec/pelib/OutputBuffer.h | 4 +- include/retdec/pelib/PeFile.h | 4 +- include/retdec/pelib/PeLib.h | 18 - include/retdec/pelib/PeLibAux.h | 35 +- include/retdec/pelib/PeLibInc.h | 4 +- include/retdec/pelib/RelocationsDirectory.h | 4 +- include/retdec/pelib/ResourceDirectory.h | 4 +- include/retdec/pelib/RichHeader.h | 4 +- include/retdec/pelib/SecurityDirectory.h | 4 +- include/retdec/pelib/TlsDirectory.h | 4 +- src/fileformat/file_format/file_format.cpp | 34 +- src/fileformat/utils/format_detection.cpp | 2 +- src/fileinfo/file_detector/pe_detector.cpp | 2 +- src/fileinfo/file_wrapper/pe_wrapper.cpp | 6 - src/fileinfo/file_wrapper/pe_wrapper.h | 1 - src/fileinfo/fileinfo.cpp | 2 +- src/pelib/DebugDirectory.cpp | 5 +- src/pelib/ImageLoader.cpp | 317 ++++-- src/pelib/PeLibAux.cpp | 2 - src/unpackertool/plugins/mpress/mpress.h | 2 +- .../plugins/upx/pe/pe_upx_stub.cpp | 18 +- src/unpackertool/plugins/upx/pe/pe_upx_stub.h | 2 +- src/unpackertool/plugins/upx/upx.cpp | 2 +- 36 files changed, 358 insertions(+), 1243 deletions(-) delete mode 100644 include/retdec/fileformat/file_format/pe/pe_template.h delete mode 100644 include/retdec/pelib/PeLib.h diff --git a/include/retdec/fileformat/file_format/pe/pe_format.h b/include/retdec/fileformat/file_format/pe/pe_format.h index 4c4bed7c2..57355c57d 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format.h +++ b/include/retdec/fileformat/file_format/pe/pe_format.h @@ -16,7 +16,7 @@ #include "retdec/fileformat/types/dotnet_headers/user_string_stream.h" #include "retdec/fileformat/types/dotnet_types/dotnet_class.h" #include "retdec/fileformat/types/visual_basic/visual_basic_info.h" -#include "retdec/pelib/PeLib.h" +#include "retdec/pelib/PeFile.h" // Forward declare OpenSSL structures used in this header. typedef struct pkcs7_st PKCS7; diff --git a/include/retdec/fileformat/file_format/pe/pe_format_parser.h b/include/retdec/fileformat/file_format/pe/pe_format_parser.h index fb721bfeb..ab5790022 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format_parser.h +++ b/include/retdec/fileformat/file_format/pe/pe_format_parser.h @@ -4,14 +4,14 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER_H -#define RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_FORMAT_PARSER_PE_FORMAT_PARSER_H +#ifndef RETDEC_FILEFORMAT_PE_FORMAT_PARSER_H +#define RETDEC_FILEFORMAT_PE_FORMAT_PARSER_H #include "retdec/common/range.h" #include "retdec/utils/alignment.h" #include "retdec/utils/string.h" #include "retdec/fileformat/fftypes.h" -#include "retdec/pelib/PeLib.h" +#include "retdec/pelib/PeFile.h" namespace retdec { namespace fileformat { @@ -22,8 +22,8 @@ class PeFormatParser { protected: - const FileFormat *inputFile; ///< pointer to input file - PeLib::PeFileT *peFile; ///< 32-bit PE file + const FileFormat *inputFile = nullptr; ///< pointer to input file + PeLib::PeFileT *peFile = nullptr; ///< 32-bit PE file public: diff --git a/include/retdec/fileformat/file_format/pe/pe_template.h b/include/retdec/fileformat/file_format/pe/pe_template.h deleted file mode 100644 index 6e6781983..000000000 --- a/include/retdec/fileformat/file_format/pe/pe_template.h +++ /dev/null @@ -1,975 +0,0 @@ -/** - * @file include/retdec/fileformat/file_format/pe/pe_template.h - * @brief Template functions for PE files. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_TEMPLATE_H -#define RETDEC_FILEFORMAT_FILE_FORMAT_PE_PE_TEMPLATE_H - -#include - -#include "retdec/utils/alignment.h" -#include "retdec/common/range.h" -#include "retdec/utils/string.h" -#include "retdec/fileformat/file_format/pe/pe_template_aux.h" -#include "retdec/fileformat/types/dotnet_headers/clr_header.h" -#include "retdec/fileformat/types/export_table/export.h" -#include "retdec/fileformat/types/import_table/import.h" -#include "retdec/fileformat/types/import_table/pe_import.h" -#include "retdec/fileformat/types/sec_seg/pe_coff_section.h" -#include "retdec/fileformat/types/sec_seg/section.h" - -#error Removed. Do not use. - -namespace retdec { -namespace fileformat { - -namespace -{ - -/** - * Get section type - * @param peHeader Parser of PE header - * @param secType Parameter for store the result - * @param sectionIndex Index of selected section (indexed from 0) - * @return @c true if index of section is valid, @c false otherwise - */ -template bool peSectionType(const PeLib::PeHeaderT &peHeader, PeCoffSection::Type &secType, unsigned long long sectionIndex) -{ - if(sectionIndex >= peHeader.getNumberOfSections()) - { - return false; - } - - std::string name; - const unsigned long long flags = peHeader.getCharacteristics(sectionIndex); - if(flags & PeLib::PELIB_IMAGE_SCN_CNT_CODE || flags & PeLib::PELIB_IMAGE_SCN_MEM_EXECUTE) - { - secType = PeCoffSection::Type::CODE; - } - else if(flags & PeLib::PELIB_IMAGE_SCN_CNT_UNINITIALIZED_DATA) - { - secType = PeCoffSection::Type::BSS; - } - else if(flags & PeLib::PELIB_IMAGE_SCN_MEM_DISCARDABLE && peSectionName(peHeader, name, sectionIndex) && retdec::utils::startsWith(name, ".debug_")) - { - secType = PeCoffSection::Type::DEBUG; - } - else if(flags & PeLib::PELIB_IMAGE_SCN_CNT_INITIALIZED_DATA) - { - secType = (!(flags & PeLib::PELIB_IMAGE_SCN_MEM_WRITE)) ? PeCoffSection::Type::CONST_DATA : PeCoffSection::Type::DATA; - } - else if(flags & PeLib::PELIB_IMAGE_SCN_LNK_INFO) - { - secType = PeCoffSection::Type::INFO; - } - else - { - secType = PeCoffSection::Type::UNDEFINED_SEC_SEG; - } - - return true; -} - -} // anonymous namespace - -/** - * Get number of sections declared in file header - * @param peHeader Parser of PE header - * @return Number of sections declared in file header - */ -template unsigned long long peDeclaredNumberOfSections(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getNumberOfSections(); -} - -/** - * Get number of sections actually present in the file - * @param peHeader Parser of PE header - * @return Stored number of sections - */ -template unsigned long long peStoredNumberOfSections(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.calcNumberOfSections(); -} - -/** - * Get IMAGE_BASE virtual address - * @param peHeader Parser of PE header - * @return Image base virtual address - */ -template unsigned long long peImageBase(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getImageBase(); -} - -/** - * Get offset of symbol table in file - * @param peHeader Parser of PE header - * @return Offset of symbol table - */ -template unsigned long long peCoffSymbolTableOffset(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getPointerToSymbolTable(); -} - -/** - * Get number of symbols in symbol table - * @param peHeader Parser of PE header - * @return Number of symbols in symbol table - */ -template unsigned long long peNumberOfCoffSymbols(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getNumberOfSymbols(); -} - -/** - * Get major version of used linker - * @param peHeader Parser of PE header - * @return Major version of used linker - */ -template unsigned long long peMajorLinkerVersion(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getMajorLinkerVersion(); -} - -/** - * Get minor version of used linker - * @param peHeader Parser of PE header - * @return Minor version of used linker - */ -template unsigned long long peMinorLinkerVersion(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getMinorLinkerVersion(); -} - -/** - * Get file flags - * @param peHeader Parser of PE header - * @return File flags as one number - */ -template unsigned long long peFileFlags(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getCharacteristics(); -} - -/** - * Get time stamp - * @param peHeader Parser of PE header - * @return Time stamp of PE file - */ -template unsigned long long peTimeStamp(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getTimeDateStamp(); -} - -/** - * Get size of optional header - * @param peHeader Parser of PE header - * @return Size of optional header - */ -template unsigned long long peSizeOfOptionalHeader(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getSizeOfOptionalHeader(); -} - -/** - * Find out if optional header SizeOfHeaders is rounded up to multiple of FileAlignment - * @param peHeader Parser of PE header - * @return @c true if SizeOfHeaders is rounded up to multiple of FileAlignment, @c false otherwise - */ -template unsigned long long peIsSizeOfHeaderMultipleOfFileAlignment( - const PeLib::PeHeaderT &peHeader) -{ - std::uint64_t remainder; - return retdec::utils::isAligned(peHeader.getSizeOfHeaders(), peHeader.getFileAlignment(), remainder); -} - -/** - * Get file alignment - * @param peHeader Parser of PE header - * @return File alignment - */ -template unsigned long long peFileAlignment(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getFileAlignment(); -} - -/** - * Get section alignment - * @param peHeader Parser of PE header - * @return Section alignment - */ -template unsigned long long peSectionAlignment(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getSectionAlignment(); -} - -/** - * Get size of image headers - * @param peHeader Parser of PE header - * @return Size of headers - */ -template unsigned long long peSizeOfHeaders(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getSizeOfHeaders(); -} - -/** - * Get size of image - * @param peHeader Parser of PE header - * @return Size of image - */ -template unsigned long long peSizeOfImage(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getSizeOfImage(); -} - -/** - * Get file checksum - * @param peHeader Parser of PE header - * @return File checksum - */ -template unsigned long long peChecksum(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getCheckSum(); -} - -/** - * Get size of the stack to reserve - * @param peHeader Parser of PE header - * @return Size of the stack to reserve - */ -template unsigned long long peSizeOfStackReserve(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getSizeOfStackReserve(); -} - -/** - * Get size of the stack to commit - * @param peHeader Parser of PE header - * @return Size of the stack to commit - */ -template unsigned long long peSizeOfStackCommit(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getSizeOfStackCommit(); -} - -/** - * Get size of the local heap space to reserve - * @param peHeader Parser of PE header - * @return Size of the local heap space to reserve - */ -template unsigned long long peSizeOfHeapReserve(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getSizeOfHeapReserve(); -} - -/** - * Get size of the local heap space to commit - * @param peHeader Parser of PE header - * @return Size of the local heap space to commit - */ -template unsigned long long peSizeOfHeapCommit(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getSizeOfHeapCommit(); -} - -/** - * Get size of the PE signature - * @param peHeader Parser of PE header - * @return Size of the PE signature - */ -template unsigned long long peSizeOfPeSignature(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getNtHeaders().sizeOfSignature(); -} - -/** - * Get real loaded size of the NT headers - * @param peHeader Parser of PE header - * @return Real loaded size of the NT headers - */ -template unsigned long long peLoadedSizeOfNtHeaders(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getNtHeaders().loadedSize(); -} - -/** - * Get allocated size of the NT headers - * @param peHeader Parser of PE header - * @return Allocated size of the NT headers - */ -template unsigned long long peAllocatedSizeOfNtHeaders(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getNtHeaders().size(); -} - -/** - * Get declared number of data directories - * @param peHeader Parser of PE header - * @return Declared number of data directories - */ -template unsigned long long peNumberOfDeclaredDataDirectories(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getNumberOfRvaAndSizes(); -} - -/** - * Get number of stored data directories - * @param peHeader Parser of PE header - * @return Number of stored data directories - */ -template unsigned long long peNumberOfStoredDataDirectories(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.calcNumberOfRvaAndSizes(); -} - -/** - * Get number of imported libraries - * @param peImports Parser of PE import directory - * @return Number of imported libraries - */ -inline unsigned long long peNumberOfImportedLibraries(const PeLib::ImportDirectory &peImports) -{ - return peImports.getNumberOfFiles(PeLib::OLDDIR); -} - -/** - * Get number of delay imported libraries - * @param delay Parser of PE delay import directory - * @return Number of delay imported libraries - */ -inline unsigned long long peNumberOfDelayImportedLibraries(const PeLib::DelayImportDirectory &delay) -{ - return delay.getNumberOfFiles(); -} - -/** - * Find out if is DLL - * @param peHeader Parser of PE header - * @return @c true if is DLL, @c false otherwise - */ -template bool peIsDll(const PeLib::PeHeaderT &peHeader) -{ - return (peHeader.getCharacteristics() & PeLib::PELIB_IMAGE_FILE_DLL); -} - -/** - * Get virtual address of entry point - * @param peHeader Parser of PE header - * @return Virtual address of entry point - */ -template unsigned long long peEpAddress(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getAddressOfEntryPoint(); -} - -/** - * Get EP offset in PE binary file - * @param peHeader Parser of PE header - * @return Offset of entry point - */ -template unsigned long long peEpOffset(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.rvaToOffset(peHeader.getAddressOfEntryPoint()); -} - -/** - * Get information about section with index @a sectionIndex - * @param inputFile Pointer to input file - * @param peHeader Parser of PE header - * @param section Structure for save information about section - * @param sectionIndex Index of section (indexed from 0) - * @return @c true if section index is valid and section is detected, @c false otherwise - */ -inline bool peSectionWithIndex(const FileFormat *inputFile, const PeLib::PeHeaderT &peHeader, PeCoffSection §ion, unsigned long long sectionIndex) -{ - std::string sectionName; - PeCoffSection::Type sectionType; - if(!peSectionName(peHeader, sectionName, sectionIndex) || !peSectionType(peHeader, sectionType, sectionIndex)) - { - return false; - } - - section.setName(sectionName); - section.setType(sectionType); - section.setIndex(sectionIndex); - section.setOffset(peHeader.getPointerToRawData(sectionIndex)); - section.setSizeInFile(peHeader.getSizeOfRawData(sectionIndex)); - section.setSizeInMemory(peHeader.getVirtualSize(sectionIndex)); - section.setAddress(peHeader.getVirtualAddress(sectionIndex) ? peHeader.getVirtualAddress(sectionIndex) + peHeader.getImageBase() : 0); - section.setMemory(section.getAddress()); - section.setPeCoffFlags(peHeader.getCharacteristics(sectionIndex)); - section.load(inputFile); - return true; -} - -/** - * Get DLL flags - * @param peHeader Parser of PE header - * @param dllFlags Into this parameter DLL flags will be stored - * @return @c true if file is DLL and flags are successfully detected, @c false otherwise - * - * If file is not DLL, @a dllFlags is left unchanged - */ -template bool peDllFlags(const PeLib::PeHeaderT &peHeader, unsigned long long &dllFlags) -{ - if(peHeader.getCharacteristics() & PeLib::PELIB_IMAGE_FILE_DLL) - { - dllFlags = peHeader.getDllCharacteristics(); - return true; - } - - return false; -} - -/** - * Get information about data directory - * @param imageLoader Reference to a valid PE image loader - * @param relAddr Into this parameter is stored relative virtual address of directory - * @param size Into this parameter is stored size of directory - * @param index Index of selected directory - * @return @c true if index of selected directory is valid, @c false otherwise - * - * If method returns @c false, @a relAddr and @a size are left unchanged. - */ -inline bool peDataDirectoryRelative(const ImageLoader & imageLoader, unsigned long long &relAddr, unsigned long long &size, unsigned long long index) -{ - if(index >= imageLoader.getOptionalHeader().NumberOfRvaAndSizes) - { - return false; - } - - relAddr = peHeader.getImageDataDirectoryRva(index); - size = peHeader.getImageDataDirectorySize(index); - return true; -} - -/** - * Get information about data directory - * @param imageLoader Reference to a valid PE image loader - * @param absAddr Into this parameter is stored absolute virtual address of directory - * @param size Into this parameter is stored size of directory - * @param index Index of selected directory - * @return @c true if index of selected directory is valid, @c false otherwise - * - * If directory start address is non-zero, start address of directory will be - * set to "image base + relative virtual address". Otherwise, address will be - * set to zero. - * - * If function returns @c false, @a absAddr and @a size are left unchanged. - */ -template bool peDataDirectoryAbsolute(const ImageLoader & imageLoader, unsigned long long &absAddr, unsigned long long &size, unsigned long long index) -{ - absAddr = imageLoader.getDataDirRva(index); - if(absAddr) - { - absAddr += peHeader.getImageBase(); - } - size = peHeader.getImageDataDirectorySize(index); - return true; -} - -/** - * Get name of imported library - * @param peImports Parser of PE import directory - * @param fileName Into this parameter is stored name of imported library - * @param index Index of selected library (indexed from 0) - * @return @c true if index of selected library is valid, @c false otherwise - * - * If function returns @c false, @a fileName is left unchanged. - */ -inline bool peImportedLibraryFileName( - const PeLib::ImportDirectory &peImports, - std::string &fileName, - unsigned long long index) -{ - if(index >= peNumberOfImportedLibraries(peImports)) - { - return false; - } - - fileName = peImports.getFileName(index, PeLib::OLDDIR); - return true; -} - -/** - * Get name of delay imported library - * @param delay Parser of PE delay import directory - * @param fileName Into this parameter is stored name of delay imported library - * @param index Index of selected library (indexed from 0) - * @return @c true if index of selected library is valid, @c false otherwise - * - * If function returns @c false, @a fileName is left unchanged. - */ -inline bool peDelayImportedLibraryFileName(const PeLib::DelayImportDirectory &delay, std::string &fileName, unsigned long long index) -{ - const auto *library = delay.getFile(index); - if(!library) - { - return false; - } - - fileName = library->Name; - - return true; -} - -/** - * Get information about import - * @param peHeader Parser of PE header - * @param peImports Parser of PE import directory - * @param fileIndex Index of selected library (indexed from 0) - * @param importIndex Index of selected import (indexed from 0) - * @return @c true if index of library and index of import are valid, @c false otherwise - * - * If function returns info about import, or @c nullptr if invalid import is requested. - */ -template std::unique_ptr peImport(const PeLib::PeHeaderT &peHeader, - const PeLib::ImportDirectory &peImports, - unsigned long long fileIndex, unsigned long long importIndex) -{ - if(fileIndex >= peNumberOfImportedLibraries(peImports) || - importIndex >= peImports.getNumberOfFunctions(fileIndex, PeLib::OLDDIR)) - { - return nullptr; - } - - auto isOrdinalNumberValid = true; - unsigned long long ordinalNumber = peImports.getFunctionHint(fileIndex, importIndex, PeLib::OLDDIR); - if(!ordinalNumber) - { - const auto firstThunk = peImports.getFirstThunk(fileIndex, importIndex, PeLib::OLDDIR); - const auto originalFirstThunk = peImports.getOriginalFirstThunk(fileIndex, importIndex, PeLib::OLDDIR); - if(firstThunk & PeLib::PELIB_IMAGE_ORDINAL_FLAGS::PELIB_IMAGE_ORDINAL_FLAG) - { - ordinalNumber = firstThunk - PeLib::PELIB_IMAGE_ORDINAL_FLAGS::PELIB_IMAGE_ORDINAL_FLAG; - } - else if(originalFirstThunk & PeLib::PELIB_IMAGE_ORDINAL_FLAGS::PELIB_IMAGE_ORDINAL_FLAG) - { - ordinalNumber = originalFirstThunk - PeLib::PELIB_IMAGE_ORDINAL_FLAGS::PELIB_IMAGE_ORDINAL_FLAG; - } - else - { - isOrdinalNumberValid = false; - } - } - - auto import = std::make_unique(PeImportFlag::None); - if(isOrdinalNumberValid) - { - import->setOrdinalNumber(ordinalNumber); - } - else - { - import->invalidateOrdinalNumber(); - } - import->setName(peImports.getFunctionName(fileIndex, importIndex, PeLib::OLDDIR)); - import->setAddress(peImageBase(peHeader) + peImports.getFirstThunk(fileIndex, PeLib::OLDDIR) + importIndex * (bits / 8)); - import->setLibraryIndex(fileIndex); - return import; -} - -/** - * Get information about delay import - * @param peHeader Parser of PE header - * @param delay Parser of PE delay import directory - * @param fileIndex Index of selected library (indexed from 0) - * @param importIndex Index of selected delay import (indexed from 0) - * @return @c true if index of library and index of delay import are valid, @c false otherwise - * - * If function returns info about delayed import, or @c nullptr if invalid import is requested. - */ -template std::unique_ptr peDelayImport(const PeLib::PeHeaderT &peHeader, - const PeLib::DelayImportDirectory &delay, - unsigned long long fileIndex, unsigned long long importIndex) -{ - const auto *library = delay.getFile(fileIndex); - if(!library) - { - return nullptr; - } - - const auto *function = library->getFunction(importIndex); - if(!function) - { - return nullptr; - } - - auto import = std::make_unique(PeImportFlag::Delayed); - import->setName(function->fname); - import->setAddress(peImageBase(peHeader) + function->address); - import->setLibraryIndex(fileIndex); - import->invalidateOrdinalNumber(); - if(library->ordinalNumbersAreValid() && function->hint != 0) - { - import->setOrdinalNumber(function->hint); - } - - return import; -} - -/** - * Get number of exported functions - * @param exports Parser of PE export directory - * @return Number of exported functions - */ -inline unsigned long long peNumberOfExportedFunctions(const PeLib::ExportDirectory &exports) -{ - return exports.calcNumberOfFunctions(); -} - -/** - * Get information about the exported function - * @param peHeader Parser of PE header - * @param exports Parser of PE export directory - * @param index Index of the exported function - * @param exportedFunction Exported function to fill - * @return @c false if index is out of bounds, otherwise @c true - */ -template bool peExportedFunction(const PeLib::PeHeaderT &peHeader, const PeLib::ExportDirectory &exports, unsigned long long index, Export& exportedFunction) -{ - if (index >= peNumberOfExportedFunctions(exports)) - { - return false; - } - - exportedFunction.setAddress(exports.getAddressOfFunction(index) + peImageBase(peHeader)); - exportedFunction.setOrdinalNumber(exports.getFunctionOrdinal(index)); - exportedFunction.setName(exports.getFunctionName(index)); - return true; -} - -/** - * Get number of debug entries - * @param debug Parser of PE debug directory - * @return Number of debug entries - */ -inline unsigned long long peNumberOfDebugEntries(const PeLib::DebugDirectory &debug) -{ - return debug.calcNumberOfEntries(); -} - -/** - * Get debug entry data - * @param debug Parser of PE debug directory - * @param index Index of debug entry - * @param data Data to fill - * @return @c false if index is out of bounds, otherwise @c true - */ -inline bool peDebugEntryData(const PeLib::DebugDirectory &debug, unsigned long long index, std::vector& data) -{ - if (index >= peNumberOfDebugEntries(debug)) - { - return false; - } - - data = debug.getData(index); - return true; -} - -/** - * Get debug entry timestamp - * @param debug Parser of PE debug directory - * @param index Index of debug entry - * @param timeDateStamp Timestamp to fill - * @return @c false if index is out of bounds, otherwise @c true - */ -inline bool peDebugEntryTimeDateStamp(const PeLib::DebugDirectory &debug, unsigned long long index, unsigned long long& timeDateStamp) -{ - if (index >= peNumberOfDebugEntries(debug)) - { - return false; - } - - timeDateStamp = debug.getTimeDateStamp(index); - return true; -} - -/** - * Get debug entry pointer to raw data - * @param debug Parser of PE debug directory - * @param index Index of debug entry - * @param pointerToRawData Pointer to raw data to fill - * @return @c false if index is out of bounds, otherwise @c true - */ -inline bool peDebugEntryPointerToRawData(const PeLib::DebugDirectory &debug, unsigned long long index, unsigned long long& pointerToRawData) -{ - if (index >= peNumberOfDebugEntries(debug)) - { - return false; - } - - pointerToRawData = debug.getPointerToRawData(index); - return true; -} - -/** - * Get resource directory file offset - * @param resources Parser of PE resource directory - * @return Directory file offset - */ -inline unsigned long long peResourceDirectoryOffset(const PeLib::ResourceDirectory &resources) -{ - return resources.getOffset(); -} - -/** - * Get resource directory tree root node - * @param resources Parser of PE resource directory - * @return Directory tree root node - */ -inline const PeLib::ResourceNode* peResourceTreeRoot(const PeLib::ResourceDirectory &resources) -{ - return resources.getRoot(); -} - -/** - * Get TLS directory startAddressOfRawData - * @param tls Parser of TLS directory - * @return StartAddressOfRawData of TLS directory - */ -inline unsigned long long peTlsStartAddressOfRawData(const PeLib::TlsDirectory &tls) -{ - return tls.getStartAddressOfRawData(); -} - -/** - * Get TLS directory endAddressOfRawData - * @param tls Parser of TLS directory - * @return EndAddressOfRawData of TLS directory - */ -inline unsigned long long peTlsEndAddressOfRawData(const PeLib::TlsDirectory &tls) -{ - return tls.getEndAddressOfRawData(); -} - -/** - * Get TLS directory addressOfIndex - * @param tls Parser of TLS directory - * @return AddressOfIndex of TLS directory - */ -inline unsigned long long peTlsAddressOfIndex(const PeLib::TlsDirectory &tls) -{ - return tls.getAddressOfIndex(); -} - -/** - * Get TLS directory addressOfCallBacks - * @param tls Parser of TLS directory - * @return AddressOfCallBacks of TLS directory - */ -inline unsigned long long peTlsAddressOfCallBacks(const PeLib::TlsDirectory &tls) -{ - return tls.getAddressOfCallBacks(); -} - -/** - * Get TLS directory sizeOfZeroFill - * @param tls Parser of TLS directory - * @return SizeOfZeroFill of TLS directory - */ -inline unsigned long long peTlsSizeOfZeroFill(const PeLib::TlsDirectory &tls) -{ - return tls.getSizeOfZeroFill(); -} - -/** - * Get TLS directory characteristics - * @param tls Parser of TLS directory - * @return Characteristics of TLS directory - */ -inline unsigned long long peTlsCharacteristics(const PeLib::TlsDirectory &tls) -{ - return tls.getCharacteristics(); -} - -/** - * Get CLR header - * @param comHeader Parser of PE COM/CLR directory - * @return Parsed CLR header - */ -inline std::unique_ptr peGetClrHeader(const PeLib::ComHeaderDirectory &comHeader) -{ - auto clrHeader = std::make_unique(); - clrHeader->setHeaderSize(comHeader.getSizeOfHeader()); - clrHeader->setMajorRuntimeVersion(comHeader.getMajorRuntimeVersion()); - clrHeader->setMinorRuntimeVersion(comHeader.getMinorRuntimeVersion()); - clrHeader->setMetadataDirectoryAddress(comHeader.getMetaDataVa()); - clrHeader->setMetadataDirectorySize(comHeader.getMetaDataSize()); - clrHeader->setFlags(comHeader.getFlags()); - clrHeader->setEntryPointToken(comHeader.getEntryPointToken()); - clrHeader->setResourcesAddress(comHeader.getResourcesVa()); - clrHeader->setResourcesSize(comHeader.getResourcesSize()); - clrHeader->setStrongNameSignatureAddress(comHeader.getStrongNameSignatureVa()); - clrHeader->setStrongNameSignatureSize(comHeader.getStrongNameSignatureSize()); - clrHeader->setCodeManagerTableAddress(comHeader.getCodeManagerTableVa()); - clrHeader->setCodeManagerTableSize(comHeader.getCodeManagerTableSize()); - clrHeader->setVTableFixupsDirectoryAddress(comHeader.getVTableFixupsVa()); - clrHeader->setVTableFixupsDirectorySize(comHeader.getVTableFixupsSize()); - clrHeader->setExportAddressTableAddress(comHeader.getExportAddressTableJumpsVa()); - clrHeader->setExportAddressTableSize(comHeader.getExportAddressTableJumpsSize()); - clrHeader->setPrecompileHeaderAddress(comHeader.getManagedNativeHeaderVa()); - clrHeader->setPrecompileHeaderSize(comHeader.getManagedNativeHeaderSize()); - return clrHeader; -} - -/** - * Get number of relocations - * @param relocs Parser of PE relocation directory - * @return Number of relocations - */ -inline unsigned long long peNumberOfRelocations(const PeLib::RelocationsDirectory &relocs) -{ - return relocs.calcNumberOfRelocations(); -} - -/** - * Get number of relocation data - * @param relocs Parser of PE relocation directory - * @param index Relocation data index - * @return Number of relocation data - */ -inline unsigned long long peNumberOfRelocationData(const PeLib::RelocationsDirectory &relocs, unsigned long long index) -{ - return relocs.calcNumberOfRelocationData(index); -} - -/** - * Get file offset of checksum field in PE header - * @param peHeader Parser of PE header - * @return File offset of checksum - */ -template unsigned long long peChecksumFileOffset(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getChecksumFileOffset(); -} - -/** - * Get file offset of security data directory in PE header - * @param peHeader Parser of PE header - * @return File offset of security data directory - */ -template unsigned long long peSecurityDirFileOffset(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getSecDirFileOffset(); -} - -/** - * Get RVA of security directory - * @param peHeader Parser of PE header - * @return RVA of security directory - */ -template unsigned long long peSecurityDirRva(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getIddSecurityRva(); -} - -/** - * Get size of security directory - * @param peHeader Parser of PE header - * @return Size of security directory - */ -template unsigned long long peSecurityDirSize(const PeLib::PeHeaderT &peHeader) -{ - return peHeader.getIddSecuritySize(); -} - -/** - * Get occupied addresses by import directory - * @param peImports Parser of PE import directory - * @return Occupied address ranges - */ -inline retdec::common::RangeContainer peImportDirectoryOccupiedAddresses(const PeLib::ImportDirectory &peImports) -{ - retdec::common::RangeContainer result; - for (const auto& addresses : peImports.getOccupiedAddresses()) - { - try - { - result.insert(addresses.first, addresses.second); - } - catch (const retdec::common::InvalidRangeException&) - { - continue; - } - } - - return result; -} - -/** - * Get occupied addresses by export directory - * @param peExports Parser of PE export directory - * @return Occupied address ranges - */ -inline retdec::common::RangeContainer peExportDirectoryOccupiedAddresses(const PeLib::ExportDirectory &peExports) -{ - retdec::common::RangeContainer result; - for (const auto& addresses : peExports.getOccupiedAddresses()) - { - try - { - result.insert(addresses.first, addresses.second); - } - catch (const retdec::common::InvalidRangeException&) - { - continue; - } - } - - return result; -} - -/** - * Get occupied addresses by debug directory - * @param peDebug Parser of PE debug directory - * @return Occupied address ranges - */ -inline retdec::common::RangeContainer peDebugDirectoryOccupiedAddresses(const PeLib::DebugDirectory &peDebug) -{ - retdec::common::RangeContainer result; - for (const auto& addresses : peDebug.getOccupiedAddresses()) - { - try - { - result.insert(addresses.first, addresses.second); - } - catch (const retdec::common::InvalidRangeException&) - { - continue; - } - } - - return result; -} - -/** - * Get occupied addresses by resource directory - * @param peResources Parser of PE resource directory - * @return Occupied address ranges - */ -inline retdec::common::RangeContainer peResourceDirectoryOccupiedAddresses(const PeLib::ResourceDirectory &peResources) -{ - retdec::common::RangeContainer result; - for (const auto& addresses : peResources.getOccupiedAddresses()) - { - try - { - result.insert(addresses.first, addresses.second); - } - catch (const retdec::common::InvalidRangeException&) - { - continue; - } - } - - return result; -} - -} // namespace fileformat -} // namespace retdec - -#endif diff --git a/include/retdec/pelib/BoundImportDirectory.h b/include/retdec/pelib/BoundImportDirectory.h index e142f462b..500b920d0 100644 --- a/include/retdec/pelib/BoundImportDirectory.h +++ b/include/retdec/pelib/BoundImportDirectory.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef BOUNDIMPORTDIRECTORY_H -#define BOUNDIMPORTDIRECTORY_H +#ifndef RETDEC_PELIB_BOUNDIMPORTDIRECTORY_H +#define RETDEC_PELIB_BOUNDIMPORTDIRECTORY_H #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/PeLibAux.h" diff --git a/include/retdec/pelib/CoffSymbolTable.h b/include/retdec/pelib/CoffSymbolTable.h index dcc882bcb..c9e2aa16f 100644 --- a/include/retdec/pelib/CoffSymbolTable.h +++ b/include/retdec/pelib/CoffSymbolTable.h @@ -4,8 +4,8 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef COFFSYMBOLTABLE_H -#define COFFSYMBOLTABLE_H +#ifndef RETDEC_PELIB_COFFSYMBOLTABLE_H +#define RETDEC_PELIB_COFFSYMBOLTABLE_H #include "retdec/pelib/PeLibInc.h" diff --git a/include/retdec/pelib/ComHeaderDirectory.h b/include/retdec/pelib/ComHeaderDirectory.h index 76ad1b8dc..bdba6ca2c 100644 --- a/include/retdec/pelib/ComHeaderDirectory.h +++ b/include/retdec/pelib/ComHeaderDirectory.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef COMHEADERDIRECTORY_H -#define COMHEADERDIRECTORY_H +#ifndef RETDEC_PELIB_COMHEADERDIRECTORY_H +#define RETDEC_PELIB_COMHEADERDIRECTORY_H #include "retdec/pelib/ImageLoader.h" diff --git a/include/retdec/pelib/DebugDirectory.h b/include/retdec/pelib/DebugDirectory.h index e57706b30..92ebe43ef 100644 --- a/include/retdec/pelib/DebugDirectory.h +++ b/include/retdec/pelib/DebugDirectory.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef DEBUGDIRECTORY_H -#define DEBUGDIRECTORY_H +#ifndef RETDEC_PELIB_DEBUGDIRECTORY_H +#define RETDEC_PELIB_DEBUGDIRECTORY_H #include "retdec/pelib/ImageLoader.h" diff --git a/include/retdec/pelib/DelayImportDirectory.h b/include/retdec/pelib/DelayImportDirectory.h index 7d2c5565a..dc39e2bb3 100644 --- a/include/retdec/pelib/DelayImportDirectory.h +++ b/include/retdec/pelib/DelayImportDirectory.h @@ -4,8 +4,8 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef DELAY_IMPORT_DIRECTORY_H -#define DELAY_IMPORT_DIRECTORY_H +#ifndef RETDEC_PELIB_DELAY_IMPORT_DIRECTORY_H +#define RETDEC_PELIB_DELAY_IMPORT_DIRECTORY_H #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/ImageLoader.h" diff --git a/include/retdec/pelib/ExportDirectory.h b/include/retdec/pelib/ExportDirectory.h index 89dee5792..158967f55 100644 --- a/include/retdec/pelib/ExportDirectory.h +++ b/include/retdec/pelib/ExportDirectory.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef EXPORTDIRECTORY_H -#define EXPORTDIRECTORY_H +#ifndef RETDEC_PELIB_EXPORTDIRECTORY_H +#define RETDEC_PELIB_EXPORTDIRECTORY_H #include "retdec/pelib/ImageLoader.h" diff --git a/include/retdec/pelib/IatDirectory.h b/include/retdec/pelib/IatDirectory.h index 9edf35dbf..1c7d3fd53 100644 --- a/include/retdec/pelib/IatDirectory.h +++ b/include/retdec/pelib/IatDirectory.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef IATDIRECTORY_H -#define IATDIRECTORY_H +#ifndef RETDEC_PELIB_IATDIRECTORY_H +#define RETDEC_PELIB_IATDIRECTORY_H #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/ImageLoader.h" diff --git a/include/retdec/pelib/ImageLoader.h b/include/retdec/pelib/ImageLoader.h index 494e663fc..62831d9e9 100644 --- a/include/retdec/pelib/ImageLoader.h +++ b/include/retdec/pelib/ImageLoader.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef IMAGE_LOADER_H -#define IMAGE_LOADER_H +#ifndef RETDEC_PELIB_IMAGE_LOADER_H +#define RETDEC_PELIB_IMAGE_LOADER_H #include #include @@ -20,24 +20,10 @@ namespace PeLib { -//----------------------------------------------------------------------------- -// Enum for Windows build numbers - -enum : std::uint32_t -{ - BuildNumberXP = 2600, // Behavior equal to Windows XP - BuildNumberVista = 6000, // Behavior equal to Windows Vista (SP0 = 6000, SP1 = 6001, SP2 = 6002) - BuildNumber7 = 7600, // Behavior equal to Windows 7 (SP0 = 7600, SP1 = 7601) - BuildNumber8 = 9200, // Behavior equal to Windows 8 - BuildNumber10 = 10240, // Behavior equal to Windows 10 - BuildNumberMask = 0x0FFFF, // Mask for extracting the operating system - BuildNumber64Bit = 0x10000, // Emulate 64-bit system -}; - //----------------------------------------------------------------------------- // Enum for ImageLoader::getFieldOffset() -enum PELIB_MEMBER_TYPE : std::uint32_t +enum struct PELIB_MEMBER_TYPE : std::uint32_t { OPTHDR_sizeof, OPTHDR_sizeof_fixed, @@ -52,28 +38,43 @@ enum PELIB_MEMBER_TYPE : std::uint32_t //----------------------------------------------------------------------------- // Support structure for one PE image compare result -enum PELIB_COMPARE_RESULT : std::uint32_t +enum struct PELIB_COMPARE_RESULT : std::uint32_t { - ImagesEqual, // The images are equal - ImagesWindowsLoadedWeDidnt, // - ImagesWindowsDidntLoadWeDid, // - ImagesDifferentSize, // The images have different size - ImagesDifferentPageAccess, // An image page is different (accessible vs non-accessible) - ImagesDifferentPageValue, // There is a different value at a certain offset + ImagesEqual, // The images are equal + ImagesWindowsLoadedWeDidnt, // + ImagesWindowsDidntLoadWeDid, // + ImagesDifferentSize, // The images have different size + ImagesDifferentPageAccess, // An image page is different (accessible vs non-accessible) + ImagesDifferentPageValue, // There is a different value at a certain offset + ImagesCompareInvalid, }; +//----------------------------------------------------------------------------- +// Windows build numbers + +const std::uint32_t BuildNumberXP = 2600; // Behavior equal to Windows XP +const std::uint32_t BuildNumberVista = 6000; // Behavior equal to Windows Vista (SP0 = 6000, SP1 = 6001, SP2 = 6002) +const std::uint32_t BuildNumber7 = 7600; // Behavior equal to Windows 7 (SP0 = 7600, SP1 = 7601) +const std::uint32_t BuildNumber8 = 9200; // Behavior equal to Windows 8 +const std::uint32_t BuildNumber10 = 10240; // Behavior equal to Windows 10 +const std::uint32_t BuildNumberMask = 0x0FFFF; // Mask for extracting the operating system +const std::uint32_t BuildNumber64Bit = 0x10000; // Emulate 64-bit system + +//----------------------------------------------------------------------------- +// Structure for comparison with Windows mapped images + typedef bool (*PFN_VERIFY_ADDRESS)(void * ptr, size_t length); typedef bool (*PFN_COMPARE_CALLBACK)(struct PELIB_IMAGE_COMPARE * pImgCompare, size_t BytesCompared, size_t BytesTotal); struct PELIB_IMAGE_COMPARE { - PFN_VERIFY_ADDRESS PfnVerifyAddress; // Custom function for verifying memory address - PFN_COMPARE_CALLBACK PfnCompareCallback; // Custom function for calling compare callback - PELIB_COMPARE_RESULT compareResult; - const char * szFileName; // Current file being compared (plain name) - const char * dumpIfNotEqual; // If non-NULL, the image will be dumped into that file if different - std::uint32_t differenceOffset; // If compareResult is ImagesDifferentPageValue, this contains offset of the difference - std::uint32_t startTickCount; // GetTickCount value at the start of image testing + PFN_VERIFY_ADDRESS PfnVerifyAddress = nullptr; // Custom function for verifying memory address + PFN_COMPARE_CALLBACK PfnCompareCallback = nullptr; // Custom function for calling compare callback + PELIB_COMPARE_RESULT compareResult = PELIB_COMPARE_RESULT::ImagesCompareInvalid; + const char * szFileName = nullptr; // Current file being compared (plain name) + const char * dumpIfNotEqual = nullptr; // If non-NULL, the image will be dumped into that file if different + std::uint32_t differenceOffset = 0; // If compareResult is ImagesDifferentPageValue, this contains offset of the difference + std::uint32_t startTickCount = 0; // GetTickCount value at the start of image testing }; //----------------------------------------------------------------------------- @@ -87,9 +88,6 @@ struct PELIB_FILE_PAGE isZeroPage = false; } - ~PELIB_FILE_PAGE() - {} - // Initializes the page with a valid data bool setValidPage(const void * data, size_t length) { @@ -127,7 +125,7 @@ struct PELIB_FILE_PAGE } } - std::vector buffer; // A page-sized buffer, holding one image page. Empty if isInvalidPage + ByteBuffer buffer; // A page-sized buffer, holding one image page. Empty if isInvalidPage bool isInvalidPage; // For invalid pages within image (SectionAlignment > 0x1000) bool isZeroPage; // For sections with VirtualSize != 0, RawSize = 0 }; @@ -140,9 +138,8 @@ class ImageLoader public: ImageLoader(std::uint32_t loaderFlags = 0); - ~ImageLoader(); - int Load(std::vector & fileData, bool loadHeadersOnly = false); + int Load(ByteBuffer & fileData, bool loadHeadersOnly = false); int Load(std::istream & fs, std::streamoff fileOffset = 0, bool loadHeadersOnly = false); int Load(const char * fileName, bool loadHeadersOnly = false); @@ -156,7 +153,12 @@ class ImageLoader std::uint32_t readString(std::string & str, std::uint32_t rva, std::uint32_t maxLength = 65535); std::uint32_t readStringRc(std::string & str, std::uint32_t rva); - std::uint32_t readStringRaw(std::vector & fileData, std::string & str, std::size_t offset, std::size_t maxLength = 65535, bool mustBePrintable = false, bool mustNotBeTooLong = false); + std::uint32_t readStringRaw(ByteBuffer & fileData, + std::string & str, + std::size_t offset, + std::size_t maxLength = 65535, + bool mustBePrintable = false, + bool mustNotBeTooLong = false); std::uint32_t stringLength(std::uint32_t rva, std::uint32_t maxLength = 65535) const; std::uint32_t readPointer(std::uint32_t rva, std::uint64_t & pointerValue); @@ -364,23 +366,23 @@ class ImageLoader bool processImageRelocations(std::uint64_t oldImageBase, std::uint64_t getImageBase, std::uint32_t VirtualAddress, std::uint32_t Size); void writeNewImageBase(std::uint64_t newImageBase); - int captureDosHeader(std::vector & fileData); + int captureDosHeader(ByteBuffer & fileData); int saveDosHeader(std::ostream & fs, std::streamoff fileOffset); - int captureNtHeaders(std::vector & fileData); + int captureNtHeaders(ByteBuffer & fileData); int saveNtHeaders(std::ostream & fs, std::streamoff fileOffset); - int captureSectionName(std::vector & fileData, std::string & sectionName, const std::uint8_t * name); - int captureSectionHeaders(std::vector & fileData); + int captureSectionName(ByteBuffer & fileData, std::string & sectionName, const std::uint8_t * name); + int captureSectionHeaders(ByteBuffer & fileData); int saveSectionHeaders(std::ostream & fs, std::streamoff fileOffset); - int captureImageSections(std::vector & fileData); + int captureImageSections(ByteBuffer & fileData); int captureOptionalHeader32(std::uint8_t * fileData, std::uint8_t * filePtr, std::uint8_t * fileEnd); int captureOptionalHeader64(std::uint8_t * fileData, std::uint8_t * filePtr, std::uint8_t * fileEnd); int verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_t fileSize); int verifyDosHeader(std::istream & fs, std::streamoff fileOffset, std::size_t fileSize); - int loadImageAsIs(std::vector & fileData); + int loadImageAsIs(ByteBuffer & fileData); - std::uint32_t captureImageSection(std::vector & fileData, + std::uint32_t captureImageSection(ByteBuffer & fileData, std::uint32_t virtualAddress, std::uint32_t virtualSize, std::uint32_t pointerToRawData, @@ -432,13 +434,13 @@ class ImageLoader std::vector sections; // Vector of section headers std::vector pages; // PE file pages as if mapped - std::vector rawFileData; // Loaded content of the image in case it couldn't have been mapped PELIB_IMAGE_DOS_HEADER dosHeader; // Loaded DOS header PELIB_IMAGE_FILE_HEADER fileHeader; // Loaded NT file header PELIB_IMAGE_OPTIONAL_HEADER optionalHeader; // 32/64-bit optional header + ByteBuffer rawFileData; // Loaded content of the image in case it couldn't have been mapped LoaderError ldrError; - std::uint32_t ntSignature; std::uint32_t windowsBuildNumber; + std::uint32_t ntSignature; std::uint32_t maxSectionCount; std::uint32_t realNumberOfRvaAndSizes; // Real present number of RVA and sizes std::uint32_t checkSumFileOffset; // File offset of the image checksum @@ -454,4 +456,4 @@ class ImageLoader } // namespace PeLib -#endif // IMAGE_LOADER_H +#endif // RETDEC_PELIB_IMAGE_LOADER_H diff --git a/include/retdec/pelib/ImportDirectory.h b/include/retdec/pelib/ImportDirectory.h index 57c57ffa6..2cd64199b 100644 --- a/include/retdec/pelib/ImportDirectory.h +++ b/include/retdec/pelib/ImportDirectory.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef IMPORTDIRECTORY_H -#define IMPORTDIRECTORY_H +#ifndef RETDEC_PELIB_IMPORTDIRECTORY_H +#define RETDEC_PELIB_IMPORTDIRECTORY_H #include #include diff --git a/include/retdec/pelib/InputBuffer.h b/include/retdec/pelib/InputBuffer.h index cbb3a4727..93f5e1a36 100644 --- a/include/retdec/pelib/InputBuffer.h +++ b/include/retdec/pelib/InputBuffer.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef INPUTBUFFER_H -#define INPUTBUFFER_H +#ifndef RETDEC_PELIB_INPUTBUFFER_H +#define RETDEC_PELIB_INPUTBUFFER_H #include #include diff --git a/include/retdec/pelib/OutputBuffer.h b/include/retdec/pelib/OutputBuffer.h index 09356845e..82fdac3a6 100644 --- a/include/retdec/pelib/OutputBuffer.h +++ b/include/retdec/pelib/OutputBuffer.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef OUTPUTBUFFER_H -#define OUTPUTBUFFER_H +#ifndef RETDEC_PELIB_OUTPUTBUFFER_H +#define RETDEC_PELIB_OUTPUTBUFFER_H #include #include diff --git a/include/retdec/pelib/PeFile.h b/include/retdec/pelib/PeFile.h index c58fdadbd..a6ed0386d 100644 --- a/include/retdec/pelib/PeFile.h +++ b/include/retdec/pelib/PeFile.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef PEFILE_H -#define PEFILE_H +#ifndef RETDEC_PELIB_PEFILE_H +#define RETDEC_PELIB_PEFILE_H #include "retdec/pelib/PeLibInc.h" #include "retdec/pelib/ImageLoader.h" diff --git a/include/retdec/pelib/PeLib.h b/include/retdec/pelib/PeLib.h deleted file mode 100644 index cfc4eaabb..000000000 --- a/include/retdec/pelib/PeLib.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -* PeLib.h - Part of the PeLib library. -* -* Copyright (c) 2004 - 2005 Sebastian Porst (webmaster@the-interweb.com) -* All rights reserved. -* -* This software is licensed under the zlib/libpng License. -* For more details see http://www.opensource.org/licenses/zlib-license.php -* or the license information file (license.htm) in the root directory -* of PeLib. -*/ - -#ifndef PELIB_H -#define PELIB_H - -#include "retdec/pelib/PeFile.h" - -#endif diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index 18acc7de9..3def2e3bb 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef PELIBAUX_H -#define PELIBAUX_H +#ifndef RETDEC_PELIB_PELIBAUX_H +#define RETDEC_PELIB_PELIBAUX_H #include #include @@ -163,22 +163,7 @@ namespace PeLib const std::uint32_t PELIB_IMAGE_RESOURCE_NAME_IS_STRING = 0x80000000; const std::uint32_t PELIB_IMAGE_RESOURCE_RVA_MASK = 0x7FFFFFFF; - template - struct PELIB_IMAGE_ORDINAL_FLAGS; - - template<> - struct PELIB_IMAGE_ORDINAL_FLAGS<32> - { - static const std::uint32_t PELIB_IMAGE_ORDINAL_FLAG = 0x80000000; - }; - - template<> - struct PELIB_IMAGE_ORDINAL_FLAGS<64> - { - static const std::uint64_t PELIB_IMAGE_ORDINAL_FLAG; - }; - - enum + enum : std::uint32_t { PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT, // OK PELIB_IMAGE_DIRECTORY_ENTRY_IMPORT, // OK @@ -250,7 +235,7 @@ namespace PeLib PELIB_IMAGE_SCN_MEM_WRITE = 0x80000000U }; - enum PELIB_IMAGE_FILE_MACHINE + enum PELIB_IMAGE_FILE_MACHINE : std::uint16_t { PELIB_IMAGE_FILE_MACHINE_UNKNOWN = 0, PELIB_IMAGE_FILE_MACHINE_I386 = 0x014C, @@ -289,7 +274,7 @@ namespace PeLib PELIB_IMAGE_FILE_MACHINE_MSIL = 0xC0EE }; - enum + enum : std::uint32_t { PELIB_IMAGE_FILE_RELOCS_STRIPPED = 0x0001, PELIB_IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002, @@ -308,7 +293,7 @@ namespace PeLib PELIB_IMAGE_FILE_BYTES_REVERSED_HI = 0x8000 }; - enum + enum : std::uint16_t { PELIB_IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040, PELIB_IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080, @@ -322,14 +307,14 @@ namespace PeLib PELIB_IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000 }; - enum + enum : std::uint16_t { PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b, PELIB_IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b, PELIB_IMAGE_ROM_OPTIONAL_HDR_MAGIC = 0x107 }; - enum + enum : std::uint16_t { PELIB_IMAGE_SUBSYSTEM_UNKNOWN = 0, PELIB_IMAGE_SUBSYSTEM_NATIVE = 1, @@ -353,7 +338,7 @@ namespace PeLib PELIB_IMAGE_REL_BASED_DIR64 = 10 }; - enum + enum : std::uint32_t { PELIB_RT_CURSOR = 1, // 1 PELIB_RT_BITMAP, // 2 @@ -380,7 +365,7 @@ namespace PeLib PELIB_RT_TOOLBAR }; - enum + enum : std::uint16_t { PELIB_LANG_NEUTRAL = 0x00, PELIB_LANG_ARABIC = 0x01, diff --git a/include/retdec/pelib/PeLibInc.h b/include/retdec/pelib/PeLibInc.h index 8213b3fff..d47638903 100644 --- a/include/retdec/pelib/PeLibInc.h +++ b/include/retdec/pelib/PeLibInc.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef STD_H -#define STD_H +#ifndef RETDEC_PELIB_PELIBINC_H +#define RETDEC_PELIB_PELIBINC_H #include #include diff --git a/include/retdec/pelib/RelocationsDirectory.h b/include/retdec/pelib/RelocationsDirectory.h index 7dc5f0834..03246beff 100644 --- a/include/retdec/pelib/RelocationsDirectory.h +++ b/include/retdec/pelib/RelocationsDirectory.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef RELOCATIONSDIRECTORY_H -#define RELOCATIONSDIRECTORY_H +#ifndef RETDEC_PELIB_RELOCATIONSDIRECTORY_H +#define RETDEC_PELIB_RELOCATIONSDIRECTORY_H #include "retdec/pelib/ImageLoader.h" diff --git a/include/retdec/pelib/ResourceDirectory.h b/include/retdec/pelib/ResourceDirectory.h index c81745810..e8fef5e91 100644 --- a/include/retdec/pelib/ResourceDirectory.h +++ b/include/retdec/pelib/ResourceDirectory.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef RESOURCEDIRECTORY_H -#define RESOURCEDIRECTORY_H +#ifndef RETDEC_PELIB_RESOURCEDIRECTORY_H +#define RETDEC_PELIB_RESOURCEDIRECTORY_H #include diff --git a/include/retdec/pelib/RichHeader.h b/include/retdec/pelib/RichHeader.h index 30c4b139c..193c4a037 100644 --- a/include/retdec/pelib/RichHeader.h +++ b/include/retdec/pelib/RichHeader.h @@ -4,8 +4,8 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef RICHHEADER_H -#define RICHHEADER_H +#ifndef RETDEC_PELIB_RICHHEADER_H +#define RETDEC_PELIB_RICHHEADER_H #include #include diff --git a/include/retdec/pelib/SecurityDirectory.h b/include/retdec/pelib/SecurityDirectory.h index 178f86d8e..e4b9c19e2 100644 --- a/include/retdec/pelib/SecurityDirectory.h +++ b/include/retdec/pelib/SecurityDirectory.h @@ -4,8 +4,8 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef SECURITYDIRECTORY_H -#define SECURITYDIRECTORY_H +#ifndef RETDEC_PELIB_SECURITYDIRECTORY_H +#define RETDEC_PELIB_SECURITYDIRECTORY_H namespace PeLib { diff --git a/include/retdec/pelib/TlsDirectory.h b/include/retdec/pelib/TlsDirectory.h index d8eccfe9a..0da328c26 100644 --- a/include/retdec/pelib/TlsDirectory.h +++ b/include/retdec/pelib/TlsDirectory.h @@ -10,8 +10,8 @@ * of PeLib. */ -#ifndef TLSDIRECTORY_H -#define TLSDIRECTORY_H +#ifndef RETDEC_PELIB_TLSDIRECTORY_H +#define RETDEC_PELIB_TLSDIRECTORY_H #include "retdec/pelib/ImageLoader.h" diff --git a/src/fileformat/file_format/file_format.cpp b/src/fileformat/file_format/file_format.cpp index a7aaa715b..f0c74dc1e 100644 --- a/src/fileformat/file_format/file_format.cpp +++ b/src/fileformat/file_format/file_format.cpp @@ -684,8 +684,8 @@ std::size_t FileFormat::getNibbleLength() const } /** - * Get number of bits in one std::uint8_t - * @return Number of bits in one std::uint8_t + * Get number of bits in one byte + * @return Number of bits in one byte * @note This assumes architectures with 8-bit bytes and may break if some * exotic architecture is encountered. */ @@ -696,8 +696,8 @@ std::size_t FileFormat::getByteLength() const } /** - * Get number of bits in one std::uint16_t - * @return Number of bits in one std::uint16_t or zero if this feature is not + * Get number of bits in one word + * @return Number of bits in one word or zero if this feature is not * supported for target architecture of input file. * * Supported architectures are defined as enumeration type Architecture. @@ -708,8 +708,8 @@ std::size_t FileFormat::getWordLength() const } /** - * Get number of nibbles in one std::uint8_t - * @return Number of nibbles in one std::uint8_t or zero if this feature is not + * Get number of nibbles in one byte + * @return Number of nibbles in one byte or zero if this feature is not * supported for target architecture of input file. * * Supported architectures are defined as enumeration type Architecture. @@ -1967,7 +1967,7 @@ bool FileFormat::getXByte(std::uint64_t address, std::uint64_t x, std::uint64_t } /** - * Get @a x bytes long std::uint8_t array from specified address + * Get @a x bytes long byte array from specified address * @param address Address to get array from * @param x Number of bytes for get * @param res Result array @@ -2061,8 +2061,8 @@ bool FileFormat::get8ByteOffset(std::uint64_t offset, std::uint64_t &res, retdec /** * Get long double from the specified offset - * If system has 80-bit (10 - uint8_t) long double, copy data directly. - * Else convert 80-bit (10 - uint8_t) long double into 64-bit (8 - uint8_t) double. + * If system has 80-bit (10 - byte) long double, copy data directly. + * Else convert 80-bit (10 - byte) long double into 64-bit (8 - uint8_t) double. * @param offset Offset to get double from * @param res Result double * @return Status of operation (@c true if all is OK, @c false otherwise) @@ -2107,7 +2107,7 @@ bool FileFormat::getXByteOffset(std::uint64_t offset, std::uint64_t x, std::uint } /** - * Get @a x bytes long std::uint8_t array from specified offset + * Get @a x bytes long byte array from specified offset * @param offset Offset to get array from * @param x Number of bytes for get * @param res Result array @@ -2126,7 +2126,7 @@ bool FileFormat::getXBytesOffset(std::uint64_t offset, std::uint64_t x, std::vec } /** - * Get std::uint16_t located at provided offset using the specified endian or default file endian + * Get word located at provided offset using the specified endian or default file endian * @param offset Offset to get integer from * @param res Result integer * @param e Endian - if specified it is forced, otherwise file's endian is used @@ -2138,10 +2138,10 @@ bool FileFormat::getWordOffset(std::uint64_t offset, std::uint64_t &res, retdec: } /** - * Get NTBS (null-terminated std::uint8_t string) from specified offset + * Get NTBS (null-terminated byte string) from specified offset * @param offset Offset to get string from * @param res Result string - * @param size Requested size of string (if @a size is zero, read until zero std::uint8_t) + * @param size Requested size of string (if @a size is zero, read until zero byte) * @return Status of operation (@c true if all is OK, @c false otherwise) */ bool FileFormat::getNTBSOffset(std::uint64_t offset, std::string &res, std::size_t size) const @@ -2445,11 +2445,11 @@ void FileFormat::dump(std::string &dumpFile) ret << "; Entry point offset: " << offset << "\n"; } - ret << "; Bytes per std::uint16_t: " << std::dec << getBytesPerWord() << "\n"; - ret << "; Bits per std::uint16_t: " << getWordLength() << "\n"; - ret << "; Bits per std::uint8_t: " << getByteLength() << "\n"; + ret << "; Bytes per word: " << std::dec << getBytesPerWord() << "\n"; + ret << "; Bits per word: " << getWordLength() << "\n"; + ret << "; Bits per byte: " << getByteLength() << "\n"; ret << "; Bits per nibble: " << getNibbleLength() << "\n"; - ret << "; Nibbles per std::uint8_t: " << getNumberOfNibblesInByte() << "\n"; + ret << "; Nibbles per byte: " << getNumberOfNibblesInByte() << "\n"; if(getNumberOfSections()) { diff --git a/src/fileformat/utils/format_detection.cpp b/src/fileformat/utils/format_detection.cpp index 704ffe5b8..59e8c4f66 100644 --- a/src/fileformat/utils/format_detection.cpp +++ b/src/fileformat/utils/format_detection.cpp @@ -16,7 +16,7 @@ #include "retdec/utils/string.h" #include "retdec/fileformat/utils/byte_array_buffer.h" #include "retdec/fileformat/utils/format_detection.h" -#include "retdec/pelib/PeLib.h" +#include "retdec/pelib/PeFile.h" #include "retdec/pelib/ImageLoader.h" using namespace retdec::utils; diff --git a/src/fileinfo/file_detector/pe_detector.cpp b/src/fileinfo/file_detector/pe_detector.cpp index 53a05dfdf..dd6f1fcfe 100644 --- a/src/fileinfo/file_detector/pe_detector.cpp +++ b/src/fileinfo/file_detector/pe_detector.cpp @@ -477,7 +477,7 @@ void PeDetector::detectArchitecture() result = "Matsushita AM33"; break; case PELIB_IMAGE_FILE_MACHINE_EBC: - result = "EFI std::uint8_t code"; + result = "EFI byte code"; break; case PELIB_IMAGE_FILE_MACHINE_MSIL: result = "MSIL - Microsoft Intermediate Language (aka CIL - Common Intermediate Language)"; diff --git a/src/fileinfo/file_wrapper/pe_wrapper.cpp b/src/fileinfo/file_wrapper/pe_wrapper.cpp index 19236386e..bc845753d 100644 --- a/src/fileinfo/file_wrapper/pe_wrapper.cpp +++ b/src/fileinfo/file_wrapper/pe_wrapper.cpp @@ -101,12 +101,6 @@ PeWrapper::PeWrapper( : PeFormat(pathToFile, dllListFile, loadFlags) {} -/** - * Destructor - */ -PeWrapper::~PeWrapper() -{} - /** * Get type of binary file * @return Type of binary file (e.g. DLL) diff --git a/src/fileinfo/file_wrapper/pe_wrapper.h b/src/fileinfo/file_wrapper/pe_wrapper.h index 76259e7ea..1c01009e1 100644 --- a/src/fileinfo/file_wrapper/pe_wrapper.h +++ b/src/fileinfo/file_wrapper/pe_wrapper.h @@ -23,7 +23,6 @@ class PeWrapper : public retdec::fileformat::PeFormat { public: PeWrapper(const std::string & pathToFile, const std::string & dllListFile, retdec::fileformat::LoadFlags loadFlags); - virtual ~PeWrapper() override; std::uint32_t getBits() { diff --git a/src/fileinfo/fileinfo.cpp b/src/fileinfo/fileinfo.cpp index 2f268e70b..5a8b52aa8 100644 --- a/src/fileinfo/fileinfo.cpp +++ b/src/fileinfo/fileinfo.cpp @@ -523,5 +523,5 @@ int main(int argc, char* argv[]) } delete fileDetector; - return isFatalError(res) ? static_cast(res) : static_cast(ReturnCode::OK); + return isFatalError(res) ? static_cast(res) : static_cast(ReturnCode::OK); } diff --git a/src/pelib/DebugDirectory.cpp b/src/pelib/DebugDirectory.cpp index 7aa1443db..be61e41d0 100644 --- a/src/pelib/DebugDirectory.cpp +++ b/src/pelib/DebugDirectory.cpp @@ -68,7 +68,10 @@ namespace PeLib return ERROR_NONE; } - void DebugDirectory::read(ImageLoader & imageLoader, std::vector & debugInfo, std::uint32_t rva, std::uint32_t size) + void DebugDirectory::read(ImageLoader & imageLoader, + std::vector & debugInfo, + std::uint32_t rva, + std::uint32_t size) { PELIB_IMG_DEBUG_DIRECTORY iddCurr; std::size_t entryCount = size / PELIB_IMAGE_DEBUG_DIRECTORY::size(); diff --git a/src/pelib/ImageLoader.cpp b/src/pelib/ImageLoader.cpp index bab620abc..5973adc23 100644 --- a/src/pelib/ImageLoader.cpp +++ b/src/pelib/ImageLoader.cpp @@ -1,12 +1,8 @@ -/*****************************************************************************/ -/* ImageLoader.cpp Copyright (c) Ladislav Zezula 2020 */ -/*---------------------------------------------------------------------------*/ -/* Implementation of PE image loader */ -/*---------------------------------------------------------------------------*/ -/* Date Ver Who Comment */ -/* -------- ---- --- ------- */ -/* 30.05.20 1.00 Lad Created */ -/*****************************************************************************/ +/** + * @file src/pelib/ImageLoader.cpp + * @brief Implementation of image + * @copyright (c) 2020 Avast Software, licensed under the MIT license + */ #include #include @@ -100,9 +96,6 @@ PeLib::ImageLoader::ImageLoader(uint32_t versionInfo) } } -PeLib::ImageLoader::~ImageLoader() -{} - //----------------------------------------------------------------------------- // Public functions @@ -156,7 +149,10 @@ bool PeLib::ImageLoader::relocateImage(uint64_t newImageBase) return result; } -uint32_t PeLib::ImageLoader::readImage(void * buffer, uint32_t rva, uint32_t bytesToRead) +uint32_t PeLib::ImageLoader::readImage( + void * buffer, + uint32_t rva, + uint32_t bytesToRead) { // If the image was properly mapped, perform an image-read operation if(rawFileData.size() == 0) @@ -170,7 +166,10 @@ uint32_t PeLib::ImageLoader::readImage(void * buffer, uint32_t rva, uint32_t byt return readWriteImageFile(buffer, rva, bytesToRead, true); } -uint32_t PeLib::ImageLoader::writeImage(void * buffer, uint32_t rva, uint32_t bytesToRead) +uint32_t PeLib::ImageLoader::writeImage( + void * buffer, + uint32_t rva, + uint32_t bytesToRead) { // If the image was properly mapped, perform an image-read operation if(rawFileData.size() == 0) @@ -181,7 +180,9 @@ uint32_t PeLib::ImageLoader::writeImage(void * buffer, uint32_t rva, uint32_t by return readWriteImageFile(buffer, rva, bytesToRead, false); } -uint32_t PeLib::ImageLoader::stringLength(uint32_t rva, uint32_t maxLength) const +uint32_t PeLib::ImageLoader::stringLength( + uint32_t rva, + uint32_t maxLength) const { uint32_t rvaBegin = rva; uint32_t rvaEnd = rva + maxLength; @@ -252,7 +253,10 @@ uint32_t PeLib::ImageLoader::stringLength(uint32_t rva, uint32_t maxLength) cons return length; } -uint32_t PeLib::ImageLoader::readString(std::string & str, uint32_t rva, uint32_t maxLength) +uint32_t PeLib::ImageLoader::readString( + std::string & str, + uint32_t rva, + uint32_t maxLength) { // Check the length of the string at the rva uint32_t length = stringLength(rva, maxLength); @@ -265,7 +269,9 @@ uint32_t PeLib::ImageLoader::readString(std::string & str, uint32_t rva, uint32_ return length; } -uint32_t PeLib::ImageLoader::readPointer(uint32_t rva, uint64_t & pointerValue) +uint32_t PeLib::ImageLoader::readPointer( + uint32_t rva, + uint64_t & pointerValue) { uint32_t bytesRead = 0; @@ -299,7 +305,9 @@ uint32_t PeLib::ImageLoader::getPointerSize() const return getImageBitability() / 8; } -uint32_t PeLib::ImageLoader::readStringRc(std::string & str, uint32_t rva) +uint32_t PeLib::ImageLoader::readStringRc( + std::string & str, + uint32_t rva) { std::vector wideString; uint32_t bytesToRead; @@ -325,7 +333,13 @@ uint32_t PeLib::ImageLoader::readStringRc(std::string & str, uint32_t rva) return charsRead; } -uint32_t PeLib::ImageLoader::readStringRaw(std::vector & fileData, std::string & str, size_t offset, size_t maxLength, bool mustBePrintable, bool mustNotBeTooLong) +uint32_t PeLib::ImageLoader::readStringRaw( + ByteBuffer & fileData, + std::string & str, + size_t offset, + size_t maxLength, + bool mustBePrintable, + bool mustNotBeTooLong) { size_t length = 0; @@ -459,35 +473,54 @@ uint32_t PeLib::ImageLoader::getFieldOffset(PELIB_MEMBER_TYPE field) const switch (field) { - case OPTHDR_sizeof: + case PELIB_MEMBER_TYPE::OPTHDR_sizeof: return (imageBitability == 64) ? sizeof(PELIB_IMAGE_OPTIONAL_HEADER64) : sizeof(PELIB_IMAGE_OPTIONAL_HEADER32); - case OPTHDR_sizeof_fixed: - return (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + case PELIB_MEMBER_TYPE::OPTHDR_sizeof_fixed: + return (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) + : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); - case OPTHDR_NumberOfRvaAndSizes: - fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, NumberOfRvaAndSizes) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, NumberOfRvaAndSizes); + case PELIB_MEMBER_TYPE::OPTHDR_NumberOfRvaAndSizes: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, NumberOfRvaAndSizes) + : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, NumberOfRvaAndSizes); return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset; - case OPTHDR_DataDirectory: - fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + case PELIB_MEMBER_TYPE::OPTHDR_DataDirectory: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) + : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset; - case OPTHDR_DataDirectory_EXPORT_Rva: - fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); - return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT * sizeof(PELIB_IMAGE_DATA_DIRECTORY); - - case OPTHDR_DataDirectory_RSRC_Rva: - fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); - return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE * sizeof(PELIB_IMAGE_DATA_DIRECTORY); - - case OPTHDR_DataDirectory_TLS_Rva: - fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); - return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_TLS * sizeof(PELIB_IMAGE_DATA_DIRECTORY); - - case OPTHDR_DataDirectory_CONFIG_Rva: - fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); - return sizeof(PELIB_IMAGE_NT_SIGNATURE) + sizeof(PELIB_IMAGE_FILE_HEADER) + fieldOffset + PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG * sizeof(PELIB_IMAGE_DATA_DIRECTORY); + case PELIB_MEMBER_TYPE::OPTHDR_DataDirectory_EXPORT_Rva: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) + : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + + sizeof(PELIB_IMAGE_FILE_HEADER) + + fieldOffset + + PELIB_IMAGE_DIRECTORY_ENTRY_EXPORT * sizeof(PELIB_IMAGE_DATA_DIRECTORY); + + case PELIB_MEMBER_TYPE::OPTHDR_DataDirectory_RSRC_Rva: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) + : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + + sizeof(PELIB_IMAGE_FILE_HEADER) + + fieldOffset + + PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE * sizeof(PELIB_IMAGE_DATA_DIRECTORY); + + case PELIB_MEMBER_TYPE::OPTHDR_DataDirectory_TLS_Rva: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) + : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + + sizeof(PELIB_IMAGE_FILE_HEADER) + + fieldOffset + + PELIB_IMAGE_DIRECTORY_ENTRY_TLS * sizeof(PELIB_IMAGE_DATA_DIRECTORY); + + case PELIB_MEMBER_TYPE::OPTHDR_DataDirectory_CONFIG_Rva: + fieldOffset = (imageBitability == 64) ? offsetof(PELIB_IMAGE_OPTIONAL_HEADER64, DataDirectory) + : offsetof(PELIB_IMAGE_OPTIONAL_HEADER32, DataDirectory); + return sizeof(PELIB_IMAGE_NT_SIGNATURE) + + sizeof(PELIB_IMAGE_FILE_HEADER) + + fieldOffset + + PELIB_IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG * sizeof(PELIB_IMAGE_DATA_DIRECTORY); } return UINT32_MAX; @@ -554,7 +587,9 @@ void PeLib::ImageLoader::setAddressOfEntryPoint(uint32_t addressOfEntryPoint) optionalHeader.AddressOfEntryPoint = addressOfEntryPoint; } -void PeLib::ImageLoader::setSizeOfCode(uint32_t sizeOfCode, uint32_t baseOfCode) +void PeLib::ImageLoader::setSizeOfCode( + uint32_t sizeOfCode, + uint32_t baseOfCode) { if(sizeOfCode != UINT32_MAX) optionalHeader.SizeOfCode = sizeOfCode; @@ -562,7 +597,10 @@ void PeLib::ImageLoader::setSizeOfCode(uint32_t sizeOfCode, uint32_t baseOfCode) optionalHeader.BaseOfCode = baseOfCode; } -void PeLib::ImageLoader::setDataDirectory(uint32_t entryIndex, uint32_t VirtualAddress, uint32_t Size) +void PeLib::ImageLoader::setDataDirectory( + uint32_t entryIndex, + uint32_t VirtualAddress, + uint32_t Size) { if(entryIndex < PELIB_IMAGE_NUMBEROF_DIRECTORY_ENTRIES) { @@ -577,7 +615,9 @@ void PeLib::ImageLoader::setDataDirectory(uint32_t entryIndex, uint32_t VirtualA } } -PeLib::PELIB_IMAGE_SECTION_HEADER * PeLib::ImageLoader::addSection(const char * name, uint32_t sectionSize) +PeLib::PELIB_IMAGE_SECTION_HEADER * PeLib::ImageLoader::addSection( + const char * name, + uint32_t sectionSize) { if(optionalHeader.FileAlignment == 0) return nullptr; @@ -603,7 +643,9 @@ PeLib::PELIB_IMAGE_SECTION_HEADER * PeLib::ImageLoader::addSection(const char * return getSectionHeader(sections.size() - 1); } -void PeLib::ImageLoader::calcNewSectionAddresses(uint32_t & Rva, uint32_t & RawOffset) +void PeLib::ImageLoader::calcNewSectionAddresses( + uint32_t & Rva, + uint32_t & RawOffset) { uint32_t NewRawOffset = optionalHeader.SizeOfHeaders; uint32_t NewRva = optionalHeader.SizeOfHeaders; @@ -620,7 +662,9 @@ void PeLib::ImageLoader::calcNewSectionAddresses(uint32_t & Rva, uint32_t & RawO Rva = AlignToSize(NewRva, optionalHeader.SectionAlignment); } -void PeLib::ImageLoader::setSectionName(std::size_t sectionIndex, const char * newName) +void PeLib::ImageLoader::setSectionName( + std::size_t sectionIndex, + const char * newName) { if(sectionIndex < sections.size()) { @@ -628,7 +672,10 @@ void PeLib::ImageLoader::setSectionName(std::size_t sectionIndex, const char * n } } -void PeLib::ImageLoader::setSectionVirtualRange(size_t sectionIndex, uint32_t VirtualAddress, uint32_t VirtualSize) +void PeLib::ImageLoader::setSectionVirtualRange( + size_t sectionIndex, + uint32_t VirtualAddress, + uint32_t VirtualSize) { if(sectionIndex < sections.size()) { @@ -636,7 +683,10 @@ void PeLib::ImageLoader::setSectionVirtualRange(size_t sectionIndex, uint32_t Vi } } -void PeLib::ImageLoader::setSectionRawDataRange(size_t sectionIndex, uint32_t PointerToRawData, uint32_t SizeOfRawData) +void PeLib::ImageLoader::setSectionRawDataRange( + size_t sectionIndex, + uint32_t PointerToRawData, + uint32_t SizeOfRawData) { if(sectionIndex < sections.size()) { @@ -644,7 +694,9 @@ void PeLib::ImageLoader::setSectionRawDataRange(size_t sectionIndex, uint32_t Po } } -void PeLib::ImageLoader::setSectionCharacteristics(size_t sectionIndex, uint32_t Characteristics) +void PeLib::ImageLoader::setSectionCharacteristics( + size_t sectionIndex, + uint32_t Characteristics) { if(sectionIndex < sections.size()) { @@ -652,7 +704,11 @@ void PeLib::ImageLoader::setSectionCharacteristics(size_t sectionIndex, uint32_t } } -int PeLib::ImageLoader::splitSection(size_t sectionIndex, const std::string & prevSectName, const std::string & nextSectName, uint32_t splitOffset) +int PeLib::ImageLoader::splitSection( + size_t sectionIndex, + const std::string & prevSectName, + const std::string & nextSectName, + uint32_t splitOffset) { if(!optionalHeader.FileAlignment) return PeLib::ERROR_NO_FILE_ALIGNMENT; @@ -738,7 +794,7 @@ void PeLib::ImageLoader::makeValid() // Fix the IMAGE_FILE_HEADER fileHeader.Machine = (imageBitability == 64) ? PELIB_IMAGE_FILE_MACHINE_AMD64 : PELIB_IMAGE_FILE_MACHINE_I386; fileHeader.NumberOfSections = (uint16_t)sections.size(); - fileHeader.SizeOfOptionalHeader = getFieldOffset(OPTHDR_sizeof); + fileHeader.SizeOfOptionalHeader = getFieldOffset(PELIB_MEMBER_TYPE::OPTHDR_sizeof); fileHeader.Characteristics = (fileHeader.Characteristics != 0) ? fileHeader.Characteristics : PELIB_IMAGE_FILE_EXECUTABLE_IMAGE | PELIB_IMAGE_FILE_32BIT_MACHINE; // Fix the IMAGE_OPTIONAL_HEADER @@ -792,7 +848,9 @@ PeLib::LoaderError PeLib::ImageLoader::loaderError() const //----------------------------------------------------------------------------- // Interface for loading files -int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHeadersOnly) +int PeLib::ImageLoader::Load( + ByteBuffer & fileData, + bool loadHeadersOnly) { int fileError; @@ -840,9 +898,12 @@ int PeLib::ImageLoader::Load(std::vector & fileData, bool loadHead return fileError; } -int PeLib::ImageLoader::Load(std::istream & fs, std::streamoff fileOffset, bool loadHeadersOnly) +int PeLib::ImageLoader::Load( + std::istream & fs, + std::streamoff fileOffset, + bool loadHeadersOnly) { - std::vector fileData; + ByteBuffer fileData; std::streampos fileSize; size_t fileSize2; int fileError; @@ -895,7 +956,9 @@ int PeLib::ImageLoader::Load(std::istream & fs, std::streamoff fileOffset, bool return Load(fileData, loadHeadersOnly); } -int PeLib::ImageLoader::Load(const char * fileName, bool loadHeadersOnly) +int PeLib::ImageLoader::Load( + const char * fileName, + bool loadHeadersOnly) { std::ifstream fs(fileName, std::ifstream::in | std::ifstream::binary); if(!fs.is_open()) @@ -907,7 +970,10 @@ int PeLib::ImageLoader::Load(const char * fileName, bool loadHeadersOnly) //----------------------------------------------------------------------------- // Interface for saving to file -int PeLib::ImageLoader::Save(std::ostream & fs, std::streamoff fileOffset, bool saveHeadersOnly) +int PeLib::ImageLoader::Save( + std::ostream & fs, + std::streamoff fileOffset, + bool saveHeadersOnly) { std::streamoff fileSize; int fileError; @@ -958,7 +1024,9 @@ int PeLib::ImageLoader::Save(std::ostream & fs, std::streamoff fileOffset, bool return ERROR_NONE; } -int PeLib::ImageLoader::Save(const char * fileName, bool saveHeadersOnly) +int PeLib::ImageLoader::Save( + const char * fileName, + bool saveHeadersOnly) { std::ofstream fs(fileName, std::ifstream::out | std::ifstream::binary); if(!fs.is_open()) @@ -970,7 +1038,11 @@ int PeLib::ImageLoader::Save(const char * fileName, bool saveHeadersOnly) //----------------------------------------------------------------------------- // Protected functions -void PeLib::ImageLoader::readFromPage(PELIB_FILE_PAGE & page, void * buffer, size_t offsetInPage, size_t bytesInPage) +void PeLib::ImageLoader::readFromPage( + PELIB_FILE_PAGE & page, + void * buffer, + size_t offsetInPage, + size_t bytesInPage) { // Is it a page with actual data? if(page.buffer.size()) @@ -983,13 +1055,21 @@ void PeLib::ImageLoader::readFromPage(PELIB_FILE_PAGE & page, void * buffer, siz } } -void PeLib::ImageLoader::writeToPage(PELIB_FILE_PAGE & page, void * buffer, size_t offsetInPage, size_t bytesInPage) +void PeLib::ImageLoader::writeToPage( + PELIB_FILE_PAGE & page, + void * buffer, + size_t offsetInPage, + size_t bytesInPage) { // Write the data to the page page.writeToPage(buffer, offsetInPage, bytesInPage); } -uint32_t PeLib::ImageLoader::readWriteImage(void * buffer, uint32_t rva, uint32_t bytesToRead, READWRITE ReadWrite) +uint32_t PeLib::ImageLoader::readWriteImage( + void * buffer, + uint32_t rva, + uint32_t bytesToRead, + READWRITE ReadWrite) { uint32_t bytesRead = 0; uint32_t rvaEnd = rva + bytesToRead; @@ -1032,7 +1112,11 @@ uint32_t PeLib::ImageLoader::readWriteImage(void * buffer, uint32_t rva, uint32_ return bytesRead; } -uint32_t PeLib::ImageLoader::readWriteImageFile(void * buffer, uint32_t rva, uint32_t bytesToRead, bool bReadOperation) +uint32_t PeLib::ImageLoader::readWriteImageFile( + void * buffer, + uint32_t rva, + uint32_t bytesToRead, + bool bReadOperation) { uint32_t fileOffset = getFileOffsetFromRva(rva); @@ -1076,7 +1160,8 @@ uint32_t PeLib::ImageLoader::readWriteImageFile(void * buffer, uint32_t rva, uin // } // -void PeLib::ImageLoader::processSectionHeader(PELIB_IMAGE_SECTION_HEADER * pSectionHeader) +void PeLib::ImageLoader::processSectionHeader( + PELIB_IMAGE_SECTION_HEADER * pSectionHeader) { // Note: Retdec's regression tests don't like it, because they require section headers to have original data // Also signature verification stops working if we modify the original data @@ -1142,7 +1227,9 @@ void PeLib::ImageLoader::processSectionHeader(PELIB_IMAGE_SECTION_HEADER * pSect TargetValue32 = (TargetValue32 & ~(((1 << Size) - 1) << InstPos)) | \ ((uint32_t)((((uint64_t)Value >> ValPos) & (((uint64_t)1 << Size) - 1))) << InstPos) -bool PeLib::ImageLoader::processImageRelocation_IA64_IMM64(uint32_t fixupAddress, uint64_t difference) +bool PeLib::ImageLoader::processImageRelocation_IA64_IMM64( + uint32_t fixupAddress, + uint64_t difference) { uint64_t Value64 = 0; uint32_t BundleBlock[4]; @@ -1237,7 +1324,11 @@ bool PeLib::ImageLoader::processImageRelocation_IA64_IMM64(uint32_t fixupAddress return (writeImage(BundleBlock, fixupAddress, sizeof(BundleBlock)) == sizeof(BundleBlock)); } -bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t newImageBase, uint32_t VirtualAddress, uint32_t Size) +bool PeLib::ImageLoader::processImageRelocations( + uint64_t oldImageBase, + uint64_t newImageBase, + uint32_t VirtualAddress, + uint32_t Size) { uint64_t difference = (newImageBase - oldImageBase); uint8_t * bufferEnd; @@ -1295,7 +1386,8 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t switch(typeAndOffset[i] >> 12) { - case PELIB_IMAGE_REL_BASED_DIR64: // The base relocation applies the difference to the 64-bit field at offset. + // The base relocation applies the difference to the 64-bit field at offset. + case PELIB_IMAGE_REL_BASED_DIR64: { int64_t fixupValue = 0; @@ -1306,7 +1398,8 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t break; } - case PELIB_IMAGE_REL_BASED_HIGHLOW: // The base relocation applies all 32 bits of the difference to the 32-bit field at offset. + // The base relocation applies all 32 bits of the difference to the 32-bit field at offset. + case PELIB_IMAGE_REL_BASED_HIGHLOW: { int32_t fixupValue = 0; @@ -1317,7 +1410,8 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t break; } - case PELIB_IMAGE_REL_BASED_HIGH: // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. + // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. + case PELIB_IMAGE_REL_BASED_HIGH: { int16_t fixupValue = 0; @@ -1330,7 +1424,8 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t break; } - case PELIB_IMAGE_REL_BASED_HIGHADJ: // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. + // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. + case PELIB_IMAGE_REL_BASED_HIGHADJ: { int16_t fixupValue = 0; @@ -1345,7 +1440,8 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t break; } - case PELIB_IMAGE_REL_BASED_LOW: // The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. + // The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. + case PELIB_IMAGE_REL_BASED_LOW: { int16_t fixupValue = 0; @@ -1356,7 +1452,8 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t break; } - case PELIB_IMAGE_REL_BASED_MIPS_JMPADDR: // Relocate a MIPS jump address. + // Relocate a MIPS jump address. + case PELIB_IMAGE_REL_BASED_MIPS_JMPADDR: { uint32_t fixupValue = 0; @@ -1373,7 +1470,8 @@ bool PeLib::ImageLoader::processImageRelocations(uint64_t oldImageBase, uint64_t processImageRelocation_IA64_IMM64(fixupAddress, difference); break; - case PELIB_IMAGE_REL_BASED_ABSOLUTE: // Absolute - no fixup required. + // Absolute - no fixup required. + case PELIB_IMAGE_REL_BASED_ABSOLUTE: break; default: @@ -1419,7 +1517,7 @@ void PeLib::ImageLoader::writeNewImageBase(uint64_t newImageBase) } } -int PeLib::ImageLoader::captureDosHeader(std::vector & fileData) +int PeLib::ImageLoader::captureDosHeader(ByteBuffer & fileData) { uint8_t * fileBegin = fileData.data(); uint8_t * fileEnd = fileBegin + fileData.size(); @@ -1433,7 +1531,9 @@ int PeLib::ImageLoader::captureDosHeader(std::vector & fileData) return verifyDosHeader(dosHeader, fileData.size()); } -int PeLib::ImageLoader::saveDosHeader(std::ostream & fs, std::streamoff fileOffset) +int PeLib::ImageLoader::saveDosHeader( + std::ostream & fs, + std::streamoff fileOffset) { // Move to the required file offset fs.seekp(fileOffset, std::ios::beg); @@ -1443,7 +1543,7 @@ int PeLib::ImageLoader::saveDosHeader(std::ostream & fs, std::streamoff fileOffs return ERROR_NONE; } -int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) +int PeLib::ImageLoader::captureNtHeaders(ByteBuffer & fileData) { uint8_t * fileBegin = fileData.data(); uint8_t * filePtr = fileBegin + dosHeader.e_lfanew; @@ -1571,11 +1671,13 @@ int PeLib::ImageLoader::captureNtHeaders(std::vector & fileData) return ERROR_NONE; } -int PeLib::ImageLoader::saveNtHeaders(std::ostream & fs, std::streamoff fileOffset) +int PeLib::ImageLoader::saveNtHeaders( + std::ostream & fs, + std::streamoff fileOffset) { // Calculate the size of the optional header. Any version of PE file, // 32 or 64-bit, must have this field set to a correct value. - uint32_t sizeOfOptionalHeader = getFieldOffset(OPTHDR_sizeof_fixed) + optionalHeader.NumberOfRvaAndSizes * sizeof(PELIB_IMAGE_DATA_DIRECTORY); + uint32_t sizeOfOptionalHeader = getFieldOffset(PELIB_MEMBER_TYPE::OPTHDR_sizeof_fixed) + optionalHeader.NumberOfRvaAndSizes * sizeof(PELIB_IMAGE_DATA_DIRECTORY); // Move to the required file offset fs.seekp(fileOffset, std::ios::beg); @@ -1680,7 +1782,10 @@ int PeLib::ImageLoader::saveNtHeaders(std::ostream & fs, std::streamoff fileOffs return ERROR_NONE; } -int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std::string & sectionName, const uint8_t * Name) +int PeLib::ImageLoader::captureSectionName( + ByteBuffer & fileData, + std::string & sectionName, + const uint8_t * Name) { // If the section name is in format of "/12345", then the section name is actually in the symbol table // Sample: 2e9c671b8a0411f2b397544b368c44d7f095eb395779de0ad1ac946914dfa34c @@ -1714,7 +1819,7 @@ int PeLib::ImageLoader::captureSectionName(std::vector & fileData, std: return ERROR_NONE; } -int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) +int PeLib::ImageLoader::captureSectionHeaders(ByteBuffer & fileData) { uint8_t * fileBegin = fileData.data(); uint8_t * filePtr; @@ -1888,7 +1993,9 @@ int PeLib::ImageLoader::captureSectionHeaders(std::vector & fileData) return ERROR_NONE; } -int PeLib::ImageLoader::saveSectionHeaders(std::ostream & fs, std::streamoff fileOffset) +int PeLib::ImageLoader::saveSectionHeaders( + std::ostream & fs, + std::streamoff fileOffset) { PELIB_IMAGE_SECTION_HEADER * pHeaders; size_t sectionCount = sections.size(); @@ -1912,7 +2019,7 @@ int PeLib::ImageLoader::saveSectionHeaders(std::ostream & fs, std::streamoff fil return ERROR_NONE; } -int PeLib::ImageLoader::captureImageSections(std::vector & fileData) +int PeLib::ImageLoader::captureImageSections(ByteBuffer & fileData) { uint32_t virtualAddress = 0; uint32_t sizeOfHeaders = optionalHeader.SizeOfHeaders; @@ -1990,7 +2097,9 @@ int PeLib::ImageLoader::captureImageSections(std::vector & fileData) return ERROR_NONE; } -int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_t fileSize) +int PeLib::ImageLoader::verifyDosHeader( + PELIB_IMAGE_DOS_HEADER & hdr, + std::size_t fileSize) { if(hdr.e_magic != PELIB_IMAGE_DOS_SIGNATURE) return ERROR_INVALID_FILE; @@ -2002,7 +2111,10 @@ int PeLib::ImageLoader::verifyDosHeader(PELIB_IMAGE_DOS_HEADER & hdr, std::size_ return ERROR_NONE; } -int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOffset, std::size_t fileSize) +int PeLib::ImageLoader::verifyDosHeader( + std::istream & fs, + std::streamoff fileOffset, + std::size_t fileSize) { PELIB_IMAGE_DOS_HEADER tempDosHeader; int fileError; @@ -2024,13 +2136,16 @@ int PeLib::ImageLoader::verifyDosHeader(std::istream & fs, std::streamoff fileOf return (ldrError == LDR_ERROR_E_LFANEW_OUT_OF_FILE) ? ERROR_INVALID_FILE : ERROR_NONE; } -int PeLib::ImageLoader::loadImageAsIs(std::vector & fileData) +int PeLib::ImageLoader::loadImageAsIs(ByteBuffer & fileData) { rawFileData = fileData; return ERROR_NONE; } -int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * fileBegin, uint8_t * filePtr, uint8_t * fileEnd) +int PeLib::ImageLoader::captureOptionalHeader64( + uint8_t * fileBegin, + uint8_t * filePtr, + uint8_t * fileEnd) { PELIB_IMAGE_OPTIONAL_HEADER64 optionalHeader64{}; uint8_t * dataDirectoryPtr; @@ -2098,7 +2213,10 @@ int PeLib::ImageLoader::captureOptionalHeader64(uint8_t * fileBegin, uint8_t * f return ERROR_NONE; } -int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * fileBegin, uint8_t * filePtr, uint8_t * fileEnd) +int PeLib::ImageLoader::captureOptionalHeader32( + uint8_t * fileBegin, + uint8_t * filePtr, + uint8_t * fileEnd) { PELIB_IMAGE_OPTIONAL_HEADER32 optionalHeader32{}; uint8_t * dataDirectoryPtr; @@ -2168,7 +2286,7 @@ int PeLib::ImageLoader::captureOptionalHeader32(uint8_t * fileBegin, uint8_t * f } uint32_t PeLib::ImageLoader::captureImageSection( - std::vector & fileData, + ByteBuffer & fileData, uint32_t virtualAddress, uint32_t virtualSize, uint32_t pointerToRawData, @@ -2275,7 +2393,9 @@ uint32_t PeLib::ImageLoader::captureImageSection( return virtualAddress + sizeOfSection; } -bool PeLib::ImageLoader::isGoodPagePointer(PFN_VERIFY_ADDRESS PfnVerifyAddress, void * pagePtr) +bool PeLib::ImageLoader::isGoodPagePointer( + PFN_VERIFY_ADDRESS PfnVerifyAddress, + void * pagePtr) { // If the caller didn't supply a verification procedure, use default one // The verification procedure can possibly be system-specific, like IsBadReadPtr on Windows @@ -2431,7 +2551,11 @@ bool PeLib::ImageLoader::isValidImageBlock(uint32_t Rva, uint32_t Size) const //----------------------------------------------------------------------------- // Testing functions -size_t PeLib::ImageLoader::getMismatchOffset(void * buffer1, void * buffer2, uint32_t rva, size_t length) +size_t PeLib::ImageLoader::getMismatchOffset( + void * buffer1, + void * buffer2, + uint32_t rva, + size_t length) { uint8_t * byteBuffer1 = reinterpret_cast(buffer1); uint8_t * byteBuffer2 = reinterpret_cast(buffer2); @@ -2456,7 +2580,10 @@ size_t PeLib::ImageLoader::getMismatchOffset(void * buffer1, void * buffer2, uin return (size_t)(-1); } -void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & ImageCompare, void * imageDataPtr, uint32_t imageSize) +void PeLib::ImageLoader::compareWithWindowsMappedImage( + PELIB_IMAGE_COMPARE & ImageCompare, + void * imageDataPtr, + uint32_t imageSize) { uint8_t * winImageData = reinterpret_cast(imageDataPtr); uint8_t * winImageEnd = winImageData + imageSize; @@ -2470,7 +2597,7 @@ void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & Ima // Check whether the image size is the same if(imageSize != getSizeOfImageAligned()) { - ImageCompare.compareResult = ImagesDifferentSize; + ImageCompare.compareResult = PELIB_COMPARE_RESULT::ImagesDifferentSize; ImageCompare.differenceOffset = 0; return; } @@ -2502,7 +2629,7 @@ void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & Ima mismatchOffset = getMismatchOffset(winImageData, singlePage, rva, PELIB_PAGE_SIZE); if(mismatchOffset != (size_t)(-1)) { - ImageCompare.compareResult = ImagesDifferentPageValue; + ImageCompare.compareResult = PELIB_COMPARE_RESULT::ImagesDifferentPageValue; ImageCompare.differenceOffset = rva + mismatchOffset; return; } @@ -2513,7 +2640,7 @@ void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & Ima // Accessible vs inacessible? if(isGoodPageWin != isGoodPageMy) { - ImageCompare.compareResult = ImagesDifferentPageAccess; + ImageCompare.compareResult = PELIB_COMPARE_RESULT::ImagesDifferentPageAccess; ImageCompare.differenceOffset = rva; return; } @@ -2531,7 +2658,7 @@ void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & Ima // Windows didn't map the image if(winImageData == nullptr) { - ImageCompare.compareResult = ImagesWindowsDidntLoadWeDid; + ImageCompare.compareResult = PELIB_COMPARE_RESULT::ImagesWindowsDidntLoadWeDid; return; } } @@ -2540,12 +2667,12 @@ void PeLib::ImageLoader::compareWithWindowsMappedImage(PELIB_IMAGE_COMPARE & Ima // Windows mapped the image if(winImageData != nullptr) { - ImageCompare.compareResult = ImagesWindowsLoadedWeDidnt; + ImageCompare.compareResult = PELIB_COMPARE_RESULT::ImagesWindowsLoadedWeDidnt; return; } } // Both Windows and our image are the same - ImageCompare.compareResult = ImagesEqual; + ImageCompare.compareResult = PELIB_COMPARE_RESULT::ImagesEqual; ImageCompare.differenceOffset = 0; } diff --git a/src/pelib/PeLibAux.cpp b/src/pelib/PeLibAux.cpp index 4418c64be..16d373d95 100644 --- a/src/pelib/PeLibAux.cpp +++ b/src/pelib/PeLibAux.cpp @@ -22,8 +22,6 @@ namespace PeLib { - const std::uint64_t PELIB_IMAGE_ORDINAL_FLAGS<64>::PELIB_IMAGE_ORDINAL_FLAG = 0x8000000000000000ULL; - // Keep in sync with PeLib::LoaderError!!! static const std::vector LdrErrStrings = { diff --git a/src/unpackertool/plugins/mpress/mpress.h b/src/unpackertool/plugins/mpress/mpress.h index ea117eb51..b5bd576ae 100644 --- a/src/unpackertool/plugins/mpress/mpress.h +++ b/src/unpackertool/plugins/mpress/mpress.h @@ -8,7 +8,7 @@ #define UNPACKERTOOL_PLUGINS_MPRESS_MPRESS_H #include "retdec/loader/loader.h" -#include "retdec/pelib/PeLib.h" +#include "retdec/pelib/PeFile.h" #include "retdec/utils/dynamic_buffer.h" #include "retdec/unpacker/plugin.h" diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp index f49c61e55..22618ddff 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp @@ -7,7 +7,7 @@ #include #include -#include "retdec/pelib/PeLib.h" +#include "retdec/pelib/PeFile.h" #include "retdec/utils/alignment.h" #include "retdec/utils/file_io.h" #include "unpackertool/plugins/upx/decompressors/decompressors.h" @@ -565,8 +565,8 @@ template UpxExtraData PeUpxStub::parseExtraData(DynamicBuffer& const PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); std::uint16_t numberOfSections = unpackedData.read(originalHeaderOffset + sizeof(PeLib::PELIB_IMAGE_NT_SIGNATURE) + 0x2); - std::uint32_t numberOfDirectories = unpackedData.read(originalHeaderOffset + imageLoader.getFieldOffset(PeLib::OPTHDR_NumberOfRvaAndSizes)); - std::uint32_t dataDirectoriesStart = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory); + std::uint32_t numberOfDirectories = unpackedData.read(originalHeaderOffset + imageLoader.getFieldOffset(PeLib::PELIB_MEMBER_TYPE::OPTHDR_NumberOfRvaAndSizes)); + std::uint32_t dataDirectoriesStart = imageLoader.getFieldOffset(PeLib::PELIB_MEMBER_TYPE::OPTHDR_DataDirectory); std::uint32_t sectionHeadersStart = dataDirectoriesStart + numberOfDirectories * PeLib::PELIB_IMAGE_DATA_DIRECTORY::size(); std::uint32_t sectionHeadersEnd = sectionHeadersStart + sizeof(PeLib::PELIB_IMAGE_SECTION_HEADER) * numberOfSections; @@ -794,7 +794,7 @@ template void PeUpxStub::fixRelocations(DynamicBuffer& unpacked template void PeUpxStub::fixTls(const DynamicBuffer& originalHeader) { PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); - std::uint32_t tlsDirOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_TLS_Rva); + std::uint32_t tlsDirOffset = imageLoader.getFieldOffset(PeLib::PELIB_MEMBER_TYPE::OPTHDR_DataDirectory_TLS_Rva); // Read original TLS data directory std::uint32_t tlsRva = originalHeader.read(tlsDirOffset); @@ -836,7 +836,7 @@ template void PeUpxStub::fixOep(const DynamicBuffer& originalHe template void PeUpxStub::fixExports(const DynamicBuffer& originalHeader) { PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); - std::uint32_t exportDirOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_EXPORT_Rva); + std::uint32_t exportDirOffset = imageLoader.getFieldOffset(PeLib::PELIB_MEMBER_TYPE::OPTHDR_DataDirectory_EXPORT_Rva); // Assumption is that exports are compressed _exportsCompressed = true; @@ -927,7 +927,7 @@ template void PeUpxStub::fixExports(const DynamicBuffer& origin template void PeUpxStub::fixLoadConfiguration(const DynamicBuffer& originalHeader) { PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); - std::uint32_t configDirOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_CONFIG_Rva); + std::uint32_t configDirOffset = imageLoader.getFieldOffset(PeLib::PELIB_MEMBER_TYPE::OPTHDR_DataDirectory_CONFIG_Rva); // Read original Load Configuration data directory std::uint32_t loadConfigRva = originalHeader.read(configDirOffset); @@ -956,7 +956,7 @@ template void PeUpxStub::fixResources(const DynamicBuffer& unpa { PeLib::PELIB_IMAGE_SECTION_HEADER * pSectionHeader; PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); - std::uint32_t rsrcDirOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_RSRC_Rva); + std::uint32_t rsrcDirOffset = imageLoader.getFieldOffset(PeLib::PELIB_MEMBER_TYPE::OPTHDR_DataDirectory_RSRC_Rva); // Check whether file contains resources std::uint32_t uncompressedRsrcRva = imageLoader.getDataDirRva(PeLib::PELIB_IMAGE_DIRECTORY_ENTRY_RESOURCE); @@ -1020,8 +1020,8 @@ template void PeUpxStub::fixSectionHeaders(const DynamicBuffer& { PeLib::ImageLoader & imageLoader = _newPeFile->imageLoader(); std::uint16_t numberOfSections = originalHeader.read(6); - std::uint32_t numberOfDirectories = originalHeader.read(imageLoader.getFieldOffset(PeLib::OPTHDR_NumberOfRvaAndSizes)); - std::uint32_t sectionHeadersOffset = imageLoader.getFieldOffset(PeLib::OPTHDR_DataDirectory_EXPORT_Rva) + numberOfDirectories * 8; + std::uint32_t numberOfDirectories = originalHeader.read(imageLoader.getFieldOffset(PeLib::PELIB_MEMBER_TYPE::OPTHDR_NumberOfRvaAndSizes)); + std::uint32_t sectionHeadersOffset = imageLoader.getFieldOffset(PeLib::PELIB_MEMBER_TYPE::OPTHDR_DataDirectory_EXPORT_Rva) + numberOfDirectories * 8; std::uint32_t sectionHeadersEnd = sectionHeadersOffset + sizeof(PeLib::PELIB_IMAGE_SECTION_HEADER) * numberOfSections; std::uint32_t readPos = sectionHeadersOffset; diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h index 60445be50..263cb6488 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h @@ -10,7 +10,7 @@ #include #include "unpackertool/plugins/upx/upx_stub.h" -#include "retdec/pelib/PeLib.h" +#include "retdec/pelib/PeFile.h" #include "retdec/utils/dynamic_buffer.h" #include "retdec/unpacker/signature.h" diff --git a/src/unpackertool/plugins/upx/upx.cpp b/src/unpackertool/plugins/upx/upx.cpp index 7e8f6496e..816d7846e 100644 --- a/src/unpackertool/plugins/upx/upx.cpp +++ b/src/unpackertool/plugins/upx/upx.cpp @@ -12,7 +12,7 @@ #include "unpackertool/plugins/upx/upx.h" #include "unpackertool/plugins/upx/upx_exceptions.h" #include "unpackertool/plugins/upx/upx_stub_signatures.h" -#include "retdec/pelib/PeLib.h" +#include "retdec/pelib/PeFile.h" #include "retdec/unpacker/unpacker_exception.h" using namespace retdec::unpacker;