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 <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.
StrCmpByByte(LPCSTR s1,LPCSTR s2)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.
ProcessImportChunk(const PEImage & image,LPCSTR module,PIMAGE_THUNK_DATA name_table,PIMAGE_THUNK_DATA iat,PVOID cookie)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.
ProcessDelayImportChunk(const PEImage & image,PImgDelayDescr delay_descriptor,LPCSTR module,PIMAGE_THUNK_DATA name_table,PIMAGE_THUNK_DATA iat,PVOID cookie)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
set_module(HMODULE module)87 void PEImage::set_module(HMODULE module) {
88 module_ = module;
89 }
90
GetDosHeader() const91 PIMAGE_DOS_HEADER PEImage::GetDosHeader() const {
92 return reinterpret_cast<PIMAGE_DOS_HEADER>(module_);
93 }
94
GetNTHeaders() const95 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
GetSectionHeader(UINT section) const102 PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(UINT 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
GetNumSections() const112 WORD PEImage::GetNumSections() const {
113 return GetNTHeaders()->FileHeader.NumberOfSections;
114 }
115
GetImageDirectoryEntrySize(UINT directory) const116 DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const {
117 const IMAGE_DATA_DIRECTORY* const entry = GetDataDirectory(directory);
118 return entry ? entry->Size : 0;
119 }
120
GetImageDirectoryEntryAddr(UINT directory) const121 PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const {
122 const IMAGE_DATA_DIRECTORY* const entry = GetDataDirectory(directory);
123 return entry ? RVAToAddr(entry->VirtualAddress) : nullptr;
124 }
125
GetImageSectionFromAddr(PVOID address) const126 PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const {
127 PBYTE target = reinterpret_cast<PBYTE>(address);
128 PIMAGE_SECTION_HEADER section;
129
130 for (UINT 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
GetImageSectionHeaderByName(LPCSTR section_name) const144 PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName(
145 LPCSTR section_name) const {
146 if (nullptr == section_name)
147 return nullptr;
148
149 PIMAGE_SECTION_HEADER ret = nullptr;
150 int num_sections = GetNumSections();
151
152 for (int i = 0; i < num_sections; i++) {
153 PIMAGE_SECTION_HEADER section = GetSectionHeader(i);
154 if (_strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name,
155 sizeof(section->Name)) == 0) {
156 ret = section;
157 break;
158 }
159 }
160
161 return ret;
162 }
163
GetDebugId(LPGUID guid,LPDWORD age,LPCSTR * pdb_filename,size_t * pdb_filename_length) const164 bool PEImage::GetDebugId(LPGUID guid,
165 LPDWORD age,
166 LPCSTR* pdb_filename,
167 size_t* pdb_filename_length) const {
168 DWORD debug_directory_size =
169 GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG);
170 PIMAGE_DEBUG_DIRECTORY debug_directory =
171 reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(
172 GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
173 if (!debug_directory)
174 return false;
175
176 size_t directory_count = debug_directory_size / sizeof(IMAGE_DEBUG_DIRECTORY);
177 for (size_t index = 0; index < directory_count; ++index) {
178 const IMAGE_DEBUG_DIRECTORY& entry = debug_directory[index];
179 if (entry.Type != IMAGE_DEBUG_TYPE_CODEVIEW)
180 continue; // Unsupported debugging info format.
181 if (entry.SizeOfData < sizeof(PdbInfo))
182 continue; // The data is too small to hold PDB info.
183 const PdbInfo* pdb_info =
184 reinterpret_cast<const PdbInfo*>(RVAToAddr(entry.AddressOfRawData));
185 if (!pdb_info)
186 continue; // The data is not present in a mapped section.
187 if (pdb_info->Signature != kPdbInfoSignature)
188 continue; // Unsupported PdbInfo signature
189
190 if (guid)
191 *guid = pdb_info->Guid;
192 if (age)
193 *age = pdb_info->Age;
194 if (pdb_filename) {
195 const size_t length_max =
196 entry.SizeOfData - offsetof(PdbInfo, PdbFileName);
197 const char* eos = pdb_info->PdbFileName;
198 for (const char* const end = pdb_info->PdbFileName + length_max;
199 eos < end && *eos; ++eos)
200 ;
201 *pdb_filename_length = eos - pdb_info->PdbFileName;
202 *pdb_filename = pdb_info->PdbFileName;
203 }
204 return true;
205 }
206 return false;
207 }
208
GetExportEntry(LPCSTR name) const209 PDWORD PEImage::GetExportEntry(LPCSTR name) const {
210 PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
211
212 if (nullptr == exports)
213 return nullptr;
214
215 WORD ordinal = 0;
216 if (!GetProcOrdinal(name, &ordinal))
217 return nullptr;
218
219 PDWORD functions =
220 reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfFunctions));
221
222 return functions + ordinal - exports->Base;
223 }
224
GetProcAddress(LPCSTR function_name) const225 FARPROC PEImage::GetProcAddress(LPCSTR function_name) const {
226 PDWORD export_entry = GetExportEntry(function_name);
227 if (nullptr == export_entry)
228 return nullptr;
229
230 PBYTE function = reinterpret_cast<PBYTE>(RVAToAddr(*export_entry));
231
232 PBYTE exports = reinterpret_cast<PBYTE>(
233 GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
234 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
235 if (!exports || !size)
236 return nullptr;
237
238 // Check for forwarded exports as a special case.
239 if (exports <= function && exports + size > function)
240 return reinterpret_cast<FARPROC>(-1);
241
242 return reinterpret_cast<FARPROC>(function);
243 }
244
GetProcOrdinal(LPCSTR function_name,WORD * ordinal) const245 bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD* ordinal) const {
246 if (nullptr == ordinal)
247 return false;
248
249 PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
250
251 if (nullptr == exports)
252 return false;
253
254 if (IsOrdinal(function_name)) {
255 *ordinal = ToOrdinal(function_name);
256 } else {
257 PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
258 PDWORD lower = names;
259 PDWORD upper = names + exports->NumberOfNames;
260 int cmp = -1;
261
262 // Binary Search for the name.
263 while (lower != upper) {
264 PDWORD middle = lower + (upper - lower) / 2;
265 LPCSTR name = reinterpret_cast<LPCSTR>(RVAToAddr(*middle));
266
267 // This may be called by sandbox before MSVCRT dll loads, so can't use
268 // CRT function here.
269 cmp = StrCmpByByte(function_name, name);
270
271 if (cmp == 0) {
272 lower = middle;
273 break;
274 }
275
276 if (cmp > 0)
277 lower = middle + 1;
278 else
279 upper = middle;
280 }
281
282 if (cmp != 0)
283 return false;
284
285 PWORD ordinals =
286 reinterpret_cast<PWORD>(RVAToAddr(exports->AddressOfNameOrdinals));
287
288 *ordinal = ordinals[lower - names] + static_cast<WORD>(exports->Base);
289 }
290
291 return true;
292 }
293
EnumSections(EnumSectionsFunction callback,PVOID cookie) const294 bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const {
295 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
296 UINT num_sections = nt_headers->FileHeader.NumberOfSections;
297 PIMAGE_SECTION_HEADER section = GetSectionHeader(0);
298
299 for (UINT i = 0; i < num_sections; i++, section++) {
300 PVOID section_start = RVAToAddr(section->VirtualAddress);
301 DWORD size = section->Misc.VirtualSize;
302
303 if (!callback(*this, section, section_start, size, cookie))
304 return false;
305 }
306
307 return true;
308 }
309
EnumExports(EnumExportsFunction callback,PVOID cookie) const310 bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const {
311 PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT);
312 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
313
314 // Check if there are any exports at all.
315 if (!directory || !size)
316 return true;
317
318 PIMAGE_EXPORT_DIRECTORY exports =
319 reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(directory);
320 UINT ordinal_base = exports->Base;
321 UINT num_funcs = exports->NumberOfFunctions;
322 UINT num_names = exports->NumberOfNames;
323 PDWORD functions =
324 reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfFunctions));
325 PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
326 PWORD ordinals =
327 reinterpret_cast<PWORD>(RVAToAddr(exports->AddressOfNameOrdinals));
328
329 for (UINT count = 0; count < num_funcs; count++) {
330 PVOID func = RVAToAddr(functions[count]);
331 if (nullptr == func)
332 continue;
333
334 // Check for a name.
335 LPCSTR name = nullptr;
336 UINT hint;
337 for (hint = 0; hint < num_names; hint++) {
338 if (ordinals[hint] == count) {
339 name = reinterpret_cast<LPCSTR>(RVAToAddr(names[hint]));
340 break;
341 }
342 }
343
344 if (name == nullptr)
345 hint = 0;
346
347 // Check for forwarded exports.
348 LPCSTR forward = nullptr;
349 if (reinterpret_cast<char*>(func) >= reinterpret_cast<char*>(directory) &&
350 reinterpret_cast<char*>(func) <=
351 reinterpret_cast<char*>(directory) + size) {
352 forward = reinterpret_cast<LPCSTR>(func);
353 func = nullptr;
354 }
355
356 if (!callback(*this, ordinal_base + count, hint, name, func, forward,
357 cookie))
358 return false;
359 }
360
361 return true;
362 }
363
EnumRelocs(EnumRelocsFunction callback,PVOID cookie) const364 bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const {
365 PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC);
366 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC);
367
368 if (!directory || !size)
369 return true;
370
371 PIMAGE_BASE_RELOCATION base =
372 reinterpret_cast<PIMAGE_BASE_RELOCATION>(directory);
373 while (size >= sizeof(IMAGE_BASE_RELOCATION) && base->SizeOfBlock &&
374 size >= base->SizeOfBlock) {
375 PWORD reloc = reinterpret_cast<PWORD>(base + 1);
376 UINT num_relocs =
377 (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
378
379 for (UINT i = 0; i < num_relocs; i++, reloc++) {
380 WORD type = *reloc >> 12;
381 PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF));
382
383 if (!callback(*this, type, address, cookie))
384 return false;
385 }
386
387 size -= base->SizeOfBlock;
388 base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
389 reinterpret_cast<char*>(base) + base->SizeOfBlock);
390 }
391
392 return true;
393 }
394
EnumImportChunks(EnumImportChunksFunction callback,PVOID cookie,LPCSTR target_module_name) const395 bool PEImage::EnumImportChunks(EnumImportChunksFunction callback,
396 PVOID cookie,
397 LPCSTR target_module_name) const {
398 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT);
399 PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk();
400
401 if (import == nullptr || size < sizeof(IMAGE_IMPORT_DESCRIPTOR))
402 return true;
403
404 for (; import->FirstThunk; import++) {
405 LPCSTR module_name = reinterpret_cast<LPCSTR>(RVAToAddr(import->Name));
406 PIMAGE_THUNK_DATA name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
407 RVAToAddr(import->OriginalFirstThunk));
408 PIMAGE_THUNK_DATA iat =
409 reinterpret_cast<PIMAGE_THUNK_DATA>(RVAToAddr(import->FirstThunk));
410
411 if (target_module_name == nullptr ||
412 (lstrcmpiA(module_name, target_module_name) == 0)) {
413 if (!callback(*this, module_name, name_table, iat, cookie))
414 return false;
415 }
416 }
417
418 return true;
419 }
420
EnumOneImportChunk(EnumImportsFunction callback,LPCSTR module_name,PIMAGE_THUNK_DATA name_table,PIMAGE_THUNK_DATA iat,PVOID cookie) const421 bool PEImage::EnumOneImportChunk(EnumImportsFunction callback,
422 LPCSTR module_name,
423 PIMAGE_THUNK_DATA name_table,
424 PIMAGE_THUNK_DATA iat,
425 PVOID cookie) const {
426 if (nullptr == name_table)
427 return false;
428
429 for (; name_table && name_table->u1.Ordinal; name_table++, iat++) {
430 LPCSTR name = nullptr;
431 WORD ordinal = 0;
432 WORD hint = 0;
433
434 if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
435 ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
436 } else {
437 PIMAGE_IMPORT_BY_NAME import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
438 RVAToAddr(name_table->u1.ForwarderString));
439
440 hint = import->Hint;
441 name = reinterpret_cast<LPCSTR>(&import->Name);
442 }
443
444 if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
445 return false;
446 }
447
448 return true;
449 }
450
EnumAllImports(EnumImportsFunction callback,PVOID cookie,LPCSTR target_module_name) const451 bool PEImage::EnumAllImports(EnumImportsFunction callback,
452 PVOID cookie,
453 LPCSTR target_module_name) const {
454 EnumAllImportsStorage temp = {callback, cookie};
455 return EnumImportChunks(ProcessImportChunk, &temp, target_module_name);
456 }
457
EnumDelayImportChunks(EnumDelayImportChunksFunction callback,PVOID cookie,LPCSTR target_module_name) const458 bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
459 PVOID cookie,
460 LPCSTR target_module_name) const {
461 PVOID directory =
462 GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
463 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
464
465 if (!directory || !size)
466 return true;
467
468 PImgDelayDescr delay_descriptor = reinterpret_cast<PImgDelayDescr>(directory);
469 for (; delay_descriptor->rvaHmod; delay_descriptor++) {
470 PIMAGE_THUNK_DATA name_table;
471 PIMAGE_THUNK_DATA iat;
472 LPCSTR module_name;
473
474 // check if VC7-style imports, using RVAs instead of
475 // VC6-style addresses.
476 bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
477
478 if (rvas) {
479 module_name =
480 reinterpret_cast<LPCSTR>(RVAToAddr(delay_descriptor->rvaDLLName));
481 name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
482 RVAToAddr(delay_descriptor->rvaINT));
483 iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
484 RVAToAddr(delay_descriptor->rvaIAT));
485 } else {
486 // Values in IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT are 32-bit, even on 64-bit
487 // platforms. See section 4.8 of PECOFF image spec rev 8.3.
488 module_name = reinterpret_cast<LPCSTR>(
489 static_cast<uintptr_t>(delay_descriptor->rvaDLLName));
490 name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
491 static_cast<uintptr_t>(delay_descriptor->rvaINT));
492 iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
493 static_cast<uintptr_t>(delay_descriptor->rvaIAT));
494 }
495
496 if (target_module_name == nullptr ||
497 (lstrcmpiA(module_name, target_module_name) == 0)) {
498 if (target_module_name) {
499 // Ensure all imports are properly loaded for the target module so that
500 // the callback is operating on a fully-realized set of imports.
501 // This call only loads the imports for the module where this code is
502 // executing, so it is only helpful or meaningful to do this if the
503 // current module is the module whose IAT we are enumerating.
504 // Use the module_name as retrieved from the IAT because this method
505 // is case sensitive.
506 if (module_ == CURRENT_MODULE() && !LDR_IS_RESOURCE(module_)) {
507 static base::NoDestructor<std::set<std::string>> loaded_dlls;
508 // pair.second is true if this is a new element
509 if (loaded_dlls.get()->emplace(module_name).second)
510 ::__HrLoadAllImportsForDll(module_name);
511 }
512 }
513
514 if (!callback(*this, delay_descriptor, module_name, name_table, iat,
515 cookie))
516 return false;
517 }
518 }
519
520 return true;
521 }
522
EnumOneDelayImportChunk(EnumImportsFunction callback,PImgDelayDescr delay_descriptor,LPCSTR module_name,PIMAGE_THUNK_DATA name_table,PIMAGE_THUNK_DATA iat,PVOID cookie) const523 bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback,
524 PImgDelayDescr delay_descriptor,
525 LPCSTR module_name,
526 PIMAGE_THUNK_DATA name_table,
527 PIMAGE_THUNK_DATA iat,
528 PVOID cookie) const {
529 for (; name_table->u1.Ordinal; name_table++, iat++) {
530 LPCSTR name = nullptr;
531 WORD ordinal = 0;
532 WORD hint = 0;
533
534 if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
535 ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
536 } else {
537 PIMAGE_IMPORT_BY_NAME import;
538 bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
539
540 if (rvas) {
541 import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
542 RVAToAddr(name_table->u1.ForwarderString));
543 } else {
544 import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
545 name_table->u1.ForwarderString);
546 }
547
548 hint = import->Hint;
549 name = reinterpret_cast<LPCSTR>(&import->Name);
550 }
551
552 if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
553 return false;
554 }
555
556 return true;
557 }
558
EnumAllDelayImports(EnumImportsFunction callback,PVOID cookie,LPCSTR target_module_name) const559 bool PEImage::EnumAllDelayImports(EnumImportsFunction callback,
560 PVOID cookie,
561 LPCSTR target_module_name) const {
562 EnumAllImportsStorage temp = {callback, cookie};
563 return EnumDelayImportChunks(ProcessDelayImportChunk, &temp,
564 target_module_name);
565 }
566
VerifyMagic() const567 bool PEImage::VerifyMagic() const {
568 PIMAGE_DOS_HEADER dos_header = GetDosHeader();
569
570 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
571 return false;
572
573 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
574
575 if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
576 return false;
577
578 if (nt_headers->FileHeader.SizeOfOptionalHeader !=
579 sizeof(IMAGE_OPTIONAL_HEADER))
580 return false;
581
582 if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
583 return false;
584
585 return true;
586 }
587
ImageRVAToOnDiskOffset(uintptr_t rva,DWORD * on_disk_offset) const588 bool PEImage::ImageRVAToOnDiskOffset(uintptr_t rva,
589 DWORD* on_disk_offset) const {
590 LPVOID address = RVAToAddr(rva);
591 return ImageAddrToOnDiskOffset(address, on_disk_offset);
592 }
593
ImageAddrToOnDiskOffset(LPVOID address,DWORD * on_disk_offset) const594 bool PEImage::ImageAddrToOnDiskOffset(LPVOID address,
595 DWORD* on_disk_offset) const {
596 if (nullptr == address)
597 return false;
598
599 // Get the section that this address belongs to.
600 PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address);
601 if (nullptr == section_header)
602 return false;
603
604 // Don't follow the virtual RVAToAddr, use the one on the base.
605 DWORD offset_within_section =
606 static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) -
607 static_cast<DWORD>(reinterpret_cast<uintptr_t>(
608 PEImage::RVAToAddr(section_header->VirtualAddress)));
609
610 *on_disk_offset = section_header->PointerToRawData + offset_within_section;
611 return true;
612 }
613
RVAToAddr(uintptr_t rva) const614 PVOID PEImage::RVAToAddr(uintptr_t rva) const {
615 if (rva == 0)
616 return nullptr;
617
618 return reinterpret_cast<char*>(module_) + rva;
619 }
620
GetDataDirectory(UINT directory) const621 const IMAGE_DATA_DIRECTORY* PEImage::GetDataDirectory(UINT directory) const {
622 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
623
624 // Does the image report that it includes this directory entry?
625 if (directory >= nt_headers->OptionalHeader.NumberOfRvaAndSizes)
626 return nullptr;
627
628 // Is there space for this directory entry in the optional header?
629 if (nt_headers->FileHeader.SizeOfOptionalHeader <
630 (offsetof(IMAGE_OPTIONAL_HEADER, DataDirectory) +
631 (directory + 1) * sizeof(IMAGE_DATA_DIRECTORY))) {
632 return nullptr;
633 }
634
635 return &nt_headers->OptionalHeader.DataDirectory[directory];
636 }
637
RVAToAddr(uintptr_t rva) const638 PVOID PEImageAsData::RVAToAddr(uintptr_t rva) const {
639 if (rva == 0)
640 return nullptr;
641
642 PVOID in_memory = PEImage::RVAToAddr(rva);
643 DWORD disk_offset;
644
645 if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset))
646 return nullptr;
647
648 return PEImage::RVAToAddr(disk_offset);
649 }
650
651 } // namespace win
652 } // namespace base
653