tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pe_image.cc (21100B)


      1 // Copyright 2010 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // This file implements PEImage, a generic class to manipulate PE files.
      6 // This file was adapted from GreenBorder's Code.
      7 
      8 #include "base/win/pe_image.h"
      9 
     10 #include <stddef.h>
     11 #include <set>
     12 #include <string>
     13 
     14 #include "base/no_destructor.h"
     15 #include "base/win/current_module.h"
     16 
     17 namespace base {
     18 namespace win {
     19 
     20 // Structure to perform imports enumerations.
     21 struct EnumAllImportsStorage {
     22  PEImage::EnumImportsFunction callback;
     23  PVOID cookie;
     24 };
     25 
     26 namespace {
     27 
     28 // PdbInfo Signature
     29 const DWORD kPdbInfoSignature = 'SDSR';
     30 
     31 // Compare two strings byte by byte on an unsigned basis.
     32 //   if s1 == s2, return 0
     33 //   if s1 < s2, return negative
     34 //   if s1 > s2, return positive
     35 // Exception if inputs are invalid.
     36 int StrCmpByByte(LPCSTR s1, LPCSTR s2) {
     37  while (*s1 != '\0' && *s1 == *s2) {
     38    ++s1;
     39    ++s2;
     40  }
     41 
     42  return (*reinterpret_cast<const unsigned char*>(s1) -
     43          *reinterpret_cast<const unsigned char*>(s2));
     44 }
     45 
     46 struct PdbInfo {
     47  DWORD Signature;
     48  GUID Guid;
     49  DWORD Age;
     50  char PdbFileName[1];
     51 };
     52 
     53 #define LDR_IS_DATAFILE(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR)1)
     54 #define LDR_IS_IMAGEMAPPING(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR)2)
     55 #define LDR_IS_RESOURCE(handle) \
     56  (LDR_IS_IMAGEMAPPING(handle) || LDR_IS_DATAFILE(handle))
     57 
     58 }  // namespace
     59 
     60 // Callback used to enumerate imports. See EnumImportChunksFunction.
     61 bool ProcessImportChunk(const PEImage& image,
     62                        LPCSTR module,
     63                        PIMAGE_THUNK_DATA name_table,
     64                        PIMAGE_THUNK_DATA iat,
     65                        PVOID cookie) {
     66  EnumAllImportsStorage& storage =
     67      *reinterpret_cast<EnumAllImportsStorage*>(cookie);
     68 
     69  return image.EnumOneImportChunk(storage.callback, module, name_table, iat,
     70                                  storage.cookie);
     71 }
     72 
     73 // Callback used to enumerate delay imports. See EnumDelayImportChunksFunction.
     74 bool ProcessDelayImportChunk(const PEImage& image,
     75                             PImgDelayDescr delay_descriptor,
     76                             LPCSTR module,
     77                             PIMAGE_THUNK_DATA name_table,
     78                             PIMAGE_THUNK_DATA iat,
     79                             PVOID cookie) {
     80  EnumAllImportsStorage& storage =
     81      *reinterpret_cast<EnumAllImportsStorage*>(cookie);
     82 
     83  return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor,
     84                                       module, name_table, iat, storage.cookie);
     85 }
     86 
     87 void PEImage::set_module(HMODULE module) {
     88  module_ = module;
     89 }
     90 
     91 PIMAGE_DOS_HEADER PEImage::GetDosHeader() const {
     92  return reinterpret_cast<PIMAGE_DOS_HEADER>(module_);
     93 }
     94 
     95 PIMAGE_NT_HEADERS PEImage::GetNTHeaders() const {
     96  PIMAGE_DOS_HEADER dos_header = GetDosHeader();
     97 
     98  return reinterpret_cast<PIMAGE_NT_HEADERS>(
     99      reinterpret_cast<char*>(dos_header) + dos_header->e_lfanew);
    100 }
    101 
    102 PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(WORD section) const {
    103  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
    104  PIMAGE_SECTION_HEADER first_section = IMAGE_FIRST_SECTION(nt_headers);
    105 
    106  if (section < nt_headers->FileHeader.NumberOfSections)
    107    return first_section + section;
    108  else
    109    return nullptr;
    110 }
    111 
    112 WORD PEImage::GetNumSections() const {
    113  return GetNTHeaders()->FileHeader.NumberOfSections;
    114 }
    115 
    116 DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const {
    117  const IMAGE_DATA_DIRECTORY* const entry = GetDataDirectory(directory);
    118  return entry ? entry->Size : 0;
    119 }
    120 
    121 PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const {
    122  const IMAGE_DATA_DIRECTORY* const entry = GetDataDirectory(directory);
    123  return entry ? RVAToAddr(entry->VirtualAddress) : nullptr;
    124 }
    125 
    126 PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const {
    127  PBYTE target = reinterpret_cast<PBYTE>(address);
    128  PIMAGE_SECTION_HEADER section;
    129 
    130  for (WORD i = 0; nullptr != (section = GetSectionHeader(i)); i++) {
    131    // Don't use the virtual RVAToAddr.
    132    PBYTE start =
    133        reinterpret_cast<PBYTE>(PEImage::RVAToAddr(section->VirtualAddress));
    134 
    135    DWORD size = section->Misc.VirtualSize;
    136 
    137    if ((start <= target) && (start + size > target))
    138      return section;
    139  }
    140 
    141  return nullptr;
    142 }
    143 
    144 PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName(
    145    LPCSTR section_name) const {
    146  if (section_name == nullptr)
    147    return nullptr;
    148 
    149  WORD num_sections = GetNumSections();
    150  for (WORD i = 0; i < num_sections; ++i) {
    151    PIMAGE_SECTION_HEADER section = GetSectionHeader(i);
    152    if (_strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name,
    153                  sizeof(section->Name)) == 0) {
    154      return section;
    155    }
    156  }
    157 
    158  return nullptr;
    159 }
    160 
    161 bool PEImage::GetDebugId(LPGUID guid,
    162                         LPDWORD age,
    163                         LPCSTR* pdb_filename,
    164                         size_t* pdb_filename_length) const {
    165  DWORD debug_directory_size =
    166      GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG);
    167  PIMAGE_DEBUG_DIRECTORY debug_directory =
    168      reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(
    169          GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
    170  if (!debug_directory)
    171    return false;
    172 
    173  size_t directory_count = debug_directory_size / sizeof(IMAGE_DEBUG_DIRECTORY);
    174  for (size_t index = 0; index < directory_count; ++index) {
    175    const IMAGE_DEBUG_DIRECTORY& entry = debug_directory[index];
    176    if (entry.Type != IMAGE_DEBUG_TYPE_CODEVIEW)
    177      continue;  // Unsupported debugging info format.
    178    if (entry.SizeOfData < sizeof(PdbInfo))
    179      continue;  // The data is too small to hold PDB info.
    180    const PdbInfo* pdb_info =
    181        reinterpret_cast<const PdbInfo*>(RVAToAddr(entry.AddressOfRawData));
    182    if (!pdb_info)
    183      continue;  // The data is not present in a mapped section.
    184    if (pdb_info->Signature != kPdbInfoSignature)
    185      continue;  // Unsupported PdbInfo signature
    186 
    187    if (guid)
    188      *guid = pdb_info->Guid;
    189    if (age)
    190      *age = pdb_info->Age;
    191    if (pdb_filename) {
    192      const size_t length_max =
    193          entry.SizeOfData - offsetof(PdbInfo, PdbFileName);
    194      const char* eos = pdb_info->PdbFileName;
    195      for (const char* const end = pdb_info->PdbFileName + length_max;
    196           eos < end && *eos; ++eos)
    197        ;
    198      // This static_cast is safe because the loop above only increments eos,
    199      // and ensures it won't wrap.
    200      *pdb_filename_length = static_cast<size_t>(eos - pdb_info->PdbFileName);
    201      *pdb_filename = pdb_info->PdbFileName;
    202    }
    203    return true;
    204  }
    205  return false;
    206 }
    207 
    208 PDWORD PEImage::GetExportEntry(LPCSTR name) const {
    209  PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
    210 
    211  if (nullptr == exports)
    212    return nullptr;
    213 
    214  WORD ordinal = 0;
    215  if (!GetProcOrdinal(name, &ordinal))
    216    return nullptr;
    217 
    218  PDWORD functions =
    219      reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfFunctions));
    220 
    221  return functions + ordinal - exports->Base;
    222 }
    223 
    224 FARPROC PEImage::GetProcAddress(LPCSTR function_name) const {
    225  PDWORD export_entry = GetExportEntry(function_name);
    226  if (nullptr == export_entry)
    227    return nullptr;
    228 
    229  PBYTE function = reinterpret_cast<PBYTE>(RVAToAddr(*export_entry));
    230 
    231  PBYTE exports = reinterpret_cast<PBYTE>(
    232      GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
    233  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
    234  if (!exports || !size)
    235    return nullptr;
    236 
    237  // Check for forwarded exports as a special case.
    238  if (exports <= function && exports + size > function)
    239    return reinterpret_cast<FARPROC>(-1);
    240 
    241  return reinterpret_cast<FARPROC>(function);
    242 }
    243 
    244 bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD* ordinal) const {
    245  if (nullptr == ordinal)
    246    return false;
    247 
    248  PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
    249 
    250  if (nullptr == exports)
    251    return false;
    252 
    253  if (IsOrdinal(function_name)) {
    254    *ordinal = ToOrdinal(function_name);
    255  } else {
    256    PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
    257    PDWORD lower = names;
    258    PDWORD upper = names + exports->NumberOfNames;
    259    int cmp = -1;
    260 
    261    // Binary Search for the name.
    262    while (lower != upper) {
    263      PDWORD middle = lower + (upper - lower) / 2;
    264      LPCSTR name = reinterpret_cast<LPCSTR>(RVAToAddr(*middle));
    265 
    266      // This may be called by sandbox before MSVCRT dll loads, so can't use
    267      // CRT function here.
    268      cmp = StrCmpByByte(function_name, name);
    269 
    270      if (cmp == 0) {
    271        lower = middle;
    272        break;
    273      }
    274 
    275      if (cmp > 0)
    276        lower = middle + 1;
    277      else
    278        upper = middle;
    279    }
    280 
    281    if (cmp != 0)
    282      return false;
    283 
    284    PWORD ordinals =
    285        reinterpret_cast<PWORD>(RVAToAddr(exports->AddressOfNameOrdinals));
    286 
    287    *ordinal = ordinals[lower - names] + static_cast<WORD>(exports->Base);
    288  }
    289 
    290  return true;
    291 }
    292 
    293 bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const {
    294  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
    295  UINT num_sections = nt_headers->FileHeader.NumberOfSections;
    296  PIMAGE_SECTION_HEADER section = GetSectionHeader(0);
    297 
    298  for (WORD i = 0; i < num_sections; i++, section++) {
    299    PVOID section_start = RVAToAddr(section->VirtualAddress);
    300    DWORD size = section->Misc.VirtualSize;
    301 
    302    if (!callback(*this, section, section_start, size, cookie))
    303      return false;
    304  }
    305 
    306  return true;
    307 }
    308 
    309 bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const {
    310  PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT);
    311  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
    312 
    313  // Check if there are any exports at all.
    314  if (!directory || !size)
    315    return true;
    316 
    317  PIMAGE_EXPORT_DIRECTORY exports =
    318      reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(directory);
    319  UINT ordinal_base = exports->Base;
    320  UINT num_funcs = exports->NumberOfFunctions;
    321  UINT num_names = exports->NumberOfNames;
    322  PDWORD functions =
    323      reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfFunctions));
    324  PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
    325  PWORD ordinals =
    326      reinterpret_cast<PWORD>(RVAToAddr(exports->AddressOfNameOrdinals));
    327 
    328  for (UINT count = 0; count < num_funcs; count++) {
    329    PVOID func = RVAToAddr(functions[count]);
    330    if (nullptr == func)
    331      continue;
    332 
    333    // Check for a name.
    334    LPCSTR name = nullptr;
    335    UINT hint;
    336    for (hint = 0; hint < num_names; hint++) {
    337      if (ordinals[hint] == count) {
    338        name = reinterpret_cast<LPCSTR>(RVAToAddr(names[hint]));
    339        break;
    340      }
    341    }
    342 
    343    if (name == nullptr)
    344      hint = 0;
    345 
    346    // Check for forwarded exports.
    347    LPCSTR forward = nullptr;
    348    if (reinterpret_cast<char*>(func) >= reinterpret_cast<char*>(directory) &&
    349        reinterpret_cast<char*>(func) <=
    350            reinterpret_cast<char*>(directory) + size) {
    351      forward = reinterpret_cast<LPCSTR>(func);
    352      func = nullptr;
    353    }
    354 
    355    if (!callback(*this, ordinal_base + count, hint, name, func, forward,
    356                  cookie))
    357      return false;
    358  }
    359 
    360  return true;
    361 }
    362 
    363 bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const {
    364  PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC);
    365  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC);
    366 
    367  if (!directory || !size)
    368    return true;
    369 
    370  PIMAGE_BASE_RELOCATION base =
    371      reinterpret_cast<PIMAGE_BASE_RELOCATION>(directory);
    372  while (size >= sizeof(IMAGE_BASE_RELOCATION) && base->SizeOfBlock &&
    373         size >= base->SizeOfBlock) {
    374    PWORD reloc = reinterpret_cast<PWORD>(base + 1);
    375    UINT num_relocs =
    376        (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
    377 
    378    for (UINT i = 0; i < num_relocs; i++, reloc++) {
    379      WORD type = *reloc >> 12;
    380      PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF));
    381 
    382      if (!callback(*this, type, address, cookie))
    383        return false;
    384    }
    385 
    386    size -= base->SizeOfBlock;
    387    base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
    388        reinterpret_cast<char*>(base) + base->SizeOfBlock);
    389  }
    390 
    391  return true;
    392 }
    393 
    394 bool PEImage::EnumImportChunks(EnumImportChunksFunction callback,
    395                               PVOID cookie,
    396                               LPCSTR target_module_name) const {
    397  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT);
    398  PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk();
    399 
    400  if (import == nullptr || size < sizeof(IMAGE_IMPORT_DESCRIPTOR))
    401    return true;
    402 
    403  for (; import->FirstThunk; import++) {
    404    LPCSTR module_name = reinterpret_cast<LPCSTR>(RVAToAddr(import->Name));
    405    PIMAGE_THUNK_DATA name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
    406        RVAToAddr(import->OriginalFirstThunk));
    407    PIMAGE_THUNK_DATA iat =
    408        reinterpret_cast<PIMAGE_THUNK_DATA>(RVAToAddr(import->FirstThunk));
    409 
    410    if (target_module_name == nullptr ||
    411        (lstrcmpiA(module_name, target_module_name) == 0)) {
    412      if (!callback(*this, module_name, name_table, iat, cookie))
    413        return false;
    414    }
    415  }
    416 
    417  return true;
    418 }
    419 
    420 bool PEImage::EnumOneImportChunk(EnumImportsFunction callback,
    421                                 LPCSTR module_name,
    422                                 PIMAGE_THUNK_DATA name_table,
    423                                 PIMAGE_THUNK_DATA iat,
    424                                 PVOID cookie) const {
    425  if (nullptr == name_table)
    426    return false;
    427 
    428  for (; name_table && name_table->u1.Ordinal; name_table++, iat++) {
    429    LPCSTR name = nullptr;
    430    WORD ordinal = 0;
    431    WORD hint = 0;
    432 
    433    if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
    434      ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
    435    } else {
    436      PIMAGE_IMPORT_BY_NAME import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
    437          RVAToAddr(name_table->u1.ForwarderString));
    438 
    439      hint = import->Hint;
    440      name = reinterpret_cast<LPCSTR>(&import->Name);
    441    }
    442 
    443    if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
    444      return false;
    445  }
    446 
    447  return true;
    448 }
    449 
    450 bool PEImage::EnumAllImports(EnumImportsFunction callback,
    451                             PVOID cookie,
    452                             LPCSTR target_module_name) const {
    453  EnumAllImportsStorage temp = {callback, cookie};
    454  return EnumImportChunks(ProcessImportChunk, &temp, target_module_name);
    455 }
    456 
    457 bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
    458                                    PVOID cookie,
    459                                    LPCSTR target_module_name) const {
    460  PVOID directory =
    461      GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
    462  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
    463 
    464  if (!directory || !size)
    465    return true;
    466 
    467  PImgDelayDescr delay_descriptor = reinterpret_cast<PImgDelayDescr>(directory);
    468  for (; delay_descriptor->rvaHmod; delay_descriptor++) {
    469    PIMAGE_THUNK_DATA name_table;
    470    PIMAGE_THUNK_DATA iat;
    471    LPCSTR module_name;
    472 
    473    // check if VC7-style imports, using RVAs instead of
    474    // VC6-style addresses.
    475    bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
    476 
    477    if (rvas) {
    478      module_name =
    479          reinterpret_cast<LPCSTR>(RVAToAddr(delay_descriptor->rvaDLLName));
    480      name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
    481          RVAToAddr(delay_descriptor->rvaINT));
    482      iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
    483          RVAToAddr(delay_descriptor->rvaIAT));
    484    } else {
    485      // Values in IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT are 32-bit, even on 64-bit
    486      // platforms. See section 4.8 of PECOFF image spec rev 8.3.
    487      module_name = reinterpret_cast<LPCSTR>(
    488          static_cast<uintptr_t>(delay_descriptor->rvaDLLName));
    489      name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
    490          static_cast<uintptr_t>(delay_descriptor->rvaINT));
    491      iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
    492          static_cast<uintptr_t>(delay_descriptor->rvaIAT));
    493    }
    494 
    495    if (target_module_name == nullptr ||
    496        (lstrcmpiA(module_name, target_module_name) == 0)) {
    497      if (target_module_name) {
    498        // Ensure all imports are properly loaded for the target module so that
    499        // the callback is operating on a fully-realized set of imports.
    500        // This call only loads the imports for the module where this code is
    501        // executing, so it is only helpful or meaningful to do this if the
    502        // current module is the module whose IAT we are enumerating.
    503        // Use the module_name as retrieved from the IAT because this method
    504        // is case sensitive.
    505        if (module_ == CURRENT_MODULE() && !LDR_IS_RESOURCE(module_)) {
    506          static base::NoDestructor<std::set<std::string>> loaded_dlls;
    507          // pair.second is true if this is a new element
    508          if (loaded_dlls.get()->emplace(module_name).second)
    509            ::__HrLoadAllImportsForDll(module_name);
    510        }
    511      }
    512 
    513      if (!callback(*this, delay_descriptor, module_name, name_table, iat,
    514                    cookie))
    515        return false;
    516    }
    517  }
    518 
    519  return true;
    520 }
    521 
    522 bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback,
    523                                      PImgDelayDescr delay_descriptor,
    524                                      LPCSTR module_name,
    525                                      PIMAGE_THUNK_DATA name_table,
    526                                      PIMAGE_THUNK_DATA iat,
    527                                      PVOID cookie) const {
    528  for (; name_table->u1.Ordinal; name_table++, iat++) {
    529    LPCSTR name = nullptr;
    530    WORD ordinal = 0;
    531    WORD hint = 0;
    532 
    533    if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
    534      ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
    535    } else {
    536      PIMAGE_IMPORT_BY_NAME import;
    537      bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
    538 
    539      if (rvas) {
    540        import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
    541            RVAToAddr(name_table->u1.ForwarderString));
    542      } else {
    543        import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
    544            name_table->u1.ForwarderString);
    545      }
    546 
    547      hint = import->Hint;
    548      name = reinterpret_cast<LPCSTR>(&import->Name);
    549    }
    550 
    551    if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
    552      return false;
    553  }
    554 
    555  return true;
    556 }
    557 
    558 bool PEImage::EnumAllDelayImports(EnumImportsFunction callback,
    559                                  PVOID cookie,
    560                                  LPCSTR target_module_name) const {
    561  EnumAllImportsStorage temp = {callback, cookie};
    562  return EnumDelayImportChunks(ProcessDelayImportChunk, &temp,
    563                               target_module_name);
    564 }
    565 
    566 bool PEImage::VerifyMagic() const {
    567  PIMAGE_DOS_HEADER dos_header = GetDosHeader();
    568 
    569  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
    570    return false;
    571 
    572  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
    573 
    574  if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
    575    return false;
    576 
    577  if (nt_headers->FileHeader.SizeOfOptionalHeader !=
    578      sizeof(IMAGE_OPTIONAL_HEADER))
    579    return false;
    580 
    581  if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
    582    return false;
    583 
    584  return true;
    585 }
    586 
    587 bool PEImage::ImageRVAToOnDiskOffset(uintptr_t rva,
    588                                     DWORD* on_disk_offset) const {
    589  LPVOID address = RVAToAddr(rva);
    590  return ImageAddrToOnDiskOffset(address, on_disk_offset);
    591 }
    592 
    593 bool PEImage::ImageAddrToOnDiskOffset(LPVOID address,
    594                                      DWORD* on_disk_offset) const {
    595  if (nullptr == address)
    596    return false;
    597 
    598  // Get the section that this address belongs to.
    599  PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address);
    600  if (nullptr == section_header)
    601    return false;
    602 
    603  // Don't follow the virtual RVAToAddr, use the one on the base.
    604  DWORD offset_within_section =
    605      static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) -
    606      static_cast<DWORD>(reinterpret_cast<uintptr_t>(
    607          PEImage::RVAToAddr(section_header->VirtualAddress)));
    608 
    609  *on_disk_offset = section_header->PointerToRawData + offset_within_section;
    610  return true;
    611 }
    612 
    613 PVOID PEImage::RVAToAddr(uintptr_t rva) const {
    614  if (rva == 0)
    615    return nullptr;
    616 
    617  return reinterpret_cast<char*>(module_) + rva;
    618 }
    619 
    620 const IMAGE_DATA_DIRECTORY* PEImage::GetDataDirectory(UINT directory) const {
    621  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
    622 
    623  // Does the image report that it includes this directory entry?
    624  if (directory >= nt_headers->OptionalHeader.NumberOfRvaAndSizes)
    625    return nullptr;
    626 
    627  // Is there space for this directory entry in the optional header?
    628  if (nt_headers->FileHeader.SizeOfOptionalHeader <
    629      (offsetof(IMAGE_OPTIONAL_HEADER, DataDirectory) +
    630       (directory + 1) * sizeof(IMAGE_DATA_DIRECTORY))) {
    631    return nullptr;
    632  }
    633 
    634  return &nt_headers->OptionalHeader.DataDirectory[directory];
    635 }
    636 
    637 PVOID PEImageAsData::RVAToAddr(uintptr_t rva) const {
    638  if (rva == 0)
    639    return nullptr;
    640 
    641  PVOID in_memory = PEImage::RVAToAddr(rva);
    642  DWORD disk_offset;
    643 
    644  if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset))
    645    return nullptr;
    646 
    647  return PEImage::RVAToAddr(disk_offset);
    648 }
    649 
    650 }  // namespace win
    651 }  // namespace base