19 package org.sleuthkit.autopsy.modules.android;
22 import java.sql.Connection;
23 import java.sql.DriverManager;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.sql.Statement;
27 import java.util.List;
28 import java.util.logging.Level;
29 import org.apache.commons.codec.binary.Base64;
30 import org.openide.util.NbBundle;
31 import org.openide.util.NbBundle.Messages;
48 class TangoMessageAnalyzer {
50 private static final String moduleName = AndroidModuleFactory.getModuleName();
51 private static final Logger logger = Logger.getLogger(TangoMessageAnalyzer.class.getName());
52 private static Blackboard blackboard;
54 public static void findTangoMessages(Content dataSource, FileManager fileManager,
55 IngestJobContext context) {
56 blackboard = Case.getCurrentCase().getServices().getBlackboard();
57 List<AbstractFile> absFiles;
59 absFiles = fileManager.findFiles(dataSource,
"tc.db");
60 for (AbstractFile abstractFile : absFiles) {
62 File jFile =
new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
63 ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled);
64 findTangoMessagesInDB(jFile.toString(), abstractFile);
65 }
catch (Exception e) {
66 logger.log(Level.SEVERE,
"Error parsing Tango messages", e);
69 }
catch (TskCoreException e) {
70 logger.log(Level.SEVERE,
"Error finding Tango messages", e);
74 @Messages({
"TangoMessageAnalyzer.indexError.message=Failed to index Tango message artifact for keyword search."})
75 private static void findTangoMessagesInDB(String DatabasePath, AbstractFile f) {
76 Connection connection = null;
77 ResultSet resultSet = null;
78 Statement statement = null;
80 if (DatabasePath == null || DatabasePath.isEmpty()) {
84 Class.forName(
"org.sqlite.JDBC");
85 connection = DriverManager.getConnection(
"jdbc:sqlite:" + DatabasePath);
86 statement = connection.createStatement();
87 }
catch (ClassNotFoundException | SQLException e) {
88 logger.log(Level.SEVERE,
"Error opening database", e);
93 resultSet = statement.executeQuery(
94 "SELECT conv_id, create_time,direction,payload FROM messages ORDER BY create_time DESC;");
100 while (resultSet.next()) {
101 conv_id = resultSet.getString(
"conv_id");
102 Long create_time = Long.valueOf(resultSet.getString(
"create_time")) / 1000;
103 if (resultSet.getString(
"direction").equals(
"1")) {
104 direction =
"Incoming";
106 direction =
"Outgoing";
108 payload = resultSet.getString(
"payload");
110 BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE);
111 bba.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, create_time));
112 bba.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, direction));
113 bba.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, moduleName, decodeMessage(conv_id, payload)));
114 bba.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName,
115 NbBundle.getMessage(TangoMessageAnalyzer.class,
116 "TangoMessageAnalyzer.bbAttribute.tangoMessage")));
120 blackboard.indexArtifact(bba);
121 }
catch (Blackboard.BlackboardException ex) {
122 MessageNotifyUtil.Notify.error(
123 Bundle.TangoMessageAnalyzer_indexError_message(), bba.getDisplayName());
124 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + bba.getArtifactID(), ex);
127 }
catch (Exception e) {
128 logger.log(Level.SEVERE,
"Error parsing Tango messages to the Blackboard", e);
131 if (resultSet != null) {
136 }
catch (Exception e) {
137 logger.log(Level.SEVERE,
"Error closing database", e);
143 private static String decodeMessage(String wrapper, String message) {
145 byte[] decoded = Base64.decodeBase64(message);
147 String Z =
new String(decoded,
"UTF-8");
148 result = Z.split(wrapper)[1];
149 }
catch (Exception e) {
150 logger.log(Level.SEVERE,
"Error decoding a Tango message", e);