1 : // Copyright 2012 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 : #include "syzygy/pe/pe_file_parser.h"
16 :
17 : // The Win8 SDK defines this in winerror.h, and it is subsequently redefined by
18 : // delayimp.h
19 : #undef FACILITY_VISUALCPP
20 : #include <delayimp.h>
21 :
22 : #include "base/bind.h"
23 : #include "base/strings/stringprintf.h"
24 : #include "syzygy/common/align.h"
25 : #include "syzygy/pe/pe_structs.h"
26 :
27 : namespace pe {
28 :
29 : namespace {
30 :
31 : using block_graph::BlockGraph;
32 : using core::AbsoluteAddress;
33 : using core::FileOffsetAddress;
34 : using core::RelativeAddress;
35 :
36 : const char* kDirEntryNames[] = {
37 : "IMAGE_DIRECTORY_ENTRY_EXPORT",
38 : "IMAGE_DIRECTORY_ENTRY_IMPORT",
39 : "IMAGE_DIRECTORY_ENTRY_RESOURCE",
40 : "IMAGE_DIRECTORY_ENTRY_EXCEPTION",
41 : "IMAGE_DIRECTORY_ENTRY_SECURITY",
42 : "IMAGE_DIRECTORY_ENTRY_BASERELOC",
43 : "IMAGE_DIRECTORY_ENTRY_DEBUG",
44 : "IMAGE_DIRECTORY_ENTRY_ARCHITECTURE",
45 : "IMAGE_DIRECTORY_ENTRY_GLOBALPTR",
46 : "IMAGE_DIRECTORY_ENTRY_TLS",
47 : "IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG",
48 : "IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT",
49 : "IMAGE_DIRECTORY_ENTRY_IAT",
50 : "IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT",
51 : "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR",
52 : };
53 :
54 : // Given a table type, and whether or not it is bound, returns the type of
55 : // data we can expect to find in the table.
56 : PEFileParser::ThunkDataType GetThunkDataType(
57 E : PEFileParser::ThunkTableType table_type, bool is_bound) {
58 E : switch (table_type) {
59 : case PEFileParser::kImportNameTable:
60 E : return PEFileParser::kImageThunkData;
61 :
62 : case PEFileParser::kImportAddressTable:
63 E : if (is_bound)
64 i : return PEFileParser::kCodeOutOfImageThunkData;
65 i : else
66 E : return PEFileParser::kImageThunkData;
67 :
68 : case PEFileParser::kDelayLoadImportNameTable:
69 E : return PEFileParser::kImageThunkData;
70 :
71 : case PEFileParser::kDelayLoadImportAddressTable:
72 E : return PEFileParser::kCodeInImageThunkData;
73 :
74 : case PEFileParser::kDelayLoadBoundImportAddressTable:
75 E : return PEFileParser::kArbitraryThunkData;
76 :
77 : default: break;
78 : }
79 i : NOTREACHED() << "Unknown ThunkDataType.";
80 i : return PEFileParser::kArbitraryThunkData;
81 E : }
82 :
83 : bool DummyOnImportThunk(const char* module_name,
84 : const char* symbol_name,
85 E : BlockGraph::Block* thunk) {
86 E : return true;
87 E : }
88 :
89 : } // namespace
90 :
91 : // This class represents a generic, untyped pointer with a fixed length,
92 : // into a PE image at a particular address.
93 : class PEFilePtr {
94 : public:
95 E : PEFilePtr() : ptr_(NULL), len_(0) {
96 E : }
97 :
98 : // Set the pointer to the address and data in @p block.
99 E : bool Set(BlockGraph::Block* block) {
100 E : return Set(block, block->addr());
101 E : }
102 :
103 : // Set the pointer to the address @p addr, which must be contained
104 : // within @p block, and the corresponding data in @p block.
105 E : bool Set(BlockGraph::Block* block, RelativeAddress addr) {
106 E : const uint8_t* ptr = block->data();
107 E : ptrdiff_t offs = addr - block->addr();
108 E : if (ptr == NULL || offs < 0)
109 i : return false;
110 E : if (static_cast<size_t>(offs) >= block->data_size())
111 i : return false;
112 :
113 E : addr_ = addr;
114 E : ptr_ = ptr + offs;
115 E : len_ = block->data_size() - offs;
116 :
117 E : return true;
118 E : }
119 :
120 : // Set the pointer to the address @p addr, and length @p len,
121 : // iff the @p image contains that data.
122 E : bool Read(const PEFile& image, RelativeAddress addr, size_t len) {
123 E : const uint8_t* ptr = image.GetImageData(addr, len);
124 E : if (ptr == NULL)
125 i : return false;
126 :
127 : // Success - store the data we now point to.
128 E : addr_ = addr;
129 E : ptr_ = ptr;
130 E : len_ = len;
131 :
132 E : return true;
133 E : }
134 :
135 : // Advance the pointer by @p len bytes iff the pointer points to at
136 : // least @len bytes.
137 E : bool Advance(size_t len) {
138 : // Do we have enough remaining?
139 E : if (len_ < len)
140 i : return false;
141 :
142 : // Walk forward, and trim the remaining length.
143 E : addr_ += len;
144 E : ptr_ += len;
145 E : len_ -= len;
146 :
147 E : return true;
148 E : }
149 :
150 : // Accessors.
151 E : RelativeAddress addr() const { return addr_; }
152 : void set_addr(RelativeAddress addr) { addr_ = addr; }
153 :
154 E : const uint8_t* ptr() const { return ptr_; }
155 : void set_ptr(const uint8_t* ptr) { ptr_ = ptr; }
156 :
157 E : size_t len() const { return len_; }
158 : void set_len(size_t len) { len_ = len; }
159 :
160 : private:
161 : RelativeAddress addr_;
162 : const uint8_t* ptr_;
163 : size_t len_;
164 : };
165 :
166 : // Represents a typed pointer into a PE image at a given address.
167 : // The data pointed to by a struct ptr is typically at least sizeof(ItemType),
168 : // but may be less when parsing structures that have grown over time.
169 : template <typename ItemType>
170 : class PEFileStructPtr {
171 : public:
172 E : PEFileStructPtr() {
173 E : }
174 :
175 : // Set this pointer to the address and data in @p block.
176 : // @returns true iff successful.
177 E : bool Set(BlockGraph::Block* block) {
178 E : if (block->data_size() < sizeof(ItemType))
179 i : return false;
180 :
181 E : return ptr_.Set(block);
182 E : }
183 :
184 : // Set this pointer to the address and data in @p block, without checking
185 : // the block length.
186 : // @note the caller assumes responsibility for not accessing fields
187 : // beyond the block length.
188 : // @returns true iff successful.
189 E : bool SetUnchecked(BlockGraph::Block* block) {
190 E : return ptr_.Set(block);
191 E : }
192 :
193 : // Set this pointer to addr, which must be contained within @p block,
194 : // and the corresponding data in @p block.
195 : // @returns true iff successful.
196 E : bool Set(BlockGraph::Block* block, RelativeAddress addr) {
197 E : if (block->data_size() < sizeof(ItemType))
198 i : return false;
199 :
200 E : return ptr_.Set(block, addr);
201 E : }
202 :
203 : // Read data from @p image at @p addr.
204 E : bool Read(const PEFile& image, RelativeAddress addr) {
205 E : return Read(image, addr, sizeof(ItemType));
206 E : }
207 :
208 : // Read @p len data bytes from @p image at @p addr.
209 : // @note @p len must be greater or equal to sizeof(ItemType).
210 E : bool Read(const PEFile& image, RelativeAddress addr, size_t len) {
211 E : DCHECK(len >= sizeof(ItemType));
212 E : return ptr_.Read(image, addr, len);
213 E : }
214 :
215 : // Advance our pointer by sizeof(ItemType) iff this would leave
216 : // this pointer valid.
217 E : bool Next() {
218 E : DCHECK(IsValid());
219 :
220 : // See whether there's enough room left for another full item.
221 E : size_t new_len = ptr_.len() - sizeof(ItemType);
222 E : if (new_len < sizeof(ItemType))
223 E : return false;
224 :
225 : // Walk forward one item. We've already checked that there's
226 : // sufficient data left, so this must succeed.
227 E : bool ret = ptr_.Advance(sizeof(ItemType));
228 E : DCHECK(ret && IsValid());
229 :
230 E : return true;
231 E : }
232 :
233 E : RelativeAddress addr() const { return ptr_.addr(); }
234 : void set_addr(RelativeAddress addr) { ptr.set_addr(addr); }
235 :
236 E : const ItemType* ptr() const {
237 E : return reinterpret_cast<const ItemType*>(ptr_.ptr());
238 E : }
239 :
240 E : const ItemType* operator->() const {
241 E : return ptr();
242 E : }
243 :
244 : // Returns the image address of the data at ptr.
245 : // @note ptr must be within the data we point to.
246 E : RelativeAddress AddressOf(const void* ptr) const {
247 E : DCHECK(IsValid());
248 :
249 E : const uint8_t* tmp = reinterpret_cast<const uint8_t*>(ptr);
250 E : DCHECK(tmp >= ptr_.ptr());
251 E : ptrdiff_t offs = tmp - ptr_.ptr();
252 E : DCHECK(offs >= 0 && static_cast<size_t>(offs) < ptr_.len());
253 :
254 E : return ptr_.addr() + offs;
255 E : }
256 :
257 E : size_t len() const { return ptr_.len(); }
258 :
259 : private:
260 : // @returns true iff this pointer is valid.
261 E : bool IsValid() const {
262 E : return ptr_.ptr() != NULL;
263 E : }
264 :
265 : PEFilePtr ptr_;
266 :
267 : DISALLOW_COPY_AND_ASSIGN(PEFileStructPtr);
268 : };
269 :
270 : PEFileParser::PEFileParser(const PEFile& image_file,
271 : BlockGraph::AddressSpace* address_space,
272 : const AddReferenceCallback& add_reference)
273 E : : image_file_(image_file),
274 E : address_space_(address_space),
275 E : add_reference_(add_reference),
276 E : on_import_thunk_(base::Bind(&DummyOnImportThunk)) {
277 E : DCHECK(!add_reference.is_null());
278 E : }
279 :
280 : const PEFileParser::DataDirParseEntry PEFileParser::parsers_[] = {
281 : {
282 : IMAGE_DIRECTORY_ENTRY_EXPORT,
283 : "export",
284 : &PEFileParser::ParseExportDir
285 : }, {
286 : // We parse the IAT ahead of the imports because if the IAT entry is
287 : // present, we want it chunked and ready to reference before we start
288 : // parsing imports.
289 : IMAGE_DIRECTORY_ENTRY_IAT,
290 : "iat",
291 : &PEFileParser::ParseIatDir
292 : }, {
293 : IMAGE_DIRECTORY_ENTRY_IMPORT,
294 : "import",
295 : &PEFileParser::ParseImportDir
296 : }, {
297 : IMAGE_DIRECTORY_ENTRY_RESOURCE,
298 : "resource",
299 : &PEFileParser::ParseResourceDir
300 : }, {
301 : IMAGE_DIRECTORY_ENTRY_EXCEPTION,
302 : "exception",
303 : &PEFileParser::ParseExceptionDir
304 : }, {
305 : IMAGE_DIRECTORY_ENTRY_SECURITY,
306 : "security",
307 : &PEFileParser::ParseSecurityDir
308 : }, {
309 : IMAGE_DIRECTORY_ENTRY_BASERELOC,
310 : "relocs",
311 : &PEFileParser::ParseRelocDir
312 : }, {
313 : IMAGE_DIRECTORY_ENTRY_DEBUG,
314 : "debug",
315 : &PEFileParser::ParseDebugDir
316 : }, {
317 : IMAGE_DIRECTORY_ENTRY_ARCHITECTURE,
318 : "architecture",
319 : &PEFileParser::ParseArchitectureDir
320 : }, {
321 : IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
322 : "global",
323 : &PEFileParser::ParseGlobalDir
324 : }, {
325 : IMAGE_DIRECTORY_ENTRY_TLS,
326 : "tls",
327 : &PEFileParser::ParseTlsDir
328 : }, {
329 : IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
330 : "load config",
331 : &PEFileParser::ParseLoadConfigDir
332 : }, {
333 : IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
334 : "bound import",
335 : &PEFileParser::ParseBoundImportDir
336 : }, {
337 : IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
338 : "delay import",
339 : &PEFileParser::ParseDelayImportDir
340 : }, {
341 : IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
342 : "com descriptor",
343 : &PEFileParser::ParseComDescriptorDir
344 : },
345 : };
346 :
347 E : bool PEFileParser::ParseImage(PEHeader* pe_header) {
348 E : if (!ParseImageHeader(pe_header)) {
349 i : LOG(ERROR) << "Unable to parse image header.";
350 i : return false;
351 : }
352 :
353 E : for (size_t i = 0; i < arraysize(parsers_); ++i) {
354 E : const DataDirParseEntry& parser = parsers_[i];
355 E : DCHECK(parser.entry < IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
356 E : DCHECK(parser.parser != NULL);
357 E : DCHECK(parser.name != NULL);
358 :
359 E : const IMAGE_DATA_DIRECTORY& entry =
360 : image_file_.nt_headers()->OptionalHeader.DataDirectory[parser.entry];
361 :
362 E : if (entry.Size != 0) {
363 E : DCHECK(entry.VirtualAddress != 0);
364 :
365 : // TODO(chrisha): Once ImageLayout/AddressSpace/etc. can support blocks
366 : // that are not mappable, then support this properly. In the meantime
367 : // simply ignore the security directory entry entirely and null it out so
368 : // that the toolchain doesn't produce binaries with bad signatures.
369 E : if (parser.entry == IMAGE_DIRECTORY_ENTRY_SECURITY) {
370 E : LOG(WARNING) << "Ignoring security directory (image signature)!";
371 E : uint8_t* data = pe_header->nt_headers->GetMutableData();
372 E : DCHECK_NE(static_cast<uint8_t*>(nullptr), data);
373 : IMAGE_NT_HEADERS* nt_headers =
374 E : reinterpret_cast<IMAGE_NT_HEADERS*>(data);
375 E : auto& data_dir = nt_headers->OptionalHeader.DataDirectory[parser.entry];
376 E : data_dir.Size = 0;
377 E : data_dir.VirtualAddress = 0;
378 E : } else {
379 E : BlockGraph::Block* block = (this->*parser.parser)(entry);
380 E : if (block == nullptr) {
381 i : LOG(ERROR) << "Failed to parse data directory " << parser.name << ".";
382 i : return false;
383 : }
384 :
385 E : pe_header->data_directory[parser.entry] = block;
386 : }
387 : }
388 E : }
389 :
390 E : return true;
391 E : }
392 :
393 E : bool PEFileParser::ParseImageHeader(PEHeader* header) {
394 : // Get the start of the image headers.
395 : size_t dos_header_size =
396 E : reinterpret_cast<const uint8_t*>(image_file_.nt_headers()) -
397 : reinterpret_cast<const uint8_t*>(image_file_.dos_header());
398 :
399 E : if (dos_header_size < sizeof(IMAGE_DOS_HEADER)) {
400 i : LOG(ERROR) << "Impossibly small DOS header.";
401 i : return false;
402 : }
403 :
404 E : PEFileStructPtr<IMAGE_DOS_HEADER> dos_header_ptr;
405 E : if (!dos_header_ptr.Read(image_file_, RelativeAddress(0), dos_header_size)) {
406 i : LOG(ERROR) << "No DOS header in image.";
407 i : return false;
408 : }
409 :
410 : // The length of the DOS header is the address of the NT headers.
411 E : RelativeAddress nt_headers_address(dos_header_size);
412 E : DCHECK(nt_headers_address.value() > sizeof(IMAGE_DOS_HEADER));
413 :
414 : // Chunk out the DOS header and stub.
415 E : BlockGraph::Block* dos_header = AddBlock(BlockGraph::DATA_BLOCK,
416 : RelativeAddress(0),
417 : nt_headers_address.value(),
418 : "DOS Header");
419 E : if (dos_header == NULL) {
420 i : LOG(ERROR) << "Unable to add DOS header block.";
421 i : return false;
422 : }
423 :
424 : // Add the reference to the PE header. This reference can be interpreted
425 : // either as a disk or a relative reference, as disk and relative addresses
426 : // coincide in the image header.
427 : static_assert(sizeof(DWORD) == sizeof(dos_header_ptr->e_lfanew),
428 : "dos_header_ptr->e_lfanew size is wrong.");
429 E : if (!AddRelative(dos_header_ptr,
430 : reinterpret_cast<const DWORD*>(&dos_header_ptr->e_lfanew))) {
431 i : LOG(ERROR) << "Unable to add DOS to NT headers reference.";
432 i : return false;
433 : }
434 :
435 E : PEFileStructPtr<IMAGE_NT_HEADERS> nt_headers_ptr;
436 E : if (!nt_headers_ptr.Read(image_file_, nt_headers_address)) {
437 i : LOG(ERROR) << "Unable to read NT headers.";
438 i : return false;
439 : }
440 :
441 E : for (size_t i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; ++i) {
442 E : if (!AddRelative(nt_headers_ptr,
443 : &nt_headers_ptr->OptionalHeader.DataDirectory[i].VirtualAddress)) {
444 i : LOG(ERROR) << "Unable to add data directory reference for "
445 : << kDirEntryNames[i];
446 i : return false;
447 : }
448 E : }
449 :
450 : // Calculate the size of the NT headers and section headers.
451 E : size_t nt_headers_size = sizeof(IMAGE_NT_HEADERS) +
452 : nt_headers_ptr->FileHeader.NumberOfSections *
453 : sizeof(IMAGE_SECTION_HEADER);
454 : // Chunk the NT & section headers.
455 E : BlockGraph::Block* nt_headers = AddBlock(BlockGraph::DATA_BLOCK,
456 : nt_headers_address,
457 : nt_headers_size,
458 : "NT Headers");
459 E : if (nt_headers == NULL) {
460 i : LOG(ERROR) << "Unable to add NT Headers block.";
461 i : return false;
462 : }
463 :
464 E : if (!AddRelative(nt_headers_ptr,
465 : &nt_headers_ptr->OptionalHeader.AddressOfEntryPoint)) {
466 i : LOG(ERROR) << "Unable to add entry point reference.";
467 i : return false;
468 : }
469 :
470 E : if (header != NULL) {
471 E : header->dos_header = dos_header;
472 E : header->nt_headers = nt_headers;
473 : }
474 :
475 E : return true;
476 E : }
477 :
478 : BlockGraph::Block* PEFileParser::ParseExportDir(
479 E : const IMAGE_DATA_DIRECTORY& dir) {
480 : BlockGraph::Block* export_dir_block =
481 E : AddBlock(BlockGraph::DATA_BLOCK,
482 : RelativeAddress(dir.VirtualAddress),
483 : dir.Size,
484 : "Export Directory");
485 E : if (export_dir_block == NULL) {
486 i : LOG(ERROR) << "Failed to create export directory block.";
487 i : return NULL;
488 : }
489 :
490 E : PEFileStructPtr<IMAGE_EXPORT_DIRECTORY> export_dir;
491 E : if (!export_dir.Set(export_dir_block)) {
492 i : LOG(ERROR) << "Unable to read export directory.";
493 i : return NULL;
494 : }
495 :
496 E : if (!AddRelative(export_dir, &export_dir->Name)) {
497 i : LOG(ERROR) << "Unable to add export functions reference.";
498 i : return NULL;
499 : }
500 :
501 : // All the references in the export directory should point back into
502 : // the export directory, unless they are NULL (empty).
503 :
504 E : if (export_dir->AddressOfFunctions != 0) {
505 E : DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
506 : RelativeAddress(export_dir->AddressOfFunctions),
507 E : sizeof(RelativeAddress)));
508 E : if (!AddRelative(export_dir, &export_dir->AddressOfFunctions)) {
509 i : LOG(ERROR) << "Unable to add export functions reference.";
510 i : return NULL;
511 : }
512 :
513 E : PEFileStructPtr<DWORD> function;
514 E : if (!function.Set(export_dir_block,
515 : RelativeAddress(export_dir->AddressOfFunctions))) {
516 i : LOG(ERROR) << "Unable to parse export function table.";
517 i : return NULL;
518 : }
519 :
520 E : for (size_t i = 0; i < export_dir->NumberOfFunctions; ++i) {
521 : // TODO(siggi): This could be labeled with the exported function's
522 : // name, if one is available.
523 E : if (!AddRelative(function, function.ptr())) {
524 i : LOG(ERROR) << "Unable to add reference to exported function.";
525 i : return NULL;
526 : }
527 :
528 E : if (!function.Next()) {
529 i : LOG(ERROR) << "Unable to parse export function table.";
530 i : return NULL;
531 : }
532 E : }
533 : }
534 :
535 E : if (export_dir->AddressOfNames != 0) {
536 E : DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
537 : RelativeAddress(export_dir->AddressOfNames),
538 E : sizeof(RelativeAddress)));
539 E : if (!AddRelative(export_dir, &export_dir->AddressOfNames)) {
540 i : LOG(ERROR) << "Unable to add export address of names reference.";
541 i : return NULL;
542 : }
543 :
544 : // Add references to the export function names.
545 E : PEFileStructPtr<DWORD> name;
546 E : if (!name.Set(export_dir_block,
547 : RelativeAddress(export_dir->AddressOfNames))) {
548 i : LOG(ERROR) << "Unable to parse export name table.";
549 : }
550 :
551 E : for (size_t i = 0; i < export_dir->NumberOfNames; ++i) {
552 : // All the names in the export directory should point back into
553 : // the export directory, sanity check this.
554 E : DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
555 : RelativeAddress(*name.ptr()),
556 E : sizeof(RelativeAddress)));
557 :
558 E : if (!AddRelative(name, name.ptr())) {
559 i : LOG(ERROR) << "Unable to add reference to export function name.";
560 i : return NULL;
561 : }
562 :
563 E : if (!name.Next()) {
564 i : LOG(ERROR) << "Unable to parse export function table.";
565 i : return NULL;
566 : }
567 E : }
568 : }
569 :
570 E : if (export_dir->AddressOfNameOrdinals != 0) {
571 E : DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
572 : RelativeAddress(export_dir->AddressOfNameOrdinals),
573 E : sizeof(RelativeAddress)));
574 E : if (!AddRelative(export_dir, &export_dir->AddressOfNameOrdinals)) {
575 i : LOG(ERROR) << "Unable to add export address of ordinals reference.";
576 i : return NULL;
577 : }
578 : }
579 :
580 E : return export_dir_block;
581 E : }
582 :
583 E : size_t PEFileParser::CountImportThunks(RelativeAddress thunk_start) {
584 E : size_t num_thunks = 0;
585 E : for (; true; ++num_thunks, thunk_start += sizeof(IMAGE_THUNK_DATA)) {
586 E : PEFileStructPtr<IMAGE_THUNK_DATA> thunk;
587 E : if (!thunk.Read(image_file_, thunk_start)) {
588 : // We didn't get to the sentinel, that's an error.
589 i : LOG(ERROR) << "Unable to read image import thunk.";
590 i : return 0;
591 : }
592 :
593 E : if (thunk->u1.AddressOfData == 0U)
594 E : break;
595 E : }
596 :
597 E : return num_thunks;
598 E : }
599 :
600 : bool PEFileParser::ParseImportThunks(RelativeAddress thunk_start,
601 : size_t num_thunks,
602 : bool is_bound,
603 : ThunkTableType table_type,
604 : const char* thunk_type,
605 E : const char* import_name) {
606 : // Only certain table types may be bound.
607 E : DCHECK(!is_bound || table_type == kImportAddressTable ||
608 : table_type == kDelayLoadBoundImportAddressTable);
609 :
610 : // Start by chunking the IAT/INT, including the terminating sentinel.
611 E : size_t ixt_size = sizeof(IMAGE_THUNK_DATA) * (num_thunks + 1);
612 :
613 : std::string ixt_name =
614 E : base::StringPrintf("%s for \"%s\"", thunk_type, import_name);
615 :
616 E : BlockGraph::Block* thunk_block = NULL;
617 E : if (table_type == kDelayLoadBoundImportAddressTable) {
618 E : thunk_block = ChunkDelayBoundIATBlock(thunk_start, ixt_size,
619 : ixt_name.c_str());
620 E : } else {
621 : // Try to add the block.
622 E : thunk_block = AddBlock(BlockGraph::DATA_BLOCK,
623 : thunk_start,
624 : ixt_size,
625 : ixt_name.c_str());
626 :
627 : // The IAT may have been chunked while parsing the IAT data directory,
628 : // in which case we want to leave a label for the start of our entries. In
629 : // this case we should be wholly contained in an existing block.
630 E : if (thunk_block == NULL)
631 E : thunk_block = address_space_->GetContainingBlock(thunk_start, ixt_size);
632 : }
633 :
634 E : if (thunk_block == NULL) {
635 i : LOG(ERROR) << "Unable to add " << thunk_type
636 : << "block for " << import_name;
637 i : return false;
638 : }
639 :
640 : // Add a label to the start of the table.
641 E : thunk_block->SetLabel(thunk_start - thunk_block->addr(),
642 : ixt_name,
643 : BlockGraph::DATA_LABEL);
644 :
645 : // Determine the type of data in the table. We only chunk out names for
646 : // import name tables. This prevents us from doing the work twice for an
647 : // unbound IAT.
648 E : ThunkDataType thunk_data_type = GetThunkDataType(table_type, is_bound);
649 E : bool chunk_names = table_type == kImportNameTable ||
650 : table_type == kDelayLoadImportNameTable;
651 :
652 : // Run through and validate the table contents, parsing IMAGE_IMPORT_BY_NAMES
653 : // if we're in an import name table.
654 E : for (size_t i = 0; i < num_thunks; ++i) {
655 E : if (!ParseImportThunk(thunk_start, thunk_data_type, thunk_type,
656 : import_name, chunk_names)) {
657 i : return false;
658 : }
659 E : thunk_start += sizeof(IMAGE_THUNK_DATA);
660 E : }
661 :
662 E : return true;
663 E : }
664 :
665 : bool PEFileParser::ParseImportThunk(RelativeAddress thunk_addr,
666 : ThunkDataType thunk_data_type,
667 : const char* thunk_type,
668 : const char* module_name,
669 E : bool chunk_name) {
670 : // We can only chunk names if we're parsing an IMAGE_THUNK_DATA object.
671 E : DCHECK(!chunk_name || thunk_data_type == kImageThunkData);
672 :
673 E : PEFileStructPtr<IMAGE_THUNK_DATA> thunk;
674 E : if (!thunk.Read(image_file_, thunk_addr)) {
675 i : LOG(ERROR) << "Unable to read image import thunk.";
676 i : return false;
677 : }
678 :
679 E : switch (thunk_data_type) {
680 : case kNullThunkData: {
681 i : if (thunk->u1.AddressOfData != 0) {
682 i : LOG(ERROR) << "Expect NULL " << thunk_type << " thunk, got 0x"
683 : << std::hex << thunk->u1.AddressOfData;
684 i : return false;
685 : }
686 i : break;
687 : }
688 :
689 : case kImageThunkData: {
690 : // If it's an ordinal, there's nothing to do.
691 E : if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
692 E : break;
693 :
694 : // It's not an ordinal, so it must contain an RVA to an
695 : // IMAGE_IMPORT_BY_NAME.
696 :
697 : // Add the IAT/INT->thunk reference.
698 : // Assuming little endian representation.
699 E : if (!AddRelative(thunk, reinterpret_cast<const DWORD*>(
700 : &thunk->u1.AddressOfData))) {
701 i : LOG(ERROR) << "Unable to add import thunk reference.";
702 i : return false;
703 : }
704 :
705 : // Read the thunk and name & chunk it out.
706 E : PEFileStructPtr<IMAGE_IMPORT_BY_NAME> name_thunk;
707 E : RelativeAddress name_thunk_addr(thunk->u1.AddressOfData);
708 E : if (!name_thunk.Read(image_file_, name_thunk_addr)) {
709 i : LOG(ERROR) << "Unable to read import name thunk.";
710 i : return false;
711 : }
712 :
713 E : std::string function_name;
714 : RelativeAddress function_name_addr(
715 E : name_thunk.AddressOf(&name_thunk->Name));
716 E : if (!image_file_.ReadImageString(function_name_addr, &function_name)) {
717 i : LOG(ERROR) << "Unable to read import function name.";
718 i : return false;
719 : }
720 :
721 : // Calculate the even-padded size of the name thunk.
722 E : size_t name_thunk_size = common::AlignUp(
723 : offsetof(IMAGE_IMPORT_BY_NAME, Name) + function_name.size() + 1, 2);
724 :
725 : // Chunk the names only on request, as more than one IAT/INT may
726 : // point to the same name blocks.
727 E : if (chunk_name) {
728 E : BlockGraph::Block* thunk = AddBlock(
729 : BlockGraph::DATA_BLOCK,
730 : name_thunk_addr,
731 : name_thunk_size,
732 : base::StringPrintf("Import Name Thunk \"%s\" from \"%s\"",
733 : function_name.c_str(),
734 : module_name).c_str());
735 E : if (thunk == NULL) {
736 i : LOG(ERROR) << "Unable to add function name block.";
737 i : return false;
738 : }
739 :
740 E : if (!on_import_thunk_.Run(module_name, function_name.c_str(), thunk)) {
741 i : LOG(ERROR) << "OnImportThunk callback failed.";
742 i : return false;
743 : }
744 E : } else {
745 : #ifndef NDEBUG
746 : // Check that the name blocks exist in debug.
747 : BlockGraph::Block* block =
748 E : address_space_->GetBlockByAddress(name_thunk_addr);
749 E : DCHECK(block != NULL);
750 E : DCHECK_EQ(name_thunk_size, block->size());
751 : #endif // NDEBUG
752 : }
753 E : break;
754 i : }
755 :
756 : case kCodeInImageThunkData: {
757 : // Add the code reference. This will check that it is in fact a reference
758 : // to an address in the image, and track the associated block
759 : // automatically.
760 : // Assuming little endian representation.
761 E : if (!AddAbsolute(thunk, reinterpret_cast<const DWORD*>(
762 : &thunk->u1.AddressOfData))) {
763 i : LOG(ERROR) << "Unable to add import thunk reference.";
764 i : return false;
765 : }
766 E : break;
767 : }
768 :
769 : case kCodeOutOfImageThunkData: {
770 : // This is an absolute address to code outside of the image. It may
771 : // actually have an address that lies inside our image because the
772 : // imported module may have an overlapping preferred load address.
773 i : if (thunk->u1.AddressOfData < 0x1000) {
774 i : AbsoluteAddress abs_addr(thunk->u1.AddressOfData);
775 i : LOG(ERROR) << thunk_type << " thunk to external code has invalid "
776 : << "address: " << abs_addr;
777 i : return false;
778 : }
779 : break;
780 : }
781 :
782 : case kArbitraryThunkData: {
783 : // We do nothing. Anything goes!
784 : break;
785 : }
786 : }
787 :
788 E : return true;
789 E : }
790 :
791 : BlockGraph::Block* PEFileParser::ChunkDelayBoundIATBlock(
792 E : RelativeAddress iat_addr, size_t iat_size, const char* iat_name) {
793 E : BlockGraph::Block* iat_block = AddBlock(BlockGraph::DATA_BLOCK,
794 : iat_addr,
795 : iat_size,
796 : iat_name);
797 E : if (iat_block != NULL)
798 E : return iat_block;
799 :
800 : // If we get here we were unable to create a block, so there must be a
801 : // conflict. We've seen the bound IATs for delay-loaded libraries be too
802 : // small. That is, one library's bound IAT is overwritten by another library's
803 : // bound IAT. We do our best to patch things up, by growing the conflicting
804 : // pre-existing block to also cover the range of the block we want to create.
805 : //
806 : // We extend the existing block by creating new blocks (one to the left, one
807 : // to the right) of the conflicting block that cover the portion of the new
808 : // table that is not covered. Then, we merge them all.
809 :
810 i : iat_block = address_space_->GetFirstIntersectingBlock(iat_addr,
811 : iat_size);
812 i : VLOG(1) << iat_name << " collides with existing block " << iat_block->name()
813 : << ".";
814 :
815 : // If we're completely contained within the conflicting block, there's no
816 : // expanding and merging to do.
817 i : if (iat_block->Contains(iat_addr, iat_size))
818 i : return iat_block;
819 :
820 : // Create a block to the left of the existing block, if the desired table
821 : // extends to the left.
822 i : if (iat_addr < iat_block->addr()) {
823 i : size_t pre_size = iat_block->addr() - iat_addr;
824 i : BlockGraph::Block* pre_block = AddBlock(BlockGraph::DATA_BLOCK,
825 : iat_addr,
826 : pre_size,
827 : iat_name);
828 : // This should never fail as iat_block is the *first* intersecting
829 : // block.
830 i : DCHECK(pre_block != NULL);
831 : }
832 :
833 : // Insert the missing part of this table to the right of the intersecting
834 : // block, if there is any needed.
835 i : RelativeAddress new_end = iat_addr + iat_size;
836 i : RelativeAddress old_end = iat_block->addr() + iat_block->size();
837 i : if (new_end > old_end) {
838 : BlockGraph::Block* next_block =
839 i : address_space_->GetFirstIntersectingBlock(
840 : old_end, new_end - old_end);
841 :
842 i : if (next_block != NULL)
843 i : new_end = next_block->addr();
844 :
845 i : if (new_end > old_end) {
846 i : BlockGraph::Block* post_block = AddBlock(BlockGraph::DATA_BLOCK,
847 : old_end,
848 : new_end - old_end,
849 : NULL);
850 : // This should never fail as we're inserting after the end of
851 : // iat_block, and before the start of the next block in the
852 : // address space.
853 i : DCHECK(post_block != NULL);
854 : }
855 : }
856 :
857 : // Merge the blocks to create one new contiguous block.
858 i : BlockGraph::AddressSpace::Range range(iat_addr, iat_size);
859 i : if (!address_space_->MergeIntersectingBlocks(range)) {
860 i : LOG(ERROR) << "Unable to merge intersecting bound IAT blocks.";
861 i : return NULL;
862 : }
863 i : iat_block = address_space_->GetContainingBlock(iat_addr, iat_size);
864 i : DCHECK(iat_block != NULL);
865 :
866 i : return iat_block;
867 E : }
868 :
869 : BlockGraph::Block* PEFileParser::ParseImportDir(
870 E : const IMAGE_DATA_DIRECTORY& dir) {
871 : // Read the import descriptor, we're going to iterate it.
872 E : RelativeAddress import_descriptor_addr(dir.VirtualAddress);
873 E : PEFileStructPtr<IMAGE_IMPORT_DESCRIPTOR> import_descriptor;
874 E : if (!import_descriptor.Read(image_file_,
875 : import_descriptor_addr,
876 : dir.Size)) {
877 i : LOG(ERROR) << "Unable to read the import directory.";
878 i : return NULL;
879 : }
880 :
881 : do {
882 : // The last import descriptor is a sentinel.
883 E : if (import_descriptor->Characteristics == 0) {
884 E : DCHECK_EQ(0U, import_descriptor->Name);
885 E : DCHECK_EQ(0U, import_descriptor->FirstThunk);
886 E : break;
887 : }
888 :
889 : // Read the name of the imported DLL.
890 E : std::string import_name;
891 E : RelativeAddress import_name_addr(import_descriptor->Name);
892 E : if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
893 i : LOG(ERROR) << "Unable to read import name.";
894 i : return NULL;
895 : }
896 :
897 E : if (!AddBlock(BlockGraph::DATA_BLOCK,
898 : import_name_addr,
899 : common::AlignUp(import_name.size() + 1, 2),
900 : base::StringPrintf("Import DLL Name \"%s\"",
901 : import_name.c_str()).c_str())) {
902 i : LOG(ERROR) << "Unable to create import name block.";
903 i : return NULL;
904 : }
905 :
906 E : if (!AddRelative(import_descriptor, &import_descriptor->Name)) {
907 i : LOG(ERROR) << "Unable to add import name reference.";
908 i : return NULL;
909 : }
910 :
911 : // Count the number of import name thunks for this import descriptor.
912 : RelativeAddress thunk_addr =
913 E : RelativeAddress(import_descriptor->OriginalFirstThunk);
914 E : size_t num_thunks = CountImportThunks(thunk_addr);
915 E : if (num_thunks == 0)
916 i : return NULL;
917 :
918 : // Parse the Import Name Table.
919 E : if (!ParseImportThunks(thunk_addr, num_thunks, false,
920 : kImportNameTable, "INT", import_name.c_str())) {
921 i : return NULL;
922 : }
923 :
924 : // Parse the Import Address Table.
925 E : bool iat_is_bound = import_descriptor->TimeDateStamp != 0;
926 E : if (!ParseImportThunks(RelativeAddress(import_descriptor->FirstThunk),
927 : num_thunks, iat_is_bound,
928 : kImportAddressTable, "IAT", import_name.c_str())) {
929 i : return NULL;
930 : }
931 :
932 E : if (!AddRelative(import_descriptor,
933 : &import_descriptor->OriginalFirstThunk)) {
934 i : LOG(ERROR) << "Unable to add import name table reference.";
935 i : return NULL;
936 : }
937 :
938 E : if (!AddRelative(import_descriptor, &import_descriptor->FirstThunk)) {
939 i : LOG(ERROR) << "Unable to add import address table reference.";
940 i : return NULL;
941 : }
942 E : } while (import_descriptor.Next());
943 :
944 : BlockGraph::Block* import_descriptor_block =
945 E : AddBlock(BlockGraph::DATA_BLOCK,
946 : import_descriptor_addr,
947 : import_descriptor.addr() - import_descriptor_addr +
948 : sizeof(IMAGE_IMPORT_DESCRIPTOR),
949 : "Import Directory");
950 :
951 E : return import_descriptor_block;
952 E : }
953 :
954 : BlockGraph::Block *PEFileParser::ParseComDescriptorDir(
955 i : const IMAGE_DATA_DIRECTORY &dir) {
956 i : LOG(ERROR) << "Parsing for COM descriptors not implemented.";
957 i : return NULL;
958 i : }
959 :
960 : BlockGraph::Block *PEFileParser::ParseDelayImportDir(
961 E : const IMAGE_DATA_DIRECTORY &dir) {
962 : // Read the delay import descriptor, we're going to iterate it.
963 E : RelativeAddress import_descriptor_addr(dir.VirtualAddress);
964 E : PEFileStructPtr<ImgDelayDescr> import_descriptor;
965 E : if (!import_descriptor.Read(image_file_,
966 : import_descriptor_addr,
967 : dir.Size)) {
968 i : LOG(ERROR) << "Unable to read the delay import directory.";
969 i : return NULL;
970 : }
971 :
972 : do {
973 : // The last descriptor is a sentinel.
974 E : if (import_descriptor->grAttrs == 0)
975 E : break;
976 :
977 E : if (import_descriptor->grAttrs != dlattrRva) {
978 i : LOG(ERROR) << "Unexpected attributes in delay import descriptor 0x"
979 : << std::hex << import_descriptor->grAttrs;
980 i : return NULL;
981 : }
982 :
983 : // Read the name of the delay imported DLL.
984 E : std::string import_name;
985 E : RelativeAddress import_name_addr(import_descriptor->rvaDLLName);
986 E : if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
987 i : LOG(ERROR) << "Unable to read delay import name.";
988 i : return NULL;
989 : }
990 :
991 E : if (!AddBlock(BlockGraph::DATA_BLOCK,
992 : import_name_addr,
993 : common::AlignUp(import_name.size() + 1, 2),
994 : base::StringPrintf("Delay import DLL Name \"%s\"",
995 : import_name.c_str()).c_str())) {
996 i : LOG(ERROR) << "Unable to create import name block.";
997 i : return NULL;
998 : }
999 :
1000 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaDLLName)) {
1001 i : LOG(ERROR) << "Unable to add delay import name reference.";
1002 i : return NULL;
1003 : }
1004 :
1005 : // Chunk the HMODULE for this import.
1006 E : if (!AddBlock(BlockGraph::DATA_BLOCK,
1007 : RelativeAddress(import_descriptor->rvaHmod),
1008 : sizeof(HMODULE),
1009 : base::StringPrintf("Module handle for delay import DLL\"%s\"",
1010 : import_name.c_str()).c_str())) {
1011 i : LOG(ERROR) << "Unable to create import module handle block.";
1012 i : return NULL;
1013 : }
1014 :
1015 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaHmod)) {
1016 i : LOG(ERROR) << "Unable to delay import module handle reference.";
1017 i : return NULL;
1018 : }
1019 :
1020 : // Count the number of import name thunks for this import descriptor.
1021 E : RelativeAddress int_addr(import_descriptor->rvaINT);
1022 E : size_t num_thunks = CountImportThunks(int_addr);
1023 E : if (num_thunks == 0)
1024 i : return NULL;
1025 :
1026 : // Parse the Delay Import Name Table.
1027 E : if (!ParseImportThunks(int_addr, num_thunks, false,
1028 : kDelayLoadImportNameTable, "DelayINT",
1029 : import_name.c_str())) {
1030 i : return NULL;
1031 : }
1032 :
1033 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaINT)) {
1034 i : LOG(ERROR) << "Unable to add delay import name table reference.";
1035 i : return NULL;
1036 : }
1037 :
1038 : // Parse the Delay Import Address Table.
1039 E : if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaIAT),
1040 : num_thunks, false,
1041 : kDelayLoadImportAddressTable, "DelayIAT",
1042 : import_name.c_str())) {
1043 i : return NULL;
1044 : }
1045 :
1046 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaIAT)) {
1047 i : LOG(ERROR) << "Unable to add delay import address table reference.";
1048 i : return NULL;
1049 : }
1050 :
1051 : // Parse the Bound Import Address Table.
1052 E : bool iat_is_bound = import_descriptor->dwTimeStamp != 0;
1053 E : if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaBoundIAT),
1054 : num_thunks, iat_is_bound,
1055 : kDelayLoadBoundImportAddressTable, "DelayBoundIAT",
1056 : import_name.c_str())) {
1057 i : return NULL;
1058 : }
1059 :
1060 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaBoundIAT)) {
1061 i : LOG(ERROR) << "Unable to add delay bound import address table reference.";
1062 i : return NULL;
1063 : }
1064 :
1065 E : if (import_descriptor->rvaUnloadIAT != 0U) {
1066 i : LOG(ERROR) << "Unexpected UnloadIAT.";
1067 i : return NULL;
1068 : }
1069 :
1070 E : if (import_descriptor->dwTimeStamp != 0U) {
1071 i : LOG(ERROR) << "Unexpected bound delay imports.";
1072 i : return NULL;
1073 : }
1074 E : } while (import_descriptor.Next());
1075 :
1076 : BlockGraph::Block* import_descriptor_block =
1077 E : AddBlock(BlockGraph::DATA_BLOCK,
1078 : import_descriptor_addr,
1079 : import_descriptor.addr() - import_descriptor_addr +
1080 : sizeof(ImgDelayDescr),
1081 : "Delay Import Directory");
1082 :
1083 E : return import_descriptor_block;
1084 E : }
1085 :
1086 : BlockGraph::Block *PEFileParser::ParseIatDir(
1087 E : const IMAGE_DATA_DIRECTORY &dir) {
1088 E : return AddBlock(BlockGraph::DATA_BLOCK,
1089 : RelativeAddress(dir.VirtualAddress),
1090 : dir.Size,
1091 : "Import Address Table");
1092 E : }
1093 :
1094 : BlockGraph::Block *PEFileParser::ParseBoundImportDir(
1095 i : const IMAGE_DATA_DIRECTORY &dir) {
1096 i : LOG(ERROR) << "Parsing for bound import dir not implemented.";
1097 i : return NULL;
1098 i : }
1099 :
1100 : BlockGraph::Block *PEFileParser::ParseGlobalDir(
1101 i : const IMAGE_DATA_DIRECTORY &dir) {
1102 i : LOG(ERROR) << "Parsing for global dir not implemented.";
1103 i : return NULL;
1104 i : }
1105 :
1106 : BlockGraph::Block *PEFileParser::ParseArchitectureDir(
1107 i : const IMAGE_DATA_DIRECTORY &dir) {
1108 i : LOG(ERROR) << "Parsing for architecture dir not implemented.";
1109 i : return NULL;
1110 i : }
1111 :
1112 : BlockGraph::Block *PEFileParser::ParseRelocDir(
1113 E : const IMAGE_DATA_DIRECTORY &dir) {
1114 E : return AddBlock(BlockGraph::DATA_BLOCK,
1115 : RelativeAddress(dir.VirtualAddress),
1116 : dir.Size,
1117 : "Relocations");
1118 E : }
1119 :
1120 : BlockGraph::Block *PEFileParser::ParseSecurityDir(
1121 i : const IMAGE_DATA_DIRECTORY &dir) {
1122 i : LOG(ERROR) << "Parsing for security dir not implemented.";
1123 i : return NULL;
1124 i : }
1125 :
1126 : BlockGraph::Block *PEFileParser::ParseExceptionDir(
1127 i : const IMAGE_DATA_DIRECTORY &dir) {
1128 i : LOG(ERROR) << "Parsing for exception dir not implemented.";
1129 i : return NULL;
1130 i : }
1131 :
1132 : BlockGraph::Block* PEFileParser::ParseTlsDir(
1133 E : const IMAGE_DATA_DIRECTORY& dir) {
1134 : BlockGraph::Block* tls_directory_block =
1135 E : AddBlock(BlockGraph::DATA_BLOCK,
1136 : RelativeAddress(dir.VirtualAddress),
1137 : sizeof(IMAGE_TLS_DIRECTORY),
1138 : "Tls Directory");
1139 E : if (tls_directory_block == NULL)
1140 i : return NULL;
1141 :
1142 E : PEFileStructPtr<IMAGE_TLS_DIRECTORY> tls_directory;
1143 E : if (!tls_directory.Set(tls_directory_block)) {
1144 i : LOG(ERROR) << "Unable to read the TLS directory.";
1145 i : return NULL;
1146 : }
1147 :
1148 E : return tls_directory_block;
1149 E : }
1150 :
1151 : BlockGraph::Block* PEFileParser::ParseLoadConfigDir(
1152 E : const IMAGE_DATA_DIRECTORY& dir) {
1153 : // The load config directory starts with a size field, which we use as the
1154 : // size for chunking. It appears the size of the data directory entry is
1155 : // always fixed, but the structure itself has grown over time.
1156 E : PEFileStructPtr<DWORD> load_config_len;
1157 E : if (!load_config_len.Read(image_file_, RelativeAddress(dir.VirtualAddress))) {
1158 i : LOG(ERROR) << "Unable to read load config len.";
1159 i : return NULL;
1160 : }
1161 :
1162 : LoadConfigDirectoryVersion load_config_version =
1163 E : kLoadConfigDirectorySizeUnknown;
1164 E : switch (*load_config_len.ptr()) {
1165 : case kLoadConfigDirectorySize80:
1166 : case kLoadConfigDirectorySize81:
1167 E : load_config_version =
1168 : static_cast<LoadConfigDirectoryVersion>(*load_config_len.ptr());
1169 E : break;
1170 : default:
1171 i : LOG(ERROR) << "Unknown version of the IMAGE_LOAD_CONFIG_DIRECTORY "
1172 : << "structure (" << *load_config_len.ptr() << " bytes), might "
1173 : << "be because you're using a new version of the Windows SDK.";
1174 i : return NULL;
1175 : }
1176 :
1177 : BlockGraph::Block* load_config_block =
1178 E : AddBlock(BlockGraph::DATA_BLOCK,
1179 : RelativeAddress(dir.VirtualAddress),
1180 : *load_config_len.ptr(),
1181 : "Load Config Directory");
1182 :
1183 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), load_config_block);
1184 :
1185 : // Use SetUnchecked here as the load config structure may be longer than the
1186 : // data we have for it.
1187 E : PEFileStructPtr<LoadConfigDirectory> load_config;
1188 E : if (!load_config.SetUnchecked(load_config_block)) {
1189 i : LOG(ERROR) << "Unable to parse the load config directory.";
1190 i : return NULL;
1191 : }
1192 :
1193 : // TODO(siggi): Must length check prior to each of these...
1194 : if (!AddAbsolute(load_config, &load_config->LockPrefixTable) ||
1195 : !AddAbsolute(load_config, &load_config->EditList) ||
1196 : !AddAbsolute(load_config, &load_config->SecurityCookie) ||
1197 : !AddAbsolute(load_config, &load_config->SEHandlerTable) ||
1198 : !MaybeAddAbsolute(load_config,
1199 E : &load_config->GuardCFCheckFunctionPointer) ||
1200 : !MaybeAddAbsolute(load_config, &load_config->GuardCFFunctionTable)) {
1201 i : LOG(ERROR) << "Unable to add load config directory references.";
1202 i : return NULL;
1203 : }
1204 :
1205 : // Iterate the exception handlers and add references for them.
1206 E : RelativeAddress seh_handler;
1207 E : PEFileStructPtr<DWORD> seh_handlers;
1208 : if (!image_file_.Translate(AbsoluteAddress(load_config->SEHandlerTable),
1209 E : &seh_handler) ||
1210 : !seh_handlers.Read(image_file_, seh_handler,
1211 : load_config->SEHandlerCount * sizeof(DWORD))) {
1212 i : LOG(ERROR) << "Unable to read SEH handler table.";
1213 i : return NULL;
1214 : }
1215 :
1216 E : for (size_t i = 0; i < load_config->SEHandlerCount; ++i) {
1217 E : if (!AddRelative(seh_handlers, seh_handlers.ptr() + i)) {
1218 i : LOG(ERROR) << "Unable to add SEH handler reference.";
1219 i : return NULL;
1220 : }
1221 E : }
1222 :
1223 : // TODO(siggi): Add new load config directory fields.
1224 : // As of WDK 8.1 we have the following new fields:
1225 : // DWORD GuardCFCheckFunctionPointer; // VA
1226 : // DWORD Reserved2;
1227 : // DWORD GuardCFFunctionTable; // VA
1228 : // DWORD GuardCFFunctionCount;
1229 : // DWORD GuardFlags;
1230 :
1231 E : return load_config_block;
1232 E : }
1233 :
1234 : BlockGraph::Block* PEFileParser::ParseDebugDir(
1235 E : const IMAGE_DATA_DIRECTORY& dir) {
1236 : BlockGraph::Block* debug_directory_block =
1237 E : AddBlock(BlockGraph::DATA_BLOCK,
1238 : RelativeAddress(dir.VirtualAddress),
1239 : dir.Size,
1240 : "Debug Directory");
1241 E : if (debug_directory_block == NULL)
1242 i : return NULL;
1243 :
1244 E : PEFileStructPtr<IMAGE_DEBUG_DIRECTORY> debug_directory;
1245 E : if (!debug_directory.Set(debug_directory_block)) {
1246 i : LOG(ERROR) << "Unable to read the debug directory.";
1247 i : return NULL;
1248 : }
1249 :
1250 : do {
1251 E : if (!AddRelative(debug_directory, &debug_directory->AddressOfRawData) ||
1252 : !AddFileOffset(debug_directory, &debug_directory->PointerToRawData)) {
1253 i : LOG(ERROR) << "Failed to add debug directory references.";
1254 i : return NULL;
1255 : }
1256 :
1257 : // Don't create a block for empty directories. This is seen with VS2015
1258 : // Incremental Link Time Code Generation, which generates an empty "iltcg"
1259 : // debug directory entry.
1260 E : if (debug_directory->SizeOfData == 0)
1261 E : continue;
1262 :
1263 : // Chunk the data referenced by the debug directory entry.
1264 E : AddBlock(BlockGraph::DATA_BLOCK,
1265 : RelativeAddress(debug_directory->AddressOfRawData),
1266 : debug_directory->SizeOfData, "Debug Info");
1267 E : } while (debug_directory.Next());
1268 :
1269 E : return debug_directory_block;
1270 E : }
1271 :
1272 : BlockGraph::Block* PEFileParser::ParseResourceDir(
1273 E : const IMAGE_DATA_DIRECTORY& dir) {
1274 : BlockGraph::Block* resource_block =
1275 E : AddBlock(BlockGraph::DATA_BLOCK,
1276 : RelativeAddress(dir.VirtualAddress),
1277 : dir.Size,
1278 : "Resource Directory");
1279 E : if (resource_block == NULL)
1280 i : return NULL;
1281 :
1282 E : if (!ParseResourceDirImpl(resource_block, 0))
1283 i : return NULL;
1284 :
1285 E : return resource_block;
1286 E : }
1287 :
1288 : bool PEFileParser::ParseResourceDirImpl(BlockGraph::Block* resource_block,
1289 E : size_t root_offset) {
1290 E : DCHECK(resource_block != NULL);
1291 E : RelativeAddress root_addr = resource_block->addr();
1292 :
1293 : // Setup the directory node we're currently scanning.
1294 E : PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY> directory;
1295 E : if (!directory.Set(resource_block, root_addr + root_offset)) {
1296 i : LOG(ERROR) << "Unable to read the resource directory.";
1297 i : return false;
1298 : }
1299 :
1300 : // How many entries hang from this node in the resource tree?
1301 E : size_t num_entries = directory->NumberOfNamedEntries +
1302 : directory->NumberOfIdEntries;
1303 E : size_t entry_offset = root_offset + sizeof(IMAGE_RESOURCE_DIRECTORY);
1304 :
1305 : // Let's walk through them.
1306 E : for (size_t i = 0; i < num_entries; ++i) {
1307 : // Note that the offsets in the directory entries are all relative to
1308 : // the root address of the resource block.
1309 E : PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY_ENTRY> directory_entry;
1310 E : if (!directory_entry.Set(resource_block, root_addr + entry_offset)) {
1311 i : LOG(ERROR) << "Unable to read the resource directory entry.";
1312 i : return false;
1313 : }
1314 E : if (directory_entry->DataIsDirectory) {
1315 E : if (!ParseResourceDirImpl(resource_block,
1316 : directory_entry->OffsetToDirectory)) {
1317 i : return false;
1318 : }
1319 E : } else {
1320 E : PEFileStructPtr<IMAGE_RESOURCE_DATA_ENTRY> data_entry;
1321 E : RelativeAddress entry_addr(root_addr + directory_entry->OffsetToData);
1322 E : if (!data_entry.Set(resource_block, entry_addr)) {
1323 i : LOG(ERROR) << "Unable to read the resource data entry.";
1324 i : return false;
1325 : }
1326 : // The offsets in the data entries are RVAs.
1327 E : if (!AddRelative(data_entry, &data_entry->OffsetToData)) {
1328 i : LOG(ERROR) << "Failed to add resouce data reference.";
1329 i : return false;
1330 : }
1331 : }
1332 E : entry_offset += sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY);
1333 E : }
1334 :
1335 E : return true;
1336 E : }
1337 :
1338 : bool PEFileParser::AddReference(RelativeAddress src,
1339 : BlockGraph::ReferenceType type,
1340 : BlockGraph::Size size,
1341 E : RelativeAddress dst) {
1342 E : return add_reference_.Run(src, type, size, dst);
1343 E : }
1344 :
1345 : BlockGraph::Block* PEFileParser::AddBlock(BlockGraph::BlockType type,
1346 : RelativeAddress addr,
1347 : BlockGraph::Size size,
1348 E : const char* name) {
1349 E : BlockGraph::Block* block = address_space_->AddBlock(type, addr, size, name);
1350 E : if (block != NULL) {
1351 E : block->set_attribute(BlockGraph::PE_PARSED);
1352 :
1353 : // Mark the source range from whence this block originates.
1354 E : bool pushed = block->source_ranges().Push(
1355 : BlockGraph::Block::DataRange(0, size),
1356 : BlockGraph::Block::SourceRange(addr, size));
1357 E : DCHECK(pushed);
1358 :
1359 : // Set the section for this block. We let blocks that belong to the header
1360 : // be marked with kInvalidSectionId.
1361 E : size_t section = image_file_.GetSectionIndex(addr, size);
1362 E : if (section == BlockGraph::kInvalidSectionId) {
1363 : // If no section was found for this block, we expect it to be a part of
1364 : // the header.
1365 E : const RelativeAddress end_of_headers(
1366 : image_file_.nt_headers()->OptionalHeader.SizeOfHeaders);
1367 E : if (addr + size > end_of_headers) {
1368 i : LOG(ERROR) << "Found a non-header block outside of sections.";
1369 i : return NULL;
1370 : }
1371 : }
1372 E : block->set_section(section);
1373 :
1374 E : const uint8_t* data = image_file_.GetImageData(addr, size);
1375 E : if (data != NULL)
1376 E : block->SetData(data, size);
1377 : }
1378 :
1379 E : return block;
1380 E : }
1381 :
1382 : template <typename ItemType>
1383 : bool PEFileParser::AddRelative(const PEFileStructPtr<ItemType>& structure,
1384 E : const DWORD* item) {
1385 E : DCHECK(item != NULL);
1386 E : if (*item == 0)
1387 E : return true;
1388 :
1389 E : return AddReference(structure.AddressOf(item),
1390 : BlockGraph::RELATIVE_REF,
1391 : sizeof(*item),
1392 : RelativeAddress(*item));
1393 E : }
1394 :
1395 : template <typename ItemType>
1396 : bool PEFileParser::AddAbsolute(const PEFileStructPtr<ItemType>& structure,
1397 E : const DWORD* item) {
1398 E : DCHECK(item != NULL);
1399 E : if (*item == 0)
1400 E : return true;
1401 :
1402 E : AbsoluteAddress abs(*item);
1403 E : RelativeAddress rel;
1404 :
1405 : // We expect item to be the direct (0 offset) absolute address of the
1406 : // in-image file structure. So, translation to an in-image relative
1407 : // address is expected to yield a valid RVA.
1408 E : return image_file_.Translate(abs, &rel) &&
1409 : AddReference(structure.AddressOf(item),
1410 : BlockGraph::ABSOLUTE_REF,
1411 : sizeof(*item),
1412 : rel);
1413 E : }
1414 :
1415 : template <typename ItemType>
1416 : bool PEFileParser::MaybeAddAbsolute(const PEFileStructPtr<ItemType>& structure,
1417 E : const DWORD* item) {
1418 E : DCHECK(item != NULL);
1419 :
1420 E : const uint8_t* tmp = reinterpret_cast<const uint8_t*>(item);
1421 : size_t offset =
1422 E : tmp - reinterpret_cast<const uint8_t*>(structure.ptr()) + sizeof(*item);
1423 E : if (structure.len() <= offset)
1424 E : return true;
1425 :
1426 E : return AddAbsolute(structure, item);
1427 E : }
1428 :
1429 : template <typename ItemType>
1430 : bool PEFileParser::AddFileOffset(const PEFileStructPtr<ItemType>& structure,
1431 E : const DWORD* item) {
1432 E : DCHECK(item != NULL);
1433 E : if (*item == 0)
1434 E : return true;
1435 :
1436 E : FileOffsetAddress offs(*item);
1437 E : RelativeAddress rel;
1438 :
1439 : // We expect item to be the direct (0 offset) file offset address of the
1440 : // in-image file structure. So, translation to an in-image relative
1441 : // address is expected to yield a valid RVA.
1442 E : return image_file_.Translate(offs, &rel) &&
1443 : AddReference(structure.AddressOf(item),
1444 : BlockGraph::FILE_OFFSET_REF,
1445 : sizeof(*item),
1446 : rel);
1447 E : }
1448 :
1449 : } // namespace pe
|