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