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