def _get_task_parents(self): if self.addr_space.profile.obj_has_member("task_struct", "real_parent"): ret = [x.real_parent.v() for x in linux_pslist.linux_pslist(self._config).calculate()] else: ret = [x.parent.v() for x in linux_pslist.linux_pslist(self._config).calculate()] return ret
def _get_task_parents(self): if self.addr_space.profile.obj_has_member("task_struct", "real_parent"): ret = [ self.addr_space.vtop(x.real_parent.v()) for x in linux_pslist.linux_pslist(self._config).calculate() ] else: ret = [ self.addr_space.vtop(x.parent.v()) for x in linux_pslist.linux_pslist(self._config).calculate() ] return ret
def filter_tasks(self): tasks = pslist.linux_pslist(self._config).calculate() if self._config.PID is not None: try: pidlist = [int(p) for p in self._config.PID.split(",")] except ValueError: debug.error("Invalid PID {0}".format(self._config.PID)) pids = [t for t in tasks if t.pid in pidlist] if len(pids) == 0: debug.error( "Cannot find PID {0}. If its terminated or unlinked, use psscan and then supply --offset=OFFSET".format( self._config.PID ) ) return pids if self._config.NAME is not None: try: name_re = re.compile(self._config.NAME, re.I) except re.error: debug.error("Invalid name {0}".format(self._config.NAME)) names = [t for t in tasks if name_re.search(str(t.comm))] if len(names) == 0: debug.error( "Cannot find name {0}. If its terminated or unlinked, use psscan and then supply --offset=OFFSET".format( self._config.NAME ) ) return names return tasks
def calculate(self): linux_common.set_plugin_members(self) phys_addr_space = utils.load_as(self._config, astype='physical') pl = linux_pslist.linux_pslist(self._config).calculate() ps = linux_psscan.linux_psscan(self._config).calculate() pids = [] for process in pl: pids.append(int(process.pid)) for process in ps: if int(process.pid) not in pids: start_time = process.get_task_start_time() if start_time == None: start_time = "" if process.mm.pgd == None: dtb = process.mm.pgd else: dtb = self.addr_space.vtop( process.mm.pgd) or process.mm.pgd yield process, start_time, dtb
def calculate(self): # if no gDvm object offset was specified, use this one if not self._config.GDVM_OFFSET: self._config.GDVM_OFFSET = str(0x41b0) # use linux_pslist plugin to find process address space and ID if not specified proc_as = None tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if str(task.comm) == "keystore": proc_as = task.get_process_address_space() self._config.PID = str(task.pid) break # find stack for task, vma in dalvik.get_data_section_stack(self._config): # read length and password, they seem to have constant offset length = obj.Object('int', offset=vma.vm_start + 0x1982c, vm=proc_as) password = obj.Object('String', offset=vma.vm_start + 0x19830, vm=proc_as, length=length) yield password
def calculate(self): # if no gDvm object offset was specified, use this one if not self._config.GDVM_OFFSET: self._config.GDVM_OFFSET = str(hex(0x41b0)) # use linux_pslist plugin to find process address space and ID if not specified proc_as = None tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if str(task.comm) == "ndroid.contacts": proc_as = task.get_process_address_space() if not self._config.PID: self._config.PID = str(task.pid) break # use dalvik_loaded_classes plugin to find class offset if not specified if not self._config.CLASS_OFFSET: classes = dalvik_loaded_classes.dalvik_loaded_classes(self._config).calculate() for task, clazz in classes: if (dalvik.getString(clazz.sourceFile)+"" == "PhoneCallDetails.java"): self._config.CLASS_OFFSET = str(hex(clazz.obj_offset)) break # use dalvik_find_class_instance plugin to find a list of possible class instances instances = dalvik_find_class_instance.dalvik_find_class_instance(self._config).calculate() for sysClass, inst in instances: callDetailsObj = obj.Object('PhoneCallDetails', offset = inst, vm = proc_as) # access type ID field for sanity check typeID = int(callDetailsObj.callTypes.contents0) # valid type ID must be 1,2 or 3 if (typeID == 1 or typeID == 2 or typeID == 3): yield callDetailsObj
def calculate(self): linux_common.set_plugin_members(self) fs_types = self._get_filesystem_types() # newer kernels if self.profile.has_type("mount"): mnttype = "mount" cache = linux_slabinfo(self._config).get_kmem_cache(mnttype, self._config.UNALLOCATED) for task in linux_pslist.linux_pslist(self._config).calculate(): if task.pid == 1: ns = task.nsproxy.mnt_ns break else: cache = linux_slabinfo(self._config).get_kmem_cache( "mnt_cache", self._config.UNALLOCATED, struct_name="vfsmount" ) ns = None for mnt in cache: ret = self._parse_mnt(mnt, ns, fs_types) if ret: (mnt_sb, dev_name, path, fstype, rr, mnt_string) = ret if not (dev_name == "devtmpfs" and path == "/"): yield (mnt_sb, dev_name, path, fstype, rr, mnt_string)
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 linux_common.set_plugin_members(self) if self._config.KERNEL: ## the start of kernel memory taken from VolatilityLinuxIntelValidAS if self.addr_space.profile.metadata.get('memory_model', '32bit') == "32bit": kernel_start = 0xc0000000 else: kernel_start = 0xffffffff80000000 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: for task in pslist.linux_pslist(self._config).calculate(): scanner = VmaYaraScanner(task=task, rules=rules) for hit, address in scanner.scan(): yield (task, address, hit, scanner.address_space.zread(address, 64))
def calculate(self): linux_common.set_plugin_members(self) fs_types = self._get_filesystem_types() # newer kernels if self.profile.has_type("mount"): mnttype = "mount" cache = linux_slabinfo(self._config).get_kmem_cache( mnttype, self._config.UNALLOCATED) for task in linux_pslist.linux_pslist(self._config).calculate(): if task.pid == 1: ns = task.nsproxy.mnt_ns break else: cache = linux_slabinfo(self._config).get_kmem_cache( "mnt_cache", self._config.UNALLOCATED, struct_name="vfsmount") ns = None for mnt in cache: ret = self._parse_mnt(mnt, ns, fs_types) if ret: (mnt_sb, dev_name, path, fstype, rr, mnt_string) = ret if not (dev_name == "devtmpfs" and path == "/"): yield (mnt_sb, dev_name, path, fstype, rr, mnt_string)
def _fill_cache(self): for task in linux_pslist.linux_pslist(self._config).calculate(): for filp, fd in task.lsof(): filepath = linux_common.get_path(task, filp) if type(filepath) == str and filepath.find("socket:[") != -1: to_add = filp.dentry.d_inode.i_ino self.fd_cache[to_add] = [task, filp, fd, filepath]
def _fill_cache(self): for task in linux_pslist.linux_pslist(self._config).calculate(): for filp, fd in task.lsof(): filepath = linux_common.get_path(task, filp) if type(filepath) == str and filepath.find("socket:[") != -1: to_add = filp.dentry.d_inode.i_ino.v() self.fd_cache[to_add] = [task, filp, fd, filepath]
def calculate(self): linux_common.set_plugin_members(self) mntptr = obj.Object( "Pointer", offset=self.addr_space.profile.get_symbol("mount_hashtable"), vm=self.addr_space) mnt_list = obj.Object(theType="Array", offset=mntptr.v(), vm=self.addr_space, targetType="list_head", count=512) if self.profile.has_type("mount"): mnttype = "mount" for task in linux_pslist.linux_pslist(self._config).calculate(): if task.pid == 1: ns = task.nsproxy.mnt_ns break else: mnttype = "vfsmount" ns = None # get each list_head out of the array for outerlist in mnt_list: for mnt in outerlist.list_of_type(mnttype, "mnt_hash"): yield (mnt, ns)
def filter_tasks(self): tasks = pslist.linux_pslist(self._config).calculate() if self._config.PID is not None: try: pidlist = [int(p) for p in self._config.PID.split(',')] except ValueError: debug.error("Invalid PID {0}".format(self._config.PID)) pids = [t for t in tasks if t.pid in pidlist] if len(pids) == 0: debug.error( "Cannot find PID {0}. If its terminated or unlinked, use psscan and then supply --offset=OFFSET" .format(self._config.PID)) return pids if self._config.NAME is not None: try: name_re = re.compile(self._config.NAME, re.I) except re.error: debug.error("Invalid name {0}".format(self._config.NAME)) names = [t for t in tasks if name_re.search(str(t.comm))] if len(names) == 0: debug.error( "Cannot find name {0}. If its terminated or unlinked, use psscan and then supply --offset=OFFSET" .format(self._config.NAME)) return names return tasks
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 linux_common.set_plugin_members(self) if self._config.KERNEL: ## the start of kernel memory taken from VolatilityLinuxIntelValidAS if self.addr_space.profile.metadata.get('memory_model', '32bit') == "32bit": kernel_start = 0xc0000000 else: kernel_start = 0xffffffff80000000 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: for task in pslist.linux_pslist(self._config).calculate(): scanner = VmaYaraScanner(task = task, rules = rules) for hit, address in scanner.scan(): yield (task, address, hit, scanner.address_space.zread(address, 64))
def calculate(self): # Should contain the options for one e-mail out = [] tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if not task.mm: continue # Get the dump for the process content = task.get_elf(task.mm.start_code) #print all elements that have at least 4 characters string_contents = self.binaryToString(content) emails = self.emailSearch(string_contents) # If dump directory is specified, we should dump all the tasks to the directory if self._config.DUMP_DIR: linux_common.write_elf_file(self._config.DUMP_DIR, task, task.mm.start_code) #proc_contents = task.get_elf(task.get_process_address_space()) out.append({"task": task, "emails": emails}) #Returns a tuple of (task, content) return out
def check_open_files_fop(self, f_op_members, modules): # get all the members in file_operations, they are all function pointers tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: for filp, i in task.lsof(): for (hooked_member, hook_address) in self.verify_ops(filp.f_op, f_op_members, modules): name = "{0:s} {1:d} {2:s}".format(task.comm, i, linux_common.get_path(task, filp)) yield (name, hooked_member, hook_address)
def _compare_filps(self): dcache = self._gather_dcache() tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: for filp, i in task.lsof(): val = filp.dentry.v() if not val in dcache: yield val procs = linux_pslist.linux_pslist(self._config).calculate() for proc in procs: for vma in proc.get_proc_maps(): if vma.vm_file: val = vma.vm_file.dentry.v() if not val in dcache: yield val
def calculate(self): if (not self._config.OUT_DIR or not os.path.isdir(self._config.OUT_DIR)): debug.error("Please specify an existing output dir (--out-dir)") if (not os.path.isfile("./loader")): debug.error( "Cannot find 'loader' inside current working directory, compile it or `cd` in the right directory" ) # Extract mappings, kind of ugly but i did not find another way to call the modules.. for p in linux_pslist.linux_pslist(self._config).calculate(): pname = str(p.comm) if pname == 'X' or pname == 'Xorg': break tmp_dir = tempfile.mkdtemp() self._config.add_option("PID") self._config.add_option("DUMP_DIR") self._config.PID = str(p.pid) self._config.DUMP_DIR = tmp_dir out = StringIO.StringIO() data = linux_proc_maps.linux_proc_maps(self._config).calculate() print("[+] Dumping Xorg memory mappings in %s" % tmp_dir) linux_dump_map.linux_dump_map(self._config).render_text(out, data) # Extract screenshots xw = linux_xwindows.linux_xwindows(self._config) for msg, screen_windows, screen_info in xw.calculate(): for screen_id, win in screen_windows: # print('{} on Screen {}\n'.format(str(win), screen_id)) if win.drawable.type == 0 and win.drawable.width > 150 and win.drawable.height > 150: out = StringIO.StringIO() xw.visit_property( win.optional.dereference().userProps.dereference(), out) loader = [ "./loader", str(win.drawable), str(win.drawable.pScreen.visuals), str(win.borderWidth), str(screen_info.imageByteOrder), str(screen_info.bitmapScanlineUnit), str(screen_info.bitmapScanlinePad), str(screen_info.bitmapBitOrder), str(win.drawable.pScreen.GetImage), str(tmp_dir), str(self._config.OUT_DIR) ] print("[+] Calling %s" % ' '.join(loader)) subprocess.check_call(loader)
def filter_tasks(self): tasks = linux_pslist(self._config).calculate() tasks_filt = [] for task in tasks: for c_plug, c_param1, c_param2 in LINUX_RAKOS_A_FILTER: if c_plug == 'netstat': for ents in task.netstat(): if ents[0] == socket.AF_INET: (_, proto, saddr, sport, daddr, dport, state) = ents[1] if (str(saddr) == c_param1) and (str(sport) == c_param2): tasks_filt.append(task) print("Suspected PID: {0:8s} {1:<16}:{2:>5} {3:<16}:{4:>5} {5:<15s} {6:>17s}/{7:<5d}\n".format(proto, saddr, sport, daddr, dport, state, task.comm, task.pid)) return tasks_filt
def filter_tasks(self): tasks = linux_pslist.linux_pslist(self._config).calculate() if self._config.PID is not None: try: pidlist = [int(p) for p in self._config.PID.split(',')] except ValueError: debug.error("Invalid PID {0}".format(self._config.PID)) pids = [t for t in tasks if t.pid in pidlist] if len(pids) == 0: debug.error("Cannot find PID {0}. If its terminated or unlinked, use psscan and then supply --offset=OFFSET".format(self._config.PID)) return pids return tasks
def set_context(self, offset=None, pid=None, name=None, physical=False): if physical and offset != None: offset = pslist.linux_pslist( self._config).virtual_process_from_physical_offset( offset).obj_offset elif pid is not None: offsets = [] for p in self.getpidlist(): if p.pid.v() == pid: offsets.append(p) if not offsets: print "Unable to find process matching pid {0}".format(pid) return elif len(offsets) > 1: print "Multiple processes match {0}, please specify by offset".format( pid) print "Matching processes:" self.ps(offsets) return else: offset = offsets[0].v() elif name is not None: offsets = [] for p in self.getpidlist(): if p.comm.find(name) >= 0: offsets.append(p) if not offsets: print "Unable to find process matching name {0}".format(name) return elif len(offsets) > 1: print "Multiple processes match name {0}, please specify by PID or offset".format( name) print "Matching processes:" self.ps(offsets) return else: offset = offsets[0].v() elif offset is None: print "Must provide one of: offset, name, or pid as a argument." return self._proc = obj.Object("task_struct", offset=offset, vm=self._addrspace) self.context_display()
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: proc_as = task.get_process_address_space() # In cases when mm is an invalid pointer if not proc_as: continue if not self._config.HISTORY_LIST: # Do we scan everything or just /bin/bash instances? if not (self._config.SCAN_ALL or str(task.comm) == "bash"): continue for hist in task.bash_history_entries(): yield task, hist else: the_history_addr = the_history_addr = self._config.HISTORY_LIST the_history = obj.Object( "Pointer", vm=proc_as, offset=the_history_addr ) max_ents = 2001 the_history = obj.Object( theType='Array', offset=the_history, vm=proc_as, targetType='Pointer', count=max_ents, ) for ptr in the_history: if not ptr: if self._config.PRINTUNALLOC: continue else: break hist = ptr.dereference_as("_hist_entry") if hist.is_valid(): yield task, hist
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: proc_as = task.get_process_address_space() # In cases when mm is an invalid pointer if not proc_as: continue # Do we scan everything or just /bin/bash instances? if not (self._config.SCAN_ALL or str(task.comm) == "bash"): continue for ent in task.bash_hash_entries(): yield task, ent
def get_processes(self, addr_space): """Enumerate processes based on user options. :param addr_space | <addrspace.AbstractVirtualAddressSpace> :returns <list> """ tasks = linux_pslist.linux_pslist(self._config).calculate() try: if self._config.PID is not None: pidlist = [int(p) for p in self._config.PID.split(',')] tasks = [t for t in tasks if int(t.pid) in pidlist] except (ValueError, TypeError): debug.error("Invalid PID {0}".format(self._config.PID)) return tasks
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() if not self._config.HISTORY_LIST: debug.error("History list address not specified.") the_history_addr = self._config.HISTORY_LIST for task in tasks: proc_as = task.get_process_address_space() # In cases when mm is an invalid pointer if not proc_as: continue the_history = obj.Object("Pointer", vm=proc_as, offset=the_history_addr) max_ents = 2001 the_history = obj.Object(theType='Array', offset=the_history, vm=proc_as, targetType='Pointer', count=max_ents) for ptr in the_history: if not ptr: if self._config.PRINTUNALLOC: continue else: break hist = obj.Object("_hist_entry", offset=ptr, vm=proc_as) cmd = hist.line.dereference() cmdtime = hist.timestamp.dereference() if cmd and len(cmd) and cmdtime and len(cmdtime): yield (cmd, cmdtime)
def calculate(self): linux_common.set_plugin_members(self) # newer kernels if self.profile.has_type("mount"): mnttype = "mount" cache = linux_slabinfo(self._config).get_kmem_cache(mnttype, self._config.UNALLOCATED) for task in linux_pslist.linux_pslist(self._config).calculate(): if task.pid == 1: ns = task.nsproxy.mnt_ns break else: cache = linux_slabinfo(self._config).get_kmem_cache("mnt_cache", self._config.UNALLOCATED, struct_name = "vfsmount") ns = None for mnt in cache: yield (mnt, ns)
def calculate(self): common.set_plugin_members(self) if self.profile.metadata["arch"] not in ["x64", "x86"]: debug.error("This plugin is only supported on Intel-based memory captures") self.bits = self.profile.metadata.get("memory_model", "32bit") self.reg_size = reg_size[self.bits] self.offsets = offsets[self.bits] self.fmt = fmt[self.bits] for proc in linux_pslist.linux_pslist(self._config).calculate(): name = proc.get_commandline() thread_registers = [] for thread_task in proc.threads(): thread_name = thread_task.comm regs = self.parse_kernel_stack(thread_task) thread_registers.append((thread_name, regs)) yield proc, name, thread_registers
def calculate(self): common.set_plugin_members(self) if self.profile.metadata['arch'] not in ["x64", "x86"]: debug.error( "This plugin is only supported on Intel-based memory captures") self.bits = self.profile.metadata.get('memory_model', '32bit') self.reg_size = reg_size[self.bits] self.offsets = offsets[self.bits] self.fmt = fmt[self.bits] for proc in linux_pslist.linux_pslist(self._config).calculate(): name = proc.get_commandline() thread_registers = [] for thread_task in proc.threads(): thread_name = thread_task.comm regs = self.parse_kernel_stack(thread_task) thread_registers.append((thread_name, regs)) yield proc, name, thread_registers
def set_context(self, offset = None, pid = None, name = None, physical = False): if physical and offset != None: offset = pslist.linux_pslist(self._config).virtual_process_from_physical_offset(offset).obj_offset elif pid is not None: offsets = [] for p in self.getpidlist(): if p.pid.v() == pid: offsets.append(p) if not offsets: print "Unable to find process matching pid {0}".format(pid) return elif len(offsets) > 1: print "Multiple processes match {0}, please specify by offset".format(pid) print "Matching processes:" self.ps(offsets) return else: offset = offsets[0].v() elif name is not None: offsets = [] for p in self.getpidlist(): if p.comm.find(name) >= 0: offsets.append(p) if not offsets: print "Unable to find process matching name {0}".format(name) return elif len(offsets) > 1: print "Multiple processes match name {0}, please specify by PID or offset".format(name) print "Matching processes:" self.ps(offsets) return else: offset = offsets[0].v() elif offset is None: print "Must provide one of: offset, name, or pid as a argument." return self._proc = obj.Object("task_struct", offset = offset, vm = self._addrspace) self.context_display()
def calculate(self): # if no gDvm object offset was specified, use this one if not self._config.GDVM_OFFSET: self._config.GDVM_OFFSET = str(0x41b0) # use linux_pslist plugin to find process address space and ID if not specified proc_as = None tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if str(task.comm) == "keystore": proc_as = task.get_process_address_space() self._config.PID = str(task.pid) break # find stack for task, vma in dalvik.get_data_section_stack(self._config): # read length and password, they seem to have constant offset length = obj.Object('int', offset = vma.vm_start + 0x1982c, vm = proc_as) password = obj.Object('String', offset = vma.vm_start + 0x19830, vm = proc_as, length = length) yield password
def calculate(self): # if no gDvm object offset was specified, use this one if not self._config.GDVM_OFFSET: self._config.GDVM_OFFSET = str(0x41b0) # use linux_pslist plugin to find process address space and ID if not specified proc_as = None tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if str(task.comm) == "putmethod.latin": proc_as = task.get_process_address_space() self._config.PID = str(task.pid) break # use dalvik_loaded_classes plugin to find class offset if not specified if not self._config.CLASS_OFFSET: classes = dalvik_loaded_classes.dalvik_loaded_classes(self._config).calculate() for task, clazz in classes: if (dalvik.getString(clazz.sourceFile)+"" == "RichInputConnection.java"): self._config.CLASS_OFFSET = str(hex(clazz.obj_offset)) break # use dalvik_find_class_instance plugin to find a list of possible class instances instance = dalvik_find_class_instance.dalvik_find_class_instance(self._config).calculate() for sysClass, inst in instance: # get stringBuilder object stringBuilder = inst.clazz.getJValuebyName(inst, "mCommittedTextBeforeComposingText").Object.dereference_as('Object') # get superclass object abstractStringBuilder = stringBuilder.clazz.super.dereference_as('ClassObject') # array object of super class charArray = abstractStringBuilder.getJValuebyName(stringBuilder, "value").Object.dereference_as('ArrayObject') # get length of array object count = charArray.length # create string object with content of the array object text = obj.Object('String', offset = charArray.contents0.obj_offset, vm = abstractStringBuilder.obj_vm, length = count*2, encoding = "utf16") yield inst, text
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: proc_as = task.get_process_address_space() # In cases when mm is an invalid pointer if not proc_as: continue if not self._config.HISTORY_LIST: # Do we scan everything or just /bin/bash instances? if not (self._config.SCAN_ALL or str(task.comm) == "bash"): continue for hist in task.bash_history_entries(): yield task, hist else: the_history_addr = the_history_addr = self._config.HISTORY_LIST the_history = obj.Object("Pointer", vm = proc_as, offset = the_history_addr) max_ents = 2001 the_history = obj.Object(theType = 'Array', offset = the_history, vm = proc_as, targetType = 'Pointer', count = max_ents) for ptr in the_history: if not ptr: if self._config.PRINTUNALLOC: continue else: break hist = ptr.dereference_as("_hist_entry") if hist.is_valid(): yield task, hist
def calculate(self): linux_common.set_plugin_members(self) mntptr = obj.Object("Pointer", offset = self.addr_space.profile.get_symbol("mount_hashtable"), vm = self.addr_space) mnt_list = obj.Object(theType = "Array", offset = mntptr.v(), vm = self.addr_space, targetType = "list_head", count = 512) if self.profile.has_type("mount"): mnttype = "mount" for task in linux_pslist.linux_pslist(self._config).calculate(): if task.pid == 1: ns = task.nsproxy.mnt_ns break else: mnttype = "vfsmount" ns = None # get each list_head out of the array for outerlist in mnt_list: for mnt in outerlist.list_of_type(mnttype, "mnt_hash"): yield (mnt, ns)
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() if not self._config.HISTORY_LIST: debug.error("History list address not specified.") the_history_addr = self._config.HISTORY_LIST for task in tasks: proc_as = task.get_process_address_space() # In cases when mm is an invalid pointer if not proc_as: continue the_history = obj.Object("Pointer", vm = proc_as, offset = the_history_addr) max_ents = 2001 the_history = obj.Object(theType = 'Array', offset = the_history, vm = proc_as, targetType = 'Pointer', count = max_ents) for ptr in the_history: if not ptr: if self._config.PRINTUNALLOC: continue else: break hist = obj.Object("_hist_entry", offset = ptr, vm = proc_as) cmd = hist.line.dereference() cmdtime = hist.timestamp.dereference() if cmd and len(cmd) and cmdtime and len(cmdtime): yield (cmd, cmdtime)
def calculate(self): # if no gDvm object offset was specified, use this one if not self._config.GDVM_OFFSET: self._config.GDVM_OFFSET = str(hex(0x41b0)) # use linux_pslist plugin to find process address space and ID if not specified proc_as = None tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if str(task.comm) == "ndroid.contacts": proc_as = task.get_process_address_space() if not self._config.PID: self._config.PID = str(task.pid) break # use dalvik_loaded_classes plugin to find class offset if not specified if not self._config.CLASS_OFFSET: classes = dalvik_loaded_classes.dalvik_loaded_classes( self._config).calculate() for task, clazz in classes: if (dalvik.getString(clazz.sourceFile) + "" == "PhoneCallDetails.java"): self._config.CLASS_OFFSET = str(hex(clazz.obj_offset)) break # use dalvik_find_class_instance plugin to find a list of possible class instances instances = dalvik_find_class_instance.dalvik_find_class_instance( self._config).calculate() for sysClass, inst in instances: callDetailsObj = obj.Object('PhoneCallDetails', offset=inst, vm=proc_as) # access type ID field for sanity check typeID = int(callDetailsObj.callTypes.contents0) # valid type ID must be 1,2 or 3 if (typeID == 1 or typeID == 2 or typeID == 3): yield callDetailsObj
def get_pid_from_name(self, name): for proc in linux_pslist.linux_pslist(self._config).calculate(): if proc.comm == name: return proc.pid else: raise (Exception("Bad Process name: {}".format(name)))
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if self.init_for_task(task): if self.profile.metadata.get('memory_model') == '64bit': self.profile.vtypes.update(ZshProfile64().zshprofile) else: # default/fallback profile self.profile.vtypes.update(ZshProfile32().zshprofile) self.profile.compile() chunks_dict = dict() chunk_data_pointers = list() chunk_size = self.get_aligned_size( self.profile.get_obj_size('histent')) data_offset = self.profile.get_obj_offset("malloc_chunk", "fd") for chunk in self.get_all_allocated_chunks(): chunks_dict[chunk.v() + data_offset] = chunk chunk_data_pointers.append(chunk.v() + data_offset) commands_dict = dict() valid_histentry = None # we first try to find a chunk that most probably contains a # histent struct for chunk in self.get_all_allocated_chunks(): if not chunk.chunksize() == chunk_size: continue histent = obj.Object('histent', offset=chunk.v() + data_offset, vm=self.process_as) # we test if the current histent struct seems to be valid # first test: do we know the chunks where relevant # pointers point to pointers = [ histent.node.nam.v(), histent.down.v(), histent.up.v() ] if not len(set(pointers) & set(chunk_data_pointers)) \ == len(pointers): continue # second test: points the previous/next histent entry to # this histent entry? if not histent.up.down == histent or not histent.down.up \ == histent: continue # we hopefully found one valid_histentry = histent break if valid_histentry: debug.debug( "We probably found a valid histent chunk and now " "start walking.") # entries are linked circular so walking in one direction # should be sufficient for histent in heap_analysis.iterate_through_linked_list( valid_histentry, lambda x: x.down): command = '' try: command = chunks_dict[histent.node.nam.v()] command = command.to_string() command = command[:command.index("\x00")] except KeyError: debug.warning( "Unexpected error: chunk for given " "command-reference does not seem to exist.") except ValueError: pass if histent.stim == histent.ftim == 0 and command == '': histent_vma = heap_analysis.get_vma_for_offset( self.vmas, histent.v()) if histent_vma not in self.heap_vmas: # we most probably found the "curline" histent # struct located in zsh's .bss section. as it # doesn't contain an actual executed command, # we are skipping it continue command_number = histent.histnum start = obj.Object('UnixTimeStamp', offset=histent.stim.obj_offset, vm=self.process_as) end = obj.Object('UnixTimeStamp', offset=histent.stim.obj_offset, vm=self.process_as) commands_dict[command_number] = [ start, end, repr(command) ] for key, value in sorted(commands_dict.items()): yield (task.pid, key, value[0], value[1], value[2])
def getpidlist(self): return pslist.linux_pslist(self._config).allprocs()
def calculate(self): # if no gDvm object offset was specified, use this one if not self._config.GDVM_OFFSET: self._config.GDVM_OFFSET = str(0x41b0) # use linux_pslist plugin to find process address space and ID if not specified proc_as = None tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if str(task.comm) == "droid.gallery3d": proc_as = task.get_process_address_space() self._config.PID = str(task.pid) break # use dalvik_loaded_classes plugin to find class offset if not specified if not self._config.CLASS_OFFSET: classes = dalvik_loaded_classes.dalvik_loaded_classes(self._config).calculate() for task, clazz in classes: if (dalvik.getString(clazz.sourceFile)+"" == "LocalAlbum.java"): self._config.CLASS_OFFSET = str(hex(clazz.obj_offset)) break # use dalvik_find_class_instance plugin to find a list of possible class instances instance = dalvik_find_class_instance.dalvik_find_class_instance(self._config).calculate() for sysClass, inst in instance: # boolean value, 1 for images, 0 for videos isImage = inst.clazz.getJValuebyName(inst, "mIsImage").int # sanity check if isImage != True: continue # number of pictures, initilized with -1 count = inst.clazz.getJValuebyName(inst, "mCachedCount").int # sanity check if count == -1: continue # get album name album_name = inst.clazz.getJValuebyName(inst, "mName").Object.dereference_as('Object') # get pictures of album album_path = inst.clazz.getJValuebyName(inst, "mItemPath").Object.dereference_as('Object') iCache = album_path.clazz.getJValuebyName(album_path, "mChildren").Object.dereference_as('Object') hashmap = iCache.clazz.getJValuebyName(iCache, "mWeakMap").Object.dereference_as('Object') # in this table there is a reference to every single picture map_table = hashmap.clazz.getJValuebyName(hashmap, "table").Object.dereference_as('ArrayObject') # parse the table map_entries = dalvik.parseArrayObject(map_table) # for every reference of the table for field in map_entries: entry = field.clazz.getJValuebyName(field, "value").Object.dereference_as('Object') weak_reference_clazz = entry.clazz.super.dereference_as('ClassObject') reference_clazz = weak_reference_clazz.super.dereference_as('ClassObject') image_path = reference_clazz.getJValuebyName(entry, "referent").Object.dereference_as('Object') image_weak_reference = image_path.clazz.getJValuebyName(image_path, "mObject").Object.dereference_as('Object') # finally this is the instance of one picture class local_image = reference_clazz.getJValuebyName(image_weak_reference, "referent").Object.dereference_as('Object') # the interesting information is found in the superclass local_media_item = local_image.clazz.super.dereference_as('ClassObject') # get picture information image_name = local_media_item.getJValuebyName(local_image, "caption").Object.dereference_as('Object') image_size = local_media_item.getJValuebyName(local_image, "fileSize").int image_lat = local_media_item.getJValuebyName(local_image, "latitude").longlong image_long = local_media_item.getJValuebyName(local_image, "longitude").longlong image_date_taken = local_media_item.getJValuebyName(local_image, "dateTakenInMs").ulonglong image_filepath = local_media_item.getJValuebyName(local_image, "filePath").Object.dereference_as('Object') image_width = local_media_item.getJValuebyName(local_image, "width").int image_heigth = local_media_item.getJValuebyName(local_image, "height").int yield inst, image_name, album_name, image_size, image_lat, image_long, image_date_taken, image_width, image_heigth
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if self.init_for_task(task): if self.profile.metadata.get('memory_model') == '64bit': self.profile.vtypes.update(ZshProfile64().zshprofile) else: # default/fallback profile self.profile.vtypes.update(ZshProfile32().zshprofile) self.profile.compile() chunks_dict = dict() chunk_data_pointers = list() chunk_size = self.get_aligned_size( self.profile.get_obj_size('histent')) data_offset = self.profile.get_obj_offset("malloc_chunk", "fd") for chunk in self.get_all_allocated_chunks(): chunks_dict[chunk.v() + data_offset] = chunk chunk_data_pointers.append(chunk.v() + data_offset) commands_dict = dict() valid_histentry = None # we first try to find a chunk that most probably contains a # histent struct for chunk in self.get_all_allocated_chunks(): if not chunk.chunksize() == chunk_size: continue histent = obj.Object('histent', offset=chunk.v()+data_offset, vm=self.process_as) # we test if the current histent struct seems to be valid # first test: do we know the chunks where relevant # pointers point to pointers = [histent.node.nam.v(), histent.down.v(), histent.up.v()] if not len(set(pointers) & set(chunk_data_pointers)) \ == len(pointers): continue # second test: points the previous/next histent entry to # this histent entry? if not histent.up.down == histent or not histent.down.up \ == histent: continue # we hopefully found one valid_histentry = histent break if valid_histentry: debug.debug( "We probably found a valid histent chunk and now " "start walking.") # entries are linked circular so walking in one direction # should be sufficient for histent in heap_analysis.iterate_through_linked_list( valid_histentry, lambda x: x.down): command = '' try: command = chunks_dict[histent.node.nam.v()] command = command.to_string() command = command[:command.index("\x00")] except KeyError: debug.warning( "Unexpected error: chunk for given " "command-reference does not seem to exist.") except ValueError: pass if histent.stim == histent.ftim == 0 and command == '': histent_vma = heap_analysis.get_vma_for_offset( self.vmas, histent.v()) if histent_vma not in self.heap_vmas: # we most probably found the "curline" histent # struct located in zsh's .bss section. as it # doesn't contain an actual executed command, # we are skipping it continue command_number = histent.histnum start = obj.Object('UnixTimeStamp', offset=histent.stim.obj_offset, vm=self.process_as) end = obj.Object('UnixTimeStamp', offset=histent.stim.obj_offset, vm=self.process_as) commands_dict[command_number] = [start, end, repr(command)] for key, value in sorted(commands_dict.items()): yield (task.pid, key, value[0], value[1], value[2])
def _get_task_parents(self): return [x.real_parent.v() for x in linux_pslist.linux_pslist(self._config).calculate()]
def _get_pslist(self): return [ x.obj_offset for x in linux_pslist.linux_pslist(self._config).calculate() ]
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() # Are we dealing with 32 or 64-bit pointers if self.addr_space.profile.metadata.get('memory_model', '32bit') == '32bit': pack_format = "<I" addr_sz = 4 else: pack_format = "<Q" addr_sz = 8 for task in tasks: proc_as = task.get_process_address_space() # In cases when mm is an invalid pointer if not proc_as: continue procvars = [] for vma in task.get_proc_maps(): if not (vma.vm_file and str(vma.vm_flags) == "rw-" and linux_common.get_path(task, vma.vm_file).find("bash") != -1): continue env_start = 0 for off in range(vma.vm_start, vma.vm_end): # check the first index addrstr = proc_as.read(off, addr_sz) if not addrstr or len(addrstr) != addr_sz: continue addr = struct.unpack(pack_format, addrstr)[0] # check first idx... if addr: firstaddrstr = proc_as.read(addr, addr_sz) if not firstaddrstr or len(firstaddrstr) != addr_sz: continue firstaddr = struct.unpack(pack_format, firstaddrstr)[0] buf = proc_as.read(firstaddr, 64) if not buf: continue eqidx = buf.find("=") if eqidx > 0: nullidx = buf.find("\x00") # single char name, = if nullidx >= eqidx: env_start = addr if env_start == 0: continue envars = obj.Object(theType="Array", targetType="Pointer", vm=proc_as, offset=env_start, count=256) for var in envars: if var: varstr = proc_as.read(var, 1600) eqidx = varstr.find("=") idx = varstr.find("\x00") if idx == -1 or eqidx == -1 or idx < eqidx: break varstr = varstr[:idx] procvars.append(varstr) yield task, " ".join(procvars) break
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: proc_as = task.get_process_address_space() # In cases when mm is an invalid pointer if not proc_as: continue if not self._config.HISTORY_LIST: # Do we scan everything or just /bin/bash instances? if not (self._config.SCAN_ALL or str(task.comm) == "bash"): continue # Keep a bucket of history objects so we can order them history_entries = [] # Brute force the history list of an address isn't provided ts_offset = proc_as.profile.get_obj_offset("_hist_entry", "timestamp") # Are we dealing with 32 or 64-bit pointers if proc_as.profile.metadata.get('memory_model', '32bit') == '32bit': pack_format = "I" else: pack_format = "Q" # Look for strings that begin with pound/hash on the process heap for ptr_hash in task.search_process_memory(["#"], heap_only = True): # Find pointers to this strings address, also on the heap addr = struct.pack(pack_format, ptr_hash) for ptr_string in task.search_process_memory([addr], heap_only = True): # Check if we found a valid history entry object hist = obj.Object("_hist_entry", offset = ptr_string - ts_offset, vm = proc_as) if hist.is_valid(): history_entries.append(hist) # We can terminate this inner loop now break # Report everything we found in order for hist in sorted(history_entries, key = attrgetter('time_as_integer')): yield task, hist else: the_history_addr = the_history_addr = self._config.HISTORY_LIST the_history = obj.Object("Pointer", vm = proc_as, offset = the_history_addr) max_ents = 2001 the_history = obj.Object(theType = 'Array', offset = the_history, vm = proc_as, targetType = 'Pointer', count = max_ents) for ptr in the_history: if not ptr: if self._config.PRINTUNALLOC: continue else: break hist = ptr.dereference_as("_hist_entry") if hist.is_valid(): yield task, hist
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: proc_as = task.get_process_address_space() # In cases when mm is an invalid pointer if not proc_as: continue if not self._config.HISTORY_LIST: # Do we scan everything or just /bin/bash instances? if not (self._config.SCAN_ALL or str(task.comm) == "bash"): continue # Keep a bucket of history objects so we can order them history_entries = [] # Brute force the history list of an address isn't provided ts_offset = proc_as.profile.get_obj_offset( "_hist_entry", "timestamp") # Are we dealing with 32 or 64-bit pointers if proc_as.profile.metadata.get('memory_model', '32bit') == '32bit': pack_format = "I" else: pack_format = "Q" # Look for strings that begin with pound/hash on the process heap for ptr_hash in task.search_process_memory(["#"], heap_only=True): # Find pointers to this strings address, also on the heap addr = struct.pack(pack_format, ptr_hash) for ptr_string in task.search_process_memory( [addr], heap_only=True): # Check if we found a valid history entry object hist = obj.Object("_hist_entry", offset=ptr_string - ts_offset, vm=proc_as) if hist.is_valid(): history_entries.append(hist) # We can terminate this inner loop now break # Report everything we found in order for hist in sorted(history_entries, key=attrgetter('time_as_integer')): yield task, hist else: the_history_addr = the_history_addr = self._config.HISTORY_LIST the_history = obj.Object("Pointer", vm=proc_as, offset=the_history_addr) max_ents = 2001 the_history = obj.Object(theType='Array', offset=the_history, vm=proc_as, targetType='Pointer', count=max_ents) for ptr in the_history: if not ptr: if self._config.PRINTUNALLOC: continue else: break hist = ptr.dereference_as("_hist_entry") if hist.is_valid(): yield task, hist
def _get_task_parents(self): return [ x.real_parent.v() for x in linux_pslist.linux_pslist(self._config).calculate() ]
def _get_pslist(self): return [self.addr_space.vtop(x.obj_offset) for x in linux_pslist.linux_pslist(self._config).calculate()]
def getpidlist(self): return pslist.linux_pslist(self._config).calculate()
def _get_pslist(self): return [x.obj_offset for x in linux_pslist.linux_pslist(self._config).calculate()]
def calculate(self): linux_common.set_plugin_members(self) tasks = linux_pslist.linux_pslist(self._config).calculate() for task in tasks: if self.init_for_task(task): chunks_dict = dict() data_offset = self.profile.get_obj_offset("malloc_chunk", "fd") for chunk in self.get_all_allocated_chunks(): chunks_dict[chunk.v() + data_offset] = chunk if self.profile.metadata.get('memory_model') == '64bit': string_offset = 26 relevant_chunk_size = 192 pointer_offsets = [16, 24, 32, 64] else: string_offset = 18 relevant_chunk_size = 96 pointer_offsets = [12, 16, 20, 36] entry_number = 1 for chunk in chunks_dict.values(): try: # chunks containing refs to password entries typically # have a size of 96 in the tested 32 bit environment if not chunk.chunksize() == relevant_chunk_size: continue p_entry_data = chunk.to_string() field_strings = [] # the pointers to title, username and so on are at # these offsets for i in pointer_offsets: if self.profile.metadata.get('memory_model') == '32bit': pointer = struct.unpack('I', p_entry_data[i:i+4])[0] else: pointer = struct.unpack('Q', p_entry_data[i:i+8])[0] # if there is no chunk for the given pointer, we # most probably have a wrong chunk. this will # throw a KeyError exception and we proceed with # the next chunk curr_chunk_data = chunks_dict[pointer].to_string() string_size = struct.unpack( 'I', curr_chunk_data[8:12])[0] string_size *= 2 curr_string = curr_chunk_data[ string_offset:string_offset+string_size] curr_string = curr_string.decode('utf-16-le') field_strings.append(repr(curr_string)) yield (task.pid, entry_number, field_strings[0], field_strings[1], field_strings[2], field_strings[3]) entry_number += 1 except (KeyError, UnicodeDecodeError): # a password entry struct not containing a pointer to # a chunk => out of scope pass