Пример #1
0
    def build_pids(self):
        if self._config.PROC_NAME:
            # PROC_NAME
            name_list = self._config.PROC_NAME.split(",")
            pid_list = []
            for name in name_list:
                for task in tasks.pslist(self.addr_space):
                    if name in str(task.ImageFileName):
                        pid_list.append(task.UniqueProcessId)
    
            pids = ','.join(map(str, pid_list))
        else:
            # PROC_NAME_MATCH
            name_list = self._config.PROC_NAME_MATCH.split(",")
            pid_list = []
            for name in name_list:
                for task in tasks.pslist(self.addr_space):
                    if name == str(task.ImageFileName):
                        pid_list.append(task.UniqueProcessId)
        
            pids = ','.join(map(str, pid_list))

        if pids == '':
            debug.error("No process matches given name. Please specify a valid name or PID.")
        return pids
Пример #2
0
    def calculate(self):

        if not has_pydeep:
            debug.error(
                "Please install ssdeep and pydeep from http://ssdeep.sourceforge.net/ and https://github.com/kbandla/pydeep"
            )

        addr_space = utils.load_as(self._config)
        self._addr_space = addr_space

        page_sig = self._pydeep_page()
        if page_sig == None:
            debug.error("Pydeep was not able to hash the input")

        if self._config.KERNEL:

            # Find KDBG so we know where kernel memory begins. Do not assume
            # the starting range is 0x80000000 because we may be dealing with
            # an image with the /3GB boot switch.
            kdbg = tasks.get_kdbg(addr_space)

            start = kdbg.MmSystemRangeStart.dereference_as("Pointer")

            # Modules so we can map addresses to owners
            mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space))
            mod_addrs = sorted(mods.keys())

            # There are multiple views (GUI sessions) of kernel memory.
            # Since we're scanning virtual memory and not physical,
            # all sessions must be scanned for full coverage. This
            # really only has a positive effect if the data you're
            # searching for is in GUI memory.
            sessions = []

            for proc in tasks.pslist(addr_space):
                sid = proc.SessionId
                # Skip sessions we've already seen
                if sid == None or sid in sessions:
                    continue

                session_space = proc.get_process_address_space()
                if session_space == None:
                    continue

                sessions.append(sid)
                scanner = DiscontigSSDeepScanner(address_space=session_space, rules=rules)

                for hit, address in scanner.scan(start_offset=start):
                    module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(address))
                    yield (module, address, hit, session_space.zread(address - self._config.REVERSE, self._config.SIZE))

        else:
            for task in self.filter_tasks(tasks.pslist(addr_space)):
                scanner = VadSSDeepScanner(task=task, pydeep_hash=page_sig)
                for sig, vStart, vLength, offset, alike in scanner.scan():
                    yield (task, sig, vStart, vLength, offset, alike, scanner.address_space.zread(offset, 0x1000))
Пример #3
0
    def calculate(self):
        addr_space = utils.load_as(self._config)
        addr_space.profile.add_types(sde_types)

        if addr_space.profile.metadata.get("major", 0) == 5 and addr_space.profile.metadata.get("minor", 0) == 2:
            addr_space.profile.add_types(sdt_types_2k3)
        else:
            addr_space.profile.add_types(sdt_types)

        ## Get a sorted list of module addresses
        mods = dict((mod.DllBase.v(), mod) for mod in modules.lsmod(addr_space))
        mod_addrs = sorted(mods.keys())

        # Gather up all SSDTs referenced by threads
        print "Gathering all referenced SSDTs from KTHREADs..."
        ssdts = set()
        for proc in tasks.pslist(addr_space):
            for thread in proc.ThreadListHead.list_of_type("_ETHREAD", "ThreadListEntry"):
                ssdt_obj = thread.Tcb.ServiceTable.dereference_as("_SERVICE_DESCRIPTOR_TABLE")
                ssdts.add(ssdt_obj)

        # Get a list of *unique* SSDT entries. Typically we see only two.
        tables = set()

        for ssdt_obj in ssdts:
            for i, desc in enumerate(ssdt_obj.Descriptors):
                # Apply some extra checks - KiServiceTable should reside in kernel memory and ServiceLimit
                # should be greater than 0 but not unbelievably high
                if (
                    desc.is_valid()
                    and desc.ServiceLimit > 0
                    and desc.ServiceLimit < 0xFFFF
                    and desc.KiServiceTable > 0x80000000
                ):
                    tables.add((i, desc.KiServiceTable.v(), desc.ServiceLimit.v()))

        print "Finding appropriate address space for tables..."
        tables_with_vm = []
        for idx, table, n in tables:
            found = False
            for p in tasks.pslist(addr_space):
                ## This is the process address space
                ps_ad = p.get_process_address_space()
                ## Is the table accessible from the process AS?
                if ps_ad.is_valid_address(table):
                    tables_with_vm.append((idx, table, n, ps_ad))
                    found = True
                    break
            ## If not we use the kernel address space
            if not found:
                # Any VM is equally bad...
                tables_with_vm.append((idx, table, n, addr_space))

        for idx, table, n, vm in sorted(tables_with_vm, key=itemgetter(0)):
            yield idx, table, n, vm, mods, mod_addrs
Пример #4
0
    def calculate(self):
        addr_space = utils.load_as(self._config)

        ## Get a sorted list of module addresses
        mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space))
        mod_addrs = sorted(mods.keys())

        ssdts = set()

        if addr_space.profile.metadata.get("memory_model", "32bit") == "32bit":
            # Gather up all SSDTs referenced by threads
            print "[x86] Gathering all referenced SSDTs from KTHREADs..."
            for proc in tasks.pslist(addr_space):
                for thread in proc.ThreadListHead.list_of_type("_ETHREAD", "ThreadListEntry"):
                    ssdt_obj = thread.Tcb.ServiceTable.dereference_as("_SERVICE_DESCRIPTOR_TABLE")
                    ssdts.add(ssdt_obj)
        else:
            print "[x64] Gathering all referenced SSDTs from KeAddSystemServiceTable..."
            # The NT module always loads first
            ntos = list(modules.lsmod(addr_space))[0]
            func_rva = ntos.getprocaddress("KeAddSystemServiceTable")
            if func_rva == None:
                raise StopIteration("Cannot locate KeAddSystemServiceTable")
            KeAddSystemServiceTable = ntos.DllBase + func_rva
            for table_rva in find_tables(KeAddSystemServiceTable, addr_space):
                ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE", ntos.DllBase + table_rva, addr_space)
                ssdts.add(ssdt_obj)

        # Get a list of *unique* SSDT entries. Typically we see only two.
        tables = set()

        for ssdt_obj in ssdts:
            for i, desc in enumerate(ssdt_obj.Descriptors):
                # Apply some extra checks - KiServiceTable should reside in kernel memory and ServiceLimit
                # should be greater than 0 but not unbelievably high
                if (
                    desc.is_valid()
                    and desc.ServiceLimit > 0
                    and desc.ServiceLimit < 0xFFFF
                    and desc.KiServiceTable > 0x80000000
                ):
                    tables.add((i, desc.KiServiceTable.v(), desc.ServiceLimit.v()))

        print "Finding appropriate address space for tables..."
        tables_with_vm = []
        procs = list(tasks.pslist(addr_space))
        for idx, table, n in tables:
            vm = tasks.find_space(addr_space, procs, table)
            if vm:
                tables_with_vm.append((idx, table, n, vm))
            else:
                debug.debug("[SSDT not resident at 0x{0:08X}]\n".format(table))

        for idx, table, n, vm in sorted(tables_with_vm, key=itemgetter(0)):
            yield idx, table, n, vm, mods, mod_addrs
Пример #5
0
    def calculate(self):

        if not has_yara:
            debug.error("Please install Yara from code.google.com/p/yara-project")

        addr_space = utils.load_as(self._config)

        rules = self._compile_rules()

        if self._config.KERNEL:

            # Find KDBG so we know where kernel memory begins. Do not assume
            # the starting range is 0x80000000 because we may be dealing with
            # an image with the /3GB boot switch. 
            kdbg = tasks.get_kdbg(addr_space)

            start = kdbg.MmSystemRangeStart.dereference_as("Pointer")

            # Modules so we can map addresses to owners
            mods = dict((addr_space.address_mask(mod.DllBase), mod)
                        for mod in modules.lsmod(addr_space))
            mod_addrs = sorted(mods.keys())

            # There are multiple views (GUI sessions) of kernel memory.
            # Since we're scanning virtual memory and not physical, 
            # all sessions must be scanned for full coverage. This 
            # really only has a positive effect if the data you're
            # searching for is in GUI memory. 
            sessions = []

            for proc in tasks.pslist(addr_space):
                sid = proc.SessionId
                # Skip sessions we've already seen 
                if sid == None or sid in sessions:
                    continue

                session_space = proc.get_process_address_space()
                if session_space == None:
                    continue

                sessions.append(sid)
                scanner = DiscontigYaraScanner(address_space = session_space,
                                               rules = rules)

                for hit, address in scanner.scan(start_offset = start):
                    module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(address))
                    yield (module, address, hit, session_space.zread(address, 1024))

        else:
            for task in self.filter_tasks(tasks.pslist(addr_space)):
                scanner = VadYaraScanner(task = task, rules = rules)
                for hit, address in scanner.scan():
                    yield (task, address, hit, scanner.address_space.zread(address, 1024))
Пример #6
0
    def calculate(self):
        addr_space = utils.load_as(self._config)

        if not has_yara:
            debug.error("You must install yara to use this plugin")

        if not self._config.DUMP_DIR:
            debug.error("You must supply a --dump-dir parameter")
        
        if self._config.PHYSICAL:
            # Find the FileAddressSpace
            while addr_space.__class__.__name__ != "FileAddressSpace":
                addr_space = addr_space.base 
            scanner = malfind.DiscontigYaraScanner(address_space = addr_space, 
                                                   rules = DumpCerts.rules)
            for hit, address in scanner.scan():
                cert = obj.Object(DumpCerts.type_map.get(hit.rule), 
                                            vm = scanner.address_space,
                                            offset = address, 
                                            )
                if cert.is_valid():
                    yield None, cert
        else:
            for process in self.filter_tasks(tasks.pslist(addr_space)):
                scanner = malfind.VadYaraScanner(task = process, rules = DumpCerts.rules)
                for hit, address in scanner.scan():
                    cert = obj.Object(DumpCerts.type_map.get(hit.rule), 
                                            vm = scanner.address_space,
                                            offset = address, 
                                            )
                    if cert.is_valid():
                        yield process, cert
    def calculate(self):
        if self._config.OUTPUT == "xlsx" and not has_openpyxl:
            debug.error("You must install OpenPyxl for xlsx format:\n\thttps://bitbucket.org/ericgazoni/openpyxl/wiki/Home")
        elif self._config.OUTPUT == "xlsx" and not self._config.OUTPUT_FILE:
            debug.error("You must specify an output *.xlsx file!\n\t(Example: --output-file=OUTPUT.xlsx)")

        addr_space = utils.load_as(self._config)

        all_tasks = list(tasks.pslist(addr_space))

        ps_sources = {}
        # The keys are names of process sources. The values
        # are dictionaries whose keys are physical process 
        # offsets and the values are _EPROCESS objects. 
        ps_sources['pslist'] = self.check_pslist(all_tasks)
        ps_sources['psscan'] = self.check_psscan()
        ps_sources['thrdproc'] = self.check_thrdproc(addr_space)
        ps_sources['csrss'] = self.check_csrss_handles(all_tasks)
        ps_sources['pspcid'] = self.check_pspcid(addr_space)
        ps_sources['session'] = self.check_sessions(addr_space)
        if addr_space.profile.metadata.get('major', 0) == 6 and addr_space.profile.metadata.get('minor', 0) >= 2:
            ps_sources['deskthrd'] = {}
        else:
            ps_sources['deskthrd'] = self.check_desktop_thread(addr_space)

        # Build a list of offsets from all sources
        seen_offsets = []
        for source in ps_sources.values():
            for offset in source.keys():
                if offset not in seen_offsets:
                    seen_offsets.append(offset)
                    yield offset, source[offset], ps_sources
Пример #8
0
    def calculate(self):
        addr_space = utils.load_as(self._config)
        
        if not self.is_valid_profile(addr_space.profile):
            debug.error("This plugin only works on XP and 2003")

        ## When verbose is specified, we recalculate the list of SIDs for
        ## services in the registry. Otherwise, we take the list from the 
        ## pre-populated dictionary in getservicesids.py
        if self._config.VERBOSE:
            ssids = getservicesids.GetServiceSids(self._config).calculate()
            for sid, service in ssids:
                self.extrasids[sid] = " (Service: " + service + ")" 
        else:
            for sid, service in getservicesids.servicesids.items():
                self.extrasids[sid] = " (Service: " + service + ")"

        ## Get the user's SIDs from the registry
        self.load_user_sids()

        for proc in tasks.pslist(addr_space):
            if str(proc.ImageFileName).lower() == "services.exe":
                for vad, process_space in proc.get_vads(vad_filter = proc._mapped_file_filter):
                    if vad.FileObject.FileName:
                        name = str(vad.FileObject.FileName).lower()
                        if name.endswith(".evt"):
                            ## Maybe check the length is reasonable, though probably there won't 
                            ## ever be event logs that are multiple GB or TB in size.
                            data = process_space.zread(vad.Start, vad.Length)
                            yield name, data
