1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 __author__ = "Michael Cohen <scudette@gmail.com>"
20
21 from rekall import obj
22
23 from rekall.plugins.addrspaces import amd64
24 from rekall.plugins.overlays import basic
25 from rekall_lib import utils
26
27
28 darwin_overlay = {
29 "proc": [None, {
30
31 "name": lambda x: x.p_comm,
32 "pid": lambda x: x.p_pid.v(),
33 "dtb": lambda x: x.task.map.pmap.pm_cr3.v(),
34
35 "p_list": [None, ["LIST_ENTRY"]],
36 "p_sibling": [None, ["LIST_ENTRY"]],
37
38 "p_comm": [None, ["UnicodeString", dict(length=17)]],
39 "task": [None, ["Pointer", dict(
40 target="task"
41 )]],
42 }],
43
44 "task": [None, {
45 "bsd_info": [None, ["Pointer", dict(target="proc")]],
46 }],
47
48 "rtentry": [None, {
49 "base_calendartime": [None, ["UnixTimeStamp"]],
50
51 "source_ip": lambda x: x.rt_nodes[0].rn_u.rn_leaf.m(
52 "rn_Key").dereference_as("sockaddr"),
53
54 "dest_ip": lambda x: x.rt_gateway.deref(),
55
56 "name": lambda x: x.rt_ifp.name,
57
58 "sent": lambda x: x.m("rt_stats").nstat_txpackets,
59
60 "rx": lambda x: x.rt_expire if x.m("rt_stats") else None,
61
62 "delta": lambda x: (x.rt_expire - x.base_uptime
63 if x.rt_expire else 0),
64
65 }],
66
67 "kmod_info": [None, {
68 "name": lambda x: utils.SmartUnicode(x.m("name").cast("UnicodeString")),
69 "base": lambda x: x.address.v(),
70 "end": lambda x: x.base + x.size,
71 "version": [None, ["String"]],
72
73
74 "address": [None, ["Pointer"]],
75 }],
76
77 "sockaddr": [None, {
78
79 "sa_family": [None, ["Enumeration", dict(
80 enum_name="sa_family_t",
81 target="unsigned char",
82 )]],
83 }],
84
85 "sysctl_oid": [None, {
86
87
88
89 "oid_kind_type": lambda x: x.m("oid_kind").cast(
90 "Enumeration", choices={
91 1: "CTLTYPE_NODE",
92 2: "CTLTYPE_INT",
93 3: "CTLTYPE_STRING",
94 4: "CTLTYPE_QUAD",
95 5: "CTLTYPE_OPAQUE",
96 },
97 target="BitField",
98 target_args=dict(start_bit=0, end_bit=8),
99 ),
100
101 "oid_perms": lambda x: x.m("oid_kind").cast(
102 "Flags", maskmap={
103 "CTLFLAG_RD": 0x80000000,
104 "CTLFLAG_WR": 0x40000000,
105
106 "CTLFLAG_LOCKED": 0x00800000,
107 },
108 ),
109
110 "oid_name": [None, ["Pointer", dict(target="String")]],
111
112 }],
113
114 "zone": [None, {
115 "zone_name": [None, ["Pointer", dict(target="String")]],
116 "free_elements": [None, ["Pointer", dict(
117 target="zone_free_element"
118 )]],
119 }],
120
121 "vm_map_entry": [None, {
122
123 "protection": [None, ["Flags", dict(
124 maskmap={
125 "VM_PROT_READ": 1,
126 "VM_PROT_WRITE": 2,
127 "VM_PROT_EXECUTE": 4,
128 },
129 target="BitField",
130 target_args=dict(
131 start_bit=7,
132 end_bit=10
133 )
134 )]],
135 "max_protection": [None, ["Flags", dict(
136 maskmap={
137 "VM_PROT_READ": 1,
138 "VM_PROT_WRITE": 2,
139 "VM_PROT_EXECUTE": 4,
140 },
141 target="BitField",
142 target_args=dict(
143 start_bit=10,
144 end_bit=13
145 )
146 )]],
147 }],
148
149 "vnode": [None, {
150 "v_name": [None, ["Pointer", dict(target="String")]],
151
152 "path": lambda self: "/".join(reversed(
153 [unicode(y.v_name.deref()) for y in self.walk_list("v_parent")])),
154
155
156 "v_flag": [None, ["Flags", dict(
157 maskmap={
158 "VROOT": 0x000001,
159 "VTEXT": 0x000002,
160 "VSYSTEM": 0x000004,
161 "VISTTY": 0x000008,
162 "VRAGE": 0x000010,
163 }
164 )]],
165 }],
166
167 "cat_attr": [None, {
168 "ca_atime": [None, ["UnixTimeStamp"]],
169 "ca_atimeondisk": [None, ["UnixTimeStamp"]],
170 "ca_mtime": [None, ["UnixTimeStamp"]],
171 "ca_ctime": [None, ["UnixTimeStamp"]],
172 "ca_itime": [None, ["UnixTimeStamp"]],
173 "ca_btime": [None, ["UnixTimeStamp"]],
174 }],
175
176 "ifnet": [None, {
177 "if_name": [None, ["Pointer", dict(target="String")]],
178 }],
179
180 "session": [None, {
181 "s_login": [None, ["String"]],
182 }],
183
184 "filedesc": [None, {
185
186
187 "fd_ofileflags": [None, ["Pointer", dict(
188 target="Array",
189 target_args=dict(
190 target="Flags",
191 target_args=dict(
192 target="unsigned char",
193 maskmap=utils.MaskMapFromDefines("""
194 /*
195 * Per-process open flags.
196 */
197 #define UF_EXCLOSE 0x01 /* auto-close on exec */
198 #define UF_FORKCLOSE 0x02 /* auto-close on fork */
199 #define UF_RESERVED 0x04 /* open pending / in progress */
200 #define UF_CLOSING 0x08 /* close in progress */
201
202 #define UF_RESVWAIT 0x10 /* close in progress */
203 #define UF_INHERIT 0x20 /* "inherit-on-exec" */
204 """))))]],
205
206 "fd_ofiles": [None, ["Pointer", dict(
207 target="Array",
208 target_args=dict(
209 target="Pointer",
210 count=lambda x: x.fd_lastfile,
211 target_args=dict(
212 target="fileproc"
213 )
214 )
215 )]],
216 }],
217
218 "mount": [None, {
219
220 "mnt_flag": [None, ["Flags", dict(
221 maskmap={
222 "MNT_LOCAL": 0x00001000,
223 "MNT_QUOTA": 0x00002000,
224 "MNT_ROOTFS": 0x00004000,
225 }
226 )]],
227 }],
228
229 "vfsstatfs": [None, {
230 "f_mntonname": [None, ["String"]],
231 "f_mntfromname": [None, ["String"]],
232 "f_fstypename": [None, ["String"]],
233 }],
234
235 "sockaddr_un": [None, {
236
237
238
239
240
241
242
243 "sun_path": [None, ["String", dict(
244 length=lambda x: (
245 x.sun_len
246 - x.obj_profile.get_obj_offset("sockaddr_un", "sun_path")
247 ),
248 )]],
249 }],
250
251 "domain": [None, {
252
253 "dom_family": [None, ["Enumeration", dict(
254 enum_name="sa_family_t",
255 target="unsigned char",
256 )]],
257 }],
258
259 "tcpcb": [None, {
260 "t_state": [None, ["Enumeration", dict(
261
262 choices={
263 0: "TCPS_CLOSED",
264 1: "TCPS_LISTEN",
265 2: "TCPS_SYN_SENT",
266 3: "TCPS_SYN_RECEIVED",
267 4: "TCPS_ESTABLISHED",
268 5: "TCPS_CLOSE_WAIT",
269 6: "TCPS_FIN_WAIT_1",
270 7: "TCPS_CLOSING",
271 8: "TCPS_LAST_ACK",
272 9: "TCPS_FIN_WAIT_2",
273 10: "TCPS_TIME_WAIT",
274 },
275 target="int",
276 )]],
277 }],
278
279 "protosw": [None, {
280 "pr_protocol": [None, ["Enumeration", dict(
281
282 choices={
283 0: "IPPROTO_IP",
284 1: "IPPROTO_ICMP",
285 2: "IPPROTO_IGMP",
286 4: "IPPROTO_IPV4",
287 6: "IPPROTO_TCP",
288 17: "IPPROTO_UDP",
289 41: "IPPROTO_IPV6",
290 50: "IPPROTO_ESP",
291 51: "IPPROTO_AH",
292 58: "IPPROTO_ICMPV6",
293 255: "IPPROTO_RAW",
294 },
295 target="short",
296 )]],
297 "pr_type": [None, ["Enumeration", dict(
298 enum_name="pr_type",
299 target="short",
300 )]],
301 }],
302
303 "OSDictionary": [None, {
304 "dictionary": [None, ["Pointer", dict(
305 target="Array",
306 target_args=dict(
307 target="dictEntry",
308 count=lambda x: x.count,
309 )
310 )]],
311 }],
312
313 "OSString": [None, {
314 "value": lambda x: x.obj_profile.UnicodeString(
315 offset=x.string,
316 length=x.length
317 ),
318 }],
319
320 "OSOrderedSet": [None, {
321 "array": [None, ["Pointer", dict(
322 target="Array",
323 target_args=dict(
324 target="_Element",
325 count=lambda x: x.count
326 )
327 )]],
328 }],
329
330 "_Element": [8, {
331 "obj": [0, ["pointer", ["OSMetaClassBase"]]]
332 }],
333
334 "PE_state": [None, {
335 "bootArgs": [None, ["Pointer", dict(target="boot_args")]],
336 }],
337
338 "boot_args": [None, {
339 "CommandLine": [None, ["String"]]
340 }],
341
342 "EfiMemoryRange": [None, {
343
344 "Type": [None, ["Enumeration", dict(
345 choices={
346 0: "kEfiReservedMemoryType",
347 1: "kEfiLoaderCode",
348 2: "kEfiLoaderData",
349 3: "kEfiBootServicesCode",
350 4: "kEfiBootServicesData",
351 5: "kEfiRuntimeServicesCode",
352 6: "kEfiRuntimeServicesData",
353 7: "kEfiConventionalMemory",
354 8: "kEfiUnusableMemory",
355 9: "kEfiACPIReclaimMemory",
356 10: "kEfiACPIMemoryNVS",
357 11: "kEfiMemoryMappedIO",
358 12: "kEfiMemoryMappedIOPortSpace",
359 13: "kEfiPalCode",
360 14: "kEfiMaxMemoryType",
361 },
362 target="unsigned int"
363 )]],
364 }]
365 }
366
367
368 darwin_enums = {
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 "sa_family_t": utils.EnumerationFromDefines("""
387 /*
388 * Address families.
389 */
390 #define AF_UNSPEC 0 /* unspecified */
391 #define AF_UNIX 1 /* local to host (pipes) */
392 #define AF_INET 2 /* internetwork: UDP, TCP, etc. */
393 #define AF_IMPLINK 3 /* arpanet imp addresses */
394 #define AF_PUP 4 /* pup protocols: e.g. BSP */
395 #define AF_CHAOS 5 /* mit CHAOS protocols */
396 #define AF_NS 6 /* XEROX NS protocols */
397 #define AF_ISO 7 /* ISO protocols */
398 #define AF_ECMA 8 /* European computer manufacturers */
399 #define AF_DATAKIT 9 /* datakit protocols */
400 #define AF_CCITT 10 /* CCITT protocols, X.25 etc */
401 #define AF_SNA 11 /* IBM SNA */
402 #define AF_DECnet 12 /* DECnet */
403 #define AF_DLI 13 /* DEC Direct data link interface */
404 #define AF_LAT 14 /* LAT */
405 #define AF_HYLINK 15 /* NSC Hyperchannel */
406 #define AF_APPLETALK 16 /* Apple Talk */
407 #define AF_ROUTE 17 /* Internal Routing Protocol */
408 #define AF_LINK 18 /* Link layer interface */
409 #define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
410 #define AF_COIP 20 /* connection-oriented IP, aka ST II */
411 #define AF_CNT 21 /* Computer Network Technology */
412 #define pseudo_AF_RTIP 22 /* Help Identify RTIP packets */
413 #define AF_IPX 23 /* Novell Internet Protocol */
414 #define AF_SIP 24 /* Simple Internet Protocol */
415 #define pseudo_AF_PIP 25 /* Help Identify PIP packets */
416 #define AF_NDRV 27 /* Network Driver 'raw' access */
417 #define AF_ISDN 28 /* Integrated Services Digital Network*/
418 #define pseudo_AF_KEY 29 /* Internal key-management function */
419 #define AF_INET6 30 /* IPv6 */
420 #define AF_NATM 31 /* native ATM access */
421 #define AF_SYSTEM 32 /* Kernel event messages */
422 #define AF_NETBIOS 33 /* NetBIOS */
423 #define AF_PPP 34 /* PPP communication protocol */
424 #define pseudo_AF_HDRCMPLT 35 /* Used by BPF to not rewrite headers
425 * in interface output routine */
426 #define AF_AFP 36 /* Used by AFP */
427 #define AF_IEEE80211 37 /* IEEE 802.11 protocol */
428 #define AF_UTUN 38
429 #define AF_MULTIPATH 39
430 #define AF_MAX 40
431 """),
432
433
434
435 "pr_type": utils.EnumerationFromDefines("""
436 /*
437 * Types
438 */
439 #define SOCK_STREAM 1 /* stream socket */
440 #define SOCK_DGRAM 2 /* datagram socket */
441 #define SOCK_RAW 3 /* raw-protocol interface */
442 #define SOCK_RDM 4 /* reliably-delivered message */
443 #define SOCK_SEQPACKET 5 /* sequenced packet stream */
444 """),
445 }
446
447 darwin64_types = {
448 "LIST_ENTRY": [16, {
449 "le_next": [0, ["Pointer"]],
450 "le_prev": [8, ["Pointer", dict(target="Pointer")]],
451 }],
452 }
453
454
455 -class LIST_ENTRY(obj.Struct):
456 """XNU defines lists inline using an annonymous struct. This makes it hard
457 for us to automatically support lists because the debugging symbols dont
458 indicate this inner struct is of any particular type (since its annonymous).
459
460 We therefore depend on the overlays to redefine each list memeber as a
461 LIST_ENTRY member. For example we see code like:
462
463 struct proc {
464 LIST_ENTRY(proc) p_list;
465 ...
466
467 Where:
468
469 #define LIST_ENTRY(type) \
470 struct { \
471 struct type *le_next; /* next element */ \
472 struct type **le_prev; /* address of previous next element */ \
473 }
474 """
475 _forward = "le_next"
476 _backward = "le_prev"
477
478 - def is_valid(self):
479 """Must have both valid next and prev pointers."""
480 return (self.m(self._forward).is_valid() and
481 self.m(self._backward).is_valid())
482
483 - def _GetNextEntry(self, type, member):
484 return self.m(self._forward).dereference_as(type).m(member)
485
487 return self.m(self._backward).dereference_as(self.obj_type)
488
489 - def dereference_as(self, type, member, vm=None):
490 """Recasts the list entry as a member in a type, and return the type.
491
492 Args:
493 type: The name of this Struct type.
494 member: The name of the member of this Struct.
495 address_space: An optional address space to switch during
496 deferencing.
497 """
498 offset = self.obj_profile.get_obj_offset(type, member)
499
500 item = self.obj_profile.Object(
501 type_name=type, offset=self.obj_offset - offset,
502 vm=vm or self.obj_vm, parent=self.obj_parent,
503 name=type, context=self.obj_context)
504
505 return item
506
507 - def find_all_lists(self, type, member, seen=None):
508 """Follows all the list entries starting from lst.
509
510 We basically convert the list to a tree and recursively search it for
511 new nodes. From each node we follow the Flink and then the Blink. When
512 we see a node we already have, we backtrack.
513 """
514 if seen is None:
515 seen = set()
516
517 if not self.is_valid():
518 return seen
519
520 elif self in seen:
521 return seen
522
523 seen.add(self)
524
525 flink = self._GetNextEntry(type, member)
526 flink.find_all_lists(type, member, seen=seen)
527
528 blink = self._GetPreviousEntry()
529 blink.find_all_lists(type, member, seen=seen)
530
531 return seen
532
533 - def list_of_type(self, type, member=None, include_current=True):
534
535
536 result = sorted(self.find_all_lists(type, member),
537 key=lambda x: x.obj_offset)
538
539 if member is None:
540 member = self.obj_name
541
542
543 if include_current:
544 yield self.dereference_as(type, member)
545
546
547
548 for lst in result:
549
550
551 if lst.obj_offset == self.obj_offset:
552 continue
553
554 task = lst.dereference_as(type, member)
555 if task:
556
557 yield task
558
559 - def reflect(self, vm=None):
560 """Reflect this list element by following its Flink and Blink.
561
562 This is basically the same as Flink.Blink except that it also checks
563 Blink.Flink. It also ensures that Flink and Blink are dereferences to
564 the correct type in case the vtypes do not specify them as pointers.
565
566 Returns:
567 the result of Flink.Blink.
568 """
569 result1 = self.m(self._forward).dereference_as(
570 self.obj_type, vm=vm).m(self._backward).deref().cast(
571 self.obj_type)
572
573 if not result1:
574 return obj.NoneObject("Flink not valid.")
575
576 result2 = self.Blink.deref().dereference_as(
577 self.obj_type, vm=vm).m(
578 self._forward).dereference_as(self.obj_type)
579
580 if result1 != result2:
581 return obj.NoneObject("Flink and Blink not consistent.")
582
583 return result1
584
585 - def __nonzero__(self):
586
587 return bool(self.m(self._forward)) or bool(self.m(self._backward))
588
589 - def __iter__(self):
590 return self.list_of_type(self.obj_parent.obj_type, self.obj_name)
591
594 @utils.safe_property
596 try:
597 return self.la_rt.rt_llinfo.v() == self.obj_offset
598 except AttributeError:
599 return False
600
601
602 -class queue_entry(basic.ListMixIn, obj.Struct):
603 """A queue_entry is an externalized linked list.
604
605 Although the queue_entry is defined as:
606
607 struct queue_entry {
608 struct queue_entry *next; /* next element */
609 struct queue_entry *prev; /* previous element */
610 };
611
612 This is in fact not correct since the next, and prev pointers
613 point to the start of the next struct. A queue_entry has a queue
614 head which is also a queue entry and this can eb iterated over
615 using the list_of_type method.
616
617 NOTE: list_of_type should only be called on the head queue_entry.
618 """
619 _forward = "next"
620 _backward = "prev"
621
622 - def list_of_type(self, type, member):
623 seen = set()
624 seen.add(self.prev.v())
625
626 item = self.next.dereference_as(type)
627 while item != None:
628 yield item
629 if item.obj_offset in seen:
630 return
631 seen.add(item.obj_offset)
632 item = item.m(member).next.dereference_as(type)
633
637 result = []
638 for i in xrange(self.sdl_alen):
639 result.append(
640 "%.02X" % ord(self.sdl_data[self.sdl_nlen + i].v()))
641
642 return ":".join(result)
643
646 """Represents an open file, owned by a process."""
647
648 DTYPE_TO_HUMAN = {
649 "DTYPE_SOCKET": "socket",
650 "DTYPE_VNODE": "vnode",
651 "DTYPE_PSXSEM": "POSIX Semaphore",
652 "DTYPE_PSXSHM": "POSIX Shared Mem.",
653 "DTYPE_KQUEUE": "kernel queue",
654 "DTYPE_PIPE": "pipe",
655 "DTYPE_FSEVENTS": "FS Events",
656
657
658
659
660
661
662 "DTYPE_ATALK": "<unknown>",
663 "-": "INVALID",
664 }
665
666 @utils.safe_property
668 """Returns type of the fileglob (e.g. vnode, socket, etc.)"""
669 return self.multi_m(
670
671 "f_fglob.fg_type",
672
673
674 "f_fglob.fg_ops.fo_type")
675
676 @property
678 """Return the associated socket if the dtype is for socket."""
679 if self.fg_type == "DTYPE_SOCKET":
680 return self.f_fglob.fg_data.dereference_as("socket")
681
682 @property
684 """Return the associated vnode if the dtype is for vnode."""
685 if self.fg_type == "DTYPE_VNODE":
686 return self.f_fglob.fg_data.dereference_as("vnode")
687
689 """Returns the correct struct with fg_type-specific information.
690
691 This can be one of vnode, socket, shared memory or semaphore [1].
692
693 Of those four, we currently only get extra information for vnode and
694 socket. For everything else, we return a NoneObject.
695
696 [1]:
697 https://github.com/opensource-apple/xnu/blob/10.9/bsd/sys/file_internal.h#L184
698 """
699 dtype = self.fg_type
700
701
702
703 if dtype == "DTYPE_SOCKET":
704 return self.f_fglob.fg_data.dereference_as("socket")
705 elif dtype == "DTYPE_VNODE":
706 return self.f_fglob.fg_data.dereference_as("vnode")
707
708
709
710
711
712
713 return self.f_fglob.fg_data
714
715 @utils.safe_property
718
719 @utils.safe_property
727
730 """Provides human-readable accessors for sockets of the more common AFs.
731
732 This class has two basic ways of getting information. Most attributes are
733 computed using the method fill_socketinfo, which is directly adapted from
734 the kernel function of the same name. For the few things that
735 fill_socketinfo doesn't care about, the properties themselves get the
736 data and provide references to the kernel source for anyone wondering
737 why and how all this works.
738 """
739
740 cached_socketinfo = None
741
743 """Computes information about sockets of some addressing families.
744
745 This function is directly adapted from the kernel function
746 fill_socketinfo [1]. The original function is used to fill a struct
747 with addressing and other useful information about sockets of a few
748 key addressing families. All families are supported, but only the
749 following will return useful information:
750 - AF_INET (IPv4)
751 - AF_INET6 (IPv6)
752 - AF_UNIX (Unix socket)
753 - AF_NDRV (Network driver raw access)
754 - AF_SYSTEM (Darwin-specific; see documentation [3])
755
756 Differences between the kernel function and this adaptation:
757 - The kernel uses Protocol Families (prefixed with PF_). Rekall
758 relies on Addressing Families (AF_) which are exactly the same.
759
760 - The kernel fills a struct; this function returns a dict with the
761 same members.
762
763 - The kernel returns the data raw. This function converts endianness
764 and unions to human-readable representations, as appropriate.
765
766 - Only a subset of members are filled in.
767
768 - Other differences as documented in code.
769
770 Returns:
771 A dict with the same members as struct socket_info and related.
772 Only member that's always filled is "soi_kind". That's not Spanish,
773 but one of the values in this anonymous enum [2], which determines
774 what other members are present. (Read the code.)
775
776 [1]
777 https://github.com/opensource-apple/xnu/blob/10.9/bsd/kern/socket_info.c#L98
778 [2]
779 https://github.com/opensource-apple/xnu/blob/10.9/bsd/sys/proc_info.h#L503
780 [3] "KEXT Controls and Notifications"
781 https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/NKEConceptual/control/control.html
782 """
783 domain = self.so_proto.pr_domain.dom_family
784 type_name = self.so_proto.pr_type
785 protocol = self.so_proto.pr_protocol
786
787 si = {"soi_kind": "SOCKINFO_GENERIC"}
788
789
790
791 if domain in ["AF_INET", "AF_INET6"]:
792 si["soi_kind"] = "SOCKINFO_IN"
793
794 inp = self.so_pcb.dereference_as("inpcb")
795
796 si["insi_fport"] = utils.ntoh(inp.inp_fport)
797 si["insi_lport"] = utils.ntoh(inp.inp_lport)
798 si["insi_ip_ttl"] = inp.inp_ip_ttl.v()
799
800
801
802
803 if domain == "AF_INET":
804 si["insi_faddr"] = utils.FormatIPAddress(
805 "AF_INET",
806 inp.inp_dependfaddr.inp46_foreign.ia46_addr4.s_addr
807 )
808 si["insi_laddr"] = utils.FormatIPAddress(
809 "AF_INET",
810 inp.inp_dependladdr.inp46_local.ia46_addr4.s_addr
811 )
812 else:
813 si["insi_faddr"] = utils.FormatIPAddress(
814 "AF_INET6",
815 inp.inp_dependfaddr.inp6_foreign.m("__u6_addr")
816 )
817 si["insi_laddr"] = utils.FormatIPAddress(
818 "AF_INET6",
819 inp.inp_dependladdr.inp6_local.m("__u6_addr")
820 )
821
822 if (type_name == "SOCK_STREAM"
823 and (protocol == 0 or protocol == "IPPROTO_TCP")
824 and inp.inp_ppcb != None):
825
826 tp = inp.inp_ppcb.dereference_as("tcpcb")
827 si["soi_kind"] = "SOCKINFO_TCP"
828
829 si["tcpsi_state"] = tp.t_state
830 si["tcpsi_flags"] = tp.t_flags
831 elif domain == "AF_UNIX":
832 unp = self.so_pcb.dereference_as("unpcb")
833 si["soi_kind"] = "SOCKINFO_UN"
834
835 if unp.unp_addr:
836
837
838
839 si["unsi_addr"] = unp.unp_addr.sun_path
840
841 elif domain == "AF_NDRV":
842
843
844 si["soi_kind"] = "SOCKINFO_NDRV"
845 elif domain == "AF_SYSTEM":
846
847
848
849
850 if protocol == "SYSPROTO_EVENT":
851
852
853 si["soi_kind"] = "SOCKINFO_KERN_EVENT"
854 elif protocol == "SYSPROTO_CONTROL":
855 kcb = self.so_pcb.dereference_as("ctl_cb")
856 kctl = kcb.kctl
857 si["soi_kind"] = "SOCKINFO_KERN_CTL"
858
859 if kctl:
860 si["kcsi_id"] = kctl.id
861 si["kcsi_name"] = kctl.name
862
863 return si
864
878
879 @utils.safe_property
881 """For IPv[46] sockets, return source IP as string."""
882 return self.get_socketinfo_attr("insi_laddr")
883
884 @utils.safe_property
886 """For IPv[46] sockets, return destination IP as string."""
887 return self.get_socketinfo_attr("insi_faddr")
888
889 @utils.safe_property
891 """The Addressing Family corresponds roughly to OSI layer 3."""
892 return self.so_proto.pr_domain.dom_family
893
894 @utils.safe_property
897
898 @utils.safe_property
900 """For Unix sockets, pointer to vnode, if any.
901
902 This is the same way that OS gathers this information in response to
903 syscall [1] (this is the API used by netstat, among others).
904
905 1:
906 https://github.com/opensource-apple/xnu/blob/10.9/bsd/kern/uipc_usrreq.c#L1683
907 """
908 if self.addressing_family == "AF_UNIX":
909 return self.so_pcb.dereference_as("unpcb").unp_vnode
910
911 @utils.safe_property
913 """For Unix sockets, the pcb of the paired socket. [1]
914
915 You most likely want to do sock.conn_pcb.unp_socket to get at the
916 other socket in the pair. However, because the sockets are paired
917 through the protocol control block, it's actually useful to have
918 a direct pointer at it in order to be able to spot paired sockets.
919
920 1:
921 https://github.com/opensource-apple/xnu/blob/10.9/bsd/sys/unpcb.h#L128
922 """
923 if self.addressing_family == "AF_UNIX":
924 return self.so_pcb.dereference_as("unpcb").unp_conn
925
926 @utils.safe_property
929
930 @utils.safe_property
933
934 @utils.safe_property
936 if self.addressing_family in ["AF_INET", "AF_INET6"]:
937
938 return str(self.so_proto.pr_protocol).replace("IPPROTO_", "")
939
940 @utils.safe_property
942 if self.addressing_family == "AF_UNIX":
943 pr_type = str(self.so_proto.pr_type)
944
945 if pr_type:
946
947 return pr_type.replace("SOCK_", "")
948 else:
949
950
951
952 return "Unix Socket"
953
954 @utils.safe_property
968
969 @utils.safe_property
987
991 addr = obj.NoneObject("Unknown socket family")
992
993 if self.sa_family == "AF_INET":
994 addr = self.cast("sockaddr_in").sin_addr.s_addr
995
996 elif self.sa_family == "AF_INET6":
997 addr = self.cast("sockaddr_in6").sin6_addr.m("__u6_addr")
998
999 elif self.sa_family == "AF_LINK":
1000 addr = self.cast("sockaddr_dl")
1001
1002 return addr
1003
1004 @utils.safe_property
1006 result = ""
1007 addr = self._get_address_obj()
1008 if addr:
1009 if self.sa_family in ("AF_INET6", "AF_INET"):
1010 result = utils.FormatIPAddress(self.sa_family, addr)
1011
1012 elif self.sa_family == "AF_LINK":
1013 result = addr
1014
1015 return str(result)
1016
1019
1020
1021 -class vm_map_entry(obj.Struct):
1023 """Find the underlying vnode object for the given vm_map_entry.
1024
1025 xnu-2422.1.72/osfmk/vm/bsd_vm.c: 1339.
1026 """
1027 if not self.is_sub_map.v():
1028
1029
1030
1031
1032
1033 shadow = self.last_shadow
1034 if not shadow:
1035 return shadow
1036
1037 if (shadow and not shadow.internal.v() and
1038 shadow.pager_ready.v() and
1039 not shadow.terminating.v() and
1040 shadow.alive.v()):
1041 memory_object = shadow.pager
1042 pager_ops = memory_object.mo_pager_ops
1043
1044
1045
1046
1047
1048
1049 if pager_ops == self.obj_profile.get_constant(
1050 "_vnode_pager_ops", is_address=True):
1051 return shadow.pager.dereference_as(
1052 "vnode_pager").vnode_handle
1053
1054 return obj.NoneObject("vnode not found")
1055
1056 @utils.safe_property
1057 - def sharing_mode(self):
1058 """Returns the sharing mode of the backing vm_object.
1059
1060 This is losely adapted from vm_map.c, void vm_map_region_top_walk(),
1061 except we're not filling page counts for resident/reusable, etc.
1062 """
1063 if not self.vmo_object or self.is_sub_map:
1064 return "SM_EMPTY"
1065
1066 vmobj = self.vmo_object
1067 ref_count = vmobj.ref_count
1068 if vmobj.paging_in_progress:
1069 ref_count -= 1
1070
1071 if vmobj.shadow:
1072 return "SM_COW"
1073
1074 if self.superpage_size:
1075 return "SM_LARGE_PAGE"
1076
1077 if self.needs_copy:
1078 return "SM_COW"
1079
1080 if ref_count == 1 or (not vmobj.pager_trusted and not
1081 vmobj.internal):
1082 return "SM_PRIVATE"
1083
1084 return "SM_SHARED"
1085
1086 @utils.safe_property
1087 - def code_signed(self):
1089
1090 @utils.safe_property
1091 - def last_shadow(self):
1092 shadow = self.vmo_object
1093 if not shadow:
1094 return obj.NoneObject("no vm_object found")
1095
1096 while shadow.shadow:
1097 shadow = shadow.shadow
1098
1099 return shadow
1100
1101 @utils.safe_property
1103 return self.links.start.v()
1104
1105 @utils.safe_property
1107 return self.links.end.v()
1108
1109 @utils.safe_property
1110 - def vmo_object(self):
1111 """Return the vm_object instance for this entry.
1112
1113 There's an intermediate link called struct vm_map_entry.
1114
1115 The members will be called either 'object' and 'vm_object' or
1116 'vme_object' and 'vmo_object'.
1117
1118 There is no easy heuristic for which it will be in a particular kernel
1119 version* so we just try both, since they mean the same thing.
1120
1121 * The kernel version numbers could be identical for kernels built from
1122 a feature branch and a kernel build from trunk, and the two could be
1123 months apart. Furthermore, the profiles are generated not from the
1124 kernel itself but from a debug kit and can end up using out of date
1125 naming conventions.
1126 """
1127 vme_object = self.multi_m("vme_object", "object")
1128 return vme_object.multi_m("vmo_object", "vm_object")
1129
1130
1131 -class clist(obj.Struct):
1132
1133 @utils.safe_property
1135 """Gets the full contents of the ring buffer, which may be freed.
1136
1137 This is different from getting the legal contents as with b_to_q [1]
1138 because clists are only used by TTYs and they seem to always be all
1139 marked as consumed, so b_to_q wouldn't let us see any content.
1140
1141 1: github.com/opensource-apple/xnu/blob/10.9/bsd/kern/tty_subr.c#L358
1142 """
1143 return utils.HexDumpedString(
1144 self.obj_vm.read(self.c_cs, self.c_cn))
1145
1146 @utils.safe_property
1148 return int(self.c_cn)
1149
1150
1151 -class tty(obj.Struct):
1152 @utils.safe_property
1154 return self.t_session.s_ttyvp
1155
1156 @utils.safe_property
1159
1160 @utils.safe_property
1163
1164
1165 -class proc(obj.Struct):
1166 """Represents a Darwin process."""
1167
1168 @utils.safe_property
1170 return self.task.map.hdr.walk_list("links.next", include_current=False)
1171
1173 """Gets all open files (sockets, pipes...) owned by this proc.
1174
1175 Yields:
1176 tuple of (fd, fileproc, flags)
1177 """
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196 last_fd = self.p_fd.fd_lastfile
1197 ofiles = self.p_fd.fd_ofiles.deref()
1198 ofileflags = self.p_fd.fd_ofileflags
1199
1200 for fd in xrange(last_fd + 1):
1201 file_obj = ofiles[fd].deref()
1202
1203
1204
1205
1206
1207
1208 if file_obj:
1209 yield (fd, file_obj, ofileflags[fd])
1210
1212 cr3 = self.task.map.pmap.pm_cr3
1213 as_class = self.obj_vm.__class__
1214 if self.task.map.pmap.pm_task_map == "TASK_MAP_64BIT_SHARED":
1215 as_class = amd64.AMD64PagedMemory
1216
1217 return as_class(base=self.obj_vm.base, session=self.obj_vm.session,
1218 dtb=cr3, name="Pid %s" % self.p_pid)
1219
1220 @utils.safe_property
1222 return utils.SmartUnicode(self.p_comm)
1223
1224 @utils.safe_property
1226 return self.task.map.pmap.pm_cr3
1227
1228 @utils.safe_property
1230 return proc.task.map.pmap.pm_task_map == "TASK_MAP_64BIT"
1231
1232 @utils.safe_property
1234 result = []
1235 array = self.obj_profile.ListArray(
1236 target="String",
1237 offset=self.user_stack - self.p_argslen,
1238 vm=self.get_process_address_space(),
1239 maximum_size=self.p_argslen,
1240 )
1241
1242 for item in array:
1243
1244
1245 if len(result) >= self.p_argc:
1246 break
1247
1248 item = unicode(item)
1249
1250
1251
1252 if not len(item):
1253 continue
1254
1255 result.append(item)
1256
1257
1258
1259 if len(result) > 1 and result[0] == result[1]:
1260 result.pop(0)
1261
1262 return result
1263
1265 """Use heuristics to guess whether this proc is valid."""
1266 return (self.p_argc > 0
1267 and len(self.p_comm) > 0
1268 and self.p_start.v() > 0
1269 and 99999 > self.pid > 0)
1270
1271
1272 -class vnode(obj.Struct):
1273 @utils.safe_property
1275
1276 result = []
1277 _vnode = self
1278
1279
1280 while not (_vnode.v_flag.VROOT and
1281 _vnode.v_mount.mnt_flag.MNT_ROOTFS):
1282 result.append(_vnode.v_name.deref())
1283
1284
1285 _vnode = _vnode.v_parent or _vnode.v_mount.mnt_vnodecovered
1286
1287
1288
1289 if not _vnode:
1290 self.obj_session.logging.warning("vnode at 0x%x is orphaned.",
1291 int(_vnode))
1292 return "<Orphan>"
1293
1294 path = "/" + "/".join((str(x) for x in reversed(result) if x))
1295 return unicode(path.encode("string-escape"))
1296
1297
1298 @utils.safe_property
1301
1302 @utils.safe_property
1305
1306 @utils.safe_property
1308 """If this is an HFS vnode, then v_data is a cnode."""
1309 node = self.v_data.dereference_as("cnode")
1310 if node.c_rwlock != node:
1311 return obj.NoneObject("This vnode has no valid cnode.")
1312
1313 return node
1314
1315 @utils.safe_property
1317 uid = self.v_cred.cr_posix.cr_ruid
1318 if uid:
1319 return uid
1320
1321 return obj.NoneObject("Could not retrieve POSIX creds.")
1322
1323
1324 -class cnode(obj.Struct):
1325 @utils.safe_property
1328
1329 @utils.safe_property
1332
1333 @utils.safe_property
1336
1337 @utils.safe_property
1340
1341
1342 -class zone(obj.Struct):
1343 @utils.safe_property
1346
1347 @utils.safe_property
1349 return int(self.count)
1350
1351 @utils.safe_property
1353 return int(self.m("sum_count") - self.count)
1354
1355 @utils.safe_property
1356 - def tracks_pages(self):
1357 return bool(self.m("use_page_list"))
1358
1359 @utils.safe_property
1361 """Find valid offsets in the zone as tuples of (state, offset).
1362
1363 Allocation zones keep track of potential places where an element of
1364 fixed size may be stored. The most basic zones only keep track of free
1365 pointers, so as to speed up allocation. Some zones also track already
1366 allocated data, using a separate mechanism. We support both.
1367
1368 Returns a set of tuples of:
1369 - State, which can be "freed", "allocated" or "unknown".
1370 - Object offset, at which a struct may be located.
1371 (You will want to validate the struct itself for sanity.)
1372 """
1373
1374 seen_offsets = set()
1375
1376
1377 seen_pages = set()
1378
1379
1380 for element in self.free_elements.walk_list("next"):
1381 seen_offsets.add(element.obj_offset)
1382
1383
1384
1385
1386
1387 for offset in seen_offsets.copy():
1388
1389
1390 page_start = offset & ~0xfff
1391 if page_start in seen_pages:
1392 continue
1393
1394 seen_pages.add(page_start)
1395 seen_offsets.update(set(self._generate_page_offsets(page_start)))
1396
1397
1398
1399
1400 page_lists = {"all_free", "all_used", "intermediate"}
1401
1402
1403 if self.m("use_page_list"):
1404 for page_list in page_lists:
1405 for page_start in self.m(page_list).walk_list("next"):
1406 if page_start in seen_pages:
1407 continue
1408
1409 seen_pages.add(page_start)
1410 seen_offsets.update(self._generate_page_offsets(page_start))
1411
1412 return seen_offsets
1413
1414 - def _generate_page_offsets(self, page_start):
1415 limit = page_start + 0x1000 - self.elem_size
1416
1417
1418 limit -= self.obj_profile.get_obj_size("zone_page_metadata")
1419
1420 return xrange(page_start, limit, self.elem_size)
1421
1422
1423 -class ifnet(obj.Struct):
1424 @utils.safe_property
1426 return "%s%d" % (self.if_name.deref(), self.if_unit)
1427
1428 @utils.safe_property
1430
1431 for tqe in self.if_addrhead.tqh_first.walk_list(
1432 "ifa_link.tqe_next"):
1433 family = tqe.ifa_addr.sa_family
1434
1435
1436 if family == "AF_LINK":
1437 l2_addr = utils.SmartUnicode(tqe.ifa_addr.deref())
1438 yield ("MAC", l2_addr)
1439 continue
1440 elif family == "AF_INET":
1441 l3_proto = "IPv4"
1442 elif family == "AF_INET6":
1443 l3_proto = "IPv6"
1444 else:
1445 l3_proto = utils.SmartUnicode(family).replace("AF_", "")
1446
1447 l3_addr = utils.SmartUnicode(tqe.ifa_addr.deref())
1448 yield (l3_proto, l3_addr)
1449
1450 @utils.safe_property
1452 for proto, addr in self.addresses:
1453 if proto == "MAC":
1454 return addr
1455
1456 @utils.safe_property
1458 return [(proto, addr) for proto, addr in self.addresses
1459 if proto != "MAC"]
1460
1461 @utils.safe_property
1463 result = []
1464 for proto, addr in self.addresses:
1465 if proto == "IPv4":
1466 result.append(addr)
1467
1468 return ", ".join(result)
1469
1470 @utils.safe_property
1472 result = []
1473 for proto, addr in self.addresses:
1474 if proto == "IPv6":
1475 result.append(addr)
1476
1477 return ", ".join(result)
1478
1481 @utils.safe_property
1484
1485 @utils.safe_property
1487 return "Session %d (%s)" % (self.s_sid, self.s_leader.command)
1488
1489 @utils.safe_property
1491 return utils.SmartUnicode(self.s_login)
1492
1493 @utils.safe_property
1496
1499 """The OSDictionary is a general purpose associative array described:
1500
1501 xnu-1699.26.8/libkern/libkern/c++/OSDictionary.h
1502 """
1503
1504 - def items(self, value_class=None):
1505 """Iterate over the associative array and yield key, value pairs."""
1506 for entry in self.dictionary:
1507 key = entry.key.dereference_as("OSString").value
1508 if value_class:
1509 yield key, entry.value.dereference_as(value_class)
1510 else:
1511 yield key, entry.value
1512
1515 """An OSOrderedSet is a list of OSObject instances.
1516
1517 xnu-1699.26.8/libkern/libkern/c++/OSOrderedSet.h
1518 """
1519
1523
1524
1525 -class Darwin32(basic.Profile32Bits, basic.BasicClasses):
1526 """A Darwin profile."""
1527 METADATA = dict(
1528 os="darwin",
1529 arch="I386",
1530 type="Kernel")
1531
1532 @classmethod
1534 super(Darwin32, cls).Initialize(profile)
1535
1536
1537
1538
1539 for k in profile.vtypes.keys():
1540 if k.endswith("_class"):
1541 stripped_k = k[:-len("_class")]
1542 if stripped_k not in profile.vtypes:
1543 profile.vtypes[stripped_k] = profile.vtypes[k]
1544 if stripped_k in darwin_overlay:
1545 darwin_overlay[k] = darwin_overlay[stripped_k]
1546
1547 profile.add_classes(
1548 LIST_ENTRY=LIST_ENTRY, queue_entry=queue_entry,
1549 sockaddr=sockaddr, sockaddr_dl=sockaddr_dl,
1550 vm_map_entry=vm_map_entry, proc=proc, vnode=vnode,
1551 socket=socket, clist=clist, zone=zone, ifnet=ifnet, tty=tty,
1552
1553 OSDictionary=OSDictionary, OSDictionary_class=OSDictionary,
1554 OSOrderedSet=OSOrderedSet, OSOrderedSet_class=OSOrderedSet,
1555 fileproc=fileproc, session=session, cnode=cnode,
1556 llinfo_arp=llinfo_arp)
1557 profile.add_enums(**darwin_enums)
1558 profile.add_overlay(darwin_overlay)
1559 profile.add_constants(dict(default_text_encoding="utf8"))
1560
1562 """A variant of get_constant_object which accounts for name mangling."""
1563 for key in self.constants:
1564 if constant in key:
1565 return self.get_constant_object(key, **kwargs)
1566
1567
1568 -class Darwin64(basic.RelativeOffsetMixin, basic.ProfileLP64, Darwin32):
1569 """Support for 64 bit darwin systems."""
1570 METADATA = dict(
1571 os="darwin",
1572 arch="AMD64",
1573 type="Kernel")
1574
1575 image_base = 0
1576
1577 @classmethod
1581
1588