def _waitForDeviceToBeReady(self): """Analyzes the device state and returns when it's ready.""" if self.state != AndroidDevice.STATE_STARTING: raise Exception( "Cannot wait of a device if its not started, its current state is '{0}'" .format(self.state)) self._logger.debug("Waiting for device {0} to be ready.".format( self.serialNumber)) cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "wait-for-device" ] OSCommand.executeCommand(cmd) self._logger.debug("Waiting for the device to be ready") self._logger.debug(" - (dev.bootcomplete)") ready = False while not ready: cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "getprop", "dev.bootcomplete" ] result = OSCommand.executeCommand(cmd) if result is not None and result.strip() == "1": ready = True else: time.sleep(1) self._logger.debug("- (sys_bootcomplete)") ready = False while not ready: cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "getprop", "sys.boot_completed" ] result = OSCommand.executeCommand(cmd) if result is not None and result.strip() == "1": ready = True else: time.sleep(1) self._logger.debug(" - (init.svc.bootanim)") ready = False while not ready: cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "getprop", "init.svc.bootanim" ] result = OSCommand.executeCommand(cmd) if result is not None and result.strip() == "stopped": ready = True else: time.sleep(1) time.sleep(5) self._logger.debug("Device {0} seems to be ready".format( self.serialNumber)) self.state = AndroidDevice.STATE_STARTED
def createTemplates(mainConfiguration, nb_templates): """Duplicates the initial template, one for each emulator. This is necessary only during an automatic analysis. """ refAVDName = os.path.split(mainConfiguration.referenceAVD)[1] refAvdConfigFile = "{0}.ini".format(mainConfiguration.referenceAVD) refAVDDir = os.path.join(mainConfiguration.virtualDevicePath, "{0}.avd/".format(refAVDName)) for emulatorId in xrange(nb_templates): newAvdConfigFile = "{0}_{1}.ini".format( mainConfiguration.referenceAVD, emulatorId) newAVDDir = os.path.join( mainConfiguration.virtualDevicePath, "{0}_{1}.avd/".format(refAVDName, emulatorId)) # delete old versions if os.path.exists(newAvdConfigFile): os.remove(newAvdConfigFile) if os.path.isdir(newAVDDir): shutil.rmtree(newAVDDir) shutil.copyfile(refAvdConfigFile, newAvdConfigFile) cmd = "cp -R {0} {1}".format(refAVDDir, newAVDDir) OSCommand.executeCommand(cmd)
def __pushBackup(self): """ Pushes backup folder to sdcard """ cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "push", os.path.join(self.__backupDir, "partitions"), os.path.join(self._dnadroidDir, "backup") ] OSCommand.executeCommand(cmd)
def __removeDirectoryHookerFromAVD(self): """Removes directory on the emulator where dnadroid has copied files. """ self._logger.debug("Deleting {0} directory on emulator {1}".format( self._dnadroidDir, self.serialNumber)) cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "rm", "-rf", self._dnadroidDir ] OSCommand.executeCommand(cmd)
def _restartADBServer(self): """ Restarts ADB server. This function is not used because we have to verify we don't have multiple devices. """ self._logger.info("Restarting ADB server...") cmd = [self.mainConfiguration.adbPath, "kill-server"] OSCommand.executeCommand(cmd) self._logger.info("ADB server has been killed.") cmd = [self.mainConfiguration.adbPath, "start-server"] OSCommand.executeCommand(cmd) self._logger.info("ADB server has been restarted.")
def accept(self): """accept the apk""" self._logger.info("accept {0}".format(self.serialNumber)) cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "input", "tap", "400 730" ] OSCommand.executeCommand(cmd) time.sleep(3) self.state = AndroidDevice.STATE_STARTING # waits for device to be ready self._waitForDeviceToBeReady()
def installAPK(self, apkFilename): """Installs the specified APK on the device""" if self.state != AndroidDevice.STATE_STARTED: raise Exception( "Cannot install the application since the device is not started." ) if apkFilename is None or len(apkFilename) == 0: raise Exception("Cannot install an application that has no name.") self._logger.info("Installing APK {0} on device {1}".format( apkFilename, self.name)) # $ adb install file.apk cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "install", apkFilename ] OSCommand.executeCommand(cmd)
def checkAPKInstrumenter(self): """Checks that APKInstrumenter application is installed on the device""" cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "pm", "list", "packages", "com.amossys.dnadroid" ] ret = OSCommand.executeCommand(cmd) if ret is None or len(ret) == 0 or 'dnadroid' not in ret: raise Exception( "APKInstrumenter application is not installed on your device. Please set up your device properly (see README file)" ) self._logger.info("ApkInstrumenter application is installed on device")
def __pushRecoveryScript(self): """ Pushes recovery script to TWRP recovery directory. This is done is 2 parts: first create the file on /sdcard/, then copy it to /cache/recovery/, using busybox. """ cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "touch", os.path.join(self._dnadroidDir, "openrecoveryscript") ] OSCommand.executeCommand(cmd) cmd = '{0} -s {1} shell echo "restore /sdcard/dnadroid/backup/" > {2}'.format( self.mainConfiguration.adbPath, self.serialNumber, os.path.join(self._dnadroidDir, "openrecoveryscript")) OSCommand.executeCommand(cmd) cmd = '{0} -s {1} shell su -c \'busybox cp {2} /cache/recovery/openrecoveryscript\''.format( self.mainConfiguration.adbPath, self.serialNumber, os.path.join(self._dnadroidDir, "openrecoveryscript")) ret = OSCommand.executeCommand(cmd) if len(ret) != 0: raise Exception(ret)
def reboot(self): """Reboot the device""" self._logger.info("Rebooting device listening on port {0}".format( self.serialNumber)) cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "reboot" ] self._logger.debug(OSCommand.executeCommand(cmd)) # Real device can take time to reboot time.sleep(15) # waits for device to be ready self._waitForDeviceToBeReady() self.state = AndroidDevice.STATE_STARTING
def reboot(self): """Reboot the emulator""" self._logger.info("Rebooting AVD listening on port {0}".format( self.serialNumber)) cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "setprop", "ctl.restart", "zygote" ] self._logger.debug(OSCommand.executeCommand(cmd)) time.sleep(5) self.state = AndroidDevice.STATE_STARTING # waits for device to be ready self._waitForDeviceToBeReady()
def __checkADBRecognizeDevice(self): """ Checks that ADB recognizes the device. Returns True if device is recognized by ADB, False otherwise. """ self._logger.info("Checking if ADB recognizes device...") cmd = [self.mainConfiguration.adbPath, "devices"] output = OSCommand.executeCommand(cmd) if self.serialNumber in output: self._logger.debug("Device has been find!") return True self._logger.error("Device has not been found.") return False
def start(self): """Starts the emulator""" if self.state != AndroidDevice.STATE_PREPARED: raise Exception( "Cannot start the emulator. (expected state was {0}, current state is {1})" .format(AndroidDevice.STATE_PREPARED, self.state)) # clean the temporary directory self.__cleanTemporaryDirectory() if self.__partitionSize is None: raise Exception("Partition size cannot be None") cmd = [ self.mainConfiguration.emulatorPath, "@{0}".format(self.name), "-partition-size", str(self.__partitionSize), "-no-snapshot-save", "-netspeed", "full", "-netdelay", "none", "-port", str(self.adbPort) ] self.__emulatorProcess = OSCommand.executeAsyncCommand(cmd) time.sleep(2) if self.__emulatorProcess.poll() is not None: raise Exception(self.__emulatorProcess.communicate()) self.state = AndroidDevice.STATE_STARTING # Waits for device to be ready self._waitForDeviceToBeReady() # Set the same time as host! self._logger.info("Setting emulator at the same time as host") localTime = datetime.datetime.now().strftime("%Y%m%d.%H%M%S") cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "date", "-s", localTime ] self._logger.debug(OSCommand.executeCommand(cmd)) # Checks that APKInstrumenter is install self.checkAPKInstrumenter()
def stop(self, askUser=False): """ Stop the device""" self._logger.info("Stopping device listening on port {0}".format( self.serialNumber)) clean = True # Pull our analysis events self._pullResults() # Ask user if they want to clean the device if askUser: answer = raw_input( "Do you want to clean your device? [Yes or No] ").lower() while answer != 'yes' and answer != 'no': answer = raw_input( "Do you want to clean your device? [Yes or No] ").lower() if answer == 'no': clean = False if clean: # If we have a real device we have to push backup to sdcard and push TWRP script to /cache/recovery/ # at each experiment self.__pushBackup() self.__pushRecoveryScript() # reboot into recovery cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "reboot", "recovery" ] self._logger.debug(OSCommand.executeCommand(cmd)) time.sleep(30) self._waitForDeviceToBeReady() time.sleep(5) # Wait 5 seconds to be sure SDcard will be mounted # When device is ready, don't forget to restore sdcard self.__restoreSDCard()
def startActivity(self, activity): """Starts the specified activity on the device""" if self.state != AndroidDevice.STATE_STARTED: raise Exception( "Cannot start an activity since the device is not started.") if activity is None or len(activity) == 0: raise Exception("Cannot start an activity that has no name.") self._logger.info("Starting activity {0} on device {1}".format( activity, self.name)) activityPackage = '.'.join(activity.split('.')[:-1]) activityName = ''.join(activity.split('.')[-1:]) # $ adb shell am start -n activityPackage/activity cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "am", "start", "-n", "{0}/.{1}".format(activityPackage, activityName) ] res = OSCommand.executeCommand(cmd) self._logger.debug("{}".format(res))
def writeContentOnSdCard(self, filename, fileContent): """Create (or replace) the filename related to the dnadroid path on the sdcard of the device with the specified fileContent.""" cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "mkdir", self._dnadroidDir ] OSCommand.executeCommand(cmd) filePath = os.path.join(self._dnadroidDir, filename) self._logger.debug("Writing content on '{0}'".format(filePath)) cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "touch", filePath ] OSCommand.executeCommand(cmd) cmd = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "echo", "\"{}\"".format(fileContent), ">", filePath ] OSCommand.executeCommand(cmd)
def __restoreSDCard(self): """ Restores the SDCard contents from backup folder. Iterates through sdcard folders and deletes files and folders that are not empty. Backup folder which contains sdcard initial folders and files will do the restore. """ self._logger.info("Restoring sdcard...") ls = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "ls" ] rm = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "shell", "rm", "-r" ] result = OSCommand.executeCommand(ls + ['/sdcard/']) folders = result.split('\r\n') for folder in folders: if len(folder) != 0: # If folder (or file) is not empty, deletes it res = OSCommand.executeCommand(ls + ['/sdcard/' + folder]) if len(res) != 0: self._logger.info("Deleting {0}".format('/sdcard/' + folder)) OSCommand.executeCommand(rm + ['/sdcard/' + folder]) # Push sdcard backup folder push = [ self.mainConfiguration.adbPath, "-s", self.serialNumber, "push", os.path.join(self.__backupDir, 'sdcard/'), '/sdcard/' ] OSCommand.executeCommand(push) self._logger.info("SDcard has been restored.")
def __duplicateAVD(self): """Creates a new emulator based on a reference one.""" self._logger.debug("Duplicate AVD '{0}'.".format( self.mainConfiguration.referenceAVD)) refAVDName = os.path.split(self.mainConfiguration.referenceAVD)[1] if self.analysisType == "manual": avdConfigFile = "{0}.ini".format( self.mainConfiguration.referenceAVD) referenceAVDDir = os.path.join( self.mainConfiguration.virtualDevicePath, "{0}.avd/".format(refAVDName)) else: #avdConfigFile = "{0}_{1}.ini".format(self.mainConfiguration.referenceAVD, self.emulatorId) #referenceAVDDir = os.path.join(self.mainConfiguration.virtualDevicePath, "{0}_{1}.avd/".format(refAVDName, self.emulatorId)) avdConfigFile = "{0}.ini".format( self.mainConfiguration.referenceAVD) referenceAVDDir = os.path.join( self.mainConfiguration.virtualDevicePath, "{0}.avd/".format(refAVDName)) if not os.path.exists(avdConfigFile): raise Exception("AVD configuration file does not exist: {}".format( avdConfigFile)) if not os.path.isdir(referenceAVDDir): raise Exception( "AVD directory does not exist: {}".format(referenceAVDDir)) newConfigFile = os.path.join(self.mainConfiguration.virtualDevicePath, "{0}.ini".format(self.name)) newAVDDir = os.path.join(self.mainConfiguration.virtualDevicePath, "{0}.avd/".format(self.name)) # If dir exists, remove it if os.path.exists(newAVDDir): self._logger.debug( "Old AVD detected, removing: {}".format(newAVDDir)) shutil.rmtree(newAVDDir) if os.path.exists(newConfigFile): self._logger.debug( "Old AVD configuration detected, removing: {}".format( newConfigFile)) os.remove(newConfigFile) hwQemuConfigFile = os.path.join(newAVDDir, "hardware-qemu.ini") defaultSnapshotConfigFile = os.path.join( newAVDDir, "snapshots.img.default-boot.ini") # First we copy the template self._logger.debug( "Copying AVD reference config file '{0}' in '{1}'...".format( avdConfigFile, newConfigFile)) shutil.copyfile(avdConfigFile, newConfigFile) # Copy the internal files of the reference avd self._logger.debug( "Duplicating the AVD internal content from '{0}' in '{1}'...". format(referenceAVDDir, newAVDDir)) # we use the internal linux 'cp' command for performance issues (shutil is too long) # shutil.copytree(referenceAVDDir, newAVDDir) cmd = "cp -R {0} {1}".format(referenceAVDDir, newAVDDir) OSCommand.executeCommand(cmd) # Than adapt the content of the copied files self.__replaceContentInFile(newConfigFile, refAVDName, self.name) self.__replaceContentInFile(hwQemuConfigFile, refAVDName, self.name) self.__replaceContentInFile(defaultSnapshotConfigFile, refAVDName, self.name) self.state = AndroidDevice.STATE_PREPARED