This file is indexed.

/usr/lib/python2.7/dist-packages/rekall/ui/renderer.py is in python-rekall-core 1.6.0+dfsg-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
# Rekall Memory Forensics
# Copyright (C) 2012 Michael Cohen
# Copyright 2013 Google Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#

"""This module implements the Rekall renderer API.

Rekall has a pluggable rendering system. At the top level we have renderers
which are reponsible for converting the output of plugins into something usable
for the user (whatever that means).

A Rekall plugin uses the renderer to produce output by providing it with a bunch
of objects which are derived from the analysis stage. The renderer is then
responsible for rendering these special objects using pluggable
ObjectRenderer() classes.

1. The framework creates a BaseRenderer implementation (e.g. TextRenderer or
   JsonRenderer)

2. This is passed to a plugin's render() method.

3. The Plugin provides various objects to the renderer via its table_row(),
   format() etc methods.

4. The renderer than uses specialized ObjectRenderer() instances to render the
   objects that the plugin gave it.

For example, by default the renderer used is an instance of TextRenderer. The
PSList() plugin in its render() method, calls renderer.table_row() passing a
WinFileTime() instance as the "Create Time" cell of the table.

The TextRenderer plugin aims to layout the output into the text terminal. For
this to happen it must convert the WinFileTime() instance to a rendering
primitive, specific to the TextRenderer - in this case a Cell() instance. This
conversion is done using an ObjectRenderer instance.

The TextRenderer therefore selects an ObjectRenderer instance based on two
criteria:

- The ObjectRenderer claims to support the WinFileTime() object, or any of its
  base classes in order (using the ObjectRenderer.renders_type attribute).

- The ObjectRenderer claims to support the specific renderer
  (i.e. TextRenderer) using its `renderers` attribute.

The TextRenderer searches for an ObjectRenderer() by traversing the
WinFileTime's __mro__ (i.e. inheritance hierarchy) for a plugin capable of
rendering it. This essentially goes from most specialized to the least
specialized renderer:

- WinFileTime
- UnixTimeStamp   <-- Specialized object renderer for unix times.
- NativeType
- BaseObject
- object          <--- Generic renderer for all objects.

Once a renderer is found, it is used to output the cell value.

## NOTES

1. A specialized object renderer is written specifically for the renderer. This
   means that it is possible to have a specialized _EPROCESS object renderer for
   TextRenderer but when using the JsonRenderer a more general renderer may be
   chosen (say at the BaseObject level).

2. The ObjectRenderer.render_row() method actually returns something which makes
   sense to the supported renderer. There is no API specification for the return
   value. For example the TextRenderer needs a Cell instance but the
   JsonRenderer requires just a dict. Since ObjectRenderer instances are only
   used within the renderer they only need to cooperate with the renderer class
   they support.
"""
import collections
import gc
import inspect
import logging
import time

from rekall import config
from rekall import constants
from rekall import registry
from rekall import utils


config.DeclareOption(
    "-v", "--verbose", default=False, type="Boolean",
    help="Set logging to debug level.", group="Output control")

config.DeclareOption(
    "-q", "--quiet", default=False, type="Boolean",
    help="Turn off logging to stderr.", group="Output control")

config.DeclareOption(
    "--debug", default=False, type="Boolean",
    help="If set we break into the debugger on error conditions.")

config.DeclareOption(
    "--output_style", type="Choices", default="concise",
    choices=["concise", "full"],
    help="How much information to show. Default is 'concise'.")

config.DeclareOption(
    "--logging_level", type="Choices", default="WARNING",
    choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
    help="The default logging level.")

config.DeclareOption(
    "--log_domain", type="ChoiceArray", default=[],
    choices=constants.LOG_DOMAINS,
    help="Add debug logging to these components.")


# A cache to map a tuple (mro, renderer) to the corresponding object renderer.
MRO_RENDERER_CACHE = utils.FastStore(100, lock=True)

# A cache to map a class to its reduced MRO list. Do not hold class references
# in this cache as these capture closure variables via the Curry() classes on
# the property methods.
MRO_CACHE = utils.FastStore(100, lock=True)


