This file is indexed.

/usr/lib/python2.7/dist-packages/rekall/plugins/darwin/compressor.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
# Rekall Memory Forensics
#
# Copyright 2014 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
"""Enumerate and dump all compressed memory pages on Darwin."""

__author__ = "Andreas Moser <amoser@google.com>"

import os

from rekall.plugins import core
from rekall.plugins.darwin import common
from rekall.plugins.darwin import WKdm


class DarwinDumpCompressedPages(core.DirectoryDumperMixin, common.AbstractDarwinCommand):
    """Dumps all compressed pages."""

    __name = "dumpcompressedmemory"

    SLOT_ARRAY_SIZE = 64
    PAGE_SIZE = 4096

    def UnpackCSize(self, c_slot):

        size = c_slot.c_size
        if size == self.PAGE_SIZE - 1:
            return self.PAGE_SIZE
        else:
            return size

    def render(self, renderer):

        pages = self.profile.get_constant_object("_c_segment_count", "int")

        renderer.format("Going to dump {0} segments.\n", pages)

        p_segu = self.profile.get_constant_object(
            "_c_segments", "Pointer", target_args={
                "target": "Array",
                "target_args": {
                    "target": "c_segu",
                    "count": int(pages),
                }})

        segu_array = p_segu.deref()

        for i, segu in enumerate(segu_array):
            renderer.RenderProgress("Segment: %d" % i)

            c_seg = segu.c_seg

            if (c_seg.c_ondisk or
                    c_seg.c_on_swappedout_q or
                    c_seg.c_on_swappedout_sparse_q):
                # Data swapped out.
                continue

            c_buffer = c_seg.c_store.c_buffer
            if c_buffer == 0:
                # No data in this segment.
                continue

            seg_buffer = c_buffer.obj_vm.read(c_buffer.v(),
                                              c_seg.c_nextoffset * 4)

            c_slot_arrays = []
            for slot in c_seg.c_slots:
                c_slot_arrays.append(
                    slot.dereference_as(
                        target="Array", target_args=dict(target="c_slot")))

            for slot_nr in xrange(c_seg.c_nextslot):
                c_slot_array = c_slot_arrays[slot_nr / self.SLOT_ARRAY_SIZE]
                c_slot = c_slot_array[slot_nr % self.SLOT_ARRAY_SIZE]

                if not (c_slot.c_offset and c_slot.c_size):
                    continue

                c_size = self.UnpackCSize(c_slot)

                # This should never happen.
                if c_slot.c_offset * 4 + c_size >= len(seg_buffer):
                    continue

                data = seg_buffer[c_slot.c_offset * 4:
                                  c_slot.c_offset * 4 + c_size]

                offset_alignment_mask = 0x3

                c_rounded_size = (c_size + offset_alignment_mask)
                c_rounded_size &= ~offset_alignment_mask

                if (c_rounded_size == self.PAGE_SIZE):
                    # Page was not compressible.
                    # Copy anyways?

                    # with renderer.open(
                    #         directory=self.dump_dir,
                    #         filename="seg%d_slot%d.dat" % (i, slot_nr),
                    #         mode="wb") as fd:
                    #     fd.write(data)
                    continue

                try:
                    decompressed = WKdm.WKdm_decompress_apple(data)
                    if decompressed:
                        dirname = os.path.join(self.dump_dir, "segment%d" % i)
                        try:
                            os.mkdir(dirname)
                        except OSError:
                            pass

                        with renderer.open(
                                directory=dirname,
                                filename="slot%d.dmp" % slot_nr,
                                mode="wb") as fd:
                            fd.write(decompressed)

                except Exception as e:
                    renderer.report_error(str(e))