Skip to content

Commit

Permalink
Fixed 'ifconfig' and 'arp' for 10.10.5 (and probably 10.11).
Browse files Browse the repository at this point in the history
BUG=
R=scudette@gmail.com

Review URL: https://codereview.appspot.com/274040043.
  • Loading branch information
the80srobot committed Oct 25, 2015
1 parent 5c7c9af commit 7be24e5
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 40 deletions.
161 changes: 127 additions & 34 deletions rekall-core/rekall/plugins/darwin/networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"Michael Cohen <scudette@google.com>",
"Adam Sindelar <adam.sindelar@gmail.com>")

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

Expand Down Expand Up @@ -87,7 +88,7 @@ def methods(cls):

@registry.classproperty
@registry.memoize
def table_header(cls):
def table_header(cls): # pylint: disable=no-self-argument
header = [dict(name="Socket", cname="socket", type="socket", width=60)]
for method in cls.methods():
header.append(dict(name=method, cname=method, width=12))
Expand All @@ -106,41 +107,123 @@ def collect(self):
yield row


class DarwinArp(common.AbstractDarwinCommand):
"""Show information about arp tables."""
class DarwinGetArpListHead(common.AbstractDarwinParameterHook):
"""
__name = "arp"
One version of arp_init looks like this:
def render(self, renderer):
renderer.table_header(
[("IP Addr", "ip_addr", "20"),
("MAC Addr", "mac", "18"),
("Interface", "interface", "9"),
("Sent", "sent", "8"),
("Recv", "recv", "8"),
("Time", "timestamp", "24"),
("Expires", "expires", "8"),
("Delta", "delta", "8")])
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")

arp_cache = self.profile.get_constant_object(
"_llinfo_arp",
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"))

while arp_cache:
entry = arp_cache.la_rt
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

renderer.table_row(
entry.source_ip,
entry.dest_ip,
entry.name,
entry.sent,
entry.rx,
entry.base_calendartime,
entry.rt_expire,
entry.delta)
llinfo_arp = self.session.profile.Object(
type_name="llinfo_arp", offset=offset)

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


class DarwinRoute(common.AbstractDarwinCommand):
Expand Down Expand Up @@ -263,14 +346,24 @@ class DarwinIfnetHook(common.AbstractDarwinParameterHook):
https://github.com/opensource-apple/xnu/blob/10.9/bsd/net/if_var.h#L816
"""

name = "ifnet"
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 = self.session.profile.get_constant_object(
"_dlil_ifnet_head",
target="Pointer",
target_args=dict(
target="ifnet"))
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")]

Expand Down
22 changes: 18 additions & 4 deletions rekall-core/rekall/plugins/overlays/darwin/darwin.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,15 @@ def __iter__(self):
return self.list_of_type(self.obj_parent.obj_type, self.obj_name)


class llinfo_arp(obj.Struct):
@property
def isvalid(self):
try:
return self.la_rt.rt_llinfo.v() == self.obj_offset
except AttributeError:
return False


class queue_entry(basic.ListMixIn, obj.Struct):
"""A queue_entry is an externalized linked list.
Expand Down Expand Up @@ -758,7 +767,7 @@ def fill_socketinfo(self):
https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/NKEConceptual/control/control.html
"""
domain = self.so_proto.pr_domain.dom_family
type = self.so_proto.pr_type
type_name = self.so_proto.pr_type
protocol = self.so_proto.pr_protocol

si = {"soi_kind": "SOCKINFO_GENERIC"}
Expand Down Expand Up @@ -796,7 +805,7 @@ def fill_socketinfo(self):
inp.inp_dependladdr.inp6_local.m("__u6_addr")
)

if (type == "SOCK_STREAM"
if (type_name == "SOCK_STREAM"
and (protocol == 0 or protocol == "IPPROTO_TCP")
and inp.inp_ppcb != None):

Expand Down Expand Up @@ -978,7 +987,8 @@ def _get_address_obj(self):

return addr

def __unicode__(self):
@property
def address(self):
result = ""
addr = self._get_address_obj()
if addr:
Expand All @@ -990,6 +1000,9 @@ def __unicode__(self):

return str(result)

def __unicode__(self):
return self.address


class vm_map_entry(obj.Struct):
def find_vnode_object(self):
Expand Down Expand Up @@ -1500,7 +1513,8 @@ def Initialize(cls, profile):
# Support both forms with and without _class suffix.
OSDictionary=OSDictionary, OSDictionary_class=OSDictionary,
OSOrderedSet=OSOrderedSet, OSOrderedSet_class=OSOrderedSet,
fileproc=fileproc, session=session, cnode=cnode)
fileproc=fileproc, session=session, cnode=cnode,
llinfo_arp=llinfo_arp)
profile.add_enums(**darwin_enums)
profile.add_overlay(darwin_overlay)
profile.add_constants(default_text_encoding="utf8")
Expand Down
25 changes: 25 additions & 0 deletions rekall-core/rekall/plugins/renderers/darwin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from rekall.ui import json_renderer

from rekall.ui import text
from rekall.plugins.renderers import base_objects
from rekall.plugins.renderers import data_export

Expand Down Expand Up @@ -121,6 +122,30 @@ class Socket_TextObjectRenderer(base_objects.StructTextRenderer):
]


class Rtentry_TextObjectRenderer(base_objects.StructTextRenderer):
renders_type = "rtentry"

COLUMNS = [
dict(name="IP Address", cname="source_ip", type="sockaddr",
width=18),
dict(name="Mac Address", cname="dest_ip", type="sockaddr",
width=18),
dict(name="Interface", cname="name", align="c"),
dict(name="Sent", cname="sent", width=8, align="r"),
dict(name="Received", cname="rx", width=8, align="r"),
dict(name="Time", cname="base_calendartime", width=30, align="c"),
dict(name="Expires", cname="rt_expire", align="r"),
dict(name="Delta", cname="delta", align="r")
]


class Sockaddr_TextObjectRenderer(text.TextObjectRenderer):
renders_type = "sockaddr"

def render_full(self, target, **_):
return text.Cell(target.address)


class Zone_TextObjectRenderer(base_objects.StructTextRenderer):
renders_type = "zone"
COLUMNS = [
Expand Down
7 changes: 5 additions & 2 deletions rekall-core/rekall/ui/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,11 @@ def render_address(self, target, width=None, **options):
self.format_address(int(target), **options),
width=width)

render_compact = render_full
render_value = render_full
def render_compact(self, *args, **kwargs):
return self.render_full(*args, **kwargs)

def render_value(self, *args, **kwargs):
return self.render_full(*args, **kwargs)

def render_row(self, target, style=None, **options):
"""Render the target suitably.
Expand Down
4 changes: 4 additions & 0 deletions tools/osx/MacPmem/MacPmemTest/rangemap_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ int test_rangemap() {

// Test filling the rangemap out of sequence.
int test_rangemap_nonsequential() {
// Disable error logging because we cause them on purpose.
PmemLogLevel previous_level = pmem_logging_level;
pmem_logging_level = kPmemFatal;
pmem_rangemap *r = pmem_rangemap_make(0x100);

// Starting the map past zero should work.
Expand All @@ -91,5 +94,6 @@ int test_rangemap_nonsequential() {
return -3;
}

pmem_logging_level = previous_level;
return 0;
}

0 comments on commit 7be24e5

Please sign in to comment.