Esempio n. 1
0
def main(input=None, debug_mode=False, quiet_mode=False):
    # TODO: print program information.

    if not input:
        argument_parser = argparse.ArgumentParser(description='Android Basic Apps Parser.')
        argument_parser.add_argument('-i', '--input_path', required=True, action='store',
                                     help='Path to input file/directory')
        argument_parser.add_argument('-o', '--output_path', required=True, action='store', help='Output path')
        argument_parser.add_argument('-d', '--debug', default=False, action='store', help='set debug mode')
        argument_parser.add_argument('-q', '--quiet', default=False, action='store', help='set quiet mode')

        args = argument_parser.parse_args()

        input_path = args.input_path
        output_path = os.path.abspath(args.output_path)
        _debug_mode = args.debug
        _quiet_mode = args.quiet
    else:
        input_path = input
        output_path = input
        _debug_mode = debug_mode
        _quiet_mode = quiet_mode

    if len(input_path) == 0:
        print('invalid input file or directory.')
        return

    if len(output_path) == 0:
        print('invalid output file or directory.')
        return

    # set output directory and logfile
    local_date_time = datetime.datetime.now()
    _result_path = '{0:s}AB2A_Results-{1:04d}{2:02d}{3:02d}T{4:02d}{5:02d}{6:02d}'.format(
        output_path + os.sep, local_date_time.year, local_date_time.month,
        local_date_time.day, local_date_time.hour, local_date_time.minute,
        local_date_time.second)

    _log_file = '{0:s}{1:s}-{2:04d}{3:02d}{4:02d}T{5:02d}{6:02d}{7:02d}.log.gz'.format(
        _result_path, os.sep + 'AB2A', local_date_time.year, local_date_time.month,
        local_date_time.day, local_date_time.hour, local_date_time.minute,
        local_date_time.second)

    loggers.ConfigureLogging(debug_output=_debug_mode, filename=_log_file,
                             quiet_mode=_quiet_mode)

    results = []
    for key, val in SUPPORTED_BASIC_APPS.items():
        search_results = search(input_path, val[0])
        if not search_results:
            if not os.path.exists(_result_path):
                os.mkdir(_result_path)
            logger.info(f'No results: {key}:{val[0]}')
        else:
            result = process(search_results, val[1], _result_path)
            if result:
                for ret in result:
                    results.append(ret)

    return results
Esempio n. 2
0
def parse_sim_info(target_files, result_path):
    """Parse SIM information databases.

    Args:
        target_files (list): target files.
        result_path (str): result path.
    """

    logger.info('Parse SIM information databases.')

    results = []
    for file in target_files:
        if str(file).endswith('telephony.db'):
            database = sqlite3.connect(str(file))
            database.row_factory = sqlite3.Row

            result = _parse_sim_info(database, result_path)
            if result:
                results.append(result)
        elif str(file).endswith('SimCard.dat'):
            result = _parse_simcard_dat(str(file), result_path)
            if result:
                results.append(result)

    return results
Esempio n. 3
0
def parse_system_info(target_files, result_path):
    """Parse system info databases.

    Args:
        target_files (list): target files.
        result_path (str): result path.
    """

    logger.info('Parse system information databases.')

    results = []
    for file in target_files:
        if str(file).endswith('settings_secure.xml'):
            result = _parse_system_info(str(file), result_path)
            if result:
                results.append(result)

    return results
Esempio n. 4
0
def parse_wifi(target_files, result_path):
    """Parse Wi-Fi profile xml file.

    Args:
        target_files (list): target files.
        result_path (str): result path.
    """

    logger.info('Parse Wi-Fi profile XML file.')

    results = []
    for file in target_files:
        if str(file).endswith('WifiConfigStore.xml'):
            result = _parse_wifi(str(file), result_path)
            if result:
                results.append(result)

    return results
Esempio n. 5
0
def parse_usagestats(target_files, result_path):
    """Parse android usagestats.

    Args:
        target_files (list): target files.
        result_path (str): result path.
    """


    logger.info('Parse usagestats')

    results = []
    for file in target_files:
        if os.path.dirname(str(file)).endswith('usagestats'):
            uid = str(file).split(os.sep)[-1]
            result = _parse_usagestats(str(file), uid, result_path)
            if result:
                results.append(result)

    return results
Esempio n. 6
0
def parse_file_cache(target_files, result_path):
    """Parse file cache databases.

    Args:
        target_files (list): target files.
        result_path (str): result path.
    """

    logger.info('Parse file cache databases.')

    results = []
    for file in target_files:
        if str(file).endswith('FileCache.db'):
            database = sqlite3.connect(str(file))
            database.row_factory = sqlite3.Row

            result = _parse_file_cache(database, result_path)
            if result:
                results.append(result)

    return results
