Example #1
0
    def runSimulation(self, duration, package_name, random, device_serial, session):
        from uiautomator import device as d  # possible bug

        # initilize status logging
        self.event_log = logging.getLogger("start_status")
        self.event_log.setLevel(logging.DEBUG)
        START_LOG = os.path.join(session.logs_dir, "interaction.log")
        ih = logging.FileHandler(START_LOG)
        ih.setLevel(logging.ERROR)
        formatter = logging.Formatter("%(asctime)s - %(message)s")
        ih.setFormatter(formatter)
        self.event_log.addHandler(ih)
        # try:

        d.screen.on()

        adb = Adb()
        start_package_command = "monkey -p %s -c android.intent.category.LAUNCHER 1" % package_name
        adb.shell(start_package_command, device_serial=device_serial)
        self.event_log.info("Started %s" % package_name)
        time.sleep(10)

        # check screen now has the same package name
        visited_screen = []
        screen_widgets = d.dump()
        root = ET.fromstring(screen_widgets)

        # DFS trigger
        self.dfs_trigger(
            current_screen=root,
            duration=duration,
            package_name=package_name,
            device_serial=device_serial,
            visited_screen=visited_screen,
        )
Example #2
0
class profile1(IPlugin, Profile):
    """
    profile works on xiaomi red mi 4G
    """

    def __init__(self):
        self.adb = Adb()
        super(profile1, self).__init__()

    def runSimulation(self, duration, package_name, random, device_serial, session):
        from uiautomator import device as d  # possible bug

        # initilize status logging
        self.event_log = logging.getLogger("start_status")
        self.event_log.setLevel(logging.DEBUG)
        START_LOG = os.path.join(session.logs_dir, "interaction.log")
        ih = logging.FileHandler(START_LOG)
        ih.setLevel(logging.ERROR)
        formatter = logging.Formatter("%(asctime)s - %(message)s")
        ih.setFormatter(formatter)
        self.event_log.addHandler(ih)
        # try:

        d.screen.on()

        adb = Adb()
        start_package_command = "monkey -p %s -c android.intent.category.LAUNCHER 1" % package_name
        adb.shell(start_package_command, device_serial=device_serial)
        self.event_log.info("Started %s" % package_name)
        time.sleep(10)

        # check screen now has the same package name
        visited_screen = []
        screen_widgets = d.dump()
        root = ET.fromstring(screen_widgets)

        # DFS trigger
        self.dfs_trigger(
            current_screen=root,
            duration=duration,
            package_name=package_name,
            device_serial=device_serial,
            visited_screen=visited_screen,
        )
        # except Exception as e:
        # self.event_log.info("ERROR in simulation")

    def dfs_trigger(self, current_screen, duration, package_name, device_serial, visited_screen):
        from uiautomator import device as d

        if current_screen == {}:
            # print "reach end of the world"
            d.press.back()
            self.event_log.info("back")
            return True

        for child in current_screen.iter("node"):
            node_dict = child.attrib
            m = hashlib.md5()
            m.update(node_dict.__str__())
            md5 = m.digest()

            if not visited_screen.__contains__(md5):
                visited_screen.append(md5)
                # press device to go to next screen
                if node_dict["long-clickable"] == True:
                    d(text=node_dict["text"], className=node_dict["class"]).long_click()
                    self.event_log.info("long click: %s" % node_dict)
                else:
                    d(text=node_dict["text"], className=node_dict["class"]).click()
                    self.event_log.info("short click: %s" % node_dict)

                screen_widgets = d.dump()
                subScreen = ET.fromstring(screen_widgets)
                return self.dfs_trigger(
                    current_screen=subScreen,
                    duration=duration,
                    package_name=package_name,
                    device_serial=device_serial,
                    visited_screen=visited_screen,
                )

        # print "child screens visited!"
        d.press.back()
        # self.event_log.info("back")
        return True

    def prepare(self, params, device_serial):
        """
        Prepare device by installing profile's apk and apk databases
        :return:
        """
        # NOTE: modified uiautomator's /usr/local/lib/python2.7/dist-packages/uiautomator/__init__.py line 470
        # to prevent library insisting on installing uiautomator without root

        # install apks for profile
        apks_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "apk")
        self.adb.wait_for_device(device_serial)
        apks = os.listdir(apks_dir)
        for apk in apks:
            apk_path = os.path.join(apks_dir, apk)
            if os.path.isfile(apk_path):
                # logs.info("Installing apk %s" %(apk_path))
                apk_realpath = os.path.realpath(apk_path)
                self.adb.push(source=apk_realpath, dest="/sdcard/tmp.apk", device_serial=device_serial)
                self.adb.shell("pm install -rt /sdcard/tmp.apk", root=True, device_serial=device_serial)
                self.adb.shell("rm -f /sdcard/tmp.apk", root=True, device_serial=device_serial)

        # copy app data to respective directory in device
        app_data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "app_data", "app_data.ini")
        app_data_ini = ConfigParser.ConfigParser()
        app_data_ini.read(app_data_path)

        for app_file in app_data_ini.sections():
            # logs.info("copying %s"%file)
            app_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "app_data", app_file)
            temp_device_path = os.path.join("data", "local", "tmp", app_file)
            self.adb.push(source=app_file_path, dest=temp_device_path, device_serial=device_serial)

            for key, value in app_data_ini.items(app_file):
                if key == "filePermission":
                    chown_command = "chown %s %s" % (value, temp_device_path)
                    self.adb.shell(root=True, command=chown_command, device_serial=device_serial)
                if key == "devicePath":
                    actual_device_path = value
                    mv_command = "mv %s %s" % (temp_device_path, actual_device_path)
                    self.adb.shell(root=True, command=mv_command, device_serial=device_serial)

        return True

    def get_view(self):
        """
        get the django configuration form.
        If you don't know what to do with this method, DON'T CHANGE ANYTHING
        :return: django configuration form
        """
        sys.path.append(os.path.dirname(os.path.abspath(__file__)))
        from view_profile1 import ConfigForm

        sys.path.remove(os.path.dirname(os.path.abspath(__file__)))
        return ConfigForm
