This file is indexed.

/usr/lib/python2.7/dist-packages/rekall/plugins/darwin/networking.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
# Rekall Memory Forensics
#
# 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

__author__ = (
    "Michael Cohen <scudette@google.com>",
    "Adam Sindelar <adam.sindelar@gmail.com>")

from rekall import obj
from rekall import plugin
from rekall import registry

from rekall.plugins.darwin import common


class DarwinUnpListCollector(common.AbstractDarwinProducer):
    """Walks the global list of sockets in uipc_usrreq."""

    name = "unp_sockets"
    type_name = "socket"

    def collect(self):
        for head_const in ["_unp_dhead", "_unp_shead"]:
            lhead = self.session.profile.get_constant_object(
                head_const,
                target="unp_head")

            for unp in lhead.lh_first.walk_list("unp_link.le_next"):
                yield [unp.unp_socket]


class DarwinSocketsFromHandles(common.AbstractDarwinProducer):
    """Looks up handles that point to a socket and collects the socket."""

    name = "open_sockets"
    type_name = "socket"

    def collect(self):
        for fileproc in self.session.plugins.collect("fileproc"):
            if fileproc.fg_type == "DTYPE_SOCKET":
                yield [fileproc.autocast_fg_data()]


class DarwinNetstat(common.AbstractDarwinCommand):
    """Prints all open sockets we know about, from any source.

    Netstat will display even connections that lsof doesn't know about, because
    they were either recovered from an allocation zone, or found through a
    secondary mechanism (like system call handler cache).

    On the other hand, netstat doesn't know the file descriptor or, really, the
    process that owns the connection (although it does know the PID of the last
    process to access the socket.)

    Netstat will also tell you, in the style of psxview, if a socket was only
    found using some of the methods available.
    """

    name = "netstat"

    @classmethod
    def methods(cls):
        """Return the names of available socket enumeration methods."""
        # Find all the producers that collect procs and inherit from
        # AbstractDarwinCachedProducer.
        methods = []
        for subclass in common.AbstractDarwinProducer.classes.itervalues():
            # We look for a plugin which is a producer and a darwin command.
            if (issubclass(subclass, common.AbstractDarwinCommand) and
                    issubclass(subclass, plugin.Producer) and
                    subclass.type_name == "socket"):
                methods.append(subclass.name)
        methods.sort()

        return methods

    @registry.classproperty
    @registry.memoize
    def table_header(cls):  # pylint: disable=no-self-argument
        header = [dict(name="socket", type="socket", width=60)]
        for method in cls.methods():
            header.append(dict(name=method, width=12))

        return plugin.PluginHeader(*header)

    def collect(self):
        methods = self.methods()

        for socket in sorted(self.session.plugins.collect("socket"),
                             key=lambda socket: socket.last_pid):
            row = [socket]
            for method in methods:
                row.append(method in socket.obj_producers)

            yield row


