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/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 : // All the references in the export directory should point back into
470 : // the export directory, sanity check this.
471 : DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
472 : RelativeAddress(export_dir->AddressOfFunctions),
473 E : sizeof(RelativeAddress)));
474 : DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
475 : RelativeAddress(export_dir->AddressOfNames),
476 E : sizeof(RelativeAddress)));
477 : DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
478 : RelativeAddress(export_dir->AddressOfNameOrdinals),
479 E : sizeof(RelativeAddress)));
480 :
481 : // Add the export directory references.
482 E : if (!AddRelative(export_dir, &export_dir->Name)) {
483 i : LOG(ERROR) << "Unable to add export functions reference.";
484 i : return NULL;
485 : }
486 :
487 E : if (!AddRelative(export_dir, &export_dir->AddressOfFunctions)) {
488 i : LOG(ERROR) << "Unable to add export functions reference.";
489 i : return NULL;
490 : }
491 :
492 E : if (!AddRelative(export_dir, &export_dir->AddressOfNames)) {
493 i : LOG(ERROR) << "Unable to add export address of names reference.";
494 i : return NULL;
495 : }
496 :
497 E : if (!AddRelative(export_dir, &export_dir->AddressOfNameOrdinals)) {
498 i : LOG(ERROR) << "Unable to add export address of ordinals reference.";
499 i : return NULL;
500 : }
501 :
502 E : PEFileStructPtr<DWORD> function;
503 : if (!function.Set(export_dir_block,
504 E : RelativeAddress(export_dir->AddressOfFunctions))) {
505 i : LOG(ERROR) << "Unable to parse export function table.";
506 i : return NULL;
507 : }
508 :
509 E : for (size_t i = 0; i < export_dir->NumberOfFunctions; ++i) {
510 : // TODO(siggi): This could be labeled with the exported function's
511 : // name, if one is available.
512 E : if (!AddRelative(function, function.ptr())) {
513 i : LOG(ERROR) << "Unable to add reference to exported function.";
514 i : return NULL;
515 : }
516 :
517 E : if (!function.Next()) {
518 i : LOG(ERROR) << "Unable to parse export function table.";
519 i : return NULL;
520 : }
521 E : }
522 :
523 : // Add references to the export function names.
524 E : PEFileStructPtr<DWORD> name;
525 : if (!name.Set(export_dir_block,
526 E : RelativeAddress(export_dir->AddressOfNames))) {
527 i : LOG(ERROR) << "Unable to parse export name table.";
528 : }
529 :
530 E : for (size_t i = 0; i < export_dir->NumberOfNames; ++i) {
531 : // All the names in the export directory should point back into
532 : // the export directory, sanity check this.
533 : DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
534 : RelativeAddress(*name.ptr()),
535 E : sizeof(RelativeAddress)));
536 :
537 E : if (!AddRelative(name, name.ptr())) {
538 i : LOG(ERROR) << "Unable to add reference to export function name.";
539 i : return NULL;
540 : }
541 :
542 E : if (!name.Next()) {
543 i : LOG(ERROR) << "Unable to parse export function table.";
544 i : return NULL;
545 : }
546 E : }
547 :
548 E : return export_dir_block;
549 E : }
550 :
551 E : size_t PEFileParser::CountImportThunks(RelativeAddress thunk_start) {
552 E : size_t num_thunks = 0;
553 E : for (; true; ++num_thunks, thunk_start += sizeof(IMAGE_THUNK_DATA)) {
554 E : PEFileStructPtr<IMAGE_THUNK_DATA> thunk;
555 E : if (!thunk.Read(image_file_, thunk_start)) {
556 : // We didn't get to the sentinel, that's an error.
557 i : LOG(ERROR) << "Unable to read image import thunk.";
558 i : return 0;
559 : }
560 :
561 E : if (thunk->u1.AddressOfData == 0U)
562 E : break;
563 E : }
564 :
565 E : return num_thunks;
566 E : }
567 :
568 : bool PEFileParser::ParseImportThunks(RelativeAddress thunk_start,
569 : size_t num_thunks,
570 : bool is_bound,
571 : ThunkTableType table_type,
572 : const char* thunk_type,
573 E : const char* import_name) {
574 : // Only certain table types may be bound.
575 : DCHECK(!is_bound || table_type == kImportAddressTable ||
576 E : table_type == kDelayLoadBoundImportAddressTable);
577 :
578 : // Start by chunking the IAT/INT, including the terminating sentinel.
579 E : size_t ixt_size = sizeof(IMAGE_THUNK_DATA) * (num_thunks + 1);
580 :
581 : std::string ixt_name =
582 E : base::StringPrintf("%s for \"%s\"", thunk_type, import_name);
583 :
584 E : BlockGraph::Block* thunk_block = NULL;
585 E : if (table_type == kDelayLoadBoundImportAddressTable) {
586 : thunk_block = ChunkDelayBoundIATBlock(thunk_start, ixt_size,
587 E : ixt_name.c_str());
588 E : } else {
589 : // Try to add the block.
590 : thunk_block = AddBlock(BlockGraph::DATA_BLOCK,
591 : thunk_start,
592 : ixt_size,
593 E : ixt_name.c_str());
594 :
595 : // The IAT may have been chunked while parsing the IAT data directory,
596 : // in which case we want to leave a label for the start of our entries. In
597 : // this case we should be wholly contained in an existing block.
598 E : if (thunk_block == NULL)
599 E : thunk_block = address_space_->GetContainingBlock(thunk_start, ixt_size);
600 : }
601 :
602 E : if (thunk_block == NULL) {
603 i : LOG(ERROR) << "Unable to add " << thunk_type
604 : << "block for " << import_name;
605 i : return false;
606 : }
607 :
608 : // Add a label to the start of the table.
609 : thunk_block->SetLabel(thunk_start - thunk_block->addr(),
610 : ixt_name,
611 E : BlockGraph::DATA_LABEL);
612 :
613 : // Determine the type of data in the table. We only chunk out names for
614 : // import name tables. This prevents us from doing the work twice for an
615 : // unbound IAT.
616 E : ThunkDataType thunk_data_type = GetThunkDataType(table_type, is_bound);
617 : bool chunk_names = table_type == kImportNameTable ||
618 E : table_type == kDelayLoadImportNameTable;
619 :
620 : // Run through and validate the table contents, parsing IMAGE_IMPORT_BY_NAMES
621 : // if we're in an import name table.
622 E : for (size_t i = 0; i < num_thunks; ++i) {
623 : if (!ParseImportThunk(thunk_start, thunk_data_type, thunk_type,
624 E : import_name, chunk_names)) {
625 i : return false;
626 : }
627 E : thunk_start += sizeof(IMAGE_THUNK_DATA);
628 E : }
629 :
630 E : return true;
631 E : }
632 :
633 : bool PEFileParser::ParseImportThunk(RelativeAddress thunk_addr,
634 : ThunkDataType thunk_data_type,
635 : const char* thunk_type,
636 : const char* module_name,
637 E : bool chunk_name) {
638 : // We can only chunk names if we're parsing an IMAGE_THUNK_DATA object.
639 E : DCHECK(!chunk_name || thunk_data_type == kImageThunkData);
640 :
641 E : PEFileStructPtr<IMAGE_THUNK_DATA> thunk;
642 E : if (!thunk.Read(image_file_, thunk_addr)) {
643 i : LOG(ERROR) << "Unable to read image import thunk.";
644 i : return false;
645 : }
646 :
647 E : switch (thunk_data_type) {
648 : case kNullThunkData: {
649 i : if (thunk->u1.AddressOfData != 0) {
650 i : LOG(ERROR) << "Expect NULL " << thunk_type << " thunk, got 0x"
651 : << std::hex << thunk->u1.AddressOfData;
652 i : return false;
653 : }
654 i : break;
655 : }
656 :
657 : case kImageThunkData: {
658 : // If it's an ordinal, there's nothing to do.
659 E : if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
660 E : break;
661 :
662 : // It's not an ordinal, so it must contain an RVA to an
663 : // IMAGE_IMPORT_BY_NAME.
664 :
665 : // Add the IAT/INT->thunk reference.
666 E : if (!AddRelative(thunk, &thunk->u1.AddressOfData)) {
667 i : LOG(ERROR) << "Unable to add import thunk reference.";
668 i : return false;
669 : }
670 :
671 : // Read the thunk and name & chunk it out.
672 E : PEFileStructPtr<IMAGE_IMPORT_BY_NAME> name_thunk;
673 E : RelativeAddress name_thunk_addr(thunk->u1.AddressOfData);
674 E : if (!name_thunk.Read(image_file_, name_thunk_addr)) {
675 i : LOG(ERROR) << "Unable to read import name thunk.";
676 i : return false;
677 : }
678 :
679 E : std::string function_name;
680 : RelativeAddress function_name_addr(
681 E : name_thunk.AddressOf(&name_thunk->Name));
682 E : if (!image_file_.ReadImageString(function_name_addr, &function_name)) {
683 i : LOG(ERROR) << "Unable to read import function name.";
684 i : return false;
685 : }
686 :
687 : // Calculate the even-padded size of the name thunk.
688 : size_t name_thunk_size = common::AlignUp(
689 E : offsetof(IMAGE_IMPORT_BY_NAME, Name) + function_name.size() + 1, 2);
690 :
691 : // Chunk the names only on request, as more than one IAT/INT may
692 : // point to the same name blocks.
693 E : if (chunk_name) {
694 : BlockGraph::Block* thunk = AddBlock(
695 : BlockGraph::DATA_BLOCK,
696 : name_thunk_addr,
697 : name_thunk_size,
698 : base::StringPrintf("Import Name Thunk \"%s\" from \"%s\"",
699 : function_name.c_str(),
700 E : module_name).c_str());
701 E : if (thunk == NULL) {
702 i : LOG(ERROR) << "Unable to add function name block.";
703 i : return false;
704 : }
705 :
706 E : if (!on_import_thunk_.Run(module_name, function_name.c_str(), thunk)) {
707 i : LOG(ERROR) << "OnImportThunk callback failed.";
708 i : return false;
709 : }
710 E : } else {
711 : #ifndef NDEBUG
712 : // Check that the name blocks exist in debug.
713 : BlockGraph::Block* block =
714 E : address_space_->GetBlockByAddress(name_thunk_addr);
715 E : DCHECK(block != NULL);
716 E : DCHECK_EQ(name_thunk_size, block->size());
717 : #endif // NDEBUG
718 : }
719 E : break;
720 : }
721 :
722 : case kCodeInImageThunkData: {
723 : // Add the code reference. This will check that it is in fact a reference
724 : // to an address in the image, and track the associated block
725 : // automatically.
726 E : if (!AddAbsolute(thunk, &thunk->u1.AddressOfData)) {
727 i : LOG(ERROR) << "Unable to add import thunk reference.";
728 i : return false;
729 : }
730 E : break;
731 : }
732 :
733 : case kCodeOutOfImageThunkData: {
734 : // This is an absolute address to code outside of the image. It may
735 : // actually have an address that lies inside our image because the
736 : // imported module may have an overlapping preferred load address.
737 i : if (thunk->u1.AddressOfData < 0x1000) {
738 i : AbsoluteAddress abs_addr(thunk->u1.AddressOfData);
739 i : LOG(ERROR) << thunk_type << " thunk to external code has invalid "
740 : << "address: " << abs_addr;
741 i : return false;
742 : }
743 : break;
744 : }
745 :
746 : case kArbitraryThunkData: {
747 : // We do nothing. Anything goes!
748 : break;
749 : }
750 : }
751 :
752 E : return true;
753 E : }
754 :
755 : BlockGraph::Block* PEFileParser::ChunkDelayBoundIATBlock(
756 E : RelativeAddress iat_addr, size_t iat_size, const char* iat_name) {
757 : BlockGraph::Block* iat_block = AddBlock(BlockGraph::DATA_BLOCK,
758 : iat_addr,
759 : iat_size,
760 E : iat_name);
761 E : if (iat_block != NULL)
762 E : return iat_block;
763 :
764 : // If we get here we were unable to create a block, so there must be a
765 : // conflict. We've seen the bound IATs for delay-loaded libraries be too
766 : // small. That is, one library's bound IAT is overwritten by another library's
767 : // bound IAT. We do our best to patch things up, by growing the conflicting
768 : // pre-existing block to also cover the range of the block we want to create.
769 : //
770 : // We extend the existing block by creating new blocks (one to the left, one
771 : // to the right) of the conflicting block that cover the portion of the new
772 : // table that is not covered. Then, we merge them all.
773 :
774 : iat_block = address_space_->GetFirstIntersectingBlock(iat_addr,
775 i : iat_size);
776 i : VLOG(1) << iat_name << " collides with existing block " << iat_block->name()
777 : << ".";
778 :
779 : // If we're completely contained within the conflicting block, there's no
780 : // expanding and merging to do.
781 i : if (iat_block->Contains(iat_addr, iat_size))
782 i : return iat_block;
783 :
784 : // Create a block to the left of the existing block, if the desired table
785 : // extends to the left.
786 i : if (iat_addr < iat_block->addr()) {
787 i : size_t pre_size = iat_block->addr() - iat_addr;
788 : BlockGraph::Block* pre_block = AddBlock(BlockGraph::DATA_BLOCK,
789 : iat_addr,
790 : pre_size,
791 i : iat_name);
792 : // This should never fail as iat_block is the *first* intersecting
793 : // block.
794 i : DCHECK(pre_block != NULL);
795 : }
796 :
797 : // Insert the missing part of this table to the right of the intersecting
798 : // block, if there is any needed.
799 i : RelativeAddress new_end = iat_addr + iat_size;
800 i : RelativeAddress old_end = iat_block->addr() + iat_block->size();
801 i : if (new_end > old_end) {
802 : BlockGraph::Block* next_block =
803 : address_space_->GetFirstIntersectingBlock(
804 i : old_end, new_end - old_end);
805 :
806 i : if (next_block != NULL)
807 i : new_end = next_block->addr();
808 :
809 i : if (new_end > old_end) {
810 : BlockGraph::Block* post_block = AddBlock(BlockGraph::DATA_BLOCK,
811 : old_end,
812 : new_end - old_end,
813 i : NULL);
814 : // This should never fail as we're inserting after the end of
815 : // iat_block, and before the start of the next block in the
816 : // address space.
817 i : DCHECK(post_block != NULL);
818 : }
819 : }
820 :
821 : // Merge the blocks to create one new contiguous block.
822 i : BlockGraph::AddressSpace::Range range(iat_addr, iat_size);
823 i : if (!address_space_->MergeIntersectingBlocks(range)) {
824 i : LOG(ERROR) << "Unable to merge intersecting bound IAT blocks.";
825 i : return NULL;
826 : }
827 i : iat_block = address_space_->GetContainingBlock(iat_addr, iat_size);
828 i : DCHECK(iat_block != NULL);
829 :
830 i : return iat_block;
831 E : }
832 :
833 : BlockGraph::Block* PEFileParser::ParseImportDir(
834 E : const IMAGE_DATA_DIRECTORY& dir) {
835 : // Read the import descriptor, we're going to iterate it.
836 E : RelativeAddress import_descriptor_addr(dir.VirtualAddress);
837 E : PEFileStructPtr<IMAGE_IMPORT_DESCRIPTOR> import_descriptor;
838 : if (!import_descriptor.Read(image_file_,
839 : import_descriptor_addr,
840 E : dir.Size)) {
841 i : LOG(ERROR) << "Unable to read the import directory.";
842 i : return NULL;
843 : }
844 :
845 : do {
846 : // The last import descriptor is a sentinel.
847 E : if (import_descriptor->Characteristics == 0) {
848 E : DCHECK_EQ(0U, import_descriptor->Name);
849 E : DCHECK_EQ(0U, import_descriptor->FirstThunk);
850 E : break;
851 : }
852 :
853 : // Read the name of the imported DLL.
854 E : std::string import_name;
855 E : RelativeAddress import_name_addr(import_descriptor->Name);
856 E : if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
857 i : LOG(ERROR) << "Unable to read import name.";
858 i : return NULL;
859 : }
860 :
861 : if (!AddBlock(BlockGraph::DATA_BLOCK,
862 : import_name_addr,
863 : common::AlignUp(import_name.size() + 1, 2),
864 : base::StringPrintf("Import DLL Name \"%s\"",
865 E : import_name.c_str()).c_str())) {
866 i : LOG(ERROR) << "Unable to create import name block.";
867 i : return NULL;
868 : }
869 :
870 E : if (!AddRelative(import_descriptor, &import_descriptor->Name)) {
871 i : LOG(ERROR) << "Unable to add import name reference.";
872 i : return NULL;
873 : }
874 :
875 : // Count the number of import name thunks for this import descriptor.
876 : RelativeAddress thunk_addr =
877 E : RelativeAddress(import_descriptor->OriginalFirstThunk);
878 E : size_t num_thunks = CountImportThunks(thunk_addr);
879 E : if (num_thunks == 0)
880 i : return NULL;
881 :
882 : // Parse the Import Name Table.
883 : if (!ParseImportThunks(thunk_addr, num_thunks, false,
884 E : kImportNameTable, "INT", import_name.c_str())) {
885 i : return NULL;
886 : }
887 :
888 : // Parse the Import Address Table.
889 E : bool iat_is_bound = import_descriptor->TimeDateStamp != 0;
890 : if (!ParseImportThunks(RelativeAddress(import_descriptor->FirstThunk),
891 : num_thunks, iat_is_bound,
892 E : kImportAddressTable, "IAT", import_name.c_str())) {
893 i : return NULL;
894 : }
895 :
896 : if (!AddRelative(import_descriptor,
897 E : &import_descriptor->OriginalFirstThunk)) {
898 i : LOG(ERROR) << "Unable to add import name table reference.";
899 i : return NULL;
900 : }
901 :
902 E : if (!AddRelative(import_descriptor, &import_descriptor->FirstThunk)) {
903 i : LOG(ERROR) << "Unable to add import address table reference.";
904 i : return NULL;
905 : }
906 E : } while (import_descriptor.Next());
907 :
908 : BlockGraph::Block* import_descriptor_block =
909 : AddBlock(BlockGraph::DATA_BLOCK,
910 : import_descriptor_addr,
911 : import_descriptor.addr() - import_descriptor_addr +
912 : sizeof(IMAGE_IMPORT_DESCRIPTOR),
913 E : "Import Directory");
914 :
915 E : return import_descriptor_block;
916 E : }
917 :
918 : BlockGraph::Block *PEFileParser::ParseComDescriptorDir(
919 i : const IMAGE_DATA_DIRECTORY &dir) {
920 i : LOG(ERROR) << "Parsing for COM descriptors not implemented.";
921 i : return NULL;
922 i : }
923 :
924 : BlockGraph::Block *PEFileParser::ParseDelayImportDir(
925 E : const IMAGE_DATA_DIRECTORY &dir) {
926 : // Read the delay import descriptor, we're going to iterate it.
927 E : RelativeAddress import_descriptor_addr(dir.VirtualAddress);
928 E : PEFileStructPtr<ImgDelayDescr> import_descriptor;
929 : if (!import_descriptor.Read(image_file_,
930 : import_descriptor_addr,
931 E : dir.Size)) {
932 i : LOG(ERROR) << "Unable to read the delay import directory.";
933 i : return NULL;
934 : }
935 :
936 : do {
937 : // The last descriptor is a sentinel.
938 E : if (import_descriptor->grAttrs == 0)
939 E : break;
940 :
941 E : if (import_descriptor->grAttrs != dlattrRva) {
942 i : LOG(ERROR) << "Unexpected attributes in delay import descriptor 0x"
943 : << std::hex << import_descriptor->grAttrs;
944 i : return NULL;
945 : }
946 :
947 : // Read the name of the delay imported DLL.
948 E : std::string import_name;
949 E : RelativeAddress import_name_addr(import_descriptor->rvaDLLName);
950 E : if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
951 i : LOG(ERROR) << "Unable to read delay import name.";
952 i : return NULL;
953 : }
954 :
955 : if (!AddBlock(BlockGraph::DATA_BLOCK,
956 : import_name_addr,
957 : common::AlignUp(import_name.size() + 1, 2),
958 : base::StringPrintf("Delay import DLL Name \"%s\"",
959 E : import_name.c_str()).c_str())) {
960 i : LOG(ERROR) << "Unable to create import name block.";
961 i : return NULL;
962 : }
963 :
964 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaDLLName)) {
965 i : LOG(ERROR) << "Unable to add delay import name reference.";
966 i : return NULL;
967 : }
968 :
969 : // Chunk the HMODULE for this import.
970 : if (!AddBlock(BlockGraph::DATA_BLOCK,
971 : RelativeAddress(import_descriptor->rvaHmod),
972 : sizeof(HMODULE),
973 : base::StringPrintf("Module handle for delay import DLL\"%s\"",
974 E : import_name.c_str()).c_str())) {
975 i : LOG(ERROR) << "Unable to create import module handle block.";
976 i : return NULL;
977 : }
978 :
979 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaHmod)) {
980 i : LOG(ERROR) << "Unable to delay import module handle reference.";
981 i : return NULL;
982 : }
983 :
984 : // Count the number of import name thunks for this import descriptor.
985 E : RelativeAddress int_addr(import_descriptor->rvaINT);
986 E : size_t num_thunks = CountImportThunks(int_addr);
987 E : if (num_thunks == 0)
988 i : return NULL;
989 :
990 : // Parse the Delay Import Name Table.
991 : if (!ParseImportThunks(int_addr, num_thunks, false,
992 : kDelayLoadImportNameTable, "DelayINT",
993 E : import_name.c_str())) {
994 i : return NULL;
995 : }
996 :
997 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaINT)) {
998 i : LOG(ERROR) << "Unable to add delay import name table reference.";
999 i : return NULL;
1000 : }
1001 :
1002 : // Parse the Delay Import Address Table.
1003 : if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaIAT),
1004 : num_thunks, false,
1005 : kDelayLoadImportAddressTable, "DelayIAT",
1006 E : import_name.c_str())) {
1007 i : return NULL;
1008 : }
1009 :
1010 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaIAT)) {
1011 i : LOG(ERROR) << "Unable to add delay import address table reference.";
1012 i : return NULL;
1013 : }
1014 :
1015 : // Parse the Bound Import Address Table.
1016 E : bool iat_is_bound = import_descriptor->dwTimeStamp != 0;
1017 : if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaBoundIAT),
1018 : num_thunks, iat_is_bound,
1019 : kDelayLoadBoundImportAddressTable, "DelayBoundIAT",
1020 E : import_name.c_str())) {
1021 i : return NULL;
1022 : }
1023 :
1024 E : if (!AddRelative(import_descriptor, &import_descriptor->rvaBoundIAT)) {
1025 i : LOG(ERROR) << "Unable to add delay bound import address table reference.";
1026 i : return NULL;
1027 : }
1028 :
1029 E : if (import_descriptor->rvaUnloadIAT != 0U) {
1030 i : LOG(ERROR) << "Unexpected UnloadIAT.";
1031 i : return NULL;
1032 : }
1033 :
1034 E : if (import_descriptor->dwTimeStamp != 0U) {
1035 i : LOG(ERROR) << "Unexpected bound delay imports.";
1036 i : return NULL;
1037 : }
1038 E : } while (import_descriptor.Next());
1039 :
1040 : BlockGraph::Block* import_descriptor_block =
1041 : AddBlock(BlockGraph::DATA_BLOCK,
1042 : import_descriptor_addr,
1043 : import_descriptor.addr() - import_descriptor_addr +
1044 : sizeof(ImgDelayDescr),
1045 E : "Delay Import Directory");
1046 :
1047 E : return import_descriptor_block;
1048 E : }
1049 :
1050 : BlockGraph::Block *PEFileParser::ParseIatDir(
1051 E : const IMAGE_DATA_DIRECTORY &dir) {
1052 : return AddBlock(BlockGraph::DATA_BLOCK,
1053 : RelativeAddress(dir.VirtualAddress),
1054 : dir.Size,
1055 E : "Import Address Table");
1056 E : }
1057 :
1058 : BlockGraph::Block *PEFileParser::ParseBoundImportDir(
1059 i : const IMAGE_DATA_DIRECTORY &dir) {
1060 i : LOG(ERROR) << "Parsing for bound import dir not implemented.";
1061 i : return NULL;
1062 i : }
1063 :
1064 : BlockGraph::Block *PEFileParser::ParseGlobalDir(
1065 i : const IMAGE_DATA_DIRECTORY &dir) {
1066 i : LOG(ERROR) << "Parsing for global dir not implemented.";
1067 i : return NULL;
1068 i : }
1069 :
1070 : BlockGraph::Block *PEFileParser::ParseArchitectureDir(
1071 i : const IMAGE_DATA_DIRECTORY &dir) {
1072 i : LOG(ERROR) << "Parsing for architecture dir not implemented.";
1073 i : return NULL;
1074 i : }
1075 :
1076 : BlockGraph::Block *PEFileParser::ParseRelocDir(
1077 E : const IMAGE_DATA_DIRECTORY &dir) {
1078 : return AddBlock(BlockGraph::DATA_BLOCK,
1079 : RelativeAddress(dir.VirtualAddress),
1080 : dir.Size,
1081 E : "Relocations");
1082 E : }
1083 :
1084 : BlockGraph::Block *PEFileParser::ParseSecurityDir(
1085 i : const IMAGE_DATA_DIRECTORY &dir) {
1086 i : LOG(ERROR) << "Parsing for security dir not implemented.";
1087 i : return NULL;
1088 i : }
1089 :
1090 : BlockGraph::Block *PEFileParser::ParseExceptionDir(
1091 i : const IMAGE_DATA_DIRECTORY &dir) {
1092 i : LOG(ERROR) << "Parsing for exception dir not implemented.";
1093 i : return NULL;
1094 i : }
1095 :
1096 : BlockGraph::Block* PEFileParser::ParseTlsDir(
1097 E : const IMAGE_DATA_DIRECTORY& dir) {
1098 : BlockGraph::Block* tls_directory_block =
1099 : AddBlock(BlockGraph::DATA_BLOCK,
1100 : RelativeAddress(dir.VirtualAddress),
1101 : sizeof(IMAGE_TLS_DIRECTORY),
1102 E : "Tls Directory");
1103 E : if (tls_directory_block == NULL)
1104 i : return NULL;
1105 :
1106 E : PEFileStructPtr<IMAGE_TLS_DIRECTORY> tls_directory;
1107 E : if (!tls_directory.Set(tls_directory_block)) {
1108 i : LOG(ERROR) << "Unable to read the TLS directory.";
1109 i : return NULL;
1110 : }
1111 :
1112 E : return tls_directory_block;
1113 E : }
1114 :
1115 : BlockGraph::Block* PEFileParser::ParseLoadConfigDir(
1116 E : const IMAGE_DATA_DIRECTORY& dir) {
1117 : // We chunk the load config directory to sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
1118 : // because it appears the VC9 linker leaves the data directory entry 8 bytes
1119 : // short for some strange reason.
1120 : BlockGraph::Block* load_config_block =
1121 : AddBlock(BlockGraph::DATA_BLOCK,
1122 : RelativeAddress(dir.VirtualAddress),
1123 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
1124 E : "Load Config Directory");
1125 :
1126 E : PEFileStructPtr<IMAGE_LOAD_CONFIG_DIRECTORY> load_config;
1127 E : if (!load_config.Set(load_config_block)) {
1128 i : LOG(ERROR) << "Unable to the load config directory.";
1129 i : return NULL;
1130 : }
1131 :
1132 : if (!AddAbsolute(load_config, &load_config->LockPrefixTable) ||
1133 : !AddAbsolute(load_config, &load_config->EditList) ||
1134 : !AddAbsolute(load_config, &load_config->SecurityCookie) ||
1135 E : !AddAbsolute(load_config, &load_config->SEHandlerTable)) {
1136 i : LOG(ERROR) << "Unable to add load config directory references.";
1137 i : return NULL;
1138 : }
1139 :
1140 : // Iterate the exception handlers and add references for them.
1141 E : RelativeAddress seh_handler;
1142 E : PEFileStructPtr<DWORD> seh_handlers;
1143 : if (!image_file_.Translate(AbsoluteAddress(load_config->SEHandlerTable),
1144 : &seh_handler) ||
1145 : !seh_handlers.Read(image_file_, seh_handler,
1146 E : load_config->SEHandlerCount * sizeof(DWORD))) {
1147 i : LOG(ERROR) << "Unable to read SEH handler table.";
1148 i : return NULL;
1149 : }
1150 :
1151 E : for (size_t i = 0; i < load_config->SEHandlerCount; ++i) {
1152 E : if (!AddRelative(seh_handlers, seh_handlers.ptr() + i)) {
1153 i : LOG(ERROR) << "Unable to add SEH handler reference.";
1154 i : return NULL;
1155 : }
1156 E : }
1157 :
1158 E : return load_config_block;
1159 E : }
1160 :
1161 : BlockGraph::Block* PEFileParser::ParseDebugDir(
1162 E : const IMAGE_DATA_DIRECTORY& dir) {
1163 : BlockGraph::Block* debug_directory_block =
1164 : AddBlock(BlockGraph::DATA_BLOCK,
1165 : RelativeAddress(dir.VirtualAddress),
1166 : dir.Size,
1167 E : "Debug Directory");
1168 E : if (debug_directory_block == NULL)
1169 i : return NULL;
1170 :
1171 E : PEFileStructPtr<IMAGE_DEBUG_DIRECTORY> debug_directory;
1172 E : if (!debug_directory.Set(debug_directory_block)) {
1173 i : LOG(ERROR) << "Unable to read the debug directory.";
1174 i : return NULL;
1175 : }
1176 :
1177 : do {
1178 : if (!AddRelative(debug_directory, &debug_directory->AddressOfRawData) ||
1179 E : !AddFileOffset(debug_directory, &debug_directory->PointerToRawData)) {
1180 i : LOG(ERROR) << "Failed to add debug directory references.";
1181 i : return NULL;
1182 : }
1183 :
1184 : // Chunk the data referenced by the debug directory entry.
1185 : BlockGraph::Block* debug_data =
1186 : AddBlock(BlockGraph::DATA_BLOCK,
1187 : RelativeAddress(debug_directory->AddressOfRawData),
1188 : debug_directory->SizeOfData,
1189 E : "Debug Info");
1190 E : } while (debug_directory.Next());
1191 :
1192 E : return debug_directory_block;
1193 E : }
1194 :
1195 : BlockGraph::Block* PEFileParser::ParseResourceDir(
1196 E : const IMAGE_DATA_DIRECTORY& dir) {
1197 : BlockGraph::Block* resource_block =
1198 : AddBlock(BlockGraph::DATA_BLOCK,
1199 : RelativeAddress(dir.VirtualAddress),
1200 : dir.Size,
1201 E : "Resource Directory");
1202 E : if (resource_block == NULL)
1203 i : return NULL;
1204 :
1205 E : if (!ParseResourceDirImpl(resource_block, 0))
1206 i : return NULL;
1207 :
1208 E : return resource_block;
1209 E : }
1210 :
1211 : bool PEFileParser::ParseResourceDirImpl(BlockGraph::Block* resource_block,
1212 E : size_t root_offset) {
1213 E : DCHECK(resource_block != NULL);
1214 E : RelativeAddress root_addr = resource_block->addr();
1215 :
1216 : // Setup the directory node we're currently scanning.
1217 E : PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY> directory;
1218 E : if (!directory.Set(resource_block, root_addr + root_offset)) {
1219 i : LOG(ERROR) << "Unable to read the resource directory.";
1220 i : return false;
1221 : }
1222 :
1223 : // How many entries hang from this node in the resource tree?
1224 : size_t num_entries = directory->NumberOfNamedEntries +
1225 E : directory->NumberOfIdEntries;
1226 E : size_t entry_offset = root_offset + sizeof(IMAGE_RESOURCE_DIRECTORY);
1227 :
1228 : // Let's walk through them.
1229 E : for (size_t i = 0; i < num_entries; ++i) {
1230 : // Note that the offsets in the directory entries are all relative to
1231 : // the root address of the resource block.
1232 E : PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY_ENTRY> directory_entry;
1233 E : if (!directory_entry.Set(resource_block, root_addr + entry_offset)) {
1234 i : LOG(ERROR) << "Unable to read the resource directory entry.";
1235 i : return false;
1236 : }
1237 E : if (directory_entry->DataIsDirectory) {
1238 : if (!ParseResourceDirImpl(resource_block,
1239 E : directory_entry->OffsetToDirectory)) {
1240 i : return false;
1241 : }
1242 E : } else {
1243 E : PEFileStructPtr<IMAGE_RESOURCE_DATA_ENTRY> data_entry;
1244 E : RelativeAddress entry_addr(root_addr + directory_entry->OffsetToData);
1245 E : if (!data_entry.Set(resource_block, entry_addr)) {
1246 i : LOG(ERROR) << "Unable to read the resource data entry.";
1247 i : return false;
1248 : }
1249 : // The offsets in the data entries are RVAs.
1250 E : if (!AddRelative(data_entry, &data_entry->OffsetToData)) {
1251 i : LOG(ERROR) << "Failed to add resouce data reference.";
1252 i : return false;
1253 : }
1254 : }
1255 E : entry_offset += sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY);
1256 E : }
1257 :
1258 E : return true;
1259 E : }
1260 :
1261 : bool PEFileParser::AddReference(RelativeAddress src,
1262 : BlockGraph::ReferenceType type,
1263 : BlockGraph::Size size,
1264 E : RelativeAddress dst) {
1265 E : return add_reference_.Run(src, type, size, dst);
1266 E : }
1267 :
1268 : BlockGraph::Block* PEFileParser::AddBlock(BlockGraph::BlockType type,
1269 : RelativeAddress addr,
1270 : BlockGraph::Size size,
1271 E : const char* name) {
1272 E : BlockGraph::Block* block = address_space_->AddBlock(type, addr, size, name);
1273 E : if (block != NULL) {
1274 E : block->set_attribute(BlockGraph::PE_PARSED);
1275 :
1276 : // Mark the source range from whence this block originates.
1277 : bool pushed = block->source_ranges().Push(
1278 : BlockGraph::Block::DataRange(0, size),
1279 E : BlockGraph::Block::SourceRange(addr, size));
1280 E : DCHECK(pushed);
1281 :
1282 : // Set the section for this block. We let blocks that belong to the header
1283 : // be marked with kInvalidSectionId.
1284 E : size_t section = image_file_.GetSectionIndex(addr, size);
1285 E : if (section == BlockGraph::kInvalidSectionId) {
1286 : // If no section was found for this block, we expect it to be a part of
1287 : // the header.
1288 : const RelativeAddress end_of_headers(
1289 E : image_file_.nt_headers()->OptionalHeader.SizeOfHeaders);
1290 E : if (addr + size > end_of_headers) {
1291 i : LOG(ERROR) << "Found a non-header block outside of sections.";
1292 i : return NULL;
1293 : }
1294 : }
1295 E : block->set_section(section);
1296 :
1297 E : const uint8* data = image_file_.GetImageData(addr, size);
1298 E : if (data != NULL)
1299 E : block->SetData(data, size);
1300 : }
1301 :
1302 E : return block;
1303 E : }
1304 :
1305 : template <typename ItemType>
1306 : bool PEFileParser::AddRelative(const PEFileStructPtr<ItemType>& structure,
1307 E : const DWORD* item) {
1308 E : DCHECK(item != NULL);
1309 E : if (*item == 0)
1310 E : return true;
1311 :
1312 : return AddReference(structure.AddressOf(item),
1313 : BlockGraph::RELATIVE_REF,
1314 : sizeof(*item),
1315 E : RelativeAddress(*item));
1316 E : }
1317 :
1318 : template <typename ItemType>
1319 : bool PEFileParser::AddAbsolute(const PEFileStructPtr<ItemType>& structure,
1320 E : const DWORD* item) {
1321 E : DCHECK(item != NULL);
1322 E : if (*item == 0)
1323 E : return true;
1324 :
1325 E : AbsoluteAddress abs(*item);
1326 E : RelativeAddress rel;
1327 :
1328 : // We expect item to be the direct (0 offset) absolute address of the
1329 : // in-image file structure. So, translation to an in-image relative
1330 : // address is expected to yield a valid RVA.
1331 : return image_file_.Translate(abs, &rel) &&
1332 : AddReference(structure.AddressOf(item),
1333 : BlockGraph::ABSOLUTE_REF,
1334 : sizeof(*item),
1335 E : rel);
1336 E : }
1337 :
1338 : template <typename ItemType>
1339 : bool PEFileParser::AddFileOffset(const PEFileStructPtr<ItemType>& structure,
1340 E : const DWORD* item) {
1341 E : DCHECK(item != NULL);
1342 E : if (*item == 0)
1343 i : return true;
1344 :
1345 E : FileOffsetAddress offs(*item);
1346 E : RelativeAddress rel;
1347 :
1348 : // We expect item to be the direct (0 offset) file offset address of the
1349 : // in-image file structure. So, translation to an in-image relative
1350 : // address is expected to yield a valid RVA.
1351 : return image_file_.Translate(offs, &rel) &&
1352 : AddReference(structure.AddressOf(item),
1353 : BlockGraph::FILE_OFFSET_REF,
1354 : sizeof(*item),
1355 E : rel);
1356 E : }
1357 :
1358 : } // namespace pe
|