1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 """References:
26 http://msdn.microsoft.com/en-us/magazine/ms809762.aspx
27 http://msdn.microsoft.com/en-us/magazine/cc301805.aspx
28 http://code.google.com/p/corkami/downloads/detail?name=pe-20110117.pdf
29 http://code.google.com/p/pefile/
30
31 Version information:
32 http://msdn.microsoft.com/en-us/library/windows/desktop/ff468916(v=vs.85).aspx
33 """
34 import copy
35 import re
36
37 from rekall import addrspace
38 from rekall import obj
39
40 from rekall.plugins.addrspaces import standard
41 from rekall.plugins.overlays import basic
42 from rekall_lib import utils
46 """A sential terminated array."""
47
48 - def __init__(self, max_count=100000, **kwargs):
52
61
64 """A variable sized array with a sentinel termination."""
65
68 """A pointer through a relative virtual address."""
69 image_base = 0
70 - def __init__(self, image_base=None, **kwargs):
80
81 - def v(self, vm=None):
82 rva_pointer = super(RVAPointer, self).v()
83 if rva_pointer:
84 rva_pointer += self.image_base
85
86 return rva_pointer
87
90 """A pointer relative to our resource section."""
91 resource_base = 0
92
93 - def __init__(self, resource_base=None, **kwargs):
110
111 - def v(self, vm=None):
112
113 resource_pointer = int(
114 super(ResourcePointer, self).v()) & ((1 << 31) - 1)
115 if resource_pointer:
116 resource_pointer += self.resource_base
117
118 return resource_pointer
119
127
130 """Align a Struct's member after another member.
131
132 Produce a callable which returns the next aligned offset after the member of
133 the required name in this struct. This callable is suitable to be specified
134 in the overlay's offset field.
135 """
136 def get_offset(x):
137 x = getattr(x, name)
138 end_of_object = x.obj_offset + x.obj_size
139
140 return RoundUpToWordAlignment(end_of_object)
141
142 return get_offset
143
144
145 pe_overlays = {
146 "_IMAGE_OPTIONAL_HEADER": [None, {
147 'Subsystem' : [None, ['Enumeration', {
148 'choices': {
149 0: 'IMAGE_SUBSYSTEM_UNKNOWN',
150 1: 'IMAGE_SUBSYSTEM_NATIVE',
151 2: 'IMAGE_SUBSYSTEM_WINDOWS_GUI',
152 3: 'IMAGE_SUBSYSTEM_WINDOWS_CUI',
153 5: 'IMAGE_SUBSYSTEM_OS2_CUI',
154 7: 'IMAGE_SUBSYSTEM_POSIX_CUI',
155 9: 'IMAGE_SUBSYSTEM_WINDOWS_CE_GUI',
156 10:'IMAGE_SUBSYSTEM_EFI_APPLICATION',
157 11:'IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER',
158 12:'IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER',
159 13:'IMAGE_SUBSYSTEM_EFI_ROM',
160 14:'IMAGE_SUBSYSTEM_XBOX'},
161 'target': 'unsigned short'}]],
162
163 'DataDirectory' : [None, ['IndexedArray', {
164 'count': 16,
165 'index_table': {
166 'IMAGE_DIRECTORY_ENTRY_EXPORT': 0,
167 'IMAGE_DIRECTORY_ENTRY_IMPORT': 1,
168 'IMAGE_DIRECTORY_ENTRY_RESOURCE': 2,
169 'IMAGE_DIRECTORY_ENTRY_EXCEPTION': 3,
170 'IMAGE_DIRECTORY_ENTRY_SECURITY': 4,
171 'IMAGE_DIRECTORY_ENTRY_BASERELOC': 5,
172 'IMAGE_DIRECTORY_ENTRY_DEBUG': 6,
173 'IMAGE_DIRECTORY_ENTRY_COPYRIGHT': 7,
174 'IMAGE_DIRECTORY_ENTRY_GLOBALPTR': 8,
175 'IMAGE_DIRECTORY_ENTRY_TLS': 9,
176 'IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG': 10,
177 'IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT': 11,
178 'IMAGE_DIRECTORY_ENTRY_IAT': 12,
179 'IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT': 13,
180 'IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR':14,
181 'IMAGE_DIRECTORY_ENTRY_RESERVED': 15,
182 },
183 'target': '_IMAGE_DATA_DIRECTORY'}]],
184 }],
185 "_IMAGE_FILE_HEADER": [None, {
186 'Machine' : [None, ['Enumeration', {
187 'choices': {
188 0x0000: 'IMAGE_FILE_MACHINE_UNKNOWN',
189 0x01d3: 'IMAGE_FILE_MACHINE_AM33',
190 0x8664: 'IMAGE_FILE_MACHINE_AMD64',
191 0x01c0: 'IMAGE_FILE_MACHINE_ARM',
192 0x0ebc: 'IMAGE_FILE_MACHINE_EBC',
193 0x014c: 'IMAGE_FILE_MACHINE_I386',
194 0x0200: 'IMAGE_FILE_MACHINE_IA64',
195 0x9041: 'IMAGE_FILE_MACHINE_MR32',
196 0x0266: 'IMAGE_FILE_MACHINE_MIPS16',
197 0x0366: 'IMAGE_FILE_MACHINE_MIPSFPU',
198 0x0466: 'IMAGE_FILE_MACHINE_MIPSFPU16',
199 0x01f0: 'IMAGE_FILE_MACHINE_POWERPC',
200 0x01f1: 'IMAGE_FILE_MACHINE_POWERPCFP',
201 0x0166: 'IMAGE_FILE_MACHINE_R4000',
202 0x01a2: 'IMAGE_FILE_MACHINE_SH3',
203 0x01a3: 'IMAGE_FILE_MACHINE_SH3DSP',
204 0x01a6: 'IMAGE_FILE_MACHINE_SH4',
205 0x01a8: 'IMAGE_FILE_MACHINE_SH5',
206 0x01c2: 'IMAGE_FILE_MACHINE_THUMB',
207 0x0169: 'IMAGE_FILE_MACHINE_WCEMIPSV2'},
208 'target': 'unsigned short'
209 }]],
210
211 'Characteristics' : [None, ['Flags', {
212 'maskmap': {
213 'IMAGE_FILE_RELOCS_STRIPPED': 0x0001,
214 'IMAGE_FILE_EXECUTABLE_IMAGE': 0x0002,
215 'IMAGE_FILE_LINE_NUMS_STRIPPED': 0x0004,
216 'IMAGE_FILE_LOCAL_SYMS_STRIPPED': 0x0008,
217 'IMAGE_FILE_AGGRESIVE_WS_TRIM': 0x0010,
218 'IMAGE_FILE_LARGE_ADDRESS_AWARE': 0x0020,
219 'IMAGE_FILE_16BIT_MACHINE': 0x0040,
220 'IMAGE_FILE_BYTES_REVERSED_LO': 0x0080,
221 'IMAGE_FILE_32BIT_MACHINE': 0x0100,
222 'IMAGE_FILE_DEBUG_STRIPPED': 0x0200,
223 'IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP': 0x0400,
224 'IMAGE_FILE_NET_RUN_FROM_SWAP': 0x0800,
225 'IMAGE_FILE_SYSTEM': 0x1000,
226 'IMAGE_FILE_DLL': 0x2000,
227 'IMAGE_FILE_UP_SYSTEM_ONLY': 0x4000,
228 'IMAGE_FILE_BYTES_REVERSED_HI': 0x8000,
229 },
230 'target': 'unsigned short'}]],
231 'TimeDateStamp' : [None, ['UnixTimeStamp', {}]],
232 }],
233
234 "_IMAGE_SECTION_HEADER": [None, {
235 'Name' : [None, ['String', {'length': 8, 'term': None}]],
236 'Characteristics' : [None, ['Flags', {
237 'maskmap': {
238 'IMAGE_SCN_CNT_CODE': 0x00000020,
239 'IMAGE_SCN_CNT_INITIALIZED_DATA': 0x00000040,
240 'IMAGE_SCN_CNT_UNINITIALIZED_DATA': 0x00000080,
241 'IMAGE_SCN_LNK_OTHER': 0x00000100,
242 'IMAGE_SCN_LNK_INFO': 0x00000200,
243 'IMAGE_SCN_LNK_REMOVE': 0x00000800,
244 'IMAGE_SCN_LNK_COMDAT': 0x00001000,
245 'IMAGE_SCN_MEM_FARDATA': 0x00008000,
246 'IMAGE_SCN_MEM_PURGEABLE': 0x00020000,
247 'IMAGE_SCN_MEM_16BIT': 0x00020000,
248 'IMAGE_SCN_MEM_LOCKED': 0x00040000,
249 'IMAGE_SCN_MEM_PRELOAD': 0x00080000,
250 'IMAGE_SCN_ALIGN_1BYTES': 0x00100000,
251 'IMAGE_SCN_ALIGN_2BYTES': 0x00200000,
252 'IMAGE_SCN_ALIGN_4BYTES': 0x00300000,
253 'IMAGE_SCN_ALIGN_8BYTES': 0x00400000,
254 'IMAGE_SCN_ALIGN_16BYTES': 0x00500000,
255 'IMAGE_SCN_ALIGN_32BYTES': 0x00600000,
256 'IMAGE_SCN_ALIGN_64BYTES': 0x00700000,
257 'IMAGE_SCN_ALIGN_128BYTES': 0x00800000,
258 'IMAGE_SCN_ALIGN_256BYTES': 0x00900000,
259 'IMAGE_SCN_ALIGN_512BYTES': 0x00A00000,
260 'IMAGE_SCN_ALIGN_1024BYTES': 0x00B00000,
261 'IMAGE_SCN_ALIGN_2048BYTES': 0x00C00000,
262 'IMAGE_SCN_ALIGN_4096BYTES': 0x00D00000,
263 'IMAGE_SCN_ALIGN_8192BYTES': 0x00E00000,
264 'IMAGE_SCN_ALIGN_MASK': 0x00F00000,
265 'IMAGE_SCN_LNK_NRELOC_OVFL': 0x01000000,
266 'IMAGE_SCN_MEM_DISCARDABLE': 0x02000000,
267 'IMAGE_SCN_MEM_NOT_CACHED': 0x04000000,
268 'IMAGE_SCN_MEM_NOT_PAGED': 0x08000000,
269 'IMAGE_SCN_MEM_SHARED': 0x10000000,
270 'IMAGE_SCN_MEM_EXECUTE': 0x20000000,
271 'IMAGE_SCN_MEM_READ': 0x40000000,
272 'IMAGE_SCN_MEM_WRITE': 0x80000000L},
273 'target': 'unsigned long'}]],
274
275 'execution_flags': lambda x: "%s%s%s" % (
276 "x" if x.Characteristics.IMAGE_SCN_MEM_EXECUTE else "-",
277 "r" if x.Characteristics.IMAGE_SCN_MEM_READ else "-",
278 "w" if x.Characteristics.IMAGE_SCN_MEM_WRITE else "-")
279 }],
280
281 "_IMAGE_IMPORT_DESCRIPTOR": [None, {
282 'Name': [None, ['RVAPointer', dict(
283 target="String",
284 target_args=dict(length=128))]],
285
286 'TimeDateStamp': [None, ['UnixTimeStamp', {}]],
287
288
289 'FirstThunk': [None, ['RVAPointer', dict(target="ThunkArray")]],
290
291
292 'OriginalFirstThunk': [None, ['RVAPointer', dict(
293 target="ThunkArray"
294 )]],
295 }],
296
297 "_IMAGE_EXPORT_DIRECTORY": [None, {
298 'Name': [None, ['RVAPointer', dict(
299 target="String",
300 target_args=dict(length=128)
301 )]],
302
303 'AddressOfFunctions': [None, ['RVAPointer', dict(
304 target="Array",
305 target_args=dict(
306 target="RVAPointer",
307 target_args=dict(target="Function"),
308 count=lambda x: x.NumberOfFunctions,
309 )
310 )]],
311
312 'AddressOfNames': [None, ["RVAPointer", dict(
313 target="Array",
314 target_args=dict(
315 target="RVAPointer",
316 target_args=dict(target="String"),
317 count=lambda x: x.NumberOfNames,
318 )
319 )]],
320
321 'AddressOfNameOrdinals': [None, ['RVAPointer', dict(
322 target="Array",
323 target_args=dict(
324 target="unsigned short int",
325 count=lambda x: x.NumberOfFunctions)
326 )]],
327 }],
328
329 "_IMAGE_THUNK_DATA32": [None, {
330 'AddressOfData' : [0x0, ['RVAPointer', dict(
331 target="_IMAGE_IMPORT_BY_NAME"
332 )]],
333 }],
334
335 "_IMAGE_NT_HEADERS": [None, {
336
337 "Sections": [
338
339 lambda x: (x.FileHeader.SizeOfOptionalHeader +
340 x.OptionalHeader.obj_offset),
341
342
343
344 ['Array', dict(
345 target="_IMAGE_SECTION_HEADER",
346 count=lambda x: x.FileHeader.NumberOfSections,
347 )]],
348 }],
349
350 "_IMAGE_RESOURCE_DIRECTORY": [None, {
351 "Entries": [0x10, ["Array", dict(
352 target="_IMAGE_RESOURCE_DIRECTORY_ENTRY",
353 count=lambda x: (x.NumberOfIdEntries +
354 x.NumberOfNamedEntries),
355 )]],
356 }],
357
358 "_IMAGE_RESOURCE_DIRECTORY_ENTRY": [None, {
359 "Name": [None, ['ResourcePointer', dict(target="PrefixedString")]],
360 "Type": [0, ["Enumeration", dict(choices={
361 1: 'RT_CURSOR',
362 2: 'RT_BITMAP',
363 3: 'RT_ICON',
364 4: 'RT_MENU',
365 5: 'RT_DIALOG',
366 6: 'RT_STRING',
367 7: 'RT_FONTDIR',
368 8: 'RT_FONT',
369 9: 'RT_ACCELERATOR',
370 10: 'RT_RCDATA',
371 11: 'RT_MESSAGETABLE',
372 12: 'RT_GROUP_CURSOR',
373 14: 'RT_GROUP_ICON',
374 16: 'RT_VERSION',
375 17: 'RT_DLGINCLUDE',
376 19: 'RT_PLUGPLAY',
377 20: 'RT_VXD',
378 21: 'RT_ANICURSOR',
379 22: 'RT_ANIICON',
380 23: 'RT_HTML',
381 24: 'RT_MANIFEST'})]],
382
383
384 "OffsetToDataInt": [0x04, ['unsigned int']],
385 "OffsetToData": [0x04, ['ResourcePointer', dict(
386 target="_IMAGE_RESOURCE_DATA_ENTRY",
387 )]],
388 "Entry": [0x04, ['ResourcePointer', dict(
389 target="_IMAGE_RESOURCE_DIRECTORY")]],
390
391
392
393 "ChildIsEntry": [0x04, ['BitField', dict(
394 start_bit=31,
395 end_bit=32,
396 )]],
397 }],
398
399 'PrefixedString' : [0x02, {
400 'Length' : [0x0, ['unsigned short']],
401 'Buffer' : [0x2, ['UnicodeString', dict(
402 length=lambda x: x.Length * 2 + 1,
403 )]],
404 }],
405
406 '_IMAGE_RESOURCE_DATA_ENTRY': [0x10, {
407 'OffsetToData': [0x00, ['RVAPointer', dict(
408 target="String",
409 target_args=dict(length=lambda x: x.Size))]],
410 'Size': [0x04, ['unsigned int']],
411 'CodePage': [0x08, ['unsigned int']],
412 }],
413
414 '_IMAGE_IMPORT_BY_NAME' : [None, {
415 'Name' : [None, ['String', dict(length=128)]],
416 }],
417
418 '_IMAGE_DATA_DIRECTORY' : [None, {
419 'VirtualAddress' : [None, ['RVAPointer', dict(
420 target='unsigned int'
421 )]],
422 }],
423
424 '_IMAGE_DEBUG_DIRECTORY': [None, {
425 "AddressOfRawData": [20, ["RVAPointer", dict(
426
427 target="CV_RSDS_HEADER",
428 )]],
429 "TimeDateStamp": [0x4, ["UnixTimeStamp"]],
430 "Type": [12, ["Enumeration", dict(
431 choices={
432 0: "IMAGE_DEBUG_TYPE_UNKNOWN",
433 1: "IMAGE_DEBUG_TYPE_COFF",
434 2: "IMAGE_DEBUG_TYPE_CODEVIEW",
435 3: "IMAGE_DEBUG_TYPE_FPO",
436 4: "IMAGE_DEBUG_TYPE_MISC",
437 5: "IMAGE_DEBUG_TYPE_EXCEPTION",
438 6: "IMAGE_DEBUG_TYPE_FIXUP",
439 7: "IMAGE_DEBUG_TYPE_OMAP_TO_SRC",
440 8: "IMAGE_DEBUG_TYPE_OMAP_FROM_SRC",
441 9: "IMAGE_DEBUG_TYPE_BORLAND",
442 10: "IMAGE_DEBUG_TYPE_RESERVED",
443 },
444 target="unsigned int",
445 )]],
446 }],
447
448 "_GUID": [16, {
449 "Data4": [8, ["String", dict(length=8, term=None)]],
450 "AsString": lambda x: ("%08x%04x%04x%s" % (
451 x.Data1, x.Data2, x.Data3, x.Data4.v().encode('hex'))).upper(),
452 }],
453
454
455 'CV_RSDS_HEADER': [None, {
456 "Signature": [0, ["String", dict(length=4)]],
457 "GUID": [4, ["_GUID"]],
458 "GUID_AGE": lambda x: "%s%X" % (x.GUID.AsString, x.Age),
459 "Age": [20, ["unsigned int"]],
460 "Filename": [24, ["String"]],
461 }],
462
463 '_IMAGE_THUNK_DATA64' : [None, {
464 'AddressOfData' : [0, ['RVAPointer', dict(
465 target="_IMAGE_IMPORT_BY_NAME"
466 )]],
467
468
469 'OrdinalBit' : [0, ['BitField', dict(
470 start_bit=63,
471 end_bit=64
472 )]],
473
474 }],
475
476 'tagVS_FIXEDFILEINFO': [None, {
477 "dwFileOS": [None, ["Flags", dict(
478 maskmap={
479 "VOS_DOS": 0x00010000,
480 "VOS_NT": 0x00040000,
481 "VOS__WINDOWS16": 0x00000001,
482 "VOS__WINDOWS32": 0x00000004,
483 },
484 target='unsigned int')]],
485 "dwFileType": [None, ['Enumeration', dict(
486 choices={
487 1: "VFT_APP (Application)",
488 2: "VFT_DLL (DLL)",
489 3: "VFT_DRV (Driver)",
490 4: "VFT_FORT (Font)",
491 5: "VFT_VXD",
492 7: "VFT_STATIC_LIB",
493 },
494 target='unsigned int')]],
495 "dwFileDate": [lambda x: x.m("dwFileDateLS").obj_offset,
496 ['WinFileTime', {}]],
497 }],
498
499
500 "StringFileInfo": [lambda x: RoundUpToWordAlignment(x.Length), {
501 "Length": [0x00, ['unsigned short int']],
502 "ValueLength": [0x02, ['unsigned short int']],
503 "Type": [0x04, ['unsigned short int']],
504
505
506 "Key": [0x06, ['UnicodeString', dict(length=28)]],
507
508 "Children": [AlignAfter("Key"), ['ListArray', dict(
509 target='StringTable',
510 maximum_offset=lambda x: x.Length + x.obj_offset)]],
511 }],
512
513
514 "VarFileInfo": [lambda x: RoundUpToWordAlignment(x.Length), {
515 "Length": [0x00, ['unsigned short int']],
516 "ValueLength": [0x02, ['unsigned short int']],
517 "Type": [0x04, ['unsigned short int']],
518
519
520 "Key": [0x06, ['UnicodeString', dict(length=24)]],
521
522 "Children": [AlignAfter("Key"), ['ListArray', dict(
523 target='Var',
524 maximum_offset=lambda x: x.Length + x.obj_offset)]],
525 }],
526
527
528 "Var": [lambda x: RoundUpToWordAlignment(x.Length), {
529 "Length": [0x00, ['unsigned short int']],
530 "ValueLength": [0x02, ['unsigned short int']],
531 "Type": [0x04, ['unsigned short int']],
532
533
534 "Key": [0x06, ['UnicodeString', dict(length=24)]],
535
536 "Value": [AlignAfter("Key"), ['String', dict(
537 length=lambda x: x.ValueLength, term=None)]],
538 }],
539
540 "StringTable": [lambda x: RoundUpToWordAlignment(x.Length), {
541 "Length": [0x00, ['unsigned short int']],
542 "ValueLength": [0x02, ['unsigned short int']],
543 "Type": [0x04, ['unsigned short int']],
544
545
546 "LangID": [0x06, ['UnicodeString', dict(length=16, term=None)]],
547
548 "Children": [AlignAfter("LangID"), ['ListArray', dict(
549 target='ResourceString',
550 maximum_offset=lambda x: x.Length + x.obj_offset)]],
551 }],
552
553
554 "ResourceString": [lambda x: RoundUpToWordAlignment(x.Length), {
555 "Length": [0x00, ['unsigned short int']],
556 "ValueLength": [0x02, ['unsigned short int']],
557 "Type": [0x04, ['unsigned short int']],
558
559
560 "Key": [0x06, ['UnicodeString', dict(length=1024)]],
561
562 "Value": [AlignAfter("Key"), ['UnicodeString', dict(
563 length=lambda x: x.ValueLength * 2)]],
564 }],
565
566
567
568
569
570
571 'VS_VERSIONINFO': [0x06, {
572 "Length": [0x00, ['unsigned short int']],
573 "ValueLength": [0x02, ['unsigned short int']],
574 "Type": [0x04, ["Enumeration", dict(
575 choices={
576 0: "Binary",
577 1: "Text",
578 },
579 target='unsigned short int')]],
580
581
582 "szKey": [0x06, ["UnicodeString", dict(length=32)]],
583
584
585 "Value": [AlignAfter("szKey"), ["tagVS_FIXEDFILEINFO"]],
586
587
588 "Children": [AlignAfter("Value"), ['ListArray', dict(
589 target="StringFileInfo",
590 maximum_offset=lambda x: x.Length + x.obj_offset)]],
591 }],
592 }
593
594
595
596 pe_overlays["_IMAGE_OPTIONAL_HEADER64"] = copy.deepcopy(
597 pe_overlays["_IMAGE_OPTIONAL_HEADER"])
598
599 -class _LDR_DATA_TABLE_ENTRY(obj.Struct):
600 """
601 Class for PE file / modules
602
603 If these classes are instantiated by _EPROCESS.list_*_modules()
604 then its guaranteed to be in the process address space.
605 """
606 _pe = None
607
608 @utils.safe_property
610 if self._pe is None:
611 self._pe = PE(address_space=self.obj_vm, image_base=self.DllBase,
612 session=self.obj_session)
613
614 return self._pe
615
616 @utils.safe_property
618 """Return the _IMAGE_NT_HEADERS object"""
619
620 dos_header = self.obj_profile._IMAGE_DOS_HEADER(
621 self.DllBase.v(), vm=self.obj_vm)
622
623 return dos_header.NTHeader
624
627 """DOS header"""
628
629
630
631 @utils.safe_property
633 """Get the NT header"""
634 if self.e_magic != 0x5a4d:
635 return obj.NoneObject(
636 'e_magic {0:04X} is not a valid DOS signature.'.format(
637 self.e_magic or 0))
638
639 nt_header = self.obj_profile._IMAGE_NT_HEADERS(
640 offset=self.e_lfanew + self.obj_offset,
641 vm=self.obj_vm, context=self.obj_context)
642
643 if nt_header.Signature != 0x4550:
644 return obj.NoneObject(
645 'NT header signature {0:04X} is not a valid'.format(
646 nt_header.Signature or 0))
647
648 return nt_header
649
652 """PE header"""
653
654 @utils.safe_property
656 optional_header = self.m("OptionalHeader")
657 if optional_header.Magic == 0x20b:
658 self.obj_context["mode"] = "AMD64"
659 return optional_header.cast("_IMAGE_OPTIONAL_HEADER64")
660
661 self.obj_context["mode"] = "I386"
662 return optional_header
663
666 """PE section"""
667
669 """Sanity checks address boundaries"""
670
671 image_size = self.obj_parent.OptionalHeader.SizeOfImage
672 if self.VirtualAddress > image_size:
673 raise ValueError('VirtualAddress {0:08x} is past the end of '
674 'image.'.format(self.VirtualAddress))
675
676 if self.Misc.VirtualSize > image_size:
677 raise ValueError('VirtualSize {0:08x} is larger than image '
678 'size.'.format(self.Misc.VirtualSize))
679
680 if self.SizeOfRawData > image_size:
681 raise ValueError('SizeOfRawData {0:08x} is larger than image '
682 'size.'.format(self.SizeOfRawData))
683
686 """A data directory."""
687
689 """Automatically resolve the data directory according to our name."""
690 result = self.m("VirtualAddress")
691
692 if self.obj_name == "IMAGE_DIRECTORY_ENTRY_IMPORT":
693 return result.dereference_as(
694 target="SentinelArray", target_args=dict(
695 target="_IMAGE_IMPORT_DESCRIPTOR"
696 ),
697 vm=vm,
698 )
699
700 elif self.obj_name == "IMAGE_DIRECTORY_ENTRY_EXPORT":
701 return result.dereference_as("_IMAGE_EXPORT_DIRECTORY", vm=vm)
702
703 elif self.obj_name == "IMAGE_DIRECTORY_ENTRY_RESOURCE":
704 return result.dereference_as("_IMAGE_RESOURCE_DIRECTORY", vm=vm)
705
706 return result.dereference(vm=vm)
707
710 """Represents a node in the resource tree."""
711
713 for entry in self.Entries:
714 yield entry
715
716 - def Open(self, node_name):
717 """Opens a specific node child."""
718 for entry in self.Entries:
719 if entry.Name == node_name or entry.Type == node_name:
720 return entry.Entry
721
722 if entry.Type == 0:
723 break
724
725 return obj.NoneObject("node %s not found" % node_name)
726
728 """A generator for _IMAGE_RESOURCE_DATA_ENTRY under this node."""
729 for entry in self:
730 if entry.ChildIsEntry:
731 for subentry in entry.Entry.Traverse():
732 yield subentry
733 else:
734 yield entry.OffsetToData.dereference()
735
738
739 @utils.safe_property
741 if self.NameIsString:
742 return utils.SmartUnicode(self.m("Name").Buffer)
743 else:
744 return utils.SmartUnicode(self.Type)
745
746 @utils.safe_property
748 if self.ChildIsEntry:
749 return self.m("Entry").dereference()
750 else:
751 return self.m("OffsetToData")
752
755 """A sential terminated array of thunks."""
756
757 - def __init__(self, parent=None, context=None, **kwargs):
766
768
769 @utils.safe_property
771 """Get all the children of this node.
772
773 The child is either a StringFileInfo or VarFileInfo depending on the
774 key."""
775 for child in self.m("Children"):
776 if child.Key.startswith("VarFileInfo"):
777 yield child.cast("VarFileInfo")
778 elif child.Key.startswith("StringFileInfo"):
779 yield child
780 else:
781 break
782
784 """Generates all the ResourceString structs by recursively traversing
785 the Children tree.
786 """
787 if item is None:
788 item = self
789
790 for child in item.Children:
791 try:
792 for subchild in self.Strings(child):
793 yield subchild
794 except AttributeError:
795 yield child
796
797
798
799 -class PE(object):
800 """A convenience object to access PE file information."""
801
802 - def __init__(self, address_space=None, image_base=0, filename=None,
803 session=None):
857
858 @utils.safe_property
860 return self.nt_header.OptionalHeader.DataDirectory[
861 "IMAGE_DIRECTORY_ENTRY_DEBUG"].VirtualAddress.dereference_as(
862 "_IMAGE_DEBUG_DIRECTORY").AddressOfRawData
863
865 """A generator over the import directory.
866
867 Note that this iterates over the OriginalFirstThunk which still remains
868 from the on-disk executable. The IAT is constructed by the linker at
869 load time, and is stored in FirstThunk in memory. Hence the IAT() method
870 is going to return code objects while this method simply returns names.
871
872 Yields:
873 a tuple of (dll, function_name)
874 """
875 import_directory = self.nt_header.OptionalHeader.DataDirectory[
876 'IMAGE_DIRECTORY_ENTRY_IMPORT'].dereference()
877
878 for directory in import_directory:
879 dll = directory.Name.dereference()
880 for thunk in directory.OriginalFirstThunk.dereference():
881 function_name = thunk.AddressOfData.Name
882
883 yield dll, function_name, thunk.AddressOfData.Hint
884
886 """A generator over the IAT.
887
888 Note that this iterates over the FirstThunk imports. In memory, these
889 contain the IAT which has been resolved by the loader.
890
891 Yields:
892 a tuple of (dll, function_name)
893 """
894 import_directory = self.nt_header.OptionalHeader.DataDirectory[
895 'IMAGE_DIRECTORY_ENTRY_IMPORT'].dereference()
896
897 for directory in import_directory:
898 dll = directory.Name.dereference()
899 for thunk in directory.FirstThunk.dereference():
900 function = thunk.u1.Function
901
902 yield dll, function, thunk.u1.Ordinal
903
905 """A generator over the export directory."""
906 export_directory = self.nt_header.OptionalHeader.DataDirectory[
907 'IMAGE_DIRECTORY_ENTRY_EXPORT'].dereference()
908
909 dll = export_directory.Name.dereference()
910 function_table = export_directory.AddressOfFunctions.dereference()
911 name_table = export_directory.AddressOfNames.dereference()
912 ordinal_table = export_directory.AddressOfNameOrdinals.dereference()
913
914 seen_ordinals = set()
915
916
917 for i, name in enumerate(name_table):
918 ordinal = int(ordinal_table[i])
919 seen_ordinals.add(ordinal)
920 func = function_table[ordinal]
921 func.obj_name = "%s:%s" % (dll, name.dereference())
922
923 yield (dll, func, name.dereference(), ordinal)
924
925
926 for i, func in enumerate(function_table):
927 ordinal = export_directory.Base + i
928 if ordinal in seen_ordinals:
929 continue
930
931 yield (dll, function_table[ordinal],
932 obj.NoneObject("Name not accessible"), ordinal)
933
935 """Scan the export table for a function of the given name.
936
937 Similar to the GetProcAddress function.
938 """
939 for _, function_pointer, func_name, _ in self.ExportDirectory():
940 if func_name == name:
941 return function_pointer.dereference()
942
955
958
963
966 """A profile for PE files.
967
968 This profile is available from the repository under the name "pe".
969 """
970
971 @classmethod
973 super(PEProfile, cls).Initialize(profile)
974 if not profile.has_class("unsigned int"):
975 basic.ProfileLLP64.Initialize(profile)
976
977 profile.add_classes({
978 '_IMAGE_DOS_HEADER': _IMAGE_DOS_HEADER,
979 '_IMAGE_NT_HEADERS': _IMAGE_NT_HEADERS,
980 '_IMAGE_SECTION_HEADER': _IMAGE_SECTION_HEADER,
981 '_LDR_DATA_TABLE_ENTRY': _LDR_DATA_TABLE_ENTRY,
982 '_IMAGE_DATA_DIRECTORY': _IMAGE_DATA_DIRECTORY,
983 "SentinelArray": SentinelArray,
984 "ThunkArray": ThunkArray,
985 "RVAPointer": RVAPointer,
986 "ResourcePointer": ResourcePointer,
987 "_IMAGE_RESOURCE_DIRECTORY": _IMAGE_RESOURCE_DIRECTORY,
988 "_IMAGE_RESOURCE_DIRECTORY_ENTRY": _IMAGE_RESOURCE_DIRECTORY_ENTRY,
989 "VS_VERSIONINFO": VS_VERSIONINFO,
990 })
991 profile.add_overlay(pe_overlays)
992
995 """An address space which applies to PE files.
996
997 This basically remaps sections in the PE file to the virtual address space.
998 See http://code.google.com/p/corkami/downloads/detail?name=pe-20110117.pdf
999
1000 The PE file is divided into sections, each section is mapped into memory at
1001 a different place:
1002
1003 File on Disk Memory Image
1004 0-> ------------ image base-> ------------
1005 Header Header
1006 ------------ ------------
1007 Section 1
1008 ------------ ------------
1009 Section 2 Section 1
1010 ------------ ------------
1011
1012 ------------
1013 Section 2
1014 ------------
1015
1016 This address space expands the file from disk into the memory image view as
1017 shown. Since all internal pe RVA references are within the virtual space,
1018 this helps resolution.
1019 """
1021 """We layer on top of the file address space."""
1022 super(PEFileAddressSpace, self).__init__(**kwargs)
1023
1024 self.as_assert(self.base is not None, "Must layer on another AS.")
1025 self.as_assert(self.base.read(0, 2) == "MZ",
1026 "File does not have a valid signature for a PE file.")
1027
1028 self.profile = self.session.LoadProfile("pe")
1029
1030 nt_header = self.profile._IMAGE_DOS_HEADER(vm=self.base).NTHeader
1031 self.image_base = obj.Pointer.integer_to_address(
1032 nt_header.OptionalHeader.ImageBase)
1033
1034
1035 self.add_run(self.image_base, 0, nt_header.OptionalHeader.SizeOfHeaders)
1036
1037 for section in nt_header.Sections:
1038 length = section.SizeOfRawData.v()
1039 if length > 0:
1040 virtual_address = section.VirtualAddress.v() + self.image_base
1041 file_offset = section.PointerToRawData.v()
1042 self.add_run(virtual_address, file_offset, length)
1043
1044
1045 self.nt_header = self.profile._IMAGE_DOS_HEADER(
1046 vm=self, offset=self.image_base,
1047 context=dict(image_base=self.image_base)).NTHeader
1048
1050 return "<PEFileAddressSpace @ %#x >" % self.image_base
1051
1054 """A utility class to demangle VC++ names.
1055
1056 This is not a complete or accurate demangler, it simply extract the name and
1057 strips out args etc.
1058
1059 Ref:
1060 http://www.kegel.com/mangle.html
1061 """
1062 STRING_MANGLE_MAP = {
1063 "^0": ",",
1064 "^2": r"\\",
1065 "^4": ".",
1066 "^3": ":",
1067 "^5": "_",
1068 "^6": ".",
1069 r"\$AA": "",
1070 r"\$AN": "",
1071 r"\$CF": "%",
1072 r"\$EA": "@",
1073 r"\$CD": "#",
1074 r"\$CG": "&",
1075 r"\$HO": "~",
1076 r"\$CI": "(",
1077 r"\$CJ": ")",
1078 r"\$DM1": "</",
1079 r"\$DMO": ">",
1080 r"\$DN": "=",
1081 r"\$CK": "*",
1082 r"\$CB": "!",
1083
1084 }
1085
1088
1090 string = string.split("@")[3]
1091
1092 result = []
1093 for cap in string.split("?"):
1094 for k, v in self.STRING_MANGLE_MAP.items():
1095 cap = re.sub(k, v, cap)
1096
1097 result.append(cap)
1098
1099 return "str:" + "".join(result).strip()
1100
1101 SIMPLE_X86_CALL = re.compile(r"[_@]([A-Za-z0-9_]+)@(\d{1,3})$")
1102 FUNCTION_NAME_RE = re.compile(r"\?([A-Za-z0-9_]+)@")
1104 """Returns the de-mangled name.
1105
1106 At this stage we don't really do proper demangling since we usually dont
1107 care about the prototype, nor c++ exports. In the future we should
1108 though.
1109 """
1110 m = self.SIMPLE_X86_CALL.match(mangled_name)
1111 if m:
1112
1113
1114
1115
1116
1117 if m.group(2) in ["4", "12"]:
1118 self._metadata.setdefault("arch", "I386")
1119
1120 return m.group(1)
1121
1122 m = self.FUNCTION_NAME_RE.match(mangled_name)
1123 if m:
1124 return m.group(1)
1125
1126
1127
1128 if mangled_name and mangled_name[0] in "_.":
1129 mangled_name = mangled_name[1:]
1130
1131 elif mangled_name.startswith("??_C@"):
1132 return self._UnpackMangledString(mangled_name)
1133
1134 return mangled_name
1135
1136
1137 -class BasicPEProfile(basic.RelativeOffsetMixin, basic.BasicClasses):
1138 """A basic profile for a pe image.
1139
1140 This profile deals with Microsoft Oddities like name mangling, and
1141 correcting global offsets to the base image address.
1142 """
1143
1144 image_base = 0
1145
1146 METADATA = dict(os="windows")
1147
1150
1152 """Add the demangled constants.
1153
1154 This allows us to handle 32 bit vs 64 bit constant names easily since
1155 the mangling rules are different.
1156 """
1157 demangler = Demangler(self._metadata)
1158 result = {}
1159
1160 for k, v in constants.iteritems():
1161 result[demangler.DemangleName(k)] = v
1162
1163 super(BasicPEProfile, self).add_constants(
1164 constants=result, **opts)
1165
1170
1171 @classmethod
1187