OLD | NEW |
| (Empty) |
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 namespace base { | |
11 namespace win { | |
12 | |
13 // TODO(jschuh): crbug.com/167707 Make sure this code works on 64-bit. | |
14 | |
15 // Structure to perform imports enumerations. | |
16 struct EnumAllImportsStorage { | |
17 PEImage::EnumImportsFunction callback; | |
18 PVOID cookie; | |
19 }; | |
20 | |
21 namespace { | |
22 | |
23 // PdbInfo Signature | |
24 const DWORD kPdbInfoSignature = 'SDSR'; | |
25 | |
26 // Compare two strings byte by byte on an unsigned basis. | |
27 // if s1 == s2, return 0 | |
28 // if s1 < s2, return negative | |
29 // if s1 > s2, return positive | |
30 // Exception if inputs are invalid. | |
31 int StrCmpByByte(LPCSTR s1, LPCSTR s2) { | |
32 while (*s1 != '\0' && *s1 == *s2) { | |
33 ++s1; | |
34 ++s2; | |
35 } | |
36 | |
37 return (*reinterpret_cast<const unsigned char*>(s1) - | |
38 *reinterpret_cast<const unsigned char*>(s2)); | |
39 } | |
40 | |
41 struct PdbInfo { | |
42 DWORD Signature; | |
43 GUID Guid; | |
44 DWORD Age; | |
45 char PdbFileName[1]; | |
46 }; | |
47 } // namespace | |
48 | |
49 // Callback used to enumerate imports. See EnumImportChunksFunction. | |
50 bool ProcessImportChunk(const PEImage &image, LPCSTR module, | |
51 PIMAGE_THUNK_DATA name_table, | |
52 PIMAGE_THUNK_DATA iat, PVOID cookie) { | |
53 EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>( | |
54 cookie); | |
55 | |
56 return image.EnumOneImportChunk(storage.callback, module, name_table, iat, | |
57 storage.cookie); | |
58 } | |
59 | |
60 // Callback used to enumerate delay imports. See EnumDelayImportChunksFunction. | |
61 bool ProcessDelayImportChunk(const PEImage &image, | |
62 PImgDelayDescr delay_descriptor, | |
63 LPCSTR module, PIMAGE_THUNK_DATA name_table, | |
64 PIMAGE_THUNK_DATA iat, PIMAGE_THUNK_DATA bound_iat, | |
65 PIMAGE_THUNK_DATA unload_iat, PVOID cookie) { | |
66 EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>( | |
67 cookie); | |
68 | |
69 return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor, | |
70 module, name_table, iat, bound_iat, | |
71 unload_iat, storage.cookie); | |
72 } | |
73 | |
74 void PEImage::set_module(HMODULE module) { | |
75 module_ = module; | |
76 } | |
77 | |
78 PIMAGE_DOS_HEADER PEImage::GetDosHeader() const { | |
79 return reinterpret_cast<PIMAGE_DOS_HEADER>(module_); | |
80 } | |
81 | |
82 PIMAGE_NT_HEADERS PEImage::GetNTHeaders() const { | |
83 PIMAGE_DOS_HEADER dos_header = GetDosHeader(); | |
84 | |
85 return reinterpret_cast<PIMAGE_NT_HEADERS>( | |
86 reinterpret_cast<char*>(dos_header) + dos_header->e_lfanew); | |
87 } | |
88 | |
89 PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(UINT section) const { | |
90 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); | |
91 PIMAGE_SECTION_HEADER first_section = IMAGE_FIRST_SECTION(nt_headers); | |
92 | |
93 if (section < nt_headers->FileHeader.NumberOfSections) | |
94 return first_section + section; | |
95 else | |
96 return NULL; | |
97 } | |
98 | |
99 WORD PEImage::GetNumSections() const { | |
100 return GetNTHeaders()->FileHeader.NumberOfSections; | |
101 } | |
102 | |
103 DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const { | |
104 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); | |
105 | |
106 return nt_headers->OptionalHeader.DataDirectory[directory].Size; | |
107 } | |
108 | |
109 PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const { | |
110 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); | |
111 | |
112 return RVAToAddr( | |
113 nt_headers->OptionalHeader.DataDirectory[directory].VirtualAddress); | |
114 } | |
115 | |
116 PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const { | |
117 PBYTE target = reinterpret_cast<PBYTE>(address); | |
118 PIMAGE_SECTION_HEADER section; | |
119 | |
120 for (UINT i = 0; NULL != (section = GetSectionHeader(i)); i++) { | |
121 // Don't use the virtual RVAToAddr. | |
122 PBYTE start = reinterpret_cast<PBYTE>( | |
123 PEImage::RVAToAddr(section->VirtualAddress)); | |
124 | |
125 DWORD size = section->Misc.VirtualSize; | |
126 | |
127 if ((start <= target) && (start + size > target)) | |
128 return section; | |
129 } | |
130 | |
131 return NULL; | |
132 } | |
133 | |
134 PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName( | |
135 LPCSTR section_name) const { | |
136 if (NULL == section_name) | |
137 return NULL; | |
138 | |
139 PIMAGE_SECTION_HEADER ret = NULL; | |
140 int num_sections = GetNumSections(); | |
141 | |
142 for (int i = 0; i < num_sections; i++) { | |
143 PIMAGE_SECTION_HEADER section = GetSectionHeader(i); | |
144 if (0 == _strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name, | |
145 sizeof(section->Name))) { | |
146 ret = section; | |
147 break; | |
148 } | |
149 } | |
150 | |
151 return ret; | |
152 } | |
153 | |
154 bool PEImage::GetDebugId(LPGUID guid, LPDWORD age) const { | |
155 if (NULL == guid || NULL == age) { | |
156 return false; | |
157 } | |
158 | |
159 DWORD debug_directory_size = | |
160 GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG); | |
161 PIMAGE_DEBUG_DIRECTORY debug_directory = | |
162 reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>( | |
163 GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG)); | |
164 | |
165 size_t directory_count = | |
166 debug_directory_size / sizeof(IMAGE_DEBUG_DIRECTORY); | |
167 | |
168 for (size_t index = 0; index < directory_count; ++index) { | |
169 if (debug_directory[index].Type == IMAGE_DEBUG_TYPE_CODEVIEW) { | |
170 PdbInfo* pdb_info = reinterpret_cast<PdbInfo*>( | |
171 RVAToAddr(debug_directory[index].AddressOfRawData)); | |
172 if (pdb_info->Signature != kPdbInfoSignature) { | |
173 // Unsupported PdbInfo signature | |
174 return false; | |
175 } | |
176 *guid = pdb_info->Guid; | |
177 *age = pdb_info->Age; | |
178 return true; | |
179 } | |
180 } | |
181 return false; | |
182 } | |
183 | |
184 PDWORD PEImage::GetExportEntry(LPCSTR name) const { | |
185 PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory(); | |
186 | |
187 if (NULL == exports) | |
188 return NULL; | |
189 | |
190 WORD ordinal = 0; | |
191 if (!GetProcOrdinal(name, &ordinal)) | |
192 return NULL; | |
193 | |
194 PDWORD functions = reinterpret_cast<PDWORD>( | |
195 RVAToAddr(exports->AddressOfFunctions)); | |
196 | |
197 return functions + ordinal - exports->Base; | |
198 } | |
199 | |
200 FARPROC PEImage::GetProcAddress(LPCSTR function_name) const { | |
201 PDWORD export_entry = GetExportEntry(function_name); | |
202 if (NULL == export_entry) | |
203 return NULL; | |
204 | |
205 PBYTE function = reinterpret_cast<PBYTE>(RVAToAddr(*export_entry)); | |
206 | |
207 PBYTE exports = reinterpret_cast<PBYTE>( | |
208 GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT)); | |
209 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT); | |
210 | |
211 // Check for forwarded exports as a special case. | |
212 if (exports <= function && exports + size > function) | |
213 #pragma warning(push) | |
214 #pragma warning(disable: 4312) | |
215 // This cast generates a warning because it is 32 bit specific. | |
216 return reinterpret_cast<FARPROC>(0xFFFFFFFF); | |
217 #pragma warning(pop) | |
218 | |
219 return reinterpret_cast<FARPROC>(function); | |
220 } | |
221 | |
222 bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const { | |
223 if (NULL == ordinal) | |
224 return false; | |
225 | |
226 PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory(); | |
227 | |
228 if (NULL == exports) | |
229 return false; | |
230 | |
231 if (IsOrdinal(function_name)) { | |
232 *ordinal = ToOrdinal(function_name); | |
233 } else { | |
234 PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames)); | |
235 PDWORD lower = names; | |
236 PDWORD upper = names + exports->NumberOfNames; | |
237 int cmp = -1; | |
238 | |
239 // Binary Search for the name. | |
240 while (lower != upper) { | |
241 PDWORD middle = lower + (upper - lower) / 2; | |
242 LPCSTR name = reinterpret_cast<LPCSTR>(RVAToAddr(*middle)); | |
243 | |
244 // This may be called by sandbox before MSVCRT dll loads, so can't use | |
245 // CRT function here. | |
246 cmp = StrCmpByByte(function_name, name); | |
247 | |
248 if (cmp == 0) { | |
249 lower = middle; | |
250 break; | |
251 } | |
252 | |
253 if (cmp > 0) | |
254 lower = middle + 1; | |
255 else | |
256 upper = middle; | |
257 } | |
258 | |
259 if (cmp != 0) | |
260 return false; | |
261 | |
262 | |
263 PWORD ordinals = reinterpret_cast<PWORD>( | |
264 RVAToAddr(exports->AddressOfNameOrdinals)); | |
265 | |
266 *ordinal = ordinals[lower - names] + static_cast<WORD>(exports->Base); | |
267 } | |
268 | |
269 return true; | |
270 } | |
271 | |
272 bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const { | |
273 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); | |
274 UINT num_sections = nt_headers->FileHeader.NumberOfSections; | |
275 PIMAGE_SECTION_HEADER section = GetSectionHeader(0); | |
276 | |
277 for (UINT i = 0; i < num_sections; i++, section++) { | |
278 PVOID section_start = RVAToAddr(section->VirtualAddress); | |
279 DWORD size = section->Misc.VirtualSize; | |
280 | |
281 if (!callback(*this, section, section_start, size, cookie)) | |
282 return false; | |
283 } | |
284 | |
285 return true; | |
286 } | |
287 | |
288 bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const { | |
289 PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT); | |
290 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT); | |
291 | |
292 // Check if there are any exports at all. | |
293 if (NULL == directory || 0 == size) | |
294 return true; | |
295 | |
296 PIMAGE_EXPORT_DIRECTORY exports = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>( | |
297 directory); | |
298 UINT ordinal_base = exports->Base; | |
299 UINT num_funcs = exports->NumberOfFunctions; | |
300 UINT num_names = exports->NumberOfNames; | |
301 PDWORD functions = reinterpret_cast<PDWORD>(RVAToAddr( | |
302 exports->AddressOfFunctions)); | |
303 PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames)); | |
304 PWORD ordinals = reinterpret_cast<PWORD>(RVAToAddr( | |
305 exports->AddressOfNameOrdinals)); | |
306 | |
307 for (UINT count = 0; count < num_funcs; count++) { | |
308 PVOID func = RVAToAddr(functions[count]); | |
309 if (NULL == func) | |
310 continue; | |
311 | |
312 // Check for a name. | |
313 LPCSTR name = NULL; | |
314 UINT hint; | |
315 for (hint = 0; hint < num_names; hint++) { | |
316 if (ordinals[hint] == count) { | |
317 name = reinterpret_cast<LPCSTR>(RVAToAddr(names[hint])); | |
318 break; | |
319 } | |
320 } | |
321 | |
322 if (name == NULL) | |
323 hint = 0; | |
324 | |
325 // Check for forwarded exports. | |
326 LPCSTR forward = NULL; | |
327 if (reinterpret_cast<char*>(func) >= reinterpret_cast<char*>(directory) && | |
328 reinterpret_cast<char*>(func) <= reinterpret_cast<char*>(directory) + | |
329 size) { | |
330 forward = reinterpret_cast<LPCSTR>(func); | |
331 func = 0; | |
332 } | |
333 | |
334 if (!callback(*this, ordinal_base + count, hint, name, func, forward, | |
335 cookie)) | |
336 return false; | |
337 } | |
338 | |
339 return true; | |
340 } | |
341 | |
342 bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const { | |
343 PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC); | |
344 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC); | |
345 PIMAGE_BASE_RELOCATION base = reinterpret_cast<PIMAGE_BASE_RELOCATION>( | |
346 directory); | |
347 | |
348 if (!directory) | |
349 return true; | |
350 | |
351 while (size >= sizeof(IMAGE_BASE_RELOCATION) && base->SizeOfBlock && | |
352 size >= base->SizeOfBlock) { | |
353 PWORD reloc = reinterpret_cast<PWORD>(base + 1); | |
354 UINT num_relocs = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / | |
355 sizeof(WORD); | |
356 | |
357 for (UINT i = 0; i < num_relocs; i++, reloc++) { | |
358 WORD type = *reloc >> 12; | |
359 PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF)); | |
360 | |
361 if (!callback(*this, type, address, cookie)) | |
362 return false; | |
363 } | |
364 | |
365 size -= base->SizeOfBlock; | |
366 base = reinterpret_cast<PIMAGE_BASE_RELOCATION>( | |
367 reinterpret_cast<char*>(base) + base->SizeOfBlock); | |
368 } | |
369 | |
370 return true; | |
371 } | |
372 | |
373 bool PEImage::EnumImportChunks(EnumImportChunksFunction callback, | |
374 PVOID cookie) const { | |
375 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT); | |
376 PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk(); | |
377 | |
378 if (import == NULL || size < sizeof(IMAGE_IMPORT_DESCRIPTOR)) | |
379 return true; | |
380 | |
381 for (; import->FirstThunk; import++) { | |
382 LPCSTR module_name = reinterpret_cast<LPCSTR>(RVAToAddr(import->Name)); | |
383 PIMAGE_THUNK_DATA name_table = reinterpret_cast<PIMAGE_THUNK_DATA>( | |
384 RVAToAddr(import->OriginalFirstThunk)); | |
385 PIMAGE_THUNK_DATA iat = reinterpret_cast<PIMAGE_THUNK_DATA>( | |
386 RVAToAddr(import->FirstThunk)); | |
387 | |
388 if (!callback(*this, module_name, name_table, iat, cookie)) | |
389 return false; | |
390 } | |
391 | |
392 return true; | |
393 } | |
394 | |
395 bool PEImage::EnumOneImportChunk(EnumImportsFunction callback, | |
396 LPCSTR module_name, | |
397 PIMAGE_THUNK_DATA name_table, | |
398 PIMAGE_THUNK_DATA iat, PVOID cookie) const { | |
399 if (NULL == name_table) | |
400 return false; | |
401 | |
402 for (; name_table && name_table->u1.Ordinal; name_table++, iat++) { | |
403 LPCSTR name = NULL; | |
404 WORD ordinal = 0; | |
405 WORD hint = 0; | |
406 | |
407 if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) { | |
408 ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal)); | |
409 } else { | |
410 PIMAGE_IMPORT_BY_NAME import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>( | |
411 RVAToAddr(name_table->u1.ForwarderString)); | |
412 | |
413 hint = import->Hint; | |
414 name = reinterpret_cast<LPCSTR>(&import->Name); | |
415 } | |
416 | |
417 if (!callback(*this, module_name, ordinal, name, hint, iat, cookie)) | |
418 return false; | |
419 } | |
420 | |
421 return true; | |
422 } | |
423 | |
424 bool PEImage::EnumAllImports(EnumImportsFunction callback, PVOID cookie) const { | |
425 EnumAllImportsStorage temp = { callback, cookie }; | |
426 return EnumImportChunks(ProcessImportChunk, &temp); | |
427 } | |
428 | |
429 bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback, | |
430 PVOID cookie) const { | |
431 PVOID directory = GetImageDirectoryEntryAddr( | |
432 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); | |
433 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); | |
434 PImgDelayDescr delay_descriptor = reinterpret_cast<PImgDelayDescr>(directory); | |
435 | |
436 if (directory == NULL || size == 0) | |
437 return true; | |
438 | |
439 for (; delay_descriptor->rvaHmod; delay_descriptor++) { | |
440 PIMAGE_THUNK_DATA name_table; | |
441 PIMAGE_THUNK_DATA iat; | |
442 PIMAGE_THUNK_DATA bound_iat; // address of the optional bound IAT | |
443 PIMAGE_THUNK_DATA unload_iat; // address of optional copy of original IAT | |
444 LPCSTR module_name; | |
445 | |
446 // check if VC7-style imports, using RVAs instead of | |
447 // VC6-style addresses. | |
448 bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0; | |
449 | |
450 if (rvas) { | |
451 module_name = reinterpret_cast<LPCSTR>( | |
452 RVAToAddr(delay_descriptor->rvaDLLName)); | |
453 name_table = reinterpret_cast<PIMAGE_THUNK_DATA>( | |
454 RVAToAddr(delay_descriptor->rvaINT)); | |
455 iat = reinterpret_cast<PIMAGE_THUNK_DATA>( | |
456 RVAToAddr(delay_descriptor->rvaIAT)); | |
457 bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>( | |
458 RVAToAddr(delay_descriptor->rvaBoundIAT)); | |
459 unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>( | |
460 RVAToAddr(delay_descriptor->rvaUnloadIAT)); | |
461 } else { | |
462 #pragma warning(push) | |
463 #pragma warning(disable: 4312) | |
464 // These casts generate warnings because they are 32 bit specific. | |
465 module_name = reinterpret_cast<LPCSTR>(delay_descriptor->rvaDLLName); | |
466 name_table = reinterpret_cast<PIMAGE_THUNK_DATA>( | |
467 delay_descriptor->rvaINT); | |
468 iat = reinterpret_cast<PIMAGE_THUNK_DATA>(delay_descriptor->rvaIAT); | |
469 bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>( | |
470 delay_descriptor->rvaBoundIAT); | |
471 unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>( | |
472 delay_descriptor->rvaUnloadIAT); | |
473 #pragma warning(pop) | |
474 } | |
475 | |
476 if (!callback(*this, delay_descriptor, module_name, name_table, iat, | |
477 bound_iat, unload_iat, cookie)) | |
478 return false; | |
479 } | |
480 | |
481 return true; | |
482 } | |
483 | |
484 bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback, | |
485 PImgDelayDescr delay_descriptor, | |
486 LPCSTR module_name, | |
487 PIMAGE_THUNK_DATA name_table, | |
488 PIMAGE_THUNK_DATA iat, | |
489 PIMAGE_THUNK_DATA bound_iat, | |
490 PIMAGE_THUNK_DATA unload_iat, | |
491 PVOID cookie) const { | |
492 UNREFERENCED_PARAMETER(bound_iat); | |
493 UNREFERENCED_PARAMETER(unload_iat); | |
494 | |
495 for (; name_table->u1.Ordinal; name_table++, iat++) { | |
496 LPCSTR name = NULL; | |
497 WORD ordinal = 0; | |
498 WORD hint = 0; | |
499 | |
500 if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) { | |
501 ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal)); | |
502 } else { | |
503 PIMAGE_IMPORT_BY_NAME import; | |
504 bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0; | |
505 | |
506 if (rvas) { | |
507 import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>( | |
508 RVAToAddr(name_table->u1.ForwarderString)); | |
509 } else { | |
510 #pragma warning(push) | |
511 #pragma warning(disable: 4312) | |
512 // This cast generates a warning because it is 32 bit specific. | |
513 import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>( | |
514 name_table->u1.ForwarderString); | |
515 #pragma warning(pop) | |
516 } | |
517 | |
518 hint = import->Hint; | |
519 name = reinterpret_cast<LPCSTR>(&import->Name); | |
520 } | |
521 | |
522 if (!callback(*this, module_name, ordinal, name, hint, iat, cookie)) | |
523 return false; | |
524 } | |
525 | |
526 return true; | |
527 } | |
528 | |
529 bool PEImage::EnumAllDelayImports(EnumImportsFunction callback, | |
530 PVOID cookie) const { | |
531 EnumAllImportsStorage temp = { callback, cookie }; | |
532 return EnumDelayImportChunks(ProcessDelayImportChunk, &temp); | |
533 } | |
534 | |
535 bool PEImage::VerifyMagic() const { | |
536 PIMAGE_DOS_HEADER dos_header = GetDosHeader(); | |
537 | |
538 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) | |
539 return false; | |
540 | |
541 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(); | |
542 | |
543 if (nt_headers->Signature != IMAGE_NT_SIGNATURE) | |
544 return false; | |
545 | |
546 if (nt_headers->FileHeader.SizeOfOptionalHeader != | |
547 sizeof(IMAGE_OPTIONAL_HEADER)) | |
548 return false; | |
549 | |
550 if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) | |
551 return false; | |
552 | |
553 return true; | |
554 } | |
555 | |
556 bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const { | |
557 LPVOID address = RVAToAddr(rva); | |
558 return ImageAddrToOnDiskOffset(address, on_disk_offset); | |
559 } | |
560 | |
561 bool PEImage::ImageAddrToOnDiskOffset(LPVOID address, | |
562 DWORD *on_disk_offset) const { | |
563 if (NULL == address) | |
564 return false; | |
565 | |
566 // Get the section that this address belongs to. | |
567 PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address); | |
568 if (NULL == section_header) | |
569 return false; | |
570 | |
571 // Don't follow the virtual RVAToAddr, use the one on the base. | |
572 DWORD offset_within_section = | |
573 static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) - | |
574 static_cast<DWORD>(reinterpret_cast<uintptr_t>( | |
575 PEImage::RVAToAddr(section_header->VirtualAddress))); | |
576 | |
577 *on_disk_offset = section_header->PointerToRawData + offset_within_section; | |
578 return true; | |
579 } | |
580 | |
581 PVOID PEImage::RVAToAddr(DWORD rva) const { | |
582 if (rva == 0) | |
583 return NULL; | |
584 | |
585 return reinterpret_cast<char*>(module_) + rva; | |
586 } | |
587 | |
588 PVOID PEImageAsData::RVAToAddr(DWORD rva) const { | |
589 if (rva == 0) | |
590 return NULL; | |
591 | |
592 PVOID in_memory = PEImage::RVAToAddr(rva); | |
593 DWORD disk_offset; | |
594 | |
595 if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset)) | |
596 return NULL; | |
597 | |
598 return PEImage::RVAToAddr(disk_offset); | |
599 } | |
600 | |
601 } // namespace win | |
602 } // namespace base | |
OLD | NEW |