1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 """A parser for dwarf modules which generates vtypes."""
21 import logging
22
23 from elftools import construct
24 from elftools.dwarf import callframe
25 from elftools.dwarf import compileunit
26 from elftools.dwarf import descriptions
27 from elftools.dwarf import dwarfinfo
28 from elftools.dwarf import enums
29 from elftools.dwarf import structs as dwarf_structs
30 from elftools.elf import elffile
31 from elftools.common.py3compat import itervalues
32 from elftools.dwarf.descriptions import describe_attr_value
33
34 from rekall import plugin
35 from rekall_lib import utils
57
58 class DWARFStructs(dwarf_structs.DWARFStructs):
59 def _create_dw_form(self):
60 super(DWARFStructs, self)._create_dw_form()
61
62 self.Dwarf_dw_form.update(dict(
63 DW_FORM_sec_offset=self.Dwarf_offset(''),
64 DW_FORM_exprloc=construct.PrefixedArray(
65 subcon=self.Dwarf_uint8('elem'),
66 length_field=self.Dwarf_uleb128('')),
67 DW_FORM_flag_present=Implicit(),
68 DW_FORM_ref_sig8=self.Dwarf_uint64(''),
69 ))
70
71 dwarf_structs.DWARFStructs = DWARFStructs
72 dwarfinfo.DWARFStructs = DWARFStructs
73 callframe.DWARFStructs = DWARFStructs
74
75 class DWARFInfo(dwarfinfo.DWARFInfo):
76 def _is_supported_version(self, version):
77 return 2 <= version <= 4
78
79 dwarfinfo.DWARFInfo = DWARFInfo
80 elffile.DWARFInfo = DWARFInfo
81
82 class CompileUnit(compileunit.CompileUnit):
83 def iter_DIEs(self):
84 try:
85 self._parse_DIEs()
86 except IndexError:
87 pass
88
89 return iter(self._dielist)
90
91 compileunit.CompileUnit = CompileUnit
92 dwarfinfo.CompileUnit = CompileUnit
93
94
95
96 PatchPyElftools()
100
101 parent = None
102
103 - def __init__(self, die, types, parents):
112
113 @utils.safe_property
115
116 if "DW_AT_name" in self.attributes:
117 return self.attributes["DW_AT_name"].value
118
119 if "DW_AT_sibling" in self.attributes:
120 sibling = self.types.get(self.attributes["DW_AT_sibling"].value +
121 self.die.cu.cu_offset)
122 if sibling and sibling.die.tag == "DW_TAG_typedef":
123 return sibling.name
124
125 return "__unnamed_%s" % self.die.offset
126
127 @utils.safe_property
129 if "DW_AT_type" in self.attributes:
130 return self.attributes["DW_AT_type"].value + self.die.cu.cu_offset
131
133 """Returns a vtype representation of this DIE."""
134 return self.name
135
137 """This DW element is given an opportunity to generate a vtype."""
138
140
142 """For typedefs we just substitute our base type."""
143 if self.type_id is None:
144 return self.name
145
146 return self.types[self.type_id].VType()
147
151
155
158 """A struct definition."""
159 - def __init__(self, die, types, parents):
163
164 @utils.safe_property
166 if "DW_AT_name" in self.attributes:
167 return self.attributes["DW_AT_name"].value
168 else:
169 return "__unnamed_%s" % self.die.offset
170
171 @utils.safe_property
173 try:
174 return self.attributes['DW_AT_byte_size'].value
175 except KeyError:
176 pass
177
179
180 if "DW_AT_declaration" in self.attributes:
181 return
182
183 if self.name in vtype and vtype[self.name][0] != self.size:
184 self.session.logging.warning(
185 "Structs of different sizes but same name")
186
187 count = 1
188 result = [self.size, {}]
189
190 for member in self.members:
191 if isinstance(member, DW_TAG_member):
192 name = member.name
193
194
195 if name.startswith("__unnamed_"):
196 name = "u%s" % count
197 count += 1
198
199 result[1][name] = member.VType()
200
201
202 if result[1]:
203 vtype[self.name] = result
204
207 @utils.safe_property
209 if "DW_AT_name" in self.attributes:
210 return self.attributes["DW_AT_name"].value
211
212 if "DW_AT_sibling" in self.attributes:
213 sibling = self.types.get(self.attributes["DW_AT_sibling"].value +
214 self.die.cu.cu_offset)
215 if sibling and sibling.die.tag == "DW_TAG_typedef":
216 return sibling.name
217
218 return "__unnamed_%s" % self.die.offset
219
223 if 'DW_AT_type' in self.attributes:
224 target = self.types[self.type_id]
225 target_type = target.VType()
226 if not isinstance(target_type, list):
227 target_type = [target_type, None]
228
229 return ['Pointer', dict(target=target_type[0],
230 target_args=target_type[1])]
231
232 return ['Pointer', dict(target="Void")]
233
238
241 count = 0
242
244 if 'DW_AT_type' in self.attributes:
245 target_type = self.types[self.type_id].VType()
246 if not isinstance(target_type, list):
247 target_type = [target_type, None]
248 return ['Array', dict(target=target_type[0],
249 target_args=target_type[1],
250 count=self.count)]
251
252 return ['Array', dict(count=self.count)]
253
256 """These specify the count of arrays."""
257 - def __init__(self, die, types, parents):
262
263
264 _DWARF_EXPR_DUMPER_CACHE = {}
281
284 offset = 0
285 type = None
286
287 - def __init__(self, die, types, parents):
302
304 """A member is just a place holder for another type in the struct.
305
306 Thie method returns the delegate.
307 """
308 return self.types[self.type_id]
309
311 member_type = self.delegate().VType()
312
313
314 if "DW_AT_bit_size" in self.attributes:
315
316
317
318
319
320
321
322
323
324 full_size = self.attributes['DW_AT_byte_size'].value * 8
325 start_bit = self.attributes['DW_AT_bit_offset'].value
326 end_bit = self.attributes['DW_AT_bit_size'].value + start_bit
327
328 converted_start_bit = full_size - end_bit
329 converted_end_bit = full_size - start_bit
330
331
332
333 if member_type[0] == "Enumeration":
334 member_type[1]["target"] = "BitField"
335 member_type[1]["target_args"] = {
336 'start_bit': converted_start_bit,
337 'end_bit': converted_end_bit
338 }
339 return [self.offset, member_type]
340
341 return [self.offset, ['BitField', {'start_bit': converted_start_bit,
342 'target': member_type,
343 'end_bit': converted_end_bit}]]
344
345 if not isinstance(member_type, list):
346 member_type = [member_type]
347
348 return [self.offset, member_type]
349
352 """Holds enumerations."""
353
354 byte_size_lookup = {4: "long",
355 2: "short int",
356 1: "char"}
357
358 - def __init__(self, die, types, parents):
362
364 byte_size = self.attributes['DW_AT_byte_size'].value
365 return ['Enumeration', {'enum_name': self.name,
366 'target': self.byte_size_lookup[byte_size]}]
367
369 """Enumerations go into the $ENUMS vtype area."""
370 vtype.setdefault("$ENUMS", {})[self.name] = self.enumerations
371 vtype.setdefault("$REVENUMS", {})[self.name] = self.reverse_enumerations
372
375 """An enumeration."""
376
377 - def __init__(self, die, types, parents):
384
385
386
387 DIE_LOOKUP = {
388 "DW_TAG_base_type": DW_TAG_base_type,
389 "DW_TAG_structure_type": DW_TAG_structure_type,
390 "DW_TAG_union_type": DW_TAG_union_type,
391 "DW_TAG_member": DW_TAG_member,
392
393
394 "DW_TAG_typedef": DW_TAG_typedef,
395 "DW_TAG_const_type": DW_TAG_typedef,
396
397
398 "DW_TAG_enumeration_type": DW_TAG_enumeration_type,
399 "DW_TAG_enumerator": DW_TAG_enumerator,
400
401 "DW_TAG_pointer_type": DW_TAG_pointer_type,
402 "DW_TAG_array_type": DW_TAG_array_type,
403 "DW_TAG_subrange_type": DW_TAG_subrange_type,
404 "DW_TAG_subroutine_type": DW_TAG_subroutine_type,
405 "DW_TAG_volatile_type": DW_TAG_volatile_type,
406 }
414
417 """A parser for DWARF files."""
418
420 self.session = session
421 self.elffile = elffile.ELFFile(fd)
422 self.types = {}
423
424 if self.elffile.has_dwarf_info():
425 self._dwarfinfo = self.elffile.get_dwarf_info()
426 else:
427 raise RuntimeError("File does not have DWARF information - "
428 "was it compiled with debugging information?")
429 self.logging = session.logging.getChild("linux.dwarf")
430 self.logging.setLevel(logging.ERROR)
431 self.compile()
432
434 """Compile the vtypes from the dwarf information."""
435
436
437
438
439 parents = []
440 section_offset = self._dwarfinfo.debug_info_sec.global_offset
441 for cu in self._dwarfinfo.iter_CUs():
442 parents.append(cu)
443
444 die_depth = 0
445 for die in cu.iter_DIEs():
446 self.logging.debug('%d %s<%x>: %s' % (
447 die_depth,
448 "\t" * die_depth,
449 die.offset,
450 ('%s' % die.tag) if not die.is_null() else ''))
451 if die.is_null():
452 die_depth -= 1
453 parents = parents[:-1]
454 continue
455
456 for attr in itervalues(die.attributes):
457 name = attr.name
458
459 if isinstance(name, int):
460 name = 'Unknown AT value: %x' % name
461
462 if self.logging.isEnabledFor(logging.DEBUG):
463 try:
464 self.logging.debug('%d %s <%2x> %-18s: %s' % (
465 die_depth,
466 "\t" * die_depth,
467 attr.offset,
468 name,
469 describe_attr_value(
470 attr, die, section_offset)))
471 except Exception:
472 pass
473
474
475 t = self.types[die.offset] = DIEFactory(
476 die, self.types, parents)
477
478 if die.has_children:
479 parents.append(t)
480 die_depth += 1
481
482
492
493
494 -class DwarfParser(plugin.TypedProfileCommand, plugin.Command):
495 """Parse the dwarf file and dump a vtype structure from it."""
496 __name = "dwarfparser"
497
498 __args = [
499 dict(name="dwarf_filename", positional=True, required=True,
500 help="The filename of the PDB file."),
501
502 dict(name="profile_class", default="Linux64",
503 help="The name of the profile implementation. "),
504 ]
505
511
513 vtypes = self.parser.VType()
514 result = {
515 "$METADATA": dict(
516 Type="Profile",
517
518
519 ProfileClass=self.plugin_args.profile_class),
520 "$STRUCTS": vtypes,
521 "$ENUMS": vtypes.pop("$ENUMS", {}),
522 "$REVENUMS": vtypes.pop("$REVENUMS", {}),
523 }
524
525 renderer.write(utils.PPrint(result))
526