Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(678)

Side by Side Diff: base/pe_image.cc

Issue 3836005: Move pe_image and registry from base to base/win and use the namespace. It re... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/pe_image.h ('k') | base/pe_image_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 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/pe_image.h"
9
10 #if defined(_WIN64) && !defined(NACL_WIN64)
11 // TODO(rvargas): Bug 27218. Make sure this is ok.
12 #error This code is not tested on x64. Please make sure all the base unit tests\
13 pass before doing any real work. The current unit tests don't test the\
14 differences between 32- and 64-bits implementations. Bugs may slip through.\
15 You need to improve the coverage before continuing.
16 #endif
17
18 // Structure to perform imports enumerations.
19 struct EnumAllImportsStorage {
20 PEImage::EnumImportsFunction callback;
21 PVOID cookie;
22 };
23
24 namespace {
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 } // namespace
42
43 // Callback used to enumerate imports. See EnumImportChunksFunction.
44 bool ProcessImportChunk(const PEImage &image, LPCSTR module,
45 PIMAGE_THUNK_DATA name_table,
46 PIMAGE_THUNK_DATA iat, PVOID cookie) {
47 EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
48 cookie);
49
50 return image.EnumOneImportChunk(storage.callback, module, name_table, iat,
51 storage.cookie);
52 }
53
54 // Callback used to enumerate delay imports. See EnumDelayImportChunksFunction.
55 bool ProcessDelayImportChunk(const PEImage &image,
56 PImgDelayDescr delay_descriptor,
57 LPCSTR module, PIMAGE_THUNK_DATA name_table,
58 PIMAGE_THUNK_DATA iat, PIMAGE_THUNK_DATA bound_iat,
59 PIMAGE_THUNK_DATA unload_iat, PVOID cookie) {
60 EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
61 cookie);
62
63 return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor,
64 module, name_table, iat, bound_iat,
65 unload_iat, storage.cookie);
66 }
67
68 void PEImage::set_module(HMODULE module) {
69 module_ = module;
70 }
71
72 PIMAGE_DOS_HEADER PEImage::GetDosHeader() const {
73 return reinterpret_cast<PIMAGE_DOS_HEADER>(module_);
74 }
75
76 PIMAGE_NT_HEADERS PEImage::GetNTHeaders() const {
77 PIMAGE_DOS_HEADER dos_header = GetDosHeader();
78
79 return reinterpret_cast<PIMAGE_NT_HEADERS>(
80 reinterpret_cast<char*>(dos_header) + dos_header->e_lfanew);
81 }
82
83 PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(UINT section) const {
84 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
85 PIMAGE_SECTION_HEADER first_section = IMAGE_FIRST_SECTION(nt_headers);
86
87 if (section < nt_headers->FileHeader.NumberOfSections)
88 return first_section + section;
89 else
90 return NULL;
91 }
92
93 WORD PEImage::GetNumSections() const {
94 return GetNTHeaders()->FileHeader.NumberOfSections;
95 }
96
97 DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const {
98 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
99
100 return nt_headers->OptionalHeader.DataDirectory[directory].Size;
101 }
102
103 PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const {
104 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
105
106 return RVAToAddr(
107 nt_headers->OptionalHeader.DataDirectory[directory].VirtualAddress);
108 }
109
110 PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const {
111 PBYTE target = reinterpret_cast<PBYTE>(address);
112 PIMAGE_SECTION_HEADER section;
113
114 for (UINT i = 0; NULL != (section = GetSectionHeader(i)); i++) {
115 // Don't use the virtual RVAToAddr.
116 PBYTE start = reinterpret_cast<PBYTE>(
117 PEImage::RVAToAddr(section->VirtualAddress));
118
119 DWORD size = section->Misc.VirtualSize;
120
121 if ((start <= target) && (start + size > target))
122 return section;
123 }
124
125 return NULL;
126 }
127
128 PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName(
129 LPCSTR section_name) const {
130 if (NULL == section_name)
131 return NULL;
132
133 PIMAGE_SECTION_HEADER ret = NULL;
134 int num_sections = GetNumSections();
135
136 for (int i = 0; i < num_sections; i++) {
137 PIMAGE_SECTION_HEADER section = GetSectionHeader(i);
138 if (0 == _strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name,
139 sizeof(section->Name))) {
140 ret = section;
141 break;
142 }
143 }
144
145 return ret;
146 }
147
148 PDWORD PEImage::GetExportEntry(LPCSTR name) const {
149 PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
150
151 if (NULL == exports)
152 return NULL;
153
154 WORD ordinal = 0;
155 if (!GetProcOrdinal(name, &ordinal))
156 return NULL;
157
158 PDWORD functions = reinterpret_cast<PDWORD>(
159 RVAToAddr(exports->AddressOfFunctions));
160
161 return functions + ordinal - exports->Base;
162 }
163
164 FARPROC PEImage::GetProcAddress(LPCSTR function_name) const {
165 PDWORD export_entry = GetExportEntry(function_name);
166 if (NULL == export_entry)
167 return NULL;
168
169 PBYTE function = reinterpret_cast<PBYTE>(RVAToAddr(*export_entry));
170
171 PBYTE exports = reinterpret_cast<PBYTE>(
172 GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
173 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
174
175 // Check for forwarded exports as a special case.
176 if (exports <= function && exports + size > function)
177 #pragma warning(push)
178 #pragma warning(disable: 4312)
179 // This cast generates a warning because it is 32 bit specific.
180 return reinterpret_cast<FARPROC>(0xFFFFFFFF);
181 #pragma warning(pop)
182
183 return reinterpret_cast<FARPROC>(function);
184 }
185
186 bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const {
187 if (NULL == ordinal)
188 return false;
189
190 PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
191
192 if (NULL == exports)
193 return false;
194
195 if (IsOrdinal(function_name)) {
196 *ordinal = ToOrdinal(function_name);
197 } else {
198 PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
199 PDWORD lower = names;
200 PDWORD upper = names + exports->NumberOfNames;
201 int cmp = -1;
202
203 // Binary Search for the name.
204 while (lower != upper) {
205 PDWORD middle = lower + (upper - lower) / 2;
206 LPCSTR name = reinterpret_cast<LPCSTR>(RVAToAddr(*middle));
207
208 // This may be called by sandbox before MSVCRT dll loads, so can't use
209 // CRT function here.
210 cmp = StrCmpByByte(function_name, name);
211
212 if (cmp == 0) {
213 lower = middle;
214 break;
215 }
216
217 if (cmp > 0)
218 lower = middle + 1;
219 else
220 upper = middle;
221 }
222
223 if (cmp != 0)
224 return false;
225
226
227 PWORD ordinals = reinterpret_cast<PWORD>(
228 RVAToAddr(exports->AddressOfNameOrdinals));
229
230 *ordinal = ordinals[lower - names] + static_cast<WORD>(exports->Base);
231 }
232
233 return true;
234 }
235
236 bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const {
237 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
238 UINT num_sections = nt_headers->FileHeader.NumberOfSections;
239 PIMAGE_SECTION_HEADER section = GetSectionHeader(0);
240
241 for (UINT i = 0; i < num_sections; i++, section++) {
242 PVOID section_start = RVAToAddr(section->VirtualAddress);
243 DWORD size = section->Misc.VirtualSize;
244
245 if (!callback(*this, section, section_start, size, cookie))
246 return false;
247 }
248
249 return true;
250 }
251
252 bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const {
253 PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT);
254 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
255
256 // Check if there are any exports at all.
257 if (NULL == directory || 0 == size)
258 return true;
259
260 PIMAGE_EXPORT_DIRECTORY exports = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
261 directory);
262 UINT ordinal_base = exports->Base;
263 UINT num_funcs = exports->NumberOfFunctions;
264 UINT num_names = exports->NumberOfNames;
265 PDWORD functions = reinterpret_cast<PDWORD>(RVAToAddr(
266 exports->AddressOfFunctions));
267 PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
268 PWORD ordinals = reinterpret_cast<PWORD>(RVAToAddr(
269 exports->AddressOfNameOrdinals));
270
271 for (UINT count = 0; count < num_funcs; count++) {
272 PVOID func = RVAToAddr(functions[count]);
273 if (NULL == func)
274 continue;
275
276 // Check for a name.
277 LPCSTR name = NULL;
278 UINT hint;
279 for (hint = 0; hint < num_names; hint++) {
280 if (ordinals[hint] == count) {
281 name = reinterpret_cast<LPCSTR>(RVAToAddr(names[hint]));
282 break;
283 }
284 }
285
286 if (name == NULL)
287 hint = 0;
288
289 // Check for forwarded exports.
290 LPCSTR forward = NULL;
291 if (reinterpret_cast<char*>(func) >= reinterpret_cast<char*>(directory) &&
292 reinterpret_cast<char*>(func) <= reinterpret_cast<char*>(directory) +
293 size) {
294 forward = reinterpret_cast<LPCSTR>(func);
295 func = 0;
296 }
297
298 if (!callback(*this, ordinal_base + count, hint, name, func, forward,
299 cookie))
300 return false;
301 }
302
303 return true;
304 }
305
306 bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const {
307 PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC);
308 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC);
309 PIMAGE_BASE_RELOCATION base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
310 directory);
311
312 if (directory == NULL || size < sizeof(IMAGE_BASE_RELOCATION))
313 return true;
314
315 while (base->SizeOfBlock) {
316 PWORD reloc = reinterpret_cast<PWORD>(base + 1);
317 UINT num_relocs = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
318 sizeof(WORD);
319
320 for (UINT i = 0; i < num_relocs; i++, reloc++) {
321 WORD type = *reloc >> 12;
322 PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF));
323
324 if (!callback(*this, type, address, cookie))
325 return false;
326 }
327
328 base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
329 reinterpret_cast<char*>(base) + base->SizeOfBlock);
330 }
331
332 return true;
333 }
334
335 bool PEImage::EnumImportChunks(EnumImportChunksFunction callback,
336 PVOID cookie) const {
337 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT);
338 PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk();
339
340 if (import == NULL || size < sizeof(IMAGE_IMPORT_DESCRIPTOR))
341 return true;
342
343 for (; import->FirstThunk; import++) {
344 LPCSTR module_name = reinterpret_cast<LPCSTR>(RVAToAddr(import->Name));
345 PIMAGE_THUNK_DATA name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
346 RVAToAddr(import->OriginalFirstThunk));
347 PIMAGE_THUNK_DATA iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
348 RVAToAddr(import->FirstThunk));
349
350 if (!callback(*this, module_name, name_table, iat, cookie))
351 return false;
352 }
353
354 return true;
355 }
356
357 bool PEImage::EnumOneImportChunk(EnumImportsFunction callback,
358 LPCSTR module_name,
359 PIMAGE_THUNK_DATA name_table,
360 PIMAGE_THUNK_DATA iat, PVOID cookie) const {
361 if (NULL == name_table)
362 return false;
363
364 for (; name_table && name_table->u1.Ordinal; name_table++, iat++) {
365 LPCSTR name = NULL;
366 WORD ordinal = 0;
367 WORD hint = 0;
368
369 if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
370 ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
371 } else {
372 PIMAGE_IMPORT_BY_NAME import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
373 RVAToAddr(name_table->u1.ForwarderString));
374
375 hint = import->Hint;
376 name = reinterpret_cast<LPCSTR>(&import->Name);
377 }
378
379 if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
380 return false;
381 }
382
383 return true;
384 }
385
386 bool PEImage::EnumAllImports(EnumImportsFunction callback, PVOID cookie) const {
387 EnumAllImportsStorage temp = { callback, cookie };
388 return EnumImportChunks(ProcessImportChunk, &temp);
389 }
390
391 bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
392 PVOID cookie) const {
393 PVOID directory = GetImageDirectoryEntryAddr(
394 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
395 DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
396 PImgDelayDescr delay_descriptor = reinterpret_cast<PImgDelayDescr>(directory);
397
398 if (directory == NULL || size == 0)
399 return true;
400
401 for (; delay_descriptor->rvaHmod; delay_descriptor++) {
402 PIMAGE_THUNK_DATA name_table;
403 PIMAGE_THUNK_DATA iat;
404 PIMAGE_THUNK_DATA bound_iat; // address of the optional bound IAT
405 PIMAGE_THUNK_DATA unload_iat; // address of optional copy of original IAT
406 LPCSTR module_name;
407
408 // check if VC7-style imports, using RVAs instead of
409 // VC6-style addresses.
410 bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
411
412 if (rvas) {
413 module_name = reinterpret_cast<LPCSTR>(
414 RVAToAddr(delay_descriptor->rvaDLLName));
415 name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
416 RVAToAddr(delay_descriptor->rvaINT));
417 iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
418 RVAToAddr(delay_descriptor->rvaIAT));
419 bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
420 RVAToAddr(delay_descriptor->rvaBoundIAT));
421 unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
422 RVAToAddr(delay_descriptor->rvaUnloadIAT));
423 } else {
424 #pragma warning(push)
425 #pragma warning(disable: 4312)
426 // These casts generate warnings because they are 32 bit specific.
427 module_name = reinterpret_cast<LPCSTR>(delay_descriptor->rvaDLLName);
428 name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
429 delay_descriptor->rvaINT);
430 iat = reinterpret_cast<PIMAGE_THUNK_DATA>(delay_descriptor->rvaIAT);
431 bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
432 delay_descriptor->rvaBoundIAT);
433 unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
434 delay_descriptor->rvaUnloadIAT);
435 #pragma warning(pop)
436 }
437
438 if (!callback(*this, delay_descriptor, module_name, name_table, iat,
439 bound_iat, unload_iat, cookie))
440 return false;
441 }
442
443 return true;
444 }
445
446 bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback,
447 PImgDelayDescr delay_descriptor,
448 LPCSTR module_name,
449 PIMAGE_THUNK_DATA name_table,
450 PIMAGE_THUNK_DATA iat,
451 PIMAGE_THUNK_DATA bound_iat,
452 PIMAGE_THUNK_DATA unload_iat,
453 PVOID cookie) const {
454 UNREFERENCED_PARAMETER(bound_iat);
455 UNREFERENCED_PARAMETER(unload_iat);
456
457 for (; name_table->u1.Ordinal; name_table++, iat++) {
458 LPCSTR name = NULL;
459 WORD ordinal = 0;
460 WORD hint = 0;
461
462 if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
463 ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
464 } else {
465 PIMAGE_IMPORT_BY_NAME import;
466 bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
467
468 if (rvas) {
469 import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
470 RVAToAddr(name_table->u1.ForwarderString));
471 } else {
472 #pragma warning(push)
473 #pragma warning(disable: 4312)
474 // This cast generates a warning because it is 32 bit specific.
475 import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
476 name_table->u1.ForwarderString);
477 #pragma warning(pop)
478 }
479
480 hint = import->Hint;
481 name = reinterpret_cast<LPCSTR>(&import->Name);
482 }
483
484 if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
485 return false;
486 }
487
488 return true;
489 }
490
491 bool PEImage::EnumAllDelayImports(EnumImportsFunction callback,
492 PVOID cookie) const {
493 EnumAllImportsStorage temp = { callback, cookie };
494 return EnumDelayImportChunks(ProcessDelayImportChunk, &temp);
495 }
496
497 bool PEImage::VerifyMagic() const {
498 PIMAGE_DOS_HEADER dos_header = GetDosHeader();
499
500 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
501 return false;
502
503 PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
504
505 if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
506 return false;
507
508 if (nt_headers->FileHeader.SizeOfOptionalHeader !=
509 sizeof(IMAGE_OPTIONAL_HEADER))
510 return false;
511
512 if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
513 return false;
514
515 return true;
516 }
517
518 bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const {
519 LPVOID address = RVAToAddr(rva);
520 return ImageAddrToOnDiskOffset(address, on_disk_offset);
521 }
522
523 bool PEImage::ImageAddrToOnDiskOffset(LPVOID address,
524 DWORD *on_disk_offset) const {
525 if (NULL == address)
526 return false;
527
528 // Get the section that this address belongs to.
529 PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address);
530 if (NULL == section_header)
531 return false;
532
533 #pragma warning(push)
534 #pragma warning(disable: 4311)
535 // These casts generate warnings because they are 32 bit specific.
536 // Don't follow the virtual RVAToAddr, use the one on the base.
537 DWORD offset_within_section = reinterpret_cast<DWORD>(address) -
538 reinterpret_cast<DWORD>(PEImage::RVAToAddr(
539 section_header->VirtualAddress));
540 #pragma warning(pop)
541
542 *on_disk_offset = section_header->PointerToRawData + offset_within_section;
543 return true;
544 }
545
546 PVOID PEImage::RVAToAddr(DWORD rva) const {
547 if (rva == 0)
548 return NULL;
549
550 return reinterpret_cast<char*>(module_) + rva;
551 }
552
553 PVOID PEImageAsData::RVAToAddr(DWORD rva) const {
554 if (rva == 0)
555 return NULL;
556
557 PVOID in_memory = PEImage::RVAToAddr(rva);
558 DWORD dummy;
559
560 if (!ImageAddrToOnDiskOffset(in_memory, &dummy))
561 return NULL;
562
563 return in_memory;
564 }
OLDNEW
« no previous file with comments | « base/pe_image.h ('k') | base/pe_image_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698