Example #1
0
def save_pcap(interface, filename):
    """
        Capture network traffic and save it to disk
        
        @param interface: network interface, e.g. eth0
        @param filename: filename to store pcap in
    """
    pcap_out = multiprocessing.Queue()
    pcap_writer = PcapWriter(filename, pcap_out)
    pcap_writer.start()
    net_sensor = NetworkSensor(interface)

    while True:
        pkt = net_sensor.read()
        if pkt is None:
            break

        pcap_out.put((pkt[0], str(pkt[1])))

    pcap_out.close()
    pcap_writer.stop()
Example #2
0
    def analysis_start(self):
        """
            Commands to execute when starting analysis.  Once this returns the
            analysis will wait for commands from the user.
            
            NOTE: Any threads will continue execute until a stop command is
                    received
        """

        # Analysis is done after this function returns
        self.CONTINUE_EXECUTION = False
        
        # Extract some important variables
        volatility_profile = self.lophi_command.volatility_profile
        lophi_command = self.lophi_command
        machine = self.machine
        sample_doc_id = lophi_command.sample_doc_id
        db_analysis_id = lophi_command.db_analysis_id
            
        # Initialize our database
        DB_samples = DatastoreSamples(lophi_command.services_host)
        DB_analysis = DatastoreAnalysis(lophi_command.services_host)
        
        # Copy the sample to the ftp server temporarily so that the SUA can
        # download it
        # store the temp directory name
        local_path = DB_samples.copy_sample_to_ftp(sample_doc_id)
        remote_path = os.path.relpath(local_path, G.FTP_ROOT)
        lophi_command.ftp_info['dir'] = remote_path
        
        # Create a tmp directory
        tmp_dir = G.dir_create_tmp()
        
        # Keep retrying in case any step fails
        while True:
            # Make sure that our machine is in the state that we expect.
            # Reversion can fail, make sure we actually revert the disk!

            timestamps = []

            print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            print "* %s: Resetting machine..."%self.machine.config.name
            reset_start = time.time()
            if not machine.machine_reset():
                continue
            reset_stop = time.time()
            timestamps.append((reset_start, reset_stop))
              
            # Start our machine up
#             print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            print "* %s: Powering on machine..."%self.machine.config.name
            boot_start = time.time()
            machine.power_on()

            
            if machine.type == G.MACHINE_TYPES.PHYSICAL:
                print "* %s: Ensuring that the disk sensor is up. (Bugfix)"%(
                                                    self.machine.config.name)
                while True:
                    time.sleep(5)
                    if machine.disk.is_up():
                        break
                    machine.power_off()
                    time.sleep(5)
                    machine.power_on()
               
            # Wait for the machine to appear on the network
            print "* %s: Timestamp: %f"%(self.machine.config.name, time.time())
            print "* %s: Waiting for OS to boot..."%self.machine.config.name
            
            bad_disk_image = False
            
            for os_attempt in xrange(self.OS_BOOT_ATTEMPTS+1):
                if os_attempt == self.OS_BOOT_ATTEMPTS:
                    bad_disk_image = True
                    break
                
                start = time.time()
                os_timed_out = False
                while not self.machine.network_get_status():
                    time.sleep(1)
                    if time.time() - start > self.OS_TIMEOUT:
                        os_timed_out = True
                        break
                # Did we timeout?
                if os_timed_out:
                    logger.error("%s: OS boot timeout! (%d/%d)" % (
                                 self.machine.config.name,
                                 os_attempt+1,
                                 self.OS_BOOT_ATTEMPTS))
                    
                    self.machine.power_reset()
                    continue
                else:
                    break

                       
            # Do we have a bad image on the disk?
            if bad_disk_image:
                logger.error("%s: Bad disk image! (Starting over)" %
                                 self.machine.config.name)
                continue

            boot_stop = time.time()
            timestamps.append((boot_start,boot_stop))
            
            # Wait a bit before doing stuff (Allow the OS to finish booting
            print "* %s: Timestamp: %f"%(self.machine.config.name, time.time())
            print "* %s: Waiting for the OS to stabilize" % \
                  self.machine.config.name
            osstable_start = time.time()
            time.sleep(self.OS_BOOT_WAIT)
            osstable_stop = time.time()
            timestamps.append((osstable_start,osstable_stop))
                 
            # Start our disk capturing