class ObjectRenderer(object):
    """Baseclass for all TestRenderer object renderers."""

    # Fall back renderer for all objects. This can also be a list or tuple of
    # all types rendered by this renderer.
    renders_type = "object"

    # These are the renderers supported by this object renderer.
    renderers = []

    __metaclass__ = registry.MetaclassRegistry

    # A cache of Renderer, MRO mappings.
    _RENDERER_CACHE = None

    def __init__(self, renderer=None, session=None, **options):
        if not isinstance(renderer, BaseRenderer):
            raise RuntimeError("Renderer object must be provided. Got %r."
                               % renderer)

        self.renderer = renderer
        self.session = session

        self.options = options
        if self.session:
            self.output_style = self.session.GetParameter("output_style")
        else:
            self.output_style = None

    @staticmethod
    def get_mro(item):
        """Return the MRO of an item."""
        if not inspect.isclass(item):
            item = item.__class__

        try:
            return MRO_CACHE.Get(item.__name__)
        except KeyError:
            # Remove duplicated class names from the MRO (The current
            # implementation uses the flat class name to select the
            # ObjectRenderer so we can get duplicates but they dont matter).
            result = tuple(collections.OrderedDict.fromkeys(
                [unicode(x.__name__) for x in item.__mro__]))

            MRO_CACHE.Put(item.__name__, result)
            return result

    @classmethod
    def ByName(cls, name, renderer):
        """A constructor for an ObjectRenderer by name."""
        cls._BuildRendererCache()

        if not isinstance(renderer, basestring):
            renderer = renderer.__class__.__name__

        # Find the object renderer which works for this name.
        return cls._RENDERER_CACHE.get((name, renderer))

    @classmethod
    def FromMRO(cls, mro, renderer):
        """Get the best object renderer class from the MRO."""
        try:
            return MRO_RENDERER_CACHE[(mro, renderer)]
        except KeyError:
            cls._BuildRendererCache()

            if not isinstance(renderer, basestring):
                renderer = renderer.__class__.__name__

            # MRO is the list of object inheritance for each type. For example:
            # FileAddressSpace,FDAddressSpace,BaseAddressSpace.  We try to match
            # the object renderer from most specific to least specific (or more
            # general).
            for class_name in mro.split(":"):
                object_renderer_cls = cls._RENDERER_CACHE.get(
                    (class_name, renderer))

                if object_renderer_cls:
                    MRO_RENDERER_CACHE.Put((mro, renderer), object_renderer_cls)
                    return object_renderer_cls

    @classmethod
    def _BuildRendererCache(cls):
        # Build the cache if needed.
        if cls._RENDERER_CACHE is None:
            # Do this in a thread safe manner.
            result = {}
            for object_renderer_cls in cls.classes.values():
                for impl_renderer in object_renderer_cls.renderers:
                    render_types = object_renderer_cls.renders_type
                    if not isinstance(render_types, (list, tuple)):
                        render_types = (render_types,)

                    for render_type in render_types:
                        key = (render_type, impl_renderer)
                        if key in result:
                            raise RuntimeError(
                                "Multiple renderer implementations for class "
                                "%s: %s, %s" % (key, object_renderer_cls,
                                                result[key]))

                        result[key] = object_renderer_cls

            cls._RENDERER_CACHE = result

    @classmethod
    def ForTarget(cls, target, renderer):
        """Get the best ObjectRenderer to encode this target.

        ObjectRenderer instances are chosen based on both the taget and the
        renderer they implement.

        Args:
          taget: The target object to render. We walk the MRO to select the best
            renderer. This is a python object to be rendered.

          renderer: The renderer that will be used. This can be a string
             (e.g. "TextRenderer") or a renderer instance.

        Returns:
          An ObjectRenderer class which is best suited for rendering the target.
        """
        return cls.ForType(type(target), renderer)

    @classmethod
    def ForType(cls, target_type, renderer):
        """Get the best ObjectRenderer to encode this target type.

        ObjectRenderer instances are chosen based on both the taget and the
        renderer they implement.

        Args:
          taget_type: Type of the rendered object. We walk the MRO to select
            the best renderer.

          renderer: The renderer that will be used. This can be a string
             (e.g. "TextRenderer") or a renderer instance.

        Returns:
          An ObjectRenderer class which is best suited for rendering the target.
        """
        cls._BuildRendererCache()

        if not isinstance(renderer, basestring):
            renderer = renderer.__class__.__name__

        # Search for a handler which supports both the renderer and the object
        # type.
        for mro_cls in cls.get_mro(target_type):
            handler = cls._RENDERER_CACHE.get((mro_cls, renderer))
            if handler:
                return handler

    @classmethod
    def cache_key(cls, item):
        """Return a suitable cache key."""
        return repr(item)

    def DelegateObjectRenderer(self, item):
        """Create an object renderer for an item based on this object renderer.

        This is useful when delegating to render something else.
        """
        renderer_cls = self.ForTarget(item, self.renderer)
        return renderer_cls(session=self.session, renderer=self.renderer,
                            **self.options)

    def render_header(self, name=None, **options):
        """This should be overloaded to return the header Cell.

        Note that typically the same ObjectRenderer instance will be used to
        render all Cells in the same column.

        Args:
          name: The name of the Column.
          options: The options of the column (i.e. the dict which defines the
            column).

        Return:
          A Cell instance containing the formatted Column header.
        """

    def render_row(self, target, **options):
        """Render the target suitably.

        Args:
          target: The object to be rendered.

          options: A dict containing rendering options. The options are created
            from the column options, overriden by the row options and finally
            the cell options.  It is ok for an instance to ignore some or all of
            the options. Some options only make sense in certain Renderer
            contexts.

        Returns:
          A Cell instance containing the rendering of target.
        """


