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