#             print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            print "* %s: Starting disk capture..."%self.machine.config.name
            disk_pcap_file = os.path.join(tmp_dir,"sut_disk_io.dcap")
            disk_queue = multiprocessing.Queue()
            dcap_writer = CaptureWriter(disk_pcap_file,
                                     disk_queue)
            disk_tap = DiskCaptureEngine(machine,
                                         disk_queue)
            # Start disk capture
            disk_tap.start()
            dcap_writer.start()
            
            # Send keypresses to download binary   
            print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())                  
            print "* %s: Sending keypresses..."%self.machine.config.name
            
            # Get our keypress generator
            kpg = machine.keypress_get_generator()
            
            # Check ftp info, and send commands to execute malware
            keypress_start = time.time()
            if lophi_command.ftp_info['ip'] is not None and \
               lophi_command.ftp_info['dir'] is not None:
                print "* %s: Executing ftp commands..."%self.machine.config.name
                ftp_script = kpg.get_ftp_script(volatility_profile,
                                                lophi_command.ftp_info,
                                                hit_enter=False)
                machine.keypress_send(ftp_script)
            else:
                print "* %s:* No ftp info given."%self.machine.config.name

            keypress_stop = time.time()
            timestamps.append((keypress_start,keypress_stop))
            # At this the point machine has the binary on it, and is one
            # ENTER key away from executing it.
            
            # Dump our memory
            print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            print "* %s: Dumping memory (Clean)..."%self.machine.config.name
            memory_file_clean = os.path.join(tmp_dir,"sut_memory_clean.mfd")
            cleandump_start = time.time()
            if not machine.memory_dump(memory_file_clean):
                # Stop everything, and start over.
                dcap_writer.stop()
                disk_tap.stop()
                logger.error("%s: Memory Dump Failed! (Starting over)"%
                             self.machine.config.name)
                continue
            cleandump_stop = time.time()
            timestamps.append((cleandump_start, cleandump_stop))
            
            # Compress clean file
            
            memory_file_clean_gz = os.path.join(tmp_dir,
                                                "sut_memory_clean.tar.gz")
            memory_file_clean_tmp = memory_file_clean+".tmp"
            
            shutil.copy(memory_file_clean, memory_file_clean_tmp)
                
            memory_clean_compress = multiprocessing.Process(
                                                    target=self.compress_file, 
                                                    args=(memory_file_clean,
                                                          memory_file_clean_gz))
            memory_clean_compress.start()

            timestamps.append((0, 0)) # Place holder for mem compression

            # Start our network capturing
            # Setup a capture thread and thread to write the pcap
            print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            print "* %s: Starting network capture"%self.machine.config.name
            network_pcap_file = os.path.join(tmp_dir,"sut_network.pcap")
            network_queue = multiprocessing.Queue()
            pcap_writer = PcapWriter(network_pcap_file,
                                     network_queue)
            net_tap = NetworkCaptureEngine(machine,
                                           network_queue)
            # Start network capture
            pcap_writer.start()
            net_tap.start()
            
            print "* %s: Getting a list of current buttons" % \
                  self.machine.config.name
            start_time = time.time() 
            # Start binary and click buttons
            try:
                # Initialize our button clicker instance on our clean mem. image
                vol_uri = "file://"+memory_file_clean_tmp
                bc = ButtonClicker(vol_uri,
                              machine.config.volatility_profile,
                              machine.memory_get_size(),
                              machine.control)
                # Get our current button list
                cleanbuttons_start = time.time()
                bc.update_buttons()
                cleanbuttons_stop = time.time()
                timestamps.append((cleanbuttons_start, cleanbuttons_stop))
            
                #
                # Start our binary!
                #
                print "* %s: Timestamp: %f"%(self.machine.config.name,
                                             time.time())
                print "* %s: Running binary!"%self.machine.config.name
                machine.keypress_send(kpg.text_to_script("SPECIAL:RETURN"))
                
                # Start wiggling our mouse to emulate a human
                print "* %s: Wiggling mouse."%self.machine.config.name
                self.machine.control.mouse_wiggle(True)
                
                start_time = time.time()
                
                # Wait a bit for it to open
                executewait_start = time.time()
                time.sleep(60)
                executewait_stop = time.time()
                timestamps.append((executewait_start, executewait_stop))
                
                # Take another memory dump
                print "* %s: Timestamp: %f"%(self.machine.config.name,
                                             time.time())
                print "* %s: Dumping memory (Interim)..." % \
                      self.machine.config.name
                interimdump_start = time.time()
                if not machine.memory_dump(memory_file_clean_tmp):
                    raise Exception("Bad memory read.")
                interimdump_stop = time.time()
                timestamps.append((interimdump_start,interimdump_stop))

                # Let's take a screenshot
                screenshot1_start = time.time()
                try:
                    print "* %s: Timestamp: %f"%(self.machine.config.name,
                                                 time.time())
                    print "* %s: Taking a screenshot."%self.machine.config.name
                    screenshot_file = os.path.join(tmp_dir,"sut_screenshot")
                    screenshot_file = self.machine.screenshot(
                        screenshot_file, vol_uri=vol_uri)
                    DB_analysis.append_analysis_file(db_analysis_id,
                                                     screenshot_file,
                                                     "screenshot")
                except:
                    import traceback
                    traceback.print_exc()
                    logger.error("Could not take a screenshot.")
                    pass
                screenshot1_stop = time.time()
                timestamps.append((screenshot1_start, screenshot1_stop))
                
                # Click any new buttons that appeared
                print "* %s: Timestamp: %f"%(self.machine.config.name,
                                             time.time())
                print "* %s: Clicking buttons..."%self.machine.config.name

                dirtybuttons_start = time.time()
                clicked = bc.click_buttons(new_only=True)
                for c in clicked:
                    print "* %s: Clicked: %s:%s"%(self.machine.config.name,
                                                  c['process'],c['name'])
                dirtybuttons_stop = time.time()
                timestamps.append((dirtybuttons_start, dirtybuttons_stop))
                
                # Clean up the file on disk
                os.remove(memory_file_clean_tmp)
                
                # Save which buttons that we clicked
                DB_analysis.update_analysis(db_analysis_id,
                                             "buttons_clicked",
                                             clicked)
                
            except:
                logger.error("%s: Failed to start binary and click buttons. "
                             "(Starting over)"%
                             self.machine.config.name)
                import traceback
                traceback.print_exc()
                
                self.machine.control.mouse_wiggle(False)
                dcap_writer.stop()
                disk_tap.stop()
                pcap_writer.stop()
                net_tap.stop()
                
                continue

            # Run binary for as long as we see fit

            sleep_time = self.MALWARE_EXECUTION_TIME-(time.time()-start_time)

            print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            executeend_start = time.time()
            if sleep_time > 0:
                print "* %s: Sleeping for %d seconds." % (
                    self.machine.config.name,
                    sleep_time)
                time.sleep(sleep_time)

            executeend_stop = time.time()
            timestamps.append((executeend_start,executeend_stop))
             
            # Dump our memory again
            print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            print "* %s: Dumping memory..."%self.machine.config.name
            memory_file_dirty = os.path.join(tmp_dir,"sut_memory_dirty.mfd")
            dirtydump_start = time.time()
            if not machine.memory_dump(memory_file_dirty):
                # Stop everything, and start over.
                self.machine.control.mouse_wiggle(False)
                dcap_writer.stop()
                disk_tap.stop()
                pcap_writer.stop()
                net_tap.stop()
                logger.error("%s: Memory Dump Failed! (Starting over)"%
                             self.machine.config.name)
                continue
            dirtydump_stop = time.time()
            timestamps.append((dirtydump_start, dirtydump_stop))
             
            # Let's take a screenshot
            screenshot2_start = time.time()
            try:
                print "* %s: Timestamp: %f"%(self.machine.config.name,
                                             time.time())
                print "* %s: Taking a screenshot."%self.machine.config.name
                screenshot_file_final = os.path.join(tmp_dir,
                                                     "sut_screenshot_final")
                vol_uri = "file://"+memory_file_dirty
                screenshot_file_final = self.machine.screenshot(
                    screenshot_file_final, vol_uri=vol_uri)
                DB_analysis.append_analysis_file(db_analysis_id,
                                                 screenshot_file_final,
                                                 "screenshot_final")
            except:
                logger.error("Could not take a screenshot.")
                pass
            screenshot2_stop = time.time()
            timestamps.append((screenshot2_start, screenshot2_stop))

            # Join our clean compression
            memory_clean_compress.join()
            memory_clean_compress.terminate()
             
            # Compress dirty file
            dirtycompress_start = time.time()
            memory_file_dirty_gz = os.path.join(tmp_dir,
                                                "sut_memory_dirty.tar.gz")
            self.compress_file(memory_file_dirty, memory_file_dirty_gz)
            dirtycompress_stop = time.time()
            timestamps.append((dirtycompress_start, dirtycompress_stop))

            # Power down the machine (Will also flush disk caches)
            print "* %s: Timestamp: %f"%(self.machine.config.name, time.time())
            print "* Shutting down machine."
            shutdown_start = time.time()
            self.machine.power_shutdown()
            # Wait for machine to power off
            start = time.time()
            offs= 0
            while True:
                # power status
                status = self.machine.power_status()
                if status != G.SENSOR_CONTROL.POWER_STATUS.ON:
                    offs += 1
                else:
                    offs = 0
                    
                # Make sure the machien is really off
                if offs > 3:
                    # machine is powered off
                    print "* Shutdown successful."
                    break
                
                if time.time()-start > 60:
                    print "* Shutdown failed."
                    break
            shutdown_stop = time.time()
            timestamps.append((shutdown_start, shutdown_stop))
            
            # Stop wiggeling our mouse
            self.machine.control.mouse_wiggle(False)
            
            # Stop Disk Capture
            dcap_writer.stop()
            disk_tap.stop()
            
            # Stop network capture
            pcap_writer.stop()
            net_tap.stop()

            storeresults_start = time.time()
            # Save all of our generated fields to the database
            print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            print "* %s: Storing results in database..." % \
                  self.machine.config.name
            DB_analysis.append_analysis_file(db_analysis_id,
                                             memory_file_clean_gz,
                                             "memory_dump_clean")
            DB_analysis.append_analysis_file(db_analysis_id,
                                             memory_file_dirty_gz,
                                             "memory_dump_dirty")
            
            # Save pcap and dcap files
            DB_analysis.append_analysis_file(db_analysis_id,
                                             network_pcap_file,
                                             "network_capture")
            DB_analysis.append_analysis_file(db_analysis_id,
                                             disk_pcap_file,
                                             "disk_capture")
            storeresults_stop = time.time()
            timestamps.append((storeresults_start, storeresults_stop))

            # Clean up files on disk
            G.dir_remove(local_path)
            G.dir_remove(tmp_dir)

            print "* %s: Timestamp: %f"%(self.machine.config.name, time.time())
            print "* %s: Done!"%self.machine.config.name
            print "** %s: Times "%self.machine.config.name, timestamps
            # Break out of our "try forever" loop
            break
