diff --git a/Core/release/InternalPythonModules/android/browserlocation.py b/Core/release/InternalPythonModules/android/browserlocation.py new file mode 100755 index 0000000000..ef79a623c2 --- /dev/null +++ b/Core/release/InternalPythonModules/android/browserlocation.py @@ -0,0 +1,120 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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 org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule.services import Blackboard +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.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 + +""" +Analyzes database created by browser that stores GEO location info. +""" +class BrowserLocationAnalyzer(general.AndroidComponentAnalyzer): + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + try: + abstractFiles = fileManager.findFiles(dataSource, "CachedGeoposition%.db") + for abstractFile in abstractFiles: + if abstractFile.getSize() == 0: + continue + try: + jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName()) + ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled) + self.__findGeoLocationsInDB(jFile.toString(), abstractFile) + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing browser location files", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Error finding browser location files", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + def __findGeoLocationsInDB(self, databasePath, abstractFile): + if not databasePath: + return + + try: + Class.forName("org.sqlite.JDBC") #load JDBC driver + connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath) + statement = connection.createStatement() + except (ClassNotFoundException, SQLException) as ex: + self._logger.log(Level.SEVERE, "Error connecting to SQL database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + return + + try: + resultSet = statement.executeQuery("SELECT timestamp, latitude, longitude, accuracy FROM CachedPosition;") + while resultSet.next(): + timestamp = Long.valueOf(resultSet.getString("timestamp")) / 1000 + latitude = Double.valueOf(resultSet.getString("latitude")) + longitude = Double.valueOf(resultSet.getString("longitude")) + + artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, general.MODULE_NAME, latitude)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, general.MODULE_NAME, longitude)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, timestamp)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME, "Browser Location History")) + # artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(),moduleName, accuracy)) + # NOTE: originally commented out + + try: + # index the artifact for keyword search + blackboard = Case.getCurrentCase().getServices().getBlackboard() + blackboard.indexArtifact(artifact) + except Blackboard.BlackboardException as ex: + self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactTypeName(), ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + MessageNotifyUtil.Notify.error("Failed to index GPS trackpoint artifact for keyword search.", artifact.getDisplayName()) + + except Exception as ex: + self._logger.log(Level.SEVERE, "Error putting artifacts to blackboard", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + finally: + try: + if resultSet is not None: + resultSet.close() + statement.close() + connection.close() + except Exception as ex: + self._logger.log(Level.SEVERE, "Error closing database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) diff --git a/Core/release/InternalPythonModules/android/cachelocation.py b/Core/release/InternalPythonModules/android/cachelocation.py new file mode 100755 index 0000000000..c28aa48fc3 --- /dev/null +++ b/Core/release/InternalPythonModules/android/cachelocation.py @@ -0,0 +1,147 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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.io import FileInputStream +from java.io import InputStream +from java.lang import Class +from java.lang import ClassNotFoundException +from java.math import BigInteger +from java.nio import ByteBuffer +from java.util.logging import Level +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule.services import Blackboard +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.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 + +""" +Parses cache files that Android maintains for Wifi and cell towers. Adds GPS points to blackboard. +""" +class CacheLocationAnalyzer(general.AndroidComponentAnalyzer): + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + """ + cache.cell stores mobile tower GPS locations and cache.wifi stores GPS + and MAC info from Wifi points. + """ + def analyze(self, dataSource, fileManager, context): + try: + abstractFiles = fileManager.findFiles(dataSource, "cache.cell") + abstractFiles.addAll(fileManager.findFiles(dataSource, "cache.wifi")) + for abstractFile in abstractFiles: + if abstractFile.getSize() == 0: + continue + try: + jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName()) + ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled) + self.__findGeoLocationsInFile(jFile, abstractFile) + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing cached location files", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Error finding cached location files", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + def __findGeoLocationsInFile(self, file, abstractFile): + + tempBytes = bytearray([0] * 2) # will temporarily hold bytes to be converted into the correct data types + + try: + inputStream = FileInputStream(file) + + inputStream.read(tempBytes) # version + + tempBytes = bytearray([0] * 2) + inputStream.read(tempBytes) # number of location entries + + iterations = BigInteger(tempBytes).intValue() + + for i in range(iterations): # loop through every entry + tempBytes = bytearray([0] * 2) + inputStream.read(tempBytes) + + tempBytes = bytearray([0]) + inputStream.read(tempBytes) + + while BigInteger(tempBytes).intValue() != 0: # pass through non important values until the start of accuracy(around 7-10 bytes) + if 0 > inputStream.read(tempBytes): + break # we've passed the end of the file, so stop + + tempBytes = bytearray([0] * 3) + inputStream.read(tempBytes) + if BigInteger(tempBytes).intValue() <= 0: # This refers to a location that could not be calculated + tempBytes = bytearray([0] * 28) # read rest of the row's bytes + inputStream.read(tempBytes) + continue + accuracy = "" + BigInteger(tempBytes).intValue() + + tempBytes = bytearray([0] * 4) + inputStream.read(tempBytes) + confidence = "" + BigInteger(tempBytes).intValue() + + tempBytes = bytearray([0] * 8) + inputStream.read(tempBytes) + latitude = CacheLocationAnalyzer.toDouble(bytes) + + tempBytes = bytearray([0] * 8) + inputStream.read(tempBytes) + longitude = CacheLocationAnalyzer.toDouble(bytes) + + tempBytes = bytearray([0] * 8) + inputStream.read(tempBytes) + timestamp = BigInteger(tempBytes).longValue() / 1000 + + artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, AndroidAnalyzer.MODULE_NAME, latitude)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, AndroidAnalyzer.MODULE_NAME, longitude)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, AndroidModuleFactorymodule.Name, timestamp)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, AndroidAnalyzer.MODULE_NAME, + file.getName() + "Location History")) + + #Not storing these for now. + # artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), AndroidModuleFactorymodule.moduleName, accuracy)) + # artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(), AndroidModuleFactorymodule.moduleName, confidence)) + try: + # index the artifact for keyword search + blackboard = Case.getCurrentCase().getServices().getBlackboard() + blackboard.indexArtifact(artifact) + except Blackboard.BlackboardException as ex: + self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + MessageNotifyUtil.Notify.error("Failed to index GPS trackpoint artifact for keyword search.", artifact.getDisplayName()) + + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing Cached GPS locations to blackboard", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + def toDouble(byteArray): + return ByteBuffer.wrap(byteArray).getDouble() diff --git a/Core/release/InternalPythonModules/android/calllog.py b/Core/release/InternalPythonModules/android/calllog.py new file mode 100755 index 0000000000..886a918449 --- /dev/null +++ b/Core/release/InternalPythonModules/android/calllog.py @@ -0,0 +1,145 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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.io import IOException +from java.lang import Class +from java.lang import ClassNotFoundException +from java.lang import String +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 org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule.services import Blackboard +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.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.BlackboardAttribute import ATTRIBUTE_TYPE +from org.sleuthkit.datamodel import Content +from org.sleuthkit.datamodel import TskCoreException + +import traceback +import general + +""" +Locates a variety of different call log databases, parses them, and populates the blackboard. +""" +class CallLogAnalyzer(general.AndroidComponentAnalyzer): + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + # the names of tables that potentially hold call logs in the dbs + _tableNames = ["calls", "logs"] + + 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: + try: + file = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName()) + ContentUtils.writeToFile(abstractFile, file, context.dataSourceIngestIsCancelled) + self.__findCallLogsInDB(file.toString(), abstractFile) + 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: + self._logger.log(Level.SEVERE, "Error finding call logs", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + def __findCallLogsInDB(self, databasePath, abstractFile): + if not databasePath: + return + + try: + connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath) + statement = connection.createStatement() + + 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 + + try: + artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) # create a call log and then add attributes from result set. + if direction == CallLogAnalyzer.OUTGOING: + artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, number)) + else: # Covers INCOMING and MISSED + artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, number)) + + artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_START, general.MODULE_NAME, date)) + artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_END, general.MODULE_NAME, duration + date)) + artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, directionString)) + artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name)) + + try: + # index the artifact for keyword search + blackboard = Case.getCurrentCase().getServices().getBlackboard() + blackboard.indexArtifact(artifact) + except Blackboard.BlackboardException as ex: + self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + MessageNotifyUtil.Notify.error("Failed to index call log artifact for keyword search.", artifact.getDisplayName()) + + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Error posting call log record to the blackboard", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except SQLException as ex: + self._logger.log(Level.WARNING, String.format("Could not read table %s in db %s", tableName, databasePath), ex) + except SQLException as ex: + self._logger.log(Level.SEVERE, "Could not parse call log; error connecting to db " + databasePath, ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) diff --git a/Core/release/InternalPythonModules/android/contact.py b/Core/release/InternalPythonModules/android/contact.py new file mode 100755 index 0000000000..202ddbdc02 --- /dev/null +++ b/Core/release/InternalPythonModules/android/contact.py @@ -0,0 +1,156 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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.sql import Connection +from java.sql import DatabaseMetaData +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 org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule.services import Blackboard +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.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 + +""" +Locates a variety of different contacts databases, parses them, and populates the blackboard. +""" +class ContactAnalyzer(general.AndroidComponentAnalyzer): + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + try: + absFiles = fileManager.findFiles(dataSource, "contacts.db") + absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db")) + if absFiles.isEmpty(): + return + for abstractFile in absFiles: + try: + jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName()) + ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled) + self.__findContactsInDB(str(jFile.toString()), abstractFile) + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing Contacts", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Error finding Contacts", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + """ + Will create artifact from a database given by the path + The fileId will be the abstract file associated with the artifacts + """ + def __findContactsInDB(self, databasePath, abstractFile): + if not databasePath: + return + + try: + Class.forName("org.sqlite.JDBC") # load JDBC driver + connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath) + statement = connection.createStatement() + except (ClassNotFoundException, SQLException) as ex: + self._logger.log(Level.SEVERE, "Error opening database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + return + + try: + # 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() + 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( + "SELECT mimetype, data1, name_raw_contact.display_name AS display_name \n" + + "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n" + + "JOIN raw_contacts AS name_raw_contact ON(name_raw_contact_id=name_raw_contact._id) " + + "LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id) \n" + + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id=mimetypes._id) \n" + + "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n" + + "ORDER BY name_raw_contact.display_name ASC;") + else: + resultSet = statement.executeQuery( + "SELECT mimetype, data1, raw_contacts.display_name AS display_name \n" + + "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n" + + "LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id) \n" + + "LEFT OUTER JOIN mimetypes ON (data.mimetype_id=mimetypes._id) \n" + + "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n" + + "ORDER BY raw_contacts.display_name ASC;") + + artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) + oldName = "" + while resultSet.next(): + name = resultSet.getString("display_name") + data1 = resultSet.getString("data1") # the phone number or email + mimetype = resultSet.getString("mimetype") # either phone or email + if name != oldName: + artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name)) + if mimetype == "vnd.android.cursor.item/phone_v2": + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1)) + else: + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, general.MODULE_NAME, data1)) + + oldName = name + + try: + # index the artifact for keyword search + blackboard = Case.getCurrentCase().getServices().getBlackboard() + blackboard.indexArtifact(artifact) + except Blackboard.BlackboardException as ex: + self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + MessageNotifyUtil.Notify.error("Failed to index contact artifact for keyword search.", artifact.getDisplayName()) + + except SQLException as ex: + self._logger.log(Level.WARNING, "Unable to execute contacts SQL query against {0} : {1}", [databasePath, ex]) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Error posting to blackboard", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + finally: + try: + if resultSet is not None: + resultSet.close() + statement.close() + connection.close() + except Exception as ex: + self._logger.log(Level.SEVERE, "Error closing database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) diff --git a/Core/release/InternalPythonModules/android/general.py b/Core/release/InternalPythonModules/android/general.py new file mode 100755 index 0000000000..02944fc3d2 --- /dev/null +++ b/Core/release/InternalPythonModules/android/general.py @@ -0,0 +1,28 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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. +""" + +MODULE_NAME = "Android Analyzer Python" + +""" +A parent class of the analyzers +""" +class AndroidComponentAnalyzer: + # The Analyzer should implement this method + def analyze(self, dataSource, fileManager, context): + raise NotImplementedError diff --git a/Core/release/InternalPythonModules/android/googlemaplocation.py b/Core/release/InternalPythonModules/android/googlemaplocation.py new file mode 100755 index 0000000000..066ed2f792 --- /dev/null +++ b/Core/release/InternalPythonModules/android/googlemaplocation.py @@ -0,0 +1,139 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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 org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule.services import Blackboard +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.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 and parses the Google Maps database. +""" +class GoogleMapLocationAnalyzer(general.AndroidComponentAnalyzer): + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + try: + absFiles = fileManager.findFiles(dataSource, "da_destination_history") + if absFiles.isEmpty(): + return + for abstractFile in absFiles: + try: + jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName()) + ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled) + self.__findGeoLocationsInDB(jFile.toString(), abstractFile) + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing Google map locations", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Error finding Google map locations", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + def __findGeoLocationsInDB(self, databasePath, abstractFile): + if not databasePath: + return + + try: + Class.forName("org.sqlite.JDBC") # load JDBC driver + connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath) + statement = connection.createStatement() + except (ClassNotFoundException, SQLException) as ex: + self._logger.log(Level.SEVERE, "Error opening database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + return + + try: + resultSet = statement.executeQuery( + "SELECT time, dest_lat, dest_lng, dest_title, dest_address, source_lat, source_lng FROM destination_history;") + + while resultSet.next(): + time = Long.valueOf(resultSet.getString("time")) / 1000 + dest_title = resultSet.getString("dest_title") + dest_address = resultSet.getString("dest_address") + + dest_lat = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("dest_lat")) + dest_lng = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("dest_lng")) + source_lat = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lat")) + source_lng = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lng")) + + artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, general.MODULE_NAME, "Destination")) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, time)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END, general.MODULE_NAME, dest_lat)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END, general.MODULE_NAME, dest_lng)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START, general.MODULE_NAME, source_lat)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START, general.MODULE_NAME, source_lng)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, dest_title)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION, general.MODULE_NAME, dest_address)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME, "Google Maps History")) + + try: + # index the artifact for keyword search + blackboard = Case.getCurrentCase().getServices().getBlackboard() + blackboard.indexArtifact(artifact) + except Blackboard.BlackboardException as ex: + self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + MessageNotifyUtil.Notify.error("Failed to index GPS route artifact for keyword search.", artifact.getDisplayName()) + + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing Google map locations to the blackboard", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + finally: + try: + if resultSet is not None: + resultSet.close() + statement.close() + connection.close() + except Exception as ex: + self._logger.log(Level.SEVERE, "Error closing the database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + # add periods 6 decimal places before the end. + @staticmethod + def convertGeo(s): + length = len(s) + if length > 6: + return Double.valueOf(s[0 : length-6] + "." + s[length-6 : length]) + else: + return Double.valueOf(s) diff --git a/Core/release/InternalPythonModules/android/module.py b/Core/release/InternalPythonModules/android/module.py new file mode 100755 index 0000000000..07ef78ed8d --- /dev/null +++ b/Core/release/InternalPythonModules/android/module.py @@ -0,0 +1,126 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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. +""" + +import jarray +import inspect +import traceback + +from java.util.logging import Level +from org.sleuthkit.autopsy.coreutils import Version +from org.sleuthkit.autopsy.ingest import IngestModuleFactory +from org.sleuthkit.autopsy.ingest import DataSourceIngestModule +from org.sleuthkit.autopsy.ingest import IngestModuleFactoryAdapter +from org.sleuthkit.autopsy.ingest import IngestModuleIngestJobSettings +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.ingest import DataSourceIngestModuleProgress +from org.sleuthkit.autopsy.ingest import IngestModule +from org.sleuthkit.datamodel import Content +from org.sleuthkit.autopsy.ingest import DataSourceIngestModule +from org.sleuthkit.autopsy.ingest import IngestJobContext +from org.sleuthkit.autopsy.ingest import IngestMessage + +import general +import browserlocation +import cachelocation +import calllog +import contact +import googlemaplocation +import tangomessage +import textmessage +import wwfmessage + +class AndroidModuleFactory(IngestModuleFactoryAdapter): + + moduleName = general.MODULE_NAME + + def getModuleDisplayName(self): + return self.moduleName + + def getModuleDescription(self): + return "Extracts Android system and third-party app data." + + def getModuleVersionNumber(self): + return Version.getVersion() + + def isDataSourceIngestModuleFactory(self): + return True + + def createDataSourceIngestModule(self, ingestOptions): + return AndroidIngestModule() + + +class AndroidIngestModule(DataSourceIngestModule): + + _logger = Logger.getLogger(AndroidModuleFactory.moduleName) + + def log(self, level, msg): + self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg) + + def __init__(self): + self.context = None + + def startUp(self, context): + self.context = context + + # Throw an IngestModule.IngestModuleException exception if there was a problem setting up + + # Where the analysis is done. + def process(self, dataSource, progressBar): + + errors = [] + fileManager = Case.getCurrentCase().getServices().getFileManager() + analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(), tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), cachelocation.CacheLocationAnalyzer()] + self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers") + progressBar.switchToDeterminate(len(analyzers)) + + n = 0 + for analyzer in analyzers: + if self.context.dataSourceIngestIsCancelled(): + return IngestModule.ProcessResult.OK + try: + analyzer.analyze(dataSource, fileManager, self.context) + n += 1 + progressBar.progress(n) + except Exception as ex: + errors.append("Error running " + analyzer.__class__.__name__) + self.log(Level.SEVERE, traceback.format_exc()) + errorMessage = [] # NOTE: this isn't used? + errorMessageSubject = "" # NOTE: this isn't used? + msgLevel = IngestMessage.MessageType.INFO + + if errors: + msgLevel = IngestMessage.MessageType.ERROR + errorMessage.append("Errors were encountered") + + errorMessage.append("
    ") # NOTE: this was missing in the original java code + for msg in errors: + errorMessage.extend(["
  • ", msg, "
  • \n"]) + errorMessage.append("
