Coverage for /Syzygy/pe/transforms/pe_add_imports_transform.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
81.6%3053740.C++source

Line-by-line coverage:

   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

Coverage information generated Thu Jan 14 17:40:38 2016.