177 lines
6.3 KiB
C++
177 lines
6.3 KiB
C++
// Copyright 2014 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef BASE_WIN_PE_IMAGE_READER_H_
|
|
#define BASE_WIN_PE_IMAGE_READER_H_
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <windows.h>
|
|
|
|
#include <memory>
|
|
|
|
#include "base/base_export.h"
|
|
|
|
namespace base {
|
|
namespace win {
|
|
|
|
// Parses headers and various data from a PE image. This parser is safe for use
|
|
// on untrusted data and works on PE files with different bitness from the
|
|
// current process. The PeImageReader is initialized after construction by
|
|
// passing the address and size of a PE file that has been read into memory -
|
|
// not loaded by the OS as an image. Parsing of a PE file that has been loaded
|
|
// as an image can be done with PEImage.
|
|
class BASE_EXPORT PeImageReader {
|
|
public:
|
|
enum WordSize {
|
|
WORD_SIZE_32,
|
|
WORD_SIZE_64,
|
|
};
|
|
|
|
// A callback invoked by EnumCertificates once for each attribute certificate
|
|
// entry in the image's attribute certificate table. |revision| and
|
|
// |certificate_type| identify the contents of |certificate_data| (which is of
|
|
// |certificate_data_size| bytes). |context| is the value provided by the
|
|
// caller to EnumCertificates(). Implementations must return true to continue
|
|
// the enumeration, or false to abort.
|
|
using EnumCertificatesCallback = bool (*)(uint16_t revision,
|
|
uint16_t certificate_type,
|
|
const uint8_t* certificate_data,
|
|
size_t certificate_data_size,
|
|
void* context);
|
|
|
|
PeImageReader();
|
|
|
|
PeImageReader(const PeImageReader&) = delete;
|
|
PeImageReader& operator=(const PeImageReader&) = delete;
|
|
|
|
~PeImageReader();
|
|
|
|
// Returns false if the given data does not appear to be a valid PE image.
|
|
bool Initialize(const uint8_t* image_data, size_t image_size);
|
|
|
|
// Returns the machine word size for the image.
|
|
WordSize GetWordSize();
|
|
|
|
const IMAGE_DOS_HEADER* GetDosHeader();
|
|
const IMAGE_FILE_HEADER* GetCoffFileHeader();
|
|
|
|
// Returns a pointer to the optional header and its size.
|
|
const uint8_t* GetOptionalHeaderData(size_t* optional_data_size);
|
|
size_t GetNumberOfSections();
|
|
const IMAGE_SECTION_HEADER* GetSectionHeaderAt(size_t index);
|
|
|
|
// Returns a pointer to the image's export data (.edata) section and its size,
|
|
// or nullptr if the section is not present.
|
|
const uint8_t* GetExportSection(size_t* section_size);
|
|
|
|
size_t GetNumberOfDebugEntries();
|
|
const IMAGE_DEBUG_DIRECTORY* GetDebugEntry(size_t index,
|
|
const uint8_t** raw_data,
|
|
size_t* raw_data_size);
|
|
|
|
// Invokes |callback| once per attribute certificate entry. |context| is a
|
|
// caller-specific value that is passed to |callback|. Returns true if all
|
|
// certificate entries are visited (even if there are no such entries) and
|
|
// |callback| returns true for each. Conversely, returns |false| if |callback|
|
|
// returns false or if the image is malformed in any way.
|
|
bool EnumCertificates(EnumCertificatesCallback callback, void* context);
|
|
|
|
// Returns the size of the image file.
|
|
DWORD GetSizeOfImage();
|
|
|
|
private:
|
|
// Bits indicating what portions of the image have been validated.
|
|
enum ValidationStages {
|
|
VALID_DOS_HEADER = 1 << 0,
|
|
VALID_PE_SIGNATURE = 1 << 1,
|
|
VALID_COFF_FILE_HEADER = 1 << 2,
|
|
VALID_OPTIONAL_HEADER = 1 << 3,
|
|
VALID_SECTION_HEADERS = 1 << 4,
|
|
};
|
|
|
|
// An interface to an image's optional header.
|
|
class OptionalHeader {
|
|
public:
|
|
virtual ~OptionalHeader() = default;
|
|
|
|
virtual WordSize GetWordSize() = 0;
|
|
|
|
// Returns the offset of the DataDirectory member relative to the start of
|
|
// the optional header.
|
|
virtual size_t GetDataDirectoryOffset() = 0;
|
|
|
|
// Returns the number of entries in the data directory.
|
|
virtual DWORD GetDataDirectorySize() = 0;
|
|
|
|
// Returns a pointer to the first data directory entry.
|
|
virtual const IMAGE_DATA_DIRECTORY* GetDataDirectoryEntries() = 0;
|
|
|
|
// Returns the size of the image file.
|
|
virtual DWORD GetSizeOfImage() = 0;
|
|
};
|
|
|
|
template <class OPTIONAL_HEADER_TYPE>
|
|
class OptionalHeaderImpl;
|
|
|
|
void Clear();
|
|
bool ValidateDosHeader();
|
|
bool ValidatePeSignature();
|
|
bool ValidateCoffFileHeader();
|
|
bool ValidateOptionalHeader();
|
|
bool ValidateSectionHeaders();
|
|
|
|
// Return a pointer to the first byte of the image's optional header.
|
|
const uint8_t* GetOptionalHeaderStart();
|
|
size_t GetOptionalHeaderSize();
|
|
|
|
// Returns the desired directory entry, or nullptr if |index| is out of
|
|
// bounds.
|
|
const IMAGE_DATA_DIRECTORY* GetDataDirectoryEntryAt(size_t index);
|
|
|
|
// Returns the header for the section that contains the given address, or
|
|
// nullptr if the address is out of bounds or the image does not contain the
|
|
// section.
|
|
const IMAGE_SECTION_HEADER* FindSectionFromRva(uint32_t relative_address);
|
|
|
|
// Returns a pointer to the |data_length| bytes referenced by the |index|'th
|
|
// data directory entry.
|
|
const uint8_t* GetImageData(size_t index, size_t* data_length);
|
|
|
|
// Populates |structure| with a pointer to a desired structure of type T at
|
|
// the given offset if the image is sufficiently large to contain it. Returns
|
|
// false if the structure does not fully fit within the image at the given
|
|
// offset.
|
|
template <typename T>
|
|
bool GetStructureAt(size_t offset, const T** structure) {
|
|
return GetStructureAt(offset, sizeof(**structure), structure);
|
|
}
|
|
|
|
// Populates |structure| with a pointer to a desired structure of type T at
|
|
// the given offset if the image is sufficiently large to contain
|
|
// |structure_size| bytes. Returns false if the structure does not fully fit
|
|
// within the image at the given offset.
|
|
template <typename T>
|
|
bool GetStructureAt(size_t offset,
|
|
size_t structure_size,
|
|
const T** structure) {
|
|
if (offset > image_size_)
|
|
return false;
|
|
if (structure_size > image_size_ - offset)
|
|
return false;
|
|
*structure = reinterpret_cast<const T*>(image_data_ + offset);
|
|
return true;
|
|
}
|
|
|
|
const uint8_t* image_data_ = nullptr;
|
|
size_t image_size_ = 0;
|
|
uint32_t validation_state_ = 0;
|
|
std::unique_ptr<OptionalHeader> optional_header_;
|
|
};
|
|
|
|
} // namespace win
|
|
} // namespace base
|
|
|
|
#endif // BASE_WIN_PE_IMAGE_READER_H_
|