Beispiel #1
0
    def wait_for_completion(self, machine, storage, machinery):
        """Wait for analysis completion.
        @return: operation status.
        """
        log.debug("%s: waiting for completion", self.id)

        # Same procedure as in self.wait(). Just look at the comments there.
        abort = Event()
        abort.clear()

        def die():
            abort.set()

        # CHANGED: Added time-based dumps here.
        resumableTimer = ResumableTimer(self.timeout, die)
        resumableTimer.start()
        sec_counter = 0
        mem_analysis_conf = Config(os.path.join(CUCKOO_ROOT, "conf", "memoryanalysis.conf"))
        time_to_sleep = int(mem_analysis_conf.time_based.time_to_sleep_before_dump_in_seconds)
        number_of_dumps = int(mem_analysis_conf.basic.max_number_of_dumps)
        memory_results_dir = os.path.join(storage, "memory")
        dumps_dir = os.path.join(memory_results_dir, "dumps")
        create_dir_safe(memory_results_dir)
        create_dir_safe(dumps_dir)
        while True:
            if abort.is_set():
                info_dict = {"trigger": {"name": "End", "args": {}}, "time": str(sec_counter)}
                log.info("Taking dump before termination...")
                self.take_mem_dump(dumps_dir, machine, machinery, info_dict)
                raise CuckooGuestError("The analysis hit the critical timeout, terminating")
            while Event(STOP_EVENT).is_set():
                time.sleep(0.005)
            time.sleep(1)
            sec_counter += 1
            if mem_analysis_conf.basic.time_based and sec_counter % time_to_sleep == 0:
                resumableTimer.stop()
                info_dict = {"trigger": {"name": "Time", "args": {"interval": time_to_sleep}}}
                self.take_mem_dump(dumps_dir, machine, machinery, info_dict)
                resumableTimer.resume()
            try:
                status = self.server.get_status()
            except Exception as e:
                log.debug("%s: error retrieving status: %s", self.id, e)
                continue

            # React according to the returned status.
            if status == CUCKOO_GUEST_COMPLETED:
                log.info("%s: analysis completed successfully", self.id)
                break
            elif status == CUCKOO_GUEST_FAILED:
                error = self.server.get_error()
                if not error:
                    error = "unknown error"
                info_dict = {"trigger": {"name": "End", "args": {}}}
                log.info("Taking dump before termination...")
                self.take_mem_dump(dumps_dir, machine, machinery, info_dict)
                raise CuckooGuestError("Analysis failed: {0}".format(error))
            # TODO: suspend machine and take dump
            else:
                log.debug("%s: analysis not completed yet (status=%s)", self.id, status)
        self.server._set_timeout(None)
        log.info("Taking dump before termination...")
        info_dict = {"trigger": {"name": "End", "args": {}}}
        self.take_mem_dump(dumps_dir, machine, machinery, info_dict)
    def wait_for_completion(self, machine, storage, machinery):
        """Wait for analysis completion.
        @return: operation status.
        """
        log.debug("%s: waiting for completion", self.id)

        # Same procedure as in self.wait(). Just look at the comments there.
        abort = Event()
        abort.clear()

        def die():
            abort.set()