Пример #9
0
def scan(service_path, profile_name, queue_results):
    # Find Yara signatures, if file is not available, we need to terminate.
    yara_path = os.path.join(os.getcwd(), 'signatures.yar')
    if not os.path.exists(yara_path):
        yara_path = get_resource(os.path.join('rules', 'signatures.yar'))
        if not os.path.exists(yara_path):
            raise DetectorError("Unable to find a valid Yara signatures file!")

    log.info("Selected Yara signature file at %s", yara_path)

    # Retrieve adress space.
    space = get_address_space(service_path, profile_name, yara_path)
    if space == None:
        log.info("Cannot generate address space")
    else:
        log.info("Address space: {0}, Base: {1}".format(space, space.base))
        log.info("Profile: {0}, DTB: {1:#x}".format(space.profile, space.dtb))

    rules = yara.compile(yara_path)

    log.info("Starting yara scanner...")

    matched = []

    for process in tasks.pslist(space):
        # Skip ourselves.
        if process.UniqueProcessId == os.getpid():
            continue

        try:
            process_name = process.ImageFileName
        except:
            process_name = ''

        try:
            try:
                log.debug("Scanning process %s, pid: %d, ppid: %d, exe: %s, cmdline: %s",
                          process_name, process.UniqueProcessId, process.InheritedFromUniqueProcessId, process.ImagePathName, process.CommandLine)
            except:
                log.debug("Scanning process %s, pid: %d", process_name, process.UniqueProcessId)

            for hit in rules.match(pid=process.UniqueProcessId):
                log.warning("Process %s (pid: %d) matched: %s, Values:", process_name, process.UniqueProcessId, hit.rule)

                for entry in hit.strings:
                    log.warning("\t%d, %s, %s", entry[0], entry[1], entry[2])

                # We only store unique results, it's pointless to store results
                # for the same rule.
                if not hit.rule in matched:
                    # Add rule to the list of unique matches.
                    matched.append(hit.rule)

                    # Add match to the list of results.
                    queue_results.put(dict(
                        rule=hit.rule,
                        detection=hit.meta.get('detection'),
                    ))
        except Exception as e:
            log.debug("Unable to scan process: %s", e)
Пример #10
0
	def calculate(self):
		self.kernel_address_space = utils.load_as(self._config)
		self.flat_address_space = utils.load_as(self._config, astype = 'physical')
		if not(bool(self._config.DIR)):
			debug.error("--dir needs to be present")
		if not(bool(self._config.pid) ^ bool(self._config.eproc) ^ bool(self._config.fobj) ^ bool(self._config.pool)):
			if not(bool(self._config.pid) or bool(self._config.eproc) or bool(self._config.fobj) or bool(self._config.pool)):
				debug.error("exactly *ONE* of the options --pid, --eproc, --fobj or --pool must be specified (you have not specified _any_ of these options)")
			else:
				debug.error("exactly *ONE* of the options --pid, --eproc, --fobj or --pool must be specified (you have used _multiple_ such options)")
		if bool(self._config.pid):
			# --pid
			eproc_matches = [ eproc for eproc in tasks.pslist(self.kernel_address_space) if eproc.UniqueProcessId == self._config.pid ]
			if len(eproc_matches) != 1:
				debug.error("--pid needs to take a *VALID* PID argument (could not find PID {0} in the process listing for this memory image)".format(self._config.pid))
			return self.dump_from_eproc(eproc_matches[0])
		elif bool(self._config.eproc):
			# --eproc
			return self.dump_from_eproc(obj.Object("_EPROCESS", offset = self._config.eproc, vm = self.kernel_address_space))
		elif bool(self._config.fobj):
			# --fobj
			try:
				file_object = obj.Object("_FILE_OBJECT", offset = self._config.fobj, vm = self.flat_address_space)
				if bool(self._config.reconstruct):
					# --reconstruct
					return [ (file_object, self.parse_string(file_object.FileName)) ]
				else:
					return filter(None, [ self.dump_file_object(file_object) ])
			except ExportException as exn:
				debug.error(exn)
		else:
			# --pool
			return self.dump_from_pool()
Пример #11
0
    def shimcache_xp(address_space):
        """Enumerate entries from the shared memory section 
        on XP systems."""

        seen = []
        shim = lambda x : (x.Tag == "Vad " and 
                                  x.VadFlags.Protection == 4)

        for process in tasks.pslist(address_space):
            for vad, space in process.get_vads(vad_filter = shim):
    
                if space.read(vad.Start, 4) != "\xEF\xBE\xAD\xDE":
                    continue
                  
                records = obj.Object("ShimRecords", 
                                     offset = vad.Start, 
                                     vm = space)

                for entry in records.Entries:

                    if not entry.is_valid():
                        continue

                    entry_offset = space.vtop(entry.obj_offset)
                    if entry_offset in seen:
                        continue
                    seen.append(entry_offset)

                    yield entry.Path, entry.LastModified, entry.LastUpdate
Пример #12
0
    def calculate(self):
        eproc = {}
        found = {}
        cmdline = {}
        pathname = {}

        # Brute force search for eproc blocks in pool memory
        for eprocess in filescan.PSScan(self._config).calculate():
            eproc[eprocess.obj_offset] = eprocess
            found[eprocess.obj_offset] = 1

        # Walking the active process list.
        # Remove any tasks we find here from the brute force search if the --short option is set.
        # Anything left is something which was hidden/terminated/of interest.
        address_space = utils.load_as(self._config)
        for task in tasks.pslist(address_space):
            phys = address_space.vtop(task.obj_offset)
            if phys in eproc:
                if self._config.SHORT:
                    del eproc[phys]
                    del found[phys]
                else:
                    found[phys] = 0

            # Grab command line and parameters
            peb = task.Peb
            if peb:
                cmdline[phys] = peb.ProcessParameters.CommandLine
                pathname[phys] = peb.ProcessParameters.ImagePathName

        ret = [eproc, found, cmdline, pathname]

        return ret
Пример #13
0
    def calculate(self):
        addr_space = utils.load_as(self._config)
        addr_space.profile.add_types(evt_log_types)
        if addr_space.profile.metadata.get('major', 0) != 5:
            print "This plugin only works on XP and 2K3"
            return

        if self._config.VERBOSE:
            self.reset_current()
            self.set_current("SYSTEM")
            ssids = getservicesids.GetServiceSids.calculate(self)
            for sid, service in ssids:
                self.extrasids[sid] = " (Service: " + service + ")" 
        else:
            for sid in self.extrasids:
                self.extrasids[sid] = " (Service: " + self.extrasids[sid] + ")"

        self.reset_current()
        self.set_current("SOFTWARE")
        for k1 in self.reg_enum_key('SOFTWARE', 'Microsoft\\Windows NT\\CurrentVersion\\ProfileList'):
            val = self.reg_get_value('SOFTWARE',  k1, 'ProfileImagePath')
            sid = k1.split("\\")[-1]
            if val != None:
                self.extrasids[sid] = " (User: "******"\\")[-1] + ")"

        for proc in tasks.pslist(addr_space):
            if str(proc.ImageFileName).lower() == "services.exe":
                map = self.list_mapped_files(proc, pe_only=False, get_data=True)
                for key, (name, buf) in map.items():
                    if name and buf:
                        name = str(name).lower()
                        if name.endswith(".evt"):
                            yield name, buf
Пример #14
0
    def calculate(self):
        addr_space = utils.load_as(self._config)

        tasklist = []
        modslist = []

        if self._config.SCAN:
            if not self._config.KERNEL_ONLY:
                for t in filescan.PSScan(self._config).calculate():
                    v = self.virtual_process_from_physical_offset(addr_space, t.obj_offset)
                    if v:
                        tasklist.append(v)
            if not self._config.PROCESS_ONLY:
                modslist = [m for m in modscan.ModScan(self._config).calculate()]
        else:
            if not self._config.KERNEL_ONLY:
                tasklist = [t for t in tasks.pslist(addr_space)]
            if not self._config.PROCESS_ONLY:
                modslist = [m for m in modules.lsmod(addr_space)]

        for task in tasklist:
            for mod in task.get_load_modules():
                yield task, mod

        for mod in modslist:
            yield None, mod
Пример #15
0
    def calculate(self):
        addr_space = utils.load_as(self._config)

        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: %s' % e)

        mods = dict((mod.DllBase.v(), mod) for mod in modules.lsmod(addr_space))
        # We need the process list to find spaces for some drivers. Enumerate them here
        # instead of inside the find_space function, so we only have to do it once. 
        procs = list(tasks.pslist(addr_space))

        if self._config.BASE:
            if self._config.BASE in mods:
                mod_name = mods[self._config.BASE].BaseDllName
            else:
                mod_name = "UNKNOWN"
            yield addr_space, procs, int(self._config.BASE), mod_name
        else:
            for mod in list(mods.values()):
                if self._config.REGEX:
                    if not mod_re.search(str(mod.FullDllName or '')) and not mod_re.search(str(mod.BaseDllName or '')):
                        continue
                yield addr_space, procs, mod.DllBase.v(), mod.BaseDllName
Пример #16
0
    def _pydeep_page(self):
        """Run pydeep and return the hash"""

        page_sig = None

        try:
            if self._config.SSDEEP_SIG:
                # s = self._config.YARA_RULES
                ## Don't wrap hex or regex rules in quotes
                # if s[0] not in ("{", "/"): s = '"' + s + '"'
                ## Scan for unicode strings
                # if self._config.WIDE: s += "wide"
                # rules = yara.compile(sources = {
                #'n' : 'rule r1 {strings: $a = ' + s + ' condition: $a}'
                # })
                pass
            elif self._config.SSDEEP_FILE:
                # rules = yara.compile(self._config.YARA_FILE)
                pass
            elif self._config.SSDEEP_PIDOFF:
                (pid, base) = self._config.SSDEEP_PIDOFF.split(":")
                for proc in tasks.pslist(self._addr_space):
                    if proc.UniqueProcessId == int(pid):
                        process_space = proc.get_process_address_space()
                        page_data = process_space.zread(int(base, 16), 0x1000)
                        page_sig = pydeep.hash_buf(page_data)
                if page_sig == "3::":
                    debug.error("PID XXX and OFFSET YYY null or not found")
            else:
                debug.error("You must specify an ssdeep hash (-Y), a file to hash (-y), or a PID:BASE pair (-T)")
        except Exception as why:
            debug.error("Cannot compile rules: {0}".format(str(why)))

        return page_sig
Пример #17
0
    def calculate(self):
        """Determines the address space"""
        addr_space = utils.load_as(self._config)

        result = None
        adrs = addr_space
        while adrs:
            if adrs.__class__.__name__ == 'WindowsHiberFileSpace32':
                sr = adrs.ProcState.SpecialRegisters

                peb = obj.NoneObject("Cannot locate a valid PEB")

                # Find the PEB by cycling through processes. This method works 
                # on all versions of Windows x86 and x64. 
                for task in tasks.pslist(addr_space):
                    if task.Peb:
                        peb = task.Peb
                        break

                result = {'header': adrs.get_header(),
                          'sr': sr,
                          'peb': peb,
                          'adrs': adrs }
            adrs = adrs.base

        if result == None:
            debug.error("Memory Image could not be identified or did not contain hiberation information")

        return result
Пример #18
0
    def calculate(self):
        result = {}

        ## Load a new address space
        addr_space = utils.load_as(self._config)
        addr_space.profile.add_types(pslist_types)

        for task in tasks.pslist(addr_space):
            task_info = {}
            task_info['eprocess'] = task
            task_info['image_file_name'] = task.ImageFileName or 'UNKNOWN'
            task_info['process_id'] = task.UniqueProcessId
            task_info['active_threads'] = task.ActiveThreads
            task_info['inherited_from'] = task.InheritedFromUniqueProcessId
            task_info['handle_count'] = task.ObjectTable.HandleCount
            task_info['create_time'] = task.CreateTime

            ## Get the Process Environment Block - Note that _EPROCESS
            ## will automatically switch to process address space by
            ## itself.
            if self._config.VERBOSE > 1:
                peb = task.Peb
                if peb:
                    task_info['command_line'] = peb.ProcessParameters.CommandLine
                    task_info['ImagePathName'] = peb.ProcessParameters.ImagePathName

                task_info['Audit ImageFileName'] = task.SeAuditProcessCreationInfo.ImageFileName.Name or 'UNKNOWN'

            result[int(task_info['process_id'])] = task_info

        return result
Пример #19
0
    def find_scouts(self):
        """ Find all 'Scout' level implants using their distinctive watermarks - these index the configuration files, allowing us to obtain AES key information """
        scouts = []
        # Dynamically generate Yara rules from watermark
        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        addr_space = utils.load_as(self._config)
        
        if not self.is_valid_profile(addr_space.profile):
            debug.error("This command does not support the selected profile.")
        
        rules = self.gen_yara_rules()

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task = task, rules = rules)

            for hit, address in scanner.scan():
                hitdata = scanner.address_space.zread(address, 8)
                # Second hit from Yara rule is the 'FIRST_WI' string that we use to differentiate from Elite implants
                # This is a wide string, so the second character is a '\x00' - the first hit is on the watermark that we want to use.
                if hitdata[1] != "\x00": 
                    scouts.append({"watermark":hitdata, "confidence":4, "pid":str(task.UniqueProcessId), "task":task, "process_name":str(task.ImageFileName), "address_space":scanner.address_space, "address":address, "implant_type":"Scout", "threat_actor":hit.rule.split('__')[2]})

        return scouts
Пример #20
0
    def calculate(self):

        addr_space = utils.load_as(self._config)

        if not self.is_valid_profile(addr_space.profile):
            debug.error("This command does not support the selected profile.")

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            task_space = task.get_process_address_space()

            # We must have a process AS
            if not task_space:
                continue

            winsock = None

            # Locate the winsock DLL
            for mod in task.get_load_modules():
                if str(mod.BaseDllName or "").lower() == "ws2_32.dll":
                    winsock = mod
                    break

            if not winsock:
                continue

            # Resolve the closesocket API
            closesocket = winsock.getprocaddress("closesocket")

            if not closesocket:
                continue

            for vad, process_space in task.get_vads(vad_filter=self._zeus_filter):

                if obj.Object("_IMAGE_DOS_HEADER", offset=vad.Start, vm=process_space).e_magic != 0x5A4D:
                    continue

                data = process_space.zread(vad.Start, vad.Length)

                scanner = impscan.ImpScan(self._config).call_scan
                calls = list(scanner(task_space, vad.Start, data))

                for (_, iat_loc, call_dest) in calls:
                    if call_dest != closesocket:
                        continue

                    # Read the DWORD directly after closesocket
                    struct_base = obj.Object("Pointer", offset=iat_loc + 4, vm=task_space)

                    # To be valid, it must point within the vad segment
                    if struct_base < vad.Start or struct_base > (vad.Start + vad.End):
                        continue

                    # Grab the key data
                    key = task_space.read(struct_base + 0x2A, RC4_KEYSIZE)

                    # Greg's sanity check
                    if len(key) != RC4_KEYSIZE or key[-2:] != "\x00\x00":
                        continue

                    yield task, struct_base, key