Example #3
0
    def analysis_start(self):
        """
            Commands to execute when starting analysis.  Once this returns the
            analysis will wait for commands from the user.
            
            NOTE: Any threads will continue execute until a stop command is
                    received
        """

        # Analysis is done after this function returns
        self.CONTINUE_EXECUTION = False

        # Extract some important variables
        volatility_profile = self.lophi_command.volatility_profile
        lophi_command = self.lophi_command
        machine = self.machine
        sample_doc_id = lophi_command.sample_doc_id
        db_analysis_id = lophi_command.db_analysis_id

        # Initialize our database
        DB_samples = DatastoreSamples(lophi_command.services_host)
        DB_analysis = DatastoreAnalysis(lophi_command.services_host)

        # Copy the sample to the ftp server temporarily so that the SUA can
        # download it
        # store the temp directory name
        local_path = DB_samples.copy_sample_to_ftp(sample_doc_id)
        remote_path = os.path.relpath(local_path, G.FTP_ROOT)
        lophi_command.ftp_info['dir'] = remote_path

        # Create a tmp directory
        tmp_dir = G.dir_create_tmp()

        # Keep retrying in case any step fails
        while True:
            # Make sure that our machine is in the state that we expect.
            # Reversion can fail, make sure we actually revert the disk!

            timestamps = []

            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* %s: Resetting machine..." % self.machine.config.name
            reset_start = time.time()
            if not machine.machine_reset():
                continue
            reset_stop = time.time()
            timestamps.append((reset_start, reset_stop))

            # Start our machine up
            #             print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            print "* %s: Powering on machine..." % self.machine.config.name
            boot_start = time.time()
            machine.power_on()

            if machine.type == G.MACHINE_TYPES.PHYSICAL:
                print "* %s: Ensuring that the disk sensor is up. (Bugfix)" % (
                    self.machine.config.name)
                while True:
                    time.sleep(5)
                    if machine.disk.is_up():
                        break
                    machine.power_off()
                    time.sleep(5)
                    machine.power_on()

            # Wait for the machine to appear on the network
            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* %s: Waiting for OS to boot..." % self.machine.config.name

            bad_disk_image = False

            for os_attempt in xrange(self.OS_BOOT_ATTEMPTS + 1):
                if os_attempt == self.OS_BOOT_ATTEMPTS:
                    bad_disk_image = True
                    break

                start = time.time()
                os_timed_out = False
                while not self.machine.network_get_status():
                    time.sleep(1)
                    if time.time() - start > self.OS_TIMEOUT:
                        os_timed_out = True
                        break
                # Did we timeout?
                if os_timed_out:
                    logger.error("%s: OS boot timeout! (%d/%d)" %
                                 (self.machine.config.name, os_attempt + 1,
                                  self.OS_BOOT_ATTEMPTS))

                    self.machine.power_reset()
                    continue
                else:
                    break

            # Do we have a bad image on the disk?
            if bad_disk_image:
                logger.error("%s: Bad disk image! (Starting over)" %
                             self.machine.config.name)
                continue

            boot_stop = time.time()
            timestamps.append((boot_start, boot_stop))

            # Wait a bit before doing stuff (Allow the OS to finish booting
            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* %s: Waiting for the OS to stabilize" % \
                  self.machine.config.name
            osstable_start = time.time()
            time.sleep(self.OS_BOOT_WAIT)
            osstable_stop = time.time()
            timestamps.append((osstable_start, osstable_stop))

            # Start our disk capturing
            #             print "* %s: Timestamp: %f"%(self.machine.config.name,time.time())
            print "* %s: Starting disk capture..." % self.machine.config.name
            disk_pcap_file = os.path.join(tmp_dir, "sut_disk_io.dcap")
            disk_queue = multiprocessing.Queue()
            dcap_writer = CaptureWriter(disk_pcap_file, disk_queue)
            disk_tap = DiskCaptureEngine(machine, disk_queue)
            # Start disk capture
            disk_tap.start()
            dcap_writer.start()

            # Send keypresses to download binary
            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* %s: Sending keypresses..." % self.machine.config.name

            # Get our keypress generator
            kpg = machine.keypress_get_generator()

            # Check ftp info, and send commands to execute malware
            keypress_start = time.time()
            if lophi_command.ftp_info['ip'] is not None and \
               lophi_command.ftp_info['dir'] is not None:
                print "* %s: Executing ftp commands..." % self.machine.config.name
                ftp_script = kpg.get_ftp_script(volatility_profile,
                                                lophi_command.ftp_info,
                                                hit_enter=False)
                machine.keypress_send(ftp_script)
            else:
                print "* %s:* No ftp info given." % self.machine.config.name

            keypress_stop = time.time()
            timestamps.append((keypress_start, keypress_stop))
            # At this the point machine has the binary on it, and is one
            # ENTER key away from executing it.

            # Dump our memory
            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* %s: Dumping memory (Clean)..." % self.machine.config.name
            memory_file_clean = os.path.join(tmp_dir, "sut_memory_clean.mfd")
            cleandump_start = time.time()
            if not machine.memory_dump(memory_file_clean):
                # Stop everything, and start over.
                dcap_writer.stop()
                disk_tap.stop()
                logger.error("%s: Memory Dump Failed! (Starting over)" %
                             self.machine.config.name)
                continue
            cleandump_stop = time.time()
            timestamps.append((cleandump_start, cleandump_stop))

            # Compress clean file

            memory_file_clean_gz = os.path.join(tmp_dir,
                                                "sut_memory_clean.tar.gz")
            memory_file_clean_tmp = memory_file_clean + ".tmp"

            shutil.copy(memory_file_clean, memory_file_clean_tmp)

            memory_clean_compress = multiprocessing.Process(
                target=self.compress_file,
                args=(memory_file_clean, memory_file_clean_gz))
            memory_clean_compress.start()

            timestamps.append((0, 0))  # Place holder for mem compression

            # Start our network capturing
            # Setup a capture thread and thread to write the pcap
            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* %s: Starting network capture" % self.machine.config.name
            network_pcap_file = os.path.join(tmp_dir, "sut_network.pcap")
            network_queue = multiprocessing.Queue()
            pcap_writer = PcapWriter(network_pcap_file, network_queue)
            net_tap = NetworkCaptureEngine(machine, network_queue)
            # Start network capture
            pcap_writer.start()
            net_tap.start()

            print "* %s: Getting a list of current buttons" % \
                  self.machine.config.name
            start_time = time.time()
            # Start binary and click buttons
            try:
                # Initialize our button clicker instance on our clean mem. image
                vol_uri = "file://" + memory_file_clean_tmp
                bc = ButtonClicker(vol_uri, machine.config.volatility_profile,
                                   machine.memory_get_size(), machine.control)
                # Get our current button list
                cleanbuttons_start = time.time()
                bc.update_buttons()
                cleanbuttons_stop = time.time()
                timestamps.append((cleanbuttons_start, cleanbuttons_stop))

                #
                # Start our binary!
                #
                print "* %s: Timestamp: %f" % (self.machine.config.name,
                                               time.time())
                print "* %s: Running binary!" % self.machine.config.name
                machine.keypress_send(kpg.text_to_script("SPECIAL:RETURN"))

                # Start wiggling our mouse to emulate a human
                print "* %s: Wiggling mouse." % self.machine.config.name
                self.machine.control.mouse_wiggle(True)

                start_time = time.time()

                # Wait a bit for it to open
                executewait_start = time.time()
                time.sleep(60)
                executewait_stop = time.time()
                timestamps.append((executewait_start, executewait_stop))

                # Take another memory dump
                print "* %s: Timestamp: %f" % (self.machine.config.name,
                                               time.time())
                print "* %s: Dumping memory (Interim)..." % \
                      self.machine.config.name
                interimdump_start = time.time()
                if not machine.memory_dump(memory_file_clean_tmp):
                    raise Exception("Bad memory read.")
                interimdump_stop = time.time()
                timestamps.append((interimdump_start, interimdump_stop))

                # Let's take a screenshot
                screenshot1_start = time.time()
                try:
                    print "* %s: Timestamp: %f" % (self.machine.config.name,
                                                   time.time())
                    print "* %s: Taking a screenshot." % self.machine.config.name
                    screenshot_file = os.path.join(tmp_dir, "sut_screenshot")
                    screenshot_file = self.machine.screenshot(screenshot_file,
                                                              vol_uri=vol_uri)
                    DB_analysis.append_analysis_file(db_analysis_id,
                                                     screenshot_file,
                                                     "screenshot")
                except:
                    import traceback
                    traceback.print_exc()
                    logger.error("Could not take a screenshot.")
                    pass
                screenshot1_stop = time.time()
                timestamps.append((screenshot1_start, screenshot1_stop))

                # Click any new buttons that appeared
                print "* %s: Timestamp: %f" % (self.machine.config.name,
                                               time.time())
                print "* %s: Clicking buttons..." % self.machine.config.name

                dirtybuttons_start = time.time()
                clicked = bc.click_buttons(new_only=True)
                for c in clicked:
                    print "* %s: Clicked: %s:%s" % (self.machine.config.name,
                                                    c['process'], c['name'])
                dirtybuttons_stop = time.time()
                timestamps.append((dirtybuttons_start, dirtybuttons_stop))

                # Clean up the file on disk
                os.remove(memory_file_clean_tmp)

                # Save which buttons that we clicked
                DB_analysis.update_analysis(db_analysis_id, "buttons_clicked",
                                            clicked)

            except:
                logger.error("%s: Failed to start binary and click buttons. "
                             "(Starting over)" % self.machine.config.name)
                import traceback
                traceback.print_exc()

                self.machine.control.mouse_wiggle(False)
                dcap_writer.stop()
                disk_tap.stop()
                pcap_writer.stop()
                net_tap.stop()

                continue

            # Run binary for as long as we see fit

            sleep_time = self.MALWARE_EXECUTION_TIME - (time.time() -
                                                        start_time)

            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            executeend_start = time.time()
            if sleep_time > 0:
                print "* %s: Sleeping for %d seconds." % (
                    self.machine.config.name, sleep_time)
                time.sleep(sleep_time)

            executeend_stop = time.time()
            timestamps.append((executeend_start, executeend_stop))

            # Dump our memory again
            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* %s: Dumping memory..." % self.machine.config.name
            memory_file_dirty = os.path.join(tmp_dir, "sut_memory_dirty.mfd")
            dirtydump_start = time.time()
            if not machine.memory_dump(memory_file_dirty):
                # Stop everything, and start over.
                self.machine.control.mouse_wiggle(False)
                dcap_writer.stop()
                disk_tap.stop()
                pcap_writer.stop()
                net_tap.stop()
                logger.error("%s: Memory Dump Failed! (Starting over)" %
                             self.machine.config.name)
                continue
            dirtydump_stop = time.time()
            timestamps.append((dirtydump_start, dirtydump_stop))

            # Let's take a screenshot
            screenshot2_start = time.time()
            try:
                print "* %s: Timestamp: %f" % (self.machine.config.name,
                                               time.time())
                print "* %s: Taking a screenshot." % self.machine.config.name
                screenshot_file_final = os.path.join(tmp_dir,
                                                     "sut_screenshot_final")
                vol_uri = "file://" + memory_file_dirty
                screenshot_file_final = self.machine.screenshot(
                    screenshot_file_final, vol_uri=vol_uri)
                DB_analysis.append_analysis_file(db_analysis_id,
                                                 screenshot_file_final,
                                                 "screenshot_final")
            except:
                logger.error("Could not take a screenshot.")
                pass
            screenshot2_stop = time.time()
            timestamps.append((screenshot2_start, screenshot2_stop))

            # Join our clean compression
            memory_clean_compress.join()
            memory_clean_compress.terminate()

            # Compress dirty file
            dirtycompress_start = time.time()
            memory_file_dirty_gz = os.path.join(tmp_dir,
                                                "sut_memory_dirty.tar.gz")
            self.compress_file(memory_file_dirty, memory_file_dirty_gz)
            dirtycompress_stop = time.time()
            timestamps.append((dirtycompress_start, dirtycompress_stop))

            # Power down the machine (Will also flush disk caches)
            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* Shutting down machine."
            shutdown_start = time.time()
            self.machine.power_shutdown()
            # Wait for machine to power off
            start = time.time()
            offs = 0
            while True:
                # power status
                status = self.machine.power_status()
                if status != G.SENSOR_CONTROL.POWER_STATUS.ON:
                    offs += 1
                else:
                    offs = 0

                # Make sure the machien is really off
                if offs > 3:
                    # machine is powered off
                    print "* Shutdown successful."
                    break

                if time.time() - start > 60:
                    print "* Shutdown failed."
                    break
            shutdown_stop = time.time()
            timestamps.append((shutdown_start, shutdown_stop))

            # Stop wiggeling our mouse
            self.machine.control.mouse_wiggle(False)

            # Stop Disk Capture
            dcap_writer.stop()
            disk_tap.stop()

            # Stop network capture
            pcap_writer.stop()
            net_tap.stop()

            storeresults_start = time.time()
            # Save all of our generated fields to the database
            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* %s: Storing results in database..." % \
                  self.machine.config.name
            DB_analysis.append_analysis_file(db_analysis_id,
                                             memory_file_clean_gz,
                                             "memory_dump_clean")
            DB_analysis.append_analysis_file(db_analysis_id,
                                             memory_file_dirty_gz,
                                             "memory_dump_dirty")

            # Save pcap and dcap files
            DB_analysis.append_analysis_file(db_analysis_id, network_pcap_file,
                                             "network_capture")
            DB_analysis.append_analysis_file(db_analysis_id, disk_pcap_file,
                                             "disk_capture")
            storeresults_stop = time.time()
            timestamps.append((storeresults_start, storeresults_stop))

            # Clean up files on disk
            G.dir_remove(local_path)
            G.dir_remove(tmp_dir)

            print "* %s: Timestamp: %f" % (self.machine.config.name,
                                           time.time())
            print "* %s: Done!" % self.machine.config.name
            print "** %s: Times " % self.machine.config.name, timestamps
            # Break out of our "try forever" loop
            break