# CHANGED: Added time-based dumps here.

        resumableTimer = ResumableTimer(self.timeout, die)
        resumableTimer.start()
        sec_counter = 0
        mem_analysis_conf = Config(
            os.path.join(CUCKOO_ROOT, "conf", "memoryanalysis.conf"))
        time_to_sleep = int(
            mem_analysis_conf.time_based.time_to_sleep_before_dump_in_seconds)
        number_of_dumps = int(mem_analysis_conf.basic.max_number_of_dumps)
        memory_results_dir = os.path.join(storage, "memory")
        dumps_dir = os.path.join(memory_results_dir, "dumps")
        create_dir_safe(memory_results_dir)
        create_dir_safe(dumps_dir)
        while True:
            if abort.is_set():
                info_dict = {
                    "trigger": {
                        "name": "End",
                        "args": {}
                    },
                    "time": str(sec_counter)
                }
                log.info("Taking dump before termination...")
                self.take_mem_dump(dumps_dir, machine, machinery, info_dict)
                raise CuckooGuestError(
                    "The analysis hit the critical timeout, terminating")
            while Event(STOP_EVENT).is_set():
                time.sleep(0.005)
            time.sleep(1)
            sec_counter += 1
            if mem_analysis_conf.basic.time_based and sec_counter % time_to_sleep == 0:
                resumableTimer.stop()
                info_dict = {
                    "trigger": {
                        "name": "Time",
                        "args": {
                            "interval": time_to_sleep
                        }
                    }
                }
                self.take_mem_dump(dumps_dir, machine, machinery, info_dict)
                resumableTimer.resume()
            try:
                status = self.server.get_status()
            except Exception as e:
                log.debug("%s: error retrieving status: %s", self.id, e)
                continue

        # React according to the returned status.
            if status == CUCKOO_GUEST_COMPLETED:
                log.info("%s: analysis completed successfully", self.id)
                break
            elif status == CUCKOO_GUEST_FAILED:
                error = self.server.get_error()
                if not error:
                    error = "unknown error"
                info_dict = {"trigger": {"name": "End", "args": {}}}
                log.info("Taking dump before termination...")
                self.take_mem_dump(dumps_dir, machine, machinery, info_dict)
                raise CuckooGuestError("Analysis failed: {0}".format(error))