Пример #21
0
    def calculate(self):
        kernel_space = utils.load_as(self._config)
        
        ## Select the tags to scan for. Always find visited URLs,
        ## but make freed and redirected records optional. 
        tags = ["URL "]
        if self._config.LEAK:
            tags.append("LEAK")
        if self._config.REDR:
            tags.append("REDR")
            
        ## Define the record type based on the tag
        tag_records = {
            "URL " : "_URL_RECORD", 
            "LEAK" : "_URL_RECORD", 
            "REDR" : "_REDR_RECORD"}
 
        ## Enumerate processes based on the --pid and --offset 
        for proc in self.filter_tasks(tasks.pslist(kernel_space)):
        
            ## Acquire a process specific AS
            ps_as = proc.get_process_address_space()
            
            for hit in proc.search_process_memory(tags):
                ## Get a preview of the data to see what tag was detected 
                tag = ps_as.read(hit, 4)
                
                ## Create the appropriate object type based on the tag 
                record = obj.Object(tag_records[tag], offset = hit, vm = ps_as)
                if record.is_valid():
                    yield proc, record
Пример #22
0
    def calculate(self):
        kernel_space = utils.load_as(self._config)
        
        #This should be collected from online eks r0ar.net/memory/whitelist.txt
        #check for efficiency stuff - process slow atm
        whitelist = open('/Users/Lunde/Documents/mrwhite.txt').read().splitlines()
        matchlist = []

        for line in whitelist:
            for process in tasks.pslist(kernel_space):
                if(str(line) == str(process.ImageFileName)):
                    matchlist.append(line)
        
        matchlist = sorted(set(matchlist))
        for process in tasks.pslist(kernel_space):
            if(str(process.ImageFileName) not in matchlist):
                yield process
Пример #23
0
    def calculate(self):
        addr_space = utils.load_as(self._config)
        self.mscarvecontrol = MsCarveDisplayControl(self.config)
        self.mscarvecontrol.runconfig()

        for proc in tasks.pslist(addr_space):
            #process_space = proc.get_process_address_space()
            yield proc 
Пример #24
0
 def calculate(self):
     """Calculate and carry out any processing that may take time upon the image"""
     # Load the address space
     addr_space = utils.load_as(self._config)
     #find some browsery processes
     for proc in tasks.pslist(addr_space):
         if str(proc.ImageFileName).lower() in("iexplore.exe","firefox","firefox.exe","chrome","chrome.exe"):
             yield proc    
Пример #25
0
    def calculate(self):

        if not has_yara:
            debug.error("You must install yara")

        addr_space = utils.load_as(self._config)

        if not self.is_valid_profile(addr_space.profile):
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=self.signatures)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            task_space = task.get_process_address_space()

            # We must have a process AS
            if not task_space:
                continue

            for vad, process_space in task.get_vads():

                if obj.Object("_IMAGE_DOS_HEADER", offset=vad.Start, vm=process_space).e_magic != 0x5A4D:
                    continue

                data = process_space.zread(vad.Start, vad.Length)

                # check for the signature with YARA, both hits must be present
                matches = rules.match(data=data)

                if len(matches) < 2:
                    continue

                try:
                    dos_header = obj.Object("_IMAGE_DOS_HEADER", offset=vad.Start, vm=task_space)
                    nt_header = dos_header.get_nt_header()
                except (ValueError, exceptions.SanityCheckException):
                    continue

                # There must be more than 2 sections
                if nt_header.FileHeader.NumberOfSections < 2:
                    continue

                # Get the last PE section's data
                sections = list(nt_header.get_sections(False))
                last_sec = sections[-1]
                last_sec_data = task_space.zread((last_sec.VirtualAddress + vad.Start), last_sec.Misc.VirtualSize)

                success = self.check_matches(task_space, vad, matches, last_sec_data)

                if not success:
                    continue

                success = self.scan_key(task_space)

                if not success:
                    continue

                yield task, vad, self.params
Пример #26
0
    def calculate(self):
        """Calculate and carry out any processing that may take time upon the image"""
        # Load the address space
        addr_space = utils.load_as(self._config)

        # Call a subfunction so that it can be used by other plugins
        for proc in tasks.pslist(addr_space):
            if str(proc.ImageFileName).lower() in("iexplore.exe","firefox","firefox.exe","chrome","chrome.exe"):
                yield proc
Пример #27
0
    def calculate(self):

        ## Load a new address space
        addr_space = utils.load_as(self._config)

        return dict(
                (int(task.UniqueProcessId), task)
                for task in tasks.pslist(addr_space)
                )
Пример #28
0
 def calculate(self):
     if not has_yara:
         debug.error("Please install Yara from code.google.com/p/yara-project")
     addr_space = utils.load_as(self._config)
     rules = yara.compile(sources=rat_9002_sig)
     
     for task in self.filter_tasks(tasks.pslist(addr_space)):
         scanner = malfind.VadYaraScanner(task = task, rules = rules)
         for hit, address in scanner.scan():
             yield (task, address, hit, scanner.address_space.zread(address, 1024))
Пример #29
0
    def calculate(self):
        """Calculate and carry out any processing that may take time upon the image"""
        # Load the address space
        addr_space = utils.load_as(self._config)

        print("Bulk Exractor Starting")
        print("Note: data is extracted using regex on a dirty dump of memory and may miss a minor percentage of edge cases.")
        # Call a subfunction so that it can be used by other plugins
        for proc in tasks.pslist(addr_space):
            if self._config.PID == proc.UniqueProcessId:
                yield proc
Пример #30
0
 def get_ghost_process(self, magic, mal_process, add_space):
     rule = "rule Gh0strat_process {strings: $any_variant = " + '"' + magic + '"'+ " condition: $any_variant}"
     ghost_proc_sig = {'ghostrat_process' : rule }
     rules = yara.compile(sources=ghost_proc_sig)
     for task in self.filter_tasks(tasks.pslist(add_space)):
         scanner = malfind.VadYaraScanner(task = task, rules = rules)
         for hit, address in scanner.scan():
             if task.obj_name == "_EPROCESS":
                 process = str(task.ImageFileName)
                 pid = task.UniqueProcessId
                 mal_process[process] = pid
Пример #31
0
    def calculate(self):
        addr_space = utils.load_as(self._config)

        # we currently don't use this on x64 because for some reason the 
        # x64 version actually doesn't create a DisplayVersion value 
        memory_model = addr_space.profile.metadata.get('memory_model')
        if memory_model == '32bit':
            regapi = registryapi.RegistryApi(self._config)
            regapi.reset_current()
            regapi.set_current(hive_name = "software")
            x86key = "Microsoft\\Windows\\CurrentVersion\\Uninstall"
            x64key = "Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
            for subkey in regapi.reg_get_all_subkeys(None, key = x86key):
                if str(subkey.Name) == "TrueCrypt":
                    subpath = x86key + "\\" + subkey.Name
                    version = regapi.reg_get_value("software", 
                                            key = subpath, 
                                            value = "DisplayVersion")
                    if version:
                        yield "Registry Version", "{0} Version {1}".format(
                            str(subkey.Name),
                            version)

        scanner = TrueCryptPassphrase(self._config)
        for offset, passphrase in scanner.calculate():
            yield "Password", "{0} at offset {1:#x}".format(
                        passphrase, offset)

        for proc in tasks.pslist(addr_space):
            if str(proc.ImageFileName).lower() == "truecrypt.exe":     
                yield "Process", "{0} at {1:#x} pid {2}".format(
                        proc.ImageFileName,
                        proc.obj_offset, 
                        proc.UniqueProcessId)   

        scanner = svcscan.SvcScan(self._config)
        for service in scanner.calculate():
            name = str(service.ServiceName.dereference())
            if name == "truecrypt":
                yield "Service", "{0} state {1}".format(
                        name, 
                        service.State)

        for mod in modules.lsmod(addr_space):
            basename = str(mod.BaseDllName or '').lower()
            fullname = str(mod.FullDllName or '').lower()
            if (basename.endswith("truecrypt.sys") or 
                        fullname.endswith("truecrypt.sys")):
                yield "Kernel Module",  "{0} at {1:#x} - {2:#x}".format(
                        mod.BaseDllName, 
                        mod.DllBase, 
                        mod.DllBase + mod.SizeOfImage)

        scanner = filescan.SymLinkScan(self._config)
        for symlink in scanner.calculate():
            object_header = symlink.get_object_header()
            if "TrueCryptVolume" in str(symlink.LinkTarget or ''):
                yield "Symbolic Link", "{0} -> {1} mounted {2}".format(
                        str(object_header.NameInfo.Name or ''), 
                        str(symlink.LinkTarget or ''), 
                        str(symlink.CreationTime or ''))

        scanner = filescan.FileScan(self._config)
        for fileobj in scanner.calculate():
            filename = str(fileobj.file_name_with_device() or '')
            if "TrueCryptVolume" in filename:
                yield "File Object", "{0} at {1:#x}".format(
                        filename,
                        fileobj.obj_offset)
        
        scanner = filescan.DriverScan(self._config)
        for driver in scanner.calculate():
            object_header = driver.get_object_header() 
            driverext = driver.DriverExtension
            drivername = str(driver.DriverName or '')
            servicekey = str(driverext.ServiceKeyName or '')
            if (drivername.endswith("truecrypt") or 
                        servicekey.endswith("truecrypt")):
                yield "Driver", "{0} at {1:#x} range {2:#x} - {3:#x}".format(
                        drivername, 
                        driver.obj_offset, 
                        driver.DriverStart, 
                        driver.DriverStart + driver.DriverSize)
                for device in driver.devices():
                    header = device.get_object_header()
                    devname = str(header.NameInfo.Name or '')
                    type = devicetree.DEVICE_CODES.get(device.DeviceType.v())
                    yield "Device", "{0} at {1:#x} type {2}".format(
                        devname or "<HIDDEN>", 
                        device.obj_offset, 
                        type or "UNKNOWN")
                    if type == "FILE_DEVICE_DISK":
                        data = addr_space.read(device.DeviceExtension, 2000)
                        ## the file-hosted container path. no other fields in
                        ## the struct are character based, so we should not 
                        ## hit false positives on this scan. 
                        offset = data.find("\\\x00?\x00?\x00\\\x00")
                        if offset == -1:
                            container = "<HIDDEN>"
                        else:
                            container = obj.Object("String", length = 255, 
                                        offset = device.DeviceExtension + offset, 
                                        encoding = "utf16",
                                        vm = addr_space)
                        yield "Container", "Path: {0}".format(container)
Пример #32
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=tscookie_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                data = proc_addr_space.zread(vad_base_addr,
                                             end - vad_base_addr)

                config_data = []

                dll_index = data.find(MZ_HEADER)
                if dll_index:
                    dll_data = data[dll_index:]
                    dll = pefile.PE(data=dll_data)
                else:
                    continue

                if "TSCookie" in str(hit):
                    d = 2
                else:
                    d = 0

                for pattern in CONFIG_PATTERNS:
                    mc = re.search(pattern, dll_data)
                    if mc:
                        try:
                            (config_rva, ) = unpack(
                                "=I", dll_data[mc.start() + d + 1:mc.start() +
                                               d + 5])
                            config_addr = dll.get_physical_by_rva(
                                config_rva -
                                dll.NT_HEADERS.OPTIONAL_HEADER.ImageBase)
                            break
                        except:
                            print("[!] Not found config data.\n")

                config_size = 0
                enc = []
                while not (
                        dll_data[config_addr + config_size] == "\x00"
                        and dll_data[config_addr + config_size + 1] == "\x00"
                        and dll_data[config_addr + config_size + 2] == "\x00"):
                    enc.append(dll_data[config_addr + config_size])
                    config_size += 1

                enc_config_data = "".join(enc)
                if config_size == 0x8D4:
                    rc4key_length = 4
                else:
                    rc4key_length = 0x80

                try:
                    enc_config = enc_config_data[rc4key_length:]
                    rc4key = enc_config_data[:rc4key_length]
                    config = self.rc4(enc_config, rc4key)
                    if len(config) > 0:
                        if "TSCookie" in str(hit):
                            config_data.append(self.parse_config(config))
                        else:
                            config_data.append(
                                self.parse_loader_config(config))
                except:
                    print("[!] Not found config data.\n")

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break
Пример #33
0
    def calculate(self):

        if not has_distorm3:
            debug.warning("For best results please install distorm3")

        # Checks that subclass AbstractThreadCheck
        checks = registry.get_plugin_classes(AbstractThreadCheck)

        # If --listtags is chosen, just print the tags and return
        if self._config.LISTTAGS:
            for cls_name, cls in checks.items():
                sys.stdout.write("{0:<20} {1}\n".format(
                    cls_name, pydoc.getdoc(cls)))
            return

        addr_space = utils.load_as(self._config)
        system_range = tasks.get_kdbg(
            addr_space).MmSystemRangeStart.dereference_as("Pointer")

        # Only show threads owned by particular processes
        if self._config.PID:
            pidlist = [int(p) for p in self._config.PID.split(',')]
        else:
            pidlist = []

        # Get sorted list of kernel modules
        mods = dict((addr_space.address_mask(mod.DllBase), mod)
                    for mod in modules.lsmod(addr_space))
        mod_addrs = sorted(mods.keys())

        # Gather processes
        all_tasks = list(tasks.pslist(addr_space))

        # Are we on x86 or x64. Save this for render_text
        self.bits32 = addr_space.profile.metadata.\
            get("memory_model", "32bit") == "32bit"

        # Get a list of hooked SSDTs but only on x86
        if self.bits32:
            hooked_tables = self.get_hooked_tables(addr_space)
        else:
            hooked_tables = None

        # Dictionary to store threads. Keys are physical offsets of
        # ETHREAD objects. Values are tuples, where the first item is
        # a boolean specifying if the object was found by scanning and
        # the second item is the actual ETHREAD object.
        seen_threads = dict()

        # Gather threads by list traversal of active/linked processes
        for task in self.filter_tasks(all_tasks):
            for thread in task.ThreadListHead.\
                    list_of_type("_ETHREAD", "ThreadListEntry"):
                seen_threads[thread.obj_vm.vtop(thread.obj_offset)] = (False,
                                                                       thread)

        # Now scan for threads and save any that haven't been seen
        for thread in modscan.ThrdScan(self._config).calculate():
            if not seen_threads.has_key(thread.obj_offset):
                seen_threads[thread.obj_offset] = (True, thread)

        # Keep a record of processes whose DLLs we've already enumerated
        process_dll_info = {}

        for _offset, (found_by_scanner, thread) in seen_threads.items():

            # Skip processes the user doesn't want to see
            if pidlist and thread.Cid.UniqueProcess not in pidlist:
                continue

            # Do we need to gather DLLs for module resolution
            if addr_space.address_compare(thread.StartAddress,
                                          system_range) != -1:
                owner = tasks.find_module(
                    mods, mod_addrs,
                    addr_space.address_mask(thread.StartAddress))
            else:
                owning_process = thread.owning_process()
                if not owning_process.is_valid():
                    owner = None
                else:
                    try:
                        user_mod_addrs, user_mods = process_dll_info[
                            owning_process.obj_offset]
                    except KeyError:
                        user_mods = dict(
                            (addr_space.address_mask(mod.DllBase), mod)
                            for mod in owning_process.get_load_modules())
                        user_mod_addrs = sorted(user_mods.keys())
                        process_dll_info[owning_process.obj_offset] = (
                            user_mod_addrs, user_mods)
                    owner = tasks.find_module(
                        user_mods, user_mod_addrs,
                        addr_space.address_mask(thread.StartAddress))

            if owner:
                owner_name = str(owner.BaseDllName or '')
            else:
                owner_name = "UNKNOWN"

            # Replace the dummy class with an instance
            instances = dict(
                (cls_name,
                 cls(thread, mods, mod_addrs, hooked_tables, found_by_scanner))
                for cls_name, cls in checks.items())

            yield thread, addr_space, mods, mod_addrs, \
                        instances, hooked_tables, system_range, owner_name
    def calculate(self):

        if not has_pydeep:
            debug.error(
                "Please install ssdeep and pydeep from http://ssdeep.sourceforge.net/ and https://github.com/kbandla/pydeep"
            )

        addr_space = utils.load_as(self._config)
        self._addr_space = addr_space

        page_sig = self._pydeep_page()
        if page_sig == None:
            debug.error("Pydeep was not able to hash the input")

        if self._config.KERNEL:

            # Find KDBG so we know where kernel memory begins. Do not assume
            # the starting range is 0x80000000 because we may be dealing with
            # an image with the /3GB boot switch.
            kdbg = tasks.get_kdbg(addr_space)

            start = kdbg.MmSystemRangeStart.dereference_as("Pointer")

            # Modules so we can map addresses to owners
            mods = dict((addr_space.address_mask(mod.DllBase), mod)
                        for mod in modules.lsmod(addr_space))
            mod_addrs = sorted(mods.keys())

            # There are multiple views (GUI sessions) of kernel memory.
            # Since we're scanning virtual memory and not physical,
            # all sessions must be scanned for full coverage. This
            # really only has a positive effect if the data you're
            # searching for is in GUI memory.
            sessions = []

            for proc in tasks.pslist(addr_space):
                sid = proc.SessionId
                # Skip sessions we've already seen
                if sid == None or sid in sessions:
                    continue

                session_space = proc.get_process_address_space()
                if session_space == None:
                    continue

                sessions.append(sid)
                scanner = DiscontigSSDeepScanner(address_space=session_space,
                                                 rules=rules)

                for hit, address in scanner.scan(start_offset=start):
                    module = tasks.find_module(
                        mods, mod_addrs, addr_space.address_mask(address))
                    yield (module, address, hit,
                           session_space.zread(address - self._config.REVERSE,
                                               self._config.SIZE))

        else:
            for task in self.filter_tasks(tasks.pslist(addr_space)):
                scanner = VadSSDeepScanner(task=task, pydeep_hash=page_sig)
                for sig, vStart, vLength, offset, alike in scanner.scan():
                    yield (task, sig, vStart, vLength, offset, alike,
                           scanner.address_space.zread(offset, 0x1000))