Esempio n. 7
0
def parse_user_dict(target_files, result_path):
    """Parse user_dict databases.

    Args:
        target_files (list): target files.
        result_path (str): result path.
    """

    logger.info('Parse User Dictionary databases.')

    results = []
    for file in target_files:
        if str(file).endswith('user_dict.db'):
            database = sqlite3.connect(str(file))
            database.row_factory = sqlite3.Row

            result = _parse_user_dict(database, result_path)
            if result:
                results.append(result)

    return results
Esempio n. 8
0
def parse_accounts_de(target_files, result_path):
    """Parse accounts_de databases.

    Args:
        target_files (list): target files.
        result_path (str): result path.
    """

    logger.info('Parse accounts_de databases.')

    results = []
    for file in target_files:
        if str(file).endswith('accounts_de.db'):
            uid = str(file).split(os.sep)[-2]
            database = sqlite3.connect(str(file))
            database.row_factory = sqlite3.Row

            result = _parse_accounts_de(database, uid, result_path)
            if result:
                results.append(result)

    return results
Esempio n. 9
0
def parse_smsmms(target_files, result_path):
    """Parse SMS and MMS databases.

    Args:
        target_files (list): target files.
        result_path (str): result path.
    """
    logger.info('Parse SMS and MMS databases.')
    results = []
    for file in target_files:
        if str(file).endswith('mmssms.db'):
            database = sqlite3.connect(str(file))
            database.row_factory = sqlite3.Row

            sms_data = _parse_sms(database, result_path)
            if sms_data:
                results.append(sms_data)

            mms_data = _parse_mms(database, result_path)
            if mms_data:
                results.append(mms_data)

    return results
Esempio n. 10
0
def _parse_mms(database, result_path):
    """Parse MMS messages.

    Args:
        database (SQLite3): target SQLite3 database.
        result_path (str): result path.
    """
    parent_path = pathlib.Path(result_path)
    parent_path = parent_path.parent

    cursor = database.cursor()
    cursor.execute(mms_query)
    results = cursor.fetchall()
    num_of_results = len(results)

    data = {}
    data['title'] = 'mms'
    header = ('mms_id', 'thread_id', 'date', 'date_sent', 'read', 'from', 'to',
              'cc', 'bcc', 'body')
    data['number_of_data_headers'] = len(header)
    data['number_of_data'] = num_of_results
    data['data_header'] = header
    data_list = []

    if num_of_results > 0:
        for row in results:
            if row['date_sent'] != 0:
                msg = MmsMessage(
                    row['mms_id'], row['thread_id'],
                    datetime.datetime.fromtimestamp(
                        row['date'], datetime.timezone.utc).strftime(
                            '%Y-%m-%dT%H:%M:%S.%fZ'),
                    datetime.datetime.fromtimestamp(
                        float(row['date_sent']) / 1000,
                        datetime.timezone.utc).strftime(
                            '%Y-%m-%dT%H:%M:%S.%fZ'), row['read'], row['FROM'],
                    row['TO'], row['CC'], row['BCC'], row['msg_box'],
                    row['part_id'], row['seq'], row['ct'], row['cl'],
                    row['_data'], row['text'])
            else:
                msg = MmsMessage(
                    row['mms_id'], row['thread_id'],
                    datetime.datetime.fromtimestamp(
                        row['date'], datetime.timezone.utc).strftime(
                            '%Y-%m-%dT%H:%M:%S.%fZ'), '', row['read'],
                    row['FROM'], row['TO'], row['CC'], row['BCC'],
                    row['msg_box'], row['part_id'], row['seq'], row['ct'],
                    row['cl'], row['_data'], row['text'])

            if row['_data'] == None:
                msg.body = row['text']
            else:
                #TODO: attachment is existed!
                result = _search(
                    parent_path,
                    '**' + os.sep + os.path.basename(row['_data']))
                if result:
                    msg.filename = str(result[0])
                    msg.body = msg.filename
                else:
                    logger.info('Attachment file is not found!'.format(
                        row['_data']))

            temp = (msg.mms_id, msg.thread_id, msg.date, msg.date_sent,
                    msg.read, msg.From, msg.to, msg.cc, msg.bcc, msg.body)
            data_list.append(temp)
        data['data'] = data_list

    return data
