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* 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* 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* ptr() const { return ptr_; }
155 : void set_ptr(const uint8* 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* 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* tmp = reinterpret_cast<const uint8*>(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 : : image_file_(image_file),
274 : address_space_(address_space),
275 : 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 : const IMAGE_DATA_DIRECTORY& entry =
360 E : 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* data = pe_header->nt_headers->GetMutableData();
372 E : DCHECK_NE(static_cast<uint8*>(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 : reinterpret_cast<const uint8*>(image_file_.nt_headers()) -
397 E : reinterpret_cast<const uint8*>(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 : BlockGraph::Block* dos_header = AddBlock(BlockGraph::DATA_BLOCK,
416 : RelativeAddress(0),
417 : nt_headers_address.value(),
418 E : "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 : if (!AddRelative(dos_header_ptr,
430 E : 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 : if (!AddRelative(nt_headers_ptr,
443 E : &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 : size_t nt_headers_size = sizeof(IMAGE_NT_HEADERS) +
452 : nt_headers_ptr->FileHeader.NumberOfSections *
453 E : sizeof(IMAGE_SECTION_HEADER);
454 : // Chunk the NT & section headers.
455 : BlockGraph::Block* nt_headers = AddBlock(BlockGraph::DATA_BLOCK,
456 : nt_headers_address,
457 : nt_headers_size,
458 E : "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 : if (!AddRelative(nt_headers_ptr,
465 E : &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 : AddBlock(BlockGraph::DATA_BLOCK,
482 : RelativeAddress(dir.VirtualAddress),
483 : dir.Size,
484 E : "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 : 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 : if (!function.Set(export_dir_block,
515 E : 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 : 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 : if (!name.Set(export_dir_block,
547 E : 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 : 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 : 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 : DCHECK(!is_bound || table_type == kImportAddressTable ||
608 E : 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 : thunk_block = ChunkDelayBoundIATBlock(thunk_start, ixt_size,
619 E : ixt_name.c_str());
620 E : } else {
621 : // Try to add the block.
622 : thunk_block = AddBlock(BlockGraph::DATA_BLOCK,
623 : thunk_start,
624 : ixt_size,
625 E : 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 : thunk_block->SetLabel(thunk_start - thunk_block->addr(),
642 : ixt_name,
643 E : 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 : bool chunk_names = table_type == kImportNameTable ||
650 E : 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 : if (!ParseImportThunk(thunk_start, thunk_data_type, thunk_type,
656 E : 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 E : if (!AddRelative(thunk, &thunk->u1.AddressOfData)) {
699 i : LOG(ERROR) << "Unable to add import thunk reference.";
700 i : return false;
701 : }
702 :
703 : // Read the thunk and name & chunk it out.
704 E : PEFileStructPtr<IMAGE_IMPORT_BY_NAME> name_thunk;
705 E : RelativeAddress name_thunk_addr(thunk->u1.AddressOfData);
706 E : if (!name_thunk.Read(image_file_, name_thunk_addr)) {
707 i : LOG(ERROR) << "Unable to read import name thunk.";
708 i : return false;
709 : }
710 :
711 E : std::string function_name;
712 : RelativeAddress function_name_addr(
713 E : name_thunk.AddressOf(&name_thunk->Name));
714 E : if (!image_file_.ReadImageString(function_name_addr, &function_name)) {
715 i : LOG(ERROR) << "Unable to read import function name.";
716 i : return false;
717 : }
718 :
719 : // Calculate the even-padded size of the name thunk.
720 : size_t name_thunk_size = common::AlignUp(
721 E : offsetof(IMAGE_IMPORT_BY_NAME, Name) + function_name.size() + 1, 2);
722 :
723 : // Chunk the names only on request, as more than one IAT/INT may
724 : // point to the same name blocks.
725 E : if (chunk_name) {
726 : BlockGraph::Block* thunk = AddBlock(
727 : BlockGraph::DATA_BLOCK,
728 : name_thunk_addr,
729 : name_thunk_size,
730 : base::StringPrintf("Import Name Thunk \"%s\" from \"%s\"",
731 : function_name.c_str(),
732 E : module_name).c_str());
733 E : if (thunk == NULL) {
734 i : LOG(ERROR) << "Unable to add function name block.";
735 i : return false;
736 : }
737 :
738 E : if (!on_import_thunk_.Run(module_name, function_name.c_str(), thunk)) {
739 i : LOG(ERROR) << "OnImportThunk callback failed.";
740 i : return false;
741 : }
742 E : } else {
743 : #ifndef NDEBUG
744 : // Check that the name blocks exist in debug.
745 : BlockGraph::Block* block =
746 E : address_space_->GetBlockByAddress(name_thunk_addr);
747 E : DCHECK(block != NULL);
748 E : DCHECK_EQ(name_thunk_size, block->size());
749 : #endif // NDEBUG
750 : }
751 E : break;
752 : }
753 :
754 : case kCodeInImageThunkData: {
755 : // Add the code reference. This will check that it is in fact a reference
756 : // to an address in the image, and track the associated block
757 : // automatically.
758 E : if (!AddAbsolute(thunk, &thunk->u1.AddressOfData)) {
759 i : LOG(ERROR) << "Unable to add import thunk reference.";
760 i : return false;
761 : }
762 E : break;
763 : }
764 :
765 : case kCodeOutOfImageThunkData: {
766 : // This is an absolute address to code outside of the image. It may
767 : // actually have an address that lies inside our image because the
768 : // imported module may have an overlapping preferred load address.
769 i : if (thunk->u1.AddressOfData < 0x1000) {
770 i : AbsoluteAddress abs_addr(thunk->u1.AddressOfData);
771 i : LOG(ERROR) << thunk_type << " thunk to external code has invalid "
772 : << "address: " << abs_addr;
773 i : return false;
774 : }
775 : break;
776 : }
777 :
778 : case kArbitraryThunkData: {
779 : // We do nothing. Anything goes!
780 : break;
781 : }
782 : }
783 :
784 E : return true;
785 E : }
786 :
787 : BlockGraph::Block* PEFileParser::ChunkDelayBoundIATBlock(
788 E : RelativeAddress iat_addr, size_t iat_size, const char* iat_name) {
789 : BlockGraph::Block* iat_block = AddBlock(BlockGraph::DATA_BLOCK,
790 : iat_addr,
791 : iat_size,
792 E : iat_name);
793 E : if (iat_block != NULL)
794 E : return iat_block;
795 :
796 : // If we get here we were unable to create a block, so there must be a
797 : // conflict. We've seen the bound IATs for delay-loaded libraries be too
798 : // small. That is, one library's bound IAT is overwritten by another library's
799 : // bound IAT. We do our best to patch things up, by growing the conflicting
800 : // pre-existing block to also cover the range of the block we want to create.
801 : //
802 : // We extend the existing block by creating new blocks (one to the left, one
803 : // to the right) of the conflicting block that cover the portion of the new
804 : // table that is not covered. Then, we merge them all.
805 :
806 : iat_block = address_space_->GetFirstIntersectingBlock(iat_addr,
807 i : iat_size);
808 i : VLOG(1) << iat_name << " collides with existing block " << iat_block->name()
809 : << ".";
810 :
811 : // If we're completely contained within the conflicting block, there's no
812 : // expanding and merging to do.
813 i : if (iat_block->Contains(iat_addr, iat_size))
814 i : return iat_block;
815 :
816 : // Create a block to the left of the existing block, if the desired table
817 : // extends to the left.
818 i : if (iat_addr < iat_block->addr()) {
819 i : size_t pre_size = iat_block->addr() - iat_addr;
820 : BlockGraph::Block* pre_block = AddBlock(BlockGraph::DATA_BLOCK,
821 : iat_addr,
822 : pre_size,
823 i : iat_name);
824 : // This should never fail as iat_block is the *first* intersecting
825 : // block.
826 i : DCHECK(pre_block != NULL);
827 : }
828 :
829 : // Insert the missing part of this table to the right of the intersecting
830 : // block, if there is any needed.
831 i : RelativeAddress new_end = iat_addr + iat_size;
832 i : RelativeAddress old_end = iat_block->addr() + iat_block->size();
833 i : if (new_end > old_end) {
834 : BlockGraph::Block* next_block =
835 : address_space_->GetFirstIntersectingBlock(
836 i : old_end, new_end - old_end);
837 :
838 i : if (next_block != NULL)
839 i : new_end = next_block->addr();
840 :
841 i : if (new_end > old_end) {
842 : BlockGraph::Block* post_block = AddBlock(BlockGraph::DATA_BLOCK,
843 : old_end,
844 : new_end - old_end,
845 i : NULL);
846 : // This should never fail as we're inserting after the end of
847 : // iat_block, and before the start of the next block in the
848 : // address space.
849 i : DCHECK(post_block != NULL);
850 : }
851 : }
852 :
853 : // Merge the blocks to create one new contiguous block.
854 i : BlockGraph::AddressSpace::Range range(iat_addr, iat_size);
855 i : if (!address_space_->MergeIntersectingBlocks(range)) {
856 i : LOG(ERROR) << "Unable to merge intersecting bound IAT blocks.";
857 i : return NULL;
858 : }
859 i : iat_block = address_space_->GetContainingBlock(iat_addr, iat_size);
860 i : DCHECK(iat_block != NULL);
861 :
862 i : return iat_block;
863 E : }
864 :
865 : BlockGraph::Block* PEFileParser::ParseImportDir(
866 E : const IMAGE_DATA_DIRECTORY& dir) {
867 : // Read the import descriptor, we're going to iterate it.
868 E : RelativeAddress import_descriptor_addr(dir.VirtualAddress);
869 E : PEFileStructPtr<IMAGE_IMPORT_DESCRIPTOR> import_descriptor;
870 : if (!import_descriptor.Read(image_file_,
871 : import_descriptor_addr,
872 E : dir.Size)) {
873 i : LOG(ERROR) << "Unable to read the import directory.";
874 i : return NULL;
875 : }
876 :
877 : do {
878 : // The last import descriptor is a sentinel.
879 E : if (import_descriptor->Characteristics == 0) {
880 E : DCHECK_EQ(0U, import_descriptor->Name);
881 E : DCHECK_EQ(0U, import_descriptor->FirstThunk);
882 E : break;
883 : }
884 :
885 : // Read the name of the imported DLL.
886 E : std::string import_name;
887 E : RelativeAddress import_name_addr(import_descriptor->Name);
888 E : if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
889 i : LOG(ERROR) << "Unable to read import name.";
890 i : return NULL;
891 : }
892 :
893 : if (!AddBlock(BlockGraph::DATA_BLOCK,
894 : import_name_addr,
895 : common::AlignUp(import_name.size() + 1, 2),
896 : base::StringPrintf("Import DLL Name \"%s\"",
897 E : import_name.c_str()).c_str())) {
898 i : LOG(ERROR) << "Unable to create import name block.";
899 i : return NULL;
900 : }
901 :
902 E : if (!AddRelative(import_descriptor, &import_descriptor->Name)) {
903 i : LOG(ERROR) << "Unable to add import name reference.";
904 i : return NULL;
905 : }
906 :
907 : // Count the number of import name thunks for this import descriptor.
908 : RelativeAddress thunk_addr =
909 E : RelativeAddress(import_descriptor->OriginalFirstThunk);
910 E : size_t num_thunks = CountImportThunks(thunk_addr);
911 E : if (num_thunks == 0)
912 i : return NULL;
913 :
914 : // Parse the Import Name Table.
915 : if (!ParseImportThunks(thunk_addr, num_thunks, false,
916 E : kImportNameTable, "INT", import_name.c_str())) {
917 i : return NULL;
918 : }
919 :
920 : // Parse the Import Address Table.
921 E : bool iat_is_bound = import_descriptor->TimeDateStamp != 0;
922 : if (!ParseImportThunks(RelativeAddress(import_descriptor->FirstThunk),
923 : num_thunks, iat_is_bound,
924 E : kImportAddressTable, "IAT", import_name.c_str())) {
925 i : return NULL;
926 : }
927 :
928 : if (!AddRelative(import_descriptor,
929 E : &import_descriptor->OriginalFirstThunk)) {
930 i : LOG(ERROR) << "Unable to add import name table reference.";
931 i : return NULL;
932 : }
933 :
934 E : if (!AddRelative(import_descriptor, &import_descriptor->FirstThunk)) {
935 i : LOG(ERROR) << "Unable to add import address table reference.";
936 i : return NULL;
937 : }
938 E : } while (import_descriptor.Next());
939 :
940 : BlockGraph::Block* import_descriptor_block =
941 : AddBlock(BlockGraph::DATA_BLOCK,
942 : import_descriptor_addr,
943 : import_descriptor.addr() - import_descriptor_addr +
944 : sizeof(IMAGE_IMPORT_DESCRIPTOR),
945 E : "Import Directory");
946 :
947 E : return import_descriptor_block;
948 E : }
949 :
950 : BlockGraph::Block *PEFileParser::ParseComDescriptorDir(
951 i : const IMAGE_DATA_DIRECTORY &dir) {
952 i : LOG(ERROR) << "Parsing for COM descriptors not implemented.";
953 i : return NULL;
954 i : }
955 :
956 : BlockGraph::Block *PEFileParser::ParseDelayImportDir(
957 E : const IMAGE_DATA_DIRECTORY &dir) {
958 : // Read the delay import descriptor, we're going to iterate it.
959 E : RelativeAddress import_descriptor_addr(dir.VirtualAddress);
960 E : PEFileStructPtr<ImgDelayDescr> import_descriptor;
961 : if (!import_descriptor.Read(image_file_,
962 : import_descriptor_addr,
963 E : dir.Size)) {
964 i : LOG(ERROR) << "Unable to read the delay import directory.";
965 i : return NULL;
966 : }
967 :
968 : do {
969 : // The last descriptor is a sentinel.
970 E : if (import_descriptor->grAttrs == 0)
971 E : break;
972 :
973 E : if (import_descriptor->grAttrs != dlattrRva) {
974 i : LOG(ERROR) << "Unexpected attributes in delay import descriptor 0x"
975 : << std::hex << import_descriptor->grAttrs;
976 i : return NULL;
977 : }
978 :
979 : // Read the name of the delay imported DLL.
980 E : std::string import_name;
981 E : RelativeAddress import_name_addr(import_descriptor->rvaDLLName);
982 E : if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
983 i : LOG(ERROR) << "Unable to read delay import name.";
984 i : return NULL;
985 : }
986 :
987 : if (!AddBlock(BlockGraph::DATA_BLOCK,
988 : import_name_addr,
989 : common::AlignUp(import_name.size() + 1, 2),
990 : base::StringPrintf("Delay import DLL Name \"%s\"",
991 E : import_name.c_str()).c_str())) {
992 i : LOG(ERROR) << "Unable to create import name block.";
993 i : return NULL;
994 : }
995 :
996 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaDLLName)) {
997 i : LOG(ERROR) << "Unable to add delay import name reference.";
998 i : return NULL;
999 : }
1000 :
1001 : // Chunk the HMODULE for this import.
1002 : if (!AddBlock(BlockGraph::DATA_BLOCK,
1003 : RelativeAddress(import_descriptor->rvaHmod),
1004 : sizeof(HMODULE),
1005 : base::StringPrintf("Module handle for delay import DLL\"%s\"",
1006 E : import_name.c_str()).c_str())) {
1007 i : LOG(ERROR) << "Unable to create import module handle block.";
1008 i : return NULL;
1009 : }
1010 :
1011 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaHmod)) {
1012 i : LOG(ERROR) << "Unable to delay import module handle reference.";
1013 i : return NULL;
1014 : }
1015 :
1016 : // Count the number of import name thunks for this import descriptor.
1017 E : RelativeAddress int_addr(import_descriptor->rvaINT);
1018 E : size_t num_thunks = CountImportThunks(int_addr);
1019 E : if (num_thunks == 0)
1020 i : return NULL;
1021 :
1022 : // Parse the Delay Import Name Table.
1023 : if (!ParseImportThunks(int_addr, num_thunks, false,
1024 : kDelayLoadImportNameTable, "DelayINT",
1025 E : import_name.c_str())) {
1026 i : return NULL;
1027 : }
1028 :
1029 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaINT)) {
1030 i : LOG(ERROR) << "Unable to add delay import name table reference.";
1031 i : return NULL;
1032 : }
1033 :
1034 : // Parse the Delay Import Address Table.
1035 : if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaIAT),
1036 : num_thunks, false,
1037 : kDelayLoadImportAddressTable, "DelayIAT",
1038 E : import_name.c_str())) {
1039 i : return NULL;
1040 : }
1041 :
1042 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaIAT)) {
1043 i : LOG(ERROR) << "Unable to add delay import address table reference.";
1044 i : return NULL;
1045 : }
1046 :
1047 : // Parse the Bound Import Address Table.
1048 E : bool iat_is_bound = import_descriptor->dwTimeStamp != 0;
1049 : if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaBoundIAT),
1050 : num_thunks, iat_is_bound,
1051 : kDelayLoadBoundImportAddressTable, "DelayBoundIAT",
1052 E : import_name.c_str())) {
1053 i : return NULL;
1054 : }
1055 :
1056 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaBoundIAT)) {
1057 i : LOG(ERROR) << "Unable to add delay bound import address table reference.";
1058 i : return NULL;
1059 : }
1060 :
1061 E : if (import_descriptor->rvaUnloadIAT != 0U) {
1062 i : LOG(ERROR) << "Unexpected UnloadIAT.";
1063 i : return NULL;
1064 : }
1065 :
1066 E : if (import_descriptor->dwTimeStamp != 0U) {
1067 i : LOG(ERROR) << "Unexpected bound delay imports.";
1068 i : return NULL;
1069 : }
1070 E : } while (import_descriptor.Next());
1071 :
1072 : BlockGraph::Block* import_descriptor_block =
1073 : AddBlock(BlockGraph::DATA_BLOCK,
1074 : import_descriptor_addr,
1075 : import_descriptor.addr() - import_descriptor_addr +
1076 : sizeof(ImgDelayDescr),
1077 E : "Delay Import Directory");
1078 :
1079 E : return import_descriptor_block;
1080 E : }
1081 :
1082 : BlockGraph::Block *PEFileParser::ParseIatDir(
1083 E : const IMAGE_DATA_DIRECTORY &dir) {
1084 : return AddBlock(BlockGraph::DATA_BLOCK,
1085 : RelativeAddress(dir.VirtualAddress),
1086 : dir.Size,
1087 E : "Import Address Table");
1088 E : }
1089 :
1090 : BlockGraph::Block *PEFileParser::ParseBoundImportDir(
1091 i : const IMAGE_DATA_DIRECTORY &dir) {
1092 i : LOG(ERROR) << "Parsing for bound import dir not implemented.";
1093 i : return NULL;
1094 i : }
1095 :
1096 : BlockGraph::Block *PEFileParser::ParseGlobalDir(
1097 i : const IMAGE_DATA_DIRECTORY &dir) {
1098 i : LOG(ERROR) << "Parsing for global dir not implemented.";
1099 i : return NULL;
1100 i : }
1101 :
1102 : BlockGraph::Block *PEFileParser::ParseArchitectureDir(
1103 i : const IMAGE_DATA_DIRECTORY &dir) {
1104 i : LOG(ERROR) << "Parsing for architecture dir not implemented.";
1105 i : return NULL;
1106 i : }
1107 :
1108 : BlockGraph::Block *PEFileParser::ParseRelocDir(
1109 E : const IMAGE_DATA_DIRECTORY &dir) {
1110 : return AddBlock(BlockGraph::DATA_BLOCK,
1111 : RelativeAddress(dir.VirtualAddress),
1112 : dir.Size,
1113 E : "Relocations");
1114 E : }
1115 :
1116 : BlockGraph::Block *PEFileParser::ParseSecurityDir(
1117 i : const IMAGE_DATA_DIRECTORY &dir) {
1118 i : LOG(ERROR) << "Parsing for security dir not implemented.";
1119 i : return NULL;
1120 i : }
1121 :
1122 : BlockGraph::Block *PEFileParser::ParseExceptionDir(
1123 i : const IMAGE_DATA_DIRECTORY &dir) {
1124 i : LOG(ERROR) << "Parsing for exception dir not implemented.";
1125 i : return NULL;
1126 i : }
1127 :
1128 : BlockGraph::Block* PEFileParser::ParseTlsDir(
1129 E : const IMAGE_DATA_DIRECTORY& dir) {
1130 : BlockGraph::Block* tls_directory_block =
1131 : AddBlock(BlockGraph::DATA_BLOCK,
1132 : RelativeAddress(dir.VirtualAddress),
1133 : sizeof(IMAGE_TLS_DIRECTORY),
1134 E : "Tls Directory");
1135 E : if (tls_directory_block == NULL)
1136 i : return NULL;
1137 :
1138 E : PEFileStructPtr<IMAGE_TLS_DIRECTORY> tls_directory;
1139 E : if (!tls_directory.Set(tls_directory_block)) {
1140 i : LOG(ERROR) << "Unable to read the TLS directory.";
1141 i : return NULL;
1142 : }
1143 :
1144 E : return tls_directory_block;
1145 E : }
1146 :
1147 : BlockGraph::Block* PEFileParser::ParseLoadConfigDir(
1148 E : const IMAGE_DATA_DIRECTORY& dir) {
1149 : // The load config directory starts with a size field, which we use as the
1150 : // size for chunking. It appears the size of the data directory entry is
1151 : // always fixed, but the structure itself has grown over time.
1152 E : PEFileStructPtr<DWORD> load_config_len;
1153 E : if (!load_config_len.Read(image_file_, RelativeAddress(dir.VirtualAddress))) {
1154 i : LOG(ERROR) << "Unable to read load config len.";
1155 i : return NULL;
1156 : }
1157 :
1158 : LoadConfigDirectoryVersion load_config_version =
1159 E : kLoadConfigDirectorySizeUnknown;
1160 E : switch (*load_config_len.ptr()) {
1161 : case kLoadConfigDirectorySize80:
1162 : case kLoadConfigDirectorySize81:
1163 : load_config_version =
1164 E : static_cast<LoadConfigDirectoryVersion>(*load_config_len.ptr());
1165 E : break;
1166 : default:
1167 i : LOG(ERROR) << "Unknown version of the IMAGE_LOAD_CONFIG_DIRECTORY "
1168 : << "structure (" << *load_config_len.ptr() << " bytes), might "
1169 : << "be because you're using a new version of the Windows SDK.";
1170 i : return NULL;
1171 : }
1172 :
1173 : BlockGraph::Block* load_config_block =
1174 : AddBlock(BlockGraph::DATA_BLOCK,
1175 : RelativeAddress(dir.VirtualAddress),
1176 : *load_config_len.ptr(),
1177 E : "Load Config Directory");
1178 :
1179 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), load_config_block);
1180 :
1181 : // Use SetUnchecked here as the load config structure may be longer than the
1182 : // data we have for it.
1183 E : PEFileStructPtr<LoadConfigDirectory> load_config;
1184 E : if (!load_config.SetUnchecked(load_config_block)) {
1185 i : LOG(ERROR) << "Unable to parse the load config directory.";
1186 i : return NULL;
1187 : }
1188 :
1189 : // TODO(siggi): Must length check prior to each of these...
1190 : if (!AddAbsolute(load_config, &load_config->LockPrefixTable) ||
1191 : !AddAbsolute(load_config, &load_config->EditList) ||
1192 : !AddAbsolute(load_config, &load_config->SecurityCookie) ||
1193 : !AddAbsolute(load_config, &load_config->SEHandlerTable) ||
1194 : !MaybeAddAbsolute(load_config,
1195 : &load_config->GuardCFCheckFunctionPointer) ||
1196 E : !MaybeAddAbsolute(load_config, &load_config->GuardCFFunctionTable)) {
1197 i : LOG(ERROR) << "Unable to add load config directory references.";
1198 i : return NULL;
1199 : }
1200 :
1201 : // Iterate the exception handlers and add references for them.
1202 E : RelativeAddress seh_handler;
1203 E : PEFileStructPtr<DWORD> seh_handlers;
1204 : if (!image_file_.Translate(AbsoluteAddress(load_config->SEHandlerTable),
1205 : &seh_handler) ||
1206 : !seh_handlers.Read(image_file_, seh_handler,
1207 E : load_config->SEHandlerCount * sizeof(DWORD))) {
1208 i : LOG(ERROR) << "Unable to read SEH handler table.";
1209 i : return NULL;
1210 : }
1211 :
1212 E : for (size_t i = 0; i < load_config->SEHandlerCount; ++i) {
1213 E : if (!AddRelative(seh_handlers, seh_handlers.ptr() + i)) {
1214 i : LOG(ERROR) << "Unable to add SEH handler reference.";
1215 i : return NULL;
1216 : }
1217 E : }
1218 :
1219 : // TODO(siggi): Add new load config directory fields.
1220 : // As of WDK 8.1 we have the following new fields:
1221 : // DWORD GuardCFCheckFunctionPointer; // VA
1222 : // DWORD Reserved2;
1223 : // DWORD GuardCFFunctionTable; // VA
1224 : // DWORD GuardCFFunctionCount;
1225 : // DWORD GuardFlags;
1226 :
1227 E : return load_config_block;
1228 E : }
1229 :
1230 : BlockGraph::Block* PEFileParser::ParseDebugDir(
1231 E : const IMAGE_DATA_DIRECTORY& dir) {
1232 : BlockGraph::Block* debug_directory_block =
1233 : AddBlock(BlockGraph::DATA_BLOCK,
1234 : RelativeAddress(dir.VirtualAddress),
1235 : dir.Size,
1236 E : "Debug Directory");
1237 E : if (debug_directory_block == NULL)
1238 i : return NULL;
1239 :
1240 E : PEFileStructPtr<IMAGE_DEBUG_DIRECTORY> debug_directory;
1241 E : if (!debug_directory.Set(debug_directory_block)) {
1242 i : LOG(ERROR) << "Unable to read the debug directory.";
1243 i : return NULL;
1244 : }
1245 :
1246 : do {
1247 : if (!AddRelative(debug_directory, &debug_directory->AddressOfRawData) ||
1248 E : !AddFileOffset(debug_directory, &debug_directory->PointerToRawData)) {
1249 i : LOG(ERROR) << "Failed to add debug directory references.";
1250 i : return NULL;
1251 : }
1252 :
1253 : // Chunk the data referenced by the debug directory entry.
1254 : AddBlock(BlockGraph::DATA_BLOCK,
1255 : RelativeAddress(debug_directory->AddressOfRawData),
1256 E : debug_directory->SizeOfData, "Debug Info");
1257 E : } while (debug_directory.Next());
1258 :
1259 E : return debug_directory_block;
1260 E : }
1261 :
1262 : BlockGraph::Block* PEFileParser::ParseResourceDir(
1263 E : const IMAGE_DATA_DIRECTORY& dir) {
1264 : BlockGraph::Block* resource_block =
1265 : AddBlock(BlockGraph::DATA_BLOCK,
1266 : RelativeAddress(dir.VirtualAddress),
1267 : dir.Size,
1268 E : "Resource Directory");
1269 E : if (resource_block == NULL)
1270 i : return NULL;
1271 :
1272 E : if (!ParseResourceDirImpl(resource_block, 0))
1273 i : return NULL;
1274 :
1275 E : return resource_block;
1276 E : }
1277 :
1278 : bool PEFileParser::ParseResourceDirImpl(BlockGraph::Block* resource_block,
1279 E : size_t root_offset) {
1280 E : DCHECK(resource_block != NULL);
1281 E : RelativeAddress root_addr = resource_block->addr();
1282 :
1283 : // Setup the directory node we're currently scanning.
1284 E : PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY> directory;
1285 E : if (!directory.Set(resource_block, root_addr + root_offset)) {
1286 i : LOG(ERROR) << "Unable to read the resource directory.";
1287 i : return false;
1288 : }
1289 :
1290 : // How many entries hang from this node in the resource tree?
1291 : size_t num_entries = directory->NumberOfNamedEntries +
1292 E : directory->NumberOfIdEntries;
1293 E : size_t entry_offset = root_offset + sizeof(IMAGE_RESOURCE_DIRECTORY);
1294 :
1295 : // Let's walk through them.
1296 E : for (size_t i = 0; i < num_entries; ++i) {
1297 : // Note that the offsets in the directory entries are all relative to
1298 : // the root address of the resource block.
1299 E : PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY_ENTRY> directory_entry;
1300 E : if (!directory_entry.Set(resource_block, root_addr + entry_offset)) {
1301 i : LOG(ERROR) << "Unable to read the resource directory entry.";
1302 i : return false;
1303 : }
1304 E : if (directory_entry->DataIsDirectory) {
1305 : if (!ParseResourceDirImpl(resource_block,
1306 E : directory_entry->OffsetToDirectory)) {
1307 i : return false;
1308 : }
1309 E : } else {
1310 E : PEFileStructPtr<IMAGE_RESOURCE_DATA_ENTRY> data_entry;
1311 E : RelativeAddress entry_addr(root_addr + directory_entry->OffsetToData);
1312 E : if (!data_entry.Set(resource_block, entry_addr)) {
1313 i : LOG(ERROR) << "Unable to read the resource data entry.";
1314 i : return false;
1315 : }
1316 : // The offsets in the data entries are RVAs.
1317 E : if (!AddRelative(data_entry, &data_entry->OffsetToData)) {
1318 i : LOG(ERROR) << "Failed to add resouce data reference.";
1319 i : return false;
1320 : }
1321 : }
1322 E : entry_offset += sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY);
1323 E : }
1324 :
1325 E : return true;
1326 E : }
1327 :
1328 : bool PEFileParser::AddReference(RelativeAddress src,
1329 : BlockGraph::ReferenceType type,
1330 : BlockGraph::Size size,
1331 E : RelativeAddress dst) {
1332 E : return add_reference_.Run(src, type, size, dst);
1333 E : }
1334 :
1335 : BlockGraph::Block* PEFileParser::AddBlock(BlockGraph::BlockType type,
1336 : RelativeAddress addr,
1337 : BlockGraph::Size size,
1338 E : const char* name) {
1339 E : BlockGraph::Block* block = address_space_->AddBlock(type, addr, size, name);
1340 E : if (block != NULL) {
1341 E : block->set_attribute(BlockGraph::PE_PARSED);
1342 :
1343 : // Mark the source range from whence this block originates.
1344 : bool pushed = block->source_ranges().Push(
1345 : BlockGraph::Block::DataRange(0, size),
1346 E : BlockGraph::Block::SourceRange(addr, size));
1347 E : DCHECK(pushed);
1348 :
1349 : // Set the section for this block. We let blocks that belong to the header
1350 : // be marked with kInvalidSectionId.
1351 E : size_t section = image_file_.GetSectionIndex(addr, size);
1352 E : if (section == BlockGraph::kInvalidSectionId) {
1353 : // If no section was found for this block, we expect it to be a part of
1354 : // the header.
1355 : const RelativeAddress end_of_headers(
1356 E : image_file_.nt_headers()->OptionalHeader.SizeOfHeaders);
1357 E : if (addr + size > end_of_headers) {
1358 i : LOG(ERROR) << "Found a non-header block outside of sections.";
1359 i : return NULL;
1360 : }
1361 : }
1362 E : block->set_section(section);
1363 :
1364 E : const uint8* data = image_file_.GetImageData(addr, size);
1365 E : if (data != NULL)
1366 E : block->SetData(data, size);
1367 : }
1368 :
1369 E : return block;
1370 E : }
1371 :
1372 : template <typename ItemType>
1373 : bool PEFileParser::AddRelative(const PEFileStructPtr<ItemType>& structure,
1374 E : const DWORD* item) {
1375 E : DCHECK(item != NULL);
1376 E : if (*item == 0)
1377 E : return true;
1378 :
1379 : return AddReference(structure.AddressOf(item),
1380 : BlockGraph::RELATIVE_REF,
1381 : sizeof(*item),
1382 E : RelativeAddress(*item));
1383 E : }
1384 :
1385 : template <typename ItemType>
1386 : bool PEFileParser::AddAbsolute(const PEFileStructPtr<ItemType>& structure,
1387 E : const DWORD* item) {
1388 E : DCHECK(item != NULL);
1389 E : if (*item == 0)
1390 E : return true;
1391 :
1392 E : AbsoluteAddress abs(*item);
1393 E : RelativeAddress rel;
1394 :
1395 : // We expect item to be the direct (0 offset) absolute address of the
1396 : // in-image file structure. So, translation to an in-image relative
1397 : // address is expected to yield a valid RVA.
1398 : return image_file_.Translate(abs, &rel) &&
1399 : AddReference(structure.AddressOf(item),
1400 : BlockGraph::ABSOLUTE_REF,
1401 : sizeof(*item),
1402 E : rel);
1403 E : }
1404 :
1405 : template <typename ItemType>
1406 : bool PEFileParser::MaybeAddAbsolute(const PEFileStructPtr<ItemType>& structure,
1407 E : const DWORD* item) {
1408 E : DCHECK(item != NULL);
1409 :
1410 E : const uint8* tmp = reinterpret_cast<const uint8*>(item);
1411 : size_t offset = tmp - reinterpret_cast<const uint8*>(structure.ptr()) +
1412 E : sizeof(*item);
1413 E : if (structure.len() <= offset)
1414 E : return true;
1415 :
1416 E : return AddAbsolute(structure, item);
1417 E : }
1418 :
1419 : template <typename ItemType>
1420 : bool PEFileParser::AddFileOffset(const PEFileStructPtr<ItemType>& structure,
1421 E : const DWORD* item) {
1422 E : DCHECK(item != NULL);
1423 E : if (*item == 0)
1424 i : return true;
1425 :
1426 E : FileOffsetAddress offs(*item);
1427 E : RelativeAddress rel;
1428 :
1429 : // We expect item to be the direct (0 offset) file offset address of the
1430 : // in-image file structure. So, translation to an in-image relative
1431 : // address is expected to yield a valid RVA.
1432 : return image_file_.Translate(offs, &rel) &&
1433 : AddReference(structure.AddressOf(item),
1434 : BlockGraph::FILE_OFFSET_REF,
1435 : sizeof(*item),
1436 E : rel);
1437 E : }
1438 :
1439 : } // namespace pe
|