Пример #35
0
    def calculate(self):
        self.DumpFolder = (self._config.DumpFolder or None)
        self.logg = open(self._config.FailFile, mode="w+", buffering=8192)
        self.logg.write(
            "On Windows, use \"type [Filename]\" for best results (Win10) {} JIT hash log file\n"
            .format(fg("cornflower_blue")))
        # get the null hash (at runtime in case a different hash is used etc..)
        null_page = bytearray(4096)
        self.null_hash = self.HashPage(null_page)

        addr_space = utils.load_as(self._config)
        if isinstance(
                addr_space, volatility.plugins.addrspaces.intel.IA32PagedMemory
        ) and not isinstance(
                addr_space,
                volatility.plugins.addrspaces.intel.IA32PagedMemoryPae):
            raise "The memory model of this memory dump dates from the 1990's and does not support execute protection."

        outputJobs = None
        taski = 0
        taskCnt = 0
        tasklist = tasks.pslist(addr_space)
        for _ in tasks.pslist(addr_space):
            taskCnt += 1

        print("{}{}{} [{}]{}".format(
            fg("chartreuse_1"),
            "pdb2json JIT PageHash calls under way...  endpoint ",
            fg("hot_pink_1b"),
            self.JITHashServer,
            fg("sky_blue_1"),
            attrs=["bold"]))
        bformat = "{elapsed}{l_bar}{postfix}{bar}"
        self.TotalBar = tqdm(
            desc="{}TotalProgress".format(fg("cornflower_blue"),
                                          total=taskCnt,
                                          position=0,
                                          mininterval=0.5,
                                          bar_format=bformat))
        # The timer is reset here since were not counting the coldstartup time
        self.StartTime = time.time()
        for task in tasklist:
            taski += 1

            proc_as = task.get_process_address_space()
            mods = []
            # Volatility workaround as there is not a consistant interface I know of
            # to handle AS the same way for kernel & user
            if task.UniqueProcessId == 4:
                mods = list(modules.lsmod(addr_space))
                proc_as = addr_space
            else:
                mods = list(task.get_load_modules())

            TaskName = "[" + task.ImageFileName + "-" + str(
                task.UniqueProcessId) + "]"

            taskBar = tqdm(desc=TaskName,
                           total=len(mods),
                           position=1,
                           leave=False,
                           mininterval=0.5,
                           bar_format=bformat)
            p = dict({
                "Name": TaskName,
                "Task": task,
                "TaskBlockCount": 0,
                "ModContext": [],
                "bar": taskBar
            })
            for mod in mods:
                #@                taskBar.set_postfix_str('{} modules'.format(len(mods), refresh=True)
                hashAddr = []
                hashVal = []
                for vpage, nx in self.mod_get_ptes(mod, proc_as):
                    if (nx):
                        continue
                    data = proc_as.read(vpage, 4096)
                    if data is None or data is self.null_hash:
                        continue
                    hashAddr.append(str(vpage))
                    hashVal.append(self.HashPage(data))
            # these statements are yet another workaround for volatility
            # for some unknown reason these data structures have never been written into Volatility...
            # of course you can acquire the timestamp by reading the nt_header/fileheader/etc but that data is
            # significantly lower quality given that it can be modified at any time.  The kernel data structure
            # remains valid unless the attacker kills the process etc... In any event (hah) since this value has never changed
            # I hard coded it here for simplicity.  Perhaps I should enforce always using it, will circle back 360 on that.. :O

                timevalue = mod.TimeDateStamp
                #this should only work for kernel space modules
                if timevalue == 0 and task.UniqueProcessId == 4:
                    timeLoc = self.to_int64(mod.v() + 0x9c)
                    redInBytes = addr_space.read(timeLoc, 4)
                    if redInBytes is not None and len(redInBytes) == 4:
                        timevalue = unpack("<L", redInBytes)[0]
                req_hdr = {
                    "ModuleName":
                    str(mod.FullDllName or ''),
                    "ImageSize":
                    str(mod.SizeOfImage),
                    "BaseAddress":
                    str(mod.DllBase),
                    "AllocationBase":
                    str(mod.DllBase),
                    "TimeDateStamp":
                    str(int(timevalue)),
                    "HdrHash":
                    self.HashPage(proc_as.read(mod.DllBase, 4096)),
                    "HashSet": [{
                        "Address": a,
                        "Hash": h
                    } for a, h in zip(hashAddr, hashVal)]
                }
                if req_hdr["ModuleName"] is '':
                    self.logg.write(
                        "{}{}{}: Unable to scan anonymous executable memory. {:#x} length: {:#x}{}.\n"
                        .format(bg("black"), fg("yellow_2"), TaskName,
                                mod.DllBase, mod.SizeOfImage,
                                fg("cornflower_blue")))
                    filename = "{}/{}-{:#x}".format(self.DumpFolder, TaskName,
                                                    mod.DllBase)
                    open(filename, 'w').close()
                    for vpage in range(mod.DllBase,
                                       mod.DllBase + mod.SizeOfImage, 4096):
                        data = proc_as.read(vpage, 4096)
                        if self.DumpFolder is not None and data is not None:
                            with open(filename, 'ab') as block:
                                block.write(bytearray(data))
                else:
                    LocalMod = dict({
                        "Module": mod,
                        "Ctx": p,
                        "ModBlockCount": hashAddr.count,
                        "json": req_hdr,
                        "AS": addr_space
                    })
                    p["TaskBlockCount"] = p["TaskBlockCount"] + len(hashAddr)
                    taskBar.update(1)
                    self.pool.spawn(self.pozt, LocalMod)

            #= [gevent.spawn(self.pozt, cx) for cx in p["ModContext"]]
            #gevent.wait(outputJobs)
            self.TotalBar.update(1)