Example #3
0
class Partition(object):
    __metaclass__ = Singleton

    def __init__(self):
        self.adb = Adb()
        self.fastboot = Fastboot()
        self.device = Device()

        #constant variables
        self.RECOVERY = "recovery"
        self.TWRP_SWITCH = "BDO" #BSDCO


    def restore(self, twrp_path, backup_src, backup_dest, device_serial):
        try:
            log.info("Restoring android device partitions")
            RECOVERY = self.RECOVERY
            ORIGINAL_RECOVERY_PATH = os.path.join(backup_src, "original_recovery")

            log.info("Waiting for device in adb mode")
            self.adb.wait_for_device(device_serial)

            self.adb.reboot_bootloader(device_serial)
            self.fastboot.flash(partition=RECOVERY, image_path=twrp_path, device_serial=device_serial)
            self.fastboot.reboot(device_serial)
            self.adb.wait_for_device(device_serial)
            self.adb.reboot_recovery(device_serial)
            #self.adb.shell("mkdir -p %s"%(backup_dest))

            backup_file_paths = glob.glob(os.path.join(backup_src, "*.win*"))
            self.adb.reboot_recovery(device_serial) #needed, if not will have bug in adb push
            for backup_file_path in backup_file_paths:
                backup_file_split = backup_file_path.split("/")
                backup_file_name = backup_file_split[len(backup_file_split) - 1]
                #self.__copy_backup(source_filepath=backup_file_path, dest_filepath=os.path.join(backup_dest, backup_file_name), direction="push", twrp=True, device_serial=device_serial, check_hash=True)


            backup_dest_split = backup_dest.split("/")
            backup_folder_name = backup_dest_split[-2]

            self.adb.shell("twrp restore %s %s"%(backup_folder_name, self.TWRP_SWITCH),device_serial)
            self.adb.shell("rm -rf %s"%(backup_dest), device_serial)
            self.adb.reboot(device_serial)
            self.adb.wait_for_device(device_serial)
            self.adb.reboot_bootloader(device_serial)
            self.fastboot.flash(RECOVERY, ORIGINAL_RECOVERY_PATH, device_serial)
            self.fastboot.reboot(device_serial)
            self.adb.wait_for_device(device_serial)
            log.info("Restore device successfully")
            return True
        except Exception as e:
            log.error("unable to restore device partitions")
            self.restore(self, twrp_path, backup_src, backup_dest, device_serial)


    def backup(self, twrp_path, backup_dest, device_serial):
        try:
            log.info("Backing up android device partitions")
            RECOVERY = self.RECOVERY

            RECOVERY_PATH = self.device.backup_path(device_serial)

            RECOVERY_TEMP_DEV_LOC = os.path.join(RECOVERY_PATH, RECOVERY)
            ORIGINAL_RECOVERY_PATH = os.path.join(backup_dest, "original_recovery")

            mount_point = self.__get_mount_point(device_serial=device_serial)
            partitions = self.__get_partitions(mount_point, device_serial=device_serial)

            if partitions.has_key(RECOVERY):
                recovery_device = partitions[RECOVERY]
            else:
                raise BackupError

            log.info("Waiting for device in adb mode")
            self.adb.wait_for_device(device_serial)

            self.__dd_backup_partition(partition_name=RECOVERY, device=recovery_device, dest=RECOVERY_TEMP_DEV_LOC, device_serial=device_serial)
            self.__copy_backup(source_filepath=RECOVERY_TEMP_DEV_LOC, dest_filepath=ORIGINAL_RECOVERY_PATH, direction="pull", device_serial=device_serial, check_hash=True)
            self.adb.shell("rm -f %s"%(RECOVERY_TEMP_DEV_LOC), device_serial=device_serial)
            self.adb.reboot_bootloader(device_serial)
            self.fastboot.flash(partition=RECOVERY, image_path=twrp_path, device_serial=device_serial)
            self.fastboot.reboot(device_serial)
            self.adb.wait_for_device(device_serial)
            self.adb.reboot_recovery(device_serial)
            backup_path = self.__twrp_backup_partitions(switches=self.TWRP_SWITCH, device_serial=device_serial)

            backup_files = self.adb.shell("ls %s"%(backup_path),device_serial=device_serial)
            self.adb.reboot_recovery(device_serial) #needed, if not there's a bug in adb pull
            for file in backup_files.std_output:
                source_filepath = os.path.join(backup_path, file)
                dest_filepath = os.path.join(backup_dest, file)
                #self.__copy_backup(source_filepath, dest_filepath, direction="pull", twrp=True, check_hash=False, device_serial=device_serial)
                time.sleep(2)
                #self.adb.shell("rm -f %s"%(source_filepath))

            self.adb.reboot_bootloader(device_serial)
            self.fastboot.flash(partition=RECOVERY, image_path=ORIGINAL_RECOVERY_PATH, device_serial=device_serial)
            self.fastboot.reboot(device_serial)
            self.adb.wait_for_device(device_serial)
            #self.adb.shell("rm -rf %s"%(backup_path))

            log.info("Backup device successfully")
            return backup_path
        except Exception as e:
            log.error("Unable to perform partition backup")
            #self.backup(twrp_path,backup_dest, device_serial)



    def __copy_backup(self, source_filepath, dest_filepath, check_hash, direction,tries=30, twrp=False, device_serial=""):
        """
        Recursive function to backup file from device to host machine with limited retries
        :param source_filepath: source file path on device
        :param dest_filepath: destination file path on host machine
        :param tries: number of retries (default:3)
        :return: bool
        """
        try:
            if tries == 0:
                log.critical("Reach max retries")
                raise PartitionError

            if direction =="pull":
                self.adb.pull(source=source_filepath, dest=dest_filepath, device_serial=device_serial)
                time.sleep(2)
                if check_hash:
                    has_file_integrity = self.__compare_md5(source_filepath, dest_filepath, twrp, device_serial)
            elif direction == "push":
                self.adb.push(source=source_filepath, dest=dest_filepath, device_serial=device_serial)
                time.sleep(2)
                if check_hash:
                    has_file_integrity = self.__compare_md5(dest_filepath, source_filepath, twrp, device_serial)
            else:
                raise BackupError
            if check_hash:
                if not has_file_integrity :
                    log.critical("Hash of %s of copied file is different from file on device."%(source_filepath))
                    log.critical("Retrying after 10 seconds...")
                    time.sleep(10)
                    return self.__copy_backup(source_filepath, dest_filepath,check_hash,direction, tries-1, twrp, device_serial)
        except Exception as e:
            log.error("Unable to copy backup files from device to host machine")
            self.__copy_backup(source_filepath, dest_filepath, check_hash, direction,tries-1, twrp, device_serial)




    def __compare_md5(self, device_path, host_path, twrp, device_serial):
        """
        Compare the md5 of original file on device and copied file to host machine
        :param device_path:  file path on device
        :param host_path:  file path on host machine
        :return: bool
        """
        try:
            if not twrp:
                result = self.adb.shell("md5 " + device_path, device_serial)
            else:
                result = self.adb.shell("md5sum " + device_path, device_serial)

            stdout = result.std_output
            try:
                device_md5 = stdout[0].split(" ")[0]
            except IndexError:
                device_md5 = ""

            host_md5 = hashlib.md5(open(host_path).read()).hexdigest()
            log.debug("device: %s    host: %s"%(device_md5, host_md5))
            if device_md5 == host_md5:
                return True
            else:
                return False
        except Exception as e:
            log.error("Unable to compare md5")
            raise PartitionError

    def __twrp_backup_partitions(self, switches, foldername="", device_serial=""):
        try:
            command = "twrp backup %s %s"%(switches, foldername)
            result = self.adb.shell(command, device_serial=device_serial)

            backup_path = ""
            log.debug(result.std_output)
            for line in result.std_output:
                match = re.search(r'Backup Folder: .*', line)
                if match:
                    log.debug(match.group())
                    match_split = match.group().split(":")
                    backup_path = match_split[1].replace(" ", "")

            return backup_path
        except Exception as e:
            log.error("unable to perform twrp partition backup")
            self.__twrp_backup_partitions(self, switches, foldername, device_serial)




    def __get_mount_point(self,device_serial):
        """
        Get the mount point of device partition
        :return:
        """
        try:
            self.adb.wait_for_device(device_serial)
            FIRST_LINE = 0

            parameter = "mount | grep -E /dev/block/platform/.+/by-name/system"
            result = self.adb.shell(root=True, command=parameter, device_serial=device_serial)
            if result.std_error:
                raise Exception
            #remove /system from command outline
            mount_point = result.std_output[FIRST_LINE].split()[FIRST_LINE][:-6]

            return mount_point
        except Exception as e:
            log.error("cannot get device mount points")
            time.sleep(5)
            return self.__get_mount_point(device_serial)

    def __get_partitions(self, device, device_serial):
        """
        Get android device partitions
        :param device: mount path
        :return: list of dict of partition name as key and partition location as value
        """
        try:
            self.adb.wait_for_device(device_serial)
            parameter = "ls -al " + device
            result = self.adb.shell(root=True, command=parameter, device_serial=device_serial)

            if result.std_error:
                raise Exception

            partitions = {}
            for line in result.std_output:
                match = re.search(r'\w* -> .*', line)
                if match:
                    match_split = match.group().split(" -> ")
                    partitions[match_split[0]] = match_split[1]

            return partitions
        except Exception as e:
            log.error("Unable to get device partitions")
            time.sleep(5)
            return self.__get_partitions(device, device_serial)

    def __dd_backup_partition(self, partition_name, device, dest, device_serial):
        """
        backup given partition to desired destination
        :param partition_name: name of partition
        :param device: dev path of partition
        :return:
        """
        try:
            command = "dd if=%s of=%s"%(device, dest)
            result = self.adb.shell(root=True, command=command, device_serial=device_serial)

            if result.std_output:
                log.debug(result.std_output)
                return True
            else:
                log.debug(result.std_error)
                return False
        except Exception as e:
            log.error("Unable to backup partition to destination")
            raise PartitionError