class DarwinGetArpListHead(common.AbstractDarwinParameterHook):
    """

    One version of arp_init looks like this:

    void
    arp_init(void)
    {
        VERIFY(!arpinit_done);

        LIST_INIT(&llinfo_arp); // <-- This is the global we want.

        llinfo_arp_zone = zinit(sizeof (struct llinfo_arp),
            LLINFO_ARP_ZONE_MAX * sizeof (struct llinfo_arp), 0,
            LLINFO_ARP_ZONE_NAME);
        if (llinfo_arp_zone == NULL)
            panic("%s: failed allocating llinfo_arp_zone", __func__);

        zone_change(llinfo_arp_zone, Z_EXPAND, TRUE);
        zone_change(llinfo_arp_zone, Z_CALLERACCT, FALSE);

        arpinit_done = 1;
    }

    Disassembled, the first few instructions look like this:
     0x0 55                   PUSH RBP
     0x1 4889e5               MOV RBP, RSP
     0x4 803d65e9400001       CMP BYTE [RIP+0x40e965], 0x1
     0xb 7518                 JNZ 0xff80090a7f95
     0xd 488d3dee802900       LEA RDI, [RIP+0x2980ee]
    0x14 488d35f5802900       LEA RSI, [RIP+0x2980f5]
    0x1b baf3000000           MOV EDX, 0xf3

    # This is a call to kernel!panic (later kernel!assfail):
    0x20 e80b6c1400           CALL 0xff80091eeba0

    # This is where it starts initializing the linked list:
    0x25 48c70548e94000000000 MOV QWORD [RIP+0x40e948], 0x0
         00
    0x30 488d0d0e812900       LEA RCX, [RIP+0x29810e]
    """
    name = "disassembled_llinfo_arp"

    PANIC_FUNCTIONS = (u"__kernel__!_panic", u"__kernel__!_assfail")

    def calculate(self):
        resolver = self.session.address_resolver
        arp_init = resolver.get_constant_object("__kernel__!_arp_init",
                                                target="Function")
        instructions = iter(arp_init.Decompose(20))

        # Walk down to the CALL mnemonic and use the address resolver to
        # see if it calls one of the panic functions.
        for instruction in instructions:
            # Keep spinning until we get to the first CALL.
            if instruction.mnemonic != "CALL":
                continue

            # This is absolute:
            target = instruction.operands[0].value
            _, names = resolver.get_nearest_constant_by_address(target)
            if not names:
                return obj.NoneObject("Could not find CALL in arp_init.")

            if names[0] not in self.PANIC_FUNCTIONS:
                return obj.NoneObject(
                    "CALL was to %r, which is not on the PANIC list."
                    % names)

            # We verified it's the right CALL. MOV should be right after it,
            # so let's just grab it.
            mov_instruction = next(instructions)
            if mov_instruction.mnemonic != "MOV":
                return obj.NoneObject("arp_init code changed.")

            offset = (mov_instruction.operands[0].disp
                      + mov_instruction.address
                      + mov_instruction.size)
            address = self.session.profile.Object(type_name="address",
                                                  offset=offset)

            llinfo_arp = self.session.profile.Object(
                type_name="llinfo_arp",
                offset=address.v())

            if llinfo_arp.isvalid:
                return llinfo_arp.obj_offset

            return obj.NoneObject("llinfo_arp didn't validate.")


class DarwinArp(common.AbstractDarwinProducer):
    """Show information about arp tables."""

    name = "arp"
    type_name = "rtentry"

    def collect(self):
        llinfo_arp = self.session.address_resolver.get_constant_object(
            "__kernel__!_llinfo_arp",
            target="Pointer",
            target_args=dict(target="llinfo_arp"))

        if not llinfo_arp:
            # Must not have it in the profile. Try asking the session hook
            # for the address.
            offset = self.session.GetParameter("disassembled_llinfo_arp")
            if not offset:
                self.session.logging.error(
                    "Could not find the address of llinfo_arp.")
                return

            llinfo_arp = self.session.profile.Object(
                type_name="llinfo_arp", offset=offset)

        for arp_hit in llinfo_arp.walk_list("la_le.le_next"):
            yield [arp_hit.la_rt]


