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

Side by Side Diff: sandbox/src/pe_image.cc

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

Powered by Google App Engine
This is Rietveld 408576698