Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lz include relocation into image load #1063

Merged
merged 2 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion include/retdec/fileformat/file_format/pe/pe_format_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ class PeFormatParser
const auto imageBase = peFile->imageLoader().getImageBase();
const auto bits = peFile->imageLoader().getImageBitability();
std::string importName;
std::uint64_t addressMask = (bits == 0x20) ? 0xFFFFFFFF : 0xFFFFFFFFFFFFFFFF;
std::uint32_t ordinalNumber = 0;
std::uint32_t patchRva = 0;
std::uint16_t importHint = 0;
Expand All @@ -362,7 +363,10 @@ class PeFormatParser
import->setName(importName);

import->setLibraryIndex(fileIndex);
import->setAddress(imageBase + patchRva);

// Don't allow address overflow for samples with high image bases
// (342EE6CCB04AB0194275360EE6F752007B9F0CE5420203A41C8C9B5BAC7626DD)
import->setAddress((imageBase + patchRva) & addressMask);
return import;
}

Expand Down
9 changes: 5 additions & 4 deletions include/retdec/pelib/ImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ class ImageLoader

ImageLoader(std::uint32_t loaderFlags = 0);

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);
int Load(ByteBuffer & fileData, std::uint32_t loadFlags = 0);
int Load(std::istream & fs, std::streamoff fileOffset = 0, std::uint32_t loadFlags = 0);
int Load(const char * fileName, std::uint32_t loadFlags = 0);

int Save(std::ostream & fs, std::streamoff fileOffset = 0, std::uint32_t saveFlags = 0);
int Save(const char * fileName, std::uint32_t saveFlags = 0);
Expand Down Expand Up @@ -410,7 +410,7 @@ class ImageLoader
int captureSectionHeaders(ByteBuffer & fileData);
int saveSectionHeadersNew(std::ostream & fs, std::streamoff fileOffset);
int saveSectionHeaders(std::ostream & fs, std::streamoff fileOffset);
int captureImageSections(ByteBuffer & fileData);
int captureImageSections(ByteBuffer & fileData, std::uint32_t loadFlags);
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);
std::uint32_t copyDataDirectories(std::uint8_t * optionalHeaderPtr, std::uint8_t * dataDirectoriesPtr, std::size_t optionalHeaderMax, std::uint32_t numberOfRvaAndSizes);
Expand All @@ -436,6 +436,7 @@ class ImageLoader
bool isLegacyImageArchitecture(std::uint16_t Machine);
bool checkForValid64BitMachine();
bool checkForValid32BitMachine();
bool checkForInvalidImageRange();
bool isValidMachineForCodeIntegrifyCheck(std::uint32_t Bits);
bool checkForSectionTablesWithinHeader(std::uint32_t e_lfanew);
bool checkForBadCodeIntegrityImages(ByteBuffer & fileData);
Expand Down
56 changes: 47 additions & 9 deletions src/pelib/ImageLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -912,9 +912,10 @@ PeLib::LoaderError PeLib::ImageLoader::loaderError() const

//-----------------------------------------------------------------------------
// Interface for loading files

