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