Example #4
0
class SessionManager(object):
    def __init__(self):
        self.monitorManager = MonitorsManager()
        self.profileManager = ProfilesManager()
        self.adb = Adb()
        self.fastboot = Fastboot()
        self.partition = Partition()

        self.tool = Tool()
        self.session = object
        self.config_ini = config.Session()
        self.device_backup_path = ""
        self.device = Device()

    def create_session_dir(self, session_id, device_serial):
        """
        Create new session directory with given session ID
        :param session_id: session id
        :return: nil
        """
        try:
            id_path = os.path.join(SESSION_DIR, session_id.__str__())

            is_session_dir_exist = os.path.isdir(id_path)

            if is_session_dir_exist:
                raise SessionDirError

            for directory in directories:
                new_session_path = os.path.join(id_path, directory)
                os.makedirs(new_session_path)

            self.config_ini.create(id_path, device_serial)

        except Exception as e:
            log.error("Unable to create session directory")
            self.create_session_dir(session_id, device_serial)

    def save_result(self, session_id, name, result, ext=""):
        """
        save processing result into session directory
        :param session_id:
        :param name:
        :param result:
        :return:
        """
        try:
            session = Session(session_id)
            file = open(os.path.join(session.report_dir, name + ext), "w")
            file.write(result)
            file.close()

            return True
        except Exception as e:
            return False

    def get_results(self, session_id):
        """
        Get all json results from session's report directory
        :param session_id:
        :return:
        """
        reports = {}  # key: file name, value: json content
        current_session = Session(session_id)
        for file in os.listdir(current_session.report_dir):
            if file.endswith(".json"):
                with open(os.path.join(current_session.report_dir, file)) as data_file:
                    reports[file.split(".")[0].replace("_", " ")] = json.load(data_file)

        return reports

    def end(self, session_id, device_backup_path, modules_config, device_serial):
        """
        End sandbox analysis
        :param session_id:
        :return:
        """
        self.session = Session(session_id)

        log_name = "end_status_%s" % session_id
        end_logger = logging.getLogger(log_name)
        end_logger.setLevel(logging.INFO)
        START_LOG = os.path.join(self.session.logs_dir, "end_status.log")
        fh = logging.FileHandler(START_LOG)
        fh.setLevel(logging.INFO)
        formatter = logging.Formatter("%(asctime)s - %(message)s")
        fh.setFormatter(formatter)
        end_logger.addHandler(fh)

        # get post-session monitor required data from device
        end_logger.info("Post-session information gathering")
        if modules_config:
            for module, params in modules_config.iteritems():
                if params["module_type"] == "monitor":
                    end_result = self.monitorManager.postSession(
                        module, params, self.session, device_serial=device_serial
                    )
                    log_file = os.path.join(self.session.logs_dir, module.replace(" ", "_") + ".post" + ".cap")
                    file_handler = open(log_file, "w+")
                    file_handler.write(end_result.__str__())
                    file_handler.close()

        # restore partitions
        end_logger.info("Restoring boot partition")
        self.restore_boot_partition(self.session, device_serial)
        end_logger.info("Restoring other partitions")
        self.partition.restore(
            twrp_path=self.tool.twrp,
            backup_src=self.session.partition_dir,
            backup_dest=device_backup_path,
            device_serial=device_serial,
        )

        return True

    def start_logger(self, session_id):
        # initilize status logging
        log_name = "start_status_%s" % session_id
        self.start_logger = logging.getLogger(log_name)
        self.start_logger.setLevel(logging.INFO)
        self.START_LOG = os.path.join(self.session.logs_dir, "status.log")
        fh = logging.FileHandler(self.START_LOG)
        fh.setLevel(logging.INFO)
        formatter = logging.Formatter("%(asctime)s - %(message)s")
        fh.setFormatter(formatter)
        self.start_logger.addHandler(fh)

    def start(self, modules_config, session_id, apk_paths, duration, device_serial):
        """
        Begin sandbox analysis.
        :param modules_config: parameters selected from configuration page
        :type modules_config: dictionary. configuration of modules from django session database
        :return: if analysis is successful or not
        """

        # create session directory
        self.create_session_dir(session_id, device_serial)
        # session object
        self.session = Session(session_id)

        self.start_logger(session_id)

        # checking device temp folders are ready
        self.start_logger.info("Initilizing device %s", device_serial)
        self.start_logger.info("Checking device temp folders are ready")
        self.check_device_tmp_folders(device_serial)

        # create symbolic link for apks
        self.start_logger.info("Creating symbolic links for APKs")
        self.create_apk_symbolic_links(apk_paths)
        # backup device partitions
        self.start_logger.info("Backing up partitions")
        device_backup_path = self.backup_device_partitions(device_serial)

        # prepare device for session (haven't copy to device yet)
        self.start_logger.info("Preparing device partitions")
        is_partition_init = self.prepare_device_for_session(device_serial, modules_config)

        # install user profile
        self.start_logger.info("Installing user profile")
        self.install_user_profile(device_serial, modules_config)

        # copy daemons to device
        self.start_logger.info("Copying daemons onto device")
        self.copy_daemons_to_device(device_serial, modules_config)

        # push modified partition to device
        self.start_logger.info("Pushing modified partitions to device")
        self.push_modified_partition_to_device(device_serial, is_partition_init)

        # get baseline of the device (pre session)
        # depending on the monitor modules requirements
        self.start_logger.info("Pre-session initilizations")
        self.device_presession(device_serial, modules_config)

        # lastly, install the suspicious apk
        self.start_logger.info("Installing APK on device")
        package_name = self.install_apk(device_serial)
        while not package_name:
            package_name = self.install_apk(device_serial)

        # whitelist package name for monitoring
        self.whitelist_package_name(package_name, device_serial)

        # run profile simulation script
        self.start_logger.info("package name is %s" % package_name)
        self.start_logger.info("Running profile simulation")

        now = datetime.datetime.now()
        end_time = now + datetime.timedelta(minutes=duration)
        end_time_str = end_time.strftime("%H:%M:%S %d-%m-%Y")
        self.run_profile_simulation(duration, modules_config, device_serial, package_name, self.session)
        self.start_logger.info("Session end time:  %s" % end_time_str)

        return (device_backup_path, self.START_LOG, end_time)

    def whitelist_package_name(self, package_name, device_serial):
        tmp_path = self.device.daemon_path(device_serial)
        whitelist_path = os.path.join(tmp_path, "whitelist.txt")
        add_whitelist_command = 'echo "%s" > %s' % (package_name, whitelist_path)
        result = self.adb.shell(add_whitelist_command, root=True, device_serial=device_serial)

    def check_device_tmp_folders(self, device_serial):
        """
        Check android device for the temp folders declared in devices.ini
        :param device_serial: device serial no.
        :return: boolean result
        """
        try:
            device_backup_path = self.device.backup_path(device_serial)
            device_daemon_path = self.device.daemon_path(device_serial)

            paths = [device_backup_path, device_daemon_path]
            for path in paths:
                check_path_command = "ls %s" % path
                result = self.adb.shell(check_path_command, device_serial=device_serial, root=True)
                if not result.std_output:
                    log.error(
                        "device %s is not ready for DroidPot! Ensure all tmp folders declared in devices.ini are present on the device"
                    )
                    return False

            return True
        except Exception as e:
            log.error(
                "device %s is not ready for DroidPot! Ensure all tmp folders declared in devices.ini are present on the device"
            )
            return False

    def run_profile_simulation(self, duration, modules_config, device_serial, package_name, session):
        # try:
        log.info("Running user simulation")
        if modules_config:
            for modules, params in modules_config.iteritems():
                try:
                    if params["module_type"] == "profile":
                        simulation_option = params["simulation_option"]
                        p = Process(
                            target=run_simulation,
                            args=(simulation_option, modules, duration, device_serial, package_name, session),
                        )
                        p.start()
                        break  # break in case there's more than 1 profile selected
                except KeyError as e:
                    pass
        # except Exception as e:
        # log.error("Unable to run profile simulation")
        # time.sleep(10)
        # self.run_profile_simulation(duration, modules_config,device_serial, package_name, session)

    def install_apk(self, device_serial):
        try:
            log.info("Installing sample apk")
            self.adb.wait_for_device(device_serial)
            apks = os.listdir(self.session.apk_dir)
            for apk in apks:
                apk_path = os.path.join(self.session.apk_dir, apk)
                if os.path.isfile(apk_path):
                    log.info("Installing apk %s" % (apk_path))

                    get_current_packages_command = "pm list packages"
                    result = self.adb.shell(get_current_packages_command, root=True, device_serial=device_serial)
                    packages = result.std_output

                    apk_realpath = os.path.realpath(apk_path)
                    self.adb.push(source=apk_realpath, dest="/sdcard/tmp.apk", device_serial=device_serial)
                    time.sleep(2)
                    self.adb.shell("pm install -rt /sdcard/tmp.apk", root=True, device_serial=device_serial)
                    time.sleep(2)
                    self.adb.shell("rm -f /sdcard/tmp.apk", root=True, device_serial=device_serial)
                    # os.remove(apk_path)

                    result = self.adb.shell(get_current_packages_command, root=True, device_serial=device_serial)
                    packages_after = result.std_output
                    sample_package_name = ""
                    for package in packages_after:
                        if not packages.__contains__(package):
                            sample_package_name = package.replace("package:", "")

                    return sample_package_name
                    # break

                    # Note: ONLY 1 APK TO BE ANALYSIS AT A TIME. AFTER ANALYSIS SESSION, INSTALL THE NEXT APK
        except Exception as e:
            log.error("Unable to install APK onto device")
            print e
            time.sleep(10)
            return ""

    def device_presession(self, device_serial, modules_config):
        try:
            log.info("Getting device baseline")
            self.adb.wait_for_device(device_serial)
            time.sleep(10)
            if modules_config:
                for module, params in modules_config.iteritems():
                    if params["module_type"] == "monitor":
                        baseline = self.monitorManager.preSession(module, params, self.session, device_serial)

                        print "baseline file result is "
                        print baseline

                        # store baseline information into an analysis file
                        log_file = os.path.join(self.session.logs_dir, module.replace(" ", "_") + ".pre" + ".cap")

                        file_handler = open(log_file, "w+")
                        file_handler.write(baseline.__str__())
                        file_handler.close()
        except Exception as e:
            log.error("Unable to get baseline of device")
            time.sleep(10)
            self.device_presession(device_serial, modules_config)

    def push_modified_partition_to_device(self, device_serial, is_partition_init):
        try:
            log.info("Modifying device's partitions")
            if is_partition_init:
                self.push_boot_partition(self.session, device_serial=device_serial)
        except Exception as e:
            log.error("Unable to push modified partition to device")
            time.sleep(10)
            self.push_modified_partition_to_device(device_serial, is_partition_init)

    def copy_daemons_to_device(self, device_serial, modules_config):
        try:
            log.info("Transferring daemons to device")
            if modules_config:
                for module, params in modules_config.iteritems():
                    # copy each module's daemons individually into device

                    if params["module_type"] == "monitor":
                        daemon = self.monitorManager.daemons(module, params)
                        if daemon:
                            self.copy_daemons(daemon, self.session)
                            # check device ini for temp path preference
                            dev_daemon_path = self.device.daemon_path(device_serial)
                            self.push_daemons(self.session, dev_daemon_path, device_serial=device_serial)

        except Exception as e:
            log.error("Unable to install process monitors on device")
            time.sleep(10)
            self.copy_daemons_to_device(device_serial, modules_config)

    def install_user_profile(self, device_serial, modules_config):
        try:
            log.info("Installing profile on device")
            self.adb.wait_for_device(device_serial)
            if modules_config:
                for module, params in modules_config.iteritems():
                    if params["module_type"] == "profile":
                        self.profileManager.setup_device(module, params, device_serial)
                        break
        except Exception as e:
            log.error("Unable to install user profile onto device")
            time.sleep(10)
            self.install_user_profile(device_serial, modules_config)

    def prepare_device_for_session(self, device_serial, modules_config):
        try:
            is_partition_init = self.monitorManager.prepare(modules_config, self.session, device_serial)
        except Exception as e:
            log.error("Unable to prepare partitions for session")
            time.sleep(10)
            return self.prepare_device_for_session(device_serial, modules_config)

        return is_partition_init

    def backup_device_partitions(self, device_serial):
        try:
            log.info("Backing up device partitions")
            self.start_logger.info("Performing TWRP backup")
            device_backup_path = self.partition.backup(
                twrp_path=self.tool.twrp, backup_dest=self.session.partition_dir, device_serial=device_serial
            )

            if device_backup_path:
                log.debug("Backup completed, extracting boot partition for modification")

                time.sleep(3)
                self.device_backup_path = device_backup_path
                is_boot_extracted = self.get_and_extract_boot_partition(self.session, device_serial=device_serial)
                while not is_boot_extracted:
                    time.sleep(3)
                    is_boot_extracted = self.get_and_extract_boot_partition(self.session, device_serial=device_serial)
        except Exception as e:
            log.error("Unable to perform backup")
            time.sleep(2)
            return self.backup_device_partitions(device_serial)

        return device_backup_path

    def create_apk_symbolic_links(self, apk_paths):
        try:
            log.info("Creating symbolic links for APKs")
            for apk_name, apk_realpath in apk_paths.iteritems():
                os.symlink(apk_realpath, os.path.join(self.session.apk_dir, apk_name))
        except Exception as e:
            log.error("Unable to create symbolic link for apks")
            time.sleep(10)
            self.create_apk_symbolic_links(apk_paths)

    def get_baseline(self, device_serial):
        """
        Get the device baseline processes
        """
        process_names = []

        list_proc_command = "ls /proc/"
        output = self.adb.shell(list_proc_command, root=True, needOutput=True, device_serial=device_serial)
        processes = output.std_output

        commands = ""
        for proc in processes:
            get_proc_name_command = "cat /proc/%s/status" % (proc)

            commands += get_proc_name_command + " && "

        proc_name = self.adb.shell(commands, root=True, needOutput=True, device_serial=device_serial).std_output
        if proc_name:
            process_names.append(proc_name)

        return process_names

    """
    DAEMON HANDLER
    handles the copying daemons into session directory and pushing daemons to android device
    """

    def copy_daemons(self, daemons, session):
        daemon_dir = session.daemon_dir

        for module_name, daemons_path in daemons.iteritems():
            log.debug("found %s in module %s" % (daemons_path, module_name))

            for d_path in daemons_path:
                shutil.copy(d_path, daemon_dir)
        return True

    def push_daemons(self, session, dir, device_serial):
        daemon_dir = session.daemon_dir

        for daemon in os.listdir(daemon_dir):
            log.info("[*] Pushing %s to device" % daemon)
            log.debug("pushing %s to device %s directory" % (daemon, dir))
            source = os.path.join(daemon_dir, daemon)

            self.adb.push(source=source, dest=dir, device_serial=device_serial)

            log.info("[*] Changing permission of daemons")
            device_daemon_path = os.path.join(dir, daemon)
            chmod_command = "chmod 777 %s" % device_daemon_path
            chown_command = "chown root:root %s" % device_daemon_path
            self.adb.shell(chown_command, root=True, device_serial=device_serial)
            self.adb.shell(chmod_command, root=True, device_serial=device_serial)

        return True

    """
    PARTITION HANDLER
    handles the partition extraction and reflashing of android device
    """

    def get_and_extract_boot_partition(self, session, device_serial):
        self.start_logger.info("Extracting boot partition for modification")
        EXTRACTED_BOOT_LOC = "/sdcard/boot.img"

        # retrieve boot partition location
        retry = True
        while retry:
            log.warn("[*] Retrieving boot partition location...")
            command = "ls -al /dev/block/platform/msm_sdcc.1/by-name | grep ' boot'"
            result = self.adb.shell(command=command, device_serial=device_serial)

            boot_image_loc = ""

            for output in result.std_output:
                log.debug("result line: %s" % output)
                try:
                    output_split = output.split("-> ")
                    boot_image_loc = output_split[1]
                    boot_image_loc.replace("\r", "")
                    retry = False
                except IndexError:
                    log.debug("Cannot get boot partition location. Retrying.")
                    time.sleep(3)
                    pass

        time.sleep(5)

        # copy image locally
        log.info("[*] dd image on device...")
        command = "dd if=" + boot_image_loc + " of=" + EXTRACTED_BOOT_LOC
        result = self.adb.shell(root=True, command=command, device_serial=device_serial)

        if not result.isSuccess:
            raise OSError

        time.sleep(5)

        # pulling boot.img from device
        log.info("[*] Pulling boot.img from device...")
        self.adb.pull(source=EXTRACTED_BOOT_LOC, dest=session.partition_dir, device_serial=device_serial)

        time.sleep(5)

        # decompress boot.img
        log.info("[*] Decompressing boot.img with mkboot tool...")
        params = " ".join([session.bootimg_dir, session.extracted_boot_dir])

        log.debug("parameters are %s" % params)
        cmd = Command()
        cmd.setCommand(self.tool.mkboot)
        cmd.setParameters(params)
        logging.debug(params)
        cmd.execute()

        time.sleep(5)

        if not os.path.exists(session.extracted_boot_dir):
            self.start_logger.info("Extracting boot partition failed")
            return False
        else:
            return True

    def push_boot_partition(self, session, device_serial):
        # create new boot.img
        logging.debug("creating new boot partition")
        params = " ".join([session.extracted_boot_dir, session.new_bootimg_dir])
        cmd = Command()
        cmd.setCommand(self.tool.mkboot)
        cmd.setParameters(params)
        logging.debug(params)
        cmd.execute()

        time.sleep(5)

        # push new partition to device
        self.adb.reboot_bootloader(device_serial)
        time.sleep(5)

        fastboot_devices = self.fastboot.devices()
        for i in range(0, 5):
            if len(fastboot_devices) > 0:
                log.info("[*] Device found in bootloader mode")
                break
            else:
                log.info("[!] Could not detect device in bootloader mode. Retrying...")
                time.sleep(10)
                fastboot_devices = self.fastboot.devices()

            if i == 4:
                log.warning("[!] Could not detect device in bootloader mode. TIME OUT")
                return False

        # flash boot partition with fastboot
        # must be in sudo
        log.info("[*] Flashing partition with new image")

        self.fastboot.flash(partition="boot", image_path=session.new_bootimg_dir, device_serial=device_serial)

        time.sleep(5)
        self.fastboot.reboot(device_serial)

    def restore_boot_partition(self, session, device_serial):
        log.info("[*] Restoring boot partition...")
        self.adb.wait_for_device(device_serial)
        self.adb.reboot_bootloader(device_serial)

        while True:
            devices = self.fastboot.devices()
            if devices:
                break

        self.fastboot.flash("boot", session.bootimg_dir, device_serial=device_serial)
        self.fastboot.reboot(device_serial)