Пример #36
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=datper_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                data = proc_addr_space.zread(vad_base_addr,
                                             end - vad_base_addr)

                config_data = []

                try:
                    pe = pefile.PE(data=data)
                except:
                    sys.exit("[!] could not parse as a PE file")

                config_size = CONFSIZE

                if pe.FILE_HEADER.Machine in (
                        pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_IA64'],
                        pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']):
                    enc = self.get_config_data_64(data, pe)
                else:
                    enc = self.get_config_data_32(data, pe, vad_base_addr)

                dec = ""
                for key in RC4KEY:
                    for rc4key_seed in range(0xFF):
                        dec = self.custom_rc4(enc, key, rc4key_seed)
                        dec = self.decrypt(dec)
                        for dline in config_delimiter:
                            if dline in dec:
                                break
                        else:
                            continue
                        break
                    else:
                        continue
                    break

                if dec == "":
                    dec = self.decrypt(enc)
                    for dline in config_delimiter:
                        if dline in dec:
                            key = "NULL"
                            rc4key_seed = "NULL"
                            break

                p_data = OrderedDict()
                if dec != "":
                    p_data["RC4 key"] = key
                    p_data["RC4 Sbox seed"] = rc4key_seed
                    p_data["Config delimiter"] = dline
                    idx = 0
                    for e in (dec.split(dline)):
                        try:
                            p_data[idx_list[idx]] = e
                        except:
                            p_data["Unknown " + str(idx)] = e
                        idx += 1
                else:
                    outfd.write("[!] failed to decrypt\n")

                config_data.append(p_data)

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break
Пример #37
0
    def calculate(self):

        space = utils.load_as(self._config)

        # enumerate system threads (0x00000010 = PS_CROSS_THREAD_FLAGS_SYSTEM)
        system_threads = [
            t for t in modscan.ThrdScan(self._config).calculate()
            if t.CrossThreadFlags & 0x00000010
        ]

        # find and dump the malicious kernel driver
        for item in filescan.DriverScan(self._config).calculate():

            # unpack the parameters
            (object, driver, extension, object_name) = item

            # looking for unnamed driver objects
            if driver.DriverName.Length != 0:
                continue

            # the first and only device should be ACPI#PNP[...]
            device = obj.Object("_DEVICE_OBJECT",
                                offset=driver.DeviceObject,
                                vm=space)

            # get the device's object header
            object = obj.Object("_OBJECT_HEADER", \
                offset = device.obj_offset - \
                device.obj_vm.profile.get_obj_offset("_OBJECT_HEADER", "Body"), \
                vm = space)

            object.kas = space
            device_name = object.get_object_name()

            # did we find zeroaccess?
            if not str(device_name).startswith("ACPI#PNP"):
                continue

            sys.stdout.write("DriverObject:  {0:#x}\n".format(
                device.DriverObject))
            sys.stdout.write("  DriverStart: {0:#x}\n".format(
                driver.DriverStart))
            sys.stdout.write("  DriverSize:  {0:#x}\n".format(
                driver.DriverSize))
            sys.stdout.write("DeviceObject:  {0:#x} {1}\n".format(
                device.obj_offset, device_name))

            # dump the driver
            file_name = "Driver.{0:#x}.sys".format(driver.DriverStart)
            self.dump_pe(space, driver.DriverStart, file_name)

            # now what we know the memory range, look for bad threads
            for thread in system_threads:

                if thread.StartAddress > driver.DriverStart and \
                        thread.StartAddress < driver.DriverStart + driver.DriverSize:

                    sys.stdout.write("Bad Thread:    {0:#x} Tid {1}\n".format(\
                        thread.obj_offset,
                        thread.Cid.UniqueThread))

        # now find and dump the fake usermode ADS process
        for proc in tasks.pslist(space):

            for dll in proc.Peb.Ldr.InLoadOrderModuleList.list_of_type(\
                "_LDR_DATA_TABLE_ENTRY", "InLoadOrderLinks"):

                # look for the ADS name
                if str(dll.BaseDllName).find(":") != -1:

                    sys.stdout.write("Fake ADS EXE:  {0} pid {1} base {2:#x}\n".format(\
                        proc.ImageFileName,
                        proc.UniqueProcessId,
                        dll.DllBase))

                    file_name = "Dll.{0:#x}.{1:#x}.dll".format(
                        proc.obj_offset, dll.DllBase)
                    self.dump_pe(proc.get_process_address_space(), dll.DllBase,
                                 file_name)
Пример #38
0
 def find_lsass(self):
     addr_space = utils.load_as(self._config)
     for task in tasks.pslist(addr_space):
         if str(task.ImageFileName) == 'lsass.exe':
             return task
Пример #39
0
class ModDump(procdump.ProcDump):
    """Dump a kernel driver to an executable file sample"""
    def __init__(self, config, *args, **kwargs):
        procdump.ProcDump.__init__(self, config, *args, **kwargs)
        config.remove_option("PID")
        config.remove_option("OFFSET")
        config.add_option('REGEX',
                          short_option='r',
                          help='Dump modules matching REGEX',
                          action='store',
                          type='string')
        config.add_option('IGNORE-CASE',
                          short_option='i',
                          help='Ignore case in pattern match',
                          action='store_true',
                          default=False)
        config.add_option('BASE',
                          short_option='b',
                          default=None,
                          help='Dump driver with BASE address (in hex)',
                          action='store',
                          type='int')

    @cache.CacheDecorator(
        lambda self: "tests/moddump/regex={0}/ignore-case={1}/base={2}".format(
            self._config.REGEX, self._config.IGNORE_CASE, self._config.BASE))
    def calculate(self):
        if self._config.DUMP_DIR == None:
            debug.error("Please specify a dump directory (--dump-dir)")
        if not os.path.isdir(self._config.DUMP_DIR):
            debug.error(self._config.DUMP_DIR + " is not a directory")

        addr_space = utils.load_as(self._config)

        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, e:
                debug.error('Error parsing regular expression: {0}'.format(e))

        mods = dict(
            (mod.DllBase.v(), mod) for mod in modules.lsmod(addr_space))
        # We need the process list to find spaces for some drivers. Enumerate them here
        # instead of inside the find_space function, so we only have to do it once.
        procs = list(tasks.pslist(addr_space))

        if self._config.BASE:
            if mods.has_key(self._config.BASE):
                mod_name = mods[self._config.BASE].BaseDllName
            else:
                mod_name = "UNKNOWN"
            yield addr_space, procs, int(self._config.BASE), mod_name
        else:
            for mod in mods.values():
                if self._config.REGEX:
                    if not mod_re.search(str(mod.FullDllName
                                             or '')) and not mod_re.search(
                                                 str(mod.BaseDllName or '')):
                        continue
                yield addr_space, procs, mod.DllBase.v(), mod.BaseDllName
Пример #40
0
    def update_vads(self):
        '''
        Call volatility to obtain VADS.
        '''
        if self.unpickled:
            return
        import volatility.obj as obj
        import volatility.win32.tasks as tasks
        import volatility.plugins.vadinfo as vadinfo
        from utils import get_addr_space

        addr_space = get_addr_space(self.get_pgd())

        eprocs = [
            t for t in tasks.pslist(addr_space)
            if t.UniqueProcessId == self.pid
        ]
        for task in eprocs:
            heaps = task.Peb.ProcessHeaps.dereference()
            modules = [mod.DllBase for mod in task.get_load_modules()]
            stacks = []
            for thread in task.ThreadListHead.list_of_type(
                    "_ETHREAD", "ThreadListEntry"):
                teb = obj.Object("_TEB",
                                 offset=thread.Tcb.Teb,
                                 vm=task.get_process_address_space())
                if teb:
                    stacks.append(teb.NtTib.StackBase)
            for vad in task.VadRoot.traverse():
                if vad is not None:
                    vad_type = ""
                    if vad.Start in heaps:
                        # Heaps
                        vad_type = "H"
                    elif vad.Start in modules:
                        # Module
                        vad_type = "M"
                    elif vad.Start in stacks:
                        # Stacks
                        vad_type = "S"
                    else:
                        vad_type = "-"

                    try:
                        protection = vadinfo.PROTECT_FLAGS.get(
                            vad.VadFlags.Protection.v(), "")
                    except Exception:
                        traceback.print_exc()

                    fileNameWithDevice = ""
                    try:
                        control_area = vad.ControlArea
                        # even if the ControlArea is not NULL, it is only meaningful
                        # for shared (non private) memory sections.
                        if vad.VadFlags.PrivateMemory != 1 and control_area:
                            if control_area:
                                file_object = vad.FileObject
                                if file_object:
                                    fileNameWithDevice = file_object.file_name_with_device(
                                    )
                    except AttributeError:
                        pass

                    try:
                        new_vad = VADRegion(vad.Start, (vad.End - vad.Start),
                                            self, fileNameWithDevice,
                                            str(vad.Tag), vad_type,
                                            (vad.VadFlags.PrivateMemory == 1),
                                            protection)
                    except Exception:
                        traceback.print_exc()

                    if new_vad not in self.vads:
                        self.vads.append(new_vad)
Пример #41
0
def dump(pgd_list, pyrebox_print, path="/tmp/unpacker_results"):
    '''
    Dump the process, modules, vads..., given a list of process address spaces and a path.
    '''
    import volatility.constants as constants
    import volatility.exceptions as exceptions
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    from utils import get_addr_space
    import api

    # Delete contents, and create directory under path
    if os.path.isdir(path):
        shutil.rmtree(path)
    os.mkdir(path)

    try:
        # Get volatility address space
        addr_space = get_addr_space()

        # Get list of processes (tasks) from volatility
        eprocs = [
            t for t in tasks.pslist(addr_space)
            if t.Pcb.DirectoryTableBase.v() in pgd_list
        ]

        # For every selected task
        for task in eprocs:
            # Code adapted from procdump (volatility)
            task_space = task.get_process_address_space()
            if task_space is None:
                pyrebox_print("Error: Cannot acquire process AS")
                return
            elif task.Peb is None:
                # we must use m() here, because any other attempt to
                # reference task.Peb will try to instantiate the _PEB
                pyrebox_print(
                    "Error: PEB at {0:#x} is unavailable (possibly due to paging)"
                    .format(task.m('Peb')))
                return
            elif task_space.vtop(task.Peb.ImageBaseAddress) is None:
                pyrebox_print(
                    "Error: ImageBaseAddress at {0:#x} is unavailable" +
                    "(possibly due to paging)".format(
                        task.Peb.ImageBaseAddress))
                return
            else:
                dump_file = os.path.join(
                    path, "PID_%x.executable.ex_" % (task.UniqueProcessId))
                of = open(dump_file, 'wb')
                pe_file = obj.Object("_IMAGE_DOS_HEADER",
                                     offset=task.Peb.ImageBaseAddress,
                                     vm=task_space)
                try:
                    for offset, code in pe_file.get_image(unsafe=True,
                                                          memory=False,
                                                          fix=True):
                        of.seek(offset)
                        of.write(code)
                except ValueError, ve:
                    pyrebox_print("Error: {0}".format(ve))
                    return
                except exceptions.SanityCheckException, ve:
                    pyrebox_print("Error: {0} Try -u/--unsafe".format(ve))
                    return
Пример #42
0
    def calculate(self):

        if not has_distorm:
            debug.error("You must install distorm3")

        addr_space = utils.load_as(self._config)

        all_mods = []
        if self._config.OFFSET != None:
            all_tasks = [
                taskmods.DllList.virtual_process_from_physical_offset(
                    addr_space, self._config.OFFSET)
            ]
        else:
            all_tasks = list(tasks.pslist(addr_space))
            all_mods = list(modules.lsmod(addr_space))

        # Operate in kernel mode if pid is not supplied
        if not self._config.PID and not self._config.OFFSET:
            if not self._config.BASE:
                debug.error("You must specify --BASE")

            base_address = self._config.BASE
            size_to_read = self._config.SIZE

            # Get the size from the module list if its not supplied
            if not size_to_read:
                for module in all_mods:
                    if module.DllBase == base_address:
                        size_to_read = module.SizeOfImage
                        break
                # Alternately, try the size from the PE header
                if not size_to_read:
                    pefile = obj.Object("_IMAGE_DOS_HEADER",
                                        offset=base_address,
                                        vm=addr_space)
                    try:
                        nt_header = pefile.get_nt_header()
                        size_to_read = nt_header.OptionalHeader.SizeOfImage
                    except ValueError:
                        pass

                    if not size_to_read:
                        debug.error("You must specify --SIZE")

            kernel_space = tasks.find_space(addr_space, all_tasks,
                                            base_address)

            if not kernel_space:
                debug.error("Cannot read supplied address")

            data = kernel_space.zread(base_address, size_to_read)
            apis = self.enum_apis(all_mods)
            addr_space = kernel_space

            is_wow64 = False

        else:
            # In process mode, we find the process by PID
            task = None

            for atask in all_tasks:
                if (self._config.OFFSET
                        or atask.UniqueProcessId == self._config.PID):
                    task = atask
                    break

            if not task:
                debug.error("You must supply an active PID")

            task_space = task.get_process_address_space()

            if not task_space:
                debug.error("Cannot acquire process AS")

            all_mods = list(task.get_load_modules())

            # PEB is paged or no DLLs loaded
            if not all_mods:
                debug.error("Cannot load DLLs in process AS")

            # If an address is supplied with a size, try to get
            # the size from the vad node. If neither are supplied,
            # assume we should carve the main process executable.
            if self._config.BASE:
                base_address = self._config.BASE
                size_to_read = self._config.SIZE

                if not size_to_read:
                    for vad in task.VadRoot.traverse():
                        if (base_address >= vad.Start
                                and base_address <= vad.End):
                            size_to_read = vad.Length
                    if not size_to_read:
                        debug.error("You must specify --SIZE")
            else:
                # Its OK to blindly take the 0th element because the
                # executable is always the first module to load.
                base_address = all_mods[0].DllBase
                size_to_read = all_mods[0].SizeOfImage

            is_wow64 = task.IsWow64

            data = task_space.zread(base_address, size_to_read)
            apis = self.enum_apis(all_mods)
            addr_space = task_space

        # This is a dictionary of confirmed API calls.
        calls_imported = dict((iat, call) for (
            _, iat,
            call) in self.call_scan(addr_space, base_address, data, is_wow64)
                              if call in apis)

        # Scan forward
        self._vicinity_scan(
            addr_space,
            calls_imported,
            apis,
            base_address,
            len(data),
            is_wow64,
            forward=True,
        )

        # Scan reverse
        self._vicinity_scan(
            addr_space,
            calls_imported,
            apis,
            base_address,
            len(data),
            is_wow64,
            forward=False,
        )

        for iat, call in sorted(calls_imported.items()):
            yield iat, call, apis[call][0], apis[call][1]
Пример #43
0
    def calculate(self):
        addr_space = malware.get_malware_space(self._config)
        addr_space.profile.add_types(zeus_types)

        RC4_KEYSIZE = 0x102

        # cycle the processes
        for p in self.filter_tasks(tasks.pslist(addr_space)):

            # get the process address space
            ps_ad = p.get_process_address_space()
            if ps_ad == None:
                continue

            rules = yara.compile(sources=zeus_key_sigs)

            # traverse the VAD
            for vad in p.VadRoot.traverse():

                if vad == None:
                    continue

                # find the start and end range

                ## for Volatility 2.0 use the following
                start = vad.StartingVpn << 12
                end = ((vad.EndingVpn + 1) << 12) - 1
                data = malware.get_vad_data(ps_ad, start, end)
                ## For Volatility >= 2.1 use the following
                #start = vad.get_start()
                #end   = vad.get_end()
                #data  = vad.get_data()

                # last check for PE headers at the base
                if data[0:2] != 'MZ':
                    continue

                # check for the signature with YARA, both hits must be present
                matches = rules.match(data=data)

                if len(matches) != 2:
                    continue

                # get the NT header
                dos_header = obj.Object("_IMAGE_DOS_HEADER", start, ps_ad)
                nt_header = dos_header.get_nt_header()

                # there must be more than 2 sections
                if nt_header.FileHeader.NumberOfSections < 2:
                    continue

                # get the last PE section's data
                sections = list(nt_header.get_sections(unsafe=False))

                last_sec = sections[-1]
                last_sec_data = ps_ad.read((last_sec.VirtualAddress + start),
                                           last_sec.Misc.VirtualSize)

                # contains C2 URL, RC4 key for decoding local.ds and the magic buffer
                decoded_config = ''
                # contains hw lock info, the user.ds RC4 key, and XOR key
                encoded_magic = ''

                for match in matches:
                    sigaddr = (match.strings[0][0] + start)
                    debug.debug('Found {0} at {1:#x}'.format(
                        match.rule, sigaddr))
                    if match.rule == 'z1':
                        encoded_config = ps_ad.read(
                            obj.Object('unsigned long',
                                       offset=sigaddr + 8,
                                       vm=ps_ad),
                            obj.Object('unsigned long',
                                       offset=sigaddr + 2,
                                       vm=ps_ad))
                        decoded_config = self.decode_config(
                            encoded_config, last_sec_data)
                    elif match.rule == 'z2':
                        config_ptr = obj.Object('unsigned long',
                                                offset=sigaddr + 26,
                                                vm=ps_ad)
                        config_ptr = obj.Object('unsigned long',
                                                offset=config_ptr,
                                                vm=ps_ad)
                        encoded_config = ps_ad.read(config_ptr, 0x3c8)
                        decoded_config = self.rc4(
                            self.rc4_init(encoded_config), last_sec_data[2:])
                    elif match.rule == 'z5':
                        encoded_config = ps_ad.read(
                            obj.Object('unsigned long',
                                       offset=sigaddr + 8,
                                       vm=ps_ad),
                            obj.Object('unsigned long',
                                       offset=sigaddr + 2,
                                       vm=ps_ad))
                        decoded_config = self.decode_config(
                            encoded_config, last_sec_data)
                    elif match.rule == 'z3':
                        encoded_magic = ps_ad.read(
                            obj.Object('unsigned long',
                                       offset=sigaddr + 30,
                                       vm=ps_ad),
                            addr_space.profile.get_obj_size('_ZEUS_MAGIC'))
                    elif match.rule == 'z4':
                        encoded_magic = ps_ad.read(
                            obj.Object('unsigned long',
                                       offset=sigaddr + 31,
                                       vm=ps_ad),
                            addr_space.profile.get_obj_size('_ZEUS_MAGIC'))

                if not decoded_config or not encoded_magic:
                    continue

                debug.debug("encoded_config:\n{0}\n".format(
                    self.get_hex(encoded_config)))
                debug.debug("decoded_config:\n{0}\n".format(
                    self.get_hex(decoded_config)))
                debug.debug("encoded_magic:\n{0}\n".format(
                    self.get_hex(encoded_magic)))

                offset = 0

                decoded_magic = ''
                config_key = ''

                found = False

                while offset < len(decoded_config) - RC4_KEYSIZE:

                    config_key = decoded_config[offset:offset + RC4_KEYSIZE]
                    decoded_magic = self.rc4(config_key, encoded_magic)

                    # when the first four bytes of the decoded magic buffer equal the size
                    # of the magic buffer, then we've found a winning RC4 key
                    (struct_size, ) = struct.unpack("=I", decoded_magic[0:4])

                    if struct_size == addr_space.profile.get_obj_size(
                            '_ZEUS_MAGIC'):
                        found = True
                        break

                    offset += 1

                if not found:
                    debug.debug('Error, cannot decode magic')
                    continue

                debug.debug("decoded_magic:\n{0}\n".format(
                    self.get_hex(decoded_magic)))
                debug.debug("config_key:\n{0}\n".format(
                    self.get_hex(config_key)))

                # grab the URL from the decoded buffer
                url = decoded_config[decoded_config.find("http"):]
                url = url[:url.find('\x00')]

                # report what we've found
                rc4_offset = addr_space.profile.get_obj_offset(
                    '_ZEUS_MAGIC', 'rc4key')
                creds_key = decoded_magic[rc4_offset:rc4_offset + RC4_KEYSIZE]
                yield p, start, url, config_key, creds_key, decoded_config, decoded_magic
Пример #44
0
def get_vads(pgd):
    '''
        Get list of VAD regions using volatility
    '''
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    import volatility.plugins.vadinfo as vadinfo
    from utils import get_addr_space

    # Get volatility address space using the function in utils
    addr_space = get_addr_space(pgd)

    # Get list of Task objects using volatility (EPROCESS executive objects)
    eprocs = [
        t for t in tasks.pslist(addr_space)
        if t.Pcb.DirectoryTableBase.v() == pgd
    ]

    # Traverse the list of selected EPROCESSes
    for task in eprocs:
        # Get heap base for every process HEAP
        heaps = task.Peb.ProcessHeaps.dereference()

        # Get base for every DLL
        modules = [mod.DllBase for mod in task.get_load_modules()]

        # Get Stack base for every THREAD
        stacks = []
        for thread in task.ThreadListHead.list_of_type("_ETHREAD",
                                                       "ThreadListEntry"):
            teb = obj.Object("_TEB",
                             offset=thread.Tcb.Teb,
                             vm=task.get_process_address_space())
            if teb:
                stacks.append(teb.NtTib.StackBase)

        # Traverse VAD tree
        for vad in task.VadRoot.traverse():
            if vad is not None:
                # Determine if the VAD is a HEAP, STACK, or MODULE
                vad_type = ""
                if vad.Start in heaps:
                    # Heaps
                    vad_type = "H"
                elif vad.Start in modules:
                    # Module
                    vad_type = "M"
                elif vad.Start in stacks:
                    # Stacks
                    vad_type = "S"
                else:
                    vad_type = "-"

                # Get protection flags
                try:
                    protection = vadinfo.PROTECT_FLAGS.get(
                        vad.VadFlags.Protection.v(), "")
                except Exception:
                    traceback.print_exc()

                # Get mapped file
                file_name = ""
                try:
                    control_area = vad.ControlArea
                    # even if the ControlArea is not NULL, it is only meaningful
                    # for shared (non private) memory sections.
                    if vad.VadFlags.PrivateMemory != 1 and control_area:
                        if control_area:
                            file_object = vad.FileObject
                            if file_object:
                                file_name = file_object.file_name_with_device()
                except AttributeError:
                    pass

                # Return VAD regions
                yield VADRegion(vad.Start, vad.End, file_name, str(vad.Tag),
                                vad_type, (vad.VadFlags.PrivateMemory == 1),
                                protection)
Пример #45
0
    def calculate(self):

        if not has_yara:
            debug.error("Please install Yara from code.google.com/p/yara-project")

        addr_space = utils.load_as(self._config)

        if self._config.YARA_RULES:
            s = self._config.YARA_RULES
            # Don't wrap hex or regex rules in quotes 
            if s[0] not in ("{", "/"): s = '"' + s + '"'
            # Scan for unicode strings 
            if self._config.WIDE: s += "wide"
            rules = yara.compile(sources = {
                        'n' : 'rule r1 {strings: $a = ' + s + ' condition: $a}'
                        })
        elif self._config.YARA_FILE:
            rules = yara.compile(self._config.YARA_FILE)
        else:
            debug.error("You must specify a string (-Y) or a rules file (-y)")

        if self._config.KERNEL:

            # Find KDBG so we know where kernel memory begins. Do not assume
            # the starting range is 0x80000000 because we may be dealing with
            # an image with the /3GB boot switch. 
            kdbg = tasks.get_kdbg(addr_space)

            # FIXME: Addresses should be truncated to 48 bits. Currently
            # we do that in Pointer.__eq__ but not in Pointer.v(). This prevents
            # module lookups in yarascan's --kernel mode on x64 from working
            # properly because win32.tasks.find_module cannot match the truncated
            # address with non-truncated mod.DllBase.v(). Changing Pointer.v()
            # could have wide spread effects, so this yarascan issue is fixed 
            # temporarily by giving YaraScan a private version of find_module
            # that performs the pointer truncation. After fixing this globally,
            # we can dereference MmSystemRangeStart as a Pointer instead of an 
            # address and then remove the manual bitmask below. 
            start = kdbg.MmSystemRangeStart.dereference_as("address")
            start = start & 0xffffffffffff

            # Modules so we can map addresses to owners
            mods = dict((mod.DllBase & 0xffffffffffff, mod)
                        for mod in modules.lsmod(addr_space))
            mod_addrs = sorted(mods.keys())

            # There are multiple views (GUI sessions) of kernel memory.
            # Since we're scanning virtual memory and not physical, 
            # all sessions must be scanned for full coverage. This 
            # really only has a positive effect if the data you're
            # searching for is in GUI memory. 
            sessions = []

            for proc in tasks.pslist(addr_space):
                sid = proc.SessionId
                # Skip sessions we've already seen 
                if sid == None or sid in sessions:
                    continue

                session_space = proc.get_process_address_space()
                if session_space == None:
                    continue

                sessions.append(sid)
                scanner = DiscontigYaraScanner(address_space = session_space,
                                               rules = rules)

                for hit, address in scanner.scan(start_offset = start):
                    module = self.find_module(mods, mod_addrs, address)
                    yield (module, address, hit, session_space.zread(address, 1024))

        else:
            for task in self.filter_tasks(tasks.pslist(addr_space)):
                scanner = VadYaraScanner(task = task, rules = rules)
                for hit, address in scanner.scan():
                    yield (task, address, hit, scanner.address_space.zread(address, 1024))
Пример #46
0
 def _scan_process_memory(self, addr_space, rules):
     for task in self.filter_tasks(tasks.pslist(addr_space)):
         scanner = VadYaraScanner(task = task, rules = rules)
         for hit, address in scanner.scan():
             yield (task, address, hit, scanner.address_space.zread(address - self._config.REVERSE, self._config.SIZE))
Пример #47
0
    def dll_dump(self, pids):
        """
        Generate dump files containing all modules loaded by a process

        @param pids: pid list to dump

        @returns a list of DLLObject sorted by (pid, mod.BaseAddress)
        """
        if self._config.MODULE_NAME:
            dlls_expression = '{0}$'.format(
                self._config.MODULE_NAME.replace(',', '$|'))

        else:
            dlls_expression = None

        re_case_type = 0
        if self._config.SEARCH_CASE:
            re_case_type = re.IGNORECASE

        if self._config.DERELOCATION or self._config.GUIDED_DERELOCATION:
            # acquiring all dlls and exes that were opened in system
            acquire_sys_file_handlers(self, conf)

        if self._config.LOG_MEMORY_PAGES:
            if not self._config.SECTION or self._config.SECTION == 'all' or 'PE' in self._config.SECTION:
                logfile = open(self._config.LOG_MEMORY_PAGES, "w")
            else:
                debug.warning('Warning: PE is not being dumped')

        for task in tasks.pslist(self.addr_space):
            if task.UniqueProcessId in pids:
                task_space = task.get_process_address_space()
                mods = dict(
                    (mod.DllBase.v(), mod) for mod in task.get_load_modules())
                for mod in mods.values():
                    mod_base = mod.DllBase.v()
                    mod_end = mod_base + mod.SizeOfImage
                    if task_space.is_valid_address(mod_base):
                        mod_name = mod.BaseDllName
                        if dlls_expression:

                            if not re.match(dlls_expression,
                                            str(mod_name),
                                            flags=re_case_type):
                                continue
                        valid_pages = [
                            task_space.vtop(mod.DllBase + i)
                            for i in range(0, mod.SizeOfImage, PAGE_SIZE)
                        ]
                        start = time.time()
                        pe = PeMemory(
                            task_space.zread(mod.DllBase, mod.SizeOfImage),
                            mod.DllBase, valid_pages)
                        end = time.time()

                        pe_memory_time = end - start

                        pe.__modul_name__ = mod_name
                        if self._config.LIST_SECTIONS:
                            yield PESection(mod_name, self.get_pe_sections(pe),
                                            task.UniqueProcessId, mod_base)
                        else:
                            reloc = None
                            pre_processing_time = None
                            if self._config.DERELOCATION or self._config.GUIDED_DERELOCATION:
                                # Retrieving reloc for module for text section
                                reloc = get_reloc_section(self, mod)
                                if reloc:
                                    start = time.time()
                                    guided_derelocation(pe, reloc)
                                    end = time.time()

                                    pre_processing_time = end - start
                                else:
                                    debug.warning(
                                        'Warning: {0}\'s reloc section cannot be found.'
                                        .format(mod_name))
                                    if self._config.GUIDED_DERELOCATION:
                                        continue

                            if (self._config.DERELOCATION and not reloc
                                ) or self._config.LINEAR_SWEEP_DERELOCATION:
                                start = time.time()
                                linear_sweep_derelocation(pe)
                                end = time.time()

                                pre_processing_time = end - start

                            # Generate one dump Object for every section/header specified

                            # Set the list of sections that match with -S expression
                            sections = self.process_section(
                                task, self._config.SECTION, pe)
                            for sec in sections:
                                for engine in self.hash_engines:
                                    vinfo = obj.Object(
                                        "_IMAGE_DOS_HEADER", mod.DllBase,
                                        task_space).get_version_info()
                                    create_time = str(
                                        task.CreateTime
                                    ) if self._config.HUMAN_READABLE else int(
                                        task.CreateTime)
                                    yield DLLObject(
                                        task,
                                        sec.data,
                                        engine,
                                        mod_base,
                                        mod_end,
                                        mod_name,
                                        sec.Name,
                                        create_time,
                                        vinfo.FileInfo.file_version()
                                        if vinfo else '',
                                        vinfo.FileInfo.product_version()
                                        if vinfo else '',
                                        mod.FullDllName,
                                        time=self._config.TIME
                                        and not (self._config.COMPARE_HASH
                                                 or self._config.COMPARE_FILE),
                                        offset=sec.VirtualAddress,
                                        size=sec.real_size,
                                        pe_memory_time='{0:.20f}'.format(
                                            pe_memory_time),
                                        pre_processing_time='{0:.20f}'.format(
                                            pre_processing_time)
                                        if pre_processing_time else None)

                                    dump_path = os.path.join(
                                        self._config.DUMP_DIR,
                                        '{0}-{1}-{2}-{3}-{4:x}.dmp'.format(
                                            self.get_exe_module(
                                                task).BaseDllName,
                                            task.UniqueProcessId, mod_name,
                                            re.sub(
                                                r'\x00', r'',
                                                re.sub(r'\/', r'.',
                                                       sec.Name)), mod_base))
                                    if self._config.DUMP_DIR:
                                        self.backup_file(dump_path, sec.data)
                                    if self._config.LOG_MEMORY_PAGES and sec.Name == 'PE':
                                        if not self._config.DUMP_DIR:
                                            debug.warning(
                                                'Warning: Modules are not being dumped to file'
                                            )
                                        logfile.write(
                                            '{},{},{},{},{}:{}\n'.format(
                                                self._config.optparse_opts.
                                                location[7:], dump_path,
                                                hashlib.md5(
                                                    pe.__data__[0:PAGE_SIZE]).
                                                hexdigest(),
                                                vinfo.FileInfo.file_version(),
                                                len(valid_pages), ', '.join([
                                                    str(i) for i in range(
                                                        0, len(valid_pages))
                                                    if valid_pages[i]
                                                ])))
        if 'logfile' in locals():
            logfile.close()
Пример #48
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        if not has_crypto:
            debug.error("pycrypto must be installed for this plugin")

        if not has_pbkdf2:
            debug.error("pbkdf2 must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=quasar_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                data = proc_addr_space.zread(vad_base_addr,
                                             end - vad_base_addr)

                config_data = []

                offset = 0
                for pattern in CONFIG_PATTERNS:
                    mc = re.search(pattern, data)
                    if mc:
                        offset = mc.end()

                        if ord(data[offset]) == 0x0:
                            offset += 1

                configs = []
                if offset > 0:
                    while 1:
                        strings = []
                        string_len = ord(data[offset])
                        if ord(data[offset]) == 0x80 or ord(
                                data[offset]) == 0x81:
                            string_len = ord(data[offset + 1]) + (
                                (ord(data[offset]) - 0x80) * 256)
                            offset += 1

                        offset += 1
                        for i in range(string_len):
                            if data[offset + i] != "\x00":
                                strings.append(data[offset + i])
                        configs.append("".join(strings))
                        offset = offset + string_len

                        if ord(data[offset]) < 0x20:
                            break

                    config_data.append(self.parse_config(configs))

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break
Пример #49
0
    def calculate(self):

        if not has_distorm:
            debug.error("You must install distorm3")

        addr_space = utils.load_as(self._config)

        all_tasks = list(tasks.pslist(addr_space))
        all_mods = list(modules.lsmod(addr_space))

        # Operate in kernel mode if pid is not supplied
        if not self._config.PID:
            if not self._config.BASE:
                debug.error("You must specify --BASE")

            base_address = self._config.BASE
            size_to_read = self._config.SIZE

            # Get the size from the module list if its not supplied
            if not size_to_read:
                for module in all_mods:
                    if module.DllBase == base_address:
                        size_to_read = module.SizeOfImage
                        break
                if not size_to_read:
                    debug.error("You must specify --SIZE")

            kernel_space = tasks.find_space(addr_space,
                                    all_tasks, base_address)

            if not kernel_space:
                debug.error("Cannot read supplied address")

            data = kernel_space.zread(base_address, size_to_read)
            apis = self.enum_apis(all_mods)
            addr_space = kernel_space
        else:
            # In process mode, we find the process by PID
            task = None

            for atask in all_tasks:
                if atask.UniqueProcessId == self._config.PID:
                    task = atask
                    break

            if not task:
                debug.error("You must supply an active PID")

            task_space = task.get_process_address_space()

            if not task_space:
                debug.error("Cannot acquire process AS")

            all_mods = list(task.get_load_modules())

            # PEB is paged or no DLLs loaded 
            if not all_mods:
                debug.error("Cannot load DLLs in process AS")

            # If an address is supplied with a size, try to get
            # the size from the vad node. If neither are supplied, 
            # assume we should carve the main process executable. 
            if self._config.BASE:
                base_address = self._config.BASE
                size_to_read = self._config.SIZE

                if not size_to_read:
                    for vad in task.VadRoot.traverse():
                        if base_address >= vad.Start and base_address <= vad.End:
                            size_to_read = vad.Length
                    if not size_to_read:
                        debug.error("You must specify --SIZE")
            else:
                # Its OK to blindly take the 0th element because the 
                # executable is always the first module to load. 
                base_address = all_mods[0].DllBase
                size_to_read = all_mods[0].SizeOfImage

            if not task_space.is_valid_address(base_address):
                debug.error("Address is not valid in process AS")

            data = task_space.zread(base_address, size_to_read)
            apis = self.enum_apis(all_mods)
            addr_space = task_space

        # This is a dictionary of confirmed API calls.
        calls_imported = dict(
                (iat, call)
                for (_, iat, call) in self.call_scan(addr_space, base_address, data)
                if call in apis
                )

        # Scan forward 
        self._vicinity_scan(addr_space,
                calls_imported, apis, base_address, len(data),
                forward = True)

        # Scan reverse 
        self._vicinity_scan(addr_space,
                calls_imported, apis, base_address, len(data),
                forward = False)

        for iat, call in sorted(calls_imported.items()):
            yield iat, call, apis[call][0], apis[call][1]
Пример #50
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=remcos_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                data = proc_addr_space.zread(vad_base_addr,
                                             end - vad_base_addr)

                config_data = []

                # resource PE search
                dll_index = data.rfind(MZ_HEADER)
                dll_data = data[dll_index:]

                try:
                    pe = pefile.PE(data=dll_data)
                except:
                    outfd.write("[!] Can't mapped PE.\n")
                    continue

                rc_data = ""
                for idx in pe.DIRECTORY_ENTRY_RESOURCE.entries:
                    for entry in idx.directory.entries:
                        if str(entry.name) in "SETTINGS":
                            try:
                                data_rva = entry.directory.entries[
                                    0].data.struct.OffsetToData
                                size = entry.directory.entries[
                                    0].data.struct.Size
                                rc_data = dll_data[data_rva:data_rva + size]
                                print("[*] Found SETTINGS resource.")
                            except:
                                debug.error("Faild to load SETTINGS resource.")

                if not len(rc_data):
                    for pattern in RESOURCE_PATTERNS:
                        mc = re.search(pattern, dll_data)
                        if mc:
                            try:
                                config_end = mc.end() + 1
                                while dll_data[config_end:config_end +
                                               2] != "\x00\x00":
                                    config_end += 1
                                rc_data = dll_data[mc.end():config_end - 1]
                            except:
                                debug.error("Remcos resource not found.")

                config_data.append(self.parse_config(rc_data))

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break
Пример #51
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=smokeloader_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                dll_data = proc_addr_space.zread(vad_base_addr,
                                                 end - vad_base_addr)

                config_data = []

                mz_magic = unpack_from("=2s", dll_data, 0x0)[0]
                nt_magic = unpack_from("<H", dll_data, 0x3c)[0]
                if mz_magic == "\x00\x00":
                    dll_data = "\x4d\x5a" + dll_data[2:]
                    dll_data = dll_data[:nt_magic] + "\x50\x45" + dll_data[
                        nt_magic + 2:]

                p_data = OrderedDict()
                url_base = []
                for pattern in CONFIG_PATTERNS:
                    mc = re.search(pattern, dll_data)
                    if mc:
                        offset = mc.end() + 1
                        while dll_data[offset] != "\x8B":
                            offset += 1

                        config_rva = unpack(
                            "=I",
                            dll_data[offset + 3:offset + 7])[0] - vad_base_addr

                        d = 0
                        while dll_data[config_rva + d:config_rva + d +
                                       4] != "\x00\x00\x00\x00":
                            url_base.append(
                                unpack(
                                    "=I", dll_data[config_rva + d:config_rva +
                                                   d + 4])[0])

                            d += 4

                        i = 1
                        for base in url_base:
                            base -= vad_base_addr
                            size = ord(dll_data[base])
                            key = unpack(
                                "=I",
                                dll_data[base + size + 1:base + size + 5])[0]
                            enc_data = dll_data[base + 1:base + size + 1]
                            url = self.decode(enc_data, key)
                            p_data["Static URL " + str(i)] = url
                            i += 1

                for pattern in STRINGS_PATTERNS:
                    mc = re.search(pattern, dll_data)
                    if mc:
                        offset = mc.start() + 2
                        config_rva = unpack(
                            "=I",
                            dll_data[offset:offset + 4])[0] - vad_base_addr
                        key = dll_data[config_rva - 4:config_rva]
                        enc = []
                        while dll_data[config_rva:config_rva +
                                       2] != "\x00\x00":
                            enc.append(dll_data[config_rva])
                            config_rva += 1
                        enc_strings = "".join(enc)
                        x = 0
                        i = 1
                        while x < len(enc_strings):
                            size = ord(enc_strings[x])
                            strings = self.rc4(enc_strings[x + 1:x + size + 1],
                                               key)
                            x = x + size + 1
                            p_data["Encoded string " + str(i)] = strings
                            i += 1

                config_data.append(p_data)

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break
Пример #52
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=redleaves_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                data = proc_addr_space.zread(vad_base_addr,
                                             end - vad_base_addr)

                config_data = []

                c_pt = CONF_PATTERNS[str(hit)]
                if re.search(c_pt, data):
                    m_conf = re.search(c_pt, data)
                else:
                    continue

                offset_conf = m_conf.start()

                if "RedLeaves" in str(hit):
                    config_size = 2100

                    offset_conf -= 1
                    while data[offset_conf] != "\xC7" and data[
                            offset_conf] != "\xBE" and data[
                                offset_conf] != "\xBF":
                        offset_conf -= 1

                    if data[offset_conf] != "\xC7" and data[
                            offset_conf] != "\xBE" and data[
                                offset_conf] != "\xBF":
                        continue
                    if data[offset_conf] == "\xC7" and data[
                            offset_conf + 1] != "\x85" and data[offset_conf +
                                                                1] != "\x45":
                        offset_conf -= 6

                    # get address
                    if data[offset_conf] == "\xC7" and data[offset_conf +
                                                            1] != "\x85":
                        (config_addr, ) = unpack(
                            "=I", data[offset_conf + 3:offset_conf + 7])
                    elif data[offset_conf] == "\xC7" and data[offset_conf +
                                                              1] == "\x85":
                        (config_addr, ) = unpack(
                            "=I", data[offset_conf + 6:offset_conf + 10])
                    else:
                        (config_addr, ) = unpack(
                            "=I", data[offset_conf + 1:offset_conf + 5])

                    if config_addr < vad_base_addr:
                        continue
                    config_addr -= vad_base_addr
                    config = data[config_addr:config_addr + config_size]
                    if len(config) > 0:
                        config_data.append(
                            self.parse_config(config, config_size,
                                              config_addr))

                if str(hit) in [
                        "Himawari", "Lavender", "Armadill", "zark20rk"
                ]:
                    offset_conf += 6
                    if str(hit) in ["zark20rk"]:
                        offset_conf += 6
                    config_size = 880

                    # get address
                    (config_addr, ) = unpack("=I",
                                             data[offset_conf:offset_conf + 4])

                    if config_addr < vad_base_addr:
                        continue

                    config_addr -= vad_base_addr
                    config = data[config_addr:config_addr + config_size]
                    if len(config) > 0:
                        config_data.append(
                            self.parse_config_himawari(config, config_size,
                                                       config_addr))

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break
Пример #53
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=formbook_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr)

                config_data = []
                try:
                    pe = pefile.PE(data=data)
                except:
                    continue

                for pattern in CONFIG_PATTERNS:
                    offset = re.search(pattern, data).start()

                offset += 6
                key1_offset = unpack("=I", data[offset:offset + 4])[0] + offset + 11
                key1 = data[key1_offset:key1_offset + (0x14 * 2)]
                offset += 23
                key2_offset = unpack("=I", data[offset:offset + 4])[0] + offset + 11
                key2 = data[key2_offset:key2_offset + (0x14 * 2)]
                offset += 21
                config_size = unpack("=I", data[offset:offset + 4])[0]
                offset += 5
                config_offset = unpack("=I", data[offset:offset + 4])[0] + offset + 11
                config = data[config_offset:config_offset + (config_size * 2)]
                offset += 33
                url_size = unpack("b", data[offset])[0]

                for pattern in STRINGS_PATTERNS:
                    offset = re.search(pattern, data).start()

                offset += 19
                strings_size = unpack("=I", data[offset:offset + 4])[0]
                offset += 5
                strings_offset = unpack("=I", data[offset:offset + 4])[0] + offset + 11
                strings_data = data[strings_offset:strings_offset + (strings_size * 2)]

                for pattern in HASHS_PATTERNS:
                    offset = re.search(pattern, data).start()

                offset += 1
                hashs_size = unpack("=I", data[offset:offset + 4])[0]
                offset += 11
                hashs_offset = unpack("=I", data[offset:offset + 4])[0] + offset + 11
                hashs_data = data[hashs_offset:hashs_offset + (hashs_size * 2)]

                config_data.append(self.formbook_decrypt(key1, key2, config, config_size, strings_data,
                                                         strings_size, url_size, hashs_data, hashs_size))

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break
Пример #54
0
def windows_read_memory_mapped(pgd, addr, size, pte, is_pae, bitness):
    # Step 1: Traverse the VAD tree for the process with PGD,
    #         and get the VAD that overlaps addr (if any)
    # Step 2: Check if the VAD has a ControlArea and a FilePointer,
    #         and get the file path.
    # Step 3: Get Segment (pointed to by ControlArea), and get the pointer
    #         to the first PrototypePTE.
    # Step 4: Compute offset of address with respect to the beginning
    #         of the VAD, and compute which PrototypePTE corresponds to the address
    #         No need to consider if the PTE points to the Prototype PTE here.
    # Step 6: Compute the offset in file for such PrototypePTE by looking at the
    #         subsections pointed by the ControlArea.
    # Step 7: Finally, open the file, read the contents, and return them.
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    import volatility.plugins.vadinfo as vadinfo
    from utils import get_addr_space

    addr_space = get_addr_space(pgd)

    eprocs = [
        t for t in tasks.pslist(addr_space)
        if t.Pcb.DirectoryTableBase.v() == pgd
    ]

    if len(eprocs) != 1:
        return None

    task = eprocs[0]
    vad = None
    # File name and offset
    for vad in task.VadRoot.traverse():
        if addr >= vad.Start and addr < vad.End:
            break
    if vad is None:
        return None

    filename = None
    if vad.ControlArea is not None and vad.FileObject is not None:
        filename = str(vad.ControlArea.FileObject.FileName)

    if vad.ControlArea.Segment is None:
        return None

    # Compute page offset with respect to Start of the VAD,
    # and the corresponding prototype Page Table Entry pointed
    # by the Segment
    offset_on_vad = addr - vad.Start
    page_offset_on_vad = (offset_on_vad - (offset_on_vad & 0xFFF))
    # Consider 4 KiB pages
    ppte_index = page_offset_on_vad / 0x1000

    if ppte_index >= vad.ControlArea.Segment.TotalNumberOfPtes.v():
        return None

    if bitness == 32 and is_pae:
        ppte_addr = vad.ControlArea.Segment.PrototypePte.v() + (ppte_index * 8)
    else:
        ppte_addr = vad.ControlArea.Segment.PrototypePte.v() + (
            ppte_index * addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][0])

    # Read Subsections pointed by ControlArea
    visited_subsections = {}
    if "Subsection" in vad.members:
        subsect = vad.Subsection
    # There is no Subsection pointer in VAD
    # structure, so we just read after the ControlArea
    else:
        subsect = obj.Object(
            "_SUBSECTION",
            offset=(vad.ControlArea.v() +
                    addr_space.profile.vtypes["_CONTROL_AREA"][0]),
            vm=addr_space)

    file_offset_to_read = None
    while file_offset_to_read is None and subsect is not None or subsect.v(
    ) != 0 and subsect.v() not in visited_subsections:
        visited_subsections.append(subsect.v())
        # Get the PPTE address where the Subsection starts,
        # and compute the virtual address that it corresponds
        # to.
        ppte_addr = subsect.SubsectionBase.v()
        if bitness == 32 and is_pae:
            ppte_index = (subsect.SubsectionBase.v() -
                          vad.ControlArea.Segment.PrototypePte.v()) / 8
        else:
            ppte_index = (subsect.SubsectionBase.v() -
                          vad.ControlArea.Segment.PrototypePte.v()
                          ) / addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][0]

        subsection_base = vad.Start + (ppte_index * 0x1000)
        subsection_size = subsect.PtesInSubsection.v() * 0x1000
        subsection_file_offset = subsect.StartingSector.v() * 512
        subsection_file_size = vad.Subsection.NumberOfFullSectors.v() * 512

        visited_subsections[subsect.v()] = (subsection_base, subsection_size,
                                            subsection_file_offset,
                                            subsection_file_size)

        if (addr >= subsection_base) and (addr <
                                          (subsection_base + subsection_size)):
            file_offset_to_read = (addr -
                                   subsection_base) + subsection_file_offset

        subsect = subsect.NextSubsection

    f = None
    for fs in api.get_filesystems():
        try:
            f = api.open_guest_path(fs["index"], filename)
            break
        except:
            # The file cannot be open on such filesystem
            pass
    if not f:
        raise RuntimeError(
            "Could not read memory from pagefile: file not found")

    print("Reading file %s at offset %x - Size: %x" %
          (filename, file_offset_to_read, size))
    f.seek(file_offset_to_read)
    data = f.read(size=size)
    f.close()
