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 : // The PEAddImportsTransform can be summed up as follows:
16 : //
17 : // (1) Make sure that the imports and IAT data directories exist.
18 : // (2) For each module to be imported, either find it in the import data
19 : // directory, or add a new entry. The entry is always added to the end
20 : // of the list so that module indices are strictly increasing, allowing
21 : // the transform to be stacked. Adding a new entry also causes the creation
22 : // of two new blocks (for the INT and the module filename), as well as
23 : // extends the existing IAT block.
24 : // (3) For each symbol to be imported, either find it in the module's INT/IAT,
25 : // or add a new entry. Adding a new entry causes the existing INT and IAT
26 : // blocks to be extended. The new entry is always added to the end of the
27 : // module's table so that symbol indices are strictly increasing, again
28 : // allowing the transform to be stacked. Rather than allocating a new
29 : // block for the name of the symbol we reuse the module filename block and
30 : // insert the name of the symbol immediately prior to the module filename.
31 : // This ensures that all of the strings for a module are laid out together,
32 : // mimicking the observed behavior of the MS linker.
33 : //
34 : // We give a quick rundown of the PE structures involved, their layout in
35 : // typical PE images and how we parse them into blocks. This helps visualize
36 : // the work performed by the transform.
37 : //
38 : // headers:
39 : //
40 : // ...
41 : // nt_headers
42 : // DataDirectory
43 : // ...
44 : // IMAGE_DIRECTORY_ENTRY_IMPORT -> IMAGE_IMPORT_DESCRIPTOR array
45 : // ...
46 : // IMAGE_DIRECTORY_ENTRY_IAT -> Import Address Table
47 : // ...
48 : //
49 : // .rdata:
50 : //
51 : // Import Address Table
52 : // NOTE: All entries in this table must remain consecutive as it is also
53 : // exposed directly via a data directory. At runtime these get patched to
54 : // point to the actual functions rather than the thunks. This is stored
55 : // at the very beginning of .rdata and parsed as a single Block.
56 : // IAT[0,0] -> thunk[0, 0] \
57 : // ... |
58 : // IAT[0,j] -> thunk[0, j] |
59 : // NULL terminator |
60 : // ... |- Block
61 : // IAT[i,0] -> thunk[i, 0] |
62 : // ... |
63 : // IAT[i,k] -> thunk[i, k] |
64 : // NULL terminator /
65 : //
66 : // ... whole bunch of other .rdata here ...
67 : // NOTE: The following are stored at the end of .rdata, in the order
68 : // shown (they are not quite last, being immediately prior to export
69 : // information).
70 : //
71 : // IMAGE_IMPORT_DESCRIPTOR array \
72 : // IMAGE_IMPORT_DESCRIPTOR[0] |
73 : // -> module_name[0] |
74 : // -> INT[0,0] |
75 : // -> IAT[0,0] |
76 : // ... |- Block
77 : // IMAGE_IMPORT_DESCRIPTOR[i] |
78 : // -> module_name[i] |
79 : // -> INT[i,0] |
80 : // -> IAT[i,0] |
81 : // NULL terminator /
82 : //
83 : // Import Name Table (also known as Hint Name Array)
84 : // NOTE: The entries for each module need be consecutive. While the entries
85 : // across all modules are consecutive, they need not be.
86 : // INT[0,0] -> thunk[0, 0] \
87 : // ... |_ Block
88 : // INT[0,j] -> thunk[0, j] |
89 : // NULL terminator /
90 : // ...
91 : // INT[i,0] -> thunk[i, 0] \
92 : // ... |_ Block
93 : // INT[i,k] -> thunk[i, k] |
94 : // NULL terminator /
95 : //
96 : // Array of names
97 : // NOTE: These are consecutive in typical PE images (with the layout shown
98 : // below), but they need not be.
99 : // thunk[0, 0] } Block
100 : // ...
101 : // thunk[0, j] } Block
102 : // module_name[0] } Block
103 : // ...
104 : // thunk[i, 0] } Block
105 : // ...
106 : // thunk[i, k] } Block
107 : // module_name[i] } Block
108 :
109 : #include "syzygy/pe/transforms/pe_add_imports_transform.h"
110 :
111 : #include "base/strings/string_piece.h"
112 : #include "base/strings/string_util.h"
113 : #include "base/strings/stringprintf.h"
114 : #include "syzygy/block_graph/typed_block.h"
115 : #include "syzygy/common/align.h"
116 : #include "syzygy/pe/pe_utils.h"
117 :
118 : namespace pe {
119 : namespace transforms {
120 :
121 : using block_graph::BlockGraph;
122 : using block_graph::ConstTypedBlock;
123 : using block_graph::TypedBlock;
124 : using core::RelativeAddress;
125 :
126 : // A simple struct that can be used to let us access strings using TypedBlock.
127 : struct StringStruct {
128 : const char string[1];
129 : };
130 :
131 : typedef BlockGraph::Offset Offset;
132 : typedef TypedBlock<IMAGE_DELAYLOAD_DESCRIPTOR> ImageDelayLoadDescriptor;
133 : typedef TypedBlock<IMAGE_DOS_HEADER> DosHeader;
134 : typedef TypedBlock<IMAGE_IMPORT_BY_NAME> ImageImportByName;
135 : typedef TypedBlock<IMAGE_IMPORT_DESCRIPTOR> ImageImportDescriptor;
136 : typedef TypedBlock<IMAGE_NT_HEADERS> NtHeaders;
137 : typedef TypedBlock<IMAGE_THUNK_DATA32> ImageThunkData32;
138 : typedef TypedBlock<StringStruct> String;
139 :
140 : namespace {
141 :
142 : const size_t kPtrSize = sizeof(core::RelativeAddress);
143 : const size_t kInvalidIndex = static_cast<size_t>(-1);
144 :
145 : // Looks up the given data directory and checks that it points to valid data.
146 : // If it doesn't exist and find_only is false, it will allocate a block with
147 : // the given name and size.
148 : bool FindOrAddDataDirectory(bool find_only,
149 : size_t directory_index,
150 : const base::StringPiece& block_name,
151 : size_t block_size,
152 : BlockGraph* block_graph,
153 : BlockGraph::Block* nt_headers_block,
154 E : BlockGraph::Block** directory_block) {
155 : DCHECK_LT(directory_index,
156 E : static_cast<size_t>(IMAGE_NUMBEROF_DIRECTORY_ENTRIES));
157 E : DCHECK_GT(block_size, 0u);
158 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
159 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), nt_headers_block);
160 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block**>(NULL), directory_block);
161 :
162 E : *directory_block = NULL;
163 :
164 E : NtHeaders nt_headers;
165 E : if (!nt_headers.Init(0, nt_headers_block)) {
166 i : LOG(ERROR) << "Unable to cast NT headers.";
167 i : return false;
168 : }
169 :
170 : IMAGE_DATA_DIRECTORY* data_directory =
171 E : nt_headers->OptionalHeader.DataDirectory + directory_index;
172 :
173 : BlockGraph::Offset offset = nt_headers.OffsetOf(
174 E : data_directory->VirtualAddress);
175 E : BlockGraph::Reference ref;
176 :
177 : // No entry? Then make a zero initialized block that is stored in .rdata,
178 : // where all of these structures live.
179 E : if (!nt_headers_block->GetReference(offset, &ref)) {
180 : // We don't need to create the entry if we're exploring only.
181 E : if (find_only)
182 E : return true;
183 :
184 : BlockGraph::Section* section = block_graph->FindOrAddSection(
185 E : kReadOnlyDataSectionName, kReadOnlyDataCharacteristics);
186 E : DCHECK(section != NULL);
187 :
188 : BlockGraph::Block* block = block_graph->AddBlock(
189 E : BlockGraph::DATA_BLOCK, block_size, block_name);
190 E : DCHECK(block != NULL);
191 E : block->set_section(section->id());
192 E : block->set_attribute(BlockGraph::PE_PARSED);
193 :
194 : // We need to actually allocate the data so that future TypedBlock
195 : // dereferences will work.
196 E : if (block->AllocateData(block_size) == NULL) {
197 i : LOG(ERROR) << "Failed to allocate block data.";
198 i : return false;
199 : }
200 :
201 : // Hook it up to the NT header.
202 : nt_headers.SetReference(BlockGraph::RELATIVE_REF,
203 : data_directory->VirtualAddress,
204 : block,
205 E : 0, 0);
206 E : data_directory->Size = block_size;
207 :
208 E : *directory_block = block;
209 E : } else {
210 : // If the directory already exists, return it.
211 E : if (ref.offset() != 0) {
212 i : LOG(ERROR) << "Existing \"" << block_name << "\" directory is not its "
213 : << "own block.";
214 i : return false;
215 : }
216 E : *directory_block = ref.referenced();
217 : }
218 :
219 E : return true;
220 E : }
221 :
222 : bool ModuleNameMatches(const base::StringPiece& module_name,
223 E : const String& dll_name) {
224 E : size_t max_len = dll_name.ElementCount();
225 E : if (max_len < module_name.size())
226 E : return false;
227 : return base::EqualsCaseInsensitiveASCII(
228 : base::StringPiece(dll_name->string,
229 : std::min(max_len, module_name.size())),
230 E : module_name.data());
231 E : }
232 :
233 : bool SymbolNameMatches(const base::StringPiece& symbol_name,
234 E : const ImageImportByName& iibn) {
235 : size_t max_len = iibn.block()->data_size() - iibn.offset() -
236 E : offsetof(IMAGE_IMPORT_BY_NAME, Name);
237 E : if (max_len < symbol_name.size())
238 E : return false;
239 E : return ::strncmp(iibn->Name, symbol_name.data(), max_len) == 0;
240 E : }
241 :
242 : // Finds or creates an Image Import Descriptor block for the given library.
243 : // Returns true on success, false otherwise.
244 : bool FindOrAddImageImportDescriptor(bool find_only,
245 : const char* module_name,
246 : BlockGraph* block_graph,
247 : BlockGraph::Block* iida_block,
248 : BlockGraph::Block* iat_block,
249 : ImageImportDescriptor* iid,
250 : bool* added,
251 E : bool* exists) {
252 E : DCHECK(module_name != NULL);
253 E : DCHECK(block_graph != NULL);
254 E : DCHECK(iida_block != NULL);
255 E : DCHECK(iat_block != NULL);
256 E : DCHECK(iid != NULL);
257 E : DCHECK(added != NULL);
258 E : DCHECK(exists != NULL);
259 :
260 E : *added = false;
261 E : *exists = false;
262 :
263 E : ImageImportDescriptor iida;
264 E : if (!iida.Init(0, iida_block)) {
265 i : LOG(ERROR) << "Unable to cast Image Import Descriptor.";
266 i : return false;
267 : }
268 :
269 : // The array is NULL terminated with a potentially incomplete descriptor so
270 : // we can't use ElementCount - 1.
271 E : DCHECK_GT(iida_block->size(), 0U);
272 : size_t descriptor_count =
273 : (common::AlignUp(iida_block->size(), sizeof(IMAGE_IMPORT_DESCRIPTOR)) /
274 E : sizeof(IMAGE_IMPORT_DESCRIPTOR)) - 1;
275 :
276 E : for (size_t iida_index = 0; iida_index < descriptor_count; ++iida_index) {
277 E : String dll_name;
278 E : if (!iida.Dereference(iida[iida_index].Name, &dll_name)) {
279 i : LOG(ERROR) << "Unable to dereference DLL name.";
280 i : return false;
281 : }
282 :
283 E : if (ModuleNameMatches(module_name, dll_name)) {
284 : // This should never fail, but we sanity check it nonetheless.
285 E : bool result = iid->Init(iida.OffsetOf(iida[iida_index]), iida.block());
286 E : DCHECK(result);
287 E : *exists = true;
288 E : return true;
289 : }
290 E : }
291 :
292 : // If we get here then the entry doesn't exist. If we've been asked to only
293 : // search for it then we can return early.
294 E : if (find_only)
295 E : return true;
296 :
297 : // Create room for the new descriptor, which we'll tack on to the end of the
298 : // array, but before the NULL terminator. We use 'InsertData' so that all
299 : // labels are patched up.
300 E : Offset new_iid_offset = descriptor_count * sizeof(IMAGE_IMPORT_DESCRIPTOR);
301 : iida_block->InsertData(
302 E : new_iid_offset, sizeof(IMAGE_IMPORT_DESCRIPTOR), true);
303 : iida_block->SetLabel(
304 : new_iid_offset,
305 : base::StringPrintf("Image Import Descriptor: %s", module_name),
306 E : BlockGraph::DATA_LABEL);
307 :
308 : // We expect the new entry to be dereferencable using iida[descriptor_count].
309 E : DCHECK_GT(iida.ElementCount(), descriptor_count);
310 :
311 : // Create the various child structures that will be pointed to by the
312 : // import descriptor. The INT block and the IAT block are NULL terminated
313 : // lists of pointers, and the terminating NULL is allocated. We don't yet
314 : // allocate a block to hold the import names, deferring that for later.
315 E : BlockGraph::SectionId iida_section_id = iida_block->section();
316 E : size_t name_len = strlen(module_name);
317 : BlockGraph::Block* int_block = block_graph->AddBlock(
318 : BlockGraph::DATA_BLOCK, kPtrSize,
319 E : base::StringPrintf("Import Name Table: %s", module_name));
320 : BlockGraph::Block* dll_name_block = block_graph->AddBlock(
321 : BlockGraph::DATA_BLOCK, name_len + 1,
322 E : base::StringPrintf("Import Name: %s", module_name));
323 E : if (int_block == NULL || dll_name_block == NULL) {
324 i : LOG(ERROR) << "Unable to create blocks for Image Import Descriptor.";
325 i : return false;
326 : }
327 :
328 : // NOTE: If PEParser was modified to parse a single INT block, we could be
329 : // extending/reusing it rather than creating a new INT per module.
330 E : int_block->set_section(iida_section_id);
331 E : int_block->set_attribute(BlockGraph::PE_PARSED);
332 : int_block->SetLabel(
333 : 0,
334 : base::StringPrintf("%s INT: NULL entry", module_name),
335 E : BlockGraph::DATA_LABEL);
336 E : if (int_block->AllocateData(kPtrSize) == NULL) {
337 i : LOG(ERROR) << "Failed to allocate block data.";
338 i : return false;
339 : }
340 :
341 : // We use the DLL name block and extend it. This keeps things well ordered
342 : // when writing back the image using a canonical ordering.
343 E : dll_name_block->set_section(iida_section_id);
344 E : dll_name_block->set_attribute(BlockGraph::PE_PARSED);
345 E : if (dll_name_block->CopyData(name_len + 1, module_name) == NULL) {
346 i : LOG(ERROR) << "Failed to copy block data.";
347 i : return false;
348 : }
349 :
350 : // Add another NULL entry to the IAT block, but only if it does not already
351 : // consist of a single NULL entry (meaning it was just created). We are purely
352 : // extending this block, so no need to use the data insertion functions.
353 E : Offset iat_offset = 0;
354 E : if (iat_block->size() != kPtrSize) {
355 E : iat_offset = iat_block->size();
356 E : size_t iat_size = iat_offset + kPtrSize;
357 E : iat_block->set_size(iat_size);
358 E : iat_block->ResizeData(iat_size);
359 E : DCHECK_EQ(iat_size, iat_block->size());
360 E : DCHECK_EQ(iat_size, iat_block->data_size());
361 : }
362 :
363 : // Add a label for debugging purposes.
364 : iat_block->SetLabel(iat_offset,
365 : base::StringPrintf("%s: NULL thunk", module_name),
366 E : BlockGraph::DATA_LABEL);
367 :
368 : // Hook up these blocks.
369 : iida.SetReference(BlockGraph::RELATIVE_REF,
370 E : iida[descriptor_count].OriginalFirstThunk, int_block, 0, 0);
371 : iida.SetReference(BlockGraph::RELATIVE_REF,
372 : iida[descriptor_count].FirstThunk, iat_block, iat_offset,
373 E : iat_offset);
374 : iida.SetReference(BlockGraph::RELATIVE_REF,
375 E : iida[descriptor_count].Name, dll_name_block, 0, 0);
376 :
377 : // Finally, return the descriptor.
378 E : if (!iid->Init(new_iid_offset, iida_block)) {
379 i : LOG(ERROR) << "Unable to cast Image Import Descriptor.";
380 i : return false;
381 : }
382 :
383 E : *added = true;
384 E : *exists = true;
385 :
386 E : return true;
387 E : }
388 :
389 : // Searches for the delay-load library with the given module name. Returns true
390 : // on success, false otherwise. If found, returns the index. If not found
391 : // sets the index to kInvalidIndex.
392 : bool FindDelayLoadImportDescriptor(const base::StringPiece& module_name,
393 : const ImageDelayLoadDescriptor& idld,
394 E : size_t* index) {
395 E : DCHECK_NE(reinterpret_cast<size_t*>(NULL), index);
396 :
397 E : *index = kInvalidIndex;
398 :
399 E : for (size_t i = 0; i < idld.ElementCount(); ++i) {
400 E : bool zero_data = idld[i].DllNameRVA == 0;
401 E : bool has_ref = idld.HasReference(idld[i].DllNameRVA);
402 :
403 : // Keep an eye out for null termination of the array.
404 E : if (zero_data && !has_ref)
405 E : return true;
406 :
407 : // If the data is not zero then we expect there to be a reference.
408 E : if (!zero_data && !has_ref) {
409 i : LOG(ERROR) << "Expected DllNameRVA reference at index " << i
410 : << " of IMAGE_DELAYLOAD_DESCRIPTOR array.";
411 i : return false;
412 : }
413 :
414 E : String dll_name;
415 E : if (!idld.Dereference(idld[i].DllNameRVA, &dll_name)) {
416 i : LOG(ERROR) << "Failed to dereference DllNameRVA at index " << i
417 : << " of IMAGE_DELAYLOAD_DESCRIPTOR array.";
418 i : return false;
419 : }
420 :
421 E : if (ModuleNameMatches(module_name, dll_name)) {
422 E : *index = i;
423 E : return true;
424 : }
425 E : }
426 :
427 i : return true;
428 E : }
429 :
430 : // Finds or adds an imported symbol to the given module (represented by its
431 : // import descriptor). Returns true on success, false otherwise. On success
432 : // returns a reference to the module's IAT entry. New entries are always added
433 : // to the end of the table so as not to invalidate any other unlinked references
434 : // (not part of the BlockGraph, so unable to be patched up) into the table.
435 : bool FindOrAddImportedSymbol(bool find_only,
436 : const char* symbol_name,
437 : const ImageImportDescriptor& iid,
438 : BlockGraph* block_graph,
439 : BlockGraph::Block* iat_block,
440 : size_t* iat_index,
441 E : bool* added) {
442 E : DCHECK(symbol_name != NULL);
443 E : DCHECK(block_graph != NULL);
444 E : DCHECK(iat_block != NULL);
445 E : DCHECK(iat_index != NULL);
446 E : DCHECK(added != NULL);
447 :
448 E : *iat_index = kInvalidIndex;
449 E : *added = false;
450 :
451 E : TypedBlock<IMAGE_IMPORT_BY_NAME*> hna, iat;
452 : if (!iid.Dereference(iid->OriginalFirstThunk, &hna) ||
453 E : !iid.Dereference(iid->FirstThunk, &iat)) {
454 i : LOG(ERROR) << "Unable to dereference OriginalFirstThunk/FirstThunk.";
455 i : return false;
456 : }
457 :
458 : // Loop through the existing imports and see if we can't find a match. If so,
459 : // we don't need to import the symbol as it is already imported. The array is
460 : // NULL terminated so we loop through all elements except for the last one.
461 E : size_t i = 0;
462 E : for (; i < hna.ElementCount() && i < iat.ElementCount(); ++i) {
463 E : ConstTypedBlock<IMAGE_THUNK_DATA32> thunk;
464 E : if (!thunk.Init(hna.OffsetOf(hna[i]), hna.block())) {
465 i : LOG(ERROR) << "Unable to dereference IMAGE_THUNK_DATA32.";
466 i : return false;
467 : }
468 :
469 : // Is this an ordinal import? Skip it, as we have no way of
470 : // knowing the actual name of the symbol.
471 E : if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
472 E : continue;
473 :
474 : // Have no reference? Then terminate the iteration.
475 E : if (!thunk.HasReference(thunk->u1.AddressOfData)) {
476 : // We sanity check that the actual data is null.
477 E : DCHECK_EQ(0u, thunk->u1.AddressOfData);
478 E : break;
479 : }
480 :
481 : // Otherwise this should point to an IMAGE_IMPORT_BY_NAME structure.
482 E : ImageImportByName iibn;
483 E : if (!hna.Dereference(hna[i], &iibn)) {
484 i : LOG(ERROR) << "Unable to dereference IMAGE_IMPORT_BY_NAME.";
485 i : return false;
486 : }
487 :
488 : // Check to see if this symbol matches that of the current image import
489 : // by name.
490 E : if (SymbolNameMatches(symbol_name, iibn)) {
491 E : *iat_index = i;
492 E : return true;
493 : }
494 E : }
495 :
496 : // If we get here then the entry doesn't exist. If we've been asked to only
497 : // search for it then we can return early.
498 E : if (find_only)
499 E : return true;
500 :
501 : // Figure out how large the data needs to be to hold the name of this exported
502 : // symbol. The IMAGE_IMPORT_BY_NAME struct has a WORD ordinal and a variable
503 : // sized field for the null-terminated function name. Each entry should be
504 : // WORD aligned, and will be referenced from the import address table and the
505 : // import name table.
506 E : size_t symbol_name_len = strlen(symbol_name);
507 : size_t iibn_size = sizeof(WORD) + common::AlignUp(symbol_name_len + 1,
508 E : sizeof(WORD));
509 :
510 : // Get the DLL name. We will be inserting the IIBN entry to the block
511 : // containing it immediately prior to the DLL name.
512 E : String dll_name;
513 E : if (!iid.Dereference(iid->Name, &dll_name)) {
514 i : LOG(ERROR) << "Unable to dereference DLL name.";
515 i : return false;
516 : }
517 E : Offset iibn_offset = dll_name.offset();
518 E : dll_name.block()->InsertData(iibn_offset, iibn_size, true);
519 :
520 : // Populate the import struct.
521 E : TypedBlock<IMAGE_IMPORT_BY_NAME> iibn;
522 E : if (!iibn.InitWithSize(iibn_offset, iibn_size, dll_name.block())) {
523 i : LOG(ERROR) << "Unable to dereference new IMAGE_IMPORT_BY_NAME.";
524 i : return false;
525 : }
526 E : iibn->Hint = 0;
527 : base::strlcpy(reinterpret_cast<char*>(iibn->Name), symbol_name,
528 E : symbol_name_len + 1);
529 :
530 : // Make room in the INT and the IAT for the new symbol. We place it
531 : // after the last entry for this module.
532 E : Offset int_offset = hna.OffsetOf(hna[i]);
533 E : Offset iat_offset = iat.OffsetOf(iat[i]);
534 : // We're pointed at the terminating zero. The position we're pointing at can
535 : // be the destination for references (in the normal case where someone is
536 : // using the import). However, in the special case where the IAT and the INT
537 : // are empty, our slot may also be pointed at by the import descriptor.
538 : // If we were to insert data at this position, we'd push the import
539 : // descriptor's pointer forward, past our new entry. To avoid this, we insert
540 : // the new data after the terminating zero we're pointing at, then usurp the
541 : // previously terminating zero for our entry.
542 E : hna.block()->InsertData(int_offset + kPtrSize, kPtrSize, true);
543 E : iat.block()->InsertData(iat_offset + kPtrSize, kPtrSize, true);
544 :
545 : // Because of the usurping mentioned above, we manually move any existing
546 : // labels.
547 E : BlockGraph::Label label;
548 E : if (hna.block()->GetLabel(int_offset, &label)) {
549 E : hna.block()->RemoveLabel(int_offset);
550 E : hna.block()->SetLabel(int_offset + kPtrSize, label);
551 : }
552 E : if (iat.block()->GetLabel(iat_offset, &label)) {
553 E : iat.block()->RemoveLabel(iat_offset);
554 E : iat.block()->SetLabel(iat_offset + kPtrSize, label);
555 : }
556 :
557 : // Add the new labels. We have to get the module_name at this point
558 : // because it may have been moved with our insertions above.
559 E : String module_name;
560 E : if (!iid.Dereference(iid->Name, &module_name)) {
561 i : LOG(ERROR) << "Unable to dereference import name.";
562 i : return false;
563 : }
564 : hna.block()->SetLabel(
565 : int_offset,
566 : base::StringPrintf("%s INT: %s", module_name->string, symbol_name),
567 E : BlockGraph::DATA_LABEL);
568 : iat.block()->SetLabel(
569 : iat_offset,
570 : base::StringPrintf("%s IAT: %s", module_name->string, symbol_name),
571 E : BlockGraph::DATA_LABEL);
572 :
573 : // Hook up the newly created IMAGE_IMPORT_BY_NAME to both tables.
574 : BlockGraph::Reference iibn_ref(BlockGraph::RELATIVE_REF,
575 : kPtrSize,
576 : iibn.block(),
577 : iibn.offset(),
578 E : iibn.offset());
579 E : hna.block()->SetReference(int_offset, iibn_ref);
580 E : iat.block()->SetReference(iat_offset, iibn_ref);
581 :
582 : // Return the reference to the IAT entry for the newly imported symbol.
583 E : *iat_index = i;
584 E : *added = true;
585 :
586 E : return true;
587 E : }
588 :
589 : // Looks for the given symbol in the given delay-loaded library descriptor.
590 : // Returns true on success, false otherwise. If the symbol was found sets
591 : // |found| to true, and return a reference to it via |ref|.
592 : bool FindDelayLoadSymbol(const base::StringPiece& symbol_name,
593 : const ImageDelayLoadDescriptor& idld,
594 : size_t module_index,
595 : bool* found,
596 : size_t* index,
597 E : BlockGraph::Reference* ref) {
598 E : DCHECK_NE(reinterpret_cast<bool*>(NULL), found);
599 E : DCHECK_NE(reinterpret_cast<size_t*>(NULL), index);
600 E : DCHECK_NE(reinterpret_cast<BlockGraph::Reference*>(NULL), ref);
601 :
602 E : *found = false;
603 E : *index = kInvalidIndex;
604 :
605 E : ImageThunkData32 addresses;
606 E : ImageThunkData32 names;
607 : if (!idld.Dereference(idld[module_index].ImportAddressTableRVA, &addresses) ||
608 E : !idld.Dereference(idld[module_index].ImportNameTableRVA, &names)) {
609 i : LOG(ERROR) << "Failed to dereference IAT/INT for delay-load library.";
610 i : return false;
611 : }
612 :
613 E : size_t count = std::min(addresses.ElementCount(), names.ElementCount());
614 E : for (size_t i = 0; i < count; ++i) {
615 : // Keep an eye out for zero-terminating IAT entries.
616 E : bool zero_data = addresses[i].u1.AddressOfData == 0;
617 E : bool has_ref = addresses.HasReference(addresses[i].u1.AddressOfData);
618 E : if (zero_data && !has_ref)
619 i : break;
620 E : if (!zero_data && !has_ref) {
621 i : LOG(ERROR) << "Expected reference at offset " << i
622 : << " of delay-load IAT.";
623 i : return false;
624 : }
625 :
626 : // Keep an eye out for zero-terminating INT entries.
627 E : zero_data = names[i].u1.AddressOfData == 0;
628 E : has_ref = names.HasReference(names[i].u1.AddressOfData);
629 E : if (zero_data && !has_ref)
630 i : break;
631 E : if (!zero_data && !has_ref) {
632 i : LOG(ERROR) << "Expected reference at offset " << i
633 : << " of delay-load INT.";
634 i : return false;
635 : }
636 :
637 E : ImageImportByName iibn;
638 E : if (!names.Dereference(names[i].u1.AddressOfData, &iibn)) {
639 i : LOG(ERROR) << "Failed to dereference name of entry " << i
640 : << " of delay-load INT.";
641 i : return false;
642 : }
643 :
644 E : if (SymbolNameMatches(symbol_name, iibn)) {
645 E : Offset offset = addresses.OffsetOf(addresses->u1.Function);
646 : *ref = BlockGraph::Reference(BlockGraph::ABSOLUTE_REF,
647 : BlockGraph::Reference::kMaximumSize,
648 : addresses.block(),
649 : offset,
650 E : offset);
651 E : *found = true;
652 E : *index = i;
653 E : return true;
654 : }
655 i : }
656 :
657 i : return true;
658 E : }
659 :
660 : } // namespace
661 :
662 : const char PEAddImportsTransform::kTransformName[] = "PEAddImportsTransform";
663 :
664 : PEAddImportsTransform::PEAddImportsTransform()
665 : : image_import_descriptor_block_(NULL),
666 E : import_address_table_block_(NULL) {
667 E : }
668 :
669 : bool PEAddImportsTransform::TransformBlockGraph(
670 : const TransformPolicyInterface* policy,
671 : BlockGraph* block_graph,
672 E : BlockGraph::Block* dos_header_block) {
673 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
674 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
675 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), dos_header_block);
676 E : DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
677 :
678 E : modules_added_ = 0;
679 E : symbols_added_ = 0;
680 :
681 E : DosHeader dos_header;
682 E : NtHeaders nt_headers;
683 : if (!dos_header.Init(0, dos_header_block) ||
684 E : !dos_header.Dereference(dos_header->e_lfanew, &nt_headers)) {
685 i : LOG(ERROR) << "Unable to cast image headers.";
686 i : return false;
687 : }
688 :
689 : // Find delay load imports. This is read-only, searching for existing
690 : // imports but not injecting new ones.
691 E : if (!FindDelayLoadImports(block_graph, nt_headers.block()))
692 i : return false;
693 :
694 : // Before processing regular imports, let's determine if we're on a strictly
695 : // exploratory mission. We don't want to add anything if all unresolved
696 : // modules/symbols are 'find only'.
697 E : bool find_only = true;
698 E : for (size_t i = 0; i < imported_modules_.size(); ++i) {
699 E : for (size_t j = 0; j < imported_modules_[i]->size(); ++j) {
700 : // If the symbol is resolved, we don't care about it. We don't want to
701 : // unnecessarily add PE import structures if we're not creating any
702 : // imports.
703 E : if (imported_modules_[i]->SymbolIsImported(j))
704 E : continue;
705 E : if (imported_modules_[i]->GetSymbolMode(j) != ImportedModule::kFindOnly) {
706 E : find_only = false;
707 E : break;
708 : }
709 E : }
710 E : }
711 :
712 : // Find normal imports. If the symbol is imported as both a delay-load and
713 : // a regular import, then this will overwrite it. Thus, regular imports will
714 : // be preferred. However, if the symbol was resolved as a delay-load import
715 : // then this will not cause it to also be added as a regular import.
716 E : if (!FindOrAddImports(find_only, block_graph, nt_headers.block()))
717 i : return false;
718 :
719 E : return true;
720 E : }
721 :
722 : bool PEAddImportsTransform::FindOrAddImports(
723 : bool find_only,
724 : BlockGraph* block_graph,
725 E : BlockGraph::Block* nt_headers_block) {
726 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
727 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), nt_headers_block);
728 :
729 E : NtHeaders nt_headers;
730 E : CHECK(nt_headers.Init(0, nt_headers_block));
731 :
732 : // Get the import data directory.
733 E : image_import_descriptor_block_ = NULL;
734 : if (!FindOrAddDataDirectory(find_only,
735 : IMAGE_DIRECTORY_ENTRY_IMPORT,
736 : "Image Import Descriptor Array",
737 : sizeof(IMAGE_IMPORT_DESCRIPTOR),
738 : block_graph,
739 : nt_headers.block(),
740 E : &image_import_descriptor_block_)) {
741 i : return false;
742 : }
743 E : if (image_import_descriptor_block_ == NULL)
744 i : return find_only;
745 :
746 : // Similarly, get the import address table.
747 E : import_address_table_block_ = NULL;
748 : if (!FindOrAddDataDirectory(find_only,
749 : IMAGE_DIRECTORY_ENTRY_IAT,
750 : "Import Address Table",
751 : kPtrSize,
752 : block_graph,
753 : nt_headers.block(),
754 E : &import_address_table_block_)) {
755 i : return false;
756 : }
757 E : if (import_address_table_block_ == NULL)
758 i : return find_only;
759 :
760 : // Handle each library individually.
761 E : for (size_t i = 0; i < imported_modules_.size(); ++i) {
762 E : ImportedModule* module = imported_modules_[i];
763 :
764 : // First find or create an entry for this module in the Image Import
765 : // Descriptor Array.
766 E : ImageImportDescriptor iid;
767 E : bool module_added = false;
768 E : bool module_exists = false;
769 : if (!FindOrAddImageImportDescriptor(
770 : module->mode() == ImportedModule::kFindOnly,
771 : module->name().c_str(),
772 : block_graph,
773 : image_import_descriptor_block_,
774 : import_address_table_block_,
775 : &iid,
776 : &module_added,
777 E : &module_exists)) {
778 i : LOG(ERROR) << "Failed to find or import module.";
779 i : return false;
780 : }
781 :
782 : // If we're fact finding only and the module does not exist then we don't
783 : // need to look up its symbols.
784 E : if (module->mode() == ImportedModule::kFindOnly && !module_exists) {
785 E : DCHECK(!module_added);
786 E : continue;
787 : }
788 :
789 E : DCHECK(module_exists);
790 E : UpdateModule(true, module_added, module);
791 E : modules_added_ += module_added;
792 :
793 : // Update the version date/time stamp if requested.
794 E : if (module->date() != ImportedModule::kInvalidDate)
795 E : iid->TimeDateStamp = module->date();
796 :
797 : // Get a pointer to the import thunks.
798 E : ImageThunkData32 thunks;
799 E : if (!iid.Dereference(iid->FirstThunk, &thunks)) {
800 i : LOG(ERROR) << "Unable to dereference IMAGE_THUNK_DATA32.";
801 i : return false;
802 : }
803 :
804 E : for (size_t j = 0; j < module->size(); ++j) {
805 : bool symbol_find_only =
806 E : module->GetSymbolMode(j) == ImportedModule::kFindOnly;
807 :
808 : // If the symbol was already resolved as a delay-load import, then
809 : // don't allow it to also be added as a normal import.
810 E : if (module->SymbolIsImported(j))
811 i : symbol_find_only = true;
812 :
813 : // Now, for each symbol get the offset of the IAT entry. This will create
814 : // the entry (and all accompanying structures) if necessary.
815 E : size_t symbol_iat_index = kInvalidIndex;
816 E : bool symbol_added = false;
817 : if (!FindOrAddImportedSymbol(
818 : symbol_find_only,
819 : module->GetSymbolName(j).c_str(),
820 : iid,
821 : block_graph,
822 : import_address_table_block_,
823 : &symbol_iat_index,
824 E : &symbol_added)) {
825 i : LOG(ERROR) << "Failed to find or import symbol.";
826 i : return false;
827 : }
828 E : symbols_added_ += symbol_added;
829 :
830 E : if (symbol_iat_index != kInvalidIndex) {
831 : Offset offset =
832 E : thunks.OffsetOf(thunks[symbol_iat_index].u1.AddressOfData);
833 : BlockGraph::Reference ref(BlockGraph::ABSOLUTE_REF, kPtrSize,
834 E : thunks.block(), offset, offset);
835 :
836 E : UpdateModuleSymbolInfo(j, true, symbol_added, module);
837 E : UpdateModuleSymbolReference(j, ref, true, module);
838 : }
839 E : }
840 E : }
841 :
842 : // Update the data directory sizes.
843 : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size =
844 E : image_import_descriptor_block_->size();
845 : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size =
846 E : import_address_table_block_->size();
847 :
848 E : return true;
849 E : }
850 :
851 : bool PEAddImportsTransform::FindDelayLoadImports(
852 E : BlockGraph* block_graph, BlockGraph::Block* nt_headers_block) {
853 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
854 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), nt_headers_block);
855 :
856 E : NtHeaders nt_headers;
857 E : CHECK(nt_headers.Init(0, nt_headers_block));
858 :
859 : // Get the delay-load import data directory.
860 E : image_delayload_descriptor_block_ = NULL;
861 : if (!FindOrAddDataDirectory(true,
862 : IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
863 : "Image Delay Load Descriptor Array",
864 : sizeof(IMAGE_DELAYLOAD_DESCRIPTOR),
865 : block_graph,
866 : nt_headers.block(),
867 E : &image_delayload_descriptor_block_)) {
868 i : return false;
869 : }
870 E : if (image_delayload_descriptor_block_ == NULL)
871 E : return true;
872 :
873 E : ImageDelayLoadDescriptor idld;
874 E : if (!idld.Init(0, image_delayload_descriptor_block_)) {
875 i : LOG(ERROR) << "Unable to cast IMAGE_DELAYLOAD_DESCRIPTOR.";
876 i : return false;
877 : }
878 :
879 E : for (size_t i = 0; i < imported_modules_.size(); ++i) {
880 E : ImportedModule* module = imported_modules_[i];
881 :
882 : // Look for a descriptor corresponding to this module.
883 E : size_t module_index = kInvalidIndex;
884 E : if (!FindDelayLoadImportDescriptor(module->name(), idld, &module_index))
885 i : return false;
886 E : if (module_index == kInvalidIndex)
887 E : continue;
888 :
889 E : UpdateModule(true, false, module);
890 :
891 : // Iterate over the symbols.
892 E : for (size_t j = 0; j < module->size(); ++j) {
893 : // Don't process symbols that are already imported.
894 E : if (module->SymbolIsImported(j))
895 i : continue;
896 :
897 : // Look for a matching symbol.
898 E : bool found = false;
899 E : size_t index = kInvalidIndex;
900 E : BlockGraph::Reference ref;
901 : if (!FindDelayLoadSymbol(module->GetSymbolName(j), idld, module_index,
902 E : &found, &index, &ref)) {
903 i : return false;
904 : }
905 E : if (!found)
906 i : continue;
907 :
908 : // Update the various metadata associated with this symbol.
909 : // TODO(chrisha): Currently the import index must be unique. This ensures
910 : // uniqueness for delay-load imports by setting the MSB, and combining
911 : // the module index with the symbol index.
912 E : UpdateModuleSymbolInfo(j, true, false, module);
913 E : UpdateModuleSymbolReference(j, ref, true, module);
914 E : }
915 E : }
916 :
917 E : return true;
918 E : }
919 :
920 : } // namespace transforms
921 : } // namespace pe
|