def collect(self, hint, sessions): for entity in sessions: session = entity["Struct/base"] # Have to sanitize the usernames to prevent issues when comparing # them later. username = str(session.s_login).replace("\x00", "") if username: user_identity = self.manager.identify( {"User/username": username}) yield [user_identity, definitions.User(username=username)] else: user_identity = None sid = session.s_sid # Turns out, SID is not always unique. This is disabled as it is # not being currently used, and I need to investigate the causes # of duplicate sessions occurring on 10.10. # session_identity = self.manager.identify({ # "Session/sid": sid}) | entity.identity session_identity = entity.identity if session.s_ttyp: yield definitions.Struct(base=session.s_ttyp, type="tty") if session.s_leader: yield definitions.Struct(base=session.s_leader.deref(), type="proc") yield [ session_identity, definitions.Session(user=user_identity, sid=sid), definitions.Named(name="SID %d" % int(sid), kind="Session") ]
def collect(self, hint): if self.profile_name: profile = self.session.address_resolver.LoadProfileForName( self.profile_name) else: profile = self.session.profile if not profile: raise RuntimeError("Unable to load profile %s" % self.profile_name) if self.scan_kernel_vm: address_space = self.session.kernel_address_space else: address_space = self.session.physical_address_space scanner = ConfiguredPoolScanner.configure( type_name=self.type_name, tag_name=self.tag_name, session=self.session, profile=profile, address_space=address_space) for pool_obj in scanner.scan(): pool_header_end = pool_obj.obj_offset + pool_obj.obj_size struct = profile.Object(type_name=self.type_name, vm=address_space, offset=pool_header_end) yield definitions.Struct(base=struct, type=self.type_name)
def collect(self, hint, zones): for element, state in self.collect_base_objects( zone_name=self.zone_name, zones=zones): yield definitions.Struct( base=element, type=self.type_name, state=state)
def collect(self, hint): # Note that _pgrphash is initialized through: # # xnu-1699.26.8/bsd/kern/kern_proc.c:195 # hashinit(int elements, int type, u_long *hashmask) # # /xnu-1699.26.8/bsd/kern/kern_subr.c: 327 # hashinit(int elements, int type, u_long *hashmask) { # ... # *hashmask = hashsize - 1; # # Hence the value in _pgrphash is one less than the size of the hash # table. pgr_hash_table = self.profile.get_constant_object( "_pgrphashtbl", target="Pointer", target_args=dict(target="Array", target_args=dict( target="pgrphashhead", count=self.profile.get_constant_object( "_pgrphash", "unsigned long") + 1))) for slot in pgr_hash_table.deref(): for pgrp in slot.lh_first.walk_list("pg_hash.le_next"): for proc in pgrp.pg_members.lh_first.walk_list( "p_pglist.le_next"): yield definitions.Struct(base=proc, type="proc")
def collect(self, hint): ifnet_head = self.profile.get_constant_object( "_dlil_ifnet_head", target="Pointer", target_args=dict(target="ifnet")) for ifnet in ifnet_head.walk_list("if_link.tqe_next"): yield [definitions.Struct(base=ifnet, type="ifnet")]
def collect(self, hint): for head_const in ["_unp_dhead", "_unp_shead"]: lhead = self.session.get_constant_object(head_const, target="unp_head") for unp in lhead.lh_first.walk_list("unp_link.le_next"): yield [ definitions.Struct(base=unp.unp_socket, type="socket"), definitions.Named(kind="Unix Socket") ]
def collect(self, hint): PspCidTable = self.profile.get_constant_object( "PspCidTable", target="Pointer", target_args=dict(target="_PSP_CID_TABLE")) # Walk the handle table for handle in PspCidTable.handles(): if handle.get_object_type() == "Process": yield definitions.Struct( type="_EPROCESS", base=handle.dereference_as("_EPROCESS"))
def collect(self, hint): tasks = self.profile.get_constant_object( "_tasks", target="queue_entry", vm=self.session.kernel_address_space) for task in tasks.list_of_type("task", "tasks"): proc = task.bsd_info.deref() if not proc: continue yield definitions.Struct(base=proc, type="proc")
def collect(self, hint, processes): manager = self.manager for process in processes: proc = process["Struct/base"] for fd, fileproc, flags in proc.get_open_files(): fg_data = fileproc.autocast_fg_data() # The above can return None if the data in memory is invalid. # There's nothing we can do about that, other than rely on # collector redundancy. Skip. if not fg_data: continue # In addition to yielding the handle, we will also yield the # resource it's pointing to, because other collectors rely on # memory objects already being out there when they parse them # for resource (File/Socket/etc.) specific information. resource_identity = manager.identify({ "Struct/base": fg_data}) handle_identity = manager.identify({ "Struct/base": fileproc}) yield [ resource_identity, definitions.Struct( base=fg_data, type=fg_data.obj_type)] yield [ handle_identity, definitions.Handle( process=process.identity, fd=fd, flags=flags, resource=resource_identity), definitions.Struct( base=fileproc, type="fileproc")]
def collect(self, hint, ttys): for entity in ttys: file_identity = None session_identity = None tty = entity["Struct/base"] session = tty.t_session.deref() vnode = session.s_ttyvp if session: session_identity = self.manager.identify( {"Struct/base": session}) if vnode: # Look, it has a vnode! yield definitions.Struct(base=vnode, type="vnode") file_identity = self.manager.identify({"Struct/base": vnode}) # Yield just the stubs of the input and output ring buffers. # DarwinClistParser will grab these if it cares. yield [ definitions.Struct(base=tty.t_rawq, type="clist"), definitions.Buffer(purpose="terminal_input", context=entity.identity) ] yield [ definitions.Struct(base=tty.t_outq, type="clist"), definitions.Buffer(purpose="terminal_output", context=entity.identity) ] # Last, but not least, the Terminal itself. yield [ entity.identity, definitions.Terminal(session=session_identity, file=file_identity) ]
def collect(self, hint, sessions): for entity in sessions: session = entity["Struct/base"] # Have to sanitize the usernames to prevent issues when comparing # them later. username = str(session.s_login).replace("\x00", "") if username: user_identity = self.manager.identify({ "User/username": username}) yield [user_identity, definitions.User( username=username)] else: user_identity = None sid = session.s_sid session_identity = self.manager.identify({ "Session/sid": sid}) | entity.identity if session.s_ttyp: yield definitions.Struct( base=session.s_ttyp, type="tty") yield definitions.Struct( base=session.s_leader.deref(), type="proc") yield [session_identity, definitions.Session( user=user_identity, sid=sid), definitions.Named( name="SID %d" % int(sid), kind="Session")]
def collect(self, hint): session_hash_table_size = self.profile.get_constant_object( "_sesshash", "unsigned long") # The hashtable is an array to session list heads. session_hash_table = self.profile.get_constant_object( "_sesshashtbl", target="Pointer", target_args=dict(target="Array", target_args=dict( target="sesshashhead", count=session_hash_table_size.v()))) for sesshashhead in session_hash_table: for session in sesshashhead.lh_first.walk_list("s_hash.le_next"): yield definitions.Struct(base=session, type="session")
def collect(self, hint): pid_hash_table = self.profile.get_constant_object( "_pidhashtbl", target="Pointer", target_args=dict(target="Array", target_args=dict( target="pidhashhead", count=self.profile.get_constant_object( "_pidhash", "unsigned long") + 1))) for plist in pid_hash_table.deref(): for proc in plist.lh_first.walk_list("p_hash.le_next"): if not proc: continue yield definitions.Struct(base=proc, type="proc")
def collect(self, hint, procs): manager = self.manager for entity in procs: proc = entity["Struct/base"] user_identity = manager.identify({"User/uid": proc.p_uid}) process_identity = manager.identify({ ("Process/pid", "Timestamps/created_at"): (proc.pid, proc.p_start.as_datetime()) }) # kern_proc.c:2706 session = proc.p_pgrp.pg_session if session: session_identity = manager.identify({"Struct/base": session}) yield definitions.Struct(base=session, type="session") else: session_identity = None cr3 = proc.task.map.pmap.pm_cr3 if cr3: cr3_ptr = proc.obj_profile.Pointer( vm=self.session.physical_address_space, target="void", value=proc.task.map.pmap.pm_cr3) else: cr3_ptr = None yield [ # Reuse the base object identity but also use the PID. process_identity | entity.identity, definitions.Timestamps(created_at=proc.p_start.as_datetime()), definitions.Process(pid=proc.pid, command=utils.SmartUnicode(proc.p_comm), user=user_identity, cr3=cr3_ptr, is_64bit=proc.task.map.pmap.pm_task_map == "TASK_MAP_64BIT", session=session_identity), definitions.Named(name="%s (pid=%d)" % (proc.p_comm, proc.pid), kind="Process") ] # We don't know much about the user at this stage, but this # is still kind of useful in getting at least a list of UIDs. # Once we have more robustness in listing users this can go away. yield [user_identity, definitions.User(uid=proc.p_uid)]
def collect(self, hint): first_zone = self.profile.get_constant_object( "_first_zone", target="Pointer", target_args=dict( target="zone")) for zone in first_zone.walk_list("next_zone"): yield [ definitions.AllocationZone( name=zone.zone_name.deref(), count_active=int(zone.count), count_free=int(zone.m("sum_count") - zone.count), element_size=zone.elem_size, tracks_pages=bool(zone.m("use_page_list")), allows_foreign=bool(zone.allows_foreign)), definitions.Struct( base=zone, type="zone")]
def collect(self, hint, eprocesses): for process in eprocesses: eproc = process["Struct/base"] for handle in eproc.ObjectTable.handles(): resource_type = handle.get_object_type(eproc.obj_vm) vtype = self.TYPES_MAP.get(resource_type) if not vtype: continue base = handle.dereference_as(vtype) base_id = self.manager.identify({"Struct/base": base}) _, handle = self.prebuild(components=[ definitions.Handle(process=process.identity, resource=base_id, fd=handle.HandleValue) ], keys=("Handle/process", "Handle/fd", "Handle/resource")) yield [base_id, definitions.Struct(base=base, type=vtype)] yield handle
def collect(self, hint, sockets): for socket in sockets: base_socket = socket["Struct/base"] family = str(base_socket.addressing_family).replace("AF_", "") if family in ("INET", "INET6"): l3_protocol = "IPv4" if family == "INET" else "IPv6" source_identity, source = self.prebuild( components=[ definitions.OSILayer3(address=base_socket.src_addr, protocol=l3_protocol), definitions.OSILayer4(port=base_socket.src_port, protocol=base_socket.l4_protocol, state=base_socket.tcp_state) ], keys=("OSILayer3/address", "OSILayer4/port", "OSILayer4/protocol")) destination_identity, destination = self.prebuild( components=[ definitions.OSILayer3(address=base_socket.dst_addr, protocol=l3_protocol), definitions.OSILayer4(port=base_socket.dst_port, protocol=base_socket.l4_protocol) ], keys=("OSILayer3/address", "OSILayer4/port", "OSILayer4/protocol")) connection = [ socket.identity, definitions.Named(name=base_socket.human_name, kind="IP Connection"), definitions.Connection(protocol_family=family, source=source_identity, destination=destination_identity) ] yield source yield destination yield connection elif family == "UNIX": if base_socket.vnode: path = base_socket.vnode.full_path file_identity = self.session.entities.identify( {"File/path": path}) else: path = None file_identity = None yield [ socket.identity, definitions.Named(name=base_socket.human_name, kind="Unix Socket"), definitions.Connection(protocol_family="UNIX"), definitions.Socket( type=base_socket.unix_type, file=file_identity, address="0x%x" % int(base_socket.so_pcb), connected="0x%x" % int(base_socket.unp_conn)) ] # There may be a vnode here - if so, yield it. if path: yield [ definitions.File(path=path, type="socket"), definitions.Named(name=path, kind="Socket"), definitions.Struct(base=base_socket.vnode.deref(), type="vnode") ] else: yield [ socket.identity, definitions.Named(kind="Unknown Socket"), definitions.Connection(protocol_family=family) ]
def collect(self, hint): allproc = self.profile.get_constant_object("_allproc", target="proclist") for proc in allproc.lh_first.p_list: yield definitions.Struct(base=proc, type="proc")
def collect(self, hint): phead = self.session.GetParameter("PsActiveProcessHead") for proc in phead.list_of_type("_EPROCESS", "ActiveProcessLinks"): yield definitions.Struct(type="_EPROCESS", base=proc)
def collect(self, hint, procs): # We're going to have a much better time if we can ignore processes # that aren't relevant. hint_filter = hint.run_engine("hinter", selector="MemoryDescriptor/process") for proc in procs: if (hint_filter and not hint_filter.run_engine("matcher", bindings=proc)): continue vm = proc["Struct/base"].get_process_address_space() arch = "x86_32" if vm.end() <= 0x1000000000 else "x86_64" vm_identity, vm_entity = self.prebuild(components=[ definitions.AddressSpace(dtb=vm.dtb, type="virtual", architecture=arch, owner=proc.identity), definitions.Named(kind="Virtual Address Space", name="DTB @%#016x" % vm.dtb) ], keys=("AddressSpace/dtb", )) yield vm_entity for address in proc["Struct/base"].task.map.hdr.walk_list( "links.next", include_current=False): # Is this range backed by a vnode? If so yield it, and save the # identity. This should take care of __TEXT, __LINKEDIT and # memory mapped sections. vnode = address.find_vnode_object() file_identity = None if vnode: file_identity, file = self.prebuild(components=[ definitions.Struct(base=vnode, type="vnode") ], keys=("Struct/base", )) yield file # Sort out shared memory flags. sharing_mode = address.sharing_mode if sharing_mode in ("SM_SHARED", "SM_LARGE_PAGE"): sharing_enum = "shared" elif sharing_mode == "SM_COW": sharing_enum = "copy-on-write" elif sharing_mode == "SM_PRIVATE": sharing_enum = "private" elif sharing_mode == "SM_EMPTY": sharing_mode = None else: raise ValueError("Unknown sharing mode %r." % sharing_mode) # Sort out permission bits. perms = [] max_perms = [] for flag in address.protection: perm = self.PROTECTION_FLAGS.get(flag) if not perm: raise ValueError("Unknown protection flag %r." % flag) perms.append(perm) for flag in address.max_protection: perm = self.PROTECTION_FLAGS.get(flag) if not perm: raise ValueError("Unknown protection flag %r." % flag) max_perms.append(perm) _, result = self.prebuild( components=[ definitions.MemoryDescriptor( start=obj.Void(vm=vm, profile=self.session.profile, offset=address.links.start.v()), end=obj.Void(vm=vm, profile=self.session.profile, offset=address.links.end.v()), address_space=vm_identity, permissions=perms, max_permissions=max_perms, file=file_identity, shared=sharing_enum, code_signed=address.code_signed), definitions.Struct(base=address, type="vm_map_entry") ], keys=("MemoryDescriptor/address_space", "MemoryDescriptor/start", "MemoryDescriptor/end")) yield result