Пример #55
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=wellmess_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr)

                pe = pefile.PE(data=data)

                config_data = []
                configs = []
                for pattern in CONFIG_PATTERNS:
                    mc = list(re.finditer(pattern, data))
                    if mc:
                        for m in mc:
                            hit_adderss = m.span()
                            config_rva = unpack("=I", m.groups()[1])[0]

                            if pe.FILE_HEADER.Machine == 0x14C: # for 32bit
                                config_offset = config_rva - pe.NT_HEADERS.OPTIONAL_HEADER.ImageBase
                                #config_offset = pe.get_physical_by_rva(config_rva - pe.NT_HEADERS.OPTIONAL_HEADER.ImageBase) + 0x1000
                            else: # for 64bit
                                config_offset = config_rva + hit_adderss[0] + 26
                                
                            configs.append(data[config_offset:config_offset + ord(m.groups()[0])])

                for pattern in CONFIG_PATTERNS_DOTNET:
                    mc = re.search(pattern, data)
                    if mc:
                        offset = mc.end()
                        for i in range(6):
                            strings = []
                            string_len = ord(data[offset])

                            if ord(data[offset]) == 0x80 or ord(data[offset]) == 0x83:
                                string_len = ord(data[offset + 1]) + ((ord(data[offset]) - 0x80) * 256)
                                offset += 1

                            offset += 1
                            for i in range(string_len):
                                if data[offset + i] != "\x00":
                                    strings.append(data[offset + i])
                            if string_len != 1:
                                configs.append("".join(strings))
                            offset = offset + string_len

                config_data.append(self.parse_config(configs))

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break
Пример #56
0
    def calculate(self):

        addr_space = utils.load_as(self._config)

        if not has_distorm3:
            debug.error("Install distorm3 code.google.com/p/distorm/")

        if not self._config.SKIP_PROCESS:
            for proc in self.filter_tasks(tasks.pslist(addr_space)):
                process_name = str(proc.ImageFileName).lower()

                if (self._config.QUICK and
                        process_name not in self.critical_process):
                    #debug.debug("Skipping non-critical process {0} ({1})".format(
                    #    process_name, proc.UniqueProcessId))
                    continue

                process_space = proc.get_process_address_space()
                if not process_space:
                    #debug.debug("Cannot acquire process AS for {0} ({1})".format(
                    #    process_name, proc.UniqueProcessId))
                    continue

                module_group = ModuleGroup(proc.get_load_modules())

                for dll in module_group.mods:

                    if not process_space.is_valid_address(dll.DllBase):
                        continue

                    dll_name = str(dll.BaseDllName or '').lower()

                    if (self._config.QUICK and
                            dll_name not in self.critical_dlls and
                            dll.DllBase != proc.Peb.ImageBaseAddress):
                        #debug.debug("Skipping non-critical dll {0} at {1:#x}".format(
                        #    dll_name, dll.DllBase))
                        continue

                    #debug.debug("Analyzing {0}!{1}".format(process_name, dll_name))

                    for hook in self.get_hooks(HOOK_MODE_USER, process_space, dll, module_group):
                        if not self._config.NO_WHITELIST:
                            if self.whitelist(hook.hook_mode | hook.hook_type, str(proc.ImageFileName), hook.VictimModule, hook.HookModule, hook.Function):
                                continue
                        yield proc, dll, hook

        if not self._config.SKIP_KERNEL:
            process_list = list(tasks.pslist(addr_space))
            module_group = ModuleGroup(modules.lsmod(addr_space))

            for mod in module_group.mods:

                #module_name = str(mod.BaseDllName or '')
                #debug.debug("Analyzing {0}".format(module_name))

                kernel_space = tasks.find_space(addr_space,
                    process_list, mod.DllBase)

                if not kernel_space:
                    #debug.debug("No kernel AS for {0} at {1:#x}".format(
                    #    module_name, mod.DllBase))
                    continue

                for hook in self.get_hooks(HOOK_MODE_KERNEL, kernel_space, mod, module_group):
                    if not self._config.NO_WHITELIST:
                        if self.whitelist(hook.hook_mode | hook.hook_type, "", hook.VictimModule, hook.HookModule, hook.Function):
                            continue
                    yield None, mod, hook
