blob: c032dc3619d075502f68aa8052ca86981e44aa4f [file] [log] [blame]
// Copyright 2012 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.
#ifndef SYZYGY_PE_PE_FILE_PARSER_H_
#define SYZYGY_PE_PE_FILE_PARSER_H_
#include "base/callback.h"
#include "syzygy/block_graph/block_graph.h"
#include "syzygy/core/address.h"
#include "syzygy/pe/pe_file.h"
namespace pe {
// Forward declaration.
template <class ItemType> class PEFileStructPtr;
// This class parses the PE image data in an PEImage instance, chunks out
// the image header and various other PE image sections to an address space.
class PEFileParser {
public:
typedef block_graph::BlockGraph BlockGraph;
typedef core::RelativeAddress RelativeAddress;
typedef base::Callback<bool(RelativeAddress,
BlockGraph::ReferenceType,
BlockGraph::Size,
RelativeAddress)>
AddReferenceCallback;
// Callback that is invoked for every named import thunk that is parsed. The
// arguments are as follows:
// 1. const char* module_name
// The name of the module being imported.
// 2. const char* symbol_name
// The name of the imported symbol.
// 3. BlockGraph::Block* thunk
// The block containing the thunk which will be initialized to point to
// the symbol at runtime.
typedef base::Callback<bool(const char*,
const char*,
BlockGraph::Block*)>
OnImportThunkCallback;
PEFileParser(const PEFile& image_file,
BlockGraph::AddressSpace* address_space,
const AddReferenceCallback& add_reference);
struct PEHeader {
PEHeader() {
memset(this, 0, sizeof(*this));
}
// The block that describes the DOS header, including the DOS stub.
BlockGraph::Block* dos_header;
// The block that describes the NT and the section headers.
BlockGraph::Block* nt_headers;
// The blocks that describe the data directory chunks.
BlockGraph::Block* data_directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
};
void set_on_import_thunk(const OnImportThunkCallback& on_import_thunk) {
on_import_thunk_ = on_import_thunk;
}
// Parses the image, chunks the various blocks it decomposes into and
// invokes the AddReferenceCallback for all references encountered.
bool ParseImage(PEHeader* pe_header);
// Tables of thunks come in various flavours.
enum ThunkTableType {
// For parsing of normal imports.
kImportNameTable,
kImportAddressTable,
// For parsing of delay-load imports.
kDelayLoadImportNameTable,
kDelayLoadImportAddressTable,
kDelayLoadBoundImportAddressTable,
};
// Thunks in import tables may point to various discrete things. These depend
// on the ThunkTableType and whether or not the table is bound.
enum ThunkDataType {
kNullThunkData, // Pointer values should all be NULL.
kImageThunkData, // IMAGE_THUNK_DATA containing RelativeAddress to a string
// in the image.
kCodeInImageThunkData, // AbsoluteAddress in image.
kCodeOutOfImageThunkData, // AbsoluteAddress out of image.
kArbitraryThunkData, // Anything goes.
};
protected:
// Parses the image header, chunks the various blocks it refers and
// invokes the AddReferenceCallback for all references encountered.
bool ParseImageHeader(PEHeader* pe_header);
// These methods parse a given data directory section, chunk out the blocks
// and create references as they're encountered.
// @param dir the data directory entry.
// @returns the chunked block for that directory, or NULL on error.
// IMAGE_DIRECTORY_ENTRY_EXPORT
BlockGraph::Block* ParseExportDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_IMPORT
BlockGraph::Block* ParseImportDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_RESOURCE
BlockGraph::Block* ParseResourceDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_EXCEPTION
BlockGraph::Block* ParseExceptionDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_SECURITY
BlockGraph::Block* ParseSecurityDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_BASERELOC
BlockGraph::Block* ParseRelocDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_DEBUG
BlockGraph::Block* ParseDebugDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_ARCHITECTURE
BlockGraph::Block* ParseArchitectureDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_GLOBALPTR
BlockGraph::Block* ParseGlobalDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_TLS
BlockGraph::Block* ParseTlsDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
BlockGraph::Block* ParseLoadConfigDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
BlockGraph::Block* ParseBoundImportDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_IAT
BlockGraph::Block* ParseIatDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
BlockGraph::Block* ParseDelayImportDir(const IMAGE_DATA_DIRECTORY& dir);
// IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
BlockGraph::Block* ParseComDescriptorDir(const IMAGE_DATA_DIRECTORY& dir);
private:
// Counts the number of import thunks in the run starting at thunk_start.
// @returns the number of thunks excluding the terminating sentinel, or
// zero on error.
size_t CountImportThunks(RelativeAddress thunk_start);
// Parses the IAT/INT/BoundIAT starting at thunk_start.
// @param thunk_start the RVA where the import thunks start.
// @param is_bound true iff thunks are bound, in which case we tag absolute
// references instead of relative. This may only be true if table_type is
// kImportAddressTable or kDelayLoadImportAddressTable.
// @param table_type the type of thunk table.
// @param thunk_type human readable type for thunk.
// @param import_name name of imported dll.
// @returns true on success, false otherwise.
bool ParseImportThunks(RelativeAddress thunk_start,
size_t num_thunks,
bool is_bound,
ThunkTableType table_type,
const char* thunk_type,
const char* import_name);
// Parse a single entry in an import table.
// @param thunk_addr the address of the thunk.
// @param thunk_data_type the type of data in the thunk.
// @param thunk_type human readable type for thunk.
// @param chunk_name if true, and thunk_data_type is kImageThunkData, will
// parse out the referenced IMAGE_THUNK_DATA as a block.
// @returns true on success, false otherwise.
bool ParseImportThunk(RelativeAddress thunk_addr,
ThunkDataType thunk_data_type,
const char* thunk_type,
const char* module_name,
bool chunk_name);
// Special handling for delay-load bound import address tables. We've seen
// cases in actual binaries where these are malformed. This is generally not
// an issue, but we handle these a little more loosely so that we can complete
// the decomposition process. If such malformed tables are encountered, this
// will causes a warning to be logged.
// @param iat_addr the beginning of the delay-load bound IAT.
// @param iat_size the expected size of the delay-load bound IAT.
// @param iat_name the name to give the chunked block, or the label to
// associate with iat_addr in an existing block.
// @returns the block containing the delay-load IAT table.
BlockGraph::Block* ChunkDelayBoundIATBlock(RelativeAddress iat_addr,
size_t iat_size,
const char* iat_name);
BlockGraph::Block* AddBlock(BlockGraph::BlockType type,
RelativeAddress addr,
BlockGraph::Size size,
const char* name);
bool AddReference(RelativeAddress src,
BlockGraph::ReferenceType type,
BlockGraph::Size size,
RelativeAddress dst);
template <typename ItemType>
bool AddRelative(const PEFileStructPtr<ItemType>& structure,
const DWORD* item);
template <typename ItemType>
bool AddAbsolute(const PEFileStructPtr<ItemType>& structure,
const DWORD* item);
template <typename ItemType>
bool AddFileOffset(const PEFileStructPtr<ItemType>& structure,
const DWORD* item);
bool ParseResourceDirImpl(BlockGraph::Block* resource_block,
size_t root_offset);
// Pointer to a data dir parser function.
typedef BlockGraph::Block* (PEFileParser::*ParseDirFunction)(
const IMAGE_DATA_DIRECTORY& dir);
struct DataDirParseEntry {
int entry;
const char* name;
ParseDirFunction parser;
};
// Array of data directory parser entries used to parse the
// sundry data directory entries.
static const DataDirParseEntry parsers_[];
const PEFile& image_file_;
BlockGraph::AddressSpace* address_space_;
AddReferenceCallback add_reference_;
OnImportThunkCallback on_import_thunk_;
};
} // namespace pe
#endif // SYZYGY_PE_PE_FILE_PARSER_H_