\n") + + if len(errors) == 1: + errorMsgSubject = "One error was found" + else: + errorMsgSubject = "errors found: " + str(len(errors)) + else: + errorMessage.append("No errors") + errorMsgSubject = "No errors" + + return IngestModule.ProcessResult.OK diff --git a/Core/release/InternalPythonModules/android/tangomessage.py b/Core/release/InternalPythonModules/android/tangomessage.py new file mode 100755 index 0000000000..04223f7fe1 --- /dev/null +++ b/Core/release/InternalPythonModules/android/tangomessage.py @@ -0,0 +1,136 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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 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 org.apache.commons.codec.binary import Base64 +from org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule.services import Blackboard +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.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 + +""" +Locates database for the Tango app and adds info to blackboard. +""" +class TangoMessageAnalyzer(general.AndroidComponentAnalyzer): + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + try: + absFiles = fileManager.findFiles(dataSource, "tc.db") + for abstractFile in absFiles: + try: + jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName()) + ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled) + self.__findTangoMessagesInDB(jFile.toString(), abstractFile) + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing Tango messages", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Error finding Tango messages", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + def __findTangoMessagesInDB(self, databasePath, abstractFile): + if not databasePath: + return + + try: + Class.forName("org.sqlite.JDBC") # load JDBC driver + connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath) + statement = connection.createStatement() + except (ClassNotFoundException, SQLException) as ex: + self._logger.log(Level.SEVERE, "Error opening database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + return + + try: + resultSet = statement.executeQuery( + "SELECT conv_id, create_time, direction, payload FROM messages ORDER BY create_time DESC;") + + while resultSet.next(): + 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" + else: + direction = "Outgoing" + payload = resultSet.getString("payload") + + artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) #create a call log and then add attributes from result set. + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, create_time)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, direction)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, TangoMessageAnalyzer.decodeMessage(conv_id, payload))) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Tango Message")) + + try: + # index the artifact for keyword search + blackboard = Case.getCurrentCase().getServices().getBlackboard() + blackboard.indexArtifact(artifact) + except Blackboard.BlackboardException as ex: + self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + 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()) + + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing Tango messages to the blackboard", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + finally: + try: + if resultSet is not None: + resultSet.close() + statement.close() + connection.close() + except Exception as ex: + self._logger.log(Level.SEVERE, "Error closing database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + # take the message string which is wrapped by a certain string, and return the text enclosed. + @staticmethod + def decodeMessage(wrapper, message): + result = "" + decoded = Base64.decodeBase64(message) + try: + Z = String(decoded, "UTF-8") + result = Z.split(wrapper)[1] + except Exception as ex: + self._logger.log(Level.SEVERE, "Error decoding a Tango message", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + return result diff --git a/Core/release/InternalPythonModules/android/textmessage.py b/Core/release/InternalPythonModules/android/textmessage.py new file mode 100755 index 0000000000..f618faa29a --- /dev/null +++ b/Core/release/InternalPythonModules/android/textmessage.py @@ -0,0 +1,125 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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 Integer +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 org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule.services import Blackboard +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.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 database with SMS/MMS messages and adds them to blackboard. +""" +class TextMessageAnalyzer(general.AndroidComponentAnalyzer): + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + 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) + 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: + self._logger.log(Level.SEVERE, "Error finding text messages", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + def __findTextsInDB(self, databasePath, abstractFile): + if not databasePath: + return + + try: + Class.forName("org.sqlite.JDBC") # load JDBC driver + connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath) + statement = connection.createStatement() + except (ClassNotFoundException, SQLException) as ex: + self._logger.log(Level.SEVERE, "Error opening database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + return + + try: + resultSet = statement.executeQuery( + "SELECT address, date, read, type, subject, body 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 + artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); #create Message artifact and then add attributes from result set. + if resultSet.getString("type") == "1": + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Incoming")) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, address)) + else: + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Outgoing")) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, address)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, date)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_READ_STATUS, general.MODULE_NAME, Integer(read))) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, general.MODULE_NAME, subject)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, body)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message")) + + try: + # index the artifact for keyword search + blackboard = Case.getCurrentCase().getServices().getBlackboard() + blackboard.indexArtifact(artifact) + except Blackboard.BlackboardException as ex: + self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + MessageNotifyUtil.Notify.error("Failed to index text message artifact for keyword search.", artifact.getDisplayName()) + + 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: + try: + if resultSet is not None: + resultSet.close() + statement.close() + connection.close() + except Exception as ex: + self._logger.log(Level.SEVERE, "Error closing database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) diff --git a/Core/release/InternalPythonModules/android/wwfmessage.py b/Core/release/InternalPythonModules/android/wwfmessage.py new file mode 100755 index 0000000000..97f35869ed --- /dev/null +++ b/Core/release/InternalPythonModules/android/wwfmessage.py @@ -0,0 +1,118 @@ +""" +Autopsy Forensic Browser + +Copyright 2016 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.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 org.sleuthkit.autopsy.casemodule import Case +from org.sleuthkit.autopsy.casemodule.services import Blackboard +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.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 + +""" +Analyzes messages from Words With Friends +""" +class WWFMessageAnalyzer(general.AndroidComponentAnalyzer): + + def __init__(self): + self._logger = Logger.getLogger(self.__class__.__name__) + + def analyze(self, dataSource, fileManager, context): + try: + absFiles = fileManager.findFiles(dataSource, "WordsFramework") + for abstractFile in absFiles: + try: + jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName()) + ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled) + self.__findWWFMessagesInDB(jFile.toString(), abstractFile) + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing WWF messages", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + except TskCoreException as ex: + self._logger.log(Level.SEVERE, "Error finding WWF messages", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + + def __findWWFMessagesInDB(self, databasePath, abstractFile): + if not databasePath: + return + + try: + Class.forName("org.sqlite.JDBC"); # load JDBC driver + connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath) + statement = connection.createStatement() + except (ClassNotFoundException, SQLException) as ex: + self._logger.log(Level.SEVERE, "Error opening database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + return + + try: + resultSet = statement.executeQuery( + "SELECT message, strftime('%s' ,created_at) as datetime, user_id, game_id FROM chat_messages ORDER BY game_id DESC, created_at DESC;") + + while resultSet.next(): + message = resultSet.getString("message") # WWF Message + created_at = resultSet.getLong("datetime") + user_id = resultSet.getString("user_id") # the ID of the user who sent the message. + game_id = resultSet.getString("game_id") # ID of the game which the the message was sent. + + artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) # create a call log and then add attributes from result set. + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, created_at)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, user_id)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID, general.MODULE_NAME, game_id)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, message)) + artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message")) + + try: + # index the artifact for keyword search + blackboard = Case.getCurrentCase().getServices().getBlackboard() + blackboard.indexArtifact(artifact) + except Blackboard.BlackboardException as ex: + self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + MessageNotifyUtil.Notify.error("Failed to index WWF message artifact for keyword search.", artifact.getDisplayName()) + + except Exception as ex: + self._logger.log(Level.SEVERE, "Error parsing WWF messages to the blackboard", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) + finally: + try: + if resultSet is not None: + resultSet.close() + statement.close() + connection.close() + except Exception as ex: + self._logger.log(Level.SEVERE, "Error closing database", ex) + self._logger.log(Level.SEVERE, traceback.format_exc()) diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/AndroidIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/android/AndroidIngestModule.java deleted file mode 100755 index 8dea2a95a2..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/android/AndroidIngestModule.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2016 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. - */ -package org.sleuthkit.autopsy.modules.android; - -import java.util.ArrayList; - -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; -import org.sleuthkit.autopsy.ingest.IngestModule; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; -import org.sleuthkit.autopsy.ingest.IngestJobContext; -import org.sleuthkit.autopsy.ingest.IngestMessage; - -class AndroidIngestModule implements DataSourceIngestModule { - - private IngestJobContext context = null; - - @Override - public void startUp(IngestJobContext context) throws IngestModuleException { - this.context = context; - } - - @Override - public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress progressBar) { - ArrayList errors = new ArrayList<>(); - progressBar.switchToDeterminate(9); - FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); - - try { - ContactAnalyzer.findContacts(dataSource, fileManager, context); - progressBar.progress(1); - if (context.dataSourceIngestIsCancelled()) { - return IngestModule.ProcessResult.OK; - } - } catch (Exception e) { - errors.add("Error getting Contacts"); //NON-NLS - } - - try { - CallLogAnalyzer.findCallLogs(dataSource, fileManager, context); - progressBar.progress(2); - if (context.dataSourceIngestIsCancelled()) { - return IngestModule.ProcessResult.OK; - } - } catch (Exception e) { - errors.add("Error getting Call Logs"); //NON-NLS - } - - try { - TextMessageAnalyzer.findTexts(dataSource, fileManager, context); - progressBar.progress(3); - if (context.dataSourceIngestIsCancelled()) { - return IngestModule.ProcessResult.OK; - } - } catch (Exception e) { - errors.add("Error getting Text Messages"); //NON-NLS - } - - try { - TangoMessageAnalyzer.findTangoMessages(dataSource, fileManager, context); - progressBar.progress(4); - if (context.dataSourceIngestIsCancelled()) { - return IngestModule.ProcessResult.OK; - } - } catch (Exception e) { - errors.add("Error getting Tango Messages"); //NON-NLS - } - - try { - WWFMessageAnalyzer.findWWFMessages(dataSource, fileManager, context); - progressBar.progress(5); - if (context.dataSourceIngestIsCancelled()) { - return IngestModule.ProcessResult.OK; - } - } catch (Exception e) { - errors.add("Error getting Words with Friends Messages"); //NON-NLS - } - - try { - GoogleMapLocationAnalyzer.findGeoLocations(dataSource, fileManager, context); - progressBar.progress(6); - if (context.dataSourceIngestIsCancelled()) { - return IngestModule.ProcessResult.OK; - } - } catch (Exception e) { - errors.add("Error getting Google Map Locations"); //NON-NLS - } - - try { - BrowserLocationAnalyzer.findGeoLocations(dataSource, fileManager, context); - progressBar.progress(7); - if (context.dataSourceIngestIsCancelled()) { - return IngestModule.ProcessResult.OK; - } - } catch (Exception e) { - errors.add("Error getting Browser Locations"); //NON-NLS - } - - try { - CacheLocationAnalyzer.findGeoLocations(dataSource, fileManager, context); - progressBar.progress(8); - } catch (Exception e) { - errors.add("Error getting Cache Locations"); //NON-NLS - } - - // create the final message for inbox - StringBuilder errorMessage = new StringBuilder(); - String errorMsgSubject; - IngestMessage.MessageType msgLevel = IngestMessage.MessageType.INFO; - if (errors.isEmpty() == false) { - msgLevel = IngestMessage.MessageType.ERROR; - errorMessage.append("Errors were encountered"); //NON-NLS - for (String msg : errors) { - errorMessage.append("
  • ").append(msg).append("
  • \n"); //NON-NLS - } - errorMessage.append("\n"); //NON-NLS - - if (errors.size() == 1) { - errorMsgSubject = "One error was found"; //NON-NLS - } else { - errorMsgSubject = "errors found: " + errors.size(); //NON-NLS - } - } else { - errorMessage.append("No errors"); //NON-NLS - errorMsgSubject = "No errors"; //NON-NLS - } - - return IngestModule.ProcessResult.OK; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/AndroidModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/android/AndroidModuleFactory.java deleted file mode 100755 index c30e7c3c64..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/android/AndroidModuleFactory.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2014 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. - */ -package org.sleuthkit.autopsy.modules.android; - -import org.openide.util.lookup.ServiceProvider; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.autopsy.ingest.IngestModuleFactory; -import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; -import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; -import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; - -@ServiceProvider(service = IngestModuleFactory.class) // -public class AndroidModuleFactory extends IngestModuleFactoryAdapter { - - static String getModuleName() { - return NbBundle.getMessage(AndroidModuleFactory.class, "AndroidModuleFactory.moduleName"); - } - - @Override - public String getModuleDisplayName() { - return getModuleName(); - } - - @Override - public String getModuleDescription() { - return NbBundle.getMessage(AndroidModuleFactory.class, "AndroidModuleFactory.moduleDescription"); - } - - @Override - public String getModuleVersionNumber() { - return Version.getVersion(); - } - - @Override - public boolean isDataSourceIngestModuleFactory() { - return true; - } - - @Override - public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings settings) { - return new AndroidIngestModule(); - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/BrowserLocationAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/BrowserLocationAnalyzer.java deleted file mode 100755 index 38592e432d..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/android/BrowserLocationAnalyzer.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2014 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. - */ -package org.sleuthkit.autopsy.modules.android; - -import java.io.File; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.List; -import java.util.logging.Level; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.Blackboard; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.ingest.IngestJobContext; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Analyzes database created by browser that stores GEO location info. - */ -class BrowserLocationAnalyzer { - - private static final String moduleName = AndroidModuleFactory.getModuleName(); - private static final Logger logger = Logger.getLogger(BrowserLocationAnalyzer.class.getName()); - private static Blackboard blackboard; - - public static void findGeoLocations(Content dataSource, FileManager fileManager, - IngestJobContext context) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); - try { - List abstractFiles = fileManager.findFiles(dataSource, "CachedGeoposition%.db"); //NON-NLS - - for (AbstractFile abstractFile : abstractFiles) { - try { - if (abstractFile.getSize() == 0) { - continue; - } - File jFile = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName()); - ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled); - findGeoLocationsInDB(jFile.toString(), abstractFile); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error parsing Browser Location files", e); //NON-NLS - } - } - } catch (TskCoreException e) { - logger.log(Level.SEVERE, "Error finding Browser Location files", e); //NON-NLS - - } - } - - @NbBundle.Messages({"BrowserLocationAnalyzer.indexError.message=Failed to index GPS trackpoint artifact for keyword search."}) - private static void findGeoLocationsInDB(String DatabasePath, AbstractFile f) { - Connection connection = null; - ResultSet resultSet = null; - Statement statement = null; - if (DatabasePath == null || DatabasePath.isEmpty()) { - return; - } - try { - Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver - connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS - statement = connection.createStatement(); - } catch (ClassNotFoundException | SQLException e) { - logger.log(Level.SEVERE, "Error connecting to sql database", e); //NON-NLS - return; - } - - try { - resultSet = statement.executeQuery( - "SELECT timestamp, latitude, longitude, accuracy FROM CachedPosition;"); //NON-NLS - - while (resultSet.next()) { - Long timestamp = Long.valueOf(resultSet.getString("timestamp")) / 1000; //NON-NLS - double latitude = Double.valueOf(resultSet.getString("latitude")); //NON-NLS - double longitude = Double.valueOf(resultSet.getString("longitude")); //NON-NLS - - BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, moduleName, latitude)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, moduleName, longitude)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, timestamp)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, moduleName, - NbBundle.getMessage(BrowserLocationAnalyzer.class, - "BrowserLocationAnalyzer.bbAttribute.browserLocationHistory"))); - // bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(),moduleName, accuracy)); - - try { - // index the artifact for keyword search - blackboard.indexArtifact(bba); - } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactTypeName(), ex); //NON-NLS - MessageNotifyUtil.Notify.error( - Bundle.BrowserLocationAnalyzer_indexError_message(), bba.getDisplayName()); - } - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error Putting artifacts to Blackboard", e); //NON-NLS - } finally { - try { - if (resultSet != null) { - resultSet.close(); - } - statement.close(); - connection.close(); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error closing database", e); //NON-NLS - } - } - - } -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/android/Bundle.properties deleted file mode 100755 index 9ef8ab1338..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/android/Bundle.properties +++ /dev/null @@ -1,11 +0,0 @@ -AndroidModuleFactory.moduleName=Android Analyzer -AndroidModuleFactory.moduleDescription=Extracts Android system and third-party app data. -BrowserLocationAnalyzer.bbAttribute.browserLocationHistory=Browser Location History -CacheLocationAnalyzer.bbAttribute.fileLocationHistory={0} Location History -GoogleMapLocationAnalyzer.bbAttribute.destination=Destination -GoogleMapLocationAnalyzer.bbAttribute.googleMapsHistory=Google Maps History -TangoMessageAnalyzer.bbAttribute.tangoMessage=Tango Message -TextMessageAnalyzer.bbAttribute.incoming=Incoming -TextMessageAnalyzer.bbAttribute.outgoing=Outgoing -TextMessageAnalyzer.bbAttribute.smsMessage=SMS Message -WWFMessageAnalyzer.bbAttribute.wordsWithFriendsMsg=Words With Friends Message diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/android/Bundle_ja.properties deleted file mode 100644 index e555ddc54c..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/android/Bundle_ja.properties +++ /dev/null @@ -1,10 +0,0 @@ -AndroidModuleFactory.moduleDescription=Android\u30b7\u30b9\u30c6\u30e0\u304a\u3088\u3073\u7b2c\u4e09\u8005\u30a2\u30d7\u30ea\u30c7\u30fc\u30bf\u3092\u62bd\u51fa -BrowserLocationAnalyzer.bbAttribute.browserLocationHistory=\u30d6\u30e9\u30a6\u30b6\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\u5c65\u6b74 -CacheLocationAnalyzer.bbAttribute.fileLocationHistory={0} \u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\u5c65\u6b74 -GoogleMapLocationAnalyzer.bbAttribute.destination=\u76ee\u7684\u5730 -GoogleMapLocationAnalyzer.bbAttribute.googleMapsHistory=Google\u30de\u30c3\u30d7\u5c65\u6b74 -TangoMessageAnalyzer.bbAttribute.tangoMessage=Tango\u30e1\u30c3\u30bb\u30fc\u30b8 -TextMessageAnalyzer.bbAttribute.incoming=\u53d7\u4fe1 -TextMessageAnalyzer.bbAttribute.outgoing=\u9001\u4fe1 -TextMessageAnalyzer.bbAttribute.smsMessage=SMS\u30e1\u30c3\u30bb\u30fc\u30b8 -WWFMessageAnalyzer.bbAttribute.wordsWithFriendsMsg=Words With Friends\u30e1\u30c3\u30bb\u30fc\u30b8 \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/CacheLocationAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/CacheLocationAnalyzer.java deleted file mode 100755 index debc4a0066..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/android/CacheLocationAnalyzer.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2014 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. - */ -package org.sleuthkit.autopsy.modules.android; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.util.List; -import java.util.logging.Level; -import org.openide.util.NbBundle; -import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.Blackboard; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.ingest.IngestJobContext; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Parses cache files that Android maintains for Wifi and cell towers. Adds GPS - * points to blackboard. - */ -class CacheLocationAnalyzer { - - private static final String moduleName = AndroidModuleFactory.getModuleName(); - private static final Logger logger = Logger.getLogger(CacheLocationAnalyzer.class.getName()); - private static Blackboard blackboard; - - /** - * cache.cell stores mobile tower GPS locations and cache.wifi stores GPS - * and MAC info from Wifi points. - */ - public static void findGeoLocations(Content dataSource, FileManager fileManager, - IngestJobContext context) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); - try { - List abstractFiles = fileManager.findFiles(dataSource, "cache.cell"); //NON-NLS - abstractFiles.addAll(fileManager.findFiles(dataSource, "cache.wifi")); //NON-NLS - - for (AbstractFile abstractFile : abstractFiles) { - try { - if (abstractFile.getSize() == 0) { - continue; - } - File jFile = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName()); - ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled); - - findGeoLocationsInFile(jFile, abstractFile); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error parsing cached Location files", e); //NON-NLS - } - } - } catch (TskCoreException e) { - logger.log(Level.SEVERE, "Error finding cached Location files", e); //NON-NLS - } - } - - @Messages({"CacheLocationAnalyzer.indexError.message=Failed to index GPS trackpoint artifact for keyword search."}) - private static void findGeoLocationsInFile(File file, AbstractFile f) { - byte[] bytes; // will temporarily hold bytes to be converted into the correct data types - - try { - InputStream inputStream = new FileInputStream(file); - - bytes = new byte[2]; // version - inputStream.read(bytes); - - bytes = new byte[2]; - inputStream.read(bytes); //number of location entries - - int iterations = new BigInteger(bytes).intValue(); - - for (int i = 0; i < iterations; i++) { //loop through every entry - bytes = new byte[2]; - inputStream.read(bytes); - - bytes = new byte[1]; - inputStream.read(bytes); - while (new BigInteger(bytes).intValue() != 0) { //pass through non important values until the start of accuracy(around 7-10 bytes) - if (0 > inputStream.read(bytes)) { - break; /// we've passed the end of the file, so stop - } - } - bytes = new byte[3]; - inputStream.read(bytes); - if (new BigInteger(bytes).intValue() <= 0) {//This refers to a location that could not be calculated. - bytes = new byte[28]; //read rest of the row's bytes - inputStream.read(bytes); - continue; - } - String accuracy = "" + new BigInteger(bytes).intValue(); - - bytes = new byte[4]; - inputStream.read(bytes); - String confidence = "" + new BigInteger(bytes).intValue(); - - bytes = new byte[8]; - inputStream.read(bytes); - double latitude = toDouble(bytes); - - bytes = new byte[8]; - inputStream.read(bytes); - double longitude = toDouble(bytes); - - bytes = new byte[8]; - inputStream.read(bytes); - Long timestamp = new BigInteger(bytes).longValue() / 1000; - - BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, moduleName, latitude)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, moduleName, longitude)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, timestamp)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, moduleName, - NbBundle.getMessage(CacheLocationAnalyzer.class, - "CacheLocationAnalyzer.bbAttribute.fileLocationHistory", - file.getName()))); - - //Not storing these for now. - // bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(),moduleName, accuracy)); - // bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(),moduleName, confidence)); - try { - // index the artifact for keyword search - blackboard.indexArtifact(bba); - } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS - MessageNotifyUtil.Notify.error( - Bundle.CacheLocationAnalyzer_indexError_message(), bba.getDisplayName()); - } - } - - } catch (Exception e) { - logger.log(Level.SEVERE, "Error parsing Cached GPS locations to Blackboard", e); //NON-NLS - } - } - - private static double toDouble(byte[] bytes) { - return ByteBuffer.wrap(bytes).getDouble(); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/GoogleMapLocationAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/GoogleMapLocationAnalyzer.java deleted file mode 100755 index f39e8620d9..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/android/GoogleMapLocationAnalyzer.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2014 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. - */ -package org.sleuthkit.autopsy.modules.android; - -import java.io.File; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.List; -import java.util.logging.Level; -import org.openide.util.NbBundle; -import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.Blackboard; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.ingest.IngestJobContext; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Finds and parses the Google Maps database. - */ -class GoogleMapLocationAnalyzer { - - private static final String moduleName = AndroidModuleFactory.getModuleName(); - private static final Logger logger = Logger.getLogger(GoogleMapLocationAnalyzer.class.getName()); - private static Blackboard blackboard; - - public static void findGeoLocations(Content dataSource, FileManager fileManager, - IngestJobContext context) { - List absFiles; - blackboard = Case.getCurrentCase().getServices().getBlackboard(); - try { - absFiles = fileManager.findFiles(dataSource, "da_destination_history"); //NON-NLS - if (absFiles.isEmpty()) { - return; - } - for (AbstractFile abstractFile : absFiles) { - try { - File jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName()); - ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled); - findGeoLocationsInDB(jFile.toString(), abstractFile); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error parsing Google map locations", e); //NON-NLS - } - } - } catch (TskCoreException e) { - logger.log(Level.SEVERE, "Error finding Google map locations", e); //NON-NLS - } - } - - @Messages({"GoogleMapLocationAnalyzer.indexError.message=Failed to index GPS route artifact for keyword search."}) - private static void findGeoLocationsInDB(String DatabasePath, AbstractFile f) { - Connection connection = null; - ResultSet resultSet = null; - Statement statement = null; - - if (DatabasePath == null || DatabasePath.isEmpty()) { - return; - } - try { - Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver - connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS - statement = connection.createStatement(); - } catch (ClassNotFoundException | SQLException e) { - logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS - return; - } - - try { - resultSet = statement.executeQuery( - "SELECT time,dest_lat,dest_lng,dest_title,dest_address,source_lat,source_lng FROM destination_history;"); //NON-NLS - - while (resultSet.next()) { - Long time = Long.valueOf(resultSet.getString("time")) / 1000; //NON-NLS - String dest_title = resultSet.getString("dest_title"); //NON-NLS - String dest_address = resultSet.getString("dest_address"); //NON-NLS - - double dest_lat = convertGeo(resultSet.getString("dest_lat")); //NON-NLS - double dest_lng = convertGeo(resultSet.getString("dest_lng")); //NON-NLS - double source_lat = convertGeo(resultSet.getString("source_lat")); //NON-NLS - double source_lng = convertGeo(resultSet.getString("source_lng")); //NON-NLS - -// bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT);//src -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID(), moduleName, "Source")); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), moduleName, source_lat)); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), moduleName, source_lng)); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), moduleName, time)); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID(), moduleName, "Google Maps History")); -// -// bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT);//dest -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID(), moduleName, "Destination")); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), moduleName, time)); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), moduleName, dest_lat)); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), moduleName, dest_lng)); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), moduleName, dest_title)); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID(), moduleName, dest_address)); -// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), moduleName, "Google Maps History")); - BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, moduleName, - NbBundle.getMessage(GoogleMapLocationAnalyzer.class, - "GoogleMapLocationAnalyzer.bbAttribute.destination"))); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, time)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END, moduleName, dest_lat)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END, moduleName, dest_lng)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START, moduleName, source_lat)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START, moduleName, source_lng)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, dest_title)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION, moduleName, dest_address)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, moduleName, - NbBundle.getMessage(GoogleMapLocationAnalyzer.class, - "GoogleMapLocationAnalyzer.bbAttribute.googleMapsHistory"))); - - try { - // index the artifact for keyword search - blackboard.indexArtifact(bba); - } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS - MessageNotifyUtil.Notify.error( - Bundle.GoogleMapLocationAnalyzer_indexError_message(), bba.getDisplayName()); - } - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error parsing Google map locations to the Blackboard", e); //NON-NLS - } finally { - try { - if (resultSet != null) { - resultSet.close(); - } - statement.close(); - connection.close(); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error closing the database", e); //NON-NLS - } - } - } - - //add periods 6 decimal places before the end. - private static double convertGeo(String s) { - if (s.length() > 6) { - return Double.valueOf(s.substring(0, s.length() - 6) + "." + s.substring(s.length() - 6, s.length())); - } else { - return Double.valueOf(s); - } - } -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/TangoMessageAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/TangoMessageAnalyzer.java deleted file mode 100755 index 8da1c167ef..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/android/TangoMessageAnalyzer.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2014 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. - */ -package org.sleuthkit.autopsy.modules.android; - -import java.io.File; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.List; -import java.util.logging.Level; -import org.apache.commons.codec.binary.Base64; -import org.openide.util.NbBundle; -import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.Blackboard; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.ingest.IngestJobContext; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Locates database for the Tango app and adds info to blackboard. - */ -class TangoMessageAnalyzer { - - private static final String moduleName = AndroidModuleFactory.getModuleName(); - private static final Logger logger = Logger.getLogger(TangoMessageAnalyzer.class.getName()); - private static Blackboard blackboard; - - public static void findTangoMessages(Content dataSource, FileManager fileManager, - IngestJobContext context) { - blackboard = Case.getCurrentCase().getServices().getBlackboard(); - List absFiles; - try { - absFiles = fileManager.findFiles(dataSource, "tc.db"); //NON-NLS - for (AbstractFile abstractFile : absFiles) { - try { - File jFile = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName()); - ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled); - findTangoMessagesInDB(jFile.toString(), abstractFile); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error parsing Tango messages", e); //NON-NLS - } - } - } catch (TskCoreException e) { - logger.log(Level.SEVERE, "Error finding Tango messages", e); //NON-NLS - } - } - - @Messages({"TangoMessageAnalyzer.indexError.message=Failed to index Tango message artifact for keyword search."}) - private static void findTangoMessagesInDB(String DatabasePath, AbstractFile f) { - Connection connection = null; - ResultSet resultSet = null; - Statement statement = null; - - if (DatabasePath == null || DatabasePath.isEmpty()) { - return; - } - try { - Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver - connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS - statement = connection.createStatement(); - } catch (ClassNotFoundException | SQLException e) { - logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS - return; - } - - try { - resultSet = statement.executeQuery( - "SELECT conv_id, create_time,direction,payload FROM messages ORDER BY create_time DESC;"); //NON-NLS - - String conv_id; // seems to wrap around the message found in payload after decoding from base-64 - String direction; // 1 incoming, 2 outgoing - String payload; // seems to be a base64 message wrapped by the conv_id - - while (resultSet.next()) { - conv_id = resultSet.getString("conv_id"); //NON-NLS - Long create_time = Long.valueOf(resultSet.getString("create_time")) / 1000; //NON-NLS - if (resultSet.getString("direction").equals("1")) { //NON-NLS - direction = "Incoming"; //NON-NLS - } else { - direction = "Outgoing"; //NON-NLS - } - payload = resultSet.getString("payload"); //NON-NLS - - BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create a call log and then add attributes from result set. - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, create_time)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, direction)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, moduleName, decodeMessage(conv_id, payload))); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName, - NbBundle.getMessage(TangoMessageAnalyzer.class, - "TangoMessageAnalyzer.bbAttribute.tangoMessage"))); - - try { - // index the artifact for keyword search - blackboard.indexArtifact(bba); - } catch (Blackboard.BlackboardException ex) { - MessageNotifyUtil.Notify.error( - Bundle.TangoMessageAnalyzer_indexError_message(), bba.getDisplayName()); - logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS - } - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error parsing Tango messages to the Blackboard", e); //NON-NLS - } finally { - try { - if (resultSet != null) { - resultSet.close(); - } - statement.close(); - connection.close(); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error closing database", e); //NON-NLS - } - } - } - - //take the message string which is wrapped by a certain string, and return the text enclosed. - private static String decodeMessage(String wrapper, String message) { - String result = ""; - byte[] decoded = Base64.decodeBase64(message); - try { - String Z = new String(decoded, "UTF-8"); - result = Z.split(wrapper)[1]; - } catch (Exception e) { - logger.log(Level.SEVERE, "Error decoding a Tango message", e); //NON-NLS - } - return result; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/modules/android/WWFMessageAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/android/WWFMessageAnalyzer.java deleted file mode 100755 index 5685880afc..0000000000 --- a/Core/src/org/sleuthkit/autopsy/modules/android/WWFMessageAnalyzer.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2014 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. - */ -package org.sleuthkit.autopsy.modules.android; - -import java.io.File; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.List; -import java.util.logging.Level; -import org.openide.util.NbBundle; -import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.Blackboard; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.ingest.IngestJobContext; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Finds database for words with friends, parses it, and adds info to - * blackboard. - */ -class WWFMessageAnalyzer { - - private static final String moduleName = AndroidModuleFactory.getModuleName(); - private static final Logger logger = Logger.getLogger(WWFMessageAnalyzer.class.getName()); - private static Blackboard blackboard; - - public static void findWWFMessages(Content dataSource, FileManager fileManager, - IngestJobContext context) { - List absFiles; - blackboard = Case.getCurrentCase().getServices().getBlackboard(); - try { - absFiles = fileManager.findFiles(dataSource, "WordsFramework"); //NON-NLS - - for (AbstractFile abstractFile : absFiles) { - try { - File jFile = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName()); - ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled); - - findWWFMessagesInDB(jFile.toString(), abstractFile); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error parsing WWF messages", e); //NON-NLS - } - } - } catch (TskCoreException e) { - logger.log(Level.SEVERE, "Error finding WWF messages", e); //NON-NLS - } - } - - @Messages({"WWFMessageAnalyzer.indexError.message=Failed to index WWF message artifact for keyword search."}) - private static void findWWFMessagesInDB(String DatabasePath, AbstractFile f) { - Connection connection = null; - ResultSet resultSet = null; - Statement statement = null; - - if (DatabasePath == null || DatabasePath.isEmpty()) { - return; - } - try { - Class.forName("org.sqlite.JDBC"); //load JDBC driver - connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS - statement = connection.createStatement(); - } catch (ClassNotFoundException | SQLException e) { - logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS - return; - } - - try { - resultSet = statement.executeQuery( - "SELECT message,strftime('%s' ,created_at) as datetime,user_id,game_id FROM chat_messages ORDER BY game_id DESC, created_at DESC;"); //NON-NLS - - String message; // WWF Message - String user_id; // the ID of the user who sent the message. - String game_id; // ID of the game which the the message was sent. - - while (resultSet.next()) { - message = resultSet.getString("message"); //NON-NLS - Long created_at = resultSet.getLong("datetime"); //NON-NLS - user_id = resultSet.getString("user_id"); //NON-NLS - game_id = resultSet.getString("game_id"); //NON-NLS - - BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create a call log and then add attributes from result set. - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, created_at)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, user_id)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID, moduleName, game_id)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, moduleName, message)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName, - NbBundle.getMessage(WWFMessageAnalyzer.class, - "WWFMessageAnalyzer.bbAttribute.wordsWithFriendsMsg"))); - - try { - // index the artifact for keyword search - blackboard.indexArtifact(bba); - } catch (Blackboard.BlackboardException ex) { - logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS - MessageNotifyUtil.Notify.error( - Bundle.WWFMessageAnalyzer_indexError_message(), bba.getDisplayName()); - } - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error parsing WWF messages to the Blackboard", e); //NON-NLS - } finally { - try { - if (resultSet != null) { - resultSet.close(); - } - statement.close(); - connection.close(); - } catch (Exception e) { - logger.log(Level.SEVERE, "Error closing database", e); //NON-NLS - } - } - } -}