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/core/address.h"
29 : #include "syzygy/core/address_space.h"
30 : #include "syzygy/core/serialization.h"
31 :
32 : namespace pe {
33 :
34 : // This duplicates a similar constant in the core namespace, declared by
35 : // block_graph.h. We duplicate it here so as not to add an uneccessary
36 : // dependency.
37 : // Header data and other data not from a regular section is considered as
38 : // being from an invalid section.
39 : const size_t kInvalidSection = -1;
40 :
41 : // Base class for PE and COFF file readers, parameterized with an
42 : // address and a size type, wrapped in a traits class. The base class
43 : // defines an address space, in which data ranges from the input file
44 : // should be mapped. The template address and size types define the
45 : // resulting address space.
46 : //
47 : // PECoffFile observes the following address range separation rules:
48 : // - All headers live in a single range.
49 : // - Each section lives in its own data range.
50 : // - Other data may be added by child classes, and live in ranges
51 : // different from the above.
52 : //
53 : // The address traits class @p AddressSpaceTraits should define the
54 : // following members:
55 : //
56 : // @code
57 : // struct AddressSpaceTraits {
58 : // // The type of addresses native to the address space of the reader.
59 : // typedef ... AddressType;
60 : // // The type of sizes native to the address space of the reader.
61 : // typedef ... SizeType;
62 : //
63 : // // Return an address different from all valid addresses for the
64 : // // specified address type.
65 : // static const AddressType invalid_address();
66 : //
67 : // // Return the address at which to insert global headers.
68 : // static const AddressType header_address();
69 : //
70 : // // Return the address where the corresponding section should be
71 : // // mapped, or invalid_address() if the section should not be mapped.
72 : // static AddressType GetSectionAddress(const IMAGE_SECTION_HEADER& header);
73 : //
74 : // // Return the number of bytes of the corresponding section to map
75 : // // to the resulting address space.
76 : // static SizeType GetSectionSize(const IMAGE_SECTION_HEADER& header);
77 : // };
78 : // @endcode
79 : //
80 : // @tparam AddressSpaceTraits traits describing the types of the
81 : // resulting address map.
82 : // address map.
83 : template <typename AddressSpaceTraits>
84 : class PECoffFile {
85 : public:
86 : // The type of addresses native to this reader.
87 : typedef typename AddressSpaceTraits::AddressType AddressType;
88 :
89 : // The type of sizes native to this reader.
90 : typedef typename AddressSpaceTraits::SizeType SizeType;
91 :
92 : // The type of addresses referring to the on-disk file.
93 : typedef core::FileOffsetAddress FileOffsetAddress;
94 :
95 : // Return the address where the header is expected to be found,
96 : // after a successful call to Init().
97 : //
98 : // @returns the address of the header range.
99 E : static AddressType header_address() {
100 E : return AddressSpaceTraits::header_address();
101 E : }
102 :
103 : // @returns the path of the input file read, if any.
104 E : const base::FilePath& path() const { return path_; }
105 :
106 : // Copy mapped data to buffer. The specified range to read must be
107 : // contained within the image, and cannot cross data ranges from the
108 : // original file; in particular, sections with no gaps between them
109 : // must still be read separately.
110 : //
111 : // @param addr the address where the data is mapped.
112 : // @param data the buffer to write the data to.
113 : // @param len the number of bytes to copy.
114 : // @returns true on success, false on error.
115 : bool ReadImage(AddressType addr, void* data, SizeType len) const;
116 :
117 : // Copy mapped zero-terminated string data to string object.
118 : //
119 : // @param addr the address where the data is mapped.
120 : // @param str the string to write the data to.
121 : // @returns true on success, false on error.
122 : bool ReadImageString(AddressType addr, std::string* str) const;
123 :
124 : // Retrieve a pointer to the internal buffer containing mapped
125 : // data. The specified range to read must be contained within the
126 : // image, and cannot cross data ranges from the original file; in
127 : // particular, sections with no gaps between them must still be read
128 : // separately.
129 : //
130 : // @param addr the address where the data is mapped.
131 : // @param len the number of bytes that will be accessed through the
132 : // returned pointer.
133 : // @returns a pointer into the internal buffer for the data.
134 : const uint8* GetImageData(AddressType addr, SizeType len) const;
135 :
136 : // @copydoc GetImageData(AddressType,SizeType)
137 : // The resulting buffer is mutable.
138 : uint8* GetImageData(AddressType addr, SizeType len);
139 :
140 : // Retrieve a pointer to the internal buffer containing mapped
141 : // data assumed to be of type @p ItemType.
142 : //
143 : // @tparam ItemType the type of items to cast to.
144 : // @param addr the address where the data is mapped.
145 : // @param len the number of bytes that will be accessed through the
146 : // returned pointer.
147 : // @param item_ptr a pointer to the retrieved result.
148 : // @returns true on success, false on error.
149 : // @see GetImageData(AddressType,SizeType)
150 : template <typename ItemType> bool GetImageData(
151 : AddressType addr, SizeType len, const ItemType** item_ptr) const;
152 :
153 : // @copydoc GetImageData()
154 : // The resulting buffer is mutable.
155 : template <typename ItemType> bool GetImageData(
156 : AddressType addr, SizeType len, ItemType** item_ptr);
157 :
158 : // Test whether an address range is entirely mapped.
159 : //
160 : // @param addr the start of the address range.
161 : // @param len the length of the address range.
162 : // @returns true if the range is mapped, false otherwise.
163 : bool Contains(AddressType addr, SizeType len) const;
164 :
165 : // Retrieve the index of the section containing the specified range.
166 : //
167 : // @param addr the start of the address range.
168 : // @param len the length of the address range.
169 : // @returns the section index, or kInvalidSection if none is found.
170 : size_t GetSectionIndex(AddressType addr, SizeType len) const;
171 :
172 : // Retrieve the section header structure of the section containing
173 : // the specified range.
174 : //
175 : // @param addr the start of the address range.
176 : // @param len the length of the address range.
177 : // @returns the section header, or NULL if none is found.
178 : const IMAGE_SECTION_HEADER* GetSectionHeader(AddressType addr,
179 : SizeType len) const;
180 :
181 : // Retrieve the short name of a section from its index.
182 : //
183 : // @param section_index the index of the section.
184 : // @returns the name of the section.
185 : std::string GetSectionName(size_t section_index) const;
186 :
187 : // Read the short name embedded in @p section.
188 : //
189 : // @param section the section header to read.
190 : // @returns the short name of the section.
191 : static std::string GetSectionName(const IMAGE_SECTION_HEADER& section);
192 :
193 : // @returns the COFF file header.
194 E : const IMAGE_FILE_HEADER* file_header() const {
195 E : return file_header_;
196 E : }
197 :
198 : // @returns an array of all section headers.
199 : // @note Use in combination with the NumberOfSections field of the
200 : // COFF file header.
201 E : const IMAGE_SECTION_HEADER* section_headers() const {
202 E : return section_headers_;
203 E : }
204 :
205 : // Retrieve the section header structure of a section from its index.
206 : //
207 : // @param num_section the index of the section.
208 : // @returns a pointer to the header structure.
209 E : const IMAGE_SECTION_HEADER* section_header(size_t num_section) const {
210 E : if (file_header_ != NULL && num_section < file_header_->NumberOfSections)
211 E : return section_headers_ + num_section;
212 E : return NULL;
213 E : }
214 :
215 : protected:
216 : typedef std::vector<uint8> SectionBuffer;
217 :
218 : struct SectionInfo {
219 E : SectionInfo() : id(kInvalidSection) {
220 E : }
221 : size_t id;
222 : SectionBuffer buffer;
223 : };
224 :
225 : typedef core::AddressSpace<AddressType, SizeType, SectionInfo>
226 : ImageAddressSpace;
227 :
228 : // Protected constructor, for derived classes only.
229 : PECoffFile()
230 : : file_header_(NULL),
231 E : section_headers_(NULL) {
232 E : }
233 :
234 E : ~PECoffFile() {
235 E : }
236 :
237 : // Set the file path.
238 : //
239 : // @param path the path to the input file.
240 : void Init(const base::FilePath& path);
241 :
242 : // Read headers common to both PE and COFF. Insert a range covering
243 : // all headers, including unread headers; the range spans from the
244 : // beginning of the file to the end of the known fixed headers (the
245 : // section table).
246 : //
247 : // @param file the input file stream.
248 : // @param file_header_start the offset where the COFF file header
249 : // (IMAGE_FILE_HEADER) starts.
250 : // @returns true on success, false on error.
251 : bool ReadCommonHeaders(FILE* file, FileOffsetAddress file_header_start);
252 :
253 : // Read section headers and insert a range for each section.
254 : //
255 : // @param file the input file stream.
256 : // @returns true on success, false on error.
257 : bool ReadSections(FILE* file);
258 :
259 : // Insert a range into the address map, populated by data read from
260 : // @p file.
261 : //
262 : // @param file the input file stream.
263 : // @param start the file offset to start reading at.
264 : // @param size the number of bytes to read.
265 : // @param range the range to insert.
266 : // @returns true on success, false on error.
267 : bool InsertRangeReadAt(FILE* file, FileOffsetAddress start, size_t size,
268 : const typename ImageAddressSpace::Range& range);
269 :
270 : // Read bytes from @p file into the specified buffer.
271 : //
272 : // @param file the input file stream.
273 : // @param pos the file offset to start reading at.
274 : // @param buf the buffer where to place data.
275 : // @param len the number of bytes to read.
276 : static bool ReadAt(FILE* file, size_t pos, void* buf, size_t len);
277 :
278 : base::FilePath path_;
279 : const IMAGE_FILE_HEADER* file_header_;
280 : const IMAGE_SECTION_HEADER* section_headers_;
281 :
282 : // Contains all data in the image. The address space has a range defined
283 : // for the header and each section in the image, with its associated
284 : // SectionBuffer as the data.
285 : ImageAddressSpace image_data_;
286 :
287 : private:
288 : DISALLOW_COPY_AND_ASSIGN(PECoffFile);
289 : };
290 :
291 : } // namespace pe
292 :
293 : #include "syzygy/pe/pe_coff_file_impl.h"
294 :
295 : #endif // SYZYGY_PE_PE_COFF_FILE_H_
|