Coverage for /Syzygy/pe/pe_file.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
87.8%2582940.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    :  #include "syzygy/pe/pe_file.h"
  15    :  
  16    :  #include "base/file_util.h"
  17    :  #include "base/logging.h"
  18    :  
  19    :  namespace pe {
  20    :  
  21    :  using core::AbsoluteAddress;
  22    :  using core::FileOffsetAddress;
  23    :  using core::RelativeAddress;
  24    :  
  25    :  PEFile::PEFile()
  26    :      : dos_header_(NULL),
  27  E :        nt_headers_(NULL) {
  28  E :  }
  29    :  
  30  E :  PEFile::~PEFile() {
  31  E :  }
  32    :  
  33  E :  bool PEFile::Init(const base::FilePath& path) {
  34  E :    PECoffFile::Init(path);
  35    :  
  36  E :    FILE* file = file_util::OpenFile(path, "rb");
  37  E :    if (file == NULL) {
  38  E :      LOG(ERROR) << "Failed to open file " << path.value() << ".";
  39  E :      return false;
  40    :    }
  41    :  
  42  E :    bool success = ReadHeaders(file);
  43  E :    if (success)
  44  E :      success = ReadSections(file);
  45    :  
  46  E :    file_util::CloseFile(file);
  47    :  
  48  E :    return success;
  49  E :  }
  50    :  
  51  E :  void PEFile::GetSignature(Signature* signature) const {
  52  E :    DCHECK(signature != NULL);
  53  E :    DCHECK(nt_headers_ != NULL);
  54    :  
  55    :    // TODO(chrisha): Make GetSignature return a bool, and update all calling
  56    :    //     sites.
  57  E :    base::FilePath abs_path(base::MakeAbsoluteFilePath(path_));
  58  E :    CHECK(!abs_path.empty());
  59    :  
  60  E :    signature->path = abs_path.value();
  61    :    signature->base_address =
  62  E :        AbsoluteAddress(nt_headers_->OptionalHeader.ImageBase);
  63  E :    signature->module_size = nt_headers_->OptionalHeader.SizeOfImage;
  64  E :    signature->module_time_date_stamp = nt_headers_->FileHeader.TimeDateStamp;
  65  E :    signature->module_checksum = nt_headers_->OptionalHeader.CheckSum;
  66  E :  }
  67    :  
  68  E :  bool PEFile::Contains(AbsoluteAddress abs, size_t len) const {
  69  E :    RelativeAddress rel;
  70  E :    return Translate(abs, &rel) && Contains(rel, len);
  71  E :  }
  72    :  
  73  E :  size_t PEFile::GetSectionIndex(AbsoluteAddress abs, size_t len) const {
  74  E :    RelativeAddress rel;
  75  E :    if (!Translate(abs, &rel))
  76  E :      return kInvalidSection;
  77  E :    return GetSectionIndex(rel, len);
  78  E :  }
  79    :  
  80    :  const IMAGE_SECTION_HEADER* PEFile::GetSectionHeader(
  81  E :      AbsoluteAddress abs, size_t len) const {
  82  E :    RelativeAddress rel;
  83  E :    if (!Translate(abs, &rel))
  84  i :      return NULL;
  85  E :    return GetSectionHeader(rel, len);
  86  E :  }
  87    :  
  88  E :  size_t PEFile::GetSectionIndex(const char* name) const {
  89  E :    size_t section_count = file_header_->NumberOfSections;
  90  E :    for (size_t i = 0; i < section_count; ++i) {
  91  E :      const IMAGE_SECTION_HEADER* header = section_headers_ + i;
  92    :      if (strncmp(reinterpret_cast<const char*>(header->Name), name,
  93  E :                  IMAGE_SIZEOF_SHORT_NAME) == 0)
  94  E :        return i;
  95  E :    }
  96  E :    return kInvalidSection;
  97  E :  }
  98    :  
  99  E :  const IMAGE_SECTION_HEADER* PEFile::GetSectionHeader(const char* name) const {
 100  E :    size_t id = GetSectionIndex(name);
 101  E :    if (id == kInvalidSection)
 102  E :      return NULL;
 103  E :    return section_headers_ + id;
 104  E :  }
 105    :  
 106  E :  bool PEFile::ReadHeaders(FILE* file) {
 107    :    // Read the DOS header.
 108  E :    IMAGE_DOS_HEADER dos_header = {};
 109  E :    if (!ReadAt(file, 0, &dos_header, sizeof(dos_header))) {
 110  i :      LOG(ERROR) << "Unable to read DOS header.";
 111  i :      return false;
 112    :    }
 113    :  
 114    :    // And the NT headers.
 115  E :    IMAGE_NT_HEADERS nt_headers = {};
 116  E :    size_t pos = dos_header.e_lfanew;
 117  E :    if (!ReadAt(file, pos, &nt_headers, sizeof(nt_headers))) {
 118  i :      LOG(ERROR) << "Unable to read NT headers.";
 119  i :      return false;
 120    :    }
 121    :  
 122    :    FileOffsetAddress file_header_start(
 123  E :        pos + offsetof(IMAGE_NT_HEADERS, FileHeader));
 124  E :    if (!ReadCommonHeaders(file, file_header_start)) {
 125  i :      return false;
 126    :    }
 127    :  
 128  E :    ImageAddressSpace::RangeMap::iterator it = image_data_.begin();
 129  E :    DCHECK(it != image_data_.end());
 130  E :    SectionBuffer& header = it->second.buffer;
 131    :  
 132    :    // TODO(siggi): Validate these pointers!
 133  E :    dos_header_ = reinterpret_cast<IMAGE_DOS_HEADER*>(&header.at(0));
 134    :    nt_headers_ =
 135  E :        reinterpret_cast<IMAGE_NT_HEADERS*>(&header.at(dos_header_->e_lfanew));
 136    :  
 137  E :    return true;
 138  E :  }
 139    :  
 140  E :  bool PEFile::Translate(RelativeAddress rel, AbsoluteAddress* abs) const {
 141  E :    DCHECK(abs != NULL);
 142  E :    if (rel.value() >= nt_headers_->OptionalHeader.SizeOfImage)
 143  E :      return false;
 144  E :    abs->set_value(rel.value() + nt_headers_->OptionalHeader.ImageBase);
 145  E :    return true;
 146  E :  }
 147    :  
 148  E :  bool PEFile::Translate(AbsoluteAddress abs, RelativeAddress* rel) const {
 149  E :    DCHECK(rel != NULL);
 150  E :    uint32 rel_addr = AbsToRelDisplacement(abs.value());
 151  E :    if (rel_addr >= nt_headers_->OptionalHeader.SizeOfImage)
 152  E :      return false;
 153  E :    rel->set_value(rel_addr);
 154  E :    return true;
 155  E :  }
 156    :  
 157  E :  bool PEFile::Translate(FileOffsetAddress offs, RelativeAddress* rel) const {
 158  E :    DCHECK(rel != NULL);
 159    :  
 160    :    // The first "previous section" is the headers.
 161  E :    RelativeAddress previous_section_start(0);
 162  E :    FileOffsetAddress previous_section_file_start(0);
 163  E :    const IMAGE_SECTION_HEADER* previous_section = NULL;
 164  E :    for (size_t i = 0; i < nt_headers_->FileHeader.NumberOfSections; ++i) {
 165  E :      if (offs.value() < section_headers_[i].PointerToRawData)
 166  E :        break;
 167    :  
 168  E :      previous_section_start.set_value(section_headers_[i].VirtualAddress);
 169  E :      previous_section_file_start.set_value(section_headers_[i].PointerToRawData);
 170  E :      previous_section = section_headers_ + i;
 171  E :    }
 172    :  
 173  E :    size_t section_offset = offs - previous_section_file_start;
 174    :    if (previous_section != NULL &&
 175  E :        section_offset >= previous_section->SizeOfRawData) {
 176  E :      return false;
 177    :    }
 178    :  
 179  E :    *rel = previous_section_start + section_offset;
 180    :  
 181  E :    return true;
 182  E :  }
 183    :  
 184  E :  bool PEFile::Translate(RelativeAddress rel, FileOffsetAddress* offs) const {
 185  E :    DCHECK(offs != NULL);
 186    :  
 187    :    // In the headers?
 188  E :    if (rel.value() < section_header(0)->VirtualAddress) {
 189  E :      offs->set_value(rel.value());
 190  E :      return true;
 191    :    }
 192    :  
 193    :    // Find the section in which this address lies.
 194  E :    const IMAGE_SECTION_HEADER* section = GetSectionHeader(rel, 1);
 195  E :    if (section == NULL)
 196  E :      return false;
 197    :  
 198    :    // Calculate the offset of this address and ensure it can be expressed as
 199    :    // a file offset (lies in the explicit data part of the section, not the
 200    :    // implicit virtual data at the end).
 201  E :    size_t section_offset = rel.value() - section->VirtualAddress;
 202  E :    if (section_offset >= section->SizeOfRawData)
 203  E :      return false;
 204    :  
 205  E :    offs->set_value(section->PointerToRawData + section_offset);
 206    :  
 207  E :    return true;
 208  E :  }
 209    :  
 210  E :  const uint8* PEFile::GetImageData(AbsoluteAddress abs, size_t len) const {
 211  E :    RelativeAddress rel;
 212  E :    if (Translate(abs, &rel))
 213  E :      return GetImageData(rel, len);
 214    :  
 215  i :    return NULL;
 216  E :  }
 217    :  
 218  E :  uint8* PEFile::GetImageData(AbsoluteAddress abs, size_t len) {
 219    :    return const_cast<uint8*>(
 220  E :        static_cast<const PEFile*>(this)->GetImageData(abs, len));
 221  E :  }
 222    :  
 223  E :  bool PEFile::ReadImage(AbsoluteAddress abs, void* data, size_t len) const {
 224  E :    RelativeAddress rel;
 225  E :    if (!Translate(abs, &rel))
 226  i :      return false;
 227    :  
 228  E :    return ReadImage(rel, data, len);
 229  E :  }
 230    :  
 231  E :  bool PEFile::ReadImageString(AbsoluteAddress abs, std::string* str) const {
 232  E :    RelativeAddress rel;
 233  E :    if (!Translate(abs, &rel))
 234  i :      return false;
 235    :  
 236  E :    return ReadImageString(rel, str);
 237  E :  }
 238    :  
 239  E :  bool PEFile::DecodeRelocs(RelocSet* relocs) const {
 240  E :    DCHECK(nt_headers_ != NULL);
 241  E :    DCHECK(relocs != NULL);
 242    :  
 243    :    // Walk the relocs.
 244    :    IMAGE_DATA_DIRECTORY dir =
 245    :        nt_headers_->OptionalHeader.DataDirectory[
 246  E :            IMAGE_DIRECTORY_ENTRY_BASERELOC];
 247  E :    RelativeAddress offs(dir.VirtualAddress);
 248  E :    RelativeAddress end(offs + dir.Size);
 249    :  
 250  E :    const IMAGE_BASE_RELOCATION* hdr = NULL;
 251  E :    for (; offs < end; offs += hdr->SizeOfBlock) {
 252    :      // Read the next header.
 253  E :      if (!GetImageData(offs, sizeof(hdr), &hdr)) {
 254  i :        LOG(ERROR) << "Failed to read relocation block header.";
 255  i :        return false;
 256    :      }
 257    :  
 258    :      // Read the entries.
 259  E :      size_t num_relocs = (hdr->SizeOfBlock - sizeof(*hdr)) / sizeof(WORD);
 260  E :      const WORD* reloc_block = NULL;
 261    :      if (!GetImageData(offs + sizeof(*hdr), sizeof(*reloc_block) * num_relocs,
 262  E :                        &reloc_block)) {
 263  i :        LOG(ERROR) << "Failed to read relocation entries.";
 264  i :        return false;
 265    :      }
 266    :  
 267    :      // Walk the entries.
 268  E :      for (size_t i = 0; i < num_relocs; ++i) {
 269  E :        uint8 type = reloc_block[i] >> 12;
 270  E :        uint16 offs = reloc_block[i] & 0xFFF;
 271    :        DCHECK(type == IMAGE_REL_BASED_HIGHLOW ||
 272  E :               type == IMAGE_REL_BASED_ABSOLUTE);
 273    :  
 274  E :        if (type == IMAGE_REL_BASED_HIGHLOW) {
 275    :          // Record the entry.
 276  E :          relocs->insert(RelativeAddress(hdr->VirtualAddress) + offs);
 277    :        }
 278  E :      }
 279  E :    }
 280    :  
 281  E :    DCHECK(offs == end);
 282  E :    return true;
 283  E :  }
 284    :  
 285  E :  bool PEFile::ReadRelocs(const RelocSet& relocs, RelocMap* reloc_values) const {
 286  E :    RelocSet::const_iterator it(relocs.begin());
 287  E :    for (; it != relocs.end(); ++it) {
 288  E :      const AbsoluteAddress* abs = NULL;
 289  E :      if (!GetImageData(*it, sizeof(*abs), &abs)) {
 290  i :        LOG(ERROR) << "Failed to read reloc at " << it->value() << ".";
 291  i :        return false;
 292    :      }
 293    :  
 294  E :      reloc_values->insert(std::make_pair(*it, *abs));
 295  E :    }
 296    :  
 297  E :    return true;
 298  E :  }
 299    :  
 300  E :  bool PEFile::DecodeExports(ExportInfoVector* exports) const {
 301  E :    DCHECK(exports != NULL);
 302    :  
 303    :    IMAGE_DATA_DIRECTORY dir = nt_headers_->OptionalHeader.
 304  E :        DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
 305  E :    RelativeAddress addr(dir.VirtualAddress);
 306  E :    RelativeAddress end(addr + dir.Size);
 307    :  
 308  E :    if (addr.value() == 0)
 309  i :      return true;
 310    :  
 311  E :    const IMAGE_EXPORT_DIRECTORY* export_dir = NULL;
 312  E :    if (!GetImageData(addr, sizeof(export_dir), &export_dir)) {
 313  i :      LOG(ERROR) << "Unable to read export directory.";
 314  i :      return false;
 315    :    }
 316    :  
 317  E :    const RelativeAddress* functions = NULL;
 318    :    if (!GetImageData(RelativeAddress(export_dir->AddressOfFunctions),
 319    :                      sizeof(*functions) * export_dir->NumberOfFunctions,
 320  E :                      &functions)) {
 321  i :      LOG(ERROR) << "Unable to read export functions.";
 322  i :      return false;
 323    :    }
 324    :  
 325  E :    const RelativeAddress* names = NULL;
 326    :    if (!GetImageData(RelativeAddress(export_dir->AddressOfNames),
 327    :                      sizeof(*functions) * export_dir->NumberOfNames,
 328  E :                      &names)) {
 329  i :      LOG(ERROR) << "Unable to read export names.";
 330  i :      return false;
 331    :    }
 332    :  
 333  E :    const WORD* name_ordinals = NULL;
 334    :    if (!GetImageData(RelativeAddress(export_dir->AddressOfNameOrdinals),
 335    :                      sizeof(*functions) * export_dir->NumberOfNames,
 336  E :                      &name_ordinals)) {
 337  i :      LOG(ERROR) << "Unable to read name ordinals.";
 338  i :      return false;
 339    :    }
 340    :  
 341  E :    for (size_t index = 0; index < export_dir->NumberOfFunctions; ++index) {
 342    :      // Is it a blank entry?
 343  E :      if (functions[index] != RelativeAddress(0)) {
 344  E :        ExportInfo info;
 345  E :        info.ordinal = index + 1;
 346    :  
 347  E :        RelativeAddress function = functions[index];
 348    :        // Is it a forward?
 349  E :        if (function >= addr && function < end) {
 350  E :          if (!ReadImageString(function, &info.forward)) {
 351  i :            LOG(ERROR) << "Unable to read export forward string.";
 352  i :            return false;
 353    :          }
 354  E :        } else {
 355  E :          info.function = function;
 356    :        }
 357    :  
 358    :        // Does it have a name?
 359  E :        for (size_t i = 0; i < export_dir->NumberOfNames; ++i) {
 360  E :          if (name_ordinals[i] == index) {
 361  E :            if (!ReadImageString(names[i], &info.name)) {
 362  i :              LOG(ERROR) << "Unable to read export name.";
 363  i :              return false;
 364    :            }
 365  E :            break;
 366    :          }
 367  E :        }
 368    :  
 369  E :        exports->push_back(info);
 370  E :      }
 371  E :    }
 372    :  
 373  E :    return true;
 374  E :  }
 375    :  
 376  E :  bool PEFile::DecodeImports(ImportDllVector* imports) const {
 377  E :    DCHECK(imports != NULL);
 378    :  
 379    :    // Walk the import thunks.
 380    :    IMAGE_DATA_DIRECTORY dir = nt_headers_->OptionalHeader.
 381  E :        DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
 382  E :    RelativeAddress offs(dir.VirtualAddress);
 383  E :    RelativeAddress end(offs + dir.Size);
 384    :  
 385  E :    const IMAGE_IMPORT_DESCRIPTOR* import_desc = NULL;
 386  E :    for (; offs < end; offs += sizeof(*import_desc)) {
 387  E :      if (!GetImageData(offs, sizeof(*import_desc), &import_desc)) {
 388  i :        LOG(ERROR) << "Unable to read import descriptor.";
 389  i :        return false;
 390    :      }
 391    :  
 392  E :      if (import_desc->Characteristics == 0 && import_desc->FirstThunk == 0) {
 393    :        // This is the last chunk, bail the loop.
 394  E :        break;
 395    :      }
 396    :  
 397  E :      std::string dll_name;
 398  E :      if (!ReadImageString(RelativeAddress(import_desc->Name), &dll_name)) {
 399  i :        LOG(ERROR) << "Unable to read import descriptor name.";
 400  i :        return false;
 401    :      }
 402    :  
 403    :      // Iterate the Import Name Table and the Import Address Table
 404    :      // concurrently. They will yield, respectively, the name of the
 405    :      // function and the address of the entry.
 406  E :      RelativeAddress int_offs(import_desc->OriginalFirstThunk);
 407  E :      RelativeAddress iat_offs(import_desc->FirstThunk);
 408    :  
 409  E :      imports->push_back(ImportDll());
 410  E :      ImportDll& dll = imports->back();
 411  E :      dll.name = dll_name;
 412  E :      dll.desc = *import_desc;
 413    :  
 414  E :      while (true) {
 415  E :        IMAGE_THUNK_DATA int_thunk = {};
 416  E :        IMAGE_THUNK_DATA iat_thunk = {};
 417    :  
 418    :        if (!ReadImage(int_offs, &int_thunk, sizeof(int_thunk)) ||
 419  E :            !ReadImage(iat_offs, &iat_thunk, sizeof(iat_thunk))) {
 420  i :          LOG(ERROR) << "Unable to read import name or address table thunk.";
 421  i :          return false;
 422    :        }
 423    :  
 424    :        // Are we at the end of the table?
 425  E :        if (int_thunk.u1.Function == 0) {
 426  E :          DCHECK_EQ(0U, iat_thunk.u1.Function);
 427  E :          break;
 428    :        }
 429    :  
 430  E :        uint16 hint = 0;
 431  E :        uint16 ordinal = 0;
 432  E :        std::string function_name;
 433  E :        if (int_thunk.u1.AddressOfData & IMAGE_ORDINAL_FLAG32) {
 434    :          // It's an ordinal.
 435  E :          ordinal = IMAGE_ORDINAL32(int_thunk.u1.Ordinal);
 436  E :        } else {
 437    :          // Read the hint word, followed by the function name.
 438  E :          RelativeAddress import_name(int_thunk.u1.AddressOfData);
 439    :          if (!ReadImage(import_name, &hint, sizeof(hint)) ||
 440  E :              !ReadImageString(import_name + sizeof(hint), &function_name)) {
 441  i :            LOG(ERROR) << "Unable to read import function hint or name.";
 442  i :            return false;
 443    :          }
 444    :        }
 445    :  
 446  E :        dll.functions.push_back(ImportInfo());
 447  E :        ImportInfo& info = dll.functions.back();
 448  E :        info.function = function_name;
 449  E :        info.ordinal = ordinal;
 450  E :        info.hint = hint;
 451    :  
 452  E :        int_offs += sizeof(int_thunk);
 453  E :        iat_offs += sizeof(iat_thunk);
 454  E :      }
 455  E :    }
 456    :  
 457  E :    return true;
 458  E :  }
 459    :  
 460  E :  bool PEFile::Signature::IsConsistent(const Signature& signature) const {
 461    :    return IsConsistentExceptForChecksum(signature) &&
 462  E :        module_checksum == signature.module_checksum;
 463  E :  }
 464    :  
 465    :  bool PEFile::Signature::IsConsistentExceptForChecksum(
 466  E :      const Signature& signature) const {
 467    :    return base_address == signature.base_address &&
 468    :        module_size == signature.module_size &&
 469  E :        module_time_date_stamp == signature.module_time_date_stamp;
 470  E :  }
 471    :  
 472  E :  bool PEFile::Signature::Save(core::OutArchive* out_archive) const {
 473    :    return out_archive->Save(path) &&
 474    :        out_archive->Save(base_address) &&
 475    :        out_archive->Save(module_size) &&
 476    :        out_archive->Save(module_time_date_stamp) &&
 477  E :        out_archive->Save(module_checksum);
 478  E :  }
 479    :  
 480  E :  bool PEFile::Signature::Load(core::InArchive* in_archive) {
 481    :    return in_archive->Load(&path) &&
 482    :        in_archive->Load(&base_address) &&
 483    :        in_archive->Load(&module_size) &&
 484    :        in_archive->Load(&module_time_date_stamp) &&
 485  E :        in_archive->Load(&module_checksum);
 486  E :  }
 487    :  
 488    :  }  // namespace pe

Coverage information generated Wed Dec 11 11:34:16 2013.