class DarwinRoute(common.AbstractDarwinCommand):
    """Show routing table."""

    __name = "route"

    RNF_ROOT = 2

    def rn_walk_tree(self, h):
        """Walks the radix tree starting from the header h.

        This function is taken from
        xnu-2422.1.72/bsd/net/radix.c: rn_walk_tree()

        Which is why it does not conform to the style guide.

        Note too that the darwin source code abuses C macros:

        #define rn_dupedkey     rn_u.rn_leaf.rn_Dupedkey
        #define rn_key          rn_u.rn_leaf.rn_Key
        #define rn_mask         rn_u.rn_leaf.rn_Mask
        #define rn_offset       rn_u.rn_node.rn_Off
        #define rn_left         rn_u.rn_node.rn_L
        #define rn_right        rn_u.rn_node.rn_R

        And then the original code does:
        rn = rn.rn_left

        So we replace these below.
        """
        rn = h.rnh_treetop

        seen = set()

        # First time through node, go left */
        while rn.rn_bit >= 0:
            rn = rn.rn_u.rn_node.rn_L

        while rn and rn not in seen:
            base = rn

            seen.add(rn)

            # If at right child go back up, otherwise, go right
            while (rn.rn_parent.rn_u.rn_node.rn_R == rn and
                   not rn.rn_flags & self.RNF_ROOT):
                rn = rn.rn_parent

            # Find the next *leaf* to start from
            rn = rn.rn_parent.rn_u.rn_node.rn_R
            while rn.rn_bit >= 0:
                rn = rn.rn_u.rn_node.rn_L

            next = rn

            # Process leaves
            while True:
                rn = base
                if not rn:
                    break

                base = rn.rn_u.rn_leaf.rn_Dupedkey
                if not rn.rn_flags & self.RNF_ROOT:
                    yield rn

            rn = next
            if rn.rn_flags & self.RNF_ROOT:
                return

    def render(self, renderer):
        renderer.table_header(
            [("Source IP", "source", "20"),
             ("Dest IP", "dest", "20"),
             ("Interface", "interface", "9"),
             ("Sent", "sent", "8"),
             ("Recv", "recv", "8"),
             ("Time", "timestamp", "24"),
             ("Expires", "expires", "8"),
             ("Delta", "delta", "8")])

        route_tables = self.profile.get_constant_object(
            "_rt_tables",
            target="Array",
            target_args=dict(
                count=32,
                target="Pointer",
                target_args=dict(
                    target="radix_node_head")))

        for node in self.rn_walk_tree(route_tables[2]):
            rentry = node.dereference_as("rtentry")

            renderer.table_row(
                rentry.source_ip,
                rentry.dest_ip,
                rentry.name,
                rentry.sent, rentry.rx,
                rentry.base_calendartime,
                rentry.rt_expire,
                rentry.delta)


class DarwinIfnetHook(common.AbstractDarwinParameterHook):
    """Walks the global list of interfaces.

    The head of the list of network interfaces is a kernel global [1].
    The struct we use [2] is just the public part of the data [3]. Addresses
    are related to an interface in a N:1 relationship [4]. AF-specific data
    is a normal sockaddr struct.

    References:
      1:
      https://github.com/opensource-apple/xnu/blob/10.9/bsd/net/dlil.c#L254
      2:
      https://github.com/opensource-apple/xnu/blob/10.9/bsd/net/if_var.h#L528
      3:
      https://github.com/opensource-apple/xnu/blob/10.9/bsd/net/dlil.c#L188
      4:
      https://github.com/opensource-apple/xnu/blob/10.9/bsd/net/if_var.h#L816
    """

    name = "ifconfig"

    # ifnet_head is the actual extern holding ifnets and seems to be an
    # improvement over dlil_ifnet_head, which is a static and used only in the
    # dlil (stands for data link interface, I think?) module.
    IFNET_HEAD_NAME = ("_ifnet_head", "_dlil_ifnet_head")

    def calculate(self):
        ifnet_head = obj.NoneObject("No ifnet global names given.")
        for name in self.IFNET_HEAD_NAME:
            ifnet_head = self.session.profile.get_constant_object(
                name,
                target="Pointer",
                target_args=dict(
                    target="ifnet"))

            if ifnet_head:
                break

        return [x.obj_offset for x in ifnet_head.walk_list("if_link.tqe_next")]


class DarwinIfnetCollector(common.AbstractDarwinCachedProducer):
    name = "ifconfig"
    type_name = "ifnet"


class DarwinIPFilters(common.AbstractDarwinCommand):
    """Check IP Filters for hooks."""

    __name = "ip_filters"

    def render(self, renderer):
        renderer.table_header([
            ("Context", "context", "10"),
            ("Filter", "filter", "16"),
            ("Handler", "handler", "[addrpad]"),
            ("Symbol", "symbol", "20")])

        resolver = self.session.address_resolver
        for list_name in ["_ipv4_filters", "_ipv6_filters"]:
            filter_list = self.profile.get_constant_object(
                list_name, target="ipfilter_list")

            for item in filter_list.tqh_first.walk_list("ipf_link.tqe_next"):
                filter = item.ipf_filter
                name = filter.name.deref()
                handler = filter.ipf_input.deref()
                renderer.table_row("INPUT", name, handler,
                                   resolver.format_address(handler))

                handler = filter.ipf_output.deref()
                renderer.table_row("OUTPUT", name, handler,
                                   resolver.format_address(handler))

                handler = filter.ipf_detach.deref()
                renderer.table_row("DETACH", name, handler,
                                   resolver.format_address(handler))