class BaseTable(object):
    """Renderers contain tables."""

    def __init__(self, session=None, renderer=None, columns=None, **options):
        self.session = session
        self.renderer = renderer
        self.options = options
        self.column_specs = []

        if not isinstance(renderer, BaseRenderer):
            raise TypeError("Renderer object must be supplied. Got %r."
                            % renderer)

        # For now support the legacy column specification and normalized to a
        # column_spec dict.
        for column in columns or []:
            # Old style column specification are a tuple. The new way is a dict
            # which is more expressive but more verbose.
            if isinstance(column, (tuple, list)):
                column = dict(name=column[0],
                              formatstring=column[2])

            self.column_specs.append(column)

    def render_row(self, *row, **options):
        """Render the row suitably."""

    def flush(self):
        pass


class BaseRenderer(object):
    """All renderers inherit from this.

    This class defines the only public interface for the rendering system. This
    is the API which should be used by Rekall plugins to render the
    output. Derived classes can add additional methods, but these should not be
    directly used by the plugins - otherwise plugins will fail when being
    rendered with different renderer implementations.
    """

    __metaclass__ = registry.MetaclassRegistry

    # The user friendly name of this renderer. This is used for selection from
    # command line etc.
    name = None

    last_spin_time = 0
    last_gc_time = 0
    progress_interval = 0.2

    # This is used to ensure that renderers are always called as context
    # managers. This guarantees we call start() and end() automatically.
    _started = False

    # Currently used table.
    table = None

    table_class = BaseTable

    def __init__(self, session=None):
        self.session = session

    def __enter__(self):
        self._started = True
        return self

    def __exit__(self, exc_type, exc_value, trace):
        log_handler = getattr(self.session, "_log_handler", None)
        if log_handler != None:
            log_handler.SetRenderer(None)
        self.end()

    def start(self, plugin_name=None, kwargs=None):
        """The method is called when new output is required.

        Metadata about the running plugin is provided so the renderer may log it
        if desired.

        Args:
           plugin_name: The name of the plugin which is running.
           kwargs: The args for this plugin.
        """
        _ = plugin_name
        _ = kwargs
        self._started = True

        # This handles the progress messages from rekall for the duration of
        # the rendering.
        if self.session:
            self.session.progress.Register(id(self), self.RenderProgress)

        return self

    def end(self):
        """Tells the renderer that we finished using it for a while."""
        self._started = False

        # Remove the progress handler from the session.
        if self.session:
            self.session.progress.UnRegister(id(self))

        self.flush()

    # DEPRECATED
    def write(self, data):
        """Renderer should write some data."""
        pass

    def section(self, name=None, width=50):
        """Start a new section.

        Sections are used to separate distinct entries (e.g. reports of
        different files).
        """
        _ = name
        _ = width

    def format(self, formatstring, *data):
        """Write formatted data.

        For renderers that need access to the raw data (e.g. to check for
        NoneObjects), it is preferred to call this method directly rather than
        to format the string in the plugin itself.

        By default we just call the format string directly.
        """
        _ = formatstring
        _ = data
        if not self._started:
            raise RuntimeError("Writing to a renderer that is not started.")

    def flush(self):
        """Renderer should flush data."""
        if self.table:
            self.table.flush()
            self.table = None

    def table_header(self, columns=None, **options):
        """Table header renders the title row of a table.

        This also stores the header types to ensure everything is formatted
        appropriately.  It must be a list of specs rather than a dict for
        ordering purposes.
        """
        if not self._started:
            raise RuntimeError("Renderer is used without a context manager.")

        # Ensure the previous table is flushed.
        if self.table:
            self.table.flush()

        self.table = self.table_class(session=self.session, renderer=self,
                                      columns=columns, **options)

    def table_row(self, *row, **kwargs):
        """Outputs a single row of a table."""
        self.table.render_row(row=row, **kwargs)

    def report_error(self, message):
        """Render the error in an appropriate way."""
        # By default just log the error. Visual renderers may choose to render
        # errors in a distinctive way.
        # TODO(jordi): Remove in 3 months when any usage should have been
        # noticed and fixed.
        logging.error(
            "**DEPRECATED** report_error is deprecated. Please use the session "
            "logging feature instead. Original message was: %s", message)
        self.session.logging.error(
            "**DEPRECATED** (via report_error): %s", message)

    def RenderProgress(self, *_, **kwargs):
        """Will be called to render a progress message to the user."""
        # Only write once per self.progress_interval.
        now = time.time()
        force = kwargs.get("force")

        # GC is expensive so we need to do it less frequently.
        if now > self.last_gc_time + 10:
            gc.collect()
            self.last_gc_time = now

        if force or now > self.last_spin_time + self.progress_interval:
            self.last_spin_time = now

            # Signal that progress must be written.
            return True

        return False

    def open(self, directory=None, filename=None, mode="rb"):
        """Opens a file for writing or reading."""
        _ = directory
        _ = filename
        _ = mode
        raise IOError("Renderer does not support writing to files.")

    def get_object_renderer(self, target=None, type=None, target_renderer=None,
                            **options):
        if target_renderer is None:
            target_renderer = self

        if isinstance(type, basestring):
            obj_renderer = ObjectRenderer.ByName(type, target_renderer)
            if not obj_renderer:
                # We don't want to blow up because we might still find the
                # renderer once we actually get the MRO.
                return None

        elif type is not None:
            obj_renderer = ObjectRenderer.ForType(type, target_renderer)
        else:
            obj_renderer = ObjectRenderer.ForTarget(target, target_renderer)

        if not obj_renderer:
            # This should never happen if the renderer installs a handler for
            # type object.
            # pylint: disable=protected-access
            raise RuntimeError("Unable to render object %r for renderer %s" %
                               (repr(target), target_renderer) +
                               str(ObjectRenderer._RENDERER_CACHE))

        return obj_renderer(renderer=self, session=self.session, **options)

    def Log(self, record):
        """Logs a log message. Implement if you want to handle logging."""


def CopyObjectRenderers(args, renderer=None):
    """Automatically copy the object renderers for a renderer.

    This is a convenience method which automatically generates the handlers for
    the given renderer by copying them from the object renderers given in args.

    Args:
      args: classes to copy.

      renderer: A string describing the renderer to apply the object renderers
      to.

    Return:
      Nothing - new renderers are automatically registered.

    """
    for arg in args:
        # Make a new unique name.
        new_class_name = renderer + arg.__name__
        type(new_class_name, (arg,), dict(renderers=[renderer]))