int PeLib::ImageLoader::Load(
ByteBuffer & fileData,
bool loadHeadersOnly)
std::uint32_t loadFlags)
{
int fileError;

Expand Down Expand Up @@ -942,7 +943,7 @@ int PeLib::ImageLoader::Load(
setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE);

// Shall we map the image content?
if(loadHeadersOnly == false)
if(!(loadFlags & IoFlagHeadersOnly))
{
// Large amount of memory may be allocated during loading the image to memory.
// We need to handle low memory condition carefully here
Expand All @@ -951,14 +952,26 @@ int PeLib::ImageLoader::Load(
// If there was no detected image error, map the image as if Windows loader would do
if(isImageLoadable())
{
fileError = captureImageSections(fileData);
fileError = captureImageSections(fileData, loadFlags);

// If needed, also perform image load config directory check
if(fileError == ERROR_NONE)
{
if(checkImagePostMapping && checkForImageAfterMapping())
setLoaderError(LDR_ERROR_IMAGE_NON_EXECUTABLE);
}

// Fix for imaged that modify themselves via relocations
// Sample: 342EE6CCB04AB0194275360EE6F752007B9F0CE5420203A41C8C9B5BAC7626DD
// Modifies code and import directory via relocation table.
// This only works in Windows 7 or newer
if(ldrError == LDR_ERROR_NONE && checkForInvalidImageRange())
{
// The image is gonna be relocated to address 0x10000,
// which is the first valid base address that can happen
// The relocation is done by ntdll!LdrpProtectAndRelocateImage -> ntdll!LdrRelocateImage
relocateImage(0x10000);
}
}

// If there was any kind of error that prevents the image from being mapped,
Expand All @@ -980,7 +993,7 @@ int PeLib::ImageLoader::Load(
int PeLib::ImageLoader::Load(
std::istream & fs,
std::streamoff fileOffset,
bool loadHeadersOnly)
std::uint32_t loadFlags)
{
ByteBuffer fileData;
std::streampos fileSize;
Expand Down Expand Up @@ -1032,18 +1045,18 @@ int PeLib::ImageLoader::Load(
}

// Call the Load interface on char buffer
return Load(fileData, loadHeadersOnly);
return Load(fileData, loadFlags);
}

int PeLib::ImageLoader::Load(
const char * fileName,
bool loadHeadersOnly)
std::uint32_t loadFlags)
{
std::ifstream fs(fileName, std::ifstream::in | std::ifstream::binary);
if(!fs.is_open())
return ERROR_OPENING_FILE;

return Load(fs, loadHeadersOnly);
return Load(fs, 0, loadFlags);
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -2193,7 +2206,7 @@ int PeLib::ImageLoader::saveSectionHeaders(
return saveToFile(fs, fileOffset, offsetOfHeaders, sizeOfHeaders);
}

int PeLib::ImageLoader::captureImageSections(ByteBuffer & fileData)
int PeLib::ImageLoader::captureImageSections(ByteBuffer & fileData, std::uint32_t loadFlags)
{
std::uint32_t virtualAddress = 0;
std::uint32_t sizeOfHeaders = optionalHeader.SizeOfHeaders;
Expand Down Expand Up @@ -2224,10 +2237,13 @@ int PeLib::ImageLoader::captureImageSections(ByteBuffer & fileData)
{
for(auto & sectionHeader : sections)
{
// If loading as image, we need to take data from its virtual address
std::uint32_t pointerToRawData = (loadFlags & IoFlagLoadAsImage) ? sectionHeader.VirtualAddress : sectionHeader.PointerToRawData;

// Capture all pages from the section
if(captureImageSection(fileData, sectionHeader.VirtualAddress,
sectionHeader.VirtualSize,
sectionHeader.PointerToRawData,
pointerToRawData,
sectionHeader.SizeOfRawData,
sectionHeader.Characteristics) == 0)
{
Expand Down Expand Up @@ -2668,6 +2684,28 @@ bool PeLib::ImageLoader::checkForValid32BitMachine()
return (fileHeader.Machine == PELIB_IMAGE_FILE_MACHINE_I386);
}

bool PeLib::ImageLoader::checkForInvalidImageRange()
{
// Only do the check for 32-bit images
if(optionalHeader.Magic == PELIB_IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
std::uint64_t MmHighestUserAddress = 0x7FFEFFFF;
std::uint64_t MmHighestImageBase = MmHighestUserAddress - 0x10000;
std::uint64_t MmLowestImageBase = 0x00010000;
std::uint64_t ImageBase = optionalHeader.ImageBase;
std::uint32_t AlignedSizeOfImage = AlignToSize(optionalHeader.SizeOfImage, PELIB_PAGE_SIZE);

// If any part of the image goes out of the allowed range, it's invalid
// Windows will do the same check and relocate the image if possible
if(ImageBase < MmLowestImageBase || ImageBase > MmHighestImageBase || (ImageBase + AlignedSizeOfImage) > MmHighestImageBase)
{
return true;
}
}

return false;
}

bool PeLib::ImageLoader::isValidMachineForCodeIntegrifyCheck(std::uint32_t Bits)
{
if(Bits & 64)
Expand Down