mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
5907: Update legacy Python modules to use Communication Artifacts helper.
This commit is contained in:
parent
f11a6ac526
commit
da016a0d34
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.coreutils;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
@ -286,6 +287,16 @@ public final class AppSQLiteDB {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns connection meta data.
|
||||
*
|
||||
* @return DatabaseMetaData
|
||||
* @throws SQLException
|
||||
*/
|
||||
public DatabaseMetaData getConnectionMetadata() throws SQLException {
|
||||
return connection.getMetaData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a meta file associated with the give SQLite database. If
|
||||
* found, it copies this file into the temp directory of the current case.
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
Autopsy Forensic Browser
|
||||
|
||||
Copyright 2016-2018 Basis Technology Corp.
|
||||
Copyright 2016-2020 Basis Technology Corp.
|
||||
Contact: carrier <at> sleuthkit <dot> org
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,10 +18,10 @@ limitations under the License.
|
||||
"""
|
||||
|
||||
from java.io import File
|
||||
from java.io import IOException
|
||||
from java.lang import Class
|
||||
from java.lang import ClassNotFoundException
|
||||
from java.lang import String
|
||||
from java.lang import Integer
|
||||
from java.lang import Long
|
||||
from java.sql import Connection
|
||||
from java.sql import DriverManager
|
||||
from java.sql import ResultSet
|
||||
@ -29,11 +29,14 @@ from java.sql import SQLException
|
||||
from java.sql import Statement
|
||||
from java.util.logging import Level
|
||||
from java.util import ArrayList
|
||||
from java.util import UUID
|
||||
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
|
||||
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||
from org.sleuthkit.autopsy.coreutils import AppSQLiteDB
|
||||
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||
from org.sleuthkit.autopsy.ingest import IngestServices
|
||||
from org.sleuthkit.autopsy.ingest import ModuleDataEvent
|
||||
@ -41,128 +44,103 @@ 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.BlackboardAttribute import ATTRIBUTE_TYPE
|
||||
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 import Relationship
|
||||
from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper
|
||||
from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CommunicationDirection
|
||||
from org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper import CallMediaType
|
||||
|
||||
import traceback
|
||||
import general
|
||||
|
||||
deviceAccountInstance = None
|
||||
|
||||
"""
|
||||
Locates a variety of different call log databases, parses them, and populates the blackboard.
|
||||
"""
|
||||
class CallLogAnalyzer(general.AndroidComponentAnalyzer):
|
||||
"""
|
||||
Locates a variety of different call log databases, parses them, and populates the blackboard.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||
|
||||
# the names of db files that potentially hold call logs
|
||||
_dbFileNames = ["logs.db", "contacts.db", "contacts2.db"]
|
||||
|
||||
# the names of tables that potentially hold call logs in the dbs
|
||||
_tableNames = ["calls", "logs"]
|
||||
|
||||
def __init__(self):
|
||||
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||
self._PACKAGE_NAME = "com.sec.android.provider.logsprovider"
|
||||
self._PARSER_NAME = "Android CallLog Parser"
|
||||
|
||||
class CallDirection:
|
||||
|
||||
def __init__(self, type, displayName):
|
||||
self.type = type
|
||||
self.displayName = displayName
|
||||
|
||||
def getDisplayName(self):
|
||||
return self.displayName
|
||||
|
||||
INCOMING = CallDirection(1, "Incoming")
|
||||
OUTGOING = CallDirection(2, "Outgoing")
|
||||
MISSED = CallDirection(3, "Missed")
|
||||
|
||||
@staticmethod
|
||||
def fromType(t):
|
||||
return {
|
||||
1: CallLogAnalyzer.INCOMING,
|
||||
2: CallLogAnalyzer.OUTGOING,
|
||||
3: CallLogAnalyzer.MISSED
|
||||
}.get(t, None)
|
||||
|
||||
def analyze(self, dataSource, fileManager, context):
|
||||
try:
|
||||
absFiles = fileManager.findFiles(dataSource, "logs.db")
|
||||
absFiles.addAll(fileManager.findFiles(dataSource, "contacts.db"))
|
||||
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
|
||||
for abstractFile in absFiles:
|
||||
for _dbFileName in CallLogAnalyzer._dbFileNames:
|
||||
selfAccountId = None
|
||||
callLogDbs = AppSQLiteDB.findAppDatabases(dataSource, _dbFileName, True, self._PACKAGE_NAME)
|
||||
for callLogDb in callLogDbs:
|
||||
try:
|
||||
file = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||
ContentUtils.writeToFile(abstractFile, file, context.dataSourceIngestIsCancelled)
|
||||
self.__findCallLogsInDB(file.toString(), abstractFile, dataSource)
|
||||
except IOException as ex:
|
||||
self._logger.log(Level.SEVERE, "Error writing temporary call log db to disk", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except TskCoreException as ex:
|
||||
# Error finding call logs.
|
||||
pass
|
||||
|
||||
def __findCallLogsInDB(self, databasePath, abstractFile, dataSource):
|
||||
if not databasePath:
|
||||
return
|
||||
|
||||
|
||||
bbartifacts = list()
|
||||
try:
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||
statement = connection.createStatement()
|
||||
|
||||
# Create a 'Device' account using the data source device id
|
||||
datasourceObjId = dataSource.getDataSource().getId()
|
||||
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
|
||||
deviceID = ds.getDeviceId()
|
||||
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, abstractFile)
|
||||
|
||||
for tableName in CallLogAnalyzer._tableNames:
|
||||
try:
|
||||
resultSet = statement.executeQuery("SELECT number, date, duration, type, name FROM " + tableName + " ORDER BY date DESC;")
|
||||
self._logger.log(Level.INFO, "Reading call log from table {0} in db {1}", [tableName, databasePath])
|
||||
while resultSet.next():
|
||||
date = resultSet.getLong("date") / 1000
|
||||
direction = CallLogAnalyzer.fromType(resultSet.getInt("type"))
|
||||
directionString = direction.getDisplayName() if direction is not None else ""
|
||||
number = resultSet.getString("number")
|
||||
duration = resultSet.getLong("duration") # duration of call is in seconds
|
||||
name = resultSet.getString("name") # name of person dialed or called. None if unregistered
|
||||
|
||||
current_case = Case.getCurrentCaseThrows()
|
||||
if selfAccountId is not None:
|
||||
callLogDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(),
|
||||
self._PARSER_NAME,
|
||||
callLogDb.getDBFile(),
|
||||
Account.Type.PHONE, Account.Type.PHONE, selfAccountId )
|
||||
else:
|
||||
callLogDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(),
|
||||
self._PARSER_NAME,
|
||||
callLogDb.getDBFile(),
|
||||
Account.Type.PHONE )
|
||||
|
||||
for tableName in CallLogAnalyzer._tableNames:
|
||||
try:
|
||||
attributes = ArrayList()
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) # create a call log and then add attributes from result set.
|
||||
if direction == CallLogAnalyzer.OUTGOING:
|
||||
attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, number))
|
||||
else: # Covers INCOMING and MISSED
|
||||
attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, number))
|
||||
resultSet = callLogDb.runQuery("SELECT number, date, duration, type, name FROM " + tableName + " ORDER BY date DESC;")
|
||||
self._logger.log(Level.INFO, "Reading call log from table {0} in db {1}", [tableName, callLogDb.getDBFile().getName()])
|
||||
if resultSet is not None:
|
||||
while resultSet.next():
|
||||
direction = ""
|
||||
callerId = None
|
||||
calleeId = None
|
||||
|
||||
timeStamp = resultSet.getLong("date") / 1000
|
||||
|
||||
number = resultSet.getString("number")
|
||||
duration = resultSet.getLong("duration") # duration of call is in seconds
|
||||
name = resultSet.getString("name") # name of person dialed or called. None if unregistered
|
||||
|
||||
attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_START, general.MODULE_NAME, date))
|
||||
attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_END, general.MODULE_NAME, duration + date))
|
||||
attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, directionString))
|
||||
attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
||||
calltype = resultSet.getInt("type")
|
||||
if calltype == 1 or calltype == 3:
|
||||
direction = CommunicationDirection.INCOMING
|
||||
callerId = number
|
||||
elif calltype == 2 or calltype == 5:
|
||||
direction = CommunicationDirection.OUTGOING
|
||||
calleeId = number
|
||||
else:
|
||||
direction = CommunicationDirection.UNKNOWN
|
||||
|
||||
|
||||
artifact.addAttributes(attributes)
|
||||
|
||||
# Create an account
|
||||
calllogAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, number, general.MODULE_NAME, abstractFile);
|
||||
|
||||
# create relationship between accounts
|
||||
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [calllogAccountInstance], artifact, Relationship.Type.CALL_LOG, date);
|
||||
|
||||
bbartifacts.append(artifact)
|
||||
## add a call log
|
||||
if callerId is not None or calleeId is not None:
|
||||
callLogArtifact = callLogDbHelper.addCalllog( direction,
|
||||
callerId,
|
||||
calleeId,
|
||||
timeStamp, ## start time
|
||||
timeStamp + duration * 1000, ## end time
|
||||
CallMediaType.AUDIO)
|
||||
|
||||
except SQLException as ex:
|
||||
self._logger.log(Level.WARNING, "Error processing query result for Android messages.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except TskCoreException as ex:
|
||||
self._logger.log(Level.SEVERE, "Error posting call log record to the blackboard", ex)
|
||||
self._logger.log(Level.SEVERE, "Failed to add Android call log artifacts.", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except SQLException as ex:
|
||||
# Could not read table in db.
|
||||
# Catch and proceed to the next table in the loop.
|
||||
pass
|
||||
except SQLException as ex:
|
||||
# Could not parse call log; error connecting to db.
|
||||
pass
|
||||
finally:
|
||||
if bbartifacts:
|
||||
Case.getCurrentCase().getSleuthkitCase().getBlackboard().postArtifacts(bbartifacts, general.MODULE_NAME)
|
||||
except BlackboardException as ex:
|
||||
self._logger.log(Level.WARNING, "Failed to post artifacts.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
|
||||
except TskCoreException as ex:
|
||||
self._logger.log(Level.SEVERE, "Failed to create CommunicationArtifactsHelper.", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except NoCurrentCaseException as ex:
|
||||
self._logger.log(Level.WARNING, "No case currently open.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
finally:
|
||||
callLogDb.close()
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
Autopsy Forensic Browser
|
||||
|
||||
Copyright 2016-2018 Basis Technology Corp.
|
||||
Copyright 2016-2020 Basis Technology Corp.
|
||||
Contact: carrier <at> sleuthkit <dot> org
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,6 +20,8 @@ limitations under the License.
|
||||
from java.io import File
|
||||
from java.lang import Class
|
||||
from java.lang import ClassNotFoundException
|
||||
from java.lang import Integer
|
||||
from java.lang import Long
|
||||
from java.sql import Connection
|
||||
from java.sql import DatabaseMetaData
|
||||
from java.sql import DriverManager
|
||||
@ -28,11 +30,14 @@ from java.sql import SQLException
|
||||
from java.sql import Statement
|
||||
from java.util.logging import Level
|
||||
from java.util import ArrayList
|
||||
from java.util import UUID
|
||||
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
|
||||
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||
from org.sleuthkit.autopsy.coreutils import AppSQLiteDB
|
||||
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||
from org.sleuthkit.autopsy.ingest import IngestServices
|
||||
from org.sleuthkit.autopsy.ingest import ModuleDataEvent
|
||||
@ -42,32 +47,35 @@ 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 import Relationship
|
||||
from org.sleuthkit.datamodel.blackboardutils import CommunicationArtifactsHelper
|
||||
|
||||
import traceback
|
||||
import general
|
||||
|
||||
"""
|
||||
Locates a variety of different contacts databases, parses them, and populates the blackboard.
|
||||
"""
|
||||
class ContactAnalyzer(general.AndroidComponentAnalyzer):
|
||||
|
||||
"""
|
||||
Finds and parsers Android contacts database, and populates the blackboard with Contacts.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||
|
||||
self._PACKAGE_NAME = "com.android.providers.contacts"
|
||||
self._PARSER_NAME = "Android Contacts Parser"
|
||||
self._VERSION = "53.1.0.1" # icu_version in 'properties' table.
|
||||
|
||||
def analyze(self, dataSource, fileManager, context):
|
||||
try:
|
||||
|
||||
absFiles = fileManager.findFiles(dataSource, "contacts.db")
|
||||
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
|
||||
if absFiles.isEmpty():
|
||||
contactsDbs = AppSQLiteDB.findAppDatabases(dataSource, "contacts.db", True, self._PACKAGE_NAME)
|
||||
contactsDbs.addAll(AppSQLiteDB.findAppDatabases(dataSource, "contacts2.db", True, self._PACKAGE_NAME))
|
||||
if contactsDbs.isEmpty():
|
||||
return
|
||||
for abstractFile in absFiles:
|
||||
for contactDb in contactsDbs:
|
||||
try:
|
||||
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||
self.__findContactsInDB(str(jFile.toString()), abstractFile, dataSource)
|
||||
self.__findContactsInDB(contactDb, dataSource)
|
||||
except Exception as ex:
|
||||
self._logger.log(Level.SEVERE, "Error parsing Contacts", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
@ -76,48 +84,33 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
|
||||
pass
|
||||
|
||||
"""
|
||||
Will create artifact from a database given by the path
|
||||
The fileId will be the abstract file associated with the artifacts
|
||||
Queries the given contact database and adds Contacts to the case.
|
||||
"""
|
||||
def __findContactsInDB(self, databasePath, abstractFile, dataSource):
|
||||
if not databasePath:
|
||||
def __findContactsInDB(self, contactDb, dataSource):
|
||||
if not contactDb:
|
||||
return
|
||||
|
||||
bbartifacts = list()
|
||||
try:
|
||||
Class.forName("org.sqlite.JDBC") # load JDBC driver
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||
statement = connection.createStatement()
|
||||
except (ClassNotFoundException) as ex:
|
||||
self._logger.log(Level.SEVERE, "Error loading JDBC driver", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
return
|
||||
except (SQLException) as ex:
|
||||
# Error opening database.
|
||||
return
|
||||
current_case = Case.getCurrentCaseThrows()
|
||||
|
||||
|
||||
# Create a 'Device' account using the data source device id
|
||||
datasourceObjId = dataSource.getDataSource().getId()
|
||||
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
|
||||
deviceID = ds.getDeviceId()
|
||||
|
||||
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance (Account.Type.DEVICE, deviceID, general.MODULE_NAME, abstractFile)
|
||||
|
||||
resultSet = None
|
||||
try:
|
||||
# Create a helper to parse the DB
|
||||
contactDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(),
|
||||
self._PARSER_NAME,
|
||||
contactDb.getDBFile(),
|
||||
Account.Type.PHONE )
|
||||
|
||||
# get display_name, mimetype(email or phone number) and data1 (phonenumber or email address depending on mimetype)
|
||||
# sorted by name, so phonenumber/email would be consecutive for a person if they exist.
|
||||
# check if contacts.name_raw_contact_id exists. Modify the query accordingly.
|
||||
columnFound = False
|
||||
metadata = connection.getMetaData()
|
||||
metadata = contactDb.getConnectionMetadata()
|
||||
columnListResultSet = metadata.getColumns(None, None, "contacts", None)
|
||||
while columnListResultSet.next():
|
||||
if columnListResultSet.getString("COLUMN_NAME") == "name_raw_contact_id":
|
||||
columnFound = True
|
||||
break
|
||||
if columnFound:
|
||||
resultSet = statement.executeQuery(
|
||||
resultSet = contactDb.runQuery(
|
||||
"SELECT mimetype, data1, name_raw_contact.display_name AS display_name \n"
|
||||
+ "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n"
|
||||
+ "JOIN raw_contacts AS name_raw_contact ON(name_raw_contact_id=name_raw_contact._id) "
|
||||
@ -126,7 +119,7 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
|
||||
+ "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n"
|
||||
+ "ORDER BY name_raw_contact.display_name ASC;")
|
||||
else:
|
||||
resultSet = statement.executeQuery(
|
||||
resultSet = contactDb.runQuery(
|
||||
"SELECT mimetype, data1, raw_contacts.display_name AS display_name \n"
|
||||
+ "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n"
|
||||
+ "LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id) \n"
|
||||
@ -134,51 +127,56 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
|
||||
+ "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n"
|
||||
+ "ORDER BY raw_contacts.display_name ASC;")
|
||||
|
||||
attributes = ArrayList()
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT)
|
||||
oldName = ""
|
||||
contactArtifact = None
|
||||
oldName = None
|
||||
phoneNumber = None
|
||||
emailAddr = None
|
||||
name = None
|
||||
while resultSet.next():
|
||||
name = resultSet.getString("display_name")
|
||||
data1 = resultSet.getString("data1") # the phone number or email
|
||||
mimetype = resultSet.getString("mimetype") # either phone or email
|
||||
attributes = ArrayList()
|
||||
if name != oldName:
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT)
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
||||
if oldName and (name != oldName):
|
||||
if phoneNumber or emailAddr:
|
||||
contactArtifact = contactDbHelper.addContact(oldName,
|
||||
phoneNumber, # phoneNumber,
|
||||
None, # homePhoneNumber,
|
||||
None, # mobilePhoneNumber,
|
||||
emailAddr) # emailAddr
|
||||
|
||||
oldName = name
|
||||
phoneNumber = None
|
||||
emailAddr = None
|
||||
name = None
|
||||
|
||||
if mimetype == "vnd.android.cursor.item/phone_v2":
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1))
|
||||
acctType = Account.Type.PHONE
|
||||
phoneNumber = data1
|
||||
else:
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, general.MODULE_NAME, data1))
|
||||
acctType = Account.Type.EMAIL
|
||||
emailAddr = data1
|
||||
|
||||
if name:
|
||||
oldName = name
|
||||
|
||||
artifact.addAttributes(attributes)
|
||||
|
||||
# Create an account instance
|
||||
contactAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance (acctType, data1, general.MODULE_NAME, abstractFile);
|
||||
|
||||
# create relationship between accounts
|
||||
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [contactAccountInstance], artifact,Relationship.Type.CONTACT, 0);
|
||||
|
||||
oldName = name
|
||||
|
||||
bbartifacts.append(artifact)
|
||||
|
||||
# create contact for last row
|
||||
if oldName and (phoneNumber or emailAddr):
|
||||
contactArtifact = contactDbHelper.addContact(oldName,
|
||||
phoneNumber, # phoneNumber,
|
||||
None, # homePhoneNumber,
|
||||
None, # mobilePhoneNumber,
|
||||
emailAddr) # emailAddr
|
||||
|
||||
except SQLException as ex:
|
||||
# Unable to execute contacts SQL query against database.
|
||||
pass
|
||||
self._logger.log(Level.WARNING, "Error processing query result for Android messages.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except TskCoreException as ex:
|
||||
self._logger.log(Level.SEVERE, "Error posting to blackboard", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
self._logger.log(Level.SEVERE, "Failed to add Android message artifacts.", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except BlackboardException as ex:
|
||||
self._logger.log(Level.WARNING, "Failed to post artifacts.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except NoCurrentCaseException as ex:
|
||||
self._logger.log(Level.WARNING, "No case currently open.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
finally:
|
||||
if bbartifacts:
|
||||
Case.getCurrentCase().getSleuthkitCase().getBlackboard().postArtifacts(bbartifacts, general.MODULE_NAME)
|
||||
|
||||
try:
|
||||
if resultSet is not None:
|
||||
resultSet.close()
|
||||
statement.close()
|
||||
connection.close()
|
||||
except Exception as ex:
|
||||
# Error closing database.
|
||||
pass
|
||||
contactDb.close()
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
Autopsy Forensic Browser
|
||||
|
||||
Copyright 2016-2018 Basis Technology Corp.
|
||||
Copyright 2016-2020 Basis Technology Corp.
|
||||
Contact: carrier <at> sleuthkit <dot> org
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -31,6 +31,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.casemodule.services import FileManager
|
||||
from org.sleuthkit.autopsy.coreutils import Logger
|
||||
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
|
||||
@ -43,6 +44,11 @@ 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.Blackboard import BlackboardException
|
||||
from org.sleuthkit.autopsy.coreutils import AppSQLiteDB
|
||||
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
|
||||
@ -54,16 +60,19 @@ class TangoMessageAnalyzer(general.AndroidComponentAnalyzer):
|
||||
|
||||
def __init__(self):
|
||||
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||
self._PACKAGE_NAME = "com.sgiggle.production"
|
||||
self._PARSER_NAME = "Tango Parser"
|
||||
self._MESSAGE_TYPE = "Tango Message"
|
||||
self._VERSION = "7" # DB_VERSION in 'profiles' table
|
||||
|
||||
|
||||
def analyze(self, dataSource, fileManager, context):
|
||||
try:
|
||||
|
||||
absFiles = fileManager.findFiles(dataSource, "tc.db")
|
||||
for abstractFile in absFiles:
|
||||
tangoDbFiles = AppSQLiteDB.findAppDatabases(dataSource, "tc.db", True, self._PACKAGE_NAME)
|
||||
for tangoDbFile in tangoDbFiles:
|
||||
try:
|
||||
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||
self.__findTangoMessagesInDB(jFile.toString(), abstractFile, dataSource)
|
||||
self.__findTangoMessagesInDB(tangoDbFile, dataSource)
|
||||
except Exception as ex:
|
||||
self._logger.log(Level.SEVERE, "Error parsing Tango messages", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
@ -71,74 +80,61 @@ class TangoMessageAnalyzer(general.AndroidComponentAnalyzer):
|
||||
# Error finding Tango messages.
|
||||
pass
|
||||
|
||||
def __findTangoMessagesInDB(self, databasePath, abstractFile, dataSource):
|
||||
if not databasePath:
|
||||
def __findTangoMessagesInDB(self, tangoDb, dataSource):
|
||||
if not tangoDb:
|
||||
return
|
||||
|
||||
try:
|
||||
Class.forName("org.sqlite.JDBC") # load JDBC driver
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||
statement = connection.createStatement()
|
||||
except (ClassNotFoundException) as ex:
|
||||
self._logger.log(Level.SEVERE, "Error loading JDBC driver", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
return
|
||||
except (SQLException) as ex:
|
||||
# Error opening database.
|
||||
return
|
||||
current_case = Case.getCurrentCaseThrows()
|
||||
|
||||
# Create a 'Device' account using the data source device id
|
||||
datasourceObjId = dataSource.getDataSource().getId()
|
||||
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
|
||||
deviceID = ds.getDeviceId()
|
||||
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, abstractFile)
|
||||
# Create a helper to parse the DB
|
||||
tangoDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(),
|
||||
self._PARSER_NAME,
|
||||
tangoDb.getDBFile(),
|
||||
Account.Type.TANGO )
|
||||
|
||||
resultSet = None
|
||||
try:
|
||||
resultSet = statement.executeQuery(
|
||||
resultSet = tangoDb.runQuery(
|
||||
"SELECT conv_id, create_time, direction, payload FROM messages ORDER BY create_time DESC;")
|
||||
|
||||
while resultSet.next():
|
||||
fromId = None
|
||||
toId = None
|
||||
conv_id = resultSet.getString("conv_id") # seems to wrap around the message found in payload after decoding from base-64
|
||||
create_time = Long.valueOf(resultSet.getString("create_time")) / 1000
|
||||
|
||||
if resultSet.getString("direction") == "1": # 1 incoming, 2 outgoing
|
||||
direction = "Incoming"
|
||||
direction = CommunicationDirection.INCOMING
|
||||
else:
|
||||
direction = "Outgoing"
|
||||
direction = CommunicationDirection.OUTGOING
|
||||
|
||||
payload = resultSet.getString("payload")
|
||||
|
||||
attributes = ArrayList()
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) #create a call log and then add attributes from result set.
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, create_time))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, direction))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, TangoMessageAnalyzer.decodeMessage(conv_id, payload)))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Tango Message"))
|
||||
|
||||
artifact.addAttributes(attributes)
|
||||
try:
|
||||
# index the artifact for keyword search
|
||||
blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard()
|
||||
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())
|
||||
MessageNotifyUtil.Notify.error("Failed to index Tango message artifact for keyword search.", artifact.getDisplayName())
|
||||
msgBody = TangoMessageAnalyzer.decodeMessage(conv_id, payload)
|
||||
|
||||
messageArtifact = tangoDbHelper.addMessage(
|
||||
self._MESSAGE_TYPE,
|
||||
direction,
|
||||
fromId,
|
||||
toId,
|
||||
create_time,
|
||||
MessageReadStatus.UNKNOWN,
|
||||
"", # subject
|
||||
msgBody,
|
||||
"")
|
||||
|
||||
except SQLException as ex:
|
||||
# Unable to execute Tango messages SQL query against database.
|
||||
pass
|
||||
except Exception as ex:
|
||||
self._logger.log(Level.SEVERE, "Error parsing Tango messages to the blackboard", ex)
|
||||
self._logger.log(Level.WARNING, "Error processing query result for Tango messages", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except TskCoreException as ex:
|
||||
self._logger.log(Level.SEVERE, "Failed to add Tango message artifacts.", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except BlackboardException as ex:
|
||||
self._logger.log(Level.WARNING, "Failed to post artifacts.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except NoCurrentCaseException as ex:
|
||||
self._logger.log(Level.WARNING, "No case currently open.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
finally:
|
||||
try:
|
||||
if resultSet is not None:
|
||||
resultSet.close()
|
||||
statement.close()
|
||||
connection.close()
|
||||
except Exception as ex:
|
||||
# Error closing database.
|
||||
pass
|
||||
tangoDb.close()
|
||||
|
||||
# take the message string which is wrapped by a certain string, and return the text enclosed.
|
||||
@staticmethod
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""
|
||||
Autopsy Forensic Browser
|
||||
|
||||
Copyright 2016-2018 Basis Technology Corp.
|
||||
Copyright 2016-2020 Basis Technology Corp.
|
||||
Contact: carrier <at> sleuthkit <dot> org
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -31,10 +31,12 @@ from java.util.logging import Level
|
||||
from java.util import ArrayList
|
||||
from java.util import UUID
|
||||
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
|
||||
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||
from org.sleuthkit.autopsy.coreutils import AppSQLiteDB
|
||||
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||
from org.sleuthkit.autopsy.ingest import IngestServices
|
||||
from org.sleuthkit.autopsy.ingest import ModuleDataEvent
|
||||
@ -44,114 +46,102 @@ 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 import Relationship
|
||||
from org.sleuthkit.datamodel.blackboardutils.attributes import MessageAttachments
|
||||
from org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments import FileAttachment
|
||||
from org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments import URLAttachment
|
||||
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
|
||||
|
||||
|
||||
"""
|
||||
Finds database with SMS/MMS messages and adds them to blackboard.
|
||||
"""
|
||||
class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
|
||||
"""
|
||||
Finds and parsers Android SMS/MMS database, and populates the blackboard with messages.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||
self._PACKAGE_NAME = "com.android.providers.telephony"
|
||||
self._PARSER_NAME = "Android Message Parser"
|
||||
self._MESSAGE_TYPE = "Android Message"
|
||||
|
||||
|
||||
def analyze(self, dataSource, fileManager, context):
|
||||
try:
|
||||
absFiles = fileManager.findFiles(dataSource, "mmssms.db")
|
||||
for abstractFile in absFiles:
|
||||
try:
|
||||
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||
self.__findTextsInDB(jFile.toString(), abstractFile, dataSource)
|
||||
except Exception as ex:
|
||||
self._logger.log(Level.SEVERE, "Error parsing text messages", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except TskCoreException as ex:
|
||||
# Error finding text messages.
|
||||
pass
|
||||
|
||||
def __findTextsInDB(self, databasePath, abstractFile, dataSource):
|
||||
if not databasePath:
|
||||
return
|
||||
|
||||
bbartifacts = list()
|
||||
try:
|
||||
Class.forName("org.sqlite.JDBC") # load JDBC driver
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||
statement = connection.createStatement()
|
||||
except (ClassNotFoundException) as ex:
|
||||
self._logger.log(Level.SEVERE, "Error loading JDBC driver", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
return
|
||||
except (SQLException) as ex:
|
||||
# Error opening database.
|
||||
return
|
||||
|
||||
# Create a 'Device' account using the data source device id
|
||||
datasourceObjId = dataSource.getDataSource().getId()
|
||||
ds = Case.getCurrentCase().getSleuthkitCase().getDataSource(datasourceObjId)
|
||||
deviceID = ds.getDeviceId()
|
||||
deviceAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE, deviceID, general.MODULE_NAME, abstractFile)
|
||||
uuid = UUID.randomUUID().toString()
|
||||
|
||||
resultSet = None
|
||||
try:
|
||||
resultSet = statement.executeQuery(
|
||||
"SELECT address, date, read, type, subject, body, thread_id FROM sms;")
|
||||
while resultSet.next():
|
||||
address = resultSet.getString("address") # may be phone number, or other addresses
|
||||
date = Long.valueOf(resultSet.getString("date")) / 1000
|
||||
read = resultSet.getInt("read") # may be unread = 0, read = 1
|
||||
subject = resultSet.getString("subject") # message subject
|
||||
body = resultSet.getString("body") # message body
|
||||
thread_id = "{0}-{1}".format(uuid, resultSet.getInt("thread_id"))
|
||||
attributes = ArrayList()
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); #create Message artifact and then add attributes from result set.
|
||||
if resultSet.getString("type") == "1":
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Incoming"))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, address))
|
||||
else:
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Outgoing"))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, address))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, date))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_READ_STATUS, general.MODULE_NAME, Integer(read)))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, general.MODULE_NAME, subject))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, body))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message"))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_THREAD_ID, general.MODULE_NAME, thread_id))
|
||||
|
||||
artifact.addAttributes(attributes)
|
||||
|
||||
if address is not None:
|
||||
# Create an account
|
||||
msgAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, address, general.MODULE_NAME, abstractFile);
|
||||
|
||||
# create relationship between accounts
|
||||
Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().addRelationships(deviceAccountInstance, [msgAccountInstance], artifact,Relationship.Type.MESSAGE, date);
|
||||
|
||||
bbartifacts.append(artifact)
|
||||
|
||||
except SQLException as ex:
|
||||
# Unable to execute text messages SQL query against database.
|
||||
pass
|
||||
except Exception as ex:
|
||||
self._logger.log(Level.SEVERE, "Error parsing text messages to blackboard", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
finally:
|
||||
|
||||
if bbartifacts:
|
||||
Case.getCurrentCase().getSleuthkitCase().getBlackboard().postArtifacts(bbartifacts, general.MODULE_NAME)
|
||||
|
||||
selfAccountId = None
|
||||
messageDbs = AppSQLiteDB.findAppDatabases(dataSource, "mmssms.db", True, self._PACKAGE_NAME)
|
||||
for messageDb in messageDbs:
|
||||
try:
|
||||
current_case = Case.getCurrentCaseThrows()
|
||||
if selfAccountId is not None:
|
||||
messageDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(),
|
||||
self._PARSER_NAME,
|
||||
messageDb.getDBFile(),
|
||||
Account.Type.PHONE, Account.Type.IMO, selfAccountId )
|
||||
else:
|
||||
messageDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(),
|
||||
self._PARSER_NAME,
|
||||
messageDb.getDBFile(),
|
||||
Account.Type.PHONE )
|
||||
|
||||
if resultSet is not None:
|
||||
resultSet.close()
|
||||
statement.close()
|
||||
connection.close()
|
||||
except Exception as ex:
|
||||
# Error closing database.
|
||||
pass
|
||||
uuid = UUID.randomUUID().toString()
|
||||
messagesResultSet = messageDb.runQuery("SELECT address, date, read, type, subject, body, thread_id FROM sms;")
|
||||
if messagesResultSet is not None:
|
||||
while messagesResultSet.next():
|
||||
direction = ""
|
||||
address = None
|
||||
fromId = None
|
||||
toId = None
|
||||
|
||||
address = messagesResultSet.getString("address") # may be phone number, or other addresses
|
||||
timeStamp = Long.valueOf(messagesResultSet.getString("date")) / 1000
|
||||
read = messagesResultSet.getInt("read") # may be unread = 0, read = 1
|
||||
subject = messagesResultSet.getString("subject") # message subject
|
||||
msgBody = messagesResultSet.getString("body") # message body
|
||||
thread_id = "{0}-{1}".format(uuid, messagesResultSet.getInt("thread_id"))
|
||||
if messagesResultSet.getString("type") == "1":
|
||||
direction = CommunicationDirection.INCOMING
|
||||
fromId = address
|
||||
else:
|
||||
direction = CommunicationDirection.OUTGOING
|
||||
toId = address
|
||||
|
||||
message_read = messagesResultSet.getInt("read") # may be unread = 0, read = 1
|
||||
if (message_read == 1):
|
||||
msgReadStatus = MessageReadStatus.READ
|
||||
elif (message_read == 0):
|
||||
msgReadStatus = MessageReadStatus.UNREAD
|
||||
else:
|
||||
msgReadStatus = MessageReadStatus.UNKNOWN
|
||||
|
||||
## add a message
|
||||
if address is not None:
|
||||
messageArtifact = messageDbHelper.addMessage(
|
||||
self._MESSAGE_TYPE,
|
||||
direction,
|
||||
fromId,
|
||||
toId,
|
||||
timeStamp,
|
||||
msgReadStatus,
|
||||
subject, # subject
|
||||
msgBody,
|
||||
thread_id)
|
||||
|
||||
|
||||
except SQLException as ex:
|
||||
self._logger.log(Level.WARNING, "Error processing query result for Android messages.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except TskCoreException as ex:
|
||||
self._logger.log(Level.SEVERE, "Failed to add Android message artifacts.", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
except BlackboardException as ex:
|
||||
self._logger.log(Level.WARNING, "Failed to post artifacts.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
except NoCurrentCaseException as ex:
|
||||
self._logger.log(Level.WARNING, "No case currently open.", ex)
|
||||
self._logger.log(Level.WARNING, traceback.format_exc())
|
||||
finally:
|
||||
messageDb.close()
|
||||
|
Loading…
x
Reference in New Issue
Block a user