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