From 69257c9a746546c0ec69b5f8061b812667fd2b18 Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 10 Sep 2019 09:36:58 -0400 Subject: [PATCH 01/56] File transfer apps --- InternalPythonModules/android/general.py | 14 ++++++++++++++ InternalPythonModules/android/module.py | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/InternalPythonModules/android/general.py b/InternalPythonModules/android/general.py index 28c96be9b9..73efa086e0 100644 --- a/InternalPythonModules/android/general.py +++ b/InternalPythonModules/android/general.py @@ -26,3 +26,17 @@ class AndroidComponentAnalyzer: # The Analyzer should implement this method def analyze(self, dataSource, fileManager, context): raise NotImplementedError + + +""" +A utility method to append list of attachments to msg body +""" +def appendAttachmentList(msgBody, attachmentsList): + body = msgBody + if attachmentsList: + body = body + '\n\n' + "Attachments:" + 'n' + "------------" + 'n' + body = body + '\n'.join(attachmentsList) + + return body + + diff --git a/InternalPythonModules/android/module.py b/InternalPythonModules/android/module.py index 6430ec82be..56e702068c 100644 --- a/InternalPythonModules/android/module.py +++ b/InternalPythonModules/android/module.py @@ -47,6 +47,7 @@ import tangomessage import textmessage import wwfmessage import imo +import xender class AndroidModuleFactory(IngestModuleFactoryAdapter): @@ -91,7 +92,8 @@ class AndroidIngestModule(DataSourceIngestModule): analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(), tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), - cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer()] + cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer(), + xender.XenderAnalyzer()] self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers") progressBar.switchToDeterminate(len(analyzers)) From 32ddf8dfe789493988b5035e82d669e8ba567a17 Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 10 Sep 2019 10:44:42 -0400 Subject: [PATCH 02/56] Revert "File transfer apps" This reverts commit 69257c9a746546c0ec69b5f8061b812667fd2b18. --- InternalPythonModules/android/general.py | 14 -------------- InternalPythonModules/android/module.py | 4 +--- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/InternalPythonModules/android/general.py b/InternalPythonModules/android/general.py index 73efa086e0..28c96be9b9 100644 --- a/InternalPythonModules/android/general.py +++ b/InternalPythonModules/android/general.py @@ -26,17 +26,3 @@ class AndroidComponentAnalyzer: # The Analyzer should implement this method def analyze(self, dataSource, fileManager, context): raise NotImplementedError - - -""" -A utility method to append list of attachments to msg body -""" -def appendAttachmentList(msgBody, attachmentsList): - body = msgBody - if attachmentsList: - body = body + '\n\n' + "Attachments:" + 'n' + "------------" + 'n' - body = body + '\n'.join(attachmentsList) - - return body - - diff --git a/InternalPythonModules/android/module.py b/InternalPythonModules/android/module.py index 56e702068c..6430ec82be 100644 --- a/InternalPythonModules/android/module.py +++ b/InternalPythonModules/android/module.py @@ -47,7 +47,6 @@ import tangomessage import textmessage import wwfmessage import imo -import xender class AndroidModuleFactory(IngestModuleFactoryAdapter): @@ -92,8 +91,7 @@ class AndroidIngestModule(DataSourceIngestModule): analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(), tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), - cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer(), - xender.XenderAnalyzer()] + cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer()] self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers") progressBar.switchToDeterminate(len(analyzers)) From 19bb7065ea90a02bdc0b1efe40b74a116096fcca Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 10 Sep 2019 14:27:16 -0400 Subject: [PATCH 03/56] Moved work to new branch --- .../android/ResultSetIterator.py | 35 +++ .../android/TskCallLogsParser.py | 58 ++++ .../android/TskContactsParser.py | 49 ++++ .../android/TskMessagesParser.py | 68 +++++ InternalPythonModules/android/viber.py | 274 ++++++++++++++++++ 5 files changed, 484 insertions(+) create mode 100644 InternalPythonModules/android/ResultSetIterator.py create mode 100644 InternalPythonModules/android/TskCallLogsParser.py create mode 100644 InternalPythonModules/android/TskContactsParser.py create mode 100644 InternalPythonModules/android/TskMessagesParser.py create mode 100644 InternalPythonModules/android/viber.py diff --git a/InternalPythonModules/android/ResultSetIterator.py b/InternalPythonModules/android/ResultSetIterator.py new file mode 100644 index 0000000000..4abd4438df --- /dev/null +++ b/InternalPythonModules/android/ResultSetIterator.py @@ -0,0 +1,35 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +class ResultSetIterator(object): + """ + Generic base class for iterating through database recordms + """ + + def __init__(self, result_set): + self.result_set = result_set + + def next(self): + if self.result_set is None: + return False + return self.result_set.next() + + def close(self): + if self.result_set is not None: + self.result_set.close() diff --git a/InternalPythonModules/android/TskCallLogsParser.py b/InternalPythonModules/android/TskCallLogsParser.py new file mode 100644 index 0000000000..22b509d612 --- /dev/null +++ b/InternalPythonModules/android/TskCallLogsParser.py @@ -0,0 +1,58 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from ResultSetIterator import ResultSetIterator + +class TskCallLogsParser(ResultSetIterator): + """ + Generic TSK_CALLLOG artifact template. Each of these methods + will contain the extraction and transformation logic for + converting raw database records to the expected TSK_CALLLOG + format. + + A simple example of data transformation would be computing + the end time of a call when the database only supplies the start + time and duration. + """ + + def __init__(self, result_set): + super(TskCallLogsParser, self).__init__(result_set) + self.INCOMING_MSG_STRING = "Incoming" + self.OUTGOING_MSG_STRING = "Outgoing" + self._DEFAULT_STRING = "" + + def get_account_name(self): + return self._DEFAULT_STRING + + def get_call_direction(self): + return self._DEFAULT_STRING + + def get_phone_number_from(self): + return self._DEFAULT_STRING + + def get_phone_number_to(self): + return self._DEFAULT_STRING + + def get_call_start_date_time(self): + return self._DEFAULT_LONG + + def get_call_end_date_time(self): + return self._DEFAULT_LONG + + def get_contact_name(self): + return self._DEFAULT_STRING diff --git a/InternalPythonModules/android/TskContactsParser.py b/InternalPythonModules/android/TskContactsParser.py new file mode 100644 index 0000000000..122e6a9445 --- /dev/null +++ b/InternalPythonModules/android/TskContactsParser.py @@ -0,0 +1,49 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from ResultSetIterator import ResultSetIterator + +class TskContactsParser(ResultSetIterator): + """ + Generic TSK_CONTACT artifact template. Each of these methods + will contain the extraction and transformation logic for + converting raw database records to the expected TSK_CONTACT + format. + """ + + def __init__(self, result_set): + super(TskContactsParser, self).__init__(result_set) + self._DEFAULT_VALUE = "" + + def get_account_name(self): + return self._DEFAULT_VALUE + + def get_contact_name(self): + return self._DEFAULT_VALUE + + def get_phone(self): + return self._DEFAULT_VALUE + + def get_home_phone(self): + return self._DEFAULT_VALUE + + def get_mobile_phone(self): + return self._DEFAULT_VALUE + + def get_email(self): + return self._DEFAULT_VALUE diff --git a/InternalPythonModules/android/TskMessagesParser.py b/InternalPythonModules/android/TskMessagesParser.py new file mode 100644 index 0000000000..0346a203e7 --- /dev/null +++ b/InternalPythonModules/android/TskMessagesParser.py @@ -0,0 +1,68 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from ResultSetIterator import ResultSetIterator + +class TskMessagesParser(ResultSetIterator): + """ + Generic TSK_MESSAGE artifact template. Each of these methods + will contain the extraction and transformation logic for + converting raw database records to the expected TSK_MESSAGE + format. + + An easy example of such a transformation would be converting + message date time from milliseconds to seconds. + """ + + def __init__(self, result_set): + super(TskMessagesParser, self).__init__(result_set) + self.INCOMING_MSG_STRING = "Incoming" + self.OUTGOING_MSG_STRING = "Outgoing" + self._DEFAULT_TEXT = "" + self._DEFAULT_LONG = -1L + self._DEFAULT_INT = -1 + + def get_account_id(self): + return self._DEFAULT_TEXT + + def get_message_type(self): + return self._DEFAULT_TEXT + + def get_message_direction(self): + return self._DEFAULT_TEXT + + def get_phone_number_from(self): + return self._DEFAULT_TEXT + + def get_phone_number_to(self): + return self._DEFAULT_TEXT + + def get_message_date_time(self): + return self._DEFAULT_LONG + + def get_message_read_status(self): + return self._DEFAULT_INT + + def get_message_subject(self): + return self._DEFAULT_TEXT + + def get_message_text(self): + return self._DEFAULT_TEXT + + def get_thread_id(self): + return self._DEFAULT_TEXT diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py new file mode 100644 index 0000000000..3a65382c3c --- /dev/null +++ b/InternalPythonModules/android/viber.py @@ -0,0 +1,274 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Long +from java.lang import String +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB as SQLiteUtil +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper as BlackboardUtil +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel import Account +from TskMessagesParser import TskMessagesParser +from TskContactsParser import TskContactsParser +from TskCallLogsParser import TskCallLogsParser + +import traceback +import general + +class ViberAnalyzer(general.AndroidComponentAnalyzer): + """ + Parses the Viber App databases for TSK contacts, message and calllog artifacts. + """ + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + self._VIBER_PACKAGE_NAME = "com.viber.voip" + self._PARSER_NAME = "Viber Parser" + + def analyze(self, dataSource, fileManager, context): + """ + Extract, Transform and Load all messages, contacts and calllogs from the Viber databases. + """ + + try: + contact_and_calllog_dbs = SQLiteUtil.findAppDatabases(dataSource, "viber_data", self._VIBER_PACKAGE_NAME) + message_dbs = SQLiteUtil.findAppDatabases(dataSource, "viber_messages", self._VIBER_PACKAGE_NAME) + + #Extract TSK_CONTACT and TSK_CALLLOG information + for contact_and_calllog_db in contact_and_calllog_dbs: + blackboard_util = BlackboardUtil(self._PARSER_NAME, contact_and_calllog_db.getDBFile(), Account.Type.VIBER) + + contacts_parser = ViberContactsParser(contact_and_calllog_db) + while contacts_parser.next(): + blackboard_util.addContact( + contacts_parser.get_account_name(), + contacts_parser.get_contact_name(), + contacts_parser.get_phone(), + contacts_parser.get_home_phone(), + contacts_parser.get_mobile_phone(), + contacts_parser.get_email() + ) + contacts_parser.close() + calllog_parser = ViberCallLogsParser(contact_and_calllog_db) + while calllog_parser.next(): + blackboard_util.addCalllog( + calllog_parser.get_account_name(), + calllog_parser.get_call_direction(), + calllog_parser.get_phone_number_from(), + calllog_parser.get_phone_number_to(), + calllog_parser.get_call_start_date_time(), + calllog_parser.get_call_end_date_time(), + calllog_parser.get_contact_name() + ) + calllog_parser.close() + + #Extract TSK_MESSAGE information + for message_db in message_dbs: + blackboard_util = BlackboardUtil(self._PARSER_NAME, message_db.getDBFile(), Account.Type.VIBER) + messages_parser = ViberMessagesParser(message_db) + while messages_parser.next(): + blackboard_util.addMessage( + messages_parser.get_account_id(), + messages_parser.get_message_type(), + messages_parser.get_message_direction(), + messages_parser.get_phone_number_from(), + messages_parser.get_phone_number_to(), + messages_parser.get_message_date_time(), + messages_parser.get_message_read_status(), + messages_parser.get_message_subject(), + messages_parser.get_message_text(), + messages_parser.get_thread_id() + ) + messages_parser.close() + except (SQLException, TskCoreException) as ex: + #Error parsing Viber db + self._logger.log(Level.WARNING, "Error parsing Viber Databases", ex) + self._logger.log(Level.WARNING, traceback.format_exec()) + +class ViberCallLogsParser(TskCallLogsParser): + """ + Extracts TSK_CALLLOG information from the Viber database. + TSK_CALLLOG fields that are not in the Viber database are given + a default value inherited from the super class. + """ + + def __init__(self, calllog_db): + super(ViberCallLogsParser, self).__init__(calllog_db.runQuery( + """ + SELECT C.canonized_number AS number, + C.type AS direction, + C.duration AS seconds, + C.date AS start_time + FROM calls AS C + """ + ) + ) + + self._OUTGOING_CALL = 2 + self._INCOMING_CALL = 1 + self._MISSED_CALL = 3 + + def get_phone_number_from(self): + if self.get_call_direction() == self.INCOMING_MSG_STRING: + return self.result_set.getString("number") + #Give default value if the call is outgoing, the device's # is not stored in the database. + return super(ViberCallLogsParser, self).get_phone_number_from() + + def get_phone_number_to(self): + if self.get_call_direction() == self.OUTGOING_MSG_STRING: + return self.result_set.getString("number") + #Give default value if the call is incoming, the device's # is not stored in the database. + return super(ViberCallLogsParser, self).get_phone_number_to() + + def get_call_direction(self): + direction = self.result_set.getInt("direction") + if direction == self._INCOMING_CALL or direction == self._MISSED_CALL: + return self.INCOMING_MSG_STRING + return self.OUTGOING_MSG_STRING + + def get_call_start_date_time(self): + return self.result_set.getLong("start_time") / 1000 + + def get_call_end_date_time(self): + start_time = self.get_call_start_date_time() + duration = self.result_set.getLong("seconds") + return start_time + duration + +class ViberContactsParser(TskContactsParser): + """ + Extracts TSK_CONTACT information from the Viber database. + TSK_CONTACT fields that are not in the Viber database are given a default value + inherited from the super class. + """ + + def __init__(self, contact_db): + super(ViberContactsParser, self).__init__(contact_db.runQuery( + """ + SELECT C.display_name AS name, + D.data2 AS number + FROM phonebookcontact AS C + JOIN phonebookdata AS D + ON C._id = D.contact_id + """ + ) + ) + + def get_account_name(self): + return self.result_set.getString("name") + + def get_contact_name(self): + return self.get_account_name() + + def get_phone(self): + return self.result_set.getString("number") + +class ViberMessagesParser(TskMessagesParser): + """ + Extract TSK_MESSAGE information from the Viber database. + TSK_CONTACT fields that are not in the Viber database are given a default value + inherited from the super class. + """ + + def __init__(self, message_db): + super(ViberMessagesParser, self).__init__(message_db.runQuery( + """ + SELECT FROM_RESULT.number AS from_number, + FROM_RESULT.viber_name AS from_name, + TO_RESULT.number AS to_number, + M.conversation_id AS thread_id, + M.body AS msg_content, + M.send_type AS direction, + M.msg_date AS msg_date, + M.unread AS read_status + FROM (SELECT P._id, + P.conversation_id, + PI.number, + PI.viber_name + FROM participants AS P + JOIN participants_info AS PI + ON P.participant_info_id = PI._id) AS FROM_RESULT + JOIN (SELECT P._id, + P.conversation_id, + PI.number + FROM participants AS P + JOIN participants_info AS PI + ON P.participant_info_id = PI._id) AS TO_RESULT + ON FROM_RESULT._id != TO_RESULT._id + AND FROM_RESULT.conversation_id = TO_RESULT.conversation_id + JOIN messages AS M + ON M.participant_id = FROM_RESULT._id + AND M.conversation_id = FROM_RESULT.conversation_id + """ + ) + ) + self._VIBER_MESSAGE_TYPE = "Viber Message" + self._INCOMING_MESSAGE_TYPE = 0 + self._OUTGOING_MESSAGE_TYPE = 1 + + def get_account_id(self): + name = self.result_set.getString("from_name") + if name is None or len(name) == 0: + return self.get_phone_number_from() + return name + + def get_message_type(self): + return self._VIBER_MESSAGE_TYPE + + def get_phone_number_from(self): + return self.result_set.getString("from_number") + + def get_message_direction(self): + direction = self.result_set.getInt("direction") + if direction == self._INCOMING_MESSAGE_TYPE: + return self.INCOMING_MSG_STRING + return self.OUTGOING_MSG_STRING + + def get_phone_number_to(self): + return self.result_set.getString("to_number") + + def get_message_date_time(self): + #transform from ms to seconds + return self.result_set.getLong("msg_date") / 1000 + + def get_message_read_status(self): + #Viber: 0 is read, 1 is unread. + #TSK_MESSAGE 1 is read, 0 is unread. + if self.get_message_direction() == self.INCOMING_MSG_STRING: + return 1 - self.result_set.getInt("read_status") + return super(ViberMessagesParser, self).get_message_read_status() + + def get_message_text(self): + return self.result_set.getString("msg_content") + + def get_thread_id(self): + return str(self.result_set.getInt("thread_id")) From 22968498b8942aae7e28bd62c759febb7045c4e0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 10 Sep 2019 18:16:24 -0400 Subject: [PATCH 04/56] Finished viber with new API changes --- .../android/TskMessagesParser.py | 18 ++-- InternalPythonModules/android/module.py | 3 +- InternalPythonModules/android/viber.py | 94 ++++++++++--------- 3 files changed, 60 insertions(+), 55 deletions(-) diff --git a/InternalPythonModules/android/TskMessagesParser.py b/InternalPythonModules/android/TskMessagesParser.py index 0346a203e7..e3edbb25c8 100644 --- a/InternalPythonModules/android/TskMessagesParser.py +++ b/InternalPythonModules/android/TskMessagesParser.py @@ -17,6 +17,8 @@ See the License for the specific language governing permissions and limitations under the License. """ from ResultSetIterator import ResultSetIterator +from org.sleuthkit.datamodel import Account +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper class TskMessagesParser(ResultSetIterator): """ @@ -31,14 +33,12 @@ class TskMessagesParser(ResultSetIterator): def __init__(self, result_set): super(TskMessagesParser, self).__init__(result_set) - self.INCOMING_MSG_STRING = "Incoming" - self.OUTGOING_MSG_STRING = "Outgoing" + self.INCOMING_MSG = "Incoming" + self.OUTGOING_MSG = "Outgoing" self._DEFAULT_TEXT = "" self._DEFAULT_LONG = -1L - self._DEFAULT_INT = -1 - - def get_account_id(self): - return self._DEFAULT_TEXT + self._DEFAULT_MSG_READ_STATUS = AppDBParserHelper.MessageReadStatusEnum.UNKNOWN + self._DEFAULT_ACCOUNT_ADDRESS = Account.Address("","") def get_message_type(self): return self._DEFAULT_TEXT @@ -47,16 +47,16 @@ class TskMessagesParser(ResultSetIterator): return self._DEFAULT_TEXT def get_phone_number_from(self): - return self._DEFAULT_TEXT + return self._DEFAULT_ACCOUNT_ADDRESS def get_phone_number_to(self): - return self._DEFAULT_TEXT + return self._DEFAULT_ACCOUNT_ADDRESS def get_message_date_time(self): return self._DEFAULT_LONG def get_message_read_status(self): - return self._DEFAULT_INT + return self._DEFAULT_MSG_READ_STATUS def get_message_subject(self): return self._DEFAULT_TEXT diff --git a/InternalPythonModules/android/module.py b/InternalPythonModules/android/module.py index 6430ec82be..b522704bac 100644 --- a/InternalPythonModules/android/module.py +++ b/InternalPythonModules/android/module.py @@ -47,6 +47,7 @@ import tangomessage import textmessage import wwfmessage import imo +import viber class AndroidModuleFactory(IngestModuleFactoryAdapter): @@ -91,7 +92,7 @@ class AndroidIngestModule(DataSourceIngestModule): analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(), tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), - cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer()] + cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer(), viber.ViberAnalyzer()] self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers") progressBar.switchToDeterminate(len(analyzers)) diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index 3a65382c3c..77a4560839 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -61,8 +61,8 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): """ try: - contact_and_calllog_dbs = SQLiteUtil.findAppDatabases(dataSource, "viber_data", self._VIBER_PACKAGE_NAME) - message_dbs = SQLiteUtil.findAppDatabases(dataSource, "viber_messages", self._VIBER_PACKAGE_NAME) + contact_and_calllog_dbs = SQLiteUtil.findAppDatabases(dataSource, "viber_data", True, self._VIBER_PACKAGE_NAME) + message_dbs = SQLiteUtil.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: @@ -91,6 +91,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): calllog_parser.get_contact_name() ) calllog_parser.close() + contact_and_calllog_db.close() #Extract TSK_MESSAGE information for message_db in message_dbs: @@ -98,7 +99,6 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): messages_parser = ViberMessagesParser(message_db) while messages_parser.next(): blackboard_util.addMessage( - messages_parser.get_account_id(), messages_parser.get_message_type(), messages_parser.get_message_direction(), messages_parser.get_phone_number_from(), @@ -110,6 +110,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): messages_parser.get_thread_id() ) messages_parser.close() + message_db.close() except (SQLException, TskCoreException) as ex: #Error parsing Viber db self._logger.log(Level.WARNING, "Error parsing Viber Databases", ex) @@ -138,6 +139,9 @@ class ViberCallLogsParser(TskCallLogsParser): self._INCOMING_CALL = 1 self._MISSED_CALL = 3 + def get_account_name(self): + return self.result_set.getString("number") + def get_phone_number_from(self): if self.get_call_direction() == self.INCOMING_MSG_STRING: return self.result_set.getString("number") @@ -184,10 +188,10 @@ class ViberContactsParser(TskContactsParser): ) def get_account_name(self): - return self.result_set.getString("name") + return self.result_set.getString("number") def get_contact_name(self): - return self.get_account_name() + return self.result_set.getString("name") def get_phone(self): return self.result_set.getString("number") @@ -202,32 +206,33 @@ class ViberMessagesParser(TskMessagesParser): def __init__(self, message_db): super(ViberMessagesParser, self).__init__(message_db.runQuery( """ - SELECT FROM_RESULT.number AS from_number, - FROM_RESULT.viber_name AS from_name, - TO_RESULT.number AS to_number, - M.conversation_id AS thread_id, - M.body AS msg_content, - M.send_type AS direction, - M.msg_date AS msg_date, - M.unread AS read_status - FROM (SELECT P._id, - P.conversation_id, - PI.number, - PI.viber_name - FROM participants AS P - JOIN participants_info AS PI - ON P.participant_info_id = PI._id) AS FROM_RESULT - JOIN (SELECT P._id, - P.conversation_id, - PI.number - FROM participants AS P - JOIN participants_info AS PI - ON P.participant_info_id = PI._id) AS TO_RESULT - ON FROM_RESULT._id != TO_RESULT._id - AND FROM_RESULT.conversation_id = TO_RESULT.conversation_id - JOIN messages AS M - ON M.participant_id = FROM_RESULT._id - AND M.conversation_id = FROM_RESULT.conversation_id + SELECT convo_participants.from_number AS from_number, + convo_participants.recipients AS recipients, + M.conversation_id AS thread_id, + M.body AS msg_content, + M.send_type AS direction, + M.msg_date AS msg_date, + M.unread AS read_status + FROM (SELECT *, + group_concat(TO_RESULT.number) AS recipients + FROM (SELECT P._id AS FROM_ID, + P.conversation_id, + PI.number AS FROM_NUMBER + FROM participants AS P + JOIN participants_info AS PI + ON P.participant_info_id = PI._id) AS FROM_RESULT + JOIN (SELECT P._id AS TO_ID, + P.conversation_id, + PI.number + FROM participants AS P + JOIN participants_info AS PI + ON P.participant_info_id = PI._id) AS TO_RESULT + ON FROM_RESULT.from_id != TO_RESULT.to_id + AND FROM_RESULT.conversation_id = TO_RESULT.conversation_id + GROUP BY FROM_RESULT.from_id) AS convo_participants + JOIN messages AS M + ON M.participant_id = convo_participants.from_id + AND M.conversation_id = convo_participants.conversation_id """ ) ) @@ -235,36 +240,35 @@ class ViberMessagesParser(TskMessagesParser): self._INCOMING_MESSAGE_TYPE = 0 self._OUTGOING_MESSAGE_TYPE = 1 - def get_account_id(self): - name = self.result_set.getString("from_name") - if name is None or len(name) == 0: - return self.get_phone_number_from() - return name - def get_message_type(self): return self._VIBER_MESSAGE_TYPE def get_phone_number_from(self): - return self.result_set.getString("from_number") + return Account.Address(self.result_set.getString("from_number"), + self.result_set.getString("from_number")) def get_message_direction(self): direction = self.result_set.getInt("direction") if direction == self._INCOMING_MESSAGE_TYPE: - return self.INCOMING_MSG_STRING - return self.OUTGOING_MSG_STRING + return self.INCOMING_MSG + return self.OUTGOING_MSG def get_phone_number_to(self): - return self.result_set.getString("to_number") + recipients = [] + for token in self.result_set.getString("recipients").split(","): + recipients.append(Account.Address(token, token)) + return recipients def get_message_date_time(self): #transform from ms to seconds return self.result_set.getLong("msg_date") / 1000 def get_message_read_status(self): - #Viber: 0 is read, 1 is unread. - #TSK_MESSAGE 1 is read, 0 is unread. - if self.get_message_direction() == self.INCOMING_MSG_STRING: - return 1 - self.result_set.getInt("read_status") + if self.get_message_direction() == self.INCOMING_MSG: + if self.result_set.getInt("read_status") == 0: + return BlackboardUtil.MessageReadStatusEnum.READ + else: + return BlackboardUtil.MessageReadStatusEnum.UNREAD return super(ViberMessagesParser, self).get_message_read_status() def get_message_text(self): From c03377b658acd7ea37e681f6ea85d423eb2e59b6 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 11 Sep 2019 09:43:55 -0400 Subject: [PATCH 05/56] Refactoring/code clean up --- .../android/TskCallLogsParser.py | 4 ++-- InternalPythonModules/android/viber.py | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/InternalPythonModules/android/TskCallLogsParser.py b/InternalPythonModules/android/TskCallLogsParser.py index 22b509d612..66ea27eee3 100644 --- a/InternalPythonModules/android/TskCallLogsParser.py +++ b/InternalPythonModules/android/TskCallLogsParser.py @@ -32,8 +32,8 @@ class TskCallLogsParser(ResultSetIterator): def __init__(self, result_set): super(TskCallLogsParser, self).__init__(result_set) - self.INCOMING_MSG_STRING = "Incoming" - self.OUTGOING_MSG_STRING = "Outgoing" + self.INCOMING_CALL = "Incoming" + self.OUTGOING_CALL = "Outgoing" self._DEFAULT_STRING = "" def get_account_name(self): diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index 77a4560839..1505b9956a 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -135,30 +135,30 @@ class ViberCallLogsParser(TskCallLogsParser): ) ) - self._OUTGOING_CALL = 2 - self._INCOMING_CALL = 1 - self._MISSED_CALL = 3 + self._OUTGOING_CALL_TYPE = 2 + self._INCOMING_CALL_TYPE = 1 + self._MISSED_CALL_TYPE = 3 def get_account_name(self): return self.result_set.getString("number") def get_phone_number_from(self): - if self.get_call_direction() == self.INCOMING_MSG_STRING: + if self.get_call_direction() == self.INCOMING_CALL: return self.result_set.getString("number") #Give default value if the call is outgoing, the device's # is not stored in the database. return super(ViberCallLogsParser, self).get_phone_number_from() def get_phone_number_to(self): - if self.get_call_direction() == self.OUTGOING_MSG_STRING: + if self.get_call_direction() == self.OUTGOING_CALL: return self.result_set.getString("number") #Give default value if the call is incoming, the device's # is not stored in the database. return super(ViberCallLogsParser, self).get_phone_number_to() def get_call_direction(self): direction = self.result_set.getInt("direction") - if direction == self._INCOMING_CALL or direction == self._MISSED_CALL: - return self.INCOMING_MSG_STRING - return self.OUTGOING_MSG_STRING + if direction == self._INCOMING_CALL_TYPE or direction == self._MISSED_CALL_TYPE: + return self.INCOMING_CALL + return self.OUTGOING_CALL def get_call_start_date_time(self): return self.result_set.getLong("start_time") / 1000 From 7ee98a04708f73a7a23aa2e53e732928fb5f2714 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 11 Sep 2019 10:17:48 -0400 Subject: [PATCH 06/56] More code cleaup --- InternalPythonModules/android/viber.py | 50 ++++++++++++++++---------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index 1505b9956a..64b9333432 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -29,8 +29,8 @@ from java.util.logging import Level from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger -from org.sleuthkit.autopsy.coreutils import AppSQLiteDB as SQLiteUtil -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper as BlackboardUtil +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile from org.sleuthkit.datamodel import BlackboardArtifact @@ -47,7 +47,8 @@ import general class ViberAnalyzer(general.AndroidComponentAnalyzer): """ - Parses the Viber App databases for TSK contacts, message and calllog artifacts. + Parses the Viber App databases for TSK contacts, message + and calllog artifacts. """ def __init__(self): @@ -57,20 +58,24 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): def analyze(self, dataSource, fileManager, context): """ - Extract, Transform and Load all messages, contacts and calllogs from the Viber databases. + Extract, Transform and Load all messages, contacts and + calllogs from the Viber databases. """ try: - contact_and_calllog_dbs = SQLiteUtil.findAppDatabases(dataSource, "viber_data", True, self._VIBER_PACKAGE_NAME) - message_dbs = SQLiteUtil.findAppDatabases(dataSource, "viber_messages", True, self._VIBER_PACKAGE_NAME) + 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: - blackboard_util = BlackboardUtil(self._PARSER_NAME, contact_and_calllog_db.getDBFile(), Account.Type.VIBER) + parser_helper = AppDBParserHelper(self._PARSER_NAME, + contact_and_calllog_db.getDBFile(), Account.Type.VIBER) contacts_parser = ViberContactsParser(contact_and_calllog_db) while contacts_parser.next(): - blackboard_util.addContact( + parser_helper.addContact( contacts_parser.get_account_name(), contacts_parser.get_contact_name(), contacts_parser.get_phone(), @@ -79,9 +84,10 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): contacts_parser.get_email() ) contacts_parser.close() + calllog_parser = ViberCallLogsParser(contact_and_calllog_db) while calllog_parser.next(): - blackboard_util.addCalllog( + parser_helper.addCalllog( calllog_parser.get_account_name(), calllog_parser.get_call_direction(), calllog_parser.get_phone_number_from(), @@ -91,14 +97,17 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): calllog_parser.get_contact_name() ) calllog_parser.close() + contact_and_calllog_db.close() #Extract TSK_MESSAGE information for message_db in message_dbs: - blackboard_util = BlackboardUtil(self._PARSER_NAME, message_db.getDBFile(), Account.Type.VIBER) + parser_helper = AppDBParserHelper(self._PARSER_NAME, + message_db.getDBFile(), Account.Type.VIBER) + messages_parser = ViberMessagesParser(message_db) while messages_parser.next(): - blackboard_util.addMessage( + parser_helper.addMessage( messages_parser.get_message_type(), messages_parser.get_message_direction(), messages_parser.get_phone_number_from(), @@ -110,6 +119,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): messages_parser.get_thread_id() ) messages_parser.close() + message_db.close() except (SQLException, TskCoreException) as ex: #Error parsing Viber db @@ -145,13 +155,15 @@ class ViberCallLogsParser(TskCallLogsParser): def get_phone_number_from(self): if self.get_call_direction() == self.INCOMING_CALL: return self.result_set.getString("number") - #Give default value if the call is outgoing, the device's # is not stored in the database. + #Give default value if the call is outgoing, + #the device's # is not stored in the database. return super(ViberCallLogsParser, self).get_phone_number_from() def get_phone_number_to(self): if self.get_call_direction() == self.OUTGOING_CALL: return self.result_set.getString("number") - #Give default value if the call is incoming, the device's # is not stored in the database. + #Give default value if the call is incoming, + #the device's # is not stored in the database. return super(ViberCallLogsParser, self).get_phone_number_to() def get_call_direction(self): @@ -171,8 +183,8 @@ class ViberCallLogsParser(TskCallLogsParser): class ViberContactsParser(TskContactsParser): """ Extracts TSK_CONTACT information from the Viber database. - TSK_CONTACT fields that are not in the Viber database are given a default value - inherited from the super class. + TSK_CONTACT fields that are not in the Viber database are given + a default value inherited from the super class. """ def __init__(self, contact_db): @@ -199,8 +211,8 @@ class ViberContactsParser(TskContactsParser): class ViberMessagesParser(TskMessagesParser): """ Extract TSK_MESSAGE information from the Viber database. - TSK_CONTACT fields that are not in the Viber database are given a default value - inherited from the super class. + TSK_CONTACT fields that are not in the Viber database are given + a default value inherited from the super class. """ def __init__(self, message_db): @@ -266,9 +278,9 @@ class ViberMessagesParser(TskMessagesParser): def get_message_read_status(self): if self.get_message_direction() == self.INCOMING_MSG: if self.result_set.getInt("read_status") == 0: - return BlackboardUtil.MessageReadStatusEnum.READ + return AppDBParserHelper.MessageReadStatusEnum.READ else: - return BlackboardUtil.MessageReadStatusEnum.UNREAD + return AppDBParserHelper.MessageReadStatusEnum.UNREAD return super(ViberMessagesParser, self).get_message_read_status() def get_message_text(self): From 97dc26f4d903123509316a3e31e03f0eed8e7c51 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 11 Sep 2019 11:09:56 -0400 Subject: [PATCH 07/56] comments --- InternalPythonModules/android/viber.py | 30 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index 64b9333432..0fd9a43e22 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -70,12 +70,12 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): #Extract TSK_CONTACT and TSK_CALLLOG information for contact_and_calllog_db in contact_and_calllog_dbs: - parser_helper = AppDBParserHelper(self._PARSER_NAME, + helper = AppDBParserHelper(self._PARSER_NAME, contact_and_calllog_db.getDBFile(), Account.Type.VIBER) contacts_parser = ViberContactsParser(contact_and_calllog_db) while contacts_parser.next(): - parser_helper.addContact( + helper.addContact( contacts_parser.get_account_name(), contacts_parser.get_contact_name(), contacts_parser.get_phone(), @@ -87,7 +87,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): calllog_parser = ViberCallLogsParser(contact_and_calllog_db) while calllog_parser.next(): - parser_helper.addCalllog( + helper.addCalllog( calllog_parser.get_account_name(), calllog_parser.get_call_direction(), calllog_parser.get_phone_number_from(), @@ -102,12 +102,12 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): #Extract TSK_MESSAGE information for message_db in message_dbs: - parser_helper = AppDBParserHelper(self._PARSER_NAME, + helper = AppDBParserHelper(self._PARSER_NAME, message_db.getDBFile(), Account.Type.VIBER) messages_parser = ViberMessagesParser(message_db) while messages_parser.next(): - parser_helper.addMessage( + helper.addMessage( messages_parser.get_message_type(), messages_parser.get_message_direction(), messages_parser.get_phone_number_from(), @@ -216,6 +216,26 @@ class ViberMessagesParser(TskMessagesParser): """ def __init__(self, message_db): + """ + For our purposes, the Viber datamodel is as follows: + - People can take part in N conversation(s). A conversation can have N + members and messages are exchanged in a conversation. + - Viber has a conversation table, a participant table (the people/members in the above + analogy) and a messages table. + - Each row of the participants table maps a person to a conversation_id + - Each row in the messages table has a from participant id and a conversation id. + + The query below does the following: + - The first two inner joins on participants and participants_info build + the 1 to many (N) mappings between the sender and the recipients for each + conversation_id. If a and b do private messaging, then 2 rows in the result + will be a -> b and b -> a. + If a, b, c, d are in a group, then 4 rows containing a -> b,c,d. b -> a,c,d. etc. + Participants_info is needed to get phone numbers. + - The result of the above step is a look up table for each message. Joining this result + onto the messages table lets us know which participant a message originated from and + everyone else that received it. + """ super(ViberMessagesParser, self).__init__(message_db.runQuery( """ SELECT convo_participants.from_number AS from_number, From db467414ba9d6dcf5474a2dec116eb6e616e979c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 11 Sep 2019 11:12:25 -0400 Subject: [PATCH 08/56] updated comments --- InternalPythonModules/android/viber.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index 0fd9a43e22..9f02cb7bfb 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -218,7 +218,7 @@ class ViberMessagesParser(TskMessagesParser): def __init__(self, message_db): """ For our purposes, the Viber datamodel is as follows: - - People can take part in N conversation(s). A conversation can have N + - People can take part in N conversation(s). A conversation can have M members and messages are exchanged in a conversation. - Viber has a conversation table, a participant table (the people/members in the above analogy) and a messages table. @@ -227,7 +227,7 @@ class ViberMessagesParser(TskMessagesParser): The query below does the following: - The first two inner joins on participants and participants_info build - the 1 to many (N) mappings between the sender and the recipients for each + the 1 to many (M) mappings between the sender and the recipients for each conversation_id. If a and b do private messaging, then 2 rows in the result will be a -> b and b -> a. If a, b, c, d are in a group, then 4 rows containing a -> b,c,d. b -> a,c,d. etc. From 0580ffdd2fb47b23d5adc6c0a060fc9a15e661ab Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 11 Sep 2019 16:39:48 -0400 Subject: [PATCH 09/56] Merged lasted helper code and updated viber.py to conform --- .../android/TskCallLogsParser.py | 25 ++++++++----- .../android/TskMessagesParser.py | 10 +++-- InternalPythonModules/android/viber.py | 37 ++++++++++++------- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/InternalPythonModules/android/TskCallLogsParser.py b/InternalPythonModules/android/TskCallLogsParser.py index 66ea27eee3..3bc0e0141b 100644 --- a/InternalPythonModules/android/TskCallLogsParser.py +++ b/InternalPythonModules/android/TskCallLogsParser.py @@ -17,6 +17,8 @@ See the License for the specific language governing permissions and limitations under the License. """ from ResultSetIterator import ResultSetIterator +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.datamodel import Account class TskCallLogsParser(ResultSetIterator): """ @@ -32,27 +34,30 @@ class TskCallLogsParser(ResultSetIterator): def __init__(self, result_set): super(TskCallLogsParser, self).__init__(result_set) - self.INCOMING_CALL = "Incoming" - self.OUTGOING_CALL = "Outgoing" self._DEFAULT_STRING = "" + self._DEFAULT_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN + self._DEFAULT_ADDRESS = Account.Address("","") + self._DEFAULT_CALL_TYPE = AppDBParserHelper.CallMediaType.UNKNOWN - def get_account_name(self): - return self._DEFAULT_STRING + self.INCOMING_CALL = AppDBParserHelper.CommunicationDirection.INCOMING + self.OUTGOING_CALL = AppDBParserHelper.CommunicationDirection.OUTGOING + self.AUDIO_CALL = AppDBParserHelper.CallMediaType.AUDIO + self.VIDEO_CALL = AppDBParserHelper.CallMediaType.VIDEO def get_call_direction(self): - return self._DEFAULT_STRING + return self._DEFAULT_DIRECTION def get_phone_number_from(self): - return self._DEFAULT_STRING + return self._DEFAULT_ADDRESS def get_phone_number_to(self): - return self._DEFAULT_STRING + return self._DEFAULT_ADDRESS def get_call_start_date_time(self): return self._DEFAULT_LONG def get_call_end_date_time(self): return self._DEFAULT_LONG - - def get_contact_name(self): - return self._DEFAULT_STRING + + def get_call_type(self): + return self._DEFAULT_CALL_TYPE diff --git a/InternalPythonModules/android/TskMessagesParser.py b/InternalPythonModules/android/TskMessagesParser.py index e3edbb25c8..69d05cd6fe 100644 --- a/InternalPythonModules/android/TskMessagesParser.py +++ b/InternalPythonModules/android/TskMessagesParser.py @@ -33,18 +33,22 @@ class TskMessagesParser(ResultSetIterator): def __init__(self, result_set): super(TskMessagesParser, self).__init__(result_set) - self.INCOMING_MSG = "Incoming" - self.OUTGOING_MSG = "Outgoing" self._DEFAULT_TEXT = "" self._DEFAULT_LONG = -1L self._DEFAULT_MSG_READ_STATUS = AppDBParserHelper.MessageReadStatusEnum.UNKNOWN self._DEFAULT_ACCOUNT_ADDRESS = Account.Address("","") + self._DEFAULT_COMMUNICATION_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN + + self.INCOMING = AppDBParserHelper.CommunicationDirection.INCOMING + self.OUTGOING = AppDBParserHelper.CommunicationDirection.OUTGOING + self.READ = AppDBParserHelper.MessageReadStatusEnum.READ + self.UNREAD = AppDBParserHelper.MessageReadStatusEnum.UNREAD def get_message_type(self): return self._DEFAULT_TEXT def get_message_direction(self): - return self._DEFAULT_TEXT + return self._DEFAULT_COMMUNICATION_DIRECTION def get_phone_number_from(self): return self._DEFAULT_ACCOUNT_ADDRESS diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index 9f02cb7bfb..a8442a2931 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -88,13 +88,12 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): calllog_parser = ViberCallLogsParser(contact_and_calllog_db) while calllog_parser.next(): helper.addCalllog( - calllog_parser.get_account_name(), calllog_parser.get_call_direction(), calllog_parser.get_phone_number_from(), calllog_parser.get_phone_number_to(), calllog_parser.get_call_start_date_time(), calllog_parser.get_call_end_date_time(), - calllog_parser.get_contact_name() + calllog_parser.get_call_type() ) calllog_parser.close() @@ -139,7 +138,8 @@ class ViberCallLogsParser(TskCallLogsParser): SELECT C.canonized_number AS number, C.type AS direction, C.duration AS seconds, - C.date AS start_time + C.date AS start_time, + C.viber_call_type AS call_type FROM calls AS C """ ) @@ -148,20 +148,21 @@ class ViberCallLogsParser(TskCallLogsParser): self._OUTGOING_CALL_TYPE = 2 self._INCOMING_CALL_TYPE = 1 self._MISSED_CALL_TYPE = 3 - - def get_account_name(self): - return self.result_set.getString("number") + self._AUDIO_CALL_TYPE = 1 + self._VIDEO_CALL_TYPE = 4 def get_phone_number_from(self): if self.get_call_direction() == self.INCOMING_CALL: - return self.result_set.getString("number") + return Account.Address(self.result_set.getString("number"), + self.result_set.getString("number")) #Give default value if the call is outgoing, #the device's # is not stored in the database. return super(ViberCallLogsParser, self).get_phone_number_from() def get_phone_number_to(self): if self.get_call_direction() == self.OUTGOING_CALL: - return self.result_set.getString("number") + return Account.Address(self.result_set.getString("number"), + self.result_set.getString("number")) #Give default value if the call is incoming, #the device's # is not stored in the database. return super(ViberCallLogsParser, self).get_phone_number_to() @@ -169,7 +170,7 @@ class ViberCallLogsParser(TskCallLogsParser): def get_call_direction(self): direction = self.result_set.getInt("direction") if direction == self._INCOMING_CALL_TYPE or direction == self._MISSED_CALL_TYPE: - return self.INCOMING_CALL + return self.INCOMING_CALL return self.OUTGOING_CALL def get_call_start_date_time(self): @@ -180,6 +181,14 @@ class ViberCallLogsParser(TskCallLogsParser): duration = self.result_set.getLong("seconds") return start_time + duration + def get_call_type(self): + call_type = self.result_set.getInt("call_type") + if call_type == self._AUDIO_CALL_TYPE: + return self.AUDIO_CALL + if call_type == self._VIDEO_CALL_TYPE: + return self.VIDEO_CALL + return super(ViberCallLogsParser, self).get_call_type() + class ViberContactsParser(TskContactsParser): """ Extracts TSK_CONTACT information from the Viber database. @@ -282,8 +291,8 @@ class ViberMessagesParser(TskMessagesParser): def get_message_direction(self): direction = self.result_set.getInt("direction") if direction == self._INCOMING_MESSAGE_TYPE: - return self.INCOMING_MSG - return self.OUTGOING_MSG + return self.INCOMING + return self.OUTGOING def get_phone_number_to(self): recipients = [] @@ -296,11 +305,11 @@ class ViberMessagesParser(TskMessagesParser): return self.result_set.getLong("msg_date") / 1000 def get_message_read_status(self): - if self.get_message_direction() == self.INCOMING_MSG: + if self.get_message_direction() == self.INCOMING: if self.result_set.getInt("read_status") == 0: - return AppDBParserHelper.MessageReadStatusEnum.READ + return self.READ else: - return AppDBParserHelper.MessageReadStatusEnum.UNREAD + return self.UNREAD return super(ViberMessagesParser, self).get_message_read_status() def get_message_text(self): From bf383af0664ec94c3463c3dbee0a38bbf8189a43 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 12 Sep 2019 07:45:19 -0400 Subject: [PATCH 10/56] 5446: Xender 5447: Zapya 5448: ShareIt --- InternalPythonModules/android/general.py | 15 +++ InternalPythonModules/android/module.py | 6 +- InternalPythonModules/android/shareit.py | 109 +++++++++++++++++++++ InternalPythonModules/android/xender.py | 117 +++++++++++++++++++++++ InternalPythonModules/android/zapya.py | 110 +++++++++++++++++++++ 5 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 InternalPythonModules/android/shareit.py create mode 100644 InternalPythonModules/android/xender.py create mode 100644 InternalPythonModules/android/zapya.py diff --git a/InternalPythonModules/android/general.py b/InternalPythonModules/android/general.py index 28c96be9b9..1d0832362b 100644 --- a/InternalPythonModules/android/general.py +++ b/InternalPythonModules/android/general.py @@ -26,3 +26,18 @@ class AndroidComponentAnalyzer: # The Analyzer should implement this method def analyze(self, dataSource, fileManager, context): raise NotImplementedError + + + +""" +A utility method to append list of attachments to msg body +""" +def appendAttachmentList(msgBody, attachmentsList): + body = msgBody + if attachmentsList: + body = body + "\n\n------------Attachments------------\n" + body = body + "\n".join(attachmentsList) + + return body + + diff --git a/InternalPythonModules/android/module.py b/InternalPythonModules/android/module.py index 6430ec82be..996059adbc 100644 --- a/InternalPythonModules/android/module.py +++ b/InternalPythonModules/android/module.py @@ -47,6 +47,9 @@ import tangomessage import textmessage import wwfmessage import imo +import xender +import zapya +import shareit class AndroidModuleFactory(IngestModuleFactoryAdapter): @@ -91,7 +94,8 @@ class AndroidIngestModule(DataSourceIngestModule): analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(), tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), - cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer()] + cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer(), + xender.XenderAnalyzer(), zapya.ZapyaAnalyzer(), shareit.ShareItAnalyzer()] self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers") progressBar.switchToDeterminate(len(analyzers)) diff --git a/InternalPythonModules/android/shareit.py b/InternalPythonModules/android/shareit.py new file mode 100644 index 0000000000..9d661fb9c0 --- /dev/null +++ b/InternalPythonModules/android/shareit.py @@ -0,0 +1,109 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Long +from java.lang import String +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from java.util import ArrayList +from org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import CommunicationDirection +from org.sleuthkit.autopsy.datamodel import ContentUtils +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel import Account + +import traceback +import general + +""" +Finds the SQLite DB for ShareIt, parses the DB for contacts & messages, +and adds artifacts to the case. +""" +class ShareItAnalyzer(general.AndroidComponentAnalyzer): + + moduleName = "ShareIT Analyzer" + progName = "ShareIt" + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "history.db", True, "com.lenovo.anyshare.gps") + for historyDb in historyDbs: + try: + historyDbHelper = AppDBParserHelper(self.moduleName, historyDb.getDBFile(), + Account.Type.SHAREIT) + + queryString = "SELECT history_type, device_id, device_name, description, timestamp, import_path FROM history" + historyResultSet = historyDb.runQuery(queryString) + if historyResultSet is not None: + while historyResultSet.next(): + direction = "" + fromAddress = None + toAdddress = None + + if (historyResultSet.getInt("history_type") == 1): + direction = CommunicationDirection.OUTGOING + toAddress = Account.Address(historyResultSet.getString("device_id"), historyResultSet.getString("device_name") ) + else: + direction = CommunicationDirection.INCOMING + fromAddress = Account.Address(historyResultSet.getString("device_id"), historyResultSet.getString("device_name") ) + + msgBody = "" # there is no body. + attachments = [historyResultSet.getString("import_path")] + msgBody = general.appendAttachmentList(msgBody, attachments) + + timeStamp = historyResultSet.getLong("timestamp") / 1000 + messageArtifact = transferDbHelper.addMessage( + "ShareIt Message", + direction, + fromAddress, + toAddress, + timeStamp, + AppDBParserHelper.MessageReadStatusEnum.UNKNOWN, + None, # subject + msgBody, + "" ) + + # TBD: add the file as attachment ?? + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query result for ShareIt history.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding artifacts.", ex) + finally: + historyDb.close() + + + diff --git a/InternalPythonModules/android/xender.py b/InternalPythonModules/android/xender.py new file mode 100644 index 0000000000..f3ea2ad2f3 --- /dev/null +++ b/InternalPythonModules/android/xender.py @@ -0,0 +1,117 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Long +from java.lang import String +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from java.util import ArrayList +from org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import CommunicationDirection +from org.sleuthkit.autopsy.datamodel import ContentUtils +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel import Account + +import traceback +import general + +""" +Finds the SQLite DB for Xender, parses the DB for contacts & messages, +and adds artifacts to the case. +""" +class XenderAnalyzer(general.AndroidComponentAnalyzer): + + moduleName = "Xender Analyzer" + progName = "Xender" + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + selfAccountAddress = None + transactionDbs = AppSQLiteDB.findAppDatabases(dataSource, "trans-history-db", True, "cn.xender") + for transactionDb in transactionDbs: + try: + # 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 selfAccountAddress: + selfAccountAddress = Account.Address(profilesResultSet.getString("device_id"), profilesResultSet.getString("nick_name")) + + transactionDbHelper = AppDBParserHelper(self.moduleName, transactionDb.getDBFile(), + Account.Type.XENDER, Account.Type.XENDER, selfAccountAddress ) + + 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 + fromAddress = None + toAdddress = None + + if (messagesResultSet.getInt("c_direction") == 1): + direction = CommunicationDirection.OUTGOING + toAddress = Account.Address(messagesResultSet.getString("r_device_id"), messagesResultSet.getString("r_name")) + else: + direction = CommunicationDirection.INCOMING + fromAddress = Account.Address(messagesResultSet.getString("s_device_id"), messagesResultSet.getString("s_name")) + + 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( + "Xender Message", + direction, + fromAddress, + toAddress, + timeStamp, + AppDBParserHelper.MessageReadStatusEnum.UNKNOWN, + None, + msgBody, + messagesResultSet.getString("c_session_id") ) + + # TBD: add the file as attachment ?? + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query result for profiles", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding artifacts.", ex) + finally: + transactionDb.close() + + + diff --git a/InternalPythonModules/android/zapya.py b/InternalPythonModules/android/zapya.py new file mode 100644 index 0000000000..9338e47440 --- /dev/null +++ b/InternalPythonModules/android/zapya.py @@ -0,0 +1,110 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Long +from java.lang import String +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from java.util import ArrayList +from org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import CommunicationDirection +from org.sleuthkit.autopsy.datamodel import ContentUtils +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel import Account + +import traceback +import general + +""" +Finds the SQLite DB for Zapya, parses the DB for contacts & messages, +and adds artifacts to the case. +""" +class ZapyaAnalyzer(general.AndroidComponentAnalyzer): + + moduleName = "Zapya Analyzer" + progName = "Zapya" + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + transferDbs = AppSQLiteDB.findAppDatabases(dataSource, "transfer20.db", True, "com.dewmobile.kuaiya.play") + for transferDb in transferDbs: + try: + transferDbHelper = AppDBParserHelper(self.moduleName, 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 + fromAddress = None + toAdddress = None + + if (transfersResultSet.getInt("direction") == 1): + direction = CommunicationDirection.OUTGOING + toAddress = Account.Address(transfersResultSet.getString("device"), transfersResultSet.getString("name") ) + else: + direction = CommunicationDirection.INCOMING + fromAddress = Account.Address(transfersResultSet.getString("device"), transfersResultSet.getString("name") ) + + msgBody = "" # there is no body. + attachments = [transfersResultSet.getString("path")] + msgBody = general.appendAttachmentList(msgBody, attachments) + + timeStamp = transfersResultSet.getLong("createtime") / 1000 + messageArtifact = transferDbHelper.addMessage( + "Zapya Message", + direction, + fromAddress, + toAddress, + timeStamp, + AppDBParserHelper.MessageReadStatusEnum.UNKNOWN, + None, + msgBody, + "" ) + + # TBD: add the file as attachment ?? + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query result for transfer", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding artifacts.", ex) + + finally: + transferDb.close() + + + From aa76afb25cce8befe5341e9a5494ccc1cb6008b0 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 12 Sep 2019 09:22:27 -0400 Subject: [PATCH 11/56] 5419: SBrowser 5439: Opera browser 5440: Orux Maps 5441: Installed Apps --- .../android/installedapps.py | 77 +++++++ InternalPythonModules/android/module.py | 10 +- InternalPythonModules/android/operabrowser.py | 194 ++++++++++++++++ InternalPythonModules/android/oruxmaps.py | 93 ++++++++ InternalPythonModules/android/sbrowser.py | 217 ++++++++++++++++++ 5 files changed, 590 insertions(+), 1 deletion(-) create mode 100644 InternalPythonModules/android/installedapps.py create mode 100644 InternalPythonModules/android/operabrowser.py create mode 100644 InternalPythonModules/android/oruxmaps.py create mode 100644 InternalPythonModules/android/sbrowser.py diff --git a/InternalPythonModules/android/installedapps.py b/InternalPythonModules/android/installedapps.py new file mode 100644 index 0000000000..4f9f32d30a --- /dev/null +++ b/InternalPythonModules/android/installedapps.py @@ -0,0 +1,77 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Long +from java.lang import String +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from java.util import ArrayList +from org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.autopsy.datamodel import ContentUtils +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException + +import traceback +import general + +""" +Finds the SQLite DB for Android installed applications, parses the DB, +and adds artifacts to the case. +""" +class InstalledApplicationsAnalyzer(general.AndroidComponentAnalyzer): + + moduleName = "Android Installed Applications Analyzer" + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + libraryDbs = AppSQLiteDB.findAppDatabases(dataSource, "library.db", True, "com.android.vending") + for libraryDb in libraryDbs: + try: + libraryDbHelper = AppDBParserHelper(self.moduleName, 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.SEVERE, "Error processing query result for installed applications. ", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding installed applications.", ex) + finally: + libraryDb.close() + diff --git a/InternalPythonModules/android/module.py b/InternalPythonModules/android/module.py index 996059adbc..6ce91f419a 100644 --- a/InternalPythonModules/android/module.py +++ b/InternalPythonModules/android/module.py @@ -50,6 +50,11 @@ import imo import xender import zapya import shareit +import sbrowser +import operabrowser +import oruxmaps +import installedapps + class AndroidModuleFactory(IngestModuleFactoryAdapter): @@ -95,7 +100,10 @@ class AndroidIngestModule(DataSourceIngestModule): tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer(), - xender.XenderAnalyzer(), zapya.ZapyaAnalyzer(), shareit.ShareItAnalyzer()] + xender.XenderAnalyzer(), zapya.ZapyaAnalyzer(), shareit.ShareItAnalyzer(), + sbrowser.SBrowserAnalyzer(), operabrowser.OperaAnalyzer(), + oruxmaps.OruxMapsAnalyzer(), + installedapps.InstalledApplicationsAnalyzer()] self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers") progressBar.switchToDeterminate(len(analyzers)) diff --git a/InternalPythonModules/android/operabrowser.py b/InternalPythonModules/android/operabrowser.py new file mode 100644 index 0000000000..a67cfd2992 --- /dev/null +++ b/InternalPythonModules/android/operabrowser.py @@ -0,0 +1,194 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Long +from java.lang import String +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from java.util import ArrayList +from org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.autopsy.datamodel import ContentUtils +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException + +import traceback +import general + +""" +Finds the SQLite DB for Opera browser, parses the DB for Bookmarks, Cookies, Web History +and adds artifacts to the case. +""" +class OperaAnalyzer(general.AndroidComponentAnalyzer): + + moduleName = "Opera Parser" + progName = "Opera" + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyzeCookies(self, dataSource, fileManager, context): + cookiesDbs = AppSQLiteDB.findAppDatabases(dataSource, "Cookies", True, "com.opera.browser") + for cookiesDb in cookiesDbs: + try: + cookiesDbHelper = AppDBParserHelper(self.moduleName, cookiesDb.getDBFile()) + cookiesResultSet = cookiesDb.runQuery("SELECT host_key, name, value, creation_utc FROM cookies") + if cookiesResultSet is not None: + while cookiesResultSet.next(): + createTime = cookiesResultSet.getLong("creation_utc") / 1000000 - 11644473600 # Webkit time + cookiesDbHelper.addWebCookie( cookiesResultSet.getString("host_key"), + createTime, + cookiesResultSet.getString("name"), + cookiesResultSet.getString("value"), + self.progName) + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for Opera cookies.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera cookies.", ex) + finally: + cookiesDb.close() + + + + def analyzeHistory(self, dataSource, fileManager, context): + historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.opera.browser") + for historyDb in historyDbs: + try: + historyDbHelper = AppDBParserHelper(self.moduleName, historyDb.getDBFile()) + historyResultSet = historyDb.runQuery("SELECT url, title, last_visit_time FROM urls") + if historyResultSet is not None: + while historyResultSet.next(): + accessTime = historyResultSet.getLong("last_visit_time") / 1000000 - 11644473600 + historyDbHelper.addWebHistory( historyResultSet.getString("url"), + accessTime, + "", # referrer + historyResultSet.getString("title"), + self.progName) + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for Opera history.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera history.", ex) + finally: + historyDb.close() + + + + def analyzeDownloads(self, dataSource, fileManager, context): + downloadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.opera.browser") + for downloadsDb in downloadsDbs: + try: + downloadsDbHelper = AppDBParserHelper(self.moduleName, downloadsDb.getDBFile()) + queryString = "SELECT target_path, start_time, url FROM downloads"\ + " INNER JOIN downloads_url_chains ON downloads.id = downloads_url_chains.id" + downloadsResultSet = downloadsDb.runQuery(queryString) + if downloadsResultSet is not None: + while downloadsResultSet.next(): + startTime = historyResultSet.getLong("start_time") / 1000000 - 11644473600 #Webkit time format + downloadsDbHelper.addWebDownload( downloadsResultSet.getString("target_path"), + startTime, + downloadsResultSet.getString("url"), + self.progName) + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for Opera downloads.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera downloads.", ex) + finally: + downloadsDb.close() + + def analyzeAutofill(self, dataSource, fileManager, context): + autofillDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.opera.browser") + for autofillDb in autofillDbs: + try: + autofillDbHelper = AppDBParserHelper(self.moduleName, autofillDb.getDBFile()) + autofillsResultSet = autofillDb.runQuery("SELECT name, value, count, date_created FROM autofill") + if autofillsResultSet is not None: + while autofillsResultSet.next(): + creationTime = autofillsResultSet.getLong("date_created") / 1000000 - 11644473600 #Webkit time format + autofillDbHelper.addWebFormAutofill( autofillsResultSet.getString("name"), + autofillsResultSet.getString("value"), + creationTime, + 0, + autofillsResultSet.getInt("count")) + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for Opera autofill.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera autofill.", ex) + finally: + autofillDb.close() + + def analyzeWebFormAddress(self, dataSource, fileManager, context): + webFormAddressDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.opera.browser") + for webFormAddressDb in webFormAddressDbs: + try: + webFormAddressDbHelper = AppDBParserHelper(self.moduleName, webFormAddressDb.getDBFile()) + queryString = "SELECT street_address, city, state, zipcode, country_code, date_modified, first_name, last_name, number, email FROM autofill_profiles "\ + " INNER JOIN autofill_profile_names"\ + " ON autofill_profiles.guid = autofill_profile_names.guid"\ + " INNER JOIN autofill_profile_phones"\ + " ON autofill_profiles.guid = autofill_profile_phones.guid"\ + " INNER JOIN autofill_profile_emails"\ + " ON autofill_profiles.guid = autofill_profile_emails.guid" + webFormAddressResultSet = webFormAddressDb.runQuery(queryString) + if webFormAddressResultSet is not None: + while webFormAddressResultSet.next(): + personName = webFormAddressResultSet.getString("first_name") + " " + webFormAddressResultSet.getString("last_name") + address = '\n'.join([ webFormAddressResultSet.getString("street_address"), + webFormAddressResultSet.getString("city"), + webFormAddressResultSet.getString("state") + " " + webFormAddressResultSet.getString("zipcode"), + webFormAddressResultSet.getString("country_code") ]) + + creationTime = webFormAddressResultSet.getLong("date_modified") / 1000000 - 11644473600 + autofillDbHelper.addWebFormAddress( personName, + webFormAddressResultSet.getString("email"), + webFormAddressResultSet.getString("number"), + address, + creationTime, + 0, + 0) + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for Opera web form addresses.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera form addresses.", ex) + finally: + webFormAddressDb.close() + + def analyze(self, 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) + diff --git a/InternalPythonModules/android/oruxmaps.py b/InternalPythonModules/android/oruxmaps.py new file mode 100644 index 0000000000..5a7a94c078 --- /dev/null +++ b/InternalPythonModules/android/oruxmaps.py @@ -0,0 +1,93 @@ +""" +Autopsy Forensic Browser + +Copyright 2016-2018 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Double +from java.lang import Long +from java.sql import Connection +from java.sql import DriverManager +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from java.util import ArrayList +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule.services import FileManager +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.autopsy.datamodel import ContentUtils +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import Blackboard +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException + +import traceback +import general + +""" +Analyzes database created by ORUX Maps. +""" +class OruxMapsAnalyzer(general.AndroidComponentAnalyzer): + + moduleName = "Orux Maps Analyzer" + programName = "Orux Maps" + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + oruxMapsTrackpointsDbs = AppSQLiteDB.findAppDatabases(dataSource, "oruxmapstracks.db", True, "oruxmaps") + for oruxMapsTrackpointsDb in oruxMapsTrackpointsDbs: + try: + oruxDbHelper = AppDBParserHelper(self.moduleName, 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.programName) + + 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.programName) + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query result for Orux Map trackpoints.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Orux Map trackpoints.", ex) + finally: + oruxMapsTrackpointsDb.close() diff --git a/InternalPythonModules/android/sbrowser.py b/InternalPythonModules/android/sbrowser.py new file mode 100644 index 0000000000..fc0e5e6d42 --- /dev/null +++ b/InternalPythonModules/android/sbrowser.py @@ -0,0 +1,217 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Long +from java.lang import String +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from java.util import ArrayList +from org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.autopsy.datamodel import ContentUtils +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException + +import traceback +import general + +""" +Finds the SQLite DB for S-Browser, parses the DB for Bookmarks, Cookies, Web History +and adds artifacts to the case. +""" +class SBrowserAnalyzer(general.AndroidComponentAnalyzer): + + moduleName = "SBrowser Parser" + progName = "SBrowser" + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyzeBookmarks(self, dataSource, fileManager, context): + sbrowserDbs = AppSQLiteDB.findAppDatabases(dataSource, "sbrowser.db", True, "com.sec.android.app.sbrowser") + for sbrowserDb in sbrowserDbs: + try: + sbrowserDbHelper = AppDBParserHelper(self.moduleName, sbrowserDb.getDBFile()) + bookmarkResultSet = sbrowserDb.runQuery("SELECT url, title, created FROM bookmarks WHERE url IS NOT NULL") + if bookmarkResultSet is not None: + while bookmarkResultSet.next(): + createTime = bookmarkResultSet.getLong("created") / 1000 + sbrowserDbHelper.addWebBookmark( bookmarkResultSet.getString("url"), + bookmarkResultSet.getString("title"), + createTime, + self.progName) + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for SBrowser bookmarks.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding bookmarks.", ex) + finally: + sbrowserDb.close() + + + + def analyzeCookies(self, dataSource, fileManager, context): + cookiesDbs = AppSQLiteDB.findAppDatabases(dataSource, "Cookies", True, "com.sec.android.app.sbrowser") + for cookiesDb in cookiesDbs: + try: + cookiesDbHelper = AppDBParserHelper(self.moduleName, cookiesDb.getDBFile()) + cookiesResultSet = cookiesDb.runQuery("SELECT host_key, name, value, creation_utc FROM cookies") + if cookiesResultSet is not None: + while cookiesResultSet.next(): + createTime = cookiesResultSet.getLong("creation_utc") / 1000000 - 11644473600 # Webkit time + cookiesDbHelper.addWebCookie( cookiesResultSet.getString("host_key"), + createTime, + cookiesResultSet.getString("name"), + cookiesResultSet.getString("value"), + self.progName) + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for SBrowser cookies.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser cookies.", ex) + finally: + cookiesDb.close() + + + + def analyzeHistory(self, dataSource, fileManager, context): + historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.sec.android.app.sbrowser") + for historyDb in historyDbs: + try: + historyDbHelper = AppDBParserHelper(self.moduleName, historyDb.getDBFile()) + historyResultSet = historyDb.runQuery("SELECT url, title, last_visit_time FROM urls") + if historyResultSet is not None: + while historyResultSet.next(): + accessTime = historyResultSet.getLong("last_visit_time") / 1000000 - 11644473600 # Webkit time + historyDbHelper.addWebHistory( historyResultSet.getString("url"), + accessTime, + "", # referrer + historyResultSet.getString("title"), + self.progName) + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for SBrowser history.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser history.", ex) + finally: + historyDb.close() + + + + def analyzeDownloads(self, dataSource, fileManager, context): + downloadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.sec.android.app.sbrowser") + for downloadsDb in downloadsDbs: + try: + downloadsDbHelper = AppDBParserHelper(self.moduleName, downloadsDb.getDBFile()) + queryString = "SELECT target_path, start_time, url FROM downloads"\ + " INNER JOIN downloads_url_chains ON downloads.id = downloads_url_chains.id" + downloadsResultSet = downloadsDb.runQuery(queryString) + if downloadsResultSet is not None: + while downloadsResultSet.next(): + startTime = historyResultSet.getLong("start_time") / 1000000 - 11644473600 # Webkit time + downloadsDbHelper.addWebDownload( downloadsResultSet.getString("target_path"), + startTime, + downloadsResultSet.getString("url"), + self.progName) + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for SBrowser downloads.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser downloads.", ex) + finally: + downloadsDb.close() + + def analyzeAutofill(self, dataSource, fileManager, context): + autofillDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.sec.android.app.sbrowser") + for autofillDb in autofillDbs: + try: + autofillDbHelper = AppDBParserHelper(self.moduleName, autofillDb.getDBFile()) + autofillsResultSet = autofillDb.runQuery("SELECT name, value, count, date_created FROM autofill INNER JOIN autofill_dates ON autofill.pair_id = autofill_dates.pair_id") + if autofillsResultSet is not None: + while autofillsResultSet.next(): + creationTime = autofillsResultSet.getLong("date_created") / 1000000 - 11644473600 # Webkit time + autofillDbHelper.addWebFormAutofill( autofillsResultSet.getString("name"), + autofillsResultSet.getString("value"), + creationTime, + 0, + autofillsResultSet.getInt("count")) + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for SBrowser autofill.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser autofill.", ex) + finally: + autofillDb.close() + + def analyzeWebFormAddress(self, dataSource, fileManager, context): + webFormAddressDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.sec.android.app.sbrowser") + for webFormAddressDb in webFormAddressDbs: + try: + webFormAddressDbHelper = AppDBParserHelper(self.moduleName, webFormAddressDb.getDBFile()) + queryString = "SELECT street_address, city, state, zipcode, country_code, date_modified, first_name, last_name, number, email FROM autofill_profiles "\ + " INNER JOIN autofill_profile_names"\ + " ON autofill_profiles.guid = autofill_profile_names.guid"\ + " INNER JOIN autofill_profile_phones"\ + " ON autofill_profiles.guid = autofill_profile_phones.guid"\ + " INNER JOIN autofill_profile_emails"\ + " ON autofill_profiles.guid = autofill_profile_emails.guid" + webFormAddressResultSet = webFormAddressDb.runQuery(queryString) + if webFormAddressResultSet is not None: + while webFormAddressResultSet.next(): + personName = webFormAddressResultSet.getString("first_name") + " " + webFormAddressResultSet.getString("last_name") + address = '\n'.join([ webFormAddressResultSet.getString("street_address"), + webFormAddressResultSet.getString("city"), + webFormAddressResultSet.getString("state") + " " + webFormAddressResultSet.getString("zipcode"), + webFormAddressResultSet.getString("country_code") ]) + + creationTime = webFormAddressResultSet.getLong("date_modified") / 1000000 - 11644473600 # Webkit time + autofillDbHelper.addWebFormAddress( personName, + webFormAddressResultSet.getString("email"), + webFormAddressResultSet.getString("number"), + address, + creationTime, + 0, + 0) + + except SQLException as ex: + self._logger.log(Level.SEVERE, "Error processing query results for SBrowser form addresses.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser form addresses.", ex) + finally: + webFormAddressDb.close() + + def analyze(self, dataSource, fileManager, context): + 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) + From 6d1214261a0ad8354d8ecbbfdd9a3b0173965bb1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 13 Sep 2019 17:53:31 -0400 Subject: [PATCH 12/56] infra updates --- InternalPythonModules/android/TskCallLogsParser.py | 2 +- InternalPythonModules/android/TskMessagesParser.py | 2 +- InternalPythonModules/android/general.py | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/InternalPythonModules/android/TskCallLogsParser.py b/InternalPythonModules/android/TskCallLogsParser.py index 3bc0e0141b..763ba3c15f 100644 --- a/InternalPythonModules/android/TskCallLogsParser.py +++ b/InternalPythonModules/android/TskCallLogsParser.py @@ -36,7 +36,7 @@ class TskCallLogsParser(ResultSetIterator): super(TskCallLogsParser, self).__init__(result_set) self._DEFAULT_STRING = "" self._DEFAULT_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN - self._DEFAULT_ADDRESS = Account.Address("","") + self._DEFAULT_ADDRESS = None self._DEFAULT_CALL_TYPE = AppDBParserHelper.CallMediaType.UNKNOWN self.INCOMING_CALL = AppDBParserHelper.CommunicationDirection.INCOMING diff --git a/InternalPythonModules/android/TskMessagesParser.py b/InternalPythonModules/android/TskMessagesParser.py index 69d05cd6fe..15c4166db7 100644 --- a/InternalPythonModules/android/TskMessagesParser.py +++ b/InternalPythonModules/android/TskMessagesParser.py @@ -36,7 +36,7 @@ class TskMessagesParser(ResultSetIterator): self._DEFAULT_TEXT = "" self._DEFAULT_LONG = -1L self._DEFAULT_MSG_READ_STATUS = AppDBParserHelper.MessageReadStatusEnum.UNKNOWN - self._DEFAULT_ACCOUNT_ADDRESS = Account.Address("","") + self._DEFAULT_ACCOUNT_ADDRESS = None self._DEFAULT_COMMUNICATION_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN self.INCOMING = AppDBParserHelper.CommunicationDirection.INCOMING diff --git a/InternalPythonModules/android/general.py b/InternalPythonModules/android/general.py index 28c96be9b9..53c123d13c 100644 --- a/InternalPythonModules/android/general.py +++ b/InternalPythonModules/android/general.py @@ -26,3 +26,14 @@ class AndroidComponentAnalyzer: # The Analyzer should implement this method def analyze(self, dataSource, fileManager, context): raise NotImplementedError + +""" +A utility method to append list of attachments to msg body +""" +def appendAttachmentList(msgBody, attachmentsList): + body = msgBody + if attachmentsList: + body = body + "\n\n------------Attachments------------\n" + body = body + "\n".join(attachmentsList) + + return body From fa9210114a6087a7c65b3965893a32724a877ad3 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Sat, 14 Sep 2019 10:29:06 -0400 Subject: [PATCH 13/56] Added version number --- InternalPythonModules/android/viber.py | 1 + 1 file changed, 1 insertion(+) diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index a8442a2931..e6949b169e 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -55,6 +55,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): self._logger = Logger.getLogger(self.__class__.__name__) self._VIBER_PACKAGE_NAME = "com.viber.voip" self._PARSER_NAME = "Viber Parser" + self._VERSION = "11.5.0" def analyze(self, dataSource, fileManager, context): """ From 4ad1f211e040ea94db072b75fcc9e362d0036ddf Mon Sep 17 00:00:00 2001 From: Raman Date: Sun, 15 Sep 2019 09:09:43 -0400 Subject: [PATCH 14/56] 5437: FB Messenger parser --- InternalPythonModules/android/fbmessenger.py | 219 +++++++++++++++++++ InternalPythonModules/android/module.py | 4 +- 2 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 InternalPythonModules/android/fbmessenger.py diff --git a/InternalPythonModules/android/fbmessenger.py b/InternalPythonModules/android/fbmessenger.py new file mode 100644 index 0000000000..a5503d1a88 --- /dev/null +++ b/InternalPythonModules/android/fbmessenger.py @@ -0,0 +1,219 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Long +from java.lang import String +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from java.util import ArrayList +from org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import MessageReadStatusEnum +from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import CommunicationDirection +from org.sleuthkit.autopsy.datamodel import ContentUtils +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel import Account + +import json +import traceback +import general + +""" +Finds the SQLite DB for Facebook messenger, parses the DB for contacts & messages, +and adds artifacts to the case. +""" +class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): + + selfAccountAddress = None + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + ## Analyze contacts + def analyzeContacts(self, dataSource, fileManager, context): + ## FB messenger and FB have same database structure for contacts. + ## In our example the FB Messenger database was empty. + ## But the FB database had the data. + + contactsDbs = AppSQLiteDB.findAppDatabases(dataSource, "contacts_db2", True, "com.facebook.katana") + for contactsDb in contactsDbs: + try: + selfAccountResultSet = contactsDb.runQuery("SELECT fbid, display_name FROM contacts WHERE added_time_ms = 0") + if selfAccountResultSet: + + if not self.selfAccountAddress: + self.selfAccountAddress = Account.Address(selfAccountResultSet.getString("fbid"), selfAccountResultSet.getString("display_name")) + + contactsDBHelper = AppDBParserHelper("Facebook Parser", contactsDb.getDBFile(), + Account.Type.FACEBOOK, Account.Type.FACEBOOK, self.selfAccountAddress ) + contactsResultSet = contactsDb.runQuery("SELECT fbid, display_name FROM contacts WHERE added_time_ms <> " + self.selfAccountAddress.getUniqueID() ) + if contactsResultSet is not None: + while contactsResultSet.next(): + contactsDBHelper.addContact( contactsResultSet.getString("fbid"), ## unique id for account + contactsResultSet.getString("display_name"), ## contact name + "", ## phone + "", ## home phone + "", ## mobile + "") ## email + + except SQLException as ex: + self._logger.log(Level.WARNING, "Error processing query result for account", ex) + except TskCoreException as ex: + self._logger.log(Level.WARNING, "Failed to create AppDBParserHelper for adding Facebook contacts.", ex) + finally: + contactsDb.close() + + + + ## Adds a recipient to given list + def addRecipientToList(self, user_key, name, fromAddress, recipientList): + if user_key is not None: + recipientId = user_key.replace('FACEBOOK:', '') + toAddress = Account.Address(recipientId, name) + # ensure sender, if known, isn't added to recipientList. + if (fromAddress and fromAddress.getUniqueID() != toAddress.getUniqueID()) or (not fromAddress) : + # add recipient to list + recipientList.append(toAddress) + + ## Analyze messages + def analyzeMessages(self, dataSource, fileManager, context): + threadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "threads_db2", True, "com.facebook.orca") + for threadsDb in threadsDbs: + try: + threadsDBHelper = AppDBParserHelper("FB Messenger Parser", threadsDb.getDBFile(), + Account.Type.FACEBOOK, Account.Type.FACEBOOK, self.selfAccountAddress ) + + ## Messages are found in the messages table. The participant ids can be found in the thread_participants table. + ## Participant names are found in thread_users table. + sqlString = "SELECT msg_id, text, sender, timestamp_ms, messages.thread_key as thread_key,"\ + " snippet, thread_participants.user_key as user_key, thread_users.name as name 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"\ + " ORDER BY msg_id" + + messagesResultSet = threadsDb.runQuery(sqlString) + if messagesResultSet is not None: + oldMsgId = None + + direction = CommunicationDirection.UNKNOWN + fromAddress = None + recipientAddressList = None + timeStamp = -1 + msgText = "" + threadId = "" + + 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( + "FB Messenger Message", + direction, + fromAddress, + recipientAddressList, + timeStamp, + MessageReadStatusEnum.UNKNOWN, + "", + msgText, + threadId) + + oldMsgId = msgId + + # New message - collect all attributes + recipientAddressList = [] + + ## get sender address by parsing JSON in sender column + senderJsonStr = messagesResultSet.getString("sender") + if senderJsonStr is not None: + sender_dict = json.loads(senderJsonStr) + senderId = sender_dict['user_key'] + senderId = senderId.replace('FACEBOOK:', '') + senderName = sender_dict['name'] + fromAddress = Account.Address(senderId, senderName) + if senderId == self.selfAccountAddress.getUniqueID(): + direction = CommunicationDirection.OUTGOING + else: + direction = CommunicationDirection.INCOMING + + + # Get recipient and add to list + self.addRecipientToList(messagesResultSet.getString("user_key"), messagesResultSet.getString("name"), + fromAddress, recipientAddressList) + + timeStamp = messagesResultSet.getLong("timestamp_ms") / 1000 + + # Get msg text + # Sometimes there may not be an explict msg text, + # but a app genrated snippet instead + msgText = messagesResultSet.getString("text") + if not msgText: + msgText = messagesResultSet.getString("snippet") + + # TBD: get attachment + + threadId = messagesResultSet.getString("thread_key") + + + else: # same msgId as last, just collect recipient from current row + + self.addRecipientToList(messagesResultSet.getString("user_key"), messagesResultSet.getString("name"), + fromAddress, recipientAddressList) + + + # at the end of th loop, add last message + messageArtifact = threadsDBHelper.addMessage( + "FB Messenger Message", + direction, + fromAddress, + recipientAddressList, + timeStamp, + MessageReadStatusEnum.UNKNOWN, + "", + msgText, + threadId) + + except SQLException as ex: + self._logger.log(Level.WARNING, "Error processing query result for FB Messenger messages.", ex) + except TskCoreException as ex: + self._logger.log(Level.WARNING, "Failed to create AppDBParserHelper for adding FB Messenger messages.", ex) + finally: + threadsDb.close() + + def analyze(self, dataSource, fileManager, context): + self.analyzeContacts(dataSource, fileManager, context) + self.analyzeMessages(dataSource, fileManager, context) + + diff --git a/InternalPythonModules/android/module.py b/InternalPythonModules/android/module.py index 6430ec82be..c3c785537f 100644 --- a/InternalPythonModules/android/module.py +++ b/InternalPythonModules/android/module.py @@ -47,6 +47,7 @@ import tangomessage import textmessage import wwfmessage import imo +import fbmessenger class AndroidModuleFactory(IngestModuleFactoryAdapter): @@ -91,7 +92,8 @@ class AndroidIngestModule(DataSourceIngestModule): analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(), tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), - cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer()] + cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer(), + fbmessenger.FBMessengerAnalyzer()] self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers") progressBar.switchToDeterminate(len(analyzers)) From 296f18ce3c0f19ccc6eca402ecf399cce82edafe Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Sun, 15 Sep 2019 23:33:46 -0400 Subject: [PATCH 15/56] initial infra commit --- .../android/ResultSetIterator.py | 35 +++++++++ .../android/TskCallLogsParser.py | 64 +++++++++++++++++ .../android/TskContactsParser.py | 49 +++++++++++++ .../android/TskMessagesParser.py | 72 +++++++++++++++++++ InternalPythonModules/android/general.py | 11 +++ 5 files changed, 231 insertions(+) create mode 100644 InternalPythonModules/android/ResultSetIterator.py create mode 100644 InternalPythonModules/android/TskCallLogsParser.py create mode 100644 InternalPythonModules/android/TskContactsParser.py create mode 100644 InternalPythonModules/android/TskMessagesParser.py diff --git a/InternalPythonModules/android/ResultSetIterator.py b/InternalPythonModules/android/ResultSetIterator.py new file mode 100644 index 0000000000..4abd4438df --- /dev/null +++ b/InternalPythonModules/android/ResultSetIterator.py @@ -0,0 +1,35 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +class ResultSetIterator(object): + """ + Generic base class for iterating through database recordms + """ + + def __init__(self, result_set): + self.result_set = result_set + + def next(self): + if self.result_set is None: + return False + return self.result_set.next() + + def close(self): + if self.result_set is not None: + self.result_set.close() diff --git a/InternalPythonModules/android/TskCallLogsParser.py b/InternalPythonModules/android/TskCallLogsParser.py new file mode 100644 index 0000000000..8c61070693 --- /dev/null +++ b/InternalPythonModules/android/TskCallLogsParser.py @@ -0,0 +1,64 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from ResultSetIterator import ResultSetIterator +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.datamodel import Account + +class TskCallLogsParser(ResultSetIterator): + """ + Generic TSK_CALLLOG artifact template. Each of these methods + will contain the extraction and transformation logic for + converting raw database records to the expected TSK_CALLLOG + format. + + A simple example of data transformation would be computing + the end time of a call when the database only supplies the start + time and duration. + """ + + def __init__(self, result_set): + super(TskCallLogsParser, self).__init__(result_set) + self._DEFAULT_STRING = "" + self._DEFAULT_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN + self._DEFAULT_ADDRESS = None + self._DEFAULT_CALL_TYPE = AppDBParserHelper.CallMediaType.UNKNOWN + self._DEFAULT_LONG = -1 + + self.INCOMING_CALL = AppDBParserHelper.CommunicationDirection.INCOMING + self.OUTGOING_CALL = AppDBParserHelper.CommunicationDirection.OUTGOING + self.AUDIO_CALL = AppDBParserHelper.CallMediaType.AUDIO + self.VIDEO_CALL = AppDBParserHelper.CallMediaType.VIDEO + + def get_call_direction(self): + return self._DEFAULT_DIRECTION + + def get_phone_number_from(self): + return self._DEFAULT_ADDRESS + + def get_phone_number_to(self): + return self._DEFAULT_ADDRESS + + def get_call_start_date_time(self): + return self._DEFAULT_LONG + + def get_call_end_date_time(self): + return self._DEFAULT_LONG + + def get_call_type(self): + return self._DEFAULT_CALL_TYPE diff --git a/InternalPythonModules/android/TskContactsParser.py b/InternalPythonModules/android/TskContactsParser.py new file mode 100644 index 0000000000..122e6a9445 --- /dev/null +++ b/InternalPythonModules/android/TskContactsParser.py @@ -0,0 +1,49 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from ResultSetIterator import ResultSetIterator + +class TskContactsParser(ResultSetIterator): + """ + Generic TSK_CONTACT artifact template. Each of these methods + will contain the extraction and transformation logic for + converting raw database records to the expected TSK_CONTACT + format. + """ + + def __init__(self, result_set): + super(TskContactsParser, self).__init__(result_set) + self._DEFAULT_VALUE = "" + + def get_account_name(self): + return self._DEFAULT_VALUE + + def get_contact_name(self): + return self._DEFAULT_VALUE + + def get_phone(self): + return self._DEFAULT_VALUE + + def get_home_phone(self): + return self._DEFAULT_VALUE + + def get_mobile_phone(self): + return self._DEFAULT_VALUE + + def get_email(self): + return self._DEFAULT_VALUE diff --git a/InternalPythonModules/android/TskMessagesParser.py b/InternalPythonModules/android/TskMessagesParser.py new file mode 100644 index 0000000000..15c4166db7 --- /dev/null +++ b/InternalPythonModules/android/TskMessagesParser.py @@ -0,0 +1,72 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +from ResultSetIterator import ResultSetIterator +from org.sleuthkit.datamodel import Account +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper + +class TskMessagesParser(ResultSetIterator): + """ + Generic TSK_MESSAGE artifact template. Each of these methods + will contain the extraction and transformation logic for + converting raw database records to the expected TSK_MESSAGE + format. + + An easy example of such a transformation would be converting + message date time from milliseconds to seconds. + """ + + def __init__(self, result_set): + super(TskMessagesParser, self).__init__(result_set) + self._DEFAULT_TEXT = "" + self._DEFAULT_LONG = -1L + self._DEFAULT_MSG_READ_STATUS = AppDBParserHelper.MessageReadStatusEnum.UNKNOWN + self._DEFAULT_ACCOUNT_ADDRESS = None + self._DEFAULT_COMMUNICATION_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN + + self.INCOMING = AppDBParserHelper.CommunicationDirection.INCOMING + self.OUTGOING = AppDBParserHelper.CommunicationDirection.OUTGOING + self.READ = AppDBParserHelper.MessageReadStatusEnum.READ + self.UNREAD = AppDBParserHelper.MessageReadStatusEnum.UNREAD + + def get_message_type(self): + return self._DEFAULT_TEXT + + def get_message_direction(self): + return self._DEFAULT_COMMUNICATION_DIRECTION + + def get_phone_number_from(self): + return self._DEFAULT_ACCOUNT_ADDRESS + + def get_phone_number_to(self): + return self._DEFAULT_ACCOUNT_ADDRESS + + def get_message_date_time(self): + return self._DEFAULT_LONG + + def get_message_read_status(self): + return self._DEFAULT_MSG_READ_STATUS + + def get_message_subject(self): + return self._DEFAULT_TEXT + + def get_message_text(self): + return self._DEFAULT_TEXT + + def get_thread_id(self): + return self._DEFAULT_TEXT diff --git a/InternalPythonModules/android/general.py b/InternalPythonModules/android/general.py index 28c96be9b9..53c123d13c 100644 --- a/InternalPythonModules/android/general.py +++ b/InternalPythonModules/android/general.py @@ -26,3 +26,14 @@ class AndroidComponentAnalyzer: # The Analyzer should implement this method def analyze(self, dataSource, fileManager, context): raise NotImplementedError + +""" +A utility method to append list of attachments to msg body +""" +def appendAttachmentList(msgBody, attachmentsList): + body = msgBody + if attachmentsList: + body = body + "\n\n------------Attachments------------\n" + body = body + "\n".join(attachmentsList) + + return body From 8e95f1486253482a1bffe07de1cf03bde30ac011 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Sun, 15 Sep 2019 23:43:21 -0400 Subject: [PATCH 16/56] Initial skeleton commit --- InternalPythonModules/android/skype.py | 194 +++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 InternalPythonModules/android/skype.py diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py new file mode 100644 index 0000000000..bbf1afccc3 --- /dev/null +++ b/InternalPythonModules/android/skype.py @@ -0,0 +1,194 @@ +""" +Autopsy Forensic Browser + +Copyright 2019 Basis Technology Corp. +Contact: carrier sleuthkit org + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from java.io import File +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import Long +from java.lang import String +from java.sql import ResultSet +from java.sql import SQLException +from java.sql import Statement +from java.util.logging import Level +from org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import AppSQLiteDB +from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.datamodel import AbstractFile +from org.sleuthkit.datamodel import BlackboardArtifact +from org.sleuthkit.datamodel import BlackboardAttribute +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel import Account +from TskMessagesParser import TskMessagesParser +from TskContactsParser import TskContactsParser +from TskCallLogsParser import TskCallLogsParser + +import traceback +import general + +class SkypeAnalyzer(general.AndroidComponentAnalyzer): + """ + Parses the Viber App databases for TSK contacts, message + and calllog artifacts. + """ + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + self._SKYPE_PACKAGE_NAME = "" + self._PARSER_NAME = "Skype Parser" + self._VERSION = "" + + def analyze(self, dataSource, fileManager, context): + """ + Extract, Transform and Load all messages, contacts and + calllogs from the Skype databases. + """ + + try: + skype_dbs = AppSQLiteDB.findAppDatabases(dataSource, + "", True, self._SKYPE_PACKAGE_NAME) + + #Extract TSK_CONTACT and TSK_CALLLOG information + for skype_db in skype_dbs: + helper = AppDBParserHelper(self._PARSER_NAME, + contact_and_calllog_db.getDBFile(), Account.Type.SKYPE) + + contacts_parser = SkypeContactsParser(skype_db) + while contacts_parser.next(): + helper.addContact( + contacts_parser.get_account_name(), + contacts_parser.get_contact_name(), + contacts_parser.get_phone(), + contacts_parser.get_home_phone(), + contacts_parser.get_mobile_phone(), + contacts_parser.get_email() + ) + contacts_parser.close() + + calllog_parser = SkypeCallLogsParser(skype_db) + while calllog_parser.next(): + helper.addCalllog( + calllog_parser.get_call_direction(), + calllog_parser.get_phone_number_from(), + calllog_parser.get_phone_number_to(), + calllog_parser.get_call_start_date_time(), + calllog_parser.get_call_end_date_time(), + calllog_parser.get_call_type() + ) + calllog_parser.close() + + messages_parser = SkypeMessagesParser(skype_db) + while messages_parser.next(): + helper.addMessage( + messages_parser.get_message_type(), + messages_parser.get_message_direction(), + messages_parser.get_phone_number_from(), + messages_parser.get_phone_number_to(), + messages_parser.get_message_date_time(), + messages_parser.get_message_read_status(), + messages_parser.get_message_subject(), + messages_parser.get_message_text(), + messages_parser.get_thread_id() + ) + messages_parser.close() + + skype_db.close() + except (SQLException, TskCoreException) as ex: + #Error parsing Viber db + self._logger.log(Level.WARNING, "Error parsing Skype Databases", ex) + self._logger.log(Level.WARNING, traceback.format_exec()) + +class SkypeCallLogsParser(TskCallLogsParser): + """ + Extracts TSK_CALLLOG information from the Skype database. + TSK_CALLLOG fields that are not in the Skype database are given + a default value inherited from the super class. + """ + + def __init__(self, calllog_db): + super(SkypeCallLogsParser, self).__init__(calllog_db.runQuery( + """ + """ + ) + ) + + # def get_phone_number_from(self): + + # def get_phone_number_to(self): + + # def get_call_direction(self): + + # def get_call_start_date_time(self): + +# def get_call_end_date_time(self): + +# def get_call_type(self): + +class SkypeContactsParser(TskContactsParser): + """ + Extracts TSK_CONTACT information from the Skype database. + TSK_CONTACT fields that are not in the Skype database are given + a default value inherited from the super class. + """ + + def __init__(self, contact_db): + super(SkypeContactsParser, self).__init__(contact_db.runQuery( + """ + """ + ) + ) + +# def get_account_name(self): + +# def get_contact_name(self): + +# def get_phone(self): + +class SkypeMessagesParser(TskMessagesParser): + """ + Extract TSK_MESSAGE information from the Skype database. + TSK_CONTACT fields that are not in the Skype database are given + a default value inherited from the super class. + """ + + def __init__(self, message_db): + super(SkypeMessagesParser, self).__init__(message_db.runQuery( + """ + """ + ) + ) + + #def get_message_type(self): + + #def get_phone_number_from(self): + + #def get_message_direction(self): + + #def get_phone_number_to(self): + + #def get_message_date_time(self): + + #def get_message_read_status(self): + + #def get_message_text(self): + + #def get_thread_id(self): From 08ce5a4555852968b777b02210144250174cc980 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Mon, 16 Sep 2019 10:08:55 -0400 Subject: [PATCH 17/56] Implemented contacts and some of the call logs parsing --- InternalPythonModules/android/module.py | 3 +- InternalPythonModules/android/skype.py | 112 ++++++++++++++++++++---- 2 files changed, 96 insertions(+), 19 deletions(-) diff --git a/InternalPythonModules/android/module.py b/InternalPythonModules/android/module.py index 6430ec82be..796f4026da 100644 --- a/InternalPythonModules/android/module.py +++ b/InternalPythonModules/android/module.py @@ -47,6 +47,7 @@ import tangomessage import textmessage import wwfmessage import imo +import skype class AndroidModuleFactory(IngestModuleFactoryAdapter): @@ -91,7 +92,7 @@ class AndroidIngestModule(DataSourceIngestModule): analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(), tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), - cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer()] + cachelocation.CacheLocationAnalyzer(), imo.IMOAnalyzer(), skype.SkypeAnalyzer()] self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers") progressBar.switchToDeterminate(len(analyzers)) diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index bbf1afccc3..a4db7de556 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -53,9 +53,9 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): def __init__(self): self._logger = Logger.getLogger(self.__class__.__name__) - self._SKYPE_PACKAGE_NAME = "" + self._SKYPE_PACKAGE_NAME = "com.skype.raider" self._PARSER_NAME = "Skype Parser" - self._VERSION = "" + self._VERSION = "8.15.0.428" def analyze(self, dataSource, fileManager, context): """ @@ -65,12 +65,12 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): try: skype_dbs = AppSQLiteDB.findAppDatabases(dataSource, - "", True, self._SKYPE_PACKAGE_NAME) + "live", False, "") #self._SKYPE_PACKAGE_NAME) #Extract TSK_CONTACT and TSK_CALLLOG information for skype_db in skype_dbs: helper = AppDBParserHelper(self._PARSER_NAME, - contact_and_calllog_db.getDBFile(), Account.Type.SKYPE) + skype_db.getDBFile(), Account.Type.SKYPE) contacts_parser = SkypeContactsParser(skype_db) while contacts_parser.next(): @@ -83,7 +83,7 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): contacts_parser.get_email() ) contacts_parser.close() - + """ calllog_parser = SkypeCallLogsParser(skype_db) while calllog_parser.next(): helper.addCalllog( @@ -110,7 +110,7 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): messages_parser.get_thread_id() ) messages_parser.close() - + """ skype_db.close() except (SQLException, TskCoreException) as ex: #Error parsing Viber db @@ -127,21 +127,75 @@ class SkypeCallLogsParser(TskCallLogsParser): def __init__(self, calllog_db): super(SkypeCallLogsParser, self).__init__(calllog_db.runQuery( """ + SELECT full_contacts_list.id, + full_contacts_list.members, + full_contacts_list.names, + time, + duration, + is_sender_me, + person_id + FROM (SELECT conversation_id AS id , + Group_concat(person_id) AS members, + Group_concat(CASE + WHEN Ifnull(first_name, "") == "" + AND Ifnull(last_name,"") == "" THEN entry_id + WHEN Ifnull(first_name, "") == "" THEN last_name + WHEN Ifnull(last_name, "") == "" THEN first_name + ELSE first_name || " " || last_name + END) AS names + FROM particiapnt AS PART + JOIN person AS P + ON PART.person_id = P.entry_id + GROUP BY conversation_id + UNION + SELECT entry_id AS id, + NULL, + CASE + WHEN Ifnull(first_name, "") == "" + AND Ifnull(last_name, "") == "" THEN entry_id + WHEN Ifnull(first_name, "") == "" THEN last_name + WHEN Ifnull(last_name, "") == "" THEN first_name + ELSE first_name + || " " + || last_name + end AS name + FROM person) AS full_contacts_list + JOIN chatitem AS C + ON C.conversation_link = full_contacts_list.id + WHERE message_type == 3 """ ) ) + self._INCOMING_CALL_TYPE = 0 + self._OUTGOING_CALL_TYPE = 1 + - # def get_phone_number_from(self): + def get_phone_number_from(self): + if self.get_call_direction() == self._INCOMING_CALL_TYPE: + return Account.Address(self.result_set.getString("id"), + self.result_set.getString("names")) + return super(SkypeCallLogsParser, self).get_phone_number_from() - # def get_phone_number_to(self): + def get_phone_number_to(self): + if self.get_call_direction() == self._OUTGOING_CALL_TYPE: + return Account.Address(self.result_set.getString("id"), + self.result_set.getString("names")) + return super(SkypeCallLogsParser, self).get_phone_number_to() + - # def get_call_direction(self): + def get_call_direction(self): + direction = self.result_set.getInt("is_sender_me") + if direction == self._INCOMING_TYPE: + return self.INCOMING_CALL + return self.OUTGOING_CALL - # def get_call_start_date_time(self): + def get_call_start_date_time(self): + return self.result_set.getLong("time") / 1000 -# def get_call_end_date_time(self): - -# def get_call_type(self): + def get_call_end_date_time(self): + start = self.get_call_start_date_time() + duration = self.result_set.getInt("duration") / 1000 + return start + duration class SkypeContactsParser(TskContactsParser): """ @@ -153,15 +207,37 @@ class SkypeContactsParser(TskContactsParser): def __init__(self, contact_db): super(SkypeContactsParser, self).__init__(contact_db.runQuery( """ + SELECT entry_id, + CASE + WHEN Ifnull(first_name, "") == "" + AND Ifnull(last_name, "") == "" THEN entry_id + WHEN Ifnull(first_name, "") == "" THEN last_name + WHEN Ifnull(last_name, "") == "" THEN first_name + ELSE first_name + || " " + || last_name + end AS name + FROM person + union + SELECT entry_id, CASE + WHEN Ifnull(first_name, "") == "" + AND Ifnull(last_name, "") == "" THEN entry_id + WHEN Ifnull(first_name, "") == "" THEN last_name + WHEN Ifnull(last_name, "") == "" THEN first_name + ELSE first_name + || " " + || last_name + end AS name + FROM user """ - ) + ) ) -# def get_account_name(self): + def get_account_name(self): + return self.result_set.getString("entry_id") -# def get_contact_name(self): - -# def get_phone(self): + def get_contact_name(self): + return self.result_set.getString("name") class SkypeMessagesParser(TskMessagesParser): """ From cd38f57e4fd1f9c87df6391c6f06b0ab3c7851da Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 17 Sep 2019 12:47:29 -0400 Subject: [PATCH 18/56] 5446: Updated the Xender, Zapya & ShareIt parsers to match the latest helper definition and api. --- InternalPythonModules/android/shareit.py | 16 +++++++++------- InternalPythonModules/android/xender.py | 17 +++++++++-------- InternalPythonModules/android/zapya.py | 18 ++++++++++-------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/InternalPythonModules/android/shareit.py b/InternalPythonModules/android/shareit.py index 9d661fb9c0..ac359f51a3 100644 --- a/InternalPythonModules/android/shareit.py +++ b/InternalPythonModules/android/shareit.py @@ -32,8 +32,6 @@ from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper -from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import CommunicationDirection from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile @@ -42,6 +40,9 @@ from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import Account +from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection import traceback import general @@ -62,8 +63,9 @@ class ShareItAnalyzer(general.AndroidComponentAnalyzer): historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "history.db", True, "com.lenovo.anyshare.gps") for historyDb in historyDbs: try: - historyDbHelper = AppDBParserHelper(self.moduleName, historyDb.getDBFile(), - Account.Type.SHAREIT) + historyDbHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, historyDb.getDBFile(), + Account.Type.SHAREIT) queryString = "SELECT history_type, device_id, device_name, description, timestamp, import_path FROM history" historyResultSet = historyDb.runQuery(queryString) @@ -91,7 +93,7 @@ class ShareItAnalyzer(general.AndroidComponentAnalyzer): fromAddress, toAddress, timeStamp, - AppDBParserHelper.MessageReadStatusEnum.UNKNOWN, + MessageReadStatus.UNKNOWN, None, # subject msgBody, "" ) @@ -99,9 +101,9 @@ class ShareItAnalyzer(general.AndroidComponentAnalyzer): # TBD: add the file as attachment ?? except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query result for ShareIt history.", ex) + self._logger.log(Level.WARNING, "Error processing query result for ShareIt history.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding artifacts.", ex) + self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding artifacts.", ex) finally: historyDb.close() diff --git a/InternalPythonModules/android/xender.py b/InternalPythonModules/android/xender.py index f3ea2ad2f3..b59f18dce3 100644 --- a/InternalPythonModules/android/xender.py +++ b/InternalPythonModules/android/xender.py @@ -32,8 +32,6 @@ from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper -from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import CommunicationDirection from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile @@ -42,7 +40,9 @@ from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import Account - +from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection import traceback import general @@ -70,8 +70,9 @@ class XenderAnalyzer(general.AndroidComponentAnalyzer): if not selfAccountAddress: selfAccountAddress = Account.Address(profilesResultSet.getString("device_id"), profilesResultSet.getString("nick_name")) - transactionDbHelper = AppDBParserHelper(self.moduleName, transactionDb.getDBFile(), - Account.Type.XENDER, Account.Type.XENDER, selfAccountAddress ) + transactionDbHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, transactionDb.getDBFile(), + Account.Type.XENDER, Account.Type.XENDER, selfAccountAddress ) 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) @@ -99,7 +100,7 @@ class XenderAnalyzer(general.AndroidComponentAnalyzer): fromAddress, toAddress, timeStamp, - AppDBParserHelper.MessageReadStatusEnum.UNKNOWN, + MessageReadStatus.UNKNOWN, None, msgBody, messagesResultSet.getString("c_session_id") ) @@ -107,9 +108,9 @@ class XenderAnalyzer(general.AndroidComponentAnalyzer): # TBD: add the file as attachment ?? except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query result for profiles", ex) + self._logger.log(Level.WARNING, "Error processing query result for profiles", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding artifacts.", ex) + self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding artifacts.", ex) finally: transactionDb.close() diff --git a/InternalPythonModules/android/zapya.py b/InternalPythonModules/android/zapya.py index 9338e47440..fed51dd27d 100644 --- a/InternalPythonModules/android/zapya.py +++ b/InternalPythonModules/android/zapya.py @@ -32,8 +32,6 @@ from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper -from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import CommunicationDirection from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile @@ -42,6 +40,9 @@ from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import Account +from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection import traceback import general @@ -62,8 +63,9 @@ class ZapyaAnalyzer(general.AndroidComponentAnalyzer): transferDbs = AppSQLiteDB.findAppDatabases(dataSource, "transfer20.db", True, "com.dewmobile.kuaiya.play") for transferDb in transferDbs: try: - transferDbHelper = AppDBParserHelper(self.moduleName, transferDb.getDBFile(), - Account.Type.ZAPYA) + transferDbHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, transferDb.getDBFile(), + Account.Type.ZAPYA) queryString = "SELECT device, name, direction, createtime, path, title FROM transfer" transfersResultSet = transferDb.runQuery(queryString) @@ -71,7 +73,7 @@ class ZapyaAnalyzer(general.AndroidComponentAnalyzer): while transfersResultSet.next(): direction = CommunicationDirection.UNKNOWN fromAddress = None - toAdddress = None + toAddress = None if (transfersResultSet.getInt("direction") == 1): direction = CommunicationDirection.OUTGOING @@ -91,7 +93,7 @@ class ZapyaAnalyzer(general.AndroidComponentAnalyzer): fromAddress, toAddress, timeStamp, - AppDBParserHelper.MessageReadStatusEnum.UNKNOWN, + MessageReadStatus.UNKNOWN, None, msgBody, "" ) @@ -99,9 +101,9 @@ class ZapyaAnalyzer(general.AndroidComponentAnalyzer): # TBD: add the file as attachment ?? except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query result for transfer", ex) + self._logger.log(Level.WARNING, "Error processing query result for transfer", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding artifacts.", ex) + self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding artifacts.", ex) finally: transferDb.close() From 2b10527b33d4e8b35e6a484deb5121171240b8b9 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 17 Sep 2019 13:35:18 -0400 Subject: [PATCH 19/56] fully implemented skype parser --- InternalPythonModules/android/skype.py | 162 +++++++++++++++++++------ 1 file changed, 127 insertions(+), 35 deletions(-) diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index a4db7de556..b88becf295 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -47,7 +47,7 @@ import general class SkypeAnalyzer(general.AndroidComponentAnalyzer): """ - Parses the Viber App databases for TSK contacts, message + Parses the Skype App databases for TSK contacts, message and calllog artifacts. """ @@ -56,6 +56,25 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): self._SKYPE_PACKAGE_NAME = "com.skype.raider" self._PARSER_NAME = "Skype Parser" self._VERSION = "8.15.0.428" + + def get_account_instance(self, skype_db): + account_query_result = skype_db.runQuery( + """ + SELECT entry_id, + CASE + WHEN first_name is NULL AND last_name is NULL THEN entry_id + WHEN first_name is NULL THEN last_name + WHEN last_name is NULL THEN first_name + ELSE first_name || " " || last_name + END as name + FROM user + """ + ) + + if account_query_result is not None and account_query_result.next(): + return Account.Address(account_query_result.getString("entry_id"), + account_query_result.getString("name")) + return None def analyze(self, dataSource, fileManager, context): """ @@ -64,13 +83,21 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): """ try: + #Skype databases are of the form: live:XYZ.db, where + #XYZ is the skype id of the user. skype_dbs = AppSQLiteDB.findAppDatabases(dataSource, "live", False, "") #self._SKYPE_PACKAGE_NAME) #Extract TSK_CONTACT and TSK_CALLLOG information for skype_db in skype_dbs: - helper = AppDBParserHelper(self._PARSER_NAME, - skype_db.getDBFile(), Account.Type.SKYPE) + account_instance = self.get_account_instance(skype_db) + if account_instance is None: + helper = AppDBParserHelper(self._PARSER_NAME, + skype_db.getDBFile(), Account.Type.SKYPE) + else: + helper = AppDBParserHelper(self._PARSER_NAME, + skype_db.getDBFile(), Account.Type.SKYPE, + Account.Type.SKYPE, account_instance) contacts_parser = SkypeContactsParser(skype_db) while contacts_parser.next(): @@ -83,7 +110,7 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): contacts_parser.get_email() ) contacts_parser.close() - """ + calllog_parser = SkypeCallLogsParser(skype_db) while calllog_parser.next(): helper.addCalllog( @@ -110,7 +137,7 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): messages_parser.get_thread_id() ) messages_parser.close() - """ + skype_db.close() except (SQLException, TskCoreException) as ex: #Error parsing Viber db @@ -128,12 +155,10 @@ class SkypeCallLogsParser(TskCallLogsParser): super(SkypeCallLogsParser, self).__init__(calllog_db.runQuery( """ SELECT full_contacts_list.id, - full_contacts_list.members, full_contacts_list.names, time, duration, - is_sender_me, - person_id + is_sender_me FROM (SELECT conversation_id AS id , Group_concat(person_id) AS members, Group_concat(CASE @@ -141,7 +166,9 @@ class SkypeCallLogsParser(TskCallLogsParser): AND Ifnull(last_name,"") == "" THEN entry_id WHEN Ifnull(first_name, "") == "" THEN last_name WHEN Ifnull(last_name, "") == "" THEN first_name - ELSE first_name || " " || last_name + ELSE first_name + || " " + || last_name END) AS names FROM particiapnt AS PART JOIN person AS P @@ -158,7 +185,7 @@ class SkypeCallLogsParser(TskCallLogsParser): ELSE first_name || " " || last_name - end AS name + END AS name FROM person) AS full_contacts_list JOIN chatitem AS C ON C.conversation_link = full_contacts_list.id @@ -171,23 +198,24 @@ class SkypeCallLogsParser(TskCallLogsParser): def get_phone_number_from(self): - if self.get_call_direction() == self._INCOMING_CALL_TYPE: + if self.get_call_direction() == self.INCOMING_CALL: return Account.Address(self.result_set.getString("id"), self.result_set.getString("names")) return super(SkypeCallLogsParser, self).get_phone_number_from() def get_phone_number_to(self): - if self.get_call_direction() == self._OUTGOING_CALL_TYPE: + if self.get_call_direction() == self.OUTGOING_CALL: return Account.Address(self.result_set.getString("id"), self.result_set.getString("names")) return super(SkypeCallLogsParser, self).get_phone_number_to() - def get_call_direction(self): direction = self.result_set.getInt("is_sender_me") - if direction == self._INCOMING_TYPE: + if direction == self._INCOMING_CALL_TYPE: return self.INCOMING_CALL - return self.OUTGOING_CALL + if direction == self._OUTGOING_CALL_TYPE: + return self.OUTGOING_CALL + return super(SkypeCallLogsParser, self).get_call_direction() def get_call_start_date_time(self): return self.result_set.getLong("time") / 1000 @@ -218,17 +246,6 @@ class SkypeContactsParser(TskContactsParser): || last_name end AS name FROM person - union - SELECT entry_id, CASE - WHEN Ifnull(first_name, "") == "" - AND Ifnull(last_name, "") == "" THEN entry_id - WHEN Ifnull(first_name, "") == "" THEN last_name - WHEN Ifnull(last_name, "") == "" THEN first_name - ELSE first_name - || " " - || last_name - end AS name - FROM user """ ) ) @@ -249,22 +266,97 @@ class SkypeMessagesParser(TskMessagesParser): def __init__(self, message_db): super(SkypeMessagesParser, self).__init__(message_db.runQuery( """ - """ + SELECT full_contacts_list.id, + full_contacts_list.members, + full_contacts_list.names, + time, + content, + file_name, + device_gallery_path, + is_sender_me + FROM (SELECT conversation_id AS id , + Group_concat(person_id) AS members, + Group_concat(CASE + WHEN Ifnull(first_name, "") == "" + AND Ifnull(last_name,"") == "" THEN entry_id + WHEN Ifnull(first_name, "") == "" THEN last_name + WHEN Ifnull(last_name, "") == "" THEN first_name + ELSE first_name + || " " + || last_name + END) AS names + FROM particiapnt AS PART + JOIN person AS P + ON PART.person_id = P.entry_id + GROUP BY conversation_id + UNION + SELECT entry_id AS id, + NULL, + CASE + WHEN Ifnull(first_name, "") == "" + AND Ifnull(last_name, "") == "" THEN entry_id + WHEN Ifnull(first_name, "") == "" THEN last_name + WHEN Ifnull(last_name, "") == "" THEN first_name + ELSE first_name + || " " + || last_name + END AS name + FROM person) AS full_contacts_list + JOIN chatitem AS C + ON C.conversation_link = full_contacts_list.id + WHERE message_type != 3 + """ ) ) + self._SKYPE_MESSAGE_TYPE = "Skype Message" + self._OUTGOING_MESSAGE_TYPE = 1 + self._INCOMING_MESSAGE_TYPE = 0 - #def get_message_type(self): + def get_message_type(self): + return self._SKYPE_MESSAGE_TYPE - #def get_phone_number_from(self): + def get_phone_number_from(self): + if self.get_message_direction() == self.INCOMING: + return Account.Address(self.result_set.getString("id"), + self.result_set.getString("names")) + return super(SkypeMessagesParser, self).get_phone_number_from() - #def get_message_direction(self): + def get_message_direction(self): + direction = self.result_set.getInt("is_sender_me") + if direction == self._OUTGOING_MESSAGE_TYPE: + return self.OUTGOING + if direction == self._INCOMING_MESSAGE_TYPE: + return self.INCOMING + return super(SkypeMessagesParser, self).get_message_direction() - #def get_phone_number_to(self): + def get_phone_number_to(self): + if self.get_message_direction() == self.OUTGOING: + return Account.Address(self.result_set.getString("id"), + self.result_set.getString("names")) + return super(SkypeMessagesParser, self).get_phone_number_to() - #def get_message_date_time(self): + def get_message_date_time(self): + date = self.result_set.getLong("time") + return date / 1000 - #def get_message_read_status(self): + def get_message_text(self): + content = self.result_set.getString("content") - #def get_message_text(self): + if content is not None: + file_name = self.result_set.getString("file_name") + file_path = self.result_set.getString("device_gallery_path") - #def get_thread_id(self): + #if a file name and file path are associated with a message, append it + if file_name is not None and file_path is not None: + attachment = "File Name: "+file_name +"\n"+ "File Path: "+file_path + return general.appendAttachmentList(content, [attachment]) + + return content + + return super(SkypeMessagesParser, self).get_message_text() + + def get_thread_id(self): + members = self.result_set.getString("members") + if members is not None: + return self.result_set.getString("id") + return super(SkypeMessagesParser, self).get_thread_id() From 160a1dfd3103130b570c41be9b3a214395f156a9 Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 17 Sep 2019 13:58:54 -0400 Subject: [PATCH 20/56] Updated Sbrowser, Opera browser, Orux maps, and installed apps analyzer to be in sync with the latest helper classes definition and api. --- .../android/installedapps.py | 9 ++-- InternalPythonModules/android/operabrowser.py | 37 +++++++++------- InternalPythonModules/android/oruxmaps.py | 9 ++-- InternalPythonModules/android/sbrowser.py | 44 +++++++++++-------- 4 files changed, 56 insertions(+), 43 deletions(-) diff --git a/InternalPythonModules/android/installedapps.py b/InternalPythonModules/android/installedapps.py index 4f9f32d30a..b830b050cd 100644 --- a/InternalPythonModules/android/installedapps.py +++ b/InternalPythonModules/android/installedapps.py @@ -32,7 +32,6 @@ from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile @@ -40,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.blackboardutils import ArtifactsHelper import traceback import general @@ -59,7 +59,8 @@ class InstalledApplicationsAnalyzer(general.AndroidComponentAnalyzer): libraryDbs = AppSQLiteDB.findAppDatabases(dataSource, "library.db", True, "com.android.vending") for libraryDb in libraryDbs: try: - libraryDbHelper = AppDBParserHelper(self.moduleName, libraryDb.getDBFile()) + libraryDbHelper = ArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, libraryDb.getDBFile()) queryString = "SELECT doc_id, purchase_time FROM ownership" ownershipResultSet = libraryDb.runQuery(queryString) if ownershipResultSet is not None: @@ -69,9 +70,9 @@ class InstalledApplicationsAnalyzer(general.AndroidComponentAnalyzer): purchase_time) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query result for installed applications. ", ex) + self._logger.log(Level.WARNING, "Error processing query result for installed applications. ", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding installed applications.", ex) + self._logger.log(Level.WARNING, "Failed to create ArtifactsHelper for adding installed applications.", ex) finally: libraryDb.close() diff --git a/InternalPythonModules/android/operabrowser.py b/InternalPythonModules/android/operabrowser.py index a67cfd2992..8abbef2792 100644 --- a/InternalPythonModules/android/operabrowser.py +++ b/InternalPythonModules/android/operabrowser.py @@ -32,7 +32,6 @@ from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile @@ -40,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.blackboardutils import WebBrowserArtifactsHelper import traceback import general @@ -60,7 +60,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): cookiesDbs = AppSQLiteDB.findAppDatabases(dataSource, "Cookies", True, "com.opera.browser") for cookiesDb in cookiesDbs: try: - cookiesDbHelper = AppDBParserHelper(self.moduleName, cookiesDb.getDBFile()) + cookiesDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, cookiesDb.getDBFile()) cookiesResultSet = cookiesDb.runQuery("SELECT host_key, name, value, creation_utc FROM cookies") if cookiesResultSet is not None: while cookiesResultSet.next(): @@ -72,9 +73,9 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): self.progName) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for Opera cookies.", ex) + self._logger.log(Level.WARNING, "Error processing query results for Opera cookies.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera cookies.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera cookies.", ex) finally: cookiesDb.close() @@ -84,7 +85,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.opera.browser") for historyDb in historyDbs: try: - historyDbHelper = AppDBParserHelper(self.moduleName, historyDb.getDBFile()) + historyDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, historyDb.getDBFile()) historyResultSet = historyDb.runQuery("SELECT url, title, last_visit_time FROM urls") if historyResultSet is not None: while historyResultSet.next(): @@ -95,9 +97,9 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): historyResultSet.getString("title"), self.progName) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for Opera history.", ex) + self._logger.log(Level.WARNING, "Error processing query results for Opera history.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera history.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera history.", ex) finally: historyDb.close() @@ -107,7 +109,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): downloadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.opera.browser") for downloadsDb in downloadsDbs: try: - downloadsDbHelper = AppDBParserHelper(self.moduleName, downloadsDb.getDBFile()) + downloadsDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, downloadsDb.getDBFile()) queryString = "SELECT target_path, start_time, url FROM downloads"\ " INNER JOIN downloads_url_chains ON downloads.id = downloads_url_chains.id" downloadsResultSet = downloadsDb.runQuery(queryString) @@ -120,9 +123,9 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): self.progName) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for Opera downloads.", ex) + self._logger.log(Level.WARNING, "Error processing query results for Opera downloads.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera downloads.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera downloads.", ex) finally: downloadsDb.close() @@ -130,7 +133,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): autofillDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.opera.browser") for autofillDb in autofillDbs: try: - autofillDbHelper = AppDBParserHelper(self.moduleName, autofillDb.getDBFile()) + autofillDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, autofillDb.getDBFile()) autofillsResultSet = autofillDb.runQuery("SELECT name, value, count, date_created FROM autofill") if autofillsResultSet is not None: while autofillsResultSet.next(): @@ -142,9 +146,9 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): autofillsResultSet.getInt("count")) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for Opera autofill.", ex) + self._logger.log(Level.WARNING, "Error processing query results for Opera autofill.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera autofill.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera autofill.", ex) finally: autofillDb.close() @@ -152,7 +156,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): webFormAddressDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.opera.browser") for webFormAddressDb in webFormAddressDbs: try: - webFormAddressDbHelper = AppDBParserHelper(self.moduleName, webFormAddressDb.getDBFile()) + webFormAddressDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, webFormAddressDb.getDBFile()) queryString = "SELECT street_address, city, state, zipcode, country_code, date_modified, first_name, last_name, number, email FROM autofill_profiles "\ " INNER JOIN autofill_profile_names"\ " ON autofill_profiles.guid = autofill_profile_names.guid"\ @@ -179,9 +184,9 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): 0) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for Opera web form addresses.", ex) + self._logger.log(Level.WARNING, "Error processing query results for Opera web form addresses.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Opera form addresses.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera form addresses.", ex) finally: webFormAddressDb.close() diff --git a/InternalPythonModules/android/oruxmaps.py b/InternalPythonModules/android/oruxmaps.py index 5a7a94c078..b4f63ed187 100644 --- a/InternalPythonModules/android/oruxmaps.py +++ b/InternalPythonModules/android/oruxmaps.py @@ -34,7 +34,6 @@ from org.sleuthkit.autopsy.casemodule.services import FileManager from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile @@ -43,6 +42,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.blackboardutils import ArtifactsHelper import traceback import general @@ -62,7 +62,8 @@ class OruxMapsAnalyzer(general.AndroidComponentAnalyzer): oruxMapsTrackpointsDbs = AppSQLiteDB.findAppDatabases(dataSource, "oruxmapstracks.db", True, "oruxmaps") for oruxMapsTrackpointsDb in oruxMapsTrackpointsDbs: try: - oruxDbHelper = AppDBParserHelper(self.moduleName, oruxMapsTrackpointsDb.getDBFile()) + oruxDbHelper = ArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, oruxMapsTrackpointsDb.getDBFile()) poiQueryString = "SELECT poilat, poilon, poitime, poiname FROM pois" poisResultSet = oruxMapsTrackpointsDb.runQuery(poiQueryString) @@ -86,8 +87,8 @@ class OruxMapsAnalyzer(general.AndroidComponentAnalyzer): "", self.programName) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query result for Orux Map trackpoints.", ex) + self._logger.log(Level.WARNING, "Error processing query result for Orux Map trackpoints.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding Orux Map trackpoints.", ex) + self._logger.log(Level.WARNING, "Failed to create ArtifactsHelper for adding Orux Map trackpoints.", ex) finally: oruxMapsTrackpointsDb.close() diff --git a/InternalPythonModules/android/sbrowser.py b/InternalPythonModules/android/sbrowser.py index fc0e5e6d42..85b477405e 100644 --- a/InternalPythonModules/android/sbrowser.py +++ b/InternalPythonModules/android/sbrowser.py @@ -32,7 +32,6 @@ from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile @@ -40,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.blackboardutils import WebBrowserArtifactsHelper import traceback import general @@ -60,7 +60,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): sbrowserDbs = AppSQLiteDB.findAppDatabases(dataSource, "sbrowser.db", True, "com.sec.android.app.sbrowser") for sbrowserDb in sbrowserDbs: try: - sbrowserDbHelper = AppDBParserHelper(self.moduleName, sbrowserDb.getDBFile()) + sbrowserDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, sbrowserDb.getDBFile()) bookmarkResultSet = sbrowserDb.runQuery("SELECT url, title, created FROM bookmarks WHERE url IS NOT NULL") if bookmarkResultSet is not None: while bookmarkResultSet.next(): @@ -70,9 +71,9 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): createTime, self.progName) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for SBrowser bookmarks.", ex) + self._logger.log(Level.WARNING, "Error processing query results for SBrowser bookmarks.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding bookmarks.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding bookmarks.", ex) finally: sbrowserDb.close() @@ -82,7 +83,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): cookiesDbs = AppSQLiteDB.findAppDatabases(dataSource, "Cookies", True, "com.sec.android.app.sbrowser") for cookiesDb in cookiesDbs: try: - cookiesDbHelper = AppDBParserHelper(self.moduleName, cookiesDb.getDBFile()) + cookiesDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, cookiesDb.getDBFile()) cookiesResultSet = cookiesDb.runQuery("SELECT host_key, name, value, creation_utc FROM cookies") if cookiesResultSet is not None: while cookiesResultSet.next(): @@ -94,9 +96,9 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): self.progName) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for SBrowser cookies.", ex) + self._logger.log(Level.WARNING, "Error processing query results for SBrowser cookies.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser cookies.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser cookies.", ex) finally: cookiesDb.close() @@ -106,7 +108,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.sec.android.app.sbrowser") for historyDb in historyDbs: try: - historyDbHelper = AppDBParserHelper(self.moduleName, historyDb.getDBFile()) + historyDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, historyDb.getDBFile()) historyResultSet = historyDb.runQuery("SELECT url, title, last_visit_time FROM urls") if historyResultSet is not None: while historyResultSet.next(): @@ -117,9 +120,9 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): historyResultSet.getString("title"), self.progName) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for SBrowser history.", ex) + self._logger.log(Level.WARNING, "Error processing query results for SBrowser history.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser history.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser history.", ex) finally: historyDb.close() @@ -129,7 +132,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): downloadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.sec.android.app.sbrowser") for downloadsDb in downloadsDbs: try: - downloadsDbHelper = AppDBParserHelper(self.moduleName, downloadsDb.getDBFile()) + downloadsDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, downloadsDb.getDBFile()) queryString = "SELECT target_path, start_time, url FROM downloads"\ " INNER JOIN downloads_url_chains ON downloads.id = downloads_url_chains.id" downloadsResultSet = downloadsDb.runQuery(queryString) @@ -142,9 +146,9 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): self.progName) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for SBrowser downloads.", ex) + self._logger.log(Level.WARNING, "Error processing query results for SBrowser downloads.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser downloads.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser downloads.", ex) finally: downloadsDb.close() @@ -152,7 +156,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): autofillDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.sec.android.app.sbrowser") for autofillDb in autofillDbs: try: - autofillDbHelper = AppDBParserHelper(self.moduleName, autofillDb.getDBFile()) + autofillDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, autofillDb.getDBFile()) autofillsResultSet = autofillDb.runQuery("SELECT name, value, count, date_created FROM autofill INNER JOIN autofill_dates ON autofill.pair_id = autofill_dates.pair_id") if autofillsResultSet is not None: while autofillsResultSet.next(): @@ -164,9 +169,9 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): autofillsResultSet.getInt("count")) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for SBrowser autofill.", ex) + self._logger.log(Level.WARNING, "Error processing query results for SBrowser autofill.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser autofill.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser autofill.", ex) finally: autofillDb.close() @@ -174,7 +179,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): webFormAddressDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.sec.android.app.sbrowser") for webFormAddressDb in webFormAddressDbs: try: - webFormAddressDbHelper = AppDBParserHelper(self.moduleName, webFormAddressDb.getDBFile()) + webFormAddressDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + self.moduleName, webFormAddressDb.getDBFile()) queryString = "SELECT street_address, city, state, zipcode, country_code, date_modified, first_name, last_name, number, email FROM autofill_profiles "\ " INNER JOIN autofill_profile_names"\ " ON autofill_profiles.guid = autofill_profile_names.guid"\ @@ -201,9 +207,9 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): 0) except SQLException as ex: - self._logger.log(Level.SEVERE, "Error processing query results for SBrowser form addresses.", ex) + self._logger.log(Level.WARNING, "Error processing query results for SBrowser form addresses.", ex) except TskCoreException as ex: - self._logger.log(Level.SEVERE, "Failed to create AppDBParserHelper for adding SBrowser form addresses.", ex) + self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser form addresses.", ex) finally: webFormAddressDb.close() From 6534576170c3a4bc4ce7dc6dba20057238be5c14 Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 17 Sep 2019 14:38:45 -0400 Subject: [PATCH 21/56] Updated FB messnger parser to be in sync with the latest artifact helper class definition and api. --- InternalPythonModules/android/fbmessenger.py | 22 +++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/InternalPythonModules/android/fbmessenger.py b/InternalPythonModules/android/fbmessenger.py index a5503d1a88..ddd818ab66 100644 --- a/InternalPythonModules/android/fbmessenger.py +++ b/InternalPythonModules/android/fbmessenger.py @@ -32,9 +32,6 @@ from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper -from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import MessageReadStatusEnum -from org.sleuthkit.autopsy.coreutils.AppDBParserHelper import CommunicationDirection from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile @@ -43,6 +40,9 @@ from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import Account +from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection import json import traceback @@ -74,8 +74,9 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): if not self.selfAccountAddress: self.selfAccountAddress = Account.Address(selfAccountResultSet.getString("fbid"), selfAccountResultSet.getString("display_name")) - contactsDBHelper = AppDBParserHelper("Facebook Parser", contactsDb.getDBFile(), - Account.Type.FACEBOOK, Account.Type.FACEBOOK, self.selfAccountAddress ) + contactsDBHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + "Facebook Parser", contactsDb.getDBFile(), + Account.Type.FACEBOOK, Account.Type.FACEBOOK, self.selfAccountAddress ) contactsResultSet = contactsDb.runQuery("SELECT fbid, display_name FROM contacts WHERE added_time_ms <> " + self.selfAccountAddress.getUniqueID() ) if contactsResultSet is not None: while contactsResultSet.next(): @@ -89,7 +90,7 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for account", ex) except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create AppDBParserHelper for adding Facebook contacts.", ex) + self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding Facebook contacts.", ex) finally: contactsDb.close() @@ -110,8 +111,9 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): threadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "threads_db2", True, "com.facebook.orca") for threadsDb in threadsDbs: try: - threadsDBHelper = AppDBParserHelper("FB Messenger Parser", threadsDb.getDBFile(), - Account.Type.FACEBOOK, Account.Type.FACEBOOK, self.selfAccountAddress ) + threadsDBHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + "FB Messenger Parser", threadsDb.getDBFile(), + Account.Type.FACEBOOK, Account.Type.FACEBOOK, self.selfAccountAddress ) ## Messages are found in the messages table. The participant ids can be found in the thread_participants table. ## Participant names are found in thread_users table. @@ -145,7 +147,7 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): fromAddress, recipientAddressList, timeStamp, - MessageReadStatusEnum.UNKNOWN, + MessageReadStatus.UNKNOWN, "", msgText, threadId) @@ -208,7 +210,7 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for FB Messenger messages.", ex) except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create AppDBParserHelper for adding FB Messenger messages.", ex) + self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding FB Messenger messages.", ex) finally: threadsDb.close() From 7a6be8dd86d1fbb301e8b5af45411387e431fbae Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Tue, 17 Sep 2019 17:30:18 -0400 Subject: [PATCH 22/56] Made incremental improvements --- InternalPythonModules/android/skype.py | 227 +++++++++++++++---------- 1 file changed, 136 insertions(+), 91 deletions(-) diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index b88becf295..4a236a7206 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -49,6 +49,29 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): """ Parses the Skype App databases for TSK contacts, message and calllog artifacts. + + About version 8.15.0.428 (9/17/2019) Skype database: + - There are 4 tables this parser uses: + 1) person - this table appears to hold all contacts known to the user. + 2) user - this table holds information pertaining to the user. + 3) particiapnt - Yes, that is not a typo. This table maps group chat + ids to skype ids (1 to many). + 4) chatItem - This table contains all messages. It maps the group id or + skype id (for 1 to 1 communication) to the message content + and metadata. Either the group id or skype id is stored in + a column named 'conversation_link'. + + More info and implementation details: + - The person table does not include groups. To get + all 1 to 1 communications, we could simply join the person and chatItem tables. + This would mean we'd need to do a second pass to get all the group information + as they would be excluded in the join. Since the chatItem table stores both the + group id or skype_id in one column, the person and particiapnt table are unioned + together so that all rows are matched in one join with chatItem. This result is + labeled contact_list_with_groups in the following queries. + - In order to keep the formatting of the name consistent throughout each query, + a _format_user_name() function was created to encapsulate the CASE statement + that was being shared across them. Refer to the method for more details. """ def __init__(self): @@ -60,13 +83,8 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): def get_account_instance(self, skype_db): account_query_result = skype_db.runQuery( """ - SELECT entry_id, - CASE - WHEN first_name is NULL AND last_name is NULL THEN entry_id - WHEN first_name is NULL THEN last_name - WHEN last_name is NULL THEN first_name - ELSE first_name || " " || last_name - END as name + SELECT entry_id, + """+_format_user_name()+""" AS name FROM user """ ) @@ -77,18 +95,12 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): return None def analyze(self, dataSource, fileManager, context): - """ - Extract, Transform and Load all messages, contacts and - calllogs from the Skype databases. - """ - try: #Skype databases are of the form: live:XYZ.db, where #XYZ is the skype id of the user. skype_dbs = AppSQLiteDB.findAppDatabases(dataSource, "live", False, "") #self._SKYPE_PACKAGE_NAME) - #Extract TSK_CONTACT and TSK_CALLLOG information for skype_db in skype_dbs: account_instance = self.get_account_instance(skype_db) if account_instance is None: @@ -98,7 +110,9 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): helper = AppDBParserHelper(self._PARSER_NAME, skype_db.getDBFile(), Account.Type.SKYPE, Account.Type.SKYPE, account_instance) - + + #Query for contacts and iterate row by row adding + #each contact artifact contacts_parser = SkypeContactsParser(skype_db) while contacts_parser.next(): helper.addContact( @@ -111,6 +125,8 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): ) contacts_parser.close() + #Query for call logs and iterate row by row adding + #each call log artifact calllog_parser = SkypeCallLogsParser(skype_db) while calllog_parser.next(): helper.addCalllog( @@ -123,6 +139,8 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): ) calllog_parser.close() + #Query for messages and iterate row by row adding + #each message artifact messages_parser = SkypeMessagesParser(skype_db) while messages_parser.next(): helper.addMessage( @@ -140,7 +158,7 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): skype_db.close() except (SQLException, TskCoreException) as ex: - #Error parsing Viber db + #Error parsing Skype db self._logger.log(Level.WARNING, "Error parsing Skype Databases", ex) self._logger.log(Level.WARNING, traceback.format_exec()) @@ -154,41 +172,36 @@ class SkypeCallLogsParser(TskCallLogsParser): def __init__(self, calllog_db): super(SkypeCallLogsParser, self).__init__(calllog_db.runQuery( """ - SELECT full_contacts_list.id, - full_contacts_list.names, + SELECT contacts_list_with_groups.conversation_id, + contacts_list_with_groups.participant_ids, + contacts_list_with_groups.participants, time, duration, - is_sender_me - FROM (SELECT conversation_id AS id , - Group_concat(person_id) AS members, - Group_concat(CASE - WHEN Ifnull(first_name, "") == "" - AND Ifnull(last_name,"") == "" THEN entry_id - WHEN Ifnull(first_name, "") == "" THEN last_name - WHEN Ifnull(last_name, "") == "" THEN first_name - ELSE first_name - || " " - || last_name - END) AS names + is_sender_me, + person_id as sender_id, + sender_name.name as sender_name + FROM (SELECT conversation_id, + Group_concat(person_id) AS participant_ids, + Group_concat("""+_format_user_name()+""") AS participants FROM particiapnt AS PART JOIN person AS P ON PART.person_id = P.entry_id GROUP BY conversation_id UNION - SELECT entry_id AS id, - NULL, - CASE - WHEN Ifnull(first_name, "") == "" - AND Ifnull(last_name, "") == "" THEN entry_id - WHEN Ifnull(first_name, "") == "" THEN last_name - WHEN Ifnull(last_name, "") == "" THEN first_name - ELSE first_name - || " " - || last_name - END AS name - FROM person) AS full_contacts_list + SELECT entry_id, + NULL, + """+_format_user_name()+""" AS participant + FROM person) AS contacts_list_with_groups JOIN chatitem AS C - ON C.conversation_link = full_contacts_list.id + ON C.conversation_link = contacts_list_with_groups.conversation_id + JOIN (SELECT entry_id as id, + """+_format_user_name()+""" AS name + FROM person + UNION + SELECT entry_id as id, + """+_format_user_name()+""" AS name + FROM user) AS sender_name + ON sender_name.id = C.person_id WHERE message_type == 3 """ ) @@ -199,16 +212,28 @@ class SkypeCallLogsParser(TskCallLogsParser): def get_phone_number_from(self): if self.get_call_direction() == self.INCOMING_CALL: - return Account.Address(self.result_set.getString("id"), - self.result_set.getString("names")) - return super(SkypeCallLogsParser, self).get_phone_number_from() + return Account.Address(self.result_set.getString("sender_id"), + self.result_set.getString("sender_name")) def get_phone_number_to(self): if self.get_call_direction() == self.OUTGOING_CALL: - return Account.Address(self.result_set.getString("id"), - self.result_set.getString("names")) + group_ids = self.result_set.getString("participant_ids") + name = self.result_set.getString("participants") + + if group_ids is not None: + group_ids = group_ids.split(",") + name = name.split(",") + recipients = [] + + for person_id, person_name in zip(group_ids, name): + recipients.append(Account.Address(person_id, person_name)) + + return recipients + + return Account.Address(self.result_set.getString("conversation_id"), name) + return super(SkypeCallLogsParser, self).get_phone_number_to() - + def get_call_direction(self): direction = self.result_set.getInt("is_sender_me") if direction == self._INCOMING_CALL_TYPE: @@ -236,15 +261,7 @@ class SkypeContactsParser(TskContactsParser): super(SkypeContactsParser, self).__init__(contact_db.runQuery( """ SELECT entry_id, - CASE - WHEN Ifnull(first_name, "") == "" - AND Ifnull(last_name, "") == "" THEN entry_id - WHEN Ifnull(first_name, "") == "" THEN last_name - WHEN Ifnull(last_name, "") == "" THEN first_name - ELSE first_name - || " " - || last_name - end AS name + """+_format_user_name()+""" AS name FROM person """ ) @@ -266,44 +283,38 @@ class SkypeMessagesParser(TskMessagesParser): def __init__(self, message_db): super(SkypeMessagesParser, self).__init__(message_db.runQuery( """ - SELECT full_contacts_list.id, - full_contacts_list.members, - full_contacts_list.names, + SELECT contacts_list_with_groups.conversation_id, + contacts_list_with_groups.participant_ids, + contacts_list_with_groups.participants, time, content, file_name, device_gallery_path, - is_sender_me - FROM (SELECT conversation_id AS id , - Group_concat(person_id) AS members, - Group_concat(CASE - WHEN Ifnull(first_name, "") == "" - AND Ifnull(last_name,"") == "" THEN entry_id - WHEN Ifnull(first_name, "") == "" THEN last_name - WHEN Ifnull(last_name, "") == "" THEN first_name - ELSE first_name - || " " - || last_name - END) AS names + is_sender_me, + person_id as sender_id, + sender_name.name AS sender_name + FROM (SELECT conversation_id, + Group_concat(person_id) AS participant_ids, + Group_concat("""+_format_user_name()+""") AS participants FROM particiapnt AS PART JOIN person AS P ON PART.person_id = P.entry_id GROUP BY conversation_id UNION - SELECT entry_id AS id, + SELECT entry_id as conversation_id, NULL, - CASE - WHEN Ifnull(first_name, "") == "" - AND Ifnull(last_name, "") == "" THEN entry_id - WHEN Ifnull(first_name, "") == "" THEN last_name - WHEN Ifnull(last_name, "") == "" THEN first_name - ELSE first_name - || " " - || last_name - END AS name - FROM person) AS full_contacts_list + """+_format_user_name()+""" AS participant + FROM person) AS contacts_list_with_groups JOIN chatitem AS C - ON C.conversation_link = full_contacts_list.id + ON C.conversation_link = contacts_list_with_groups.conversation_id + JOIN (SELECT entry_id as id, + """+_format_user_name()+""" AS name + FROM person + UNION + SELECT entry_id as id, + """+_format_user_name()+""" AS name + FROM user) AS sender_name + ON sender_name.id = C.person_id WHERE message_type != 3 """ ) @@ -317,8 +328,8 @@ class SkypeMessagesParser(TskMessagesParser): def get_phone_number_from(self): if self.get_message_direction() == self.INCOMING: - return Account.Address(self.result_set.getString("id"), - self.result_set.getString("names")) + return Account.Address(self.result_set.getString("sender_id"), + self.result_set.getString("sender_name")) return super(SkypeMessagesParser, self).get_phone_number_from() def get_message_direction(self): @@ -331,8 +342,21 @@ class SkypeMessagesParser(TskMessagesParser): def get_phone_number_to(self): if self.get_message_direction() == self.OUTGOING: - return Account.Address(self.result_set.getString("id"), - self.result_set.getString("names")) + group_ids = self.result_set.getString("participant_ids") + names = self.result_set.getString("participants") + + if group_ids is not None: + group_ids = group_ids.split(",") + names = names.split(",") + recipients = [] + + for participant_id, participant_name in zip(group_ids, names): + recipients.append(Account.Address(participant_id, participant_name)) + + return recipients + + return Account.Address(self.result_set.getString("conversation_id"), names) + return super(SkypeMessagesParser, self).get_phone_number_to() def get_message_date_time(self): @@ -356,7 +380,28 @@ class SkypeMessagesParser(TskMessagesParser): return super(SkypeMessagesParser, self).get_message_text() def get_thread_id(self): - members = self.result_set.getString("members") - if members is not None: - return self.result_set.getString("id") + group_ids = self.result_set.getString("participant_ids") + if group_ids is not None: + return self.result_set.getString("conversation_id") return super(SkypeMessagesParser, self).get_thread_id() + +def _format_user_name(): + """ + This CASE SQL statement is used in many queries to + format the names of users. For a user, there is a first_name + column and a last_name column. Some of these columns can be null + and our goal is to produce the cleanest data possible. In the event + that both the first and last name columns are null, we return the skype_id + which is stored in the database as 'entry_id'. + """ + + return """ + CASE + WHEN Ifnull(first_name, "") == "" AND Ifnull(last_name, "") == "" THEN entry_id + WHEN first_name is NULL THEN replace(last_name, ",", "") + WHEN last_name is NULL THEN replace(first_name, ",", "") + ELSE replace(first_name, ",", "") || " " || replace(last_name, ",", "") + END + """ + + From f2b8b7775efb71cdc873bf89409851ac6c3be888 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 19 Sep 2019 06:38:51 -0400 Subject: [PATCH 23/56] Syncing Xender/Zapya/ShareIt modlues to the latest artifacts helper api definition. --- InternalPythonModules/android/imo.py | 2 +- InternalPythonModules/android/shareit.py | 5 +++-- InternalPythonModules/android/xender.py | 5 +++-- InternalPythonModules/android/zapya.py | 5 +++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/InternalPythonModules/android/imo.py b/InternalPythonModules/android/imo.py index 5a653ff9d5..aed3b4011c 100644 --- a/InternalPythonModules/android/imo.py +++ b/InternalPythonModules/android/imo.py @@ -138,7 +138,7 @@ class IMOAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for IMO friends", ex) except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to message artifacts.", ex) + self._logger.log(Level.WARNING, "Failed to create IMO message artifacts.", ex) finally: friendsDb.close() diff --git a/InternalPythonModules/android/shareit.py b/InternalPythonModules/android/shareit.py index ac359f51a3..8e3ebd3823 100644 --- a/InternalPythonModules/android/shareit.py +++ b/InternalPythonModules/android/shareit.py @@ -39,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel import Account from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus @@ -102,8 +103,8 @@ class ShareItAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for ShareIt history.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding artifacts.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to create ShareIt message artifacts.", ex) finally: historyDb.close() diff --git a/InternalPythonModules/android/xender.py b/InternalPythonModules/android/xender.py index b59f18dce3..d1cecd3a82 100644 --- a/InternalPythonModules/android/xender.py +++ b/InternalPythonModules/android/xender.py @@ -39,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel import Account from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus @@ -109,8 +110,8 @@ class XenderAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for profiles", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding artifacts.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to create Xender message artifacts.", ex) finally: transactionDb.close() diff --git a/InternalPythonModules/android/zapya.py b/InternalPythonModules/android/zapya.py index fed51dd27d..9bcb5753d1 100644 --- a/InternalPythonModules/android/zapya.py +++ b/InternalPythonModules/android/zapya.py @@ -39,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel import Account from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus @@ -102,8 +103,8 @@ class ZapyaAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for transfer", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding artifacts.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to create Zapya message artifacts.", ex) finally: transferDb.close() From 98d904eaf8648ff0fdc8fb97d2b11555769852df Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 19 Sep 2019 08:07:32 -0400 Subject: [PATCH 24/56] Sync SBrowser, Opera, OruxMaps and InstalledApps modules to latest artifact helper api definition. --- .../android/installedapps.py | 5 ++-- InternalPythonModules/android/operabrowser.py | 21 ++++++++-------- InternalPythonModules/android/oruxmaps.py | 5 ++-- InternalPythonModules/android/sbrowser.py | 25 ++++++++++--------- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/InternalPythonModules/android/installedapps.py b/InternalPythonModules/android/installedapps.py index b830b050cd..ceb8526924 100644 --- a/InternalPythonModules/android/installedapps.py +++ b/InternalPythonModules/android/installedapps.py @@ -39,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel.blackboardutils import ArtifactsHelper import traceback @@ -71,8 +72,8 @@ class InstalledApplicationsAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for installed applications. ", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create ArtifactsHelper for adding installed applications.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to adding installed application artifacts.", ex) finally: libraryDb.close() diff --git a/InternalPythonModules/android/operabrowser.py b/InternalPythonModules/android/operabrowser.py index 8abbef2792..876c5063dc 100644 --- a/InternalPythonModules/android/operabrowser.py +++ b/InternalPythonModules/android/operabrowser.py @@ -39,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel.blackboardutils import WebBrowserArtifactsHelper import traceback @@ -74,8 +75,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera cookies.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera cookies.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add Opera cookie artifacts.", ex) finally: cookiesDb.close() @@ -98,8 +99,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): self.progName) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera history.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera history.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add Opera history artifacts.", ex) finally: historyDb.close() @@ -124,8 +125,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera downloads.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera downloads.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add Opera download artifacts.", ex) finally: downloadsDb.close() @@ -147,8 +148,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera autofill.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera autofill.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add Opera autofill artifacts.", ex) finally: autofillDb.close() @@ -185,8 +186,8 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera web form addresses.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding Opera form addresses.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add Opera form address artifacts.", ex) finally: webFormAddressDb.close() diff --git a/InternalPythonModules/android/oruxmaps.py b/InternalPythonModules/android/oruxmaps.py index b4f63ed187..87f243e8af 100644 --- a/InternalPythonModules/android/oruxmaps.py +++ b/InternalPythonModules/android/oruxmaps.py @@ -42,6 +42,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel.blackboardutils import ArtifactsHelper import traceback @@ -88,7 +89,7 @@ class OruxMapsAnalyzer(general.AndroidComponentAnalyzer): self.programName) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for Orux Map trackpoints.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create ArtifactsHelper for adding Orux Map trackpoints.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add Orux Map trackpoint artifacts.", ex) finally: oruxMapsTrackpointsDb.close() diff --git a/InternalPythonModules/android/sbrowser.py b/InternalPythonModules/android/sbrowser.py index 85b477405e..ed15fdd7d6 100644 --- a/InternalPythonModules/android/sbrowser.py +++ b/InternalPythonModules/android/sbrowser.py @@ -39,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel.blackboardutils import WebBrowserArtifactsHelper import traceback @@ -72,8 +73,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): self.progName) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser bookmarks.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding bookmarks.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add SBrowser bookmark artifacts.", ex) finally: sbrowserDb.close() @@ -97,8 +98,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser cookies.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser cookies.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add SBrowser cookie artifacts.", ex) finally: cookiesDb.close() @@ -121,8 +122,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): self.progName) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser history.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser history.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add SBrowser history artifacts.", ex) finally: historyDb.close() @@ -147,8 +148,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser downloads.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser downloads.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add SBrowser download artifacts.", ex) finally: downloadsDb.close() @@ -170,8 +171,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser autofill.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser autofill.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add SBrowser autofill artifacts.", ex) finally: autofillDb.close() @@ -208,8 +209,8 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser form addresses.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create WebBrowserArtifactsHelper for adding SBrowser form addresses.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add SBrowser form address artifacts.", ex) finally: webFormAddressDb.close() From e7f3280de8193ef30d131fb9c5073e27d734acb1 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 19 Sep 2019 08:42:56 -0400 Subject: [PATCH 25/56] Syncing the FB Messenger module to latest artifacts helper api. --- InternalPythonModules/android/fbmessenger.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/InternalPythonModules/android/fbmessenger.py b/InternalPythonModules/android/fbmessenger.py index ddd818ab66..2c4a1be284 100644 --- a/InternalPythonModules/android/fbmessenger.py +++ b/InternalPythonModules/android/fbmessenger.py @@ -39,6 +39,7 @@ from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel import Account from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus @@ -89,8 +90,8 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for account", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding Facebook contacts.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add Facebook Messenger contact artifacts.", ex) finally: contactsDb.close() @@ -209,8 +210,8 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for FB Messenger messages.", ex) - except TskCoreException as ex: - self._logger.log(Level.WARNING, "Failed to create CommunicationArtifactsHelper for adding FB Messenger messages.", ex) + except (TskCoreException, BlackboardException) as ex: + self._logger.log(Level.WARNING, "Failed to add FB Messenger message artifacts.", ex) finally: threadsDb.close() From 911995f489ad8c660e6738737efb4383e7f3a859 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 19 Sep 2019 13:23:08 -0400 Subject: [PATCH 26/56] Updated the skype parser to use the new api --- .../android/TskCallLogsParser.py | 17 ++--- .../android/TskMessagesParser.py | 17 ++--- InternalPythonModules/android/skype.py | 70 ++++++++++++++----- 3 files changed, 69 insertions(+), 35 deletions(-) diff --git a/InternalPythonModules/android/TskCallLogsParser.py b/InternalPythonModules/android/TskCallLogsParser.py index 8c61070693..d4e6942134 100644 --- a/InternalPythonModules/android/TskCallLogsParser.py +++ b/InternalPythonModules/android/TskCallLogsParser.py @@ -17,7 +17,8 @@ See the License for the specific language governing permissions and limitations under the License. """ from ResultSetIterator import ResultSetIterator -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CallMediaType +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection from org.sleuthkit.datamodel import Account class TskCallLogsParser(ResultSetIterator): @@ -35,15 +36,15 @@ class TskCallLogsParser(ResultSetIterator): def __init__(self, result_set): super(TskCallLogsParser, self).__init__(result_set) self._DEFAULT_STRING = "" - self._DEFAULT_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN + self._DEFAULT_DIRECTION = CommunicationDirection.UNKNOWN self._DEFAULT_ADDRESS = None - self._DEFAULT_CALL_TYPE = AppDBParserHelper.CallMediaType.UNKNOWN - self._DEFAULT_LONG = -1 + self._DEFAULT_CALL_TYPE = CallMediaType.UNKNOWN + self._DEFAULT_LONG = -1L - self.INCOMING_CALL = AppDBParserHelper.CommunicationDirection.INCOMING - self.OUTGOING_CALL = AppDBParserHelper.CommunicationDirection.OUTGOING - self.AUDIO_CALL = AppDBParserHelper.CallMediaType.AUDIO - self.VIDEO_CALL = AppDBParserHelper.CallMediaType.VIDEO + self.INCOMING_CALL = CommunicationDirection.INCOMING + self.OUTGOING_CALL = CommunicationDirection.OUTGOING + self.AUDIO_CALL = CallMediaType.AUDIO + self.VIDEO_CALL = CallMediaType.VIDEO def get_call_direction(self): return self._DEFAULT_DIRECTION diff --git a/InternalPythonModules/android/TskMessagesParser.py b/InternalPythonModules/android/TskMessagesParser.py index 15c4166db7..4568a7400c 100644 --- a/InternalPythonModules/android/TskMessagesParser.py +++ b/InternalPythonModules/android/TskMessagesParser.py @@ -18,8 +18,9 @@ limitations under the License. """ from ResultSetIterator import ResultSetIterator from org.sleuthkit.datamodel import Account -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper - +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection + class TskMessagesParser(ResultSetIterator): """ Generic TSK_MESSAGE artifact template. Each of these methods @@ -35,14 +36,14 @@ class TskMessagesParser(ResultSetIterator): super(TskMessagesParser, self).__init__(result_set) self._DEFAULT_TEXT = "" self._DEFAULT_LONG = -1L - self._DEFAULT_MSG_READ_STATUS = AppDBParserHelper.MessageReadStatusEnum.UNKNOWN + self._DEFAULT_MSG_READ_STATUS = MessageReadStatus.UNKNOWN self._DEFAULT_ACCOUNT_ADDRESS = None - self._DEFAULT_COMMUNICATION_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN + self._DEFAULT_COMMUNICATION_DIRECTION = CommunicationDirection.UNKNOWN - self.INCOMING = AppDBParserHelper.CommunicationDirection.INCOMING - self.OUTGOING = AppDBParserHelper.CommunicationDirection.OUTGOING - self.READ = AppDBParserHelper.MessageReadStatusEnum.READ - self.UNREAD = AppDBParserHelper.MessageReadStatusEnum.UNREAD + self.INCOMING = CommunicationDirection.INCOMING + self.OUTGOING = CommunicationDirection.OUTGOING + self.READ = MessageReadStatus.READ + self.UNREAD = MessageReadStatus.UNREAD def get_message_type(self): return self._DEFAULT_TEXT diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index 4a236a7206..8444d401cb 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -26,18 +26,25 @@ from java.sql import ResultSet from java.sql import SQLException from java.sql import Statement from java.util.logging import Level +from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper + +from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel import Account +from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection from TskMessagesParser import TskMessagesParser from TskContactsParser import TskContactsParser from TskCallLogsParser import TskCallLogsParser @@ -66,9 +73,10 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): all 1 to 1 communications, we could simply join the person and chatItem tables. This would mean we'd need to do a second pass to get all the group information as they would be excluded in the join. Since the chatItem table stores both the - group id or skype_id in one column, the person and particiapnt table are unioned - together so that all rows are matched in one join with chatItem. This result is - labeled contact_list_with_groups in the following queries. + group id or skype_id in one column, an implementation decision was made to union + the person and particiapnt table together so that all rows are matched in one join + with chatItem. This result is consistently labeled contact_list_with_groups in the + following queries. - In order to keep the formatting of the name consistent throughout each query, a _format_user_name() function was created to encapsulate the CASE statement that was being shared across them. Refer to the method for more details. @@ -95,19 +103,18 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): return None def analyze(self, dataSource, fileManager, context): - try: - #Skype databases are of the form: live:XYZ.db, where - #XYZ is the skype id of the user. - skype_dbs = AppSQLiteDB.findAppDatabases(dataSource, - "live", False, "") #self._SKYPE_PACKAGE_NAME) - - for skype_db in skype_dbs: + #Skype databases are of the form: live:XYZ.db, where + #XYZ is the skype id of the user. + skype_dbs = AppSQLiteDB.findAppDatabases(dataSource, + "live", False, self._SKYPE_PACKAGE_NAME) + for skype_db in skype_dbs: + try: account_instance = self.get_account_instance(skype_db) if account_instance is None: - helper = AppDBParserHelper(self._PARSER_NAME, + helper = CommunicationArtifactsHelper(self._PARSER_NAME, skype_db.getDBFile(), Account.Type.SKYPE) else: - helper = AppDBParserHelper(self._PARSER_NAME, + helper = CommunicationArtifactsHelper(self._PARSER_NAME, skype_db.getDBFile(), Account.Type.SKYPE, Account.Type.SKYPE, account_instance) @@ -155,12 +162,17 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): messages_parser.get_thread_id() ) messages_parser.close() - + except SQLException as ex: + #Error parsing Skype db + self._logger.log(Level.WARNING, "Error parsing Skype Databases", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except (TskCoreException, BlackboardException) as ex: + #Severe error trying to add to case database.. case is not complete. + self._logger.log(Level.SEVERE, "Failed to add message artifacts" + + " to the case database.", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + finally: skype_db.close() - except (SQLException, TskCoreException) as ex: - #Error parsing Skype db - self._logger.log(Level.WARNING, "Error parsing Skype Databases", ex) - self._logger.log(Level.WARNING, traceback.format_exec()) class SkypeCallLogsParser(TskCallLogsParser): """ @@ -170,6 +182,20 @@ class SkypeCallLogsParser(TskCallLogsParser): """ def __init__(self, calllog_db): + """ + Big picture: + The query below creates a contacts_list_with_groups table, which + represents the recipient info. A chatItem record holds ids for + both the recipient and sender. The first join onto chatItem fills + in the blanks for the recipients. The second join back onto person + handles the sender info. The result is a table with all of the + communication details. + + Implementation details: + - message_type w/ value 3 appeared to be the call type, regardless + of if it was audio or video. + + """ super(SkypeCallLogsParser, self).__init__(calllog_db.runQuery( """ SELECT contacts_list_with_groups.conversation_id, @@ -281,6 +307,11 @@ class SkypeMessagesParser(TskMessagesParser): """ def __init__(self, message_db): + """ + This query is very similar to the call logs query, the only difference is + it grabs more columns in the SELECT and excludes message_types which have + the call type value (3). + """ super(SkypeMessagesParser, self).__init__(message_db.runQuery( """ SELECT contacts_list_with_groups.conversation_id, @@ -392,7 +423,8 @@ def _format_user_name(): column and a last_name column. Some of these columns can be null and our goal is to produce the cleanest data possible. In the event that both the first and last name columns are null, we return the skype_id - which is stored in the database as 'entry_id'. + which is stored in the database as 'entry_id'. Commas are removed from the name + so that we can concatenate names into a comma seperate list for group chats. """ return """ From b5370307c5baba3dffa669e5df29f7edc0d91d24 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 19 Sep 2019 13:36:58 -0400 Subject: [PATCH 27/56] Fixed enum name. --- InternalPythonModules/android/fbmessenger.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InternalPythonModules/android/fbmessenger.py b/InternalPythonModules/android/fbmessenger.py index 2c4a1be284..5f8eb762fb 100644 --- a/InternalPythonModules/android/fbmessenger.py +++ b/InternalPythonModules/android/fbmessenger.py @@ -196,14 +196,14 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): fromAddress, recipientAddressList) - # at the end of th loop, add last message + # at the end of the loop, add last message messageArtifact = threadsDBHelper.addMessage( "FB Messenger Message", direction, fromAddress, recipientAddressList, timeStamp, - MessageReadStatusEnum.UNKNOWN, + MessageReadStatus.UNKNOWN, "", msgText, threadId) From 3544e43d3a436f718e8400c71afeee3bec0cf922 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 19 Sep 2019 14:04:21 -0400 Subject: [PATCH 28/56] Log stack trace on exceptions. --- InternalPythonModules/android/fbmessenger.py | 4 ++++ InternalPythonModules/android/imo.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/InternalPythonModules/android/fbmessenger.py b/InternalPythonModules/android/fbmessenger.py index 5f8eb762fb..2747889a9a 100644 --- a/InternalPythonModules/android/fbmessenger.py +++ b/InternalPythonModules/android/fbmessenger.py @@ -90,8 +90,10 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for account", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) except (TskCoreException, BlackboardException) as ex: self._logger.log(Level.WARNING, "Failed to add Facebook Messenger contact artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) finally: contactsDb.close() @@ -210,8 +212,10 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): 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, BlackboardException) as ex: self._logger.log(Level.WARNING, "Failed to add FB Messenger message artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) finally: threadsDb.close() diff --git a/InternalPythonModules/android/imo.py b/InternalPythonModules/android/imo.py index 5a653ff9d5..e42115d62d 100644 --- a/InternalPythonModules/android/imo.py +++ b/InternalPythonModules/android/imo.py @@ -137,8 +137,10 @@ class IMOAnalyzer(general.AndroidComponentAnalyzer): 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, BlackboardException) as ex: self._logger.log(Level.WARNING, "Failed to message artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) finally: friendsDb.close() From ab8860a63e8f23eb53cff19fcdeeddf79889c1b2 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 19 Sep 2019 14:26:26 -0400 Subject: [PATCH 29/56] updated skype and tested it --- InternalPythonModules/android/skype.py | 46 +++++++++++++++++++------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index 8444d401cb..ef7c0df0d5 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -41,6 +41,7 @@ from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel.Blackboard import BlackboardException +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.datamodel import Account from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus @@ -88,7 +89,7 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): self._PARSER_NAME = "Skype Parser" self._VERSION = "8.15.0.428" - def get_account_instance(self, skype_db): + def get_user_account(self, skype_db): account_query_result = skype_db.runQuery( """ SELECT entry_id, @@ -104,19 +105,36 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): def analyze(self, dataSource, fileManager, context): #Skype databases are of the form: live:XYZ.db, where - #XYZ is the skype id of the user. + #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) + "live:", False, self._SKYPE_PACKAGE_NAME) + for skype_db in skype_dbs: try: - account_instance = self.get_account_instance(skype_db) - if account_instance is None: - helper = CommunicationArtifactsHelper(self._PARSER_NAME, - skype_db.getDBFile(), Account.Type.SKYPE) + #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 query 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(self._PARSER_NAME, - skype_db.getDBFile(), Account.Type.SKYPE, - Account.Type.SKYPE, account_instance) + helper = CommunicationArtifactsHelper( + current_case.getSleuthkitCase(), self._PARSER_NAME, + skype_db.getDBFile(), Account.Type.SKYPE, + Account.Type.SKYPE, user_account_instance + ) #Query for contacts and iterate row by row adding #each contact artifact @@ -168,9 +186,13 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): self._logger.log(Level.WARNING, traceback.format_exc()) except (TskCoreException, BlackboardException) as ex: #Severe error trying to add to case database.. case is not complete. - self._logger.log(Level.SEVERE, "Failed to add message artifacts" + - " to the case database.", ex) + #These exceptions are thrown by the CommunicationArtifactsHelper. + self._logger.log(Level.SEVERE, + "Failed to add message artifacts to the case database.", 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: skype_db.close() From 0c98287e83d8fcd22ec51f567923c9f7b5b12519 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 19 Sep 2019 16:10:31 -0400 Subject: [PATCH 30/56] Updated skype to be more fault tolerant --- InternalPythonModules/android/skype.py | 159 ++++++++++++++++--------- 1 file changed, 103 insertions(+), 56 deletions(-) diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index ef7c0df0d5..23c8114c87 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -119,7 +119,7 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): user_account_instance = self.get_user_account(skype_db) except SQLException as ex: self._logger.log(Level.WARNING, - "Error query for the user account in the Skype db.", ex) + "Error querying for the user account in the Skype db.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) current_case = Case.getCurrentCaseThrows() @@ -135,67 +135,114 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): skype_db.getDBFile(), Account.Type.SKYPE, Account.Type.SKYPE, user_account_instance ) - - #Query for contacts and iterate row by row adding - #each contact artifact - contacts_parser = SkypeContactsParser(skype_db) - while contacts_parser.next(): - helper.addContact( - contacts_parser.get_account_name(), - contacts_parser.get_contact_name(), - contacts_parser.get_phone(), - contacts_parser.get_home_phone(), - contacts_parser.get_mobile_phone(), - contacts_parser.get_email() - ) - contacts_parser.close() - - #Query for call logs and iterate row by row adding - #each call log artifact - calllog_parser = SkypeCallLogsParser(skype_db) - while calllog_parser.next(): - helper.addCalllog( - calllog_parser.get_call_direction(), - calllog_parser.get_phone_number_from(), - calllog_parser.get_phone_number_to(), - calllog_parser.get_call_start_date_time(), - calllog_parser.get_call_end_date_time(), - calllog_parser.get_call_type() - ) - calllog_parser.close() - - #Query for messages and iterate row by row adding - #each message artifact - messages_parser = SkypeMessagesParser(skype_db) - while messages_parser.next(): - helper.addMessage( - messages_parser.get_message_type(), - messages_parser.get_message_direction(), - messages_parser.get_phone_number_from(), - messages_parser.get_phone_number_to(), - messages_parser.get_message_date_time(), - messages_parser.get_message_read_status(), - messages_parser.get_message_subject(), - messages_parser.get_message_text(), - messages_parser.get_thread_id() - ) - messages_parser.close() - except SQLException as ex: - #Error parsing Skype db - self._logger.log(Level.WARNING, "Error parsing Skype Databases", ex) - self._logger.log(Level.WARNING, traceback.format_exc()) - except (TskCoreException, BlackboardException) as ex: - #Severe error trying to add to case database.. case is not complete. - #These exceptions are thrown by the CommunicationArtifactsHelper. - self._logger.log(Level.SEVERE, - "Failed to add message artifacts to the case database.", ex) - self._logger.log(Level.SEVERE, traceback.format_exc()) + 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()) finally: skype_db.close() + def parse_contacts(self, skype_db, helper): + #Query for contacts and iterate row by row adding + #each contact artifact + try: + contacts_parser = SkypeContactsParser(skype_db) + while contacts_parser.next(): + helper.addContact( + contacts_parser.get_account_name(), + contacts_parser.get_contact_name(), + contacts_parser.get_phone(), + contacts_parser.get_home_phone(), + contacts_parser.get_mobile_phone(), + contacts_parser.get_email() + ) + contacts_parser.close() + except SQLException as ex: + #Error parsing Skype db + self._logger.log(Level.WARNING, + "Error parsing contact database for call logs artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + #Severe error trying to add to case database.. case is not complete. + #These exceptions are thrown by the CommunicationArtifactsHelper. + self._logger.log(Level.SEVERE, + "Failed to add contact artifacts to the case database.", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except BlackboardException as ex: + #Failed to post notification to blackboard + self._logger.log(Level.WARNING, + "Failed to post contact artifact to the blackboard", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + + def parse_calllogs(self, skype_db, helper): + #Query for call logs and iterate row by row adding + #each call log artifact + try: + calllog_parser = SkypeCallLogsParser(skype_db) + while calllog_parser.next(): + helper.addCalllog( + calllog_parser.get_call_direction(), + calllog_parser.get_phone_number_from(), + calllog_parser.get_phone_number_to(), + calllog_parser.get_call_start_date_time(), + calllog_parser.get_call_end_date_time(), + calllog_parser.get_call_type() + ) + calllog_parser.close() + except SQLException as ex: + #Error parsing Skype db + self._logger.log(Level.WARNING, + "Error parsing Skype database for call logs artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + #Severe error trying to add to case database.. case is not complete. + #These exceptions are thrown by the CommunicationArtifactsHelper. + self._logger.log(Level.SEVERE, + "Failed to add call log artifacts to the case database.", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except BlackboardException as ex: + #Failed to post notification to blackboard + self._logger.log(Level.WARNING, + "Failed to post call log artifact to the blackboard", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + + def parse_messages(self, skype_db, helper): + #Query for messages and iterate row by row adding + #each message artifact + try: + messages_parser = SkypeMessagesParser(skype_db) + while messages_parser.next(): + helper.addMessage( + messages_parser.get_message_type(), + messages_parser.get_message_direction(), + messages_parser.get_phone_number_from(), + messages_parser.get_phone_number_to(), + messages_parser.get_message_date_time(), + messages_parser.get_message_read_status(), + messages_parser.get_message_subject(), + messages_parser.get_message_text(), + messages_parser.get_thread_id() + ) + messages_parser.close() + except SQLException as ex: + #Error parsing Skype db + self._logger.log(Level.WARNING, + "Error parsing Skype database for message artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + #Severe error trying to add to case database.. case is not complete. + #These exceptions are thrown by the CommunicationArtifactsHelper. + self._logger.log(Level.SEVERE, + "Failed to add message artifacts to the case database.", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except BlackboardException as ex: + #Failed to post notification to blackboard + self._logger.log(Level.WARNING, + "Failed to post message artifact to the blackboard", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + class SkypeCallLogsParser(TskCallLogsParser): """ Extracts TSK_CALLLOG information from the Skype database. From 596a12531c1617dcda65dfc23d6b98a8dc99d6c0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 19 Sep 2019 17:31:24 -0400 Subject: [PATCH 31/56] Changed where nocurrentcase bails out, closed all dbs after processing rather than during --- InternalPythonModules/android/skype.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index 23c8114c87..e93782e4a7 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -110,9 +110,8 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): #package. skype_dbs = AppSQLiteDB.findAppDatabases(dataSource, "live:", False, self._SKYPE_PACKAGE_NAME) - - for skype_db in skype_dbs: - try: + try: + for skype_db in skype_dbs: #Attempt to get the user account id from the database user_account_instance = None try: @@ -138,11 +137,12 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): 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()) - finally: - skype_db.close() + 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 parse_contacts(self, skype_db, helper): #Query for contacts and iterate row by row adding From 9f4ef71696df1c4688173f238ad90564dbf21deb Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 19 Sep 2019 17:44:20 -0400 Subject: [PATCH 32/56] Address review comments. --- InternalPythonModules/android/shareit.py | 30 ++++++++++++------ InternalPythonModules/android/xender.py | 40 +++++++++++++++++------- InternalPythonModules/android/zapya.py | 34 +++++++++++++------- 3 files changed, 70 insertions(+), 34 deletions(-) diff --git a/InternalPythonModules/android/shareit.py b/InternalPythonModules/android/shareit.py index 8e3ebd3823..bccc9b9a3b 100644 --- a/InternalPythonModules/android/shareit.py +++ b/InternalPythonModules/android/shareit.py @@ -54,18 +54,20 @@ and adds artifacts to the case. """ class ShareItAnalyzer(general.AndroidComponentAnalyzer): - moduleName = "ShareIT Analyzer" - progName = "ShareIt" - def __init__(self): self._logger = Logger.getLogger(self.__class__.__name__) + self._PACKAGE_NAME = "com.lenovo.anyshare.gps" + self._MODULE_NAME = "ShareIt Analyzer" + self._MESSAGE_TYPE = "ShareIt Message" + self._VERSION = "5.0.28_ww" def analyze(self, dataSource, fileManager, context): - historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "history.db", True, "com.lenovo.anyshare.gps") + historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "history.db", True, self._PACKAGE_NAME) for historyDb in historyDbs: try: - historyDbHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, historyDb.getDBFile(), + 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, import_path FROM history" @@ -89,7 +91,7 @@ class ShareItAnalyzer(general.AndroidComponentAnalyzer): timeStamp = historyResultSet.getLong("timestamp") / 1000 messageArtifact = transferDbHelper.addMessage( - "ShareIt Message", + self._MESSAGE_TYPE, direction, fromAddress, toAddress, @@ -97,14 +99,22 @@ class ShareItAnalyzer(general.AndroidComponentAnalyzer): 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) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to create ShareIt message artifacts.", 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() diff --git a/InternalPythonModules/android/xender.py b/InternalPythonModules/android/xender.py index d1cecd3a82..e3c72f33e2 100644 --- a/InternalPythonModules/android/xender.py +++ b/InternalPythonModules/android/xender.py @@ -52,28 +52,36 @@ Finds the SQLite DB for Xender, parses the DB for contacts & messages, and adds artifacts to the case. """ class XenderAnalyzer(general.AndroidComponentAnalyzer): - - moduleName = "Xender Analyzer" - progName = "Xender" - + def __init__(self): self._logger = Logger.getLogger(self.__class__.__name__) + self._PACKAGE_NAME = "cn.xender" + self._MODULE_NAME = "Xender Analyzer" + self._MESSAGE_TYPE = "Xender Message" + self._VERSION = "4.6.5" + def analyze(self, dataSource, fileManager, context): selfAccountAddress = None - transactionDbs = AppSQLiteDB.findAppDatabases(dataSource, "trans-history-db", True, "cn.xender") + 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 selfAccountAddress: selfAccountAddress = Account.Address(profilesResultSet.getString("device_id"), profilesResultSet.getString("nick_name")) - - transactionDbHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, transactionDb.getDBFile(), + # create artifacts helper + if selfAccountAddress is not None: + transactionDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), + self._MODULE_NAME, transactionDb.getDBFile(), Account.Type.XENDER, Account.Type.XENDER, selfAccountAddress ) + 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) @@ -96,13 +104,13 @@ class XenderAnalyzer(general.AndroidComponentAnalyzer): timeStamp = messagesResultSet.getLong("f_create_time") / 1000 messageArtifact = transactionDbHelper.addMessage( - "Xender Message", + self._MESSAGE_TYPE, direction, fromAddress, toAddress, timeStamp, MessageReadStatus.UNKNOWN, - None, + None, # subject msgBody, messagesResultSet.getString("c_session_id") ) @@ -110,8 +118,16 @@ class XenderAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for profiles", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to create Xender message artifacts.", 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() diff --git a/InternalPythonModules/android/zapya.py b/InternalPythonModules/android/zapya.py index 9bcb5753d1..672795c076 100644 --- a/InternalPythonModules/android/zapya.py +++ b/InternalPythonModules/android/zapya.py @@ -54,18 +54,21 @@ and adds artifacts to the case. """ class ZapyaAnalyzer(general.AndroidComponentAnalyzer): - moduleName = "Zapya Analyzer" - progName = "Zapya" - def __init__(self): self._logger = Logger.getLogger(self.__class__.__name__) + self._PACKAGE_NAME = "com.dewmobile.kuaiya.play" + self._MODULE_NAME = "Zapya Analyzer" + self._MESSAGE_TYPE = "Zapya Message" + self._VERSION = "5.8.3" def analyze(self, dataSource, fileManager, context): - transferDbs = AppSQLiteDB.findAppDatabases(dataSource, "transfer20.db", True, "com.dewmobile.kuaiya.play") + transferDbs = AppSQLiteDB.findAppDatabases(dataSource, "transfer20.db", True, self._PACKAGE_NAME) for transferDb in transferDbs: try: - transferDbHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, transferDb.getDBFile(), + 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" @@ -89,23 +92,30 @@ class ZapyaAnalyzer(general.AndroidComponentAnalyzer): timeStamp = transfersResultSet.getLong("createtime") / 1000 messageArtifact = transferDbHelper.addMessage( - "Zapya Message", + self._MESSAGE_TYPE, direction, fromAddress, toAddress, timeStamp, MessageReadStatus.UNKNOWN, - None, + 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 transfer", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to create Zapya message artifacts.", 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() From 2bb38065a69395adb7a3f626d27a1acea92610b3 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 19 Sep 2019 18:16:06 -0400 Subject: [PATCH 33/56] Updated viber to new infra changes and changed how exception handling is managed --- .../android/TskCallLogsParser.py | 16 +- .../android/TskMessagesParser.py | 17 +- InternalPythonModules/android/viber.py | 168 ++++++++++++------ 3 files changed, 130 insertions(+), 71 deletions(-) diff --git a/InternalPythonModules/android/TskCallLogsParser.py b/InternalPythonModules/android/TskCallLogsParser.py index 763ba3c15f..d4e6942134 100644 --- a/InternalPythonModules/android/TskCallLogsParser.py +++ b/InternalPythonModules/android/TskCallLogsParser.py @@ -17,7 +17,8 @@ See the License for the specific language governing permissions and limitations under the License. """ from ResultSetIterator import ResultSetIterator -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CallMediaType +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection from org.sleuthkit.datamodel import Account class TskCallLogsParser(ResultSetIterator): @@ -35,14 +36,15 @@ class TskCallLogsParser(ResultSetIterator): def __init__(self, result_set): super(TskCallLogsParser, self).__init__(result_set) self._DEFAULT_STRING = "" - self._DEFAULT_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN + self._DEFAULT_DIRECTION = CommunicationDirection.UNKNOWN self._DEFAULT_ADDRESS = None - self._DEFAULT_CALL_TYPE = AppDBParserHelper.CallMediaType.UNKNOWN + self._DEFAULT_CALL_TYPE = CallMediaType.UNKNOWN + self._DEFAULT_LONG = -1L - self.INCOMING_CALL = AppDBParserHelper.CommunicationDirection.INCOMING - self.OUTGOING_CALL = AppDBParserHelper.CommunicationDirection.OUTGOING - self.AUDIO_CALL = AppDBParserHelper.CallMediaType.AUDIO - self.VIDEO_CALL = AppDBParserHelper.CallMediaType.VIDEO + self.INCOMING_CALL = CommunicationDirection.INCOMING + self.OUTGOING_CALL = CommunicationDirection.OUTGOING + self.AUDIO_CALL = CallMediaType.AUDIO + self.VIDEO_CALL = CallMediaType.VIDEO def get_call_direction(self): return self._DEFAULT_DIRECTION diff --git a/InternalPythonModules/android/TskMessagesParser.py b/InternalPythonModules/android/TskMessagesParser.py index 15c4166db7..4568a7400c 100644 --- a/InternalPythonModules/android/TskMessagesParser.py +++ b/InternalPythonModules/android/TskMessagesParser.py @@ -18,8 +18,9 @@ limitations under the License. """ from ResultSetIterator import ResultSetIterator from org.sleuthkit.datamodel import Account -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper - +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection + class TskMessagesParser(ResultSetIterator): """ Generic TSK_MESSAGE artifact template. Each of these methods @@ -35,14 +36,14 @@ class TskMessagesParser(ResultSetIterator): super(TskMessagesParser, self).__init__(result_set) self._DEFAULT_TEXT = "" self._DEFAULT_LONG = -1L - self._DEFAULT_MSG_READ_STATUS = AppDBParserHelper.MessageReadStatusEnum.UNKNOWN + self._DEFAULT_MSG_READ_STATUS = MessageReadStatus.UNKNOWN self._DEFAULT_ACCOUNT_ADDRESS = None - self._DEFAULT_COMMUNICATION_DIRECTION = AppDBParserHelper.CommunicationDirection.UNKNOWN + self._DEFAULT_COMMUNICATION_DIRECTION = CommunicationDirection.UNKNOWN - self.INCOMING = AppDBParserHelper.CommunicationDirection.INCOMING - self.OUTGOING = AppDBParserHelper.CommunicationDirection.OUTGOING - self.READ = AppDBParserHelper.MessageReadStatusEnum.READ - self.UNREAD = AppDBParserHelper.MessageReadStatusEnum.UNREAD + self.INCOMING = CommunicationDirection.INCOMING + self.OUTGOING = CommunicationDirection.OUTGOING + self.READ = MessageReadStatus.READ + self.UNREAD = MessageReadStatus.UNREAD def get_message_type(self): return self._DEFAULT_TEXT diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index e6949b169e..5689b86be5 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -16,7 +16,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ - from java.io import File from java.lang import Class from java.lang import ClassNotFoundException @@ -26,18 +25,26 @@ from java.sql import ResultSet from java.sql import SQLException from java.sql import Statement from java.util.logging import Level +from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.coreutils import Logger +from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB -from org.sleuthkit.autopsy.coreutils import AppDBParserHelper + +from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.ingest import IngestJobContext from org.sleuthkit.datamodel import AbstractFile from org.sleuthkit.datamodel import BlackboardArtifact from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import Content from org.sleuthkit.datamodel import TskCoreException +from org.sleuthkit.datamodel.Blackboard import BlackboardException +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.datamodel import Account +from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import MessageReadStatus +from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection from TskMessagesParser import TskMessagesParser from TskContactsParser import TskContactsParser from TskCallLogsParser import TskCallLogsParser @@ -49,6 +56,14 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): """ Parses the Viber App databases for TSK contacts, message and calllog artifacts. + + The Viber v11.5.0 database structure is as follows: + - People can take part in N conversation(s). A conversation can have M + members and messages are exchanged in a conversation. + - Viber has a conversation table, a participant table (the people/members in the above + analogy) and a messages table. + - Each row of the participants table maps a person to a conversation_id + - Each row in the messages table has a from participant id and a conversation id. """ def __init__(self): @@ -71,61 +86,110 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): #Extract TSK_CONTACT and TSK_CALLLOG information for contact_and_calllog_db in contact_and_calllog_dbs: - helper = AppDBParserHelper(self._PARSER_NAME, + current_case = Case.getCurrentCaseThrows() + helper = CommunicationArtifactsHelper( + current_case.getSleuthkitCase(), self._PARSER_NAME, contact_and_calllog_db.getDBFile(), Account.Type.VIBER) - - contacts_parser = ViberContactsParser(contact_and_calllog_db) - while contacts_parser.next(): - helper.addContact( - contacts_parser.get_account_name(), - contacts_parser.get_contact_name(), - contacts_parser.get_phone(), - contacts_parser.get_home_phone(), - contacts_parser.get_mobile_phone(), - contacts_parser.get_email() - ) - contacts_parser.close() - - calllog_parser = ViberCallLogsParser(contact_and_calllog_db) - while calllog_parser.next(): - helper.addCalllog( - calllog_parser.get_call_direction(), - calllog_parser.get_phone_number_from(), - calllog_parser.get_phone_number_to(), - calllog_parser.get_call_start_date_time(), - calllog_parser.get_call_end_date_time(), - calllog_parser.get_call_type() - ) - calllog_parser.close() - - contact_and_calllog_db.close() + 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: - helper = AppDBParserHelper(self._PARSER_NAME, + current_case = Case.getCurrentCaseThrows() + helper = CommunicationArtifactsHelper( + current_case.getSleuthkitCase(), self._PARSER_NAME, message_db.getDBFile(), Account.Type.VIBER) + self.parse_messages(message_db, helper) - messages_parser = ViberMessagesParser(message_db) - while messages_parser.next(): - helper.addMessage( - messages_parser.get_message_type(), - messages_parser.get_message_direction(), - messages_parser.get_phone_number_from(), - messages_parser.get_phone_number_to(), - messages_parser.get_message_date_time(), - messages_parser.get_message_read_status(), - messages_parser.get_message_subject(), - messages_parser.get_message_text(), - messages_parser.get_thread_id() - ) - messages_parser.close() + except NoCurrentCaseException as ex: + self._logger.log(Level.WARNING, "No case currently open.", ex) + self._logger.log(Level.WARNING, traceback.format_exec()) + + for message_db in messages_db: + message_db.close() + + for contact_and_calllog_db in contact_and_calllog_dbs: + contact_and_calllog_db.close() - message_db.close() - except (SQLException, TskCoreException) as ex: - #Error parsing Viber db - self._logger.log(Level.WARNING, "Error parsing Viber Databases", ex) + def parse_contacts(self, contacts_db, helper): + try: + contacts_parser = ViberContactsParser(contacts_db) + while contacts_parser.next(): + helper.addContact( + contacts_parser.get_account_name(), + contacts_parser.get_contact_name(), + contacts_parser.get_phone(), + contacts_parser.get_home_phone(), + contacts_parser.get_mobile_phone(), + contacts_parser.get_email() + ) + contacts_parser.close() + except SQLException as ex: + self._logger.log(Level.WARNING, "Error querying the viber database for contacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exec()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, + "Error adding viber contacts artifact to case database.", ex) + self._logger.log(Level.SEVERE, traceback.format_exec()) + except BlackboardException as ex: + self._logger.log(Level.WARNING, + "Error posting viber contacts artifact to the blackboard.", ex) self._logger.log(Level.WARNING, traceback.format_exec()) + def parse_calllogs(self, calllogs_db, helper): + try: + calllog_parser = ViberCallLogsParser(calllogs_db) + while calllog_parser.next(): + helper.addCalllog( + calllog_parser.get_call_direction(), + calllog_parser.get_phone_number_from(), + calllog_parser.get_phone_number_to(), + calllog_parser.get_call_start_date_time(), + calllog_parser.get_call_end_date_time(), + calllog_parser.get_call_type() + ) + calllog_parser.close() + except SQLException as ex: + self._logger.log(Level.WARNING, "Error querying the viber database for calllogs.", ex) + self._logger.log(Level.WARNING, traceback.format_exec()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, + "Error adding viber calllogs artifact to case database.", ex) + self._logger.log(Level.SEVERE, traceback.format_exec()) + except BlackboardException as ex: + self._logger.log(Level.WARNING, + "Error posting viber calllogs artifact to the blackboard.", ex) + self._logger.log(Level.WARNING, traceback.format_exec()) + + + def parse_messages(self, messages_db, helper): + try: + messages_parser = ViberMessagesParser(messages_db) + while messages_parser.next(): + helper.addMessage( + messages_parser.get_message_type(), + messages_parser.get_message_direction(), + messages_parser.get_phone_number_from(), + messages_parser.get_phone_number_to(), + messages_parser.get_message_date_time(), + messages_parser.get_message_read_status(), + messages_parser.get_message_subject(), + messages_parser.get_message_text(), + messages_parser.get_thread_id() + ) + messages_parser.close() + except SQLException as ex: + self._logger.log(Level.WARNING, "Error querying the viber database for messages.", ex) + self._logger.log(Level.WARNING, traceback.format_exec()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, + "Error adding viber messages artifact to case database.", ex) + self._logger.log(Level.SEVERE, traceback.format_exec()) + except BlackboardException as ex: + self._logger.log(Level.WARNING, + "Error posting viber messages artifact to the blackboard.", ex) + self._logger.log(Level.WARNING, traceback.format_exec()) + class ViberCallLogsParser(TskCallLogsParser): """ Extracts TSK_CALLLOG information from the Viber database. @@ -227,14 +291,6 @@ class ViberMessagesParser(TskMessagesParser): def __init__(self, message_db): """ - For our purposes, the Viber datamodel is as follows: - - People can take part in N conversation(s). A conversation can have M - members and messages are exchanged in a conversation. - - Viber has a conversation table, a participant table (the people/members in the above - analogy) and a messages table. - - Each row of the participants table maps a person to a conversation_id - - Each row in the messages table has a from participant id and a conversation id. - The query below does the following: - The first two inner joins on participants and participants_info build the 1 to many (M) mappings between the sender and the recipients for each From 27388c109536f9b3bab181f533ad824a7c55e9fa Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 19 Sep 2019 19:42:02 -0400 Subject: [PATCH 34/56] Address review comments. --- .../android/installedapps.py | 22 +++- InternalPythonModules/android/operabrowser.py | 88 +++++++++---- InternalPythonModules/android/oruxmaps.py | 31 +++-- InternalPythonModules/android/sbrowser.py | 116 ++++++++++++------ 4 files changed, 183 insertions(+), 74 deletions(-) diff --git a/InternalPythonModules/android/installedapps.py b/InternalPythonModules/android/installedapps.py index ceb8526924..0ea9ce5d08 100644 --- a/InternalPythonModules/android/installedapps.py +++ b/InternalPythonModules/android/installedapps.py @@ -29,6 +29,7 @@ from java.util.logging import Level from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB @@ -55,12 +56,17 @@ class InstalledApplicationsAnalyzer(general.AndroidComponentAnalyzer): def __init__(self): self._logger = Logger.getLogger(self.__class__.__name__) + self._PACKAGE_NAME = "com.android.vending" + self._MODULE_NAME = "Android Installed Applications Analyzer" + self._VERSION = "5.1.1" ## Android version + self.current_case = None def analyze(self, dataSource, fileManager, context): - libraryDbs = AppSQLiteDB.findAppDatabases(dataSource, "library.db", True, "com.android.vending") + libraryDbs = AppSQLiteDB.findAppDatabases(dataSource, "library.db", True, self._PACKAGE_NAME) for libraryDb in libraryDbs: try: - libraryDbHelper = ArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + current_case = Case.getCurrentCaseThrows() + libraryDbHelper = ArtifactsHelper(current_case.getSleuthkitCase(), self.moduleName, libraryDb.getDBFile()) queryString = "SELECT doc_id, purchase_time FROM ownership" ownershipResultSet = libraryDb.runQuery(queryString) @@ -72,8 +78,16 @@ class InstalledApplicationsAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for installed applications. ", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to adding installed application artifacts.", 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() diff --git a/InternalPythonModules/android/operabrowser.py b/InternalPythonModules/android/operabrowser.py index 876c5063dc..7b61f0d500 100644 --- a/InternalPythonModules/android/operabrowser.py +++ b/InternalPythonModules/android/operabrowser.py @@ -29,6 +29,7 @@ from java.util.logging import Level from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB @@ -56,12 +57,17 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): def __init__(self): self._logger = Logger.getLogger(self.__class__.__name__) - + self._PACKAGE_NAME = "com.opera.browser" + self._MODULE_NAME = "Opera Analyzer" + self._PROGRAM_NAME = "Opera" + self._VERSION = "53.1.2569" + self.current_case = None + def analyzeCookies(self, dataSource, fileManager, context): - cookiesDbs = AppSQLiteDB.findAppDatabases(dataSource, "Cookies", True, "com.opera.browser") + cookiesDbs = AppSQLiteDB.findAppDatabases(dataSource, "Cookies", True, self._PACKAGE_NAME) for cookiesDb in cookiesDbs: try: - cookiesDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + cookiesDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), self.moduleName, cookiesDb.getDBFile()) cookiesResultSet = cookiesDb.runQuery("SELECT host_key, name, value, creation_utc FROM cookies") if cookiesResultSet is not None: @@ -71,22 +77,27 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): createTime, cookiesResultSet.getString("name"), cookiesResultSet.getString("value"), - self.progName) + self._PROGRAM_NAME) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera cookies.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add Opera cookie artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add Opera cookie 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()) finally: cookiesDb.close() def analyzeHistory(self, dataSource, fileManager, context): - historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.opera.browser") + historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, self._PACKAGE_NAME) for historyDb in historyDbs: try: - historyDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + historyDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), self.moduleName, historyDb.getDBFile()) historyResultSet = historyDb.runQuery("SELECT url, title, last_visit_time FROM urls") if historyResultSet is not None: @@ -96,21 +107,26 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): accessTime, "", # referrer historyResultSet.getString("title"), - self.progName) + self._PROGRAM_NAME) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera history.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add Opera history artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add Opera history 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()) finally: historyDb.close() def analyzeDownloads(self, dataSource, fileManager, context): - downloadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.opera.browser") + downloadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, self._PACKAGE_NAME) for downloadsDb in downloadsDbs: try: - downloadsDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + downloadsDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), self.moduleName, downloadsDb.getDBFile()) queryString = "SELECT target_path, start_time, url FROM downloads"\ " INNER JOIN downloads_url_chains ON downloads.id = downloads_url_chains.id" @@ -121,20 +137,25 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): downloadsDbHelper.addWebDownload( downloadsResultSet.getString("target_path"), startTime, downloadsResultSet.getString("url"), - self.progName) + self._PROGRAM_NAME) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera downloads.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add Opera download artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add Opera download 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()) finally: downloadsDb.close() def analyzeAutofill(self, dataSource, fileManager, context): - autofillDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.opera.browser") + autofillDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, self._PACKAGE_NAME) for autofillDb in autofillDbs: try: - autofillDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + autofillDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), self.moduleName, autofillDb.getDBFile()) autofillsResultSet = autofillDb.runQuery("SELECT name, value, count, date_created FROM autofill") if autofillsResultSet is not None: @@ -148,16 +169,21 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera autofill.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add Opera autofill artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add Opera autofill 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()) finally: autofillDb.close() def analyzeWebFormAddress(self, dataSource, fileManager, context): - webFormAddressDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.opera.browser") + webFormAddressDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, self._PACKAGE_NAME) for webFormAddressDb in webFormAddressDbs: try: - webFormAddressDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), + webFormAddressDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), self.moduleName, webFormAddressDb.getDBFile()) queryString = "SELECT street_address, city, state, zipcode, country_code, date_modified, first_name, last_name, number, email FROM autofill_profiles "\ " INNER JOIN autofill_profile_names"\ @@ -186,12 +212,26 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for Opera web form addresses.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add Opera form address artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add Opera form address 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()) finally: webFormAddressDb.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.analyzeCookies(dataSource, fileManager, context) self.analyzeHistory(dataSource, fileManager, context) self.analyzeDownloads(dataSource, fileManager, context) diff --git a/InternalPythonModules/android/oruxmaps.py b/InternalPythonModules/android/oruxmaps.py index 87f243e8af..4682ad3721 100644 --- a/InternalPythonModules/android/oruxmaps.py +++ b/InternalPythonModules/android/oruxmaps.py @@ -30,6 +30,7 @@ from java.sql import Statement from java.util.logging import Level from java.util import ArrayList from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.autopsy.casemodule.services import FileManager from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil @@ -53,18 +54,22 @@ Analyzes database created by ORUX Maps. """ class OruxMapsAnalyzer(general.AndroidComponentAnalyzer): - moduleName = "Orux Maps Analyzer" - programName = "Orux Maps" def __init__(self): self._logger = Logger.getLogger(self.__class__.__name__) + self._PACKAGE_NAME = "oruxmaps" + self._MODULE_NAME = "OruxMaps Analyzer" + self._PROGRAM_NAME = "OruxMaps" + self._VERSION = "7.5.7" + self.current_case = None def analyze(self, dataSource, fileManager, context): - oruxMapsTrackpointsDbs = AppSQLiteDB.findAppDatabases(dataSource, "oruxmapstracks.db", True, "oruxmaps") + oruxMapsTrackpointsDbs = AppSQLiteDB.findAppDatabases(dataSource, "oruxmapstracks.db", True, self._PACKAGE_NAME) for oruxMapsTrackpointsDb in oruxMapsTrackpointsDbs: try: - oruxDbHelper = ArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, oruxMapsTrackpointsDb.getDBFile()) + 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) @@ -75,7 +80,7 @@ class OruxMapsAnalyzer(general.AndroidComponentAnalyzer): poisResultSet.getDouble("poilon"), poisResultSet.getLong("poitime") / 1000, # milliseconds since unix epoch poisResultSet.getString("poiname"), - self.programName) + self._PROGRAM_NAME) trackpointsQueryString = "SELECT trkptlat, trkptlon, trkpttime FROM trackpoints" trackpointsResultSet = oruxMapsTrackpointsDb.runQuery(trackpointsQueryString) @@ -86,10 +91,18 @@ class OruxMapsAnalyzer(general.AndroidComponentAnalyzer): trackpointsResultSet.getDouble("trkptlon"), trackpointsResultSet.getLong("trkpttime") / 1000, # milliseconds since unix epoch "", - self.programName) + self._PROGRAM_NAME) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for Orux Map trackpoints.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add Orux Map trackpoint artifacts.", 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() diff --git a/InternalPythonModules/android/sbrowser.py b/InternalPythonModules/android/sbrowser.py index ed15fdd7d6..8d25678900 100644 --- a/InternalPythonModules/android/sbrowser.py +++ b/InternalPythonModules/android/sbrowser.py @@ -29,6 +29,7 @@ from java.util.logging import Level from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB @@ -51,18 +52,20 @@ and adds artifacts to the case. """ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): - moduleName = "SBrowser Parser" - progName = "SBrowser" - def __init__(self): self._logger = Logger.getLogger(self.__class__.__name__) + self._PACKAGE_NAME = "com.sec.android.app.sbrowser" + self._MODULE_NAME = "SBrowser Analyzer" + self._PROGRAM_NAME = "SBrowser" + self._VERSION = "10.1.00.27" + self.current_case = None def analyzeBookmarks(self, dataSource, fileManager, context): - sbrowserDbs = AppSQLiteDB.findAppDatabases(dataSource, "sbrowser.db", True, "com.sec.android.app.sbrowser") + sbrowserDbs = AppSQLiteDB.findAppDatabases(dataSource, "sbrowser.db", True, self._PACKAGE_NAME) for sbrowserDb in sbrowserDbs: try: - sbrowserDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, sbrowserDb.getDBFile()) + sbrowserDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, sbrowserDb.getDBFile()) bookmarkResultSet = sbrowserDb.runQuery("SELECT url, title, created FROM bookmarks WHERE url IS NOT NULL") if bookmarkResultSet is not None: while bookmarkResultSet.next(): @@ -70,22 +73,27 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): sbrowserDbHelper.addWebBookmark( bookmarkResultSet.getString("url"), bookmarkResultSet.getString("title"), createTime, - self.progName) + self._PROGRAM_NAME) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser bookmarks.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add SBrowser bookmark artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add SBrowser bookmark 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()) finally: sbrowserDb.close() def analyzeCookies(self, dataSource, fileManager, context): - cookiesDbs = AppSQLiteDB.findAppDatabases(dataSource, "Cookies", True, "com.sec.android.app.sbrowser") + cookiesDbs = AppSQLiteDB.findAppDatabases(dataSource, "Cookies", True, self._PACKAGE_NAME) for cookiesDb in cookiesDbs: try: - cookiesDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, cookiesDb.getDBFile()) + cookiesDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, cookiesDb.getDBFile()) cookiesResultSet = cookiesDb.runQuery("SELECT host_key, name, value, creation_utc FROM cookies") if cookiesResultSet is not None: while cookiesResultSet.next(): @@ -94,23 +102,28 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): createTime, cookiesResultSet.getString("name"), cookiesResultSet.getString("value"), - self.progName) + self._PROGRAM_NAME) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser cookies.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add SBrowser cookie artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add SBrowser cookie 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()) finally: cookiesDb.close() def analyzeHistory(self, dataSource, fileManager, context): - historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.sec.android.app.sbrowser") + historyDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, self._PACKAGE_NAME) for historyDb in historyDbs: try: - historyDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, historyDb.getDBFile()) + historyDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, historyDb.getDBFile()) historyResultSet = historyDb.runQuery("SELECT url, title, last_visit_time FROM urls") if historyResultSet is not None: while historyResultSet.next(): @@ -119,22 +132,27 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): accessTime, "", # referrer historyResultSet.getString("title"), - self.progName) + self._PROGRAM_NAME) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser history.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add SBrowser history artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add SBrowser history 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()) finally: historyDb.close() def analyzeDownloads(self, dataSource, fileManager, context): - downloadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, "com.sec.android.app.sbrowser") + downloadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "History", True, self._PACKAGE_NAME) for downloadsDb in downloadsDbs: try: - downloadsDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, downloadsDb.getDBFile()) + downloadsDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, downloadsDb.getDBFile()) queryString = "SELECT target_path, start_time, url FROM downloads"\ " INNER JOIN downloads_url_chains ON downloads.id = downloads_url_chains.id" downloadsResultSet = downloadsDb.runQuery(queryString) @@ -144,21 +162,26 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): downloadsDbHelper.addWebDownload( downloadsResultSet.getString("target_path"), startTime, downloadsResultSet.getString("url"), - self.progName) + self._PROGRAM_NAME) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser downloads.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add SBrowser download artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add SBrowser download 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()) finally: downloadsDb.close() def analyzeAutofill(self, dataSource, fileManager, context): - autofillDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.sec.android.app.sbrowser") + autofillDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, self._PACKAGE_NAME) for autofillDb in autofillDbs: try: - autofillDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, autofillDb.getDBFile()) + autofillDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, autofillDb.getDBFile()) autofillsResultSet = autofillDb.runQuery("SELECT name, value, count, date_created FROM autofill INNER JOIN autofill_dates ON autofill.pair_id = autofill_dates.pair_id") if autofillsResultSet is not None: while autofillsResultSet.next(): @@ -171,17 +194,22 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser autofill.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add SBrowser autofill artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add SBrowser autofill 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()) finally: autofillDb.close() def analyzeWebFormAddress(self, dataSource, fileManager, context): - webFormAddressDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, "com.sec.android.app.sbrowser") + webFormAddressDbs = AppSQLiteDB.findAppDatabases(dataSource, "Web Data", True, self._PACKAGE_NAME) for webFormAddressDb in webFormAddressDbs: try: - webFormAddressDbHelper = WebBrowserArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - self.moduleName, webFormAddressDb.getDBFile()) + webFormAddressDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, webFormAddressDb.getDBFile()) queryString = "SELECT street_address, city, state, zipcode, country_code, date_modified, first_name, last_name, number, email FROM autofill_profiles "\ " INNER JOIN autofill_profile_names"\ " ON autofill_profiles.guid = autofill_profile_names.guid"\ @@ -209,12 +237,26 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query results for SBrowser form addresses.", ex) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add SBrowser form address artifacts.", ex) + self._logger.log(Level.WARNING, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add SBrowser form address 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()) finally: webFormAddressDb.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) From 4f2b0d50214441c004d33ececdf0fd1562b623a0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 19 Sep 2019 19:55:28 -0400 Subject: [PATCH 35/56] Fixed type in traceback --- InternalPythonModules/android/viber.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index 5689b86be5..6a7e4b2451 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -103,7 +103,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): except NoCurrentCaseException as ex: self._logger.log(Level.WARNING, "No case currently open.", ex) - self._logger.log(Level.WARNING, traceback.format_exec()) + self._logger.log(Level.WARNING, traceback.format_exc()) for message_db in messages_db: message_db.close() @@ -126,15 +126,15 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): contacts_parser.close() except SQLException as ex: self._logger.log(Level.WARNING, "Error querying the viber database for contacts.", ex) - self._logger.log(Level.WARNING, traceback.format_exec()) + self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Error adding viber contacts artifact to case database.", ex) - self._logger.log(Level.SEVERE, traceback.format_exec()) + self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Error posting viber contacts artifact to the blackboard.", ex) - self._logger.log(Level.WARNING, traceback.format_exec()) + self._logger.log(Level.WARNING, traceback.format_exc()) def parse_calllogs(self, calllogs_db, helper): try: @@ -151,15 +151,15 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): calllog_parser.close() except SQLException as ex: self._logger.log(Level.WARNING, "Error querying the viber database for calllogs.", ex) - self._logger.log(Level.WARNING, traceback.format_exec()) + self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Error adding viber calllogs artifact to case database.", ex) - self._logger.log(Level.SEVERE, traceback.format_exec()) + self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Error posting viber calllogs artifact to the blackboard.", ex) - self._logger.log(Level.WARNING, traceback.format_exec()) + self._logger.log(Level.WARNING, traceback.format_exc()) def parse_messages(self, messages_db, helper): @@ -180,15 +180,15 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): messages_parser.close() except SQLException as ex: self._logger.log(Level.WARNING, "Error querying the viber database for messages.", ex) - self._logger.log(Level.WARNING, traceback.format_exec()) + self._logger.log(Level.WARNING, traceback.format_exc()) except TskCoreException as ex: self._logger.log(Level.SEVERE, "Error adding viber messages artifact to case database.", ex) - self._logger.log(Level.SEVERE, traceback.format_exec()) + self._logger.log(Level.SEVERE, traceback.format_exc()) except BlackboardException as ex: self._logger.log(Level.WARNING, "Error posting viber messages artifact to the blackboard.", ex) - self._logger.log(Level.WARNING, traceback.format_exec()) + self._logger.log(Level.WARNING, traceback.format_exc()) class ViberCallLogsParser(TskCallLogsParser): """ From 4c93fae369e83c1313dfd7d1be059754d6d4012a Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 19 Sep 2019 20:07:22 -0400 Subject: [PATCH 36/56] Fixed missing import. --- InternalPythonModules/android/shareit.py | 1 + InternalPythonModules/android/xender.py | 1 + InternalPythonModules/android/zapya.py | 1 + 3 files changed, 3 insertions(+) diff --git a/InternalPythonModules/android/shareit.py b/InternalPythonModules/android/shareit.py index bccc9b9a3b..937a663393 100644 --- a/InternalPythonModules/android/shareit.py +++ b/InternalPythonModules/android/shareit.py @@ -29,6 +29,7 @@ from java.util.logging import Level from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB diff --git a/InternalPythonModules/android/xender.py b/InternalPythonModules/android/xender.py index e3c72f33e2..cdc520fb11 100644 --- a/InternalPythonModules/android/xender.py +++ b/InternalPythonModules/android/xender.py @@ -29,6 +29,7 @@ from java.util.logging import Level from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB diff --git a/InternalPythonModules/android/zapya.py b/InternalPythonModules/android/zapya.py index 672795c076..230405075d 100644 --- a/InternalPythonModules/android/zapya.py +++ b/InternalPythonModules/android/zapya.py @@ -29,6 +29,7 @@ from java.util.logging import Level from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB From 1a5751b6c2c08dc2d2f9248fc2aed3f8f66319a9 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 19 Sep 2019 20:54:58 -0400 Subject: [PATCH 37/56] Address review comments. --- InternalPythonModules/android/fbmessenger.py | 68 ++++++++++++++------ 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/InternalPythonModules/android/fbmessenger.py b/InternalPythonModules/android/fbmessenger.py index 2747889a9a..765d727e1a 100644 --- a/InternalPythonModules/android/fbmessenger.py +++ b/InternalPythonModules/android/fbmessenger.py @@ -29,6 +29,7 @@ from java.util.logging import Level from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule import NoCurrentCaseException from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil from org.sleuthkit.autopsy.coreutils import AppSQLiteDB @@ -55,10 +56,17 @@ and adds artifacts to the case. """ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): - selfAccountAddress = None - def __init__(self): self._logger = Logger.getLogger(self.__class__.__name__) + + self._FB_MESSENGER_PACKAGE_NAME = "com.facebook.orca" + self._FACEBOOK_PACKAGE_NAME = "com.facebook.katana" + self._MODULE_NAME = "FB Messenger Analyzer" + self._MESSAGE_TYPE = "Facebook Messenger" + self._VERSION = "239.0.0.41" ## FB version number. Did not find independent version number in FB Messenger + + self.selfAccountAddress = None + self.current_case = None ## Analyze contacts def analyzeContacts(self, dataSource, fileManager, context): @@ -66,18 +74,23 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): ## In our example the FB Messenger database was empty. ## But the FB database had the data. - contactsDbs = AppSQLiteDB.findAppDatabases(dataSource, "contacts_db2", True, "com.facebook.katana") + contactsDbs = AppSQLiteDB.findAppDatabases(dataSource, "contacts_db2", True, self._FACEBOOK_PACKAGE_NAME) for contactsDb in contactsDbs: try: selfAccountResultSet = contactsDb.runQuery("SELECT fbid, display_name FROM contacts WHERE added_time_ms = 0") if selfAccountResultSet: - if not self.selfAccountAddress: self.selfAccountAddress = Account.Address(selfAccountResultSet.getString("fbid"), selfAccountResultSet.getString("display_name")) - contactsDBHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - "Facebook Parser", contactsDb.getDBFile(), + if self.selfAccountAddress is not None: + contactsDBHelper = CommunicationArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, contactsDb.getDBFile(), Account.Type.FACEBOOK, Account.Type.FACEBOOK, self.selfAccountAddress ) + else: + contactsDBHelper = CommunicationArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, contactsDb.getDBFile(), + Account.Type.FACEBOOK) + contactsResultSet = contactsDb.runQuery("SELECT fbid, display_name FROM contacts WHERE added_time_ms <> " + self.selfAccountAddress.getUniqueID() ) if contactsResultSet is not None: while contactsResultSet.next(): @@ -91,8 +104,11 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for account", ex) self._logger.log(Level.WARNING, traceback.format_exc()) - except (TskCoreException, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add Facebook Messenger contact artifacts.", ex) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Failed to add Facebook Messenger contact 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()) finally: contactsDb.close() @@ -111,15 +127,21 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): ## Analyze messages def analyzeMessages(self, dataSource, fileManager, context): - threadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "threads_db2", True, "com.facebook.orca") + threadsDbs = AppSQLiteDB.findAppDatabases(dataSource, "threads_db2", True, self._FB_MESSENGER_PACKAGE_NAME) for threadsDb in threadsDbs: try: - threadsDBHelper = CommunicationArtifactsHelper(Case.getCurrentCase().getSleuthkitCase(), - "FB Messenger Parser", threadsDb.getDBFile(), + if self.selfAccountAddress is not None: + threadsDBHelper = CommunicationArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, threadsDb.getDBFile(), Account.Type.FACEBOOK, Account.Type.FACEBOOK, self.selfAccountAddress ) + else: + threadsDBHelper = CommunicationArtifactsHelper(self.current_case.getSleuthkitCase(), + self._MODULE_NAME, threadsDb.getDBFile(), + Account.Type.FACEBOOK) ## Messages are found in the messages table. 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 sqlString = "SELECT msg_id, text, sender, timestamp_ms, messages.thread_key as thread_key,"\ " snippet, thread_participants.user_key as user_key, thread_users.name as name FROM messages"\ " JOIN thread_participants ON messages.thread_key = thread_participants.thread_key"\ @@ -145,13 +167,13 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): # Create message artifact with collected attributes if oldMsgId is not None: messageArtifact = threadsDBHelper.addMessage( - "FB Messenger Message", + self._MESSAGE_TYPE, direction, fromAddress, recipientAddressList, timeStamp, MessageReadStatus.UNKNOWN, - "", + "", # subject msgText, threadId) @@ -191,35 +213,43 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): threadId = messagesResultSet.getString("thread_key") - else: # same msgId as last, just collect recipient from current row - self.addRecipientToList(messagesResultSet.getString("user_key"), messagesResultSet.getString("name"), fromAddress, recipientAddressList) # at the end of the loop, add last message messageArtifact = threadsDBHelper.addMessage( - "FB Messenger Message", + self._MESSAGE_TYPE, direction, fromAddress, recipientAddressList, 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, BlackboardException) as ex: - self._logger.log(Level.WARNING, "Failed to add FB Messenger message artifacts.", ex) + 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()) finally: threadsDb.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.analyzeMessages(dataSource, fileManager, context) From 5b92d1a82dcc0c0cb54c2f7a90a1bc95b0fdc3df Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 20 Sep 2019 10:45:36 -0400 Subject: [PATCH 38/56] Attachment fix --- InternalPythonModules/android/skype.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index e93782e4a7..f9bd6f5466 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -388,7 +388,6 @@ class SkypeMessagesParser(TskMessagesParser): contacts_list_with_groups.participants, time, content, - file_name, device_gallery_path, is_sender_me, person_id as sender_id, @@ -467,13 +466,11 @@ class SkypeMessagesParser(TskMessagesParser): content = self.result_set.getString("content") if content is not None: - file_name = self.result_set.getString("file_name") file_path = self.result_set.getString("device_gallery_path") #if a file name and file path are associated with a message, append it - if file_name is not None and file_path is not None: - attachment = "File Name: "+file_name +"\n"+ "File Path: "+file_path - return general.appendAttachmentList(content, [attachment]) + if file_path is not None: + return general.appendAttachmentList(content, [file_path]) return content From 7334e8b6b03d16e24690263fb47ffe4aca1eb49d Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Fri, 20 Sep 2019 10:48:25 -0400 Subject: [PATCH 39/56] File encryption module handle files better Handle file extension/location used to also determine if a file is encrypted or not. --- .../Bundle.properties-MERGED | 1 + .../EncryptionDetectionFileIngestModule.java | 57 ++++++++++++++++--- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED index 905c5b3d84..1a851a0803 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED @@ -1,6 +1,7 @@ EncryptionDetectionDataSourceIngestModule.artifactComment.bitlocker=Bitlocker encryption detected. EncryptionDetectionDataSourceIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f). EncryptionDetectionDataSourceIngestModule.processing.message=Checking image for encryption. +EncryptionDetectionFileIngestModule.artifactComment.location=Location/File Extension determine encrypted file. EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected. EncryptionDetectionFileIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f). EncryptionDetectionFileIngestModule.getDesc.text=Looks for files with the specified minimum entropy. diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java index 9afafb7831..1bc96cd78d 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java @@ -29,6 +29,8 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.BufferUnderflowException; +import java.util.HashMap; +import java.util.Map; import java.util.logging.Level; import org.apache.tika.exception.EncryptedDocumentException; import org.apache.tika.exception.TikaException; @@ -76,6 +78,8 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter private static final String[] FILE_IGNORE_LIST = {"hiberfile.sys", "pagefile.sys"}; + private final Map knownEncryptedLocationExtensions = createLocationExtensionMap(); + private final IngestServices services = IngestServices.getInstance(); private final Logger logger = services.getLogger(EncryptionDetectionModuleFactory.getModuleName()); private FileTypeDetector fileTypeDetector; @@ -106,7 +110,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException { try { validateSettings(); - this.context = context; + this.context = context; blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard(); fileTypeDetector = new FileTypeDetector(); @@ -119,6 +123,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter @Messages({ "EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected.", + "EncryptionDetectionFileIngestModule.artifactComment.location=Location/File Extension determine encrypted file.", "EncryptionDetectionFileIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f)." }) @Override @@ -130,12 +135,12 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter * verify the file hasn't been deleted. */ if (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) - && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) - && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR) - && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR) - && (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || slackFilesAllowed) - && !file.getKnown().equals(TskData.FileKnown.KNOWN) - && !file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) { + && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) + && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR) + && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR) + && (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || slackFilesAllowed) + && !file.getKnown().equals(TskData.FileKnown.KNOWN) + && !file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) { /* * Is the file in FILE_IGNORE_LIST? */ @@ -155,6 +160,9 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter */ String mimeType = fileTypeDetector.getMIMEType(file); if (mimeType.equals("application/octet-stream") && isFileEncryptionSuspected(file)) { + if (checkFileLocationExtension(file)) { + return flagFile(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED, Bundle.EncryptionDetectionFileIngestModule_artifactComment_location()); + } return flagFile(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED, String.format(Bundle.EncryptionDetectionFileIngestModule_artifactComment_suspected(), calculatedEntropy)); } else if (isFilePasswordProtected(file)) { @@ -198,7 +206,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter if (context.fileIngestIsCancelled()) { return IngestModule.ProcessResult.OK; } - + BlackboardArtifact artifact = file.newArtifact(artifactType); artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, EncryptionDetectionModuleFactory.getModuleName(), comment)); @@ -325,7 +333,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter try { accessDatabase = databaseBuilder.open(); } catch (IOException | BufferUnderflowException | IndexOutOfBoundsException ignored) { - return passwordProtected; + return passwordProtected; } /* * No exception has been thrown at this point, so the file @@ -406,4 +414,35 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter return possiblyEncrypted; } + + /** + * This method checks if the AbstractFile input is in a location that is + * known to hold encrypted files. It must meet the requirements and location + * of known encrypted file(s) + * + * @param file AbstractFile to be checked. + * + * @return True if file extension and location match known values. + * + */ + private boolean checkFileLocationExtension(AbstractFile file) { + String filePath = file.getParentPath().replace("/", ""); + if (knownEncryptedLocationExtensions.containsKey(filePath)) { + if (knownEncryptedLocationExtensions.get(filePath).equals(file.getNameExtension())) { + return true; + } + } + return false; + } + + /* + * This method creates the map of paths and extensions that are known to have encrypted files + * + * @return Map of path and extension of files + */ + private Map createLocationExtensionMap() { + Map locationExtensionMap = new HashMap(); + locationExtensionMap.put(".android_secure", "asec"); + return locationExtensionMap; + } } From 1dbc41420bb51393d30a3a450bc3c49dcc94a162 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 20 Sep 2019 11:13:13 -0400 Subject: [PATCH 40/56] Removed mime type from attachment --- InternalPythonModules/android/whatsapp.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/InternalPythonModules/android/whatsapp.py b/InternalPythonModules/android/whatsapp.py index eeb561923a..328f371c76 100644 --- a/InternalPythonModules/android/whatsapp.py +++ b/InternalPythonModules/android/whatsapp.py @@ -379,8 +379,7 @@ class WhatsAppMessagesParser(TskMessagesParser): M.timestamp AS send_timestamp, M.received_timestamp, M.remote_resource AS group_sender, - M.media_url As attachment, - M.media_mime_type as attachment_mimetype + M.media_url As attachment FROM (SELECT jid, recipients FROM wadb.wa_contacts AS WC @@ -449,9 +448,6 @@ class WhatsAppMessagesParser(TskMessagesParser): message = self.result_set.getString("content") attachment = self.result_set.getString("attachment") if attachment is not None: - mime_type = self.result_set.getString("attachment_mimetype") - if mime_type is not None: - attachment += "\nMIME type: " + mime_type return general.appendAttachmentList(message, [attachment]) return message From afbfeefff54ac7b6703ea7076eb2d3d2ed83e217 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 20 Sep 2019 11:42:43 -0400 Subject: [PATCH 41/56] Fixed bug --- .../sleuthkit/autopsy/communications/FiltersPanel.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java index a804735c32..37f197f5fe 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java @@ -257,9 +257,14 @@ final public class FiltersPanel extends JPanel { //clear the device filter widget when the case changes. devicesMap.clear(); devicesListPane.removeAll(); - - accountTypeMap.clear(); + + accountTypeMap.clear(); accountTypeListPane.removeAll(); + + CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(Account.Type.DEVICE, true); + accountTypeMap.put(Account.Type.DEVICE, panel.getCheckBox()); + accountTypeListPane.add(panel); + }); } From 7c1a5b9199e3b64e48a20041ee5dceb05507e14a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Fri, 20 Sep 2019 11:46:56 -0400 Subject: [PATCH 42/56] Fixed tango bug and type in viber analyzer --- InternalPythonModules/android/tangomessage.py | 2 +- InternalPythonModules/android/viber.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/InternalPythonModules/android/tangomessage.py b/InternalPythonModules/android/tangomessage.py index 97c1eee115..54480e8823 100644 --- a/InternalPythonModules/android/tangomessage.py +++ b/InternalPythonModules/android/tangomessage.py @@ -118,7 +118,7 @@ class TangoMessageAnalyzer(general.AndroidComponentAnalyzer): try: # index the artifact for keyword search blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard() - blackboard.postArtifact(artifact, MODULE_NAME) + blackboard.postArtifact(artifact, general.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()) diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index 6a7e4b2451..fb2b77ac7a 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -105,7 +105,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): self._logger.log(Level.WARNING, "No case currently open.", ex) self._logger.log(Level.WARNING, traceback.format_exc()) - for message_db in messages_db: + for message_db in message_dbs: message_db.close() for contact_and_calllog_db in contact_and_calllog_dbs: From fe1667b8df20f7368108fea81f249f9ecdb0ad97 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 20 Sep 2019 12:14:55 -0400 Subject: [PATCH 43/56] added fucntion per Brian request --- .../autopsy/communications/FiltersPanel.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java index 37f197f5fe..a9c6f58e4e 100644 --- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java @@ -129,9 +129,7 @@ final public class FiltersPanel extends JPanel { public FiltersPanel() { initComponents(); - CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(Account.Type.DEVICE, true); - accountTypeMap.put(Account.Type.DEVICE, panel.getCheckBox()); - accountTypeListPane.add(panel); + initalizeDeviceAccountType(); deviceRequiredLabel.setVisible(false); accountTypeRequiredLabel.setVisible(false); @@ -259,12 +257,9 @@ final public class FiltersPanel extends JPanel { devicesListPane.removeAll(); accountTypeMap.clear(); - accountTypeListPane.removeAll(); + accountTypeListPane.removeAll(); - CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(Account.Type.DEVICE, true); - accountTypeMap.put(Account.Type.DEVICE, panel.getCheckBox()); - accountTypeListPane.add(panel); - + initalizeDeviceAccountType(); }); } @@ -274,6 +269,12 @@ final public class FiltersPanel extends JPanel { IngestManager.getInstance().removeIngestModuleEventListener(ingestListener); IngestManager.getInstance().removeIngestJobEventListener(ingestJobListener); } + + private void initalizeDeviceAccountType() { + CheckBoxIconPanel panel = createAccoutTypeCheckBoxPanel(Account.Type.DEVICE, true); + accountTypeMap.put(Account.Type.DEVICE, panel.getCheckBox()); + accountTypeListPane.add(panel); + } /** * Populate the Account Types filter widgets From 7587698738cfb76f0705ea6ed66a720562c81df3 Mon Sep 17 00:00:00 2001 From: Raman Date: Fri, 20 Sep 2019 12:25:10 -0400 Subject: [PATCH 44/56] fixing merge conflict --- InternalPythonModules/android/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InternalPythonModules/android/module.py b/InternalPythonModules/android/module.py index 7c2d1f21ac..e5c90bc99e 100644 --- a/InternalPythonModules/android/module.py +++ b/InternalPythonModules/android/module.py @@ -109,7 +109,7 @@ class AndroidIngestModule(DataSourceIngestModule): xender.XenderAnalyzer(), zapya.ZapyaAnalyzer(), shareit.ShareItAnalyzer(), line.LineAnalyzer(), whatsapp.WhatsAppAnalyzer(), textnow.TextNowAnalyzer(), skype.SkypeAnalyzer(), viber.ViberAnalyzer(), - fbmessenger.FBMessengerAnalyzer() + fbmessenger.FBMessengerAnalyzer(), sbrowser.SBrowserAnalyzer(), operabrowser.OperaAnalyzer(), oruxmaps.OruxMapsAnalyzer(), installedapps.InstalledApplicationsAnalyzer()] From ba4e832695c065a8d1f6150e1d1180d8840a8d3c Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Fri, 20 Sep 2019 14:54:48 -0400 Subject: [PATCH 45/56] Bug fix --- .../infrastructure/ReportWizardFileOptionsVisualPanel.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardFileOptionsVisualPanel.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardFileOptionsVisualPanel.java index 4efc674473..d2db3a75c9 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardFileOptionsVisualPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardFileOptionsVisualPanel.java @@ -80,8 +80,10 @@ class ReportWizardFileOptionsVisualPanel extends javax.swing.JPanel { optionsList.setCellRenderer(new OptionsListRenderer()); optionsList.setVisibleRowCount(-1); - selectAllButton.setEnabled(true); - deselectAllButton.setEnabled(false); + selectAllButton.setEnabled(false); + deselectAllButton.setEnabled(true); + + wizPanel.setFinish(true); // Add the ability to enable and disable Tag checkboxes to the list optionsList.addMouseListener(new MouseAdapter() { From a3c34329fcae93b20e5268a95c76870cb910bedd Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Fri, 20 Sep 2019 16:54:54 -0400 Subject: [PATCH 46/56] Update EncryptionDetectionFileIngestModule.java make map static and address codacy issue --- .../EncryptionDetectionFileIngestModule.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java index 1bc96cd78d..e405c19c15 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java @@ -78,7 +78,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter private static final String[] FILE_IGNORE_LIST = {"hiberfile.sys", "pagefile.sys"}; - private final Map knownEncryptedLocationExtensions = createLocationExtensionMap(); + private static final Map knownEncryptedLocationExtensions = createLocationExtensionMap(); private final IngestServices services = IngestServices.getInstance(); private final Logger logger = services.getLogger(EncryptionDetectionModuleFactory.getModuleName()); @@ -427,20 +427,21 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter */ private boolean checkFileLocationExtension(AbstractFile file) { String filePath = file.getParentPath().replace("/", ""); - if (knownEncryptedLocationExtensions.containsKey(filePath)) { - if (knownEncryptedLocationExtensions.get(filePath).equals(file.getNameExtension())) { - return true; - } + if ((knownEncryptedLocationExtensions.containsKey(filePath)) + && (knownEncryptedLocationExtensions.get(filePath).equals(file.getNameExtension()))) + { + return true; } return false; } - + /* - * This method creates the map of paths and extensions that are known to have encrypted files - * + * This method creates the map of paths and extensions that are known to + * have encrypted files + * * @return Map of path and extension of files */ - private Map createLocationExtensionMap() { + private static Map createLocationExtensionMap() { Map locationExtensionMap = new HashMap(); locationExtensionMap.put(".android_secure", "asec"); return locationExtensionMap; From 24379c7cca40f6f08999c8280cd127bc146646fc Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Fri, 20 Sep 2019 17:39:33 -0400 Subject: [PATCH 47/56] Fixes to Save Tagged Hashes module --- .../modules/hashdatabase/HashDbManager.java | 4 +-- .../HashesReportModuleSettings.java | 17 ++++++----- .../SaveTaggedHashesToHashDbConfigPanel.form | 2 +- .../SaveTaggedHashesToHashDbConfigPanel.java | 30 ++++++++++++------- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 9c7e536f01..3b90240ebc 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -693,9 +693,7 @@ public class HashDbManager implements PropertyChangeListener { return filePath; } - public static abstract class HashDb implements Serializable { - - private static final long serialVersionUID = 1L; + public static abstract class HashDb { /** * Indicates how files with hashes stored in a particular hash database diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/HashesReportModuleSettings.java b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/HashesReportModuleSettings.java index 097e141ee3..77ca2894ff 100755 --- a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/HashesReportModuleSettings.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/HashesReportModuleSettings.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.report.modules.taggedhashes; -import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.report.ReportModuleSettings; /** @@ -28,7 +27,7 @@ class HashesReportModuleSettings implements ReportModuleSettings { private static final long serialVersionUID = 1L; private final boolean exportAllTags; - private final HashDb hashDb; + private final String hashDbName; @Override public long getVersionNumber() { @@ -40,18 +39,18 @@ class HashesReportModuleSettings implements ReportModuleSettings { */ HashesReportModuleSettings() { exportAllTags = true; - hashDb = null; + hashDbName = ""; } /** * Configuration for the Tagged Hashes report module. * * @param exportAllTags Flag whether to export all tags. - * @param hashDb Selected HashDb object to export to + * @param hashDbName Name of selected hash database to export to */ - HashesReportModuleSettings(boolean exportAllTags, HashDb hashDb) { + HashesReportModuleSettings(boolean exportAllTags, String hashDbName) { this.exportAllTags = exportAllTags; - this.hashDb = hashDb; + this.hashDbName = hashDbName; } /** @@ -64,9 +63,11 @@ class HashesReportModuleSettings implements ReportModuleSettings { } /** + * Get name of the selected hash database. + * * @return the hashDb */ - public HashDb getHashDb() { - return hashDb; + public String getHashDbName() { + return hashDbName; } } diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.form b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.form index ae76eeb26d..6047a7a789 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.form +++ b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.form @@ -129,7 +129,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java index 3ad9990f06..d86b0f184a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/taggedhashes/SaveTaggedHashesToHashDbConfigPanel.java @@ -56,7 +56,8 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { private Map tagNameSelections = new LinkedHashMap<>(); private TagNamesListModel tagsNamesListModel = new TagNamesListModel(); private TagsNamesListCellRenderer tagsNamesRenderer = new TagsNamesListCellRenderer(); - private HashDb selectedHashSet = null; + private String selectedHashSetName; + private List updateableHashSets = new ArrayList<>(); SaveTaggedHashesToHashDbConfigPanel() { initComponents(); @@ -74,7 +75,7 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { } HashesReportModuleSettings getConfiguration() { - return new HashesReportModuleSettings(jAllTagsCheckBox.isSelected(), selectedHashSet); + return new HashesReportModuleSettings(jAllTagsCheckBox.isSelected(), selectedHashSetName); } void setConfiguration(HashesReportModuleSettings settings) { @@ -84,11 +85,14 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // update tag selection jAllTagsCheckBox.setSelected(settings.isExportAllTags()); + if (settings.isExportAllTags()) { + selectAllTags(true); + } // update hash database selection - if (settings.getHashDb() != null) { + if (settings.getHashDbName() != null) { populateHashSetComponents(); - hashSetsComboBox.setSelectedItem(settings.getHashDb()); + hashSetsComboBox.setSelectedItem(settings.getHashDbName()); } } @@ -147,13 +151,14 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // Clear the components because this method is called both during construction // and when the user changes the hash set configuration. hashSetsComboBox.removeAllItems(); - + selectedHashSetName = ""; + // Get the updateable hash databases and add their hash set names to the // JComboBox component. - List updateableHashSets = HashDbManager.getInstance().getUpdateableHashSets(); + updateableHashSets = HashDbManager.getInstance().getUpdateableHashSets(); if (!updateableHashSets.isEmpty()) { for (HashDb hashDb : updateableHashSets) { - hashSetsComboBox.addItem(hashDb); + hashSetsComboBox.addItem(hashDb.getHashSetName()); } hashSetsComboBox.setEnabled(true); } else { @@ -182,7 +187,12 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { * @return A HashDb object representing the database or null. */ HashDb getSelectedHashDatabase() { - return selectedHashSet; + for (HashDb hashDb : updateableHashSets) { + if (hashDb.getHashSetName().equals(selectedHashSetName)) { + return hashDb; + } + } + return null; } // This class is a list model for the tag names JList component. @@ -341,7 +351,7 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { }//GEN-LAST:event_selectAllButtonActionPerformed private void hashSetsComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hashSetsComboBoxActionPerformed - selectedHashSet = (HashDb)hashSetsComboBox.getSelectedItem(); + selectedHashSetName = (String)hashSetsComboBox.getSelectedItem(); }//GEN-LAST:event_hashSetsComboBoxActionPerformed private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed @@ -377,7 +387,7 @@ class SaveTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton configureHashDatabasesButton; private javax.swing.JButton deselectAllButton; - private javax.swing.JComboBox hashSetsComboBox; + private javax.swing.JComboBox hashSetsComboBox; private javax.swing.JCheckBox jAllTagsCheckBox; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; From 4f7a585e3824a52b6b63707ab1b6bc2e58379bea Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Sun, 22 Sep 2019 09:13:23 -0400 Subject: [PATCH 48/56] Doxygen fixes --- .../autopsy/report/infrastructure/ReportGenerator.java | 2 ++ .../autopsy/report/modules/html/HTMLReport.java | 9 +++------ .../autopsy/report/modules/stix/STIXReportModule.java | 2 ++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java index 7b7c68a571..68d69ed88f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportGenerator.java @@ -282,6 +282,7 @@ public class ReportGenerator { /** * Run the TableReportModules using a SwingWorker. * + * @param tableReport * @param tableReportSettings settings for the table report */ private void generateTableReport(TableReportModule tableReport, TableReportSettings tableReportSettings) throws IOException { @@ -301,6 +302,7 @@ public class ReportGenerator { /** * Run the FileReportModules using a SwingWorker. * + * @param fileReportModule * @param fileReportSettings settings for the file report */ private void generateFileListReport(FileReportModule fileReportModule, FileReportSettings fileReportSettings) throws IOException { diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java index e0eba30501..46c1268f2c 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java @@ -461,7 +461,7 @@ public class HTMLReport implements TableReportModule { * temporary workaround to avoid modifying the TableReportModule interface. * * @param name Name of the data type - * @param comment Comment on the data type, may be the empty string + * @param description Comment on the data type, may be the empty string */ @Override public void startDataType(String name, String description) { @@ -644,7 +644,6 @@ public class HTMLReport implements TableReportModule { * temporary workaround to avoid modifying the TableReportModule interface. * * @param columnHeaders column headers - * @param sourceArtifact source blackboard artifact for the table data */ public void startContentTagsTable(List columnHeaders) { StringBuilder htmlOutput = new StringBuilder(); @@ -718,12 +717,10 @@ public class HTMLReport implements TableReportModule { /** * Saves a local copy of a tagged file and adds a row with a hyper link to - * the file. The content of the hyperlink is provided in linkHTMLContent. + * the file. * * @param row Values for each data cell in the row - * @param file The file to link to in the report. - * @param tagName the name of the tag that the content was flagged by - * @param linkHTMLContent the html that will be the body of the link + * @param contentTag The tag */ public void addRowWithTaggedContentHyperlink(List row, ContentTag contentTag) { Content content = contentTag.getContent(); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModule.java index 06ebacd550..5f384e4467 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/stix/STIXReportModule.java @@ -267,6 +267,7 @@ public class STIXReportModule implements GeneralReportModule { * * @param stix STIXPackage * @param output + * @param progressPanel */ private void processIndicators(STIXPackage stix, BufferedWriter output, ReportProgressPanel progressPanel) throws TskCoreException { if (stix.getIndicators() != null) { @@ -304,6 +305,7 @@ public class STIXReportModule implements GeneralReportModule { * * @param ind * @param result + * @param progressPanel * * @throws TskCoreException */ From 118477737f38c88312983f5e4f3d550c3311fd61 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Sep 2019 11:01:19 -0400 Subject: [PATCH 49/56] Bug fix --- .../infrastructure/ReportWizardFileOptionsVisualPanel.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardFileOptionsVisualPanel.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardFileOptionsVisualPanel.java index d2db3a75c9..dbb4889c47 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardFileOptionsVisualPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportWizardFileOptionsVisualPanel.java @@ -80,10 +80,10 @@ class ReportWizardFileOptionsVisualPanel extends javax.swing.JPanel { optionsList.setCellRenderer(new OptionsListRenderer()); optionsList.setVisibleRowCount(-1); - selectAllButton.setEnabled(false); - deselectAllButton.setEnabled(true); + selectAllButton.setEnabled(notAllSelected()); + deselectAllButton.setEnabled(anySelected()); - wizPanel.setFinish(true); + wizPanel.setFinish(anySelected()); // Add the ability to enable and disable Tag checkboxes to the list optionsList.addMouseListener(new MouseAdapter() { From ce9bd67bfc11247c11b07ba6987d62cf2658f157 Mon Sep 17 00:00:00 2001 From: Joe Ho Date: Mon, 23 Sep 2019 11:43:48 -0400 Subject: [PATCH 50/56] Add *_users.txt to report --- .../dsp/AddLogicalImageTask.java | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java index f5d728b633..94ecce0d96 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.logicalimager.dsp; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; +import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; @@ -53,14 +54,14 @@ import org.sleuthkit.datamodel.TskCoreException; /** * A runnable that - copy the logical image folder to a destination folder - add - * SearchResults.txt and users.txt files to report - add an image data source to the + * SearchResults.txt and *_users.txt files to report - add an image data source to the * case database. */ final class AddLogicalImageTask implements Runnable { private final static Logger LOGGER = Logger.getLogger(AddLogicalImageTask.class.getName()); private final static String SEARCH_RESULTS_TXT = "SearchResults.txt"; //NON-NLS - private final static String USERS_TXT = "users.txt"; //NON-NLS + private final static String USERS_TXT = "_users.txt"; //NON-NLS private final static String MODULE_NAME = "Logical Imager"; //NON-NLS private final static String ROOT_STR = "root"; // NON-NLS private final static String VHD_EXTENSION = ".vhd"; // NON-NLS @@ -102,7 +103,7 @@ final class AddLogicalImageTask implements Runnable { } /** - * Add SearchResults.txt and users.txt to the case + * Add SearchResults.txt and *_users.txt to the case * report Adds the image to the case database. */ @Messages({ @@ -148,7 +149,7 @@ final class AddLogicalImageTask implements Runnable { return; } - // Add the SearchResults.txt and users.txt to the case report + // Add the SearchResults.txt and *_users.txt to the case report String resultsFilename; if (Paths.get(dest.toString(), SEARCH_RESULTS_TXT).toFile().exists()) { resultsFilename = SEARCH_RESULTS_TXT; @@ -167,15 +168,25 @@ final class AddLogicalImageTask implements Runnable { } progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingToReport(resultsFilename)); - progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingToReport(USERS_TXT)); - status = addReport(Paths.get(dest.toString(), USERS_TXT), USERS_TXT + " " + src.getName()); - if (status != null) { - errorList.add(status); - callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); - return; + // All all *_users.txt files to report + File[] userFiles = dest.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(USERS_TXT); + } + }); + + for (File userFile : userFiles) { + progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingToReport(userFile.getName())); + status = addReport(userFile.toPath(), userFile.getName() + " " + src.getName()); + if (status != null) { + errorList.add(status); + callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); + return; + } + progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingToReport(userFile.getName())); } - progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingToReport(USERS_TXT)); - + // Get all VHD files in the dest directory List imagePaths = new ArrayList<>(); for (File f : dest.listFiles()) { From 41e5e22fccbd14703c98f80b4893b03aa10363b3 Mon Sep 17 00:00:00 2001 From: Joe Ho Date: Mon, 23 Sep 2019 12:13:22 -0400 Subject: [PATCH 51/56] Fix GUI for createVHD and finish image option --- .../configuration/ConfigVisualPanel2.form | 25 +++++++++++-------- .../configuration/ConfigVisualPanel2.java | 18 ++++++++----- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel2.form b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel2.form index 5628bdb709..ba5e2d327c 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel2.form +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel2.form @@ -101,9 +101,12 @@ - - + + + + + @@ -124,7 +127,7 @@ - + @@ -132,9 +135,9 @@ - + - + @@ -190,12 +193,13 @@ - - - - - + + + + + + @@ -472,6 +476,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel2.java index cadd5e7cca..770c55144a 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/ConfigVisualPanel2.java @@ -215,6 +215,7 @@ final class ConfigVisualPanel2 extends JPanel { org.openide.awt.Mnemonics.setLocalizedText(ruleSetFileLabel, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.ruleSetFileLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(finalizeImageWriter, org.openide.util.NbBundle.getMessage(ConfigVisualPanel2.class, "ConfigVisualPanel2.finalizeImageWriter.text")); // NOI18N + finalizeImageWriter.setEnabled(false); finalizeImageWriter.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { finalizeImageWriterActionPerformed(evt); @@ -345,9 +346,11 @@ final class ConfigVisualPanel2 extends JPanel { .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(flagEncryptionProgramsCheckBox) - .addComponent(finalizeImageWriter) + .addComponent(createVHDCheckBox) .addComponent(promptBeforeExit) - .addComponent(createVHDCheckBox)) + .addGroup(layout.createSequentialGroup() + .addGap(21, 21, 21) + .addComponent(finalizeImageWriter))) .addGap(0, 0, Short.MAX_VALUE)) .addComponent(jSeparator1))))) ); @@ -418,11 +421,12 @@ final class ConfigVisualPanel2 extends JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(flagEncryptionProgramsCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(finalizeImageWriter) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(promptBeforeExit) + .addComponent(createVHDCheckBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(createVHDCheckBox)))) + .addComponent(finalizeImageWriter) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(promptBeforeExit) + .addGap(19, 19, 19)))) ); }// //GEN-END:initComponents @@ -558,6 +562,7 @@ final class ConfigVisualPanel2 extends JPanel { private void createVHDCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createVHDCheckBoxActionPerformed config.setCreateVHD(createVHDCheckBox.isSelected()); + finalizeImageWriter.setEnabled(createVHDCheckBox.isSelected()); }//GEN-LAST:event_createVHDCheckBoxActionPerformed /** @@ -661,6 +666,7 @@ final class ConfigVisualPanel2 extends JPanel { finalizeImageWriter.setSelected(config.isFinalizeImageWriter()); promptBeforeExit.setSelected(config.isPromptBeforeExit()); createVHDCheckBox.setSelected(config.isCreateVHD()); + finalizeImageWriter.setEnabled(config.isCreateVHD()); LogicalImagerRuleSet ruleSet = getRuleSetFromCurrentConfig(); flagEncryptionProgramsCheckBox.setSelected(ruleSet.find(EncryptionProgramsRule.getName()) != null); RulesTableModel rulesTableModel = new RulesTableModel(); From b0c244909c5241d94c41699f970233ee1eaf3276 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Sep 2019 12:52:22 -0400 Subject: [PATCH 52/56] Command Line opions panel UI updates --- .../commandlineingest/Bundle.properties | 9 ++++--- .../Bundle.properties-MERGED | 9 ++++--- .../CommandLineIngestSettingsPanel.form | 24 ++++++------------- .../CommandLineIngestSettingsPanel.java | 23 +++++++----------- 4 files changed, 23 insertions(+), 42 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties index 9200d5dd2f..9c4f680119 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties @@ -2,12 +2,11 @@ OpenIDE-Module-Name=CommandLineAutopsy OptionsCategory_Keywords_Command_Line_Ingest_Settings=Command Line Ingest Settings OptionsCategory_Keywords_General=Options OptionsCategory_Name_Command_Line_Ingest=Command Line Ingest -CommandLineIngestSettingsPanel.bnEditIngestSettings.toolTipText=Ingest job settings for the command line processing mode context. -CommandLineIngestSettingsPanel.bnEditIngestSettings.text=Ingest Module Settings CommandLinePanel.jLabel1.text=Ingest is running from command line CommandLineStartupWindow.title.text=Running in Command Line Mode +CommandLineIngestSettingsPanel.bnEditIngestSettings.text=Configure Ingest CommandLineIngestSettingsPanel.bnEditReportSettings.actionCommand=Report Module Settings CommandLineIngestSettingsPanel.bnEditReportSettings.toolTipText=Report generation settings for the command line processing mode context. -CommandLineIngestSettingsPanel.bnEditReportSettings.text=Report Module Settings -CommandLineIngestSettingsPanel.jLabelReportConfig.text=Configure Report Generation for Command Line Ingest: -CommandLineIngestSettingsPanel.jLabelBaselineConfig.text=Configure Baseline Configuration for Command Line Ingest: +CommandLineIngestSettingsPanel.bnEditReportSettings.text=Configure Reporting +CommandLineIngestSettingsPanel.jLabelDescription.text=You can create cases, add data sources, run ingest modules, and generate reports from the command line.
This options panel allows you to configure the settings to use when running ingest modules and generating reports.
See the user documentation for details. +CommandLineIngestSettingsPanel.bnEditIngestSettings.toolTipText=Ingest job settings for the command line processing mode context. diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED index 9200d5dd2f..9c4f680119 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/Bundle.properties-MERGED @@ -2,12 +2,11 @@ OpenIDE-Module-Name=CommandLineAutopsy OptionsCategory_Keywords_Command_Line_Ingest_Settings=Command Line Ingest Settings OptionsCategory_Keywords_General=Options OptionsCategory_Name_Command_Line_Ingest=Command Line Ingest -CommandLineIngestSettingsPanel.bnEditIngestSettings.toolTipText=Ingest job settings for the command line processing mode context. -CommandLineIngestSettingsPanel.bnEditIngestSettings.text=Ingest Module Settings CommandLinePanel.jLabel1.text=Ingest is running from command line CommandLineStartupWindow.title.text=Running in Command Line Mode +CommandLineIngestSettingsPanel.bnEditIngestSettings.text=Configure Ingest CommandLineIngestSettingsPanel.bnEditReportSettings.actionCommand=Report Module Settings CommandLineIngestSettingsPanel.bnEditReportSettings.toolTipText=Report generation settings for the command line processing mode context. -CommandLineIngestSettingsPanel.bnEditReportSettings.text=Report Module Settings -CommandLineIngestSettingsPanel.jLabelReportConfig.text=Configure Report Generation for Command Line Ingest: -CommandLineIngestSettingsPanel.jLabelBaselineConfig.text=Configure Baseline Configuration for Command Line Ingest: +CommandLineIngestSettingsPanel.bnEditReportSettings.text=Configure Reporting +CommandLineIngestSettingsPanel.jLabelDescription.text=You can create cases, add data sources, run ingest modules, and generate reports from the command line.
This options panel allows you to configure the settings to use when running ingest modules and generating reports.
See the user documentation for details. +CommandLineIngestSettingsPanel.bnEditIngestSettings.toolTipText=Ingest job settings for the command line processing mode context. diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.form index ea8344c216..c20e802081 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.form @@ -60,11 +60,10 @@ - - + - +
@@ -72,14 +71,12 @@ - + - - - + - + @@ -101,17 +98,10 @@
- + - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java index 9d29070018..63bad0bd23 100755 --- a/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/commandlineingest/CommandLineIngestSettingsPanel.java @@ -99,8 +99,7 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { nodeScrollPane = new javax.swing.JScrollPane(); nodePanel = new javax.swing.JPanel(); bnEditIngestSettings = new javax.swing.JButton(); - jLabelBaselineConfig = new javax.swing.JLabel(); - jLabelReportConfig = new javax.swing.JLabel(); + jLabelDescription = new javax.swing.JLabel(); bnEditReportSettings = new javax.swing.JButton(); setPreferredSize(new java.awt.Dimension(810, 422)); @@ -120,9 +119,7 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabelBaselineConfig, org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.jLabelBaselineConfig.text")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(jLabelReportConfig, org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.jLabelReportConfig.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabelDescription, org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.jLabelDescription.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(bnEditReportSettings, org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.bnEditReportSettings.text")); // NOI18N bnEditReportSettings.setToolTipText(org.openide.util.NbBundle.getMessage(CommandLineIngestSettingsPanel.class, "CommandLineIngestSettingsPanel.bnEditReportSettings.toolTipText")); // NOI18N @@ -141,23 +138,20 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { .addContainerGap() .addGroup(nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(bnEditIngestSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabelBaselineConfig) - .addComponent(jLabelReportConfig) + .addComponent(jLabelDescription, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(bnEditReportSettings, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(362, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); nodePanelLayout.setVerticalGroup( nodePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(nodePanelLayout.createSequentialGroup() .addGap(27, 27, 27) - .addComponent(jLabelBaselineConfig) + .addComponent(jLabelDescription, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(bnEditIngestSettings) - .addGap(18, 18, 18) - .addComponent(jLabelReportConfig) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(bnEditReportSettings) - .addContainerGap(376, Short.MAX_VALUE)) + .addContainerGap(381, Short.MAX_VALUE)) ); nodeScrollPane.setViewportView(nodePanel); @@ -187,8 +181,7 @@ public class CommandLineIngestSettingsPanel extends javax.swing.JPanel { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton bnEditIngestSettings; private javax.swing.JButton bnEditReportSettings; - private javax.swing.JLabel jLabelBaselineConfig; - private javax.swing.JLabel jLabelReportConfig; + private javax.swing.JLabel jLabelDescription; private javax.swing.JPanel nodePanel; private javax.swing.JScrollPane nodeScrollPane; // End of variables declaration//GEN-END:variables From f790879c2465f3f02a0dc80e286081397439b5fc Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 23 Sep 2019 15:17:42 -0400 Subject: [PATCH 53/56] removed events tab from timeline filterpane --- .../org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java index 92ed7c6c8a..51df6e87e4 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java @@ -335,7 +335,9 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer eventsTreeTab.setGraphic(new ImageView("org/sleuthkit/autopsy/timeline/images/timeline_marker.png")); // NON-NLS eventsTreeTab.disableProperty().bind(controller.viewModeProperty().isNotEqualTo(ViewMode.DETAIL)); - final TabPane leftTabPane = new TabPane(filterTab, eventsTreeTab); + // There is a bug in the sort of the EventsTree, it doesn't seem to + //sort anything. For now removing from tabpane until fixed + final TabPane leftTabPane = new TabPane(filterTab); VBox.setVgrow(leftTabPane, Priority.ALWAYS); controller.viewModeProperty().addListener(viewMode -> { if (controller.getViewMode() != ViewMode.DETAIL) { From 88e1694de1cc40ec5189ffe281268b9ca2506c0a Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Sep 2019 17:41:38 -0400 Subject: [PATCH 54/56] Bug fix --- .../infrastructure/PortableCaseInterestingItemsListPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseInterestingItemsListPanel.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseInterestingItemsListPanel.java index 343fd8f0cc..55da66a73d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseInterestingItemsListPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/PortableCaseInterestingItemsListPanel.java @@ -73,7 +73,7 @@ class PortableCaseInterestingItemsListPanel extends javax.swing.JPanel { customizeComponents(); // update tag selection - jAllSetsCheckBox.setSelected(settings.areAllTagsSelected()); + jAllSetsCheckBox.setSelected(settings.areAllSetsSelected()); setNamesListBox.setEnabled(!jAllSetsCheckBox.isSelected()); selectButton.setEnabled(!jAllSetsCheckBox.isSelected()); deselectButton.setEnabled(!jAllSetsCheckBox.isSelected()); From 5e63db5db2eb30cf6293b77c0f369ad51726e263 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 24 Sep 2019 08:46:13 -0400 Subject: [PATCH 55/56] Addressed exceptions in ExtractRegistry --- .../recentactivity/ExtractRegistry.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index 628b84ea08..64b601f83e 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -1141,7 +1141,9 @@ class ExtractRegistry extends Extract { line = bufferedReader.readLine(); while (line != null && !line.isEmpty()) { entry = getSAMKeyValue(line); - userInfo.put(entry.getKey(), entry.getValue()); + if (entry != null) { + userInfo.put(entry.getKey(), entry.getValue()); + } line = bufferedReader.readLine(); } users.add(userInfo); @@ -1208,14 +1210,18 @@ class ExtractRegistry extends Extract { */ private BlackboardArtifact.Type getShellBagArtifact() throws TskCoreException { if (shellBagArtifactType == null) { - try { - tskCase.addBlackboardArtifactType(SHELLBAG_ARTIFACT_NAME, Bundle.Shellbag_Artifact_Display_Name()); //NON-NLS - } catch (TskDataException ex) { - // Artifact already exists - logger.log(Level.INFO, String.format("%s may have already been defined for this case", SHELLBAG_ARTIFACT_NAME), ex); - } - shellBagArtifactType = tskCase.getArtifactType(SHELLBAG_ARTIFACT_NAME); + + if(shellBagArtifactType == null) { + try { + tskCase.addBlackboardArtifactType(SHELLBAG_ARTIFACT_NAME, Bundle.Shellbag_Artifact_Display_Name()); //NON-NLS + } catch (TskDataException ex) { + // Artifact already exists + logger.log(Level.INFO, String.format("%s may have already been defined for this case", SHELLBAG_ARTIFACT_NAME)); + } + + shellBagArtifactType = tskCase.getArtifactType(SHELLBAG_ARTIFACT_NAME); + } } return shellBagArtifactType; From ada7493bee5b498385b3b1c451aa52d4d5a1898c Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Tue, 24 Sep 2019 10:10:17 -0400 Subject: [PATCH 56/56] address review comments Address review comments with added comment and changed description. --- .../modules/encryptiondetection/Bundle.properties-MERGED | 2 +- .../EncryptionDetectionFileIngestModule.java | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED index 1a851a0803..36198317db 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED @@ -1,7 +1,7 @@ EncryptionDetectionDataSourceIngestModule.artifactComment.bitlocker=Bitlocker encryption detected. EncryptionDetectionDataSourceIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f). EncryptionDetectionDataSourceIngestModule.processing.message=Checking image for encryption. -EncryptionDetectionFileIngestModule.artifactComment.location=Location/File Extension determine encrypted file. +EncryptionDetectionFileIngestModule.artifactComment.location=High entropy and known location/extension. EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected. EncryptionDetectionFileIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f). EncryptionDetectionFileIngestModule.getDesc.text=Looks for files with the specified minimum entropy. diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java index e405c19c15..20252d4eb4 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java @@ -77,7 +77,10 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter private static final String MIME_TYPE_PDF = "application/pdf"; private static final String[] FILE_IGNORE_LIST = {"hiberfile.sys", "pagefile.sys"}; - + + /** + * This maps file locations to file extensions that are known to be encrypted + */ private static final Map knownEncryptedLocationExtensions = createLocationExtensionMap(); private final IngestServices services = IngestServices.getInstance(); @@ -123,7 +126,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter @Messages({ "EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected.", - "EncryptionDetectionFileIngestModule.artifactComment.location=Location/File Extension determine encrypted file.", + "EncryptionDetectionFileIngestModule.artifactComment.location=High entropy and known location/extension.", "EncryptionDetectionFileIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f)." }) @Override