Esempio n. 11
0
def _parse_usagestats(directory, uid, result_path):
    """Parse usagestats from /system/usagestats.

    Args:
        directory (str): target direcotry path.
        uid (str): user id.
        result_path (str): result path.
    """
    data = {}
    data['title'] = 'usagestats' + f'_{uid}'
    header = ('usage_type', 'last_time_active', 'time_active_in_msecs', 'time_active_in_secs',
              'last_time_service_used', 'last_time_visible', 'total_time_visible', 'app_launch_count',
              'package', 'types', 'class', 'source', 'all_attributes')
    data['number_of_data_headers'] = len(header)
    data['data_header'] = header
    data_list = []

    for file in glob.iglob(os.path.join(directory, '**'), recursive=True):
        if os.path.isfile(file):
            source = None
            filename = os.path.basename(file)

            if os.path.dirname(file).endswith('daily'):
                source = 'daily'
            elif os.path.dirname(file).endswith('weekly'):
                source = 'weekly'
            elif os.path.dirname(file).endswith('monthly'):
                source = 'monthly'
            elif os.path.dirname(file).endswith('yearly'):
                source = 'yearly'

            try:
                filename_int = int(filename)
            except:
                logger.error('Invalid File Name: {0:s}'.format(filename))

            try:
                tree = xml.etree.ElementTree.parse(file)
                root = tree.getroot()
                logger.info('processing: {0:s}'.format(file))
                for elem in root:
                    if elem.tag == 'packages':
                        usagestat = UsageStats()
                        usagestat.source = source
                        usagestat.usage_type = elem.tag
                        for subelem in elem:
                            usagestat.all_attributes = json.dumps(subelem.attrib)
                            last_time_active = int(subelem.attrib['lastTimeActive'])
                            if last_time_active < 0:
                                usagestat.last_time_active = abs(last_time_active)
                            else:
                                usagestat.last_time_active = filename_int + last_time_active

                            usagestat.last_time_active = datetime.datetime.fromtimestamp(usagestat.last_time_active / 1000,
                                 datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ')

                            usagestat.package = subelem.attrib['package']
                            usagestat.time_active_in_msecs = subelem.attrib['timeActive']
                            usagestat.time_active_in_secs = int(usagestat.time_active_in_msecs) / 1000
                            usagestat.app_launch_count = subelem.attrib.get('appLaunchCount', None)

                            data_list.append(
                                (usagestat.usage_type, usagestat.last_time_active, usagestat.time_active_in_msecs,
                                 usagestat.time_active_in_secs, usagestat.last_time_service_used,
                                 usagestat.last_time_visible,
                                 usagestat.total_time_visible, usagestat.app_launch_count, usagestat.package,
                                 usagestat.types, usagestat.cls, usagestat.source, usagestat.all_attributes))

                    elif elem.tag == 'configurations':
                        usagestat = UsageStats()
                        usagestat.source = source
                        usagestat.usage_type = elem.tag
                        for subelem in elem:
                            usagestat.all_attributes = json.dumps(subelem.attrib)
                            last_time_active = int(subelem.attrib['lastTimeActive'])
                            if last_time_active < 0:
                                usagestat.last_time_active = abs(last_time_active)
                            else:
                                usagestat.last_time_active = filename_int + last_time_active

                            usagestat.last_time_active = datetime.datetime.fromtimestamp(usagestat.last_time_active / 1000,
                                 datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ')

                            usagestat.time_active_in_msecs = subelem.attrib['timeActive']
                            usagestat.time_active_in_secs = int(usagestat.time_active_in_msecs) / 1000

                            data_list.append(
                                (usagestat.usage_type, usagestat.last_time_active, usagestat.time_active_in_msecs,
                                 usagestat.time_active_in_secs, usagestat.last_time_service_used,
                                 usagestat.last_time_visible,
                                 usagestat.total_time_visible, usagestat.app_launch_count, usagestat.package,
                                 usagestat.types, usagestat.cls, usagestat.source, usagestat.all_attributes))

                    elif elem.tag == 'event-log':
                        usagestat = UsageStats()
                        usagestat.source = source
                        usagestat.usage_type = elem.tag
                        for subelem in elem:
                            usagestat.all_attributes = json.dumps(subelem.attrib)
                            time = int(subelem.attrib['time'])
                            if time < 0:
                                usagestat.last_time_active = abs(time)
                            else:
                                usagestat.last_time_active = filename_int + time

                            usagestat.last_time_active = datetime.datetime.fromtimestamp(usagestat.last_time_active / 1000,
                                 datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ')

                            usagestat.package = subelem.attrib['package']
                            usagestat.types = str(EventType(int(subelem.attrib['type'])))
                            usagestat.cls =  subelem.attrib.get('class', None)

                            data_list.append((usagestat.usage_type, usagestat.last_time_active, usagestat.time_active_in_msecs,
                                    usagestat.time_active_in_secs, usagestat.last_time_service_used, usagestat.last_time_visible,
                                    usagestat.total_time_visible, usagestat.app_launch_count, usagestat.package,
                                    usagestat.types, usagestat.cls, usagestat.source, usagestat.all_attributes))


            except xml.etree.ElementTree.ParseError:
                # Perhaps an Android Q protobuf file
                try:
                    stats = _ReadUsageStatsPbFile(file)
                except:
                    logger.error('Parse Error: Non XML file and Non Protobuf file: {0:s}'.format(file))
                    continue

                if stats:
                    for stat in stats.packages:
                        usagestat = UsageStats()
                        usagestat.source = source
                        usagestat.usage_type = 'packages'
                        if stat.HasField('last_time_active_ms'):
                            last_time_active = stat.last_time_active_ms
                            if last_time_active < 0:
                                usagestat.last_time_active = abs(last_time_active)
                            else:
                                usagestat.last_time_active = filename_int + last_time_active

                            usagestat.last_time_active = datetime.datetime.fromtimestamp(usagestat.last_time_active / 1000,
                                datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ')

                        if stat.HasField('total_time_active_ms'):
                            usagestat.time_active_in_msecs = abs(stat.total_time_active_ms)

                        usagestat.package = stats.stringpool.strings[usagestat.package_index - 1]

                        if stat.HasField('app_launch_count'):
                            usagestat.app_launch_count = abs(stat.app_launch_count)

                        data_list.append(
                            (usagestat.usage_type, usagestat.last_time_active, usagestat.time_active_in_msecs,
                             usagestat.time_active_in_secs, usagestat.last_time_service_used,
                             usagestat.last_time_visible,
                             usagestat.total_time_visible, usagestat.app_launch_count, usagestat.package,
                             usagestat.types, usagestat.cls, usagestat.source, usagestat.all_attributes))

                    for stat in stats.configurations:
                        usagestat = UsageStats()
                        usagestat.source = source
                        usagestat.usage_type = 'configurations'
                        if stat.HasField('last_time_active_ms'):
                            last_time_active = stat.last_time_active_ms
                            if last_time_active < 0:
                                usagestat.last_time_active = abs(last_time_active)
                            else:
                                usagestat.last_time_active = filename_int + last_time_active

                                usagestat.last_time_active = datetime.datetime.fromtimestamp(usagestat.last_time_active / 1000,
                                    datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ')

                        if stat.HasField('total_time_active_ms'):
                            usagestat.time_active_in_msecs = abs(stat.total_time_active_ms)

                        usagestat.all_attributes = str(stat.config)

                        data_list.append(
                            (usagestat.usage_type, usagestat.last_time_active, usagestat.time_active_in_msecs,
                             usagestat.time_active_in_secs, usagestat.last_time_service_used,
                             usagestat.last_time_visible,
                             usagestat.total_time_visible, usagestat.app_launch_count, usagestat.package,
                             usagestat.types, usagestat.cls, usagestat.source, usagestat.all_attributes))

                    for stat in stats.event_log:
                        if stat.HasField('time_ms'):
                            last_time_active = stat.time_ms
                            if last_time_active < 0:
                                usagestat.last_time_active = abs(last_time_active)
                            else:
                                usagestat.last_time_active = filename_int + last_time_active

                            usagestat.last_time_active = datetime.datetime.fromtimestamp(usagestat.last_time_active / 1000,
                                datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ')

                        if stat.HasField('package_index'):
                            usagestat.package = stats.stringpool.strings[stat.package_index - 1]
                        if stat.HasField('package_index'):
                            usagestat.cls = stats.stringpool.strings[stat.class_index - 1]
                        if stat.HasField('type'):
                            usagestat.types = str(EventType(stat.type)) if stat.type <= 18 else str(stat.type)

                        data_list.append(
                            (usagestat.usage_type, usagestat.last_time_active, usagestat.time_active_in_msecs,
                             usagestat.time_active_in_secs, usagestat.last_time_service_used,
                             usagestat.last_time_visible,
                             usagestat.total_time_visible, usagestat.app_launch_count, usagestat.package,
                             usagestat.types, usagestat.cls, usagestat.source, usagestat.all_attributes))

                    continue

    data['number_of_data'] = len(data_list)
    data['data'] = data_list

    return data