blob: 43e412139c98f75f483a67d9ec66a23ee86d6680 [file] [log] [blame]
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Common definitions and helper routines for reading both PE and COFF
// file formats.
#ifndef SYZYGY_PE_PE_COFF_FILE_H_
#define SYZYGY_PE_PE_COFF_FILE_H_
#include <windows.h>
#include <winnt.h>
#include <map>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "syzygy/core/address.h"
#include "syzygy/core/address_space.h"
#include "syzygy/core/serialization.h"
namespace pe {
// This duplicates a similar constant in the core namespace, declared by
// block_graph.h. We duplicate it here so as not to add an uneccessary
// dependency.
// Header data and other data not from a regular section is considered as
// being from an invalid section.
const size_t kInvalidSection = -1;
// Base class for PE and COFF file readers, parameterized with an
// address and a size type, wrapped in a traits class. The base class
// defines an address space, in which data ranges from the input file
// should be mapped. The template address and size types define the
// resulting address space.
//
// PECoffFile observes the following address range separation rules:
// - All headers live in a single range.
// - Each section lives in its own data range.
// - Other data may be added by child classes, and live in ranges
// different from the above.
//
// The address traits class @p AddressSpaceTraits should define the
// following members:
//
// @code
// struct AddressSpaceTraits {
// // The type of addresses native to the address space of the reader.
// typedef ... AddressType;
// // The type of sizes native to the address space of the reader.
// typedef ... SizeType;
//
// // Return an address different from all valid addresses for the
// // specified address type.
// static const AddressType invalid_address();
//
// // Return the address at which to insert global headers.
// static const AddressType header_address();
//
// // Return the address where the corresponding section should be
// // mapped, or invalid_address() if the section should not be mapped.
// static AddressType GetSectionAddress(const IMAGE_SECTION_HEADER& header);
//
// // Return the number of bytes of the corresponding section to map
// // to the resulting address space.
// static SizeType GetSectionSize(const IMAGE_SECTION_HEADER& header);
// };
// @endcode
//
// @tparam AddressSpaceTraits traits describing the types of the
// resulting address map.
// address map.
template <typename AddressSpaceTraits>
class PECoffFile {
public:
// The type of addresses native to this reader.
typedef typename AddressSpaceTraits::AddressType AddressType;
// The type of sizes native to this reader.
typedef typename AddressSpaceTraits::SizeType SizeType;
// The type of addresses referring to the on-disk file.
typedef core::FileOffsetAddress FileOffsetAddress;
// Return the address where the header is expected to be found,
// after a successful call to Init().
//
// @returns the address of the header range.
static AddressType header_address() {
return AddressSpaceTraits::header_address();
}
// @returns the path of the input file read, if any.
const base::FilePath& path() const { return path_; }
// Copy mapped data to buffer. The specified range to read must be
// contained within the image, and cannot cross data ranges from the
// original file; in particular, sections with no gaps between them
// must still be read separately.
//
// @param addr the address where the data is mapped.
// @param data the buffer to write the data to.
// @param len the number of bytes to copy.
// @returns true on success, false on error.
bool ReadImage(AddressType addr, void* data, SizeType len) const;
// Copy mapped zero-terminated string data to string object.
//
// @param addr the address where the data is mapped.
// @param str the string to write the data to.
// @returns true on success, false on error.
bool ReadImageString(AddressType addr, std::string* str) const;
// Retrieve a pointer to the internal buffer containing mapped
// data. The specified range to read must be contained within the
// image, and cannot cross data ranges from the original file; in
// particular, sections with no gaps between them must still be read
// separately.
//
// @param addr the address where the data is mapped.
// @param len the number of bytes that will be accessed through the
// returned pointer.
// @returns a pointer into the internal buffer for the data.
const uint8* GetImageData(AddressType addr, SizeType len) const;
// @copydoc GetImageData(AddressType,SizeType)
// The resulting buffer is mutable.
uint8* GetImageData(AddressType addr, SizeType len);
// Retrieve a pointer to the internal buffer containing mapped
// data assumed to be of type @p ItemType.
//
// @tparam ItemType the type of items to cast to.
// @param addr the address where the data is mapped.
// @param len the number of bytes that will be accessed through the
// returned pointer.
// @param item_ptr a pointer to the retrieved result.
// @returns true on success, false on error.
// @see GetImageData(AddressType,SizeType)
template <typename ItemType> bool GetImageData(
AddressType addr, SizeType len, const ItemType** item_ptr) const;
// @copydoc GetImageData()
// The resulting buffer is mutable.
template <typename ItemType> bool GetImageData(
AddressType addr, SizeType len, ItemType** item_ptr);
// Test whether an address range is entirely mapped.
//
// @param addr the start of the address range.
// @param len the length of the address range.
// @returns true if the range is mapped, false otherwise.
bool Contains(AddressType addr, SizeType len) const;
// Retrieve the index of the section containing the specified range.
//
// @param addr the start of the address range.
// @param len the length of the address range.
// @returns the section index, or kInvalidSection if none is found.
size_t GetSectionIndex(AddressType addr, SizeType len) const;
// Retrieve the section header structure of the section containing
// the specified range.
//
// @param addr the start of the address range.
// @param len the length of the address range.
// @returns the section header, or NULL if none is found.
const IMAGE_SECTION_HEADER* GetSectionHeader(AddressType addr,
SizeType len) const;
// Retrieve the short name of a section from its index.
//
// @param section_index the index of the section.
// @returns the name of the section.
std::string GetSectionName(size_t section_index) const;
// Read the short name embedded in @p section.
//
// @param section the section header to read.
// @returns the short name of the section.
static std::string GetSectionName(const IMAGE_SECTION_HEADER& section);
// @returns the COFF file header.
const IMAGE_FILE_HEADER* file_header() const {
return file_header_;
}
// @returns an array of all section headers.
// @note Use in combination with the NumberOfSections field of the
// COFF file header.
const IMAGE_SECTION_HEADER* section_headers() const {
return section_headers_;
}
// Retrieve the section header structure of a section from its index.
//
// @param num_section the index of the section.
// @returns a pointer to the header structure.
const IMAGE_SECTION_HEADER* section_header(size_t num_section) const {
if (file_header_ != NULL && num_section < file_header_->NumberOfSections)
return section_headers_ + num_section;
return NULL;
}
protected:
typedef std::vector<uint8> SectionBuffer;
struct SectionInfo {
SectionInfo() : id(kInvalidSection) {
}
size_t id;
SectionBuffer buffer;
};
typedef core::AddressSpace<AddressType, SizeType, SectionInfo>
ImageAddressSpace;
// Protected constructor, for derived classes only.
PECoffFile()
: file_header_(NULL),
section_headers_(NULL) {
}
~PECoffFile() {
}
// Set the file path.
//
// @param path the path to the input file.
void Init(const base::FilePath& path);
// Read headers common to both PE and COFF. Insert a range covering
// all headers, including unread headers; the range spans from the
// beginning of the file to the end of the known fixed headers (the
// section table).
//
// @param file the input file stream.
// @param file_header_start the offset where the COFF file header
// (IMAGE_FILE_HEADER) starts.
// @returns true on success, false on error.
bool ReadCommonHeaders(FILE* file, FileOffsetAddress file_header_start);
// Read section headers and insert a range for each section.
//
// @param file the input file stream.
// @returns true on success, false on error.
bool ReadSections(FILE* file);
// Insert a range into the address map, populated by data read from
// @p file.
//
// @param file the input file stream.
// @param start the file offset to start reading at.
// @param size the number of bytes to read.
// @param range the range to insert.
// @returns true on success, false on error.
bool InsertRangeReadAt(FILE* file, FileOffsetAddress start, size_t size,
const typename ImageAddressSpace::Range& range);
// Read bytes from @p file into the specified buffer.
//
// @param file the input file stream.
// @param pos the file offset to start reading at.
// @param buf the buffer where to place data.
// @param len the number of bytes to read.
static bool ReadAt(FILE* file, size_t pos, void* buf, size_t len);
base::FilePath path_;
const IMAGE_FILE_HEADER* file_header_;
const IMAGE_SECTION_HEADER* section_headers_;
// Contains all data in the image. The address space has a range defined
// for the header and each section in the image, with its associated
// SectionBuffer as the data.
ImageAddressSpace image_data_;
private:
DISALLOW_COPY_AND_ASSIGN(PECoffFile);
};
} // namespace pe
#include "syzygy/pe/pe_coff_file_impl.h"
#endif // SYZYGY_PE_PE_COFF_FILE_H_