def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks.calculate(self) for proc in procs: space = proc.get_process_address_space() for map in proc.get_proc_maps(): # only read/write without filebacks if not (map.get_perms() == "rw-" and not map.get_path()): continue # check the header for sqlite3 signature header = space.zread(map.links.start, 32) if "SQLite format" not in header: continue # get the whole sqlite3 data now data = space.zread(map.links.start, map.links.end - map.links.start) for offset in utils.iterfind(data, ":ABPerson"): person = obj.Object("String", offset = map.links.start + offset, vm = space, encoding = "utf8", length = 256) yield proc, person
def calculate(self): common.set_plugin_members(self) first_zone_addr = self.addr_space.profile.get_symbol("_first_zone") if first_zone_addr: zone_ptr = obj.Object("Pointer", offset=first_zone_addr, vm=self.addr_space) zone = zone_ptr.dereference_as("zone") while zone: yield zone zone = zone.next_zone else: zone_ptr = self.addr_space.profile.get_symbol("_zone_array") zone_arr = obj.Object( theType="Array", targetType="zone", vm=self.addr_space, count=256, offset=zone_ptr, ) for zone in zone_arr: if zone.is_valid(): yield zone
def calculate(self): common.set_plugin_members(self) list_head_addr = self.addr_space.profile.get_symbol("_dlil_ifnet_head") list_head_ptr = obj.Object("Pointer", offset = list_head_addr, vm = self.addr_space) ifnet = list_head_ptr.dereference_as("ifnet") while ifnet: name = ifnet.if_name.dereference() unit = ifnet.if_unit prom = ifnet.if_flags & 0x100 == 0x100 # IFF_PROMISC addr_dl = obj.Object("sockaddr_dl", offset = ifnet.if_lladdr.ifa_addr.v(), vm = self.addr_space) if addr_dl.is_valid(): mac = addr_dl.v() else: mac = "" ifaddr = ifnet.if_addrhead.tqh_first ips = [] while ifaddr: ip = ifaddr.ifa_addr.get_address() if ip: ips.append(ip) ifaddr = ifaddr.ifa_link.tqe_next yield (name, unit, mac, prom, ips) ifnet = ifnet.if_link.tqe_next
def calculate(self): common.set_plugin_members(self) p = self.addr_space.profile.get_symbol("_g_kext_map") mapaddr = obj.Object("Pointer", offset=p, vm=self.addr_space) kextmap = mapaddr.dereference_as("_vm_map") nentries = kextmap.hdr.nentries kext = kextmap.hdr for i in range(nentries): kext = kext.links.next if not kext: break macho = obj.Object("macho_header", offset=kext.start, vm=self.addr_space) if macho.is_valid(): kmod_start = macho.address_for_symbol("_kmod_info") if kmod_start: kmod = obj.Object("kmod_info", offset=kmod_start, vm=self.addr_space) if kmod.is_valid(): yield kmod
def calculate(self): common.set_plugin_members(self) pidlist = None try: if self._config.PID: pidlist = [int(p) for p in self._config.PID.split(',')] except: pass p = self.addr_space.profile.get_symbol("_allproc") procsaddr = obj.Object("proclist", offset = p, vm = self.addr_space) proc = obj.Object("proc", offset = procsaddr.lh_first, vm = self.addr_space) seen = [] while proc.is_valid(): if proc.obj_offset in seen: debug.warning("Recursive process list detected (a result of non-atomic acquisition). Use mac_tasks or mac_psxview)") break else: seen.append(proc.obj_offset) if not pidlist or proc.p_pid in pidlist: yield proc proc = proc.p_list.le_next.dereference()
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks.calculate(self) if self.addr_space.profile.metadata.get('memory_model', '32bit') == "32bit": ptr_sz = 4 else: ptr_sz = 8 for proc in procs: if str(proc.p_comm) != "securityd": continue proc_as = proc.get_process_address_space() for map in proc.get_proc_maps(): if not (map.start > 0x00007f0000000000 and map.end < 0x00007fff00000000 and map.end - map.start == 0x100000): continue for address in range(map.start, map.end, ptr_sz): signature = obj.Object("unsigned int", offset = address, vm = proc_as) if not signature or signature != 0x18: continue key_buf_ptr = obj.Object("unsigned long", offset = address + ptr_sz, vm = proc_as) if map.start <= key_buf_ptr < map.end: yield proc_as, key_buf_ptr
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks.calculate(self) for proc in procs: if str(proc.p_comm) != "kernel_task": continue proc_as = proc.get_process_address_space() for map in proc.get_proc_maps(): if not map.get_perms() == 'r--': continue address = map.links.start Vmk1 = proc_as.read(address, 16) Vmk2 = proc_as.read( address + 0x430, 16 ) #Note: Vmk2 refers to our second instance of the VMK, not the tweak key. signature = obj.Object("unsigned int", offset=address, vm=proc_as) if not Vmk1 or signature == 0x0: continue if Vmk1 == Vmk2: yield address, Vmk1
def calculate(self): common.set_plugin_members(self) msgbuf_ptr = obj.Object("Pointer", offset = self.addr_space.profile.get_symbol("_msgbufp"), vm = self.addr_space) msgbufp = msgbuf_ptr.dereference_as("msgbuf") bufx = msgbufp.msg_bufx size = msgbufp.msg_size bufc = self.addr_space.read(msgbufp.msg_bufc, size) if bufc[bufx] == 0 and bufc[0] != 0: ## FIXME: can we do this without get_string? buf = common.get_string(bufc, self.addr_space) else: if bufx > size: bufx = 0 # older messages buf = bufc[bufx:bufx + size] buf = buf + bufc[0:bufx] # strip leading NULLs while ord(buf[0]) == 0x00: buf = buf[1:] yield buf
def render_text(self, outfd, data): common.set_plugin_members(self) if not self._config.DUMP_DIR: debug.error("Please specify an output directory.") elif not os.path.exists(self._config.DUMP_DIR): debug.error("Please specify a directory that exists.") map_address = self._config.MAP_ADDRESS self.table_header( outfd, [ ("Pid", "8"), ("Name", "20"), ("Map Name", "8"), ("Output Size", ""), ("Output Path", ""), ], ) for proc in data: pas = proc.get_process_address_space() if pas == None: continue pid = proc.p_pid if pid == 0: continue pname = str(proc.p_comm) for map in proc.get_proc_maps(): start = map.links.start.v() end = map.links.end.v() length = end - start if map_address != None and map_address != start: continue if length > self.MAXMAPSIZE: outfd.write( "Skipping suspiciously large map, smearing is suspected. Adjust MAXMAPSIZE to override.\n" ) continue fname = "%d.%#x.%#x.dmp" % (pid, start, end) of_path = os.path.join(self._config.DUMP_DIR, fname) outfile = open(of_path, "wb") written_size = 0 for addr in range(start, end, 4096): page = pas.zread(addr, 4096) outfile.write(page) written_size = written_size + 4096 outfile.close() self.table_row(outfd, pid, pname, map.get_path(), written_size, of_path)
def calculate(self): common.set_plugin_members(self) pgrphash_addr = self.addr_space.profile.get_symbol("_pgrphash") pgrphash = obj.Object("unsigned long", offset=pgrphash_addr, vm=self.addr_space) pgrphashtbl_addr = self.addr_space.profile.get_symbol("_pgrphashtbl") pgrphashtbl_ptr = obj.Object("Pointer", offset=pgrphashtbl_addr, vm=self.addr_space) pgrphash_array = obj.Object( "Array", targetType="pgrphashhead", count=pgrphash + 1, vm=self.addr_space, offset=pgrphashtbl_ptr, ) for plist in pgrphash_array: pgrp = plist.lh_first while pgrp: p = pgrp.pg_members.lh_first while p: yield p p = p.p_pglist.le_next pgrp = pgrp.pg_hash.le_next
def calculate(self): common.set_plugin_members(self) (kernel_symbol_addresses, kmods) = common.get_kernel_addrs(self) sysctl_children_addr = self.addr_space.profile.get_symbol( "_sysctl__children") sysctl_list = obj.Object("sysctl_oid_list", offset=sysctl_children_addr, vm=self.addr_space) for (sysctl, name, val) in self._process_sysctl_list(sysctl_list): if val == "INVALID -1": continue is_known = common.is_known_address(sysctl.oid_handler, kernel_symbol_addresses, kmods) if is_known: status = "OK" else: status = "UNKNOWN" yield (sysctl, name, val, is_known, status)
def calculate(self): common.set_plugin_members(self) p = self.addr_space.profile.get_symbol("_kmod") kmodaddr = obj.Object("Pointer", offset = p, vm = self.addr_space) if kmodaddr == None: return kmod = kmodaddr.dereference_as("kmod_info") seen = [] ctr = 0 while kmod.is_valid(): # key on .v() instead of .obj_offset due 'next' being at offset 0 if kmod.v() in seen: break seen.append(kmod.v()) if ctr > 1024: break ctr = ctr + 1 if not self._config.ADDR or (kmod.address <= self._config.ADDR <= (kmod.address + kmod.m("size"))): yield kmod kmod = kmod.next
def calculate(self): common.set_plugin_members(self) if self._config.REGEX: try: if self._config.IGNORE_CASE: mod_re = re.compile(self._config.REGEX, re.I) else: mod_re = re.compile(self._config.REGEX) except re.error as e: debug.error('Error parsing regular expression: {0}'.format(e)) if self._config.BASE: module_address = int(self._config.BASE) yield obj.Object("kmod_info", offset=module_address, vm=self.addr_space) else: modules_addr = self.addr_space.profile.get_symbol("_kmod") modules_ptr = obj.Object("Pointer", vm=self.addr_space, offset=modules_addr) mod = modules_ptr.dereference_as("kmod_info") while mod.is_valid(): if self._config.REGEX and not mod_re.search(str(mod.name)): mod = mod.next continue yield mod mod = mod.next
def calculate(self): common.set_plugin_members(self) # get the symbols need to check for if rootkit or not (kernel_symbol_addresses, kmods) = common.get_kernel_addrs(self) list_addrs = [ self.addr_space.profile.get_symbol("_ipv4_filters"), self.addr_space.profile.get_symbol("_ipv6_filters") ] for list_addr in list_addrs: plist = obj.Object("ipfilter_list", offset=list_addr, vm=self.addr_space) # type 'ipfilter' cur = plist.tqh_first while cur: filter = cur.ipf_filter name = filter.name.dereference() yield self.check_filter("INPUT", name, filter.ipf_input, kernel_symbol_addresses, kmods) yield self.check_filter("OUTPUT", name, filter.ipf_output, kernel_symbol_addresses, kmods) yield self.check_filter("DETACH", name, filter.ipf_detach, kernel_symbol_addresses, kmods) cur = cur.ipf_link.tqe_next
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks(self._config).calculate() for proc in procs: num_fds = proc.p_fd.fd_lastfile if proc.p_fd.fd_nfiles > num_fds: num_fds = proc.p_fd.fd_nfiles fds = obj.Object('Array', offset=proc.p_fd.fd_ofiles, vm=self.addr_space, targetType='Pointer', count=proc.p_fd.fd_nfiles) for i, fd in enumerate(fds): f = fd.dereference_as("fileproc") if f: ftype = f.f_fglob.fg_type if ftype == 'DTYPE_VNODE': vnode = f.f_fglob.fg_data.dereference_as("vnode") path = vnode.full_path() else: path = "" yield proc, i, f, path
def calculate(self): common.set_plugin_members(self) (kernel_symbol_addresses, kmods) = common.get_kernel_addrs(self) gnotify_addr = common.get_cpp_sym("gNotifications", self.addr_space.profile) gnotify_ptr = obj.Object("Pointer", offset = gnotify_addr, vm = self.addr_space) gnotifications = gnotify_ptr.dereference_as("OSDictionary") ents = obj.Object('Array', offset = gnotifications.dictionary, vm = self.addr_space, targetType = 'dictEntry', count = gnotifications.count) # walk the current set of notifications for ent in ents: if ent == None: continue key = ent.key.dereference_as("OSString") # get the value valset = ent.value.dereference_as("OSOrderedSet") notifiers_ptrs = obj.Object('Array', offset = valset.array, vm = self.addr_space, targetType = 'Pointer', count = valset.count) for ptr in notifiers_ptrs: notifier = ptr.dereference_as("_IOServiceNotifier") if notifier == None: continue matches = self.get_matching(notifier) # this is the function that handles whatever the notification is for # this should be only in the kernel or in one of the known IOKit drivers for the specific kernel handler = notifier.handler good = common.is_known_address(handler, kernel_symbol_addresses, kmods) yield (good, key, notifier, matches)
def calculate(self): common.set_plugin_members(self) # get all the members of 'mac_policy_ops' so that we can check them (they are all function ptrs) ops_members = self.get_members() # get the symbols need to check for if rootkit or not (kernel_symbol_addresses, kmods) = common.get_kernel_addrs(self) list_addr = self.addr_space.profile.get_symbol("_mac_policy_list") plist = obj.Object("mac_policy_list", offset = list_addr, vm = self.addr_space) parray = obj.Object('Array', offset = plist.entries, vm = self.addr_space, targetType = 'mac_policy_list_element', count = plist.staticmax + 1) for ent in parray: # I don't know how this can happen, but the kernel makes this check all over the place # the policy isn't useful without any ops so a rootkit can't abuse this if ent.mpc == None: continue name = ent.mpc.mpc_name.dereference() ops = obj.Object("mac_policy_ops", offset = ent.mpc.mpc_ops, vm = self.addr_space) # walk each member of the struct for check in ops_members: ptr = ops.__getattr__(check) if ptr.v() != 0 and ptr.is_valid(): (good, module) = common.is_known_address_name(ptr, kernel_symbol_addresses, kmods) yield (good, check, module, name, ptr)
def calculate(self): common.set_plugin_members(self) if not self.addr_space.profile.obj_has_member("fs_event_watcher", "proc_name"): debug.error("This plugin only supports OS X >= 10.8.2. Please file a bug if you are running against a version matching this criteria.") event_types = ["CREATE_FILE", "DELETE", "STAT_CHANGED", "RENAME", "CONTENT_MODIFIED", "EXCHANGE", "FINDER_INFO_CHANGED", "CREATE_DIR", "CHOWN"] event_types = event_types + ["XATTR_MODIFIED", "XATTR_REMOVED", "DOCID_CREATED", "DOCID_CHANGED"] table_addr = self.addr_space.profile.get_symbol("_watcher_table") arr = obj.Object(theType = "Array", targetType = "Pointer", count = 8, vm = self.addr_space, offset = table_addr) for watcher_addr in arr: if not watcher_addr.is_valid(): continue watcher = watcher_addr.dereference_as("fs_event_watcher") name = self.addr_space.read(watcher.proc_name.obj_offset, 33) if name: idx = name.find("\x00") if idx != -1: name = name[:idx] events = "" event_arr = obj.Object(theType = "Array", targetType = "unsigned char", offset = watcher.event_list.v(), count = 13, vm = self.addr_space) for (i, event) in enumerate(event_arr): if event == 1: events = events + event_types[i] + ", " if len(events) and events[-1] == " " and events[-2] == ",": events = events[:-2] yield watcher_addr, name, watcher.pid, events
def calculate(self): ## we need this module imported if not has_yara: debug.error("Please install Yara from code.google.com/p/yara-project") ## leveraged from the windows yarascan plugin rules = self._compile_rules() ## set the linux plugin address spaces common.set_plugin_members(self) if self._config.KERNEL: ## http://fxr.watson.org/fxr/source/osfmk/mach/i386/vm_param.h?v=xnu-2050.18.24 if self.addr_space.profile.metadata.get('memory_model', '32bit') == "32bit": if not common.is_64bit_capable(self.addr_space): kernel_start = 0 else: kernel_start = 0xc0000000 else: kernel_start = 0xffffff8000000000 scanner = malfind.DiscontigYaraScanner(rules = rules, address_space = self.addr_space) for hit, address in scanner.scan(start_offset = kernel_start): yield (None, address, hit, scanner.address_space.zread(address, 64)) else: # Scan each process memory block for task in pstasks.mac_tasks(self._config).calculate(): scanner = MapYaraScanner(task = task, rules = rules) for hit, address in scanner.scan(): yield (task, address, hit, scanner.address_space.zread(address, 64))
def calculate(self): common.set_plugin_members(self) p = self.addr_space.profile.get_symbol("_g_kext_map") mapaddr = obj.Object("Pointer", offset = p, vm = self.addr_space) kextmap = mapaddr.dereference_as("_vm_map") nentries = kextmap.hdr.nentries kext = kextmap.hdr for i in range(nentries): kext = kext.links.next if not kext: break macho = obj.Object("macho_header", offset = kext.start, vm = self.addr_space) if macho.is_valid(): kmod_start = macho.address_for_symbol("_kmod_info") else: kmod_start = 0 address = kext.start if kmod_start: kmod = obj.Object("kmod_info", offset = kmod_start, vm = self.addr_space) yield kmod
def render_text(self, outfd, data): common.set_plugin_members(self) self.table_header( outfd, [ ("Offset", "[addrpad]"), ("Scope", "24"), ("IData", "[addrpad]"), ("Callback Addr", "[addrpad]"), ("Callback Mod", "24"), ("Callback Sym", ""), ], ) kaddr_info = common.get_handler_name_addrs(self) for scope in data: scope_name = scope.ks_identifier for ls in scope.listeners(): cb = ls.kll_callback.v() (module, handler_sym) = common.get_handler_name(kaddr_info, cb) self.table_row( outfd, ls.v(), scope_name, ls.kll_idata, cb, module, handler_sym, )
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks(self._config).calculate() for proc in procs: fds = obj.Object('Array', offset=proc.p_fd.fd_ofiles, vm=self.addr_space, targetType='Pointer', count=proc.p_fd.fd_lastfile) for i, fd in enumerate(fds): f = fd.dereference_as("fileproc") if f: ## FIXME after 2.3 replace this explicit int field with the following line: ## if str(f.f_fglob.fg_type) == 'DTYPE_VNODE': ## Its not needed for profiles generated with convert.py after r3290 fg_type = obj.Object("int", f.f_fglob.fg_type.obj_offset, vm=self.addr_space) if fg_type == 1: # VNODE vnode = f.f_fglob.fg_data.dereference_as("vnode") path = vnode.full_path() else: path = "" yield proc, i, f, path
def calculate(self): common.set_plugin_members(self) p = self.addr_space.profile.get_symbol("_kmod") kmodaddr = obj.Object("Pointer", offset=p, vm=self.addr_space) if kmodaddr == None: return kmod = kmodaddr.dereference_as("kmod_info") seen = [] ctr = 0 while kmod.is_valid(): # key on .v() instead of .obj_offset due 'next' being at offset 0 if kmod.v() in seen: break seen.append(kmod.v()) if ctr > 1024: break ctr = ctr + 1 if not self._config.ADDR or (kmod.address <= self._config.ADDR <= (kmod.address + kmod.m("size"))): yield kmod kmod = kmod.next
def calculate(self): common.set_plugin_members(self) for task in pstasks.mac_tasks(self._config).calculate(): fdp = task.p_fd # for (i = 0; i < fdp->fd_knlistsize; i++) { # kn = SLIST_FIRST(&fdp->fd_knlist[i]); for kn in self._walk_karray(fdp.fd_knlist, fdp.fd_knlistsize): yield task, kn # if (fdp->fd_knhashmask != 0) { # for (i = 0; i < (int)fdp->fd_knhashmask + 1; i++) { # kn = SLIST_FIRST(&fdp->fd_knhash[i]); mask = fdp.fd_knhashmask if mask != 0: for kn in self._walk_karray(fdp.fd_knhash, mask + 1): yield task, kn kn = task.p_klist.slh_first while kn.is_valid(): yield task, kn kn = kn.kn_link.sle_next
def calculate(self): common.set_plugin_members(self) n = 1024 mig_buckets_addr = self.addr_space.profile.get_symbol("_mig_buckets") if self.addr_space.profile.has_type("mig_hash_t"): ele_size = self.addr_space.profile.get_obj_size("mig_hash_t") ele_type = "mig_hash_t" else: # we can't use an array as the size of mig_hash_entry # depends on if MAC_COUNTERS is set, which changes between kernels # mig_table_max_displ is declared directly after mig_buckets # which allows us to calculate the size of each entry dynamically di_addr = self.addr_space.profile.get_symbol("_mig_table_max_displ") ele_size = (di_addr - mig_buckets_addr) / n ele_type = "mig_hash_entry" for i in range(n): entry = obj.Object(ele_type, offset = mig_buckets_addr + (i * ele_size), vm = self.addr_space) if entry.routine == 0: continue rname = self.addr_space.profile.get_symbol_by_address("kernel", entry.routine) if not rname or rname == "": rname = "HOOKED" yield (entry.num, rname, entry.routine)
def calculate(self): common.set_plugin_members(self) self._set_vtypes() sym_addrs = self.profile.get_all_addresses() table_addr = self.addr_space.profile.get_symbol("_mach_trap_table") ntraps = obj.Object( "int", offset=self.addr_space.profile.get_symbol("_mach_trap_count"), vm=self.addr_space) traps = obj.Object(theType="Array", offset=table_addr, vm=self.addr_space, count=ntraps, targetType="mach_trap") for (i, trap) in enumerate(traps): ent_addr = trap.mach_trap_function.v() if not ent_addr: continue hooked = ent_addr not in sym_addrs if hooked == False: sym_name = self.profile.get_symbol_by_address( "kernel", ent_addr) else: sym_name = "HOOKED" yield (table_addr, "TrapTable", i, ent_addr, sym_name, hooked)
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks.calculate(self) for proc in procs: if str(proc.p_comm) != "kernel_task": continue proc_as = proc.get_process_address_space() for map in proc.get_proc_maps(): if not map.get_perms() == 'r--': continue address = map.links.start Vmk1 = proc_as.read(address,16) Vmk2 = proc_as.read(address + 0x430,16) #Note: Vmk2 refers to our second instance of the VMK, not the tweak key. signature = obj.Object("unsigned int", offset = address, vm = proc_as) if not Vmk1 or signature == 0x0: continue if Vmk1 == Vmk2: yield address, Vmk1
def render_text(self, outfd, data): common.set_plugin_members(self) self.table_header(outfd, [("PID","8"), ("Name", "16"), ("Start Time", "32"), ("Priority", "6"), ("Start Function", "[addrpad]"), ("Function Map", ""), ]) kaddr_info = common.get_handler_name_addrs(self) for proc in data: for th in proc.threads(): func_addr = th.continuation (module, handler_sym) = common.get_handler_name(kaddr_info, func_addr) if handler_sym: handler = handler_sym elif module: handler = module else: handler = proc.find_map_path(func_addr) self.table_row(outfd, proc.p_pid, proc.p_comm, th.start_time(), th.sched_pri, func_addr, handler)
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks.calculate(self) for proc in procs: space = proc.get_process_address_space() for map in proc.get_proc_maps(): # only read/write without filebacks if not (map.get_perms() == "rw-" and not map.get_path()): continue # check the header for sqlite3 signature header = space.zread(map.links.start, 32) if "SQLite format" not in header: continue # get the whole sqlite3 data now data = space.zread(map.links.start, map.links.end - map.links.start) for offset in utils.iterfind(data, ":ABPerson"): person = obj.Object( "String", offset=map.links.start + offset, vm=space, encoding="utf8", length=256, ) yield proc, person
def calculate(self): common.set_plugin_members(self) saddr = common.get_cpp_sym("sLoadedKexts", self.addr_space.profile) p = obj.Object("Pointer", offset=saddr, vm=self.addr_space) kOSArr = obj.Object(self._struct_or_class("OSArray"), offset=p, vm=self.addr_space) if kOSArr == None: debug.error( "The OSArray_class type was not found in the profile. Please file a bug if you are running aginst Mac >= 10.7" ) kext_arr = obj.Object(theType="Array", targetType="Pointer", offset=kOSArr.array, count=kOSArr.capacity, vm=self.addr_space) for (i, kext) in enumerate(kext_arr): kext = kext.dereference_as(self._struct_or_class("OSKext")) if kext and kext.is_valid(): yield kext
def calculate(self): common.set_plugin_members(self) # we can't use an array as the size of mig_hash_entry # depends on if MAC_COUNTERS is set, which changes between kernels # mig_table_max_displ is declared directly after mig_buckets # which allows us to calculate the size of each entry dynamically di_addr = self.addr_space.profile.get_symbol("_mig_table_max_displ") mig_buckets_addr = self.addr_space.profile.get_symbol("_mig_buckets") ele_size = (di_addr - mig_buckets_addr) / 1024 for i in range(1024): entry = obj.Object("mig_hash_entry", offset=mig_buckets_addr + (i * ele_size), vm=self.addr_space) if entry.routine == 0: continue rname = self.addr_space.profile.get_symbol_by_address( "kernel", entry.routine) if not rname or rname == "": rname = "HOOKED" yield (entry.num, rname, entry.routine)
def calculate(self): common.set_plugin_members(self) list_head_addr = self.addr_space.profile.get_symbol("_dlil_ifnet_head") list_head_ptr = obj.Object("Pointer", offset=list_head_addr, vm=self.addr_space) ifnet = list_head_ptr.dereference_as("ifnet") while ifnet: name = ifnet.if_name.dereference() unit = ifnet.if_unit prom = ifnet.if_flags & 0x100 == 0x100 # IFF_PROMISC addr_dl = ifnet.sockaddr_dl() if addr_dl.is_valid(): mac = addr_dl.v() else: mac = "" ifaddr = ifnet.if_addrhead.tqh_first ips = [] while ifaddr: ip = ifaddr.ifa_addr.get_address() if ip: ips.append(ip) ifaddr = ifaddr.ifa_link.tqe_next yield (name, unit, mac, prom, ips) ifnet = ifnet.if_link.tqe_next
def render_text(self, outfd, data): common.set_plugin_members(self) self.table_header(outfd, [ ("PID", "8"), ("Name", "16"), ("Start Time", "32"), ("Priority", "6"), ("Start Function", "[addrpad]"), ("Function Map", ""), ]) kaddr_info = common.get_handler_name_addrs(self) for proc in data: for th in proc.threads(): func_addr = th.continuation (module, handler_sym) = common.get_handler_name(kaddr_info, func_addr) if handler_sym: handler = handler_sym elif module: handler = module else: handler = proc.find_map_path(func_addr) self.table_row(outfd, proc.p_pid, proc.p_comm, th.start_time(), th.priority, func_addr, handler)
def calculate(self): common.set_plugin_members(self) self._set_vtypes() sym_addrs = self.profile.get_all_addresses() table_addr = self.addr_space.profile.get_symbol("_mach_trap_table") ntraps = obj.Object("int", offset = self.addr_space.profile.get_symbol("_mach_trap_count"), vm = self.addr_space) traps = obj.Object(theType = "Array", offset = table_addr, vm = self.addr_space, count = ntraps, targetType = "mach_trap") for (i, trap) in enumerate(traps): ent_addr = trap.mach_trap_function.v() if not ent_addr: continue hooked = ent_addr not in sym_addrs if hooked == False: sym_name = self.profile.get_symbol_by_address("kernel", ent_addr) else: sym_name = "HOOKED" yield (table_addr, "TrapTable", i, ent_addr, sym_name, hooked)
def calculate(self): common.set_plugin_members(self) shash_addr = self.addr_space.profile.get_symbol("_sesshash") shash = obj.Object("unsigned long", offset=shash_addr, vm=self.addr_space) shashtbl_addr = self.addr_space.profile.get_symbol("_sesshashtbl") shashtbl_ptr = obj.Object("Pointer", offset=shashtbl_addr, vm=self.addr_space) shash_array = obj.Object( theType="Array", targetType="sesshashhead", count=shash + 1, vm=self.addr_space, offset=shashtbl_ptr, ) for sess in shash_array: s = sess.lh_first while s: yield s s = s.s_hash.le_next
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks(self._config).calculate() for proc in procs: fds = obj.Object('Array', offset = proc.p_fd.fd_ofiles, vm = self.addr_space, targetType = 'Pointer', count = proc.p_fd.fd_lastfile) for i, fd in enumerate(fds): f = fd.dereference_as("fileproc") if f: if 'fg_type' in f.f_fglob.dereference().__dict__['members']: ## FIXME after 2.3 replace this explicit int field with the following line: ## if str(f.f_fglob.fg_type) == 'DTYPE_VNODE': ## Its not needed for profiles generated with convert.py after r3290 fg_type = obj.Object("int", f.f_fglob.fg_type.obj_offset, vm = self.addr_space) # OS X MAVERICKS else: fg_type = obj.Object("int", f.f_fglob.fg_ops.fo_type.obj_offset, vm = self.addr_space) if fg_type == 1: # VNODE vnode = f.f_fglob.fg_data.dereference_as("vnode") path = vnode.full_path() else: path = "" yield proc, i, f, path
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks(self._config).calculate() for proc in procs: proc_as = proc.get_process_address_space() for mapping in proc.get_dyld_maps(): path = mapping.imageFilePath macho = obj.Object("macho_header", offset=mapping.imageLoadAddress, vm=proc_as) needed_libraries = {} for n in macho.needed_libraries(): needed_libraries[n] = 1 for (name, addr) in macho.imports(): is_lazy = False is_ptr_hooked = False is_api_hooked = False hook_addr = 0 hook_type = "" vma_mapping = self._find_mapping(proc, addr) if vma_mapping == None: vma_mapping = self._find_mapping_proc_maps(proc, addr) if vma_mapping: (vma_path, vma_start, vma_end) = vma_mapping else: # the address points to a bogus (non-mapped region) vma_path = "<UNKNOWN>" vma_start = addr vma_end = addr addr_mapping = vma_path # non-resolved symbols if vma_start <= mapping.imageLoadAddress <= vma_end: is_lazy = True else: is_ptr_hooked = not addr_mapping in needed_libraries # check if pointing into the shared region # this happens as libraries in the region are not listed as needed if is_ptr_hooked: if proc.task.shared_region.sr_base_address <= addr <= proc.task.shared_region.sr_base_address + proc.task.shared_region.sr_size: is_ptr_hooked = False if not is_ptr_hooked: is_api_hooked = self._is_api_hooked(addr, proc_as) if is_api_hooked: (hook_type, hook_addr) = is_api_hooked yield (proc, name, addr, is_lazy, is_ptr_hooked, is_api_hooked, hook_type, hook_addr, addr_mapping)
def render_text(self, outfd, data): common.set_plugin_members(self) self.table_header( outfd, [ ("PID", "8"), ("Name", "16"), ("Start Address", "[addrpad]"), ("Mapping", "40"), ("Name", "40"), ("Status", ""), ], ) (kstart, kend, kmods) = common.get_kernel_addrs_start_end(self) for proc in data: for thread in proc.threads(): start = thread.continuation if start == 0: continue (good, mapping) = common.is_in_kernel_or_module( start, kstart, kend, kmods) if not good: mapping = "UNKNOWN" for map in proc.get_proc_maps(): if map.links.start <= start <= map.links.end: mapping = map.get_path() if mapping == "": mapping = map.get_special_path() good = 1 start = map.links.start status = "UNKNOWN" if good: status = "OK" name = b"" if thread.uthread: name_buf = self.addr_space.read( thread.uthread.dereference_as("uthread").pth_name, 256) if name_buf: idx = name_buf.find(b"\x00") if idx != -1: name_buf = name_buf[:idx] name = name_buf self.table_row( outfd, proc.p_pid, proc.p_comm, start, mapping, name, status, )
def calculate(self): common.set_plugin_members(self) kaddr_info = common.get_handler_name_addrs(self) dict_ptr_addr = common.get_cpp_sym("sAllClassesDict", self.addr_space.profile) dict_addr = obj.Object("unsigned long", offset=dict_ptr_addr, vm=self.addr_space) fdict = obj.Object(self._struct_or_class("OSDictionary"), offset=dict_addr.v(), vm=self.addr_space) ents = obj.Object('Array', offset=fdict.dictionary, vm=self.addr_space, targetType=self._struct_or_class("dictEntry"), count=fdict.count) for ent in ents: if ent == None or not ent.is_valid(): continue class_name = str( ent.key.dereference_as(self._struct_or_class("OSString"))) osmeta = obj.Object(self._struct_or_class("OSMetaClass"), offset=ent.value.v(), vm=self.addr_space) cname = str( osmeta.className.dereference_as( self._struct_or_class("OSString"))) offset = 0 if hasattr(osmeta, "metaClass"): arr_start = osmeta.metaClass.v() else: arr_start = obj.Object("Pointer", offset=osmeta.obj_offset, vm=self.addr_space) vptr = obj.Object("unsigned long", offset=arr_start, vm=self.addr_space) while vptr != 0: (module, handler_sym) = common.get_handler_name(kaddr_info, vptr) yield (cname, vptr, module, handler_sym) offset = offset + vptr.size() vptr = obj.Object("unsigned long", offset=arr_start + offset, vm=self.addr_space)
def render_text(self, outfd, data): common.set_plugin_members(self) if not self._config.OUTPUTFILE: debug.error("Please specify an OUTPUTFILE") elif os.path.exists(self._config.OUTPUTFILE): debug.error("Cowardly refusing to overwrite an existing file.") outfile = open(self._config.OUTPUTFILE, "wb+") map_address = self._config.MAP_ADDRESS size = 0 self.table_header(outfd, [("Pid", "8"), ("Name", "20"), ("Start", "#018x"), ("End", "#018x"), ("Perms", "9"), ("Map Name", "")]) # from osfmk/vm/vm_object.h. compressor_object is the high level VM object. self.compressor_object = obj.Object("vm_object", offset = self.addr_space.profile.get_symbol("_compressor_object_store"), vm = self.addr_space) # from osfmk/vm/vm_compressor.c. c_segments is an array of c_segu objects, which track and store compressed pages. # c_segment_count is current size of c_segments array. self.c_segment_count = obj.Object("unsigned int", offset = self.addr_space.profile.get_symbol("_c_segment_count"), vm = self.addr_space) self.c_segments_ptr = obj.Object("Pointer", offset = self.addr_space.profile.get_symbol("_c_segments"), vm = self.addr_space) self.c_segments = obj.Object("Array", targetType = "c_segu", count = self.c_segment_count, offset = self.c_segments_ptr, vm = self.addr_space) for proc, map in data: self.table_row(outfd, str(proc.p_pid), proc.p_comm, map.links.start, map.links.end, map.get_perms(), map.get_path()) if (map.links.end - map.links.start) > self.MAXMAPSIZE: outfd.write("Skipping suspiciously large map, smearing is suspected. Adjust MAXMAPSIZE to override.\n") continue if not map_address or map_address == map.links.start: for page in self._read_addr_range(outfd, proc, map): if not page is None: size += self.wkdm.PAGE_SIZE_IN_BYTES if not self._config.SKIP_WRITING: for k in range(0, self.wkdm.PAGE_SIZE_IN_WORDS): outfile.write(struct.pack('<i', page[k])) outfile.close() outfd.write("Wrote {0} bytes.\n".format(size)) if self._config.DECOMPRESS_SWAP: outfd.write("{0} pages were successfully decompressed.\n".format(self.successful_decompressions))
def calculate(self): common.set_plugin_members(self) yield obj.Object( "String", offset=self.addr_space.profile.get_symbol("_version"), vm=self.addr_space, length=256, )
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks.calculate(self) for proc in procs: for map in proc.get_proc_maps(): yield proc, map
def unified_output(self, data): common.set_plugin_members(self) return TreeGrid([("Pid", int), ("Name", str), ("Start", Address), ("Map Name", str), ], self.generator(data))
def calculate(self): common.set_plugin_members(self) pe_state_addr = self.addr_space.profile.get_symbol("_PE_state") pe_state = obj.Object("PE_state", offset=pe_state_addr, vm=self.addr_space) bootargs = pe_state.bootArgs.dereference_as("boot_args") yield bootargs.CommandLine
def calculate(self): common.set_plugin_members(self) procs = pstasks.mac_tasks(self._config).calculate() for proc in procs: proc_as = proc.get_process_address_space() for mapping in proc.get_dyld_maps(): path = mapping.imageFilePath macho = obj.Object("macho_header", offset = mapping.imageLoadAddress, vm = proc_as) needed_libraries = {} for n in macho.needed_libraries(): needed_libraries[n] = 1 for (name, addr) in macho.imports(): is_lazy = False is_ptr_hooked = False is_api_hooked = False hook_addr = 0 hook_type = "" vma_mapping = self._find_mapping(proc, addr) if vma_mapping == None: vma_mapping = self._find_mapping_proc_maps(proc, addr) if vma_mapping: (vma_path, vma_start, vma_end) = vma_mapping else: # the address points to a bogus (non-mapped region) vma_path = "<UNKNOWN>" vma_start = addr vma_end = addr addr_mapping = vma_path # non-resolved symbols if vma_start <= mapping.imageLoadAddress <= vma_end: is_lazy = True else: is_ptr_hooked = not addr_mapping in needed_libraries # check if pointing into the shared region # this happens as libraries in the region are not listed as needed if is_ptr_hooked: if proc.task.shared_region.sr_base_address <= addr <= proc.task.shared_region.sr_base_address + proc.task.shared_region.sr_size: is_ptr_hooked = False if not is_ptr_hooked: is_api_hooked = self._is_api_hooked(addr, proc_as) if is_api_hooked: (hook_type, hook_addr) = is_api_hooked yield (proc, name, addr, is_lazy, is_ptr_hooked, is_api_hooked, hook_type, hook_addr, addr_mapping)
def unified_output(self, data): common.set_plugin_members(self) return TreeGrid([("PID",int), ("Name", str), ("Start Time", str), ("Priority", str), ("Start Function", Address), ("Function Map", str), ], self.generator(data))
def calculate(self): common.set_plugin_members(self) arp_addr = self.addr_space.profile.get_symbol("_llinfo_arp") ptr = obj.Object("Pointer", offset = arp_addr, vm = self.addr_space) ent = ptr.dereference_as("llinfo_arp") while ent: yield ent.la_rt ent = ent.la_le.le_next
def calculate(self): common.set_plugin_members(self) scopes_addr = self.addr_space.profile.get_symbol("_kauth_scopes") scopes_ptr = obj.Object("Pointer", offset = scopes_addr, vm = self.addr_space) scope = scopes_ptr.dereference_as("kauth_scope") while scope.is_valid(): yield scope scope = scope.ks_link.tqe_next.dereference()
def calculate(self): common.set_plugin_members(self) p = self.get_profile_symbol("_kmod") kmodaddr = obj.Object("Pointer", offset = p, vm = self.addr_space) kmod = kmodaddr.dereference_as("kmod_info") while kmod.is_valid(): yield kmod kmod = kmod.next
def calculate(self): common.set_plugin_members(self) kaddr_info = common.get_handler_name_addrs(self) funcs = [self._walk_opv_desc, self._walk_vfstbllist] for func in funcs: for (vfs_ptr, name, ptr, module, handler_sym) in func(kaddr_info): yield (vfs_ptr, name, ptr, module, handler_sym)
def calculate(self): common.set_plugin_members(self) mountlist_addr = self.get_profile_symbol("_mountlist") mount = obj.Object("mount", offset = mountlist_addr, vm = self.addr_space) mount = mount.mnt_list.tqe_next while mount: yield mount mount = mount.mnt_list.tqe_next
def unified_output(self, data): common.set_plugin_members(self) return TreeGrid([("Offset", Address), ("Scope", str), ("IData", Address), ("Callback Addr", Address), ("Callback Mod", str), ("Callback Sym", str), ], self.generator(data))
def unified_output(self, data): common.set_plugin_members(self) return TreeGrid([("PID",int), ("Process Name", str), ("Start Address", Address), ("Mapping", str), ("Name", str), ("Status", str), ], self.generator(data))