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