1 : // Copyright 2013 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : // Common definitions and helper routines for reading both PE and COFF
16 : // file formats.
17 :
18 : #ifndef SYZYGY_PE_PE_COFF_FILE_H_
19 : #define SYZYGY_PE_PE_COFF_FILE_H_
20 :
21 : #include <windows.h>
22 : #include <winnt.h>
23 : #include <map>
24 : #include <string>
25 : #include <vector>
26 :
27 : #include "base/files/file_path.h"
28 : #include "syzygy/common/buffer_parser.h"
29 : #include "syzygy/core/address.h"
30 : #include "syzygy/core/address_space.h"
31 : #include "syzygy/core/serialization.h"
32 :
33 : namespace pe {
34 :
35 : // These duplicate similar constants in the block_graph namespace, declared by
36 : // block_graph.h. We duplicate it here so as not to add an uneccessary
37 : // dependency.
38 : // Header data and other data not from a regular section is considered as
39 : // being from an invalid section.
40 : const size_t kInvalidSection = SIZE_MAX;
41 : const size_t kPointerSize = sizeof(void*);
42 :
43 : // Base class for PE and COFF file readers, parameterized with an
44 : // address and a size type, wrapped in a traits class. The base class
45 : // defines an address space, in which data ranges from the input file
46 : // should be mapped. The template address and size types define the
47 : // resulting address space.
48 : //
49 : // PECoffFile observes the following address range separation rules:
50 : // - All headers live in a single range.
51 : // - Each section lives in its own data range.
52 : // - Other data may be added by child classes, and live in ranges
53 : // different from the above.
54 : //
55 : // The address traits class @p AddressSpaceTraits should define the
56 : // following members:
57 : //
58 : // @code
59 : // struct AddressSpaceTraits {
60 : // // The type of addresses native to the address space of the reader.
61 : // typedef ... AddressType;
62 : // // The type of sizes native to the address space of the reader.
63 : // typedef ... SizeType;
64 : //
65 : // // Return an address different from all valid addresses for the
66 : // // specified address type.
67 : // static const AddressType invalid_address();
68 : //
69 : // // Return the address at which to insert global headers.
70 : // static const AddressType header_address();
71 : //
72 : // // Return the address where the corresponding section should be
73 : // // mapped, or invalid_address() if the section should not be mapped.
74 : // static AddressType GetSectionAddress(const IMAGE_SECTION_HEADER& header);
75 : //
76 : // // Return the number of bytes of the corresponding section to map
77 : // // to the resulting address space.
78 : // static SizeType GetSectionSize(const IMAGE_SECTION_HEADER& header);
79 : // };
80 : // @endcode
81 : //
82 : // @tparam AddressSpaceTraits traits describing the types of the
83 : // resulting address map.
84 : // address map.
85 : template <typename AddressSpaceTraits>
86 : class PECoffFile {
87 : public:
88 : // The type of addresses native to this reader.
89 : typedef typename AddressSpaceTraits::AddressType AddressType;
90 :
91 : // The type of sizes native to this reader.
92 : typedef typename AddressSpaceTraits::SizeType SizeType;
93 :
94 : // The type of addresses referring to the on-disk file.
95 : typedef core::FileOffsetAddress FileOffsetAddress;
96 :
97 : // Return the address where the header is expected to be found,
98 : // after a successful call to Init().
99 : //
100 : // @returns the address of the header range.
101 E : static AddressType header_address() {
102 E : return AddressSpaceTraits::header_address();
103 E : }
104 :
105 : // @returns the path of the input file read, if any.
106 E : const base::FilePath& path() const { return path_; }
107 :
108 : // Copy mapped data to buffer. The specified range to read must be
109 : // contained within the image, and cannot cross data ranges from the
110 : // original file; in particular, sections with no gaps between them
111 : // must still be read separately.
112 : //
113 : // @param addr the address where the data is mapped.
114 : // @param data the buffer to write the data to.
115 : // @param len the number of bytes to copy.
116 : // @returns true on success, false on error.
117 : bool ReadImage(AddressType addr, void* data, SizeType len) const;
118 :
119 : // Copy mapped zero-terminated string data to string object.
120 : //
121 : // @param addr the address where the data is mapped.
122 : // @param str the string to write the data to.
123 : // @returns true on success, false on error.
124 : bool ReadImageString(AddressType addr, std::string* str) const;
125 :
126 : // Retrieve a pointer to the internal buffer containing image data. If the
127 : // specified range to read is not wholly contained within the image this will
128 : // return nullptr. This allows reading across arbitrary section boundaries,
129 : // and also allows reading "unmapped" data.
130 : //
131 : // @param addr the address of the data.
132 : // @param len the number of bytes that will be accessed through the
133 : // returned pointer.
134 : // @returns a pointer into the internal buffer for the data, nullptr on
135 : // failure.
136 : const uint8_t* GetImageDataByFileOffset(FileOffsetAddress addr,
137 : SizeType len) const;
138 :
139 : // Retrieve a pointer to the internal buffer containing mapped
140 : // data. The specified range to read must be contained within the
141 : // image, and cannot cross data ranges from the original file; in
142 : // particular, sections with no gaps between them must still be read
143 : // separately.
144 : //
145 : // @param addr the address where the data is mapped.
146 : // @param len the number of bytes that will be accessed through the
147 : // returned pointer.
148 : // @returns a pointer into the internal buffer for the data.
149 : const uint8_t* GetImageData(AddressType addr, SizeType len) const;
150 :
151 : // @copydoc GetImageData(AddressType,SizeType)
152 : // The resulting buffer is mutable.
153 : uint8_t* GetImageData(AddressType addr, SizeType len);
154 :
155 : // Retrieve a pointer to the internal buffer containing mapped
156 : // data assumed to be of type @p ItemType.
157 : //
158 : // @tparam ItemType the type of items to cast to.
159 : // @param addr the address where the data is mapped.
160 : // @param len the number of bytes that will be accessed through the
161 : // returned pointer.
162 : // @param item_ptr a pointer to the retrieved result.
163 : // @returns true on success, false on error.
164 : // @see GetImageData(AddressType,SizeType)
165 : template <typename ItemType> bool GetImageData(
166 : AddressType addr, SizeType len, const ItemType** item_ptr) const;
167 :
168 : // @copydoc GetImageData()
169 : // The resulting buffer is mutable.
170 : template <typename ItemType> bool GetImageData(
171 : AddressType addr, SizeType len, ItemType** item_ptr);
172 :
173 : // Test whether an address range is entirely mapped.
174 : //
175 : // @param addr the start of the address range.
176 : // @param len the length of the address range.
177 : // @returns true if the range is mapped, false otherwise.
178 : bool Contains(AddressType addr, SizeType len) const;
179 :
180 : // Retrieve the index of the section containing the specified range.
181 : //
182 : // @param addr the start of the address range.
183 : // @param len the length of the address range.
184 : // @returns the section index, or kInvalidSection if none is found.
185 : size_t GetSectionIndex(AddressType addr, SizeType len) const;
186 :
187 : // Retrieve the section header structure of the section containing
188 : // the specified range.
189 : //
190 : // @param addr the start of the address range.
191 : // @param len the length of the address range.
192 : // @returns the section header, or NULL if none is found.
193 : const IMAGE_SECTION_HEADER* GetSectionHeader(AddressType addr,
194 : SizeType len) const;
195 :
196 : // Retrieve the short name of a section from its index.
197 : //
198 : // @param section_index the index of the section.
199 : // @returns the name of the section.
200 : std::string GetSectionName(size_t section_index) const;
201 :
202 : // Read the short name embedded in @p section.
203 : //
204 : // @param section the section header to read.
205 : // @returns the short name of the section.
206 : static std::string GetSectionName(const IMAGE_SECTION_HEADER& section);
207 :
208 : // @returns the COFF file header.
209 E : const IMAGE_FILE_HEADER* file_header() const {
210 E : return file_header_;
211 E : }
212 :
213 : // @returns an array of all section headers.
214 : // @note Use in combination with the NumberOfSections field of the
215 : // COFF file header.
216 E : const IMAGE_SECTION_HEADER* section_headers() const {
217 E : return section_headers_;
218 E : }
219 :
220 : // Retrieve the section header structure of a section from its index.
221 : //
222 : // @param num_section the index of the section.
223 : // @returns a pointer to the header structure.
224 E : const IMAGE_SECTION_HEADER* section_header(size_t num_section) const {
225 E : if (file_header_ != NULL && num_section < file_header_->NumberOfSections)
226 E : return section_headers_ + num_section;
227 E : return NULL;
228 E : }
229 :
230 : protected:
231 : struct SectionInfo {
232 : SectionInfo() : id(kInvalidSection), parser(nullptr, 0) {}
233 : SectionInfo(size_t id, const void* data, size_t length)
234 E : : id(id), parser(data, length) {}
235 : size_t id;
236 : common::BinaryBufferParser parser;
237 : };
238 :
239 : typedef core::AddressSpace<AddressType, SizeType, SectionInfo>
240 : ImageAddressSpace;
241 :
242 : // Protected constructor, for derived classes only.
243 : PECoffFile()
244 E : : file_header_(NULL),
245 E : section_headers_(NULL) {
246 E : }
247 :
248 E : ~PECoffFile() {
249 E : }
250 :
251 : // Set the file path and read all of its data.
252 : //
253 : // @param path the path to the input file.
254 : // @returns true on success, false on failure.
255 : bool Init(const base::FilePath& path);
256 :
257 : // Read headers common to both PE and COFF. Insert a range covering
258 : // all headers, including unread headers; the range spans from the
259 : // beginning of the file to the end of the known fixed headers (the
260 : // section table).
261 : //
262 : // @param file_header_start the offset where the COFF file header
263 : // (IMAGE_FILE_HEADER) starts.
264 : // @returns true on success, false on error.
265 : bool ReadCommonHeaders(FileOffsetAddress file_header_start);
266 :
267 : // Read section headers and insert a range for each section.
268 : //
269 : // @returns true on success, false on error.
270 : bool ReadSections();
271 :
272 : // Insert a section into the address map, backed by data in image_data_.
273 : //
274 : // @param id the id of the section.
275 : // @param start the file offset to start reading at.
276 : // @param size the number of bytes to read.
277 : // @param range the range to insert.
278 : // @returns true on success, false on error.
279 : bool InsertSection(size_t id,
280 : FileOffsetAddress start,
281 : size_t size,
282 : const typename ImageAddressSpace::Range& range);
283 :
284 : // Reads data from the file at the given offset.
285 : //
286 : // @param offset the offset to read.
287 : // @param destination the variable to be populated with the result.
288 : // @param size the number of bytes to read.
289 : // @returns true on success, false otherwise.
290 : bool ReadAt(size_t offset, void* destination, size_t size) const;
291 :
292 : base::FilePath path_;
293 : const IMAGE_FILE_HEADER* file_header_;
294 : const IMAGE_SECTION_HEADER* section_headers_;
295 :
296 : // Contains all of the data in the image, as a single contiguous buffer.
297 : std::string image_data_;
298 :
299 : // A parser for the image data. This takes care of bounds and alignment
300 : // checking.
301 : common::BinaryBufferParser parser_;
302 :
303 : // Contains all addressable data in the image. The address space has a range
304 : // defined for the header and each section in the image, backed by data in
305 : // |image_data_|.
306 : ImageAddressSpace address_space_;
307 :
308 : private:
309 : DISALLOW_COPY_AND_ASSIGN(PECoffFile);
310 : };
311 :
312 : } // namespace pe
313 :
314 : #include "syzygy/pe/pe_coff_file_impl.h"
315 :
316 : #endif // SYZYGY_PE_PE_COFF_FILE_H_
|