1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """The module implements the base class for address resolution."""
20
21 __author__ = "Michael Cohen <scudette@gmail.com>"
22
23 import re
24
25 from rekall import config
26 from rekall import obj
27 from rekall_lib import utils
28
29
30 config.DeclareOption(
31 "--name_resolution_strategies", default=["Module", "Symbol", "Export"],
32 group="Interface", type="ChoiceArray",
33 choices=["Module", "Symbol", "Export"])
34
35
37 """A range in the virtual address space which maps an executable.
38
39 Each binary in the address space has its own profile, which knows about
40 symbols within it. This simple class is just a container to facilitate
41 access to the profile that represents this module.
42
43 Within Rekall, each module has a name. Rekall uses a simple syntax to refer
44 to an address in the address space by name (see below).
45 """
46 - def __init__(self, name=None, start=None, end=None, profile=None,
47 session=None):
53
55 return "%s: %s" % (self.__class__.__name__, self.name)
56
57
59
60 """The basic building block for constructing an address resolver plugin.
61
62 An address resolver maintains a collection of Modules and abstracts access
63 to specific symbol names within the modules.
64
65 Rekall uses a symbolic notation to refer to specific addresses within the
66 address space. The address resolver is responsible for parsing this notation
67 and resolving it to an actual address.
68
69 Rules of symbol syntax
70 ======================
71
72 The address space is divided into "modules". A module has a name, a start
73 address and an end address. Modules can also contain a profile which knows
74 about symbols related to that module.
75
76 1. Module reference: The start address of a module can be refered to by its
77 name. e.g: "nt", "ntdll", "tcpip".
78
79 2. If a module contains a valid profile, the profile may also know about
80 symbols within the module. We can refer to these
81 symbols. e.g. "nt!MmGetIoSessionState"
82
83 3. If an exact symbol is not found, it can be referred to with an offset
84 from another symbol name. e.g. "nt!MmGetIoSessionState+5FE" (Note
85 integers are given in hex).
86
87 4. If the symbol is preceeded with a "*" - it means that the symbol is a
88 pointer. The address will be read as a pointer and the symbol name will
89 resolve to the address of the pointer's target.
90
91 """
92
93 __args = [
94 dict(name="symbol", type="ArrayString", default=[],
95 help="List of symbols to lookup"),
96 ]
97
98 table_header = [
99 dict(name="Symbol", width=20),
100 dict(name="Offset", width=20, style="address"),
101 ]
102
103
104 name = "address_resolver"
105
106
107 ADDRESS_NAME_REGEX = re.compile(
108 r"(?P<deref>[*])?"
109
110 r"((?P<address>0x[0-9A-Fa-f]+)|"
111
112 r"(?P<module>[A-Za-z_0-9\.\\]+)"
113
114
115 r"!?"
116
117
118 r"(?P<symbol>[^ +-]+)?"
119 r")"
120
121 r"(?P<op> *[+-] *)?"
122 r"(?P<offset>[0-9a-fA-Fx]+)?")
123
127
129
130 self._address_ranges = utils.RangedCollection()
131
132
133 self._modules_by_name = {}
134
135 self._initialized = False
136
138 if module_name is not None:
139 module_name = unicode(module_name)
140 module_name = re.split(r"[/\\]", module_name)[-1]
141
142 return module_name.lower()
143
145 """Initialize this address resolver."""
146
148 self._address_ranges.insert(module.start, module.end, module)
149 if module.name:
150 self._modules_by_name[module.name] = module
151
153 """Parses the symbol from Rekall symbolic notation.
154
155 Raises:
156 TypeError if the expression has a syntax error.
157
158 Returns:
159 a dict containing the different components of the expression.
160 """
161 m = self.ADDRESS_NAME_REGEX.match(name)
162 if m:
163 capture = m.groupdict()
164 if not capture.get("address"):
165 module = capture.get("module")
166 if not module:
167 raise TypeError("Module name not specified.")
168
169 capture["module"] = self.NormalizeModuleName(module)
170
171 if capture["op"] and not (capture["symbol"] or
172 capture["address"] or
173 capture["module"]):
174 raise TypeError("Operator %s must have an operand." %
175 capture["op"])
176
177 if capture["op"] and not (capture["symbol"] or capture["address"] or
178 capture["module"]):
179 raise TypeError(
180 "Operator %s must operate on a symbol or address." %
181 capture["op"])
182
183 return capture
184
185 raise TypeError("Unable to parse %r as a symbol name" % name)
186
188 self._EnsureInitialized()
189 for _, _, module in self._address_ranges:
190 yield module
191
193 """Finds the module containing the specified address.
194
195 Returns:
196 A Module() instance.
197 """
198 self._EnsureInitialized()
199 address = obj.Pointer.integer_to_address(address)
200
201 _, _, module = self._address_ranges.get_containing_range(address)
202 return module
203
207
209 self._EnsureInitialized()
210 return self._modules_by_name.values()
211
213 """Instantiate the named constant with these args.
214
215 This method is the main entry point for instantiating constants. It is
216 preferred than calling the profile's method of the same name directly
217 since it will be responsible with loading the right profile.
218 """
219 self._EnsureInitialized()
220
221
222 components = self._ParseAddress(name)
223 if not components["symbol"]:
224 raise ValueError("No symbol name specified.")
225
226 module = self._modules_by_name.get(components["module"])
227 if module is not None:
228
229 if module.profile:
230 return module.profile.get_constant_object(
231 components["symbol"], target=target, **kwargs)
232
233 return obj.NoneObject("Profile for name %s unknown." % name, log=True)
234
295
316
318 """Searches for a known symbol at an address lower than this.
319
320 Returns a tuple (nearest_offset, list of symbol names).
321 """
322 self._EnsureInitialized()
323
324 address = obj.Pointer.integer_to_address(address)
325 symbols = []
326 module = self.GetContainingModule(address)
327 if not module or not module.name:
328 return (-1, [])
329
330 if module.profile != None:
331 offset, symbols = module.profile.get_nearest_constant_by_address(
332 address)
333
334
335 if not symbols:
336 if address - module.start > max_distance:
337 return (-1, [])
338
339 if address == module.start:
340 return (module.start, [module.name])
341
342 return (module.start, [
343 "%s+%#x" % (module.name, address - module.start)])
344
345 if address - offset > max_distance:
346 return (-1, [])
347
348
349 if offset == address:
350 return (offset, ["%s!%s" % (module.name, x) for x in symbols])
351
352
353 for x in symbols:
354 if x in module.profile.constant_types:
355 type_name = self._format_type(module, x, address)
356 if type_name is not None:
357 return (offset, ["%s!%s" % (module.name, type_name)])
358
359 return (offset, ["%s!%s+%#x" % (module.name, x, address - offset)
360 for x in symbols])
361
399
401 """Searches symbols for the pattern.
402
403 pattern may contain wild cards (*). Note that currently a module name is
404 required. Example pattern:
405
406 nt!Ps*
407 """
408 self._EnsureInitialized()
409 result = []
410
411 components = self._ParseAddress(pattern)
412 module_name = self.NormalizeModuleName(components["module"])
413 if module_name == None:
414 raise RuntimeError(
415 "Module name must be specified for symbol search.")
416
417 module = self._modules_by_name.get(module_name)
418 if module:
419
420 symbol_regex = re.compile(components["symbol"].replace("*", ".*"))
421 if module.profile:
422 for constant in module.profile.constants:
423 if symbol_regex.match(constant):
424 result.append("%s!%s" % (module_name, constant))
425
426 return result
427
431