# TODO: suspend machine and take dump
            else:
                log.debug("%s: analysis not completed yet (status=%s)",
                          self.id, status)
        self.server._set_timeout(None)
        log.info("Taking dump before termination...")
        info_dict = {"trigger": {"name": "End", "args": {}}}
        self.take_mem_dump(dumps_dir, machine, machinery, info_dict)
	def run_memory_analysis(self):		
		"""
		The main engine function for memory analysis
		"""
		# We copy the results because we add results that the user did not choose to run,
		# but will run as a dependency.
		log.info("Running memory analysis for dump: %s" % self.memfile)
		new_results = copy.deepcopy(self.results)
		mem_analysis = {}
		mem_analysis["diffs"] = {}
		dlls_dir = os.path.join(os.path.dirname(self.memfile), DLLS_DIR)
                drivers_dir = os.path.join(os.path.dirname(self.memfile), DRIVERS_DIR)
                malfinds_dir = os.path.join(os.path.dirname(self.memfile), MALFINDS_DIR)

		if not self.is_clean:
                        utils.create_dir_safe(dlls_dir)
			utils.create_dir_safe(drivers_dir)
			utils.create_dir_safe(malfinds_dir)
		for mem_analysis_name, dependencies in MEMORY_ANALYSIS_DEPENDENCIES.iteritems():
			attrs = getattr(self.voptions, mem_analysis_name)
			if attrs.enabled:
				attrs.pop("enabled")
				if attrs.has_key("filter"):
					attrs.pop("filter")
				if self.is_clean:
                                	self.results = self.run_dependencies(self.results, dependencies, **attrs)
                        	else:
                                	new_results = self.run_dependencies(new_results, dependencies, **attrs)
					if mem_analysis_name == "static_analyze_new_exe":
						mem_analysis[mem_analysis_name] = self.static_analyze_new_exe(self.clean_data, new_results, dependencies, **attrs)
					elif mem_analysis_name == "diff_heap_entropy":
						mem_analysis["diffs"]["diff_heap_entropy"] = {"desc" : "Calculates entropy of malware heap process", "new" : [], "deleted" : [], "star": "no"}
						proc = self.get_malware_proc(self.clean_data,new_results,dependencies)
                				if proc is not None:
                        				pid = proc["process_id"]
							try:
                        					mem_analysis["diffs"]["diff_heap_entropy"]["value"] = self.vol.heapentropy(pid=str(pid))["data"][0]["entropy"]
							except:
								pass
					else:
						self.run_memory_plugin(mem_analysis, mem_analysis_name, self.clean_data, new_results, **attrs)
		if not self.is_clean:
			trigger = self.info["trigger"]["name"]
			args = self.info["trigger"]["args"]
			smart_analysis, plugins_to_run = self.parse_trigger_plugins(trigger)
			for plugin in plugins_to_run:
				if not mem_analysis["diffs"].has_key(plugin):
                                	self.run_memory_plugin(mem_analysis, plugin, self.clean_data, new_results)
			if smart_analysis:
			    if TRIGGER_PLUGINS.has_key(trigger):
				for plugin in TRIGGER_PLUGINS[trigger]:
					if not mem_analysis["diffs"].has_key(plugin):
						self.run_memory_plugin(mem_analysis, plugin, self.clean_data, new_results)			
					mem_analysis["diffs"][plugin]["star"] = "yes"
		    	    if trigger == "ZwLoadDriver":
				patcher_res = self.vol.patcher(os.path.join(CUCKOO_ROOT, "data", "patchers", "patchpe.xml"))
				# Dump the new driver
				for p in patcher_res["patches"]:
					log.info("Dumping drive in offset: %d" % p)
					base = int(p) + 0x7fe00000
					res = self.vol.moddump(dump_dir=drivers_dir, base=base)
					name = res["data"][0]["module_name"]
					mem_analysis["diffs"]["diff_moddump"]["new"].append({"module_name" : name,"module_base" : base})
			    elif trigger == "SetWindowsHookExA" or trigger == "SetWindowsHookExW":
			    	for mh in mem_analysis["diffs"]["diff_messagehooks"]["new"]:
						pid_pat = "\(.*?(\d+)\)"
						
						pids = re.findall(pid_pat, mh["thread"])
						if len(pids) > 0:
							pid = pids[0]
							mod_name = mh["module"].split("\\")[-1]
							dlldump = self.vol.dlldump(dump_dir=dlls_dir, pid=pid, regex=mod_name)
							mem_analysis["diffs"]["injected_dll"] = {
                        									"new"           : [],
                        									"deleted"       : [],
                        									"star"          : "yes",
                        									"desc"          : "Shows the injected DLL",
                        									}
							if dlldump["data"] != []:
								mem_analysis["diffs"]["injected_dll"]["new"].append(dlldump["data"][0])	
			    elif trigger == "VirtualProtectEx":
				verbal_protect = PAGE_PROTECTIONS[int(args["Protection"],16)]
				protect_vad_val = [key for key,val in vadinfo.PROTECT_FLAGS.iteritems() if val == verbal_protect][0]
        			if "EXECUTE" in verbal_protect:
					key = "new"
				else:
					key = "deleted"
				mem_analysis["diffs"]["diff_malfind"][key].append( \
				self.vol.malfind(dump_dir=malfinds_dir, 
						 pid=str(args["ProcessId"]), 
						 add_data=False, 
						 ignore_protect=True, 
						 address=int(args["Address"],16))["data"][0])
				mem_analysis["diffs"]["diff_malfind"]["star"] = "yes"
		    	    elif trigger == "WriteProcessMemory -> CreateRemoteThread -> LoadLibrary":
			 	resdir = os.path.join(os.path.dirname(self.memfile), "dlls")
                                utils.create_dir_safe(resdir)
				pid = str(args["ProcessId"])
				base = int(args["BaseAddress"], 16)
				
				new_dlldump = self.vol.dlldump(dump_dir=resdir, pid=pid, base=base)
				mem_analysis["diffs"]["injected_dll"] = \
					{
                        		"new"           : new_dlldump["data"],
                        		"deleted"       : [],
                        		"star"          : "yes",
                        		"desc"          : "Shows the injected DLL",
                        		}
		    	    elif trigger == "NtSetContextThread -> NtResumeThread":
				pid = str(args["ProcessId"])
				tid = int(args["ThreadId"])
				self.get_injected_thread(pid, tid, mem_analysis)
		    	    elif trigger == "WriteProcessMemory -> CreateRemoteThread":
				start = int(args["StartRoutine"], 16)
				pid = str(args["ProcessId"])
                                tid = int(args["ThreadId"])
				dis = None
                                try:
                                        dis = disasm_from_memory(self.memfile, int(pid), start, 100)
                                except:
                                        pass
				self.get_injected_thread(pid, tid, mem_analysis, dis)

		return mem_analysis, new_results