Example #5
0
class adb_testcase(unittest.TestCase):
    def setUp(self):
        self.adb_c = Adb()
        self.adb_c.start_server()

    def tearDown(self):
        #self.adb_c.kill_server()
        pass

    #@unittest.skip("skipping test device")
    def test_devices(self):
        devices = self.adb_c.devices()

        #print devices
        result = True
        if len(devices) == 0:
            result = False

        self.assertTrue(result, msg="No device detected")


    def test_push_file(self):
        path = os.path.dirname(os.path.realpath(__file__))

        src = os.path.join(path, TEST_FILE)
        dest = os.path.join(SDCARD_PATH, TEST_FILE)

        isSuccessful = self.adb_c.push(source=src, dest=dest)
        self.assertTrue(isSuccessful, msg="adb push not successful")

    def test_pull_file(self):
        path = os.path.dirname(os.path.realpath(__file__))

        src = os.path.join(SDCARD_PATH, TEST_FILE)
        dest = os.path.join(path, "extract.txt")

        isSuccessful = self.adb_c.pull(source=src, dest=dest)
        self.assertTrue(isSuccessful, msg="adb pull not successful")

        os.remove(dest)

    def test_shell_no_root(self):
        parameters = "ps"
        result = self.adb_c.shell(command=parameters)

        self.assertTrue(result.isSuccess, msg="adb shell ps not successful")
        print result.std_output

    def test_shell_with_root(self):
        parameters = "strace -p 1"
        result = self.adb_c.shell(needOutput=False, root=True, command=parameters)

        self.assertTrue(result.isSuccess, msg="adb shell with root not successful")
        self.adb_c.reboot()

        sleep(5)
        while len(self.adb_c.devices()) == 0:
            print("waiting for device to reboot...")
            sleep(10)


    @unittest.skip("skipping reboot test")
    def test_reboot_commands(self):
        """
        reboot command testcase should be the last
        :return:
        """
        self.adb_c.reboot()
        print("device rebooting... Please wait...")
        sleep(3)
        devices = self.adb_c.devices()

        foundDevice = False
        if devices:
            foundDevice = True

        self.assertFalse(foundDevice, msg="adb reboot not successful")