Пример #57
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        if not has_aplib:
            debug.error("Aplib must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=ursnif_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                data = proc_addr_space.zread(vad_base_addr, end - vad_base_addr)

                config_data = []

                # Parse standard Ursnif
                config_data = self.parse_joinned_data(data)

                # Parse static configuration type Ursnif
                if not config_data:
                    p_data = OrderedDict()
                    data = self.pe_magic_check(data)
                    try:
                        pe = pefile.PE(data=data)
                    except:
                        continue
                    imagebase = pe.NT_HEADERS.OPTIONAL_HEADER.ImageBase
                    for pattern in CONFIG_PATTERNS:
                        m = re.search(pattern, data)
                        if m:
                            if pe.FILE_HEADER.Machine in (pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_IA64'], pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']):
                                c2_num = unpack("b", data[m.start(7) + 19])[0]
                            else:
                                c2_num = unpack("b", data[m.start(6)])[0]
                            if c2_num >= 16:
                                c2_num = 1
                            for i in range(c2_num):
                                if pe.FILE_HEADER.Machine in (pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_IA64'], pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']):
                                    c2_addr = m.start(4) + unpack("=I", data[m.start(3):m.start(3) + 4])[0]
                                    c2_table_offset = unpack("=Q", data[c2_addr + (8 * i):c2_addr + 8 + (8 * i)])[0] - imagebase
                                else:
                                    c2_addr = unpack("=I", data[m.start(4):m.start(4) + 4])[0] - imagebase
                                    c2_table_offset = unpack("=I", data[c2_addr + (4 * i):c2_addr + 4 + (4 * i)])[0] - imagebase

                                try:
                                    c2 = self.decode_data(data, pe, c2_table_offset)
                                except:
                                    c2 = "Decode fail"

                                p_data["Server " + str(i)] = c2

                            if pe.FILE_HEADER.Machine in (pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_IA64'], pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']):
                                serpent_key_offset = m.start(8) + unpack("=I", data[m.start(7):m.start(7) + 4])[0]
                            else:
                                serpent_key_offset = unpack("=I", data[m.start(8):m.start(8) + 4])[0] - imagebase
                            try:
                                serpent_key = self.decode_data(data, pe, serpent_key_offset)
                            except:
                                serpent_key = "Decode fail"
                            p_data["Serpent key"] = serpent_key

                    for pattern in RSA_PATTERNS:
                        m = re.search(pattern, data)
                        if m:
                            if pe.FILE_HEADER.Machine in (pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_IA64'], pefile.MACHINE_TYPE['IMAGE_FILE_MACHINE_AMD64']):
                                rsa_key_offset = m.start(2) + unpack("=I", data[m.start(1):m.start(1) + 4])[0]
                                rsa_key = data[rsa_key_offset + 4:rsa_key_offset + 0x44]

                                rsa_mod = data[rsa_key_offset + 0x44:rsa_key_offset + 0x84]
                            else:
                                rsa_key_offset = unpack("=I", data[m.start(1):m.start(1) + 4])[0] - imagebase
                                rsa_key = data[rsa_key_offset:rsa_key_offset + 0x40]

                                mod_offset = unpack("=I", data[m.start(4):m.start(4) + 4])[0] - imagebase
                                rsa_mod = data[mod_offset:mod_offset + 0x40]
                            p_data["RSA key"] = rsa_key.encode("hex")
                            p_data["RSA modulus"] = rsa_mod.encode("hex")

                    config_data.append(p_data)

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break
Пример #58
0
    def calculate(self):
        """Search memory for credentials"""

        kernel_memory = utils.load_as(self._config)

        # Find all OpenVPN processes
        processes = tasks.pslist(kernel_memory)
        processes = filter(
            lambda p: str(p.ImageFileName).lower() == "openvpn.exe", processes)

        # Search for credentials in each process
        for process in processes:
            process_memory = process.get_process_address_space()

            # Get some basic process information
            pid = int(process.UniqueProcessId)
            image_base = process.Peb.ImageBaseAddress
            dos_header = obj.Object("_IMAGE_DOS_HEADER",
                                    offset=image_base,
                                    vm=process_memory)
            nt_header = dos_header.get_nt_header()

            # Find the .data section
            sections = nt_header.get_sections(True)
            sections = filter(lambda s: str(s.Name) == ".data", sections)
            if len(sections) != 1:
                # Section may be unavailable
                continue

            # Determine dimensions of section
            data_section = sections[0]
            data_start = data_section.VirtualAddress + image_base
            data_end = data_start + data_section.Misc.VirtualSize

            # Search static user_pass struct
            # Assumptions:
            #  - Struct is aligned on 16-byte boundary
            #  - Bool fields are 4 bytes long
            #  - Username and password buffers are 4096 bytes long
            for creds_start in xrange(data_start, data_end, 16):
                creds = process_memory.read(creds_start, 9)
                if not creds:
                    continue

                # Try to unpack and verify the beginning of the struct
                defined, nocache, username = struct.unpack("IIc", creds)
                if defined > 1 or nocache > 1 or username == "\0":
                    continue

                # Completely unpack the struct
                creds = process_memory.zread(creds_start, 4 + 4 + 4096 + 4096)
                defined, nocache, username, password = \
                    struct.unpack("II4096s4096s", creds)

                # Truncate string padding
                username, _, _ = username.partition("\0")
                password = password.rstrip("\0")

                # CENSOR PASSWORD
                #password = "******" * len(password)

                yield (pid, username, password)

                # Stop searching in current process
                break
Пример #59
0
    def calculate(self):

        if not has_yara:
            debug.error("Yara must be installed for this plugin")

        if not has_yara:
            debug.error("Aplib must be installed for this plugin")

        addr_space = utils.load_as(self._config)

        os, memory_model = self.is_valid_profile(addr_space.profile)
        if not os:
            debug.error("This command does not support the selected profile.")

        rules = yara.compile(sources=ursnif_sig)

        for task in self.filter_tasks(tasks.pslist(addr_space)):
            scanner = malfind.VadYaraScanner(task=task, rules=rules)

            for hit, address in scanner.scan():

                vad_base_addr, end = self.get_vad_base(task, address)
                proc_addr_space = task.get_process_address_space()
                data = proc_addr_space.zread(vad_base_addr,
                                             end - vad_base_addr)

                config_data = []

                mz_magic = unpack_from("=2s", data, 0x0)[0]
                nt_magic = unpack_from("<H", data, 0x3c)[0]

                if mz_magic == "\x00\x00":
                    data = "\x4d\x5a" + data[2:]
                    data = data[:nt_magic] + "\x50\x45" + data[nt_magic + 2:]
                fnames = []
                for m in re.finditer(magic + "\x00.", data):
                    xor_dword = 0
                    magic_dword = data[m.start():m.start() + 4]
                    if (magic_dword[0:1] == "J1" or magic_dword[3] == "\0"):
                        (flags, crc32_name, addr,
                         size) = unpack_from("<LLLL", data,
                                             m.start() + 4)
                        print(
                            "[+] magic: {0} flags: 0x{1:X} crc32_name: 0x{2:X} addr: 0x{3:X} size: 0x{4:X}\n"
                            .format(repr(magic_dword), flags, crc32_name, addr,
                                    size))
                    elif (magic_dword[0:1] == "JJ"
                          or (ord(magic_dword[3]) & 1) == 1):
                        (xor_dword, crc32_name, addr,
                         size) = unpack_from("<LLLL", data,
                                             m.start() + 4)
                        print(
                            "[+] magic: {0} xor: 0x{1:X} crc32_name: 0x{2:X} addr: 0x{3:X} size: 0x{4:X}\n"
                            .format(repr(magic_dword), xor_dword, crc32_name,
                                    addr, size))
                    else:
                        raise ValueError("Unknown joiner header")

                    if size > 0x80000:
                        print("[!] size is too large, skipped this entry\n")
                        continue

                    try:
                        offset = addr
                    except:
                        print("[!] This PE is old Ursnif (not DreamBot)\n")
                        (addr, size, crc32_name,
                         flags) = unpack_from("<LLLL", data,
                                              m.start() + 4)
                        print(
                            "[+] magic: {0} addr: 0x{1:X} size: 0x{2:X} crc32_name: 0x{3:X} flags: 0x{4:X}\n"
                            .format(repr(magic_dword), addr, size, crc32_name,
                                    flags))
                        offset = addr
                    joined_res = data[offset:offset + size]
                    try:
                        dec_data = aplib.decompress(joined_res).do()[0]
                    except:
                        print("[!] Cann't decode data.\n")
                        continue

                    if (xor_dword != 0):
                        mod_data = ""
                        for i in range(min(4, size + 1)):
                            mod_data += chr(
                                ord(dec_data[i])
                                ^ ((xor_dword >> 8 * i) & 0xff))
                        if (size >= 4):
                            mod_data += dec_data[4:]
                        dec_data = mod_data

                    if crc32_name in (0x4f75cea7, 0x9e154a0c):
                        fname = "ursnif_client32.bin"
                        open(fname, "wb").write(dec_data)
                        print("[+] dumped 32 bit client dll: {0}\n".format(
                            fname))
                        fnames.append(fname)
                    elif crc32_name in (0x90f8aab4, 0x41982e1f):
                        fname = "ursnif_client64.bin"
                        open(fname, "wb").write(dec_data)
                        print("[+] dumped 64 bit client dll: {0}\n".format(
                            fname))
                        # fnames.append(fname)

                    elif crc32_name in (0xe1285e64, ):
                        fname = "ursnif_public_key.bin"
                        open(fname, "wb").write(dec_data)
                        print("[+] dumped public key: {0}\n".format(fname))
                    elif crc32_name in (0xd722afcb, 0x8365b957, 0x8fb1dde1):
                        fname = "ursnif_st_config.bin"
                        open(fname, "wb").write(dec_data)
                        print("[+] dumped static config: {0}\n".format(fname))
                        config_data.append(self.parse_config(dec_data))
                    else:
                        fname = "ursnif_" + hex(addr) + "_ap32_dec.bin"
                        open(fname, "wb").write(dec_data)
                        print("[+] dumped: {0}".format(fname))
                for fname in fnames:
                    parse_joinned_data(fname, magic)

                yield task, vad_base_addr, end, hit, memory_model, config_data
                break