def analyze(self, dataSource, fileManager, context): try: contact_and_message_dbs = AppSQLiteDB.findAppDatabases( dataSource, "naver_line", True, self._LINE_PACKAGE_NAME) calllog_dbs = AppSQLiteDB.findAppDatabases(dataSource, "call_history", True, self._LINE_PACKAGE_NAME) for contact_and_message_db in contact_and_message_dbs: current_case = Case.getCurrentCaseThrows() helper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, contact_and_message_db.getDBFile(), Account.Type.LINE) self.parse_contacts(contact_and_message_db, helper) self.parse_messages(contact_and_message_db, helper) for calllog_db in calllog_dbs: current_case = Case.getCurrentCaseThrows() helper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, calllog_db.getDBFile(), Account.Type.LINE) self.parse_calllogs(dataSource, calllog_db, helper) except NoCurrentCaseException as ex: # Error parsing Line databases. self._logger.log(Level.WARNING, "Error parsing the Line App Databases", ex) self._logger.log(Level.WARNING, traceback.format_exc()) for contact_and_message_db in contact_and_message_dbs: contact_and_message_db.close() for calllog_db in calllog_dbs: calllog_db.close()
def process(self, data_source, progress_bar): """Where the analysis is done Args: data_source (Content): autopsy case data source progressBar (DataSourceIngestModuleProgress): progress bar related to this analysis """ progress_bar.switchToIndeterminate() self.log(Level.INFO, "GBoard Data Source Ingest Module is analysing...") try: current_case = Case.getCurrentCaseThrows() services = current_case.getServices() blackboard = services.getBlackboard() file_manager = services.getFileManager() input_dir = self.get_input_dir(data_source, file_manager) # Run GBoard analysis tool analysis_output = self.run_analyzer(input_dir) # Report analysis to Autopsy Blackboard self.report_analysis(input_dir, data_source, blackboard, file_manager, analysis_output) # Report clipboard analysis to Autopsy Blackboard # TODO: This should be inside the tool aswell self.analyze_clipboard(blackboard, data_source, file_manager) return IngestModule.ProcessResult.OK except NoCurrentCaseException as ex: self.log(Level.WARNING, "No case currently open. " + ex.toString())
def generateReport(self, baseReportDir, progressBar): module_path = os.path.dirname(os.path.abspath(__file__)) exe_ext = '.exe' if os.name == 'nt' else '' self.path_to_exe = os.path.join(module_path, 'gboard-forensics' + exe_ext) self.log(Level.INFO, "Running reporter for " + baseReportDir.getReportDirectoryPath() + " folder") self.log(Level.INFO, "Relative file path: " + self.getRelativeFilePath()) # Issue: https://sleuthkit.discourse.group/t/error-generting-reports-in-python/2297 output_file = os.path.join(baseReportDir.getReportDirectoryPath(), self.getRelativeFilePath()) progressBar.setIndeterminate(True) progressBar.start() try: current_case = Case.getCurrentCaseThrows() services = current_case.getServices() file_manager = services.getFileManager() input_dir = self.get_input_dir(file_manager) # Run GBoard analysis tool report_output = self.run_reporter(input_dir) report = open(output_file, 'w') report.write(report_output) report.close() current_case.addReport(output_file, self.moduleName, "HTML Report") progressBar.complete(ReportStatus.COMPLETE) except NoCurrentCaseException as ex: self.log(Level.WARNING, "No case currently open. " + ex.toString()) progressBar.complete(ReportStatus.ERROR)
def analyze(self, dataSource, fileManager, context): historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "history.db", True, self._PACKAGE_NAME) for historyDb in historyDbs: try: current_case = Case.getCurrentCaseThrows() historyDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), self._MODULE_NAME, historyDb.getDBFile(), Account.Type.SHAREIT) queryString = """ SELECT history_type, device_id, device_name, description, timestamp, file_path FROM history JOIN item where history.content_id = item.item_id """ historyResultSet = historyDb.runQuery(queryString) if historyResultSet is not None: while historyResultSet.next(): direction = "" fromId = None toId = None if (historyResultSet.getInt("history_type") == 1): direction = CommunicationDirection.INCOMING fromId = historyResultSet.getString("device_id") else: direction = CommunicationDirection.OUTGOING toId = historyResultSet.getString("device_id") msgBody = "" # there is no body. attachments = [historyResultSet.getString("file_path")] msgBody = general.appendAttachmentList(msgBody, attachments) timeStamp = historyResultSet.getLong("timestamp") / 1000 messageArtifact = historyDbHelper.addMessage( self._MESSAGE_TYPE, direction, fromId, toId, timeStamp, MessageReadStatus.UNKNOWN, None, # subject msgBody, None ) # thread id # TBD: add the file as attachment ?? except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for ShareIt history.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Failed to create ShareIt message artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: historyDb.close()
def analyze(self, dataSource, fileManager, context): """ Extract, Transform and Load all messages, contacts and calllogs from the TextNow databases. """ textnow_dbs = AppSQLiteDB.findAppDatabases(dataSource, "textnow_data.db", True, self._TEXTNOW_PACKAGE_NAME) try: for textnow_db in textnow_dbs: current_case = Case.getCurrentCaseThrows() helper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, textnow_db.getDBFile(), Account.Type.TEXTNOW ) self.parse_contacts(textnow_db, helper) self.parse_calllogs(textnow_db, helper) self.parse_messages(textnow_db, helper, current_case) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) for textnow_db in textnow_dbs: textnow_db.close()
def analyze(self, dataSource, fileManager, context): try: self.current_case = Case.getCurrentCaseThrows() except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) return try: absFiles = fileManager.findFiles(dataSource, "da_destination_history") if absFiles.isEmpty(): return for abstractFile in absFiles: try: jFile = File( self.current_case.getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName()) ContentUtils.writeToFile( abstractFile, jFile, context.dataSourceIngestIsCancelled) self.__findGeoLocationsInDB(jFile.toString(), abstractFile) except Exception as ex: self._logger.log(Level.SEVERE, "Error parsing Google map locations", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except TskCoreException as ex: # Error finding Google map locations. pass
def startUp(self, context): """Where module setup and configuration is done Args: context (IngestJobContext): Context of the ingest module """ self.log(Level.INFO, "GBoard Data Source Ingest Module is starting up...") # setup the current context self.context = context # check if executable exists module_path = os.path.dirname(os.path.abspath(__file__)) exe_ext = '.exe' if 'win' in System.getProperty("os.name").encode('ascii','ignore').lower() else '' self.path_to_exe = os.path.join(module_path, 'gboard-forensics' + exe_ext) if not os.path.exists(self.path_to_exe): raise IngestModuleException('Executable file not found!') try: current_case = Case.getCurrentCaseThrows() # create artifacts self.dictionary_art_type = self.createCustomArtifactType(current_case, self.GBOARD_DICTIONARY_ARTIFACT, 'Gboard Dictionary') self.tc_history_timeline_art_type = self.createCustomArtifactType(current_case, self.GBOARD_TC_HISTORY_TIMELINE_ARTIFACT, 'Gboard History Timeline') self.tc_raw_assembled_timeline_art_type = self.createCustomArtifactType(current_case, self.GBOARD_TC_RAW_ASSEMBLED_TIMELINE_ARTIFACT, 'Gboard Assembled Timeline') self.tc_processed_history_art_type = self.createCustomArtifactType(current_case, self.GBOARD_TC_PROCESSED_HISTORY_ARTIFACT, 'Gboard Processed History') self.emojis_art_type = self.createCustomArtifactType(current_case, self.GBOARD_EMOJIS_ARTIFACT, 'Gboard Expression History: Emojis') self.emoticons_art_type = self.createCustomArtifactType(current_case, self.GBOARD_EMOTICONS_ARTIFACT, 'Gboard Expression History: Emoticons') self.translate_art_type = self.createCustomArtifactType(current_case, self.GBOARD_TRANSLATE_ARTIFACT, 'Gboard Translate Cache') # emojis and emoticons attributes self.expression_shares_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_EXPRESSION_SHARES_ATTRIBUTE, 'Shares') self.expression_emoji_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_EXPRESSION_EMOJI_ATTRIBUTE, 'Emoji') self.expression_base_emoji_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_EXPRESSION_BASE_EMOJI_ATTRIBUTE, 'Base Emoji') self.expression_emoticon_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_EXPRESSION_EMOTICON_ATTRIBUTE, 'Emoticon') # training cache attributes self.tc_delete_flag_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_TC_DELETE_FLAG_ATTRIBUTE, 'Deleted?') # clipboard attributes self.clipboard_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_CLIPBOARD_ATTRIBUTE, 'Gboard Clipboard') self.clipboard_html_text_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_CLIPBOARD_HTML_TEXT_ATTRIBUTE, 'HTML Text') # dictionary attributes self.dictionary_word_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_DICTIONARY_WORD_ATTRIBUTE, 'Word') self.dictionary_shortcut_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_DICTIONARY_SHORTCUT_ATTRIBUTE, 'Shortcut') self.dictionary_locale_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_DICTIONARY_LOCALE_ATTRIBUTE, 'Locale') # translation cache attributes self.translate_original_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_TRANSLATE_ORIGINAL_ATTRIBUTE, 'Original Text') self.translate_translated_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_TRANSLATE_TRANSLATED_ATTRIBUTE, 'Translated Text') self.translate_from_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_TRANSLATE_FROM_ATTRIBUTE, 'From Language') self.translate_to_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_TRANSLATE_TO_ATTRIBUTE, 'To Language') self.translate_url_attr_type = self.createCustomAttributeType(current_case, self.GBOARD_TRANSLATE_URL_ATTRIBUTE, 'Request URL') except NoCurrentCaseException as ex: self.log(Level.WARNING, "No case currently open. " + ex)
def __findWWFMessagesInDB(self, wwfDb, dataSource): if not wwfDb: return current_case = Case.getCurrentCaseThrows() # Create a helper to parse the DB wwfDbHelper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, wwfDb.getDBFile(), wwfAccountType) uuid = UUID.randomUUID().toString() resultSet = None try: resultSet = wwfDb.runQuery( "SELECT message, strftime('%s' ,created_at) as datetime, user_id, game_id FROM chat_messages ORDER BY game_id DESC, created_at DESC;" ) while resultSet.next(): message = resultSet.getString("message") # WWF Message created_at = resultSet.getLong("datetime") user_id = resultSet.getString( "user_id" ) # the ID of the user who sent/received the message. game_id = resultSet.getString( "game_id" ) # ID of the game which the the message was sent. thread_id = "{0}-{1}".format(uuid, user_id) messageArtifact = wwfDbHelper.addMessage( self._MESSAGE_TYPE, CommunicationDirection.UNKNOWN, user_id, # fromId None, # toId created_at, MessageReadStatus.UNKNOWN, "", # subject message, thread_id) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for WWF messages", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Failed to add WWF message artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: wwfDb.close()
def analyze(self, dataSource, fileManager, context): transferDbs = AppSQLiteDB.findAppDatabases(dataSource, "transfer20.db", True, self._PACKAGE_NAME) for transferDb in transferDbs: try: current_case = Case.getCurrentCaseThrows() # transferDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), self._MODULE_NAME, transferDb.getDBFile(), Account.Type.ZAPYA) queryString = "SELECT device, name, direction, createtime, path, title FROM transfer" transfersResultSet = transferDb.runQuery(queryString) if transfersResultSet is not None: while transfersResultSet.next(): direction = CommunicationDirection.UNKNOWN fromId = None toId = None fileAttachments = ArrayList() if (transfersResultSet.getInt("direction") == 1): direction = CommunicationDirection.OUTGOING toId = transfersResultSet.getString("device") else: direction = CommunicationDirection.INCOMING fromId = transfersResultSet.getString("device") timeStamp = transfersResultSet.getLong("createtime") / 1000 messageArtifact = transferDbHelper.addMessage( self._MESSAGE_TYPE, direction, fromId, toId, timeStamp, MessageReadStatus.UNKNOWN, None, # subject None, # message Text None ) # thread id # add the file as attachment fileAttachments.add(FileAttachment(current_case.getSleuthkitCase(), transferDb.getDBFile().getDataSource(), transfersResultSet.getString("path"))) messageAttachments = MessageAttachments(fileAttachments, []) transferDbHelper.addAttachments(messageArtifact, messageAttachments) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for transfer.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Failed to create Zapya message artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: transferDb.close()
def analyze(self, dataSource, fileManager, context): try: self.current_case = Case.getCurrentCaseThrows() except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) return self.analyzeContacts(dataSource, fileManager, context) self.analyzeMessagesAndCallLogs(dataSource, fileManager, context)
def __findTangoMessagesInDB(self, tangoDb, dataSource): if not tangoDb: return try: current_case = Case.getCurrentCaseThrows() # Create a helper to parse the DB tangoDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), self._PARSER_NAME, tangoDb.getDBFile(), Account.Type.TANGO ) resultSet = tangoDb.runQuery( "SELECT conv_id, create_time, direction, payload FROM messages ORDER BY create_time DESC;") while resultSet.next(): fromId = None toId = None conv_id = resultSet.getString("conv_id") # seems to wrap around the message found in payload after decoding from base-64 create_time = Long.valueOf(resultSet.getString("create_time")) / 1000 if resultSet.getString("direction") == "1": # 1 incoming, 2 outgoing direction = CommunicationDirection.INCOMING else: direction = CommunicationDirection.OUTGOING payload = resultSet.getString("payload") msgBody = TangoMessageAnalyzer.decodeMessage(conv_id, payload) messageArtifact = tangoDbHelper.addMessage( self._MESSAGE_TYPE, direction, fromId, toId, create_time, MessageReadStatus.UNKNOWN, "", # subject msgBody, "") except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for Tango messages", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Failed to add Tango message artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: tangoDb.close()
def analyze(self, dataSource, fileManager, context): oruxMapsTrackpointsDbs = AppSQLiteDB.findAppDatabases( dataSource, "oruxmapstracks.db", True, self._PACKAGE_NAME) for oruxMapsTrackpointsDb in oruxMapsTrackpointsDbs: try: current_case = Case.getCurrentCaseThrows() oruxDbHelper = ArtifactsHelper( current_case.getSleuthkitCase(), self._MODULE_NAME, oruxMapsTrackpointsDb.getDBFile()) poiQueryString = "SELECT poilat, poilon, poitime, poiname FROM pois" poisResultSet = oruxMapsTrackpointsDb.runQuery(poiQueryString) if poisResultSet is not None: while poisResultSet.next(): oruxDbHelper.addGPSLocation( poisResultSet.getDouble("poilat"), poisResultSet.getDouble("poilon"), poisResultSet.getLong("poitime") / 1000, # milliseconds since unix epoch poisResultSet.getString("poiname"), self._PROGRAM_NAME) trackpointsQueryString = "SELECT trkptlat, trkptlon, trkpttime FROM trackpoints" trackpointsResultSet = oruxMapsTrackpointsDb.runQuery( trackpointsQueryString) if trackpointsResultSet is not None: while trackpointsResultSet.next(): oruxDbHelper.addGPSLocation( trackpointsResultSet.getDouble("trkptlat"), trackpointsResultSet.getDouble("trkptlon"), trackpointsResultSet.getLong("trkpttime") / 1000, # milliseconds since unix epoch "", self._PROGRAM_NAME) except SQLException as ex: self._logger.log( Level.WARNING, "Error processing query result for Orux Map trackpoints.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log( Level.SEVERE, "Failed to add Orux Map trackpoint artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: oruxMapsTrackpointsDb.close()
def analyze(self, dataSource, fileManager, context): """ Extract, Transform and Load all TSK contact, message and calllog artifacts from the WhatsApp databases. """ try: contact_dbs = AppSQLiteDB.findAppDatabases( dataSource, "wa.db", True, self._WHATSAPP_PACKAGE_NAME) calllog_and_message_dbs = AppSQLiteDB.findAppDatabases( dataSource, "msgstore.db", True, self._WHATSAPP_PACKAGE_NAME) #Extract TSK_CONTACT information for contact_db in contact_dbs: current_case = Case.getCurrentCaseThrows() helper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, contact_db.getDBFile(), Account.Type.WHATSAPP) self.parse_contacts(contact_db, helper) for calllog_and_message_db in calllog_and_message_dbs: current_case = Case.getCurrentCaseThrows() helper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, calllog_and_message_db.getDBFile(), Account.Type.WHATSAPP) self.parse_calllogs(calllog_and_message_db, helper) self.parse_messages(dataSource, calllog_and_message_db, helper, current_case) except NoCurrentCaseException as ex: #If there is no current case, bail out immediately. self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exec()) #Clean up open file handles. for contact_db in contact_dbs: contact_db.close() for calllog_and_message_db in calllog_and_message_dbs: calllog_and_message_db.close()
def analyze(self, dataSource, fileManager, context): """ Extract, Transform and Load all messages, contacts and calllogs from the Viber databases. """ try: contact_and_calllog_dbs = AppSQLiteDB.findAppDatabases( dataSource, "viber_data", True, self._VIBER_PACKAGE_NAME) message_dbs = AppSQLiteDB.findAppDatabases( dataSource, "viber_messages", True, self._VIBER_PACKAGE_NAME) #Extract TSK_CONTACT and TSK_CALLLOG information for contact_and_calllog_db in contact_and_calllog_dbs: current_case = Case.getCurrentCaseThrows() helper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, contact_and_calllog_db.getDBFile(), Account.Type.VIBER) self.parse_contacts(contact_and_calllog_db, helper) self.parse_calllogs(contact_and_calllog_db, helper) #Extract TSK_MESSAGE information for message_db in message_dbs: current_case = Case.getCurrentCaseThrows() helper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, message_db.getDBFile(), Account.Type.VIBER) self.parse_messages(message_db, helper, current_case) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) for message_db in message_dbs: message_db.close() for contact_and_calllog_db in contact_and_calllog_dbs: contact_and_calllog_db.close()
def analyze(self, dataSource, fileManager, context): ## open current case try: self.current_case = Case.getCurrentCaseThrows() except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) return self.analyzeBookmarks(dataSource, fileManager, context) self.analyzeCookies(dataSource, fileManager, context) self.analyzeHistory(dataSource, fileManager, context) self.analyzeDownloads(dataSource, fileManager, context) self.analyzeAutofill(dataSource, fileManager, context) self.analyzeWebFormAddress(dataSource, fileManager, context)
def analyze(self, dataSource, fileManager, context): #Skype databases are of the form: live:XYZ.db, where #XYZ is the skype id of the user. The following search #does a generic substring match for 'live' in the skype #package. skype_dbs = AppSQLiteDB.findAppDatabases(dataSource, "live:", False, self._SKYPE_PACKAGE_NAME) try: for skype_db in skype_dbs: #Attempt to get the user account id from the database user_account_instance = None try: user_account_instance = self.get_user_account(skype_db) except SQLException as ex: self._logger.log( Level.WARNING, "Error querying for the user account in the Skype db.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) current_case = Case.getCurrentCaseThrows() if user_account_instance is None: helper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, skype_db.getDBFile(), Account.Type.SKYPE) else: helper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, skype_db.getDBFile(), Account.Type.SKYPE, Account.Type.SKYPE, user_account_instance) self.parse_contacts(skype_db, helper) self.parse_calllogs(skype_db, helper) self.parse_messages(skype_db, helper) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) for skype_db in skype_dbs: skype_db.close()
def analyze(self, dataSource, fileManager, context): libraryDbs = AppSQLiteDB.findAppDatabases(dataSource, "library.db", True, self._PACKAGE_NAME) for libraryDb in libraryDbs: try: current_case = Case.getCurrentCaseThrows() libraryDbHelper = ArtifactsHelper( current_case.getSleuthkitCase(), self._MODULE_NAME, libraryDb.getDBFile()) queryString = "SELECT doc_id, purchase_time FROM ownership" ownershipResultSet = libraryDb.runQuery(queryString) if ownershipResultSet is not None: while ownershipResultSet.next(): purchase_time = ownershipResultSet.getLong( "purchase_time") / 1000 libraryDbHelper.addInstalledProgram( ownershipResultSet.getString("doc_id"), purchase_time) except SQLException as ex: self._logger.log( Level.WARNING, "Error processing query result for installed applications. ", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log( Level.SEVERE, "Failed to adding installed application artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: libraryDb.close()
def analyze(self, dataSource, fileManager, context): oruxMapsTrackpointsDbs = AppSQLiteDB.findAppDatabases( dataSource, "oruxmapstracks.db", True, self._PACKAGE_NAME) for oruxMapsTrackpointsDb in oruxMapsTrackpointsDbs: try: current_case = Case.getCurrentCaseThrows() skCase = Case.getCurrentCase().getSleuthkitCase() geoArtifactHelper = GeoArtifactsHelper( skCase, self._MODULE_NAME, self._PROGRAM_NAME, oruxMapsTrackpointsDb.getDBFile()) poiQueryString = "SELECT poilat, poilon, poialt, poitime, poiname FROM pois" poisResultSet = oruxMapsTrackpointsDb.runQuery(poiQueryString) abstractFile = oruxMapsTrackpointsDb.getDBFile() if poisResultSet is not None: while poisResultSet.next(): latitude = poisResultSet.getDouble("poilat") longitude = poisResultSet.getDouble("poilon") time = poisResultSet.getLong( "poitime") / 1000 # milliseconds since unix epoch name = poisResultSet.getString("poiname") altitude = poisResultSet.getDouble("poialt") attributes = ArrayList() artifact = abstractFile.newArtifact( BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_DATETIME, self._MODULE_NAME, time)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_GEO_LATITUDE, self._MODULE_NAME, latitude)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_GEO_LONGITUDE, self._MODULE_NAME, longitude)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_GEO_ALTITUDE, self._MODULE_NAME, altitude)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, self._MODULE_NAME, name)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_PROG_NAME, self._MODULE_NAME, self._PROGRAM_NAME)) artifact.addAttributes(attributes) try: # index the artifact for keyword search blackboard = Case.getCurrentCase( ).getSleuthkitCase().getBlackboard() blackboard.postArtifact(artifact, self._MODULE_NAME) except Blackboard.BlackboardException as ex: self._logger.log( Level.SEVERE, "Unable to index blackboard artifact " + str(artifact.getArtifactID()), ex) self._logger.log(Level.SEVERE, traceback.format_exc()) MessageNotifyUtil.Notify.error( "Failed to index trackpoint artifact for keyword search.", artifact.getDisplayName()) # tracks -> segments -> trackpoints # # The reason that the track and the segment are put into arrays is that once the segment query is run an error occurs that it cannot find the # trackname column in the track query. This is avoided if all the tracks/segments are found and put into an array(s) that can then be processed all at once. trackQueryString = "SELECT _id, trackname, trackciudad FROM tracks" trackResultSet = oruxMapsTrackpointsDb.runQuery( trackQueryString) if trackResultSet is not None: trackResults = ArrayList() while trackResultSet.next(): tempTrack = ArrayList() trackName = trackResultSet.getString( "trackname") + " - " + trackResultSet.getString( "trackciudad") trackId = str(trackResultSet.getInt("_id")) tempTrack.append(trackId) tempTrack.append(trackName) trackResults.append(tempTrack) for trackResult in trackResults: trackId = trackResult[0] trackName = trackResult[1] segmentQueryString = "SELECT _id, segname FROM segments WHERE segtrack = " + trackId segmentResultSet = oruxMapsTrackpointsDb.runQuery( segmentQueryString) if segmentResultSet is not None: segmentResults = ArrayList() while segmentResultSet.next(): segmentName = trackName + " - " + segmentResultSet.getString( "segname") segmentId = str(segmentResultSet.getInt("_id")) tempSegment = ArrayList() tempSegment.append(segmentId) tempSegment.append(segmentName) segmentResults.append(tempSegment) for segmentResult in segmentResults: segmentId = segmentResult[0] segmentName = segmentResult[1] trackpointsQueryString = "SELECT trkptlat, trkptlon, trkptalt, trkpttime FROM trackpoints WHERE trkptseg = " + segmentId trackpointsResultSet = oruxMapsTrackpointsDb.runQuery( trackpointsQueryString) if trackpointsResultSet is not None: geoPointList = GeoTrackPoints() while trackpointsResultSet.next(): latitude = trackpointsResultSet.getDouble( "trkptlat") longitude = trackpointsResultSet.getDouble( "trkptlon") altitude = trackpointsResultSet.getDouble( "trkptalt") time = trackpointsResultSet.getLong( "trkpttime" ) / 1000 # milliseconds since unix epoch geoPointList.addPoint( TrackPoint(latitude, longitude, altitude, segmentName, 0, 0, 0, time)) try: geoartifact = geoArtifactHelper.addTrack( segmentName, geoPointList, None) except Blackboard.BlackboardException as ex: self._logger.log( Level.SEVERE, "Error using geo artifact helper with blackboard", ex) self._logger.log( Level.SEVERE, traceback.format_exc()) MessageNotifyUtil.Notify.error( "Failed to add track artifact.", "geoArtifactHelper") except TskCoreException as e: self._logger.log( Level.SEVERE, "Error using geo artifact helper with TskCoreException", ex) self._logger.log( Level.SEVERE, traceback.format_exc()) MessageNotifyUtil.Notify.error( "Failed to add track artifact with TskCoreException.", "geoArtifactHelper") except SQLException as ex: self._logger.log( Level.WARNING, "Error processing query result for Orux Map trackpoints.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log( Level.SEVERE, "Failed to add Orux Map trackpoint artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: oruxMapsTrackpointsDb.close()
def __findContactsInDB(self, contactDb, dataSource): if not contactDb: return try: current_case = Case.getCurrentCaseThrows() # Create a helper to parse the DB contactDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), self._PARSER_NAME, contactDb.getDBFile(), Account.Type.PHONE ) # get display_name, mimetype(email or phone number) and data1 (phonenumber or email address depending on mimetype) # sorted by name, so phonenumber/email would be consecutive for a person if they exist. # check if contacts.name_raw_contact_id exists. Modify the query accordingly. columnFound = contactDb.columnExists("contacts", "name_raw_contact_id") if columnFound: resultSet = contactDb.runQuery( "SELECT mimetype, data1, name_raw_contact.display_name AS display_name \n" + "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n" + "JOIN raw_contacts AS name_raw_contact ON(name_raw_contact_id=name_raw_contact._id) " + "LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id) \n" + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id=mimetypes._id) \n" + "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n" + "ORDER BY name_raw_contact.display_name ASC;") else: resultSet = contactDb.runQuery( "SELECT mimetype, data1, raw_contacts.display_name AS display_name \n" + "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n" + "LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id) \n" + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id=mimetypes._id) \n" + "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n" + "ORDER BY raw_contacts.display_name ASC;") contactArtifact = None oldName = None phoneNumber = None emailAddr = None name = None while resultSet.next(): name = resultSet.getString("display_name") data1 = resultSet.getString("data1") # the phone number or email mimetype = resultSet.getString("mimetype") # either phone or email if oldName and (name != oldName): if phoneNumber or emailAddr: contactArtifact = contactDbHelper.addContact(oldName, phoneNumber, # phoneNumber, None, # homePhoneNumber, None, # mobilePhoneNumber, emailAddr) # emailAddr oldName = name phoneNumber = None emailAddr = None name = None if mimetype == "vnd.android.cursor.item/phone_v2": phoneNumber = data1 else: emailAddr = data1 if name: oldName = name # create contact for last row if oldName and (phoneNumber or emailAddr): contactArtifact = contactDbHelper.addContact(oldName, phoneNumber, # phoneNumber, None, # homePhoneNumber, None, # mobilePhoneNumber, emailAddr) # emailAddr except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for Android messages.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Failed to add Android message artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: contactDb.close()
def analyze(self, dataSource, fileManager, context): selfAccountId = None messageDbs = AppSQLiteDB.findAppDatabases(dataSource, "mmssms.db", True, self._PACKAGE_NAME) for messageDb in messageDbs: try: current_case = Case.getCurrentCaseThrows() if selfAccountId is not None: messageDbHelper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, messageDb.getDBFile(), Account.Type.PHONE, Account.Type.IMO, selfAccountId) else: messageDbHelper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, messageDb.getDBFile(), Account.Type.PHONE) uuid = UUID.randomUUID().toString() messagesResultSet = messageDb.runQuery( "SELECT address, date, read, type, subject, body, thread_id FROM sms;" ) if messagesResultSet is not None: while messagesResultSet.next(): direction = "" address = None fromId = None toId = None address = messagesResultSet.getString( "address" ) # may be phone number, or other addresses timeStamp = Long.valueOf( messagesResultSet.getString("date")) / 1000 read = messagesResultSet.getInt( "read") # may be unread = 0, read = 1 subject = messagesResultSet.getString( "subject") # message subject msgBody = messagesResultSet.getString( "body") # message body thread_id = "{0}-{1}".format( uuid, messagesResultSet.getInt("thread_id")) if messagesResultSet.getString("type") == "1": direction = CommunicationDirection.INCOMING fromId = address else: direction = CommunicationDirection.OUTGOING toId = address message_read = messagesResultSet.getInt( "read") # may be unread = 0, read = 1 if (message_read == 1): msgReadStatus = MessageReadStatus.READ elif (message_read == 0): msgReadStatus = MessageReadStatus.UNREAD else: msgReadStatus = MessageReadStatus.UNKNOWN ## add a message if address is not None: messageArtifact = messageDbHelper.addMessage( self._MESSAGE_TYPE, direction, fromId, toId, timeStamp, msgReadStatus, subject, # subject msgBody, thread_id) except SQLException as ex: self._logger.log( Level.WARNING, "Error processing query result for Android messages.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Failed to add Android message artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: messageDb.close()
def analyze(self, dataSource, fileManager, context): selfAccountId = None accountDbs = AppSQLiteDB.findAppDatabases(dataSource, "accountdb.db", True, self._PACKAGE_NAME) for accountDb in accountDbs: try: accountResultSet = accountDb.runQuery("SELECT uid, name FROM account") if accountResultSet: # We can determine the IMO user ID of the device owner. # Therefore we can create and use a app account and use that # as a 'self' account instead of a Device account if not selfAccountId: selfAccountId = accountResultSet.getString("uid") except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for account", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: accountDb.close() friendsDbs = AppSQLiteDB.findAppDatabases(dataSource, "imofriends.db", True, self._PACKAGE_NAME) for friendsDb in friendsDbs: try: current_case = Case.getCurrentCaseThrows() if selfAccountId is not None: friendsDBHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), self._PARSER_NAME, friendsDb.getDBFile(), Account.Type.IMO, Account.Type.IMO, selfAccountId ) else: friendsDBHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), self._PARSER_NAME, friendsDb.getDBFile(), Account.Type.IMO ) contactsResultSet = friendsDb.runQuery("SELECT buid, name FROM friends") if contactsResultSet is not None: while contactsResultSet.next(): contactId = contactsResultSet.getString("buid") ## add a TSK_ID attribute with contact's IMO Id additionalAttributes = ArrayList() additionalAttributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ID, self._PARSER_NAME, contactId)) friendsDBHelper.addContact( contactsResultSet.getString("name"), ## contact name "", ## phone "", ## home phone "", ## mobile "", ## email additionalAttributes) queryString = """ SELECT messages.buid AS buid, imdata, last_message, timestamp, message_type, message_read, name FROM messages INNER JOIN friends ON friends.buid = messages.buid """ messagesResultSet = friendsDb.runQuery(queryString) if messagesResultSet is not None: while messagesResultSet.next(): direction = "" fromId = None toId = None name = messagesResultSet.getString("name") uniqueId = messagesResultSet.getString("buid") if (messagesResultSet.getInt("message_type") == 1): direction = CommunicationDirection.INCOMING fromId = uniqueId else: direction = CommunicationDirection.OUTGOING toId = uniqueId message_read = messagesResultSet.getInt("message_read") if (message_read == 1): msgReadStatus = MessageReadStatus.READ elif (message_read == 0): msgReadStatus = MessageReadStatus.UNREAD else: msgReadStatus = MessageReadStatus.UNKNOWN timeStamp = messagesResultSet.getLong("timestamp") / 1000000000 messageArtifact = friendsDBHelper.addMessage( self._MESSAGE_TYPE, direction, fromId, toId, timeStamp, msgReadStatus, "", # subject messagesResultSet.getString("last_message"), "") # thread id # TBD: parse the imdata JSON structure to figure out if there is an attachment. # If one exists, add the attachment as a derived file and a child of the message artifact. except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for IMO friends", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Failed to add IMO message artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: friendsDb.close()
def analyze(self, dataSource, fileManager, context): oruxMapsTrackpointsDbs = AppSQLiteDB.findAppDatabases( dataSource, "oruxmapstracks.db", True, self._PACKAGE_NAME) for oruxMapsTrackpointsDb in oruxMapsTrackpointsDbs: try: current_case = Case.getCurrentCaseThrows() poiQueryString = "SELECT poilat, poilon, poitime, poiname FROM pois" poisResultSet = oruxMapsTrackpointsDb.runQuery(poiQueryString) abstractFile = oruxMapsTrackpointsDb.getDBFile() if poisResultSet is not None: while poisResultSet.next(): latitude = poisResultSet.getDouble("poilat") longitude = poisResultSet.getDouble("poilon") time = poisResultSet.getLong( "poitime") / 1000 # milliseconds since unix epoch name = poisResultSet.getString("poiname") attributes = ArrayList() artifact = abstractFile.newArtifact( BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT ) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_DATETIME, self._MODULE_NAME, time)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_GEO_LATITUDE, self._MODULE_NAME, latitude)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_GEO_LONGITUDE, self._MODULE_NAME, longitude)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, self._MODULE_NAME, name)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_PROG_NAME, self._MODULE_NAME, self._PROGRAM_NAME)) artifact.addAttributes(attributes) try: # index the artifact for keyword search blackboard = Case.getCurrentCase( ).getSleuthkitCase().getBlackboard() blackboard.postArtifact(artifact, self._MODULE_NAME) except Blackboard.BlackboardException as ex: self._logger.log( Level.SEVERE, "Unable to index blackboard artifact " + str(artifact.getArtifactID()), ex) self._logger.log(Level.SEVERE, traceback.format_exc()) MessageNotifyUtil.Notify.error( "Failed to index trackpoint artifact for keyword search.", artifact.getDisplayName()) trackpointsQueryString = "SELECT trkptlat, trkptlon, trkpttime FROM trackpoints" trackpointsResultSet = oruxMapsTrackpointsDb.runQuery( trackpointsQueryString) if trackpointsResultSet is not None: while trackpointsResultSet.next(): latitude = trackpointsResultSet.getDouble("trkptlat") longitude = trackpointsResultSet.getDouble("trkptlon") time = trackpointsResultSet.getLong( "trkpttime" ) / 1000 # milliseconds since unix epoch name = "" attributes = ArrayList() artifact = abstractFile.newArtifact( BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT ) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_DATETIME, self._MODULE_NAME, time)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_GEO_LATITUDE, self._MODULE_NAME, latitude)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_GEO_LONGITUDE, self._MODULE_NAME, longitude)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, self._MODULE_NAME, name)) attributes.add( BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE. TSK_PROG_NAME, self._MODULE_NAME, self._PROGRAM_NAME)) artifact.addAttributes(attributes) try: # index the artifact for keyword search blackboard = Case.getCurrentCase( ).getSleuthkitCase().getBlackboard() blackboard.postArtifact(artifact, self._MODULE_NAME) except Blackboard.BlackboardException as ex: self._logger.log( Level.SEVERE, "Unable to index blackboard artifact " + str(artifact.getArtifactID()), ex) self._logger.log(Level.SEVERE, traceback.format_exc()) MessageNotifyUtil.Notify.error( "Failed to index trackpoint artifact for keyword search.", artifact.getDisplayName()) except SQLException as ex: self._logger.log( Level.WARNING, "Error processing query result for Orux Map trackpoints.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log( Level.SEVERE, "Failed to add Orux Map trackpoint artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: oruxMapsTrackpointsDb.close()
def analyzeMessages(self, threadsDb, threadsDBHelper): try: ## Messages are found in the messages table. ## This query filters messages by msg_type to only get actual user created conversation messages (msg_type 0). ## The participant ids can be found in the thread_participants table. ## Participant names are found in thread_users table. ## Joining these tables produces multiple rows per message, one row for each recipient. ## The result set is processed to collect the multiple recipients for a given message. sqlString = """ SELECT msg_id, text, sender, timestamp_ms, msg_type, messages.thread_key as thread_key, snippet, thread_participants.user_key as user_key, thread_users.name as name, attachments, pending_send_media_attachment FROM messages JOIN thread_participants ON messages.thread_key = thread_participants.thread_key JOIN thread_users ON thread_participants.user_key = thread_users.user_key WHERE msg_type = 0 ORDER BY msg_id """ messagesResultSet = threadsDb.runQuery(sqlString) if messagesResultSet is not None: oldMsgId = None direction = CommunicationDirection.UNKNOWN fromId = None recipientIdsList = None timeStamp = -1 msgText = "" threadId = "" messageAttachments = None currentCase = Case.getCurrentCaseThrows() while messagesResultSet.next(): msgId = messagesResultSet.getString("msg_id") # new msg begins when msgId changes if msgId != oldMsgId: # Create message artifact with collected attributes if oldMsgId is not None: messageArtifact = threadsDBHelper.addMessage( self._MESSAGE_TYPE, direction, fromId, recipientIdsList, timeStamp, MessageReadStatus.UNKNOWN, "", # subject msgText, threadId) if (messageAttachments is not None): threadsDBHelper.addAttachments( messageArtifact, messageAttachments) messageAttachments = None oldMsgId = msgId # New message - collect all attributes recipientIdsList = [] ## get sender id by parsing JSON in sender column fromId = self.getSenderIdFromJson( messagesResultSet.getString("sender")) direction = self.deduceDirectionFromSenderId(fromId) # Get recipient and add to list self.addRecipientToList( messagesResultSet.getString("user_key"), fromId, recipientIdsList) timeStamp = messagesResultSet.getLong( "timestamp_ms") / 1000 # Get msg text # Sometimes there may not be an explict msg text, # but an app generated snippet instead msgText = messagesResultSet.getString("text") if not msgText: msgText = messagesResultSet.getString("snippet") # Get attachments and pending attachments if they exist attachment = messagesResultSet.getString("attachments") pendingAttachment = messagesResultSet.getString( "pending_send_media_attachment") urlAttachments = ArrayList() fileAttachments = ArrayList() if ((attachment is not None) or (pendingAttachment is not None)): if (attachment is not None): attachmentDict = json.loads(attachment)[0] if (attachmentDict["mime_type"] == "image/jpeg" ): urls = attachmentDict.get("urls", None) if (urls is not None): urlAttachments = self.getJPGListFromJson( urls) elif (attachmentDict["mime_type"] == "video/mp4"): # filename does not have an associated path with it so it will be ignored urls = attachmentDict.get("urls", None) if (urls is not None): urlAttachments = self.getJPGListFromJson( urls) video_data_url = attachmentDict.get( "video_data_url", None) if (video_data_url is not None): urlAttachments.add( URLAttachment(video_data_url)) video_data_thumbnail_url = attachmentDict.get( "video_data_thumbnail_url", None) if (video_data_thumbnail_url is not None): urlAttachments.add( URLAttachment( video_data_thumbnail_url)) elif (attachmentDict["mime_type"] == "audio/mpeg"): audioUri = attachmentDict.get( "audio_uri", None) if (audioUri is None or audioUri == ""): continue else: fileAttachments.add( FileAttachment( currentCase.getSleuthkitCase(), threadsDb.getDBFile(). getDataSource(), audioUri.replace( "file://", ""))) else: self._logger.log( Level.INFO, "Attachment type not handled: " + attachmentDict["mime_type"]) if (pendingAttachment is not None): pendingAttachmentDict = json.loads( pendingAttachment)[0] pendingAttachmentUri = pendingAttachmentDict.get( "uri", None) if (pendingAttachmentUri is not None): fileAttachments.add( FileAttachment( currentCase.getSleuthkitCase(), threadsDb.getDBFile(). getDataSource(), pendingAttachmentUri.replace( "file://", ""))) messageAttachments = MessageAttachments( fileAttachments, urlAttachments) threadId = messagesResultSet.getString("thread_key") else: # same msgId as last, just collect recipient from current row self.addRecipientToList( messagesResultSet.getString("user_key"), fromId, recipientIdsList) # at the end of the loop, add last message messageArtifact = threadsDBHelper.addMessage( self._MESSAGE_TYPE, direction, fromId, recipientIdsList, timeStamp, MessageReadStatus.UNKNOWN, "", # subject msgText, threadId) except SQLException as ex: self._logger.log( Level.WARNING, "Error processing query result for FB Messenger messages.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Failed to add FB Messenger message artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc())
def analyze(self, dataSource, fileManager, context): selfAccountId = None transactionDbs = AppSQLiteDB.findAppDatabases(dataSource, "trans-history-db", True, self._PACKAGE_NAME) for transactionDb in transactionDbs: try: current_case = Case.getCurrentCaseThrows() # get the profile with connection_times 0, that's the self account. profilesResultSet = transactionDb.runQuery("SELECT device_id, nick_name FROM profile WHERE connect_times = 0") if profilesResultSet: while profilesResultSet.next(): if not selfAccountId: selfAccountId = profilesResultSet.getString("device_id") # create artifacts helper if selfAccountId is not None: transactionDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), self._MODULE_NAME, transactionDb.getDBFile(), Account.Type.XENDER, Account.Type.XENDER, selfAccountId ) else: transactionDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), self._MODULE_NAME, transactionDb.getDBFile(), Account.Type.XENDER) queryString = """ SELECT f_path, f_display_name, f_size_str, f_create_time, c_direction, c_session_id, s_name, s_device_id, r_name, r_device_id FROM new_history """ messagesResultSet = transactionDb.runQuery(queryString) if messagesResultSet is not None: while messagesResultSet.next(): direction = CommunicationDirection.UNKNOWN fromId = None toId = None if (messagesResultSet.getInt("c_direction") == 1): direction = CommunicationDirection.OUTGOING toId = messagesResultSet.getString("r_device_id") else: direction = CommunicationDirection.INCOMING fromId = messagesResultSet.getString("s_device_id") msgBody = "" # there is no body. attachments = [messagesResultSet.getString("f_path")] msgBody = general.appendAttachmentList(msgBody, attachments) timeStamp = messagesResultSet.getLong("f_create_time") / 1000 messageArtifact = transactionDbHelper.addMessage( self._MESSAGE_TYPE, direction, fromId, toId, timeStamp, MessageReadStatus.UNKNOWN, None, # subject msgBody, messagesResultSet.getString("c_session_id") ) # TBD: add the file as attachment ?? except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for profiles.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Failed to create Xender message artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: transactionDb.close()
def analyze(self, dataSource, fileManager, context): for _dbFileName in CallLogAnalyzer._dbFileNames: selfAccountId = None callLogDbs = AppSQLiteDB.findAppDatabases(dataSource, _dbFileName, True, self._PACKAGE_NAME) for callLogDb in callLogDbs: try: current_case = Case.getCurrentCaseThrows() if selfAccountId is not None: callLogDbHelper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, callLogDb.getDBFile(), Account.Type.PHONE, Account.Type.PHONE, selfAccountId) else: callLogDbHelper = CommunicationArtifactsHelper( current_case.getSleuthkitCase(), self._PARSER_NAME, callLogDb.getDBFile(), Account.Type.PHONE) for tableName in CallLogAnalyzer._tableNames: try: tableFound = callLogDb.tableExists(tableName) if tableFound: resultSet = callLogDb.runQuery( "SELECT number, date, duration, type, name FROM " + tableName + " ORDER BY date DESC;") self._logger.log( Level.INFO, "Reading call log from table {0} in db {1}", [ tableName, callLogDb.getDBFile().getName() ]) if resultSet is not None: while resultSet.next(): direction = "" callerId = None calleeId = None timeStamp = resultSet.getLong( "date") / 1000 number = resultSet.getString("number") duration = resultSet.getLong( "duration" ) # duration of call is in seconds name = resultSet.getString( "name" ) # name of person dialed or called. None if unregistered calltype = resultSet.getInt("type") if calltype == 1 or calltype == 3: direction = CommunicationDirection.INCOMING callerId = number elif calltype == 2 or calltype == 5: direction = CommunicationDirection.OUTGOING calleeId = number else: direction = CommunicationDirection.UNKNOWN ## add a call log if callerId is not None or calleeId is not None: callLogArtifact = callLogDbHelper.addCalllog( direction, callerId, calleeId, timeStamp, ## start time timeStamp + duration * 1000, ## end time CallMediaType.AUDIO) except SQLException as ex: self._logger.log( Level.WARNING, "Error processing query result for Android messages.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log( Level.SEVERE, "Failed to add Android call log artifacts.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Failed to post artifacts.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log( Level.SEVERE, "Failed to create CommunicationArtifactsHelper.", ex) self._logger.log(Level.SEVERE, traceback.format_exc()) except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) finally: callLogDb.close()