From f3df211cb45da298c9d87cf558c990d9732df28a Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Fri, 22 May 2020 16:02:51 +0200 Subject: [PATCH 1/3] Added detection of in-memory layout PE files --- include/retdec/pelib/PeFile.h | 86 ++++++++++++++++++++++----------- include/retdec/pelib/PeLibAux.h | 3 ++ src/pelib/PeLibAux.cpp | 3 ++ 3 files changed, 63 insertions(+), 29 deletions(-) diff --git a/include/retdec/pelib/PeFile.h b/include/retdec/pelib/PeFile.h index 5bf27cf7d..4e249602e 100644 --- a/include/retdec/pelib/PeFile.h +++ b/include/retdec/pelib/PeFile.h @@ -213,6 +213,7 @@ namespace PeLib /// Checks the entry point code LoaderError checkEntryPointErrors() const; + LoaderError checkForInMemoryLayout(LoaderError ldrError) const; /// Returns a loader error, if there was any LoaderError loaderError() const; @@ -738,55 +739,82 @@ namespace PeLib return LDR_ERROR_NONE; } + template + LoaderError PeFileT::checkForInMemoryLayout(LoaderError ldrError) const + { + std::uint64_t ulFileSize = fileSize(m_iStream); + std::uint64_t sizeOfImage = peHeader().getSizeOfImage(); + + // The file size must be greater or equal to SizeOfImage + if(ulFileSize >= sizeOfImage) + { + // SectionAlignment must be greater than file alignment + if(peHeader().getSectionAlignment() > peHeader().getFileAlignment()) + { + // SizeOfHeaders must be smaller than SectionAlignment + if(peHeader().getSizeOfHeaders() < peHeader().getSectionAlignment()) + { + std::size_t headerDataSize = peHeader().getSectionAlignment() - peHeader().getSizeOfHeaders(); + + // Read the entire after-header-data + std::vector headerData(headerDataSize); + m_iStream.seekg(peHeader().getSizeOfHeaders(), 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 { - LoaderError ldrError; - - // Was there a problem in the DOS header? - ldrError = mzHeader().loaderError(); - if (ldrError != LDR_ERROR_NONE) - return ldrError; + // Check for problems in DOS header + LoaderError ldrError = mzHeader().loaderError(); // Was there a problem in the NT headers? - ldrError = peHeader().loaderError(); - if (ldrError != LDR_ERROR_NONE) - return ldrError; + if (ldrError == LDR_ERROR_NONE) + ldrError = peHeader().loaderError(); // Check the loader error - ldrError = coffSymTab().loaderError(); - if (ldrError != LDR_ERROR_NONE) - return ldrError; + if (ldrError == LDR_ERROR_NONE) + ldrError = coffSymTab().loaderError(); // Check errors in import directory - ldrError = impDir().loaderError(); - if (ldrError != LDR_ERROR_NONE) - return ldrError; + if (ldrError == LDR_ERROR_NONE) + ldrError = impDir().loaderError(); // Check errors in resource directory - ldrError = resDir().loaderError(); - if (ldrError != LDR_ERROR_NONE) - return ldrError; + if (ldrError == LDR_ERROR_NONE) + ldrError = resDir().loaderError(); // Check errors in relocations directory - ldrError = relocDir().loaderError(); - if (ldrError != LDR_ERROR_NONE) - return ldrError; + 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 - ldrError = checkEntryPointErrors(); - if (ldrError != LDR_ERROR_NONE) - return ldrError; + if (ldrError == LDR_ERROR_NONE) + ldrError = checkEntryPointErrors(); - // Check errors in security directory - ldrError = securityDir().loaderError(); - if (ldrError != LDR_ERROR_NONE) - return ldrError; + // 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 LDR_ERROR_NONE; + return ldrError; } } diff --git a/include/retdec/pelib/PeLibAux.h b/include/retdec/pelib/PeLibAux.h index 262355a0f..34af2ced8 100644 --- a/include/retdec/pelib/PeLibAux.h +++ b/include/retdec/pelib/PeLibAux.h @@ -113,6 +113,9 @@ namespace PeLib LDR_ERROR_RELOC_BLOCK_INVALID_LENGTH, // A relocation block has invalid length LDR_ERROR_RELOC_ENTRY_BAD_TYPE, // A relocation entry has invalid type + // Other errors + LDR_ERROR_INMEMORY_IMAGE, // The file is a 1:1 in-memory image + LDR_ERROR_MAX }; diff --git a/src/pelib/PeLibAux.cpp b/src/pelib/PeLibAux.cpp index 85eda8be7..b64ff1a7f 100644 --- a/src/pelib/PeLibAux.cpp +++ b/src/pelib/PeLibAux.cpp @@ -91,6 +91,9 @@ namespace PeLib {"LDR_ERROR_RELOC_BLOCK_INVALID_LENGTH", "A relocation block has invalid length", true }, {"LDR_ERROR_RELOC_ENTRY_BAD_TYPE", "A relocation entry has invalid type", true }, + // Other errors + {"LDR_ERROR_INMEMORY_IMAGE", "The file is an in-memory image", false }, + }; PELIB_IMAGE_FILE_MACHINE_ITERATOR::PELIB_IMAGE_FILE_MACHINE_ITERATOR() From 39375e370536e89a9087a5676838d1aa8a931f4a Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Fri, 22 May 2020 16:04:47 +0200 Subject: [PATCH 2/3] Fixed indentation --- src/pelib/PeLibAux.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pelib/PeLibAux.cpp b/src/pelib/PeLibAux.cpp index b64ff1a7f..350fade95 100644 --- a/src/pelib/PeLibAux.cpp +++ b/src/pelib/PeLibAux.cpp @@ -92,7 +92,7 @@ namespace PeLib {"LDR_ERROR_RELOC_ENTRY_BAD_TYPE", "A relocation entry has invalid type", true }, // Other errors - {"LDR_ERROR_INMEMORY_IMAGE", "The file is an in-memory image", false }, + {"LDR_ERROR_INMEMORY_IMAGE", "The file is an in-memory image", false }, }; From 718faf19bd3cbe11ed6a5e0fa68b3a23df3dbde5 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Sat, 23 May 2020 06:06:54 +0200 Subject: [PATCH 3/3] Added check for section alignment --- include/retdec/pelib/PeFile.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/retdec/pelib/PeFile.h b/include/retdec/pelib/PeFile.h index 4e249602e..ca3b70985 100644 --- a/include/retdec/pelib/PeFile.h +++ b/include/retdec/pelib/PeFile.h @@ -748,13 +748,17 @@ 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(); + // SectionAlignment must be greater than file alignment - if(peHeader().getSectionAlignment() > peHeader().getFileAlignment()) + if(sectionAlignment >= PELIB_PAGE_SIZE && sectionAlignment > fileAlignment) { // SizeOfHeaders must be smaller than SectionAlignment - if(peHeader().getSizeOfHeaders() < peHeader().getSectionAlignment()) + if(sizeOfHeaders < sectionAlignment) { - std::size_t headerDataSize = peHeader().getSectionAlignment() - peHeader().getSizeOfHeaders(); + std::size_t headerDataSize = sectionAlignment - sizeOfHeaders; // Read the entire after-header-data std::vector headerData(headerDataSize);