mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +00:00
Merge pull request #862 from millmanorama/call_log_locations
Merge remote-tracking branch 'upstream/develop' into call_log_locations
This commit is contained in:
commit
ab2ad235be
@ -19,114 +19,126 @@
|
||||
package org.sleuthkit.autopsy.modules.android;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
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.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
class CallLogAnalyzer {
|
||||
|
||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CallLogAnalyzer.class.getName());
|
||||
|
||||
/** the where clause(without 'where' of sql select statement to choose call
|
||||
* log dbs, update the list of file names to include more files */
|
||||
private static final String fileNameQuery = Stream.of("'logs.db'", "'contacts2.db'", "'contacts.db'")
|
||||
.collect(Collectors.joining(" OR name = ", "name = ", ""));
|
||||
|
||||
/** the names of tables that potentially hold call logs in the dbs */
|
||||
private static final Iterable<String> tableNames = Arrays.asList("calls", "logs");
|
||||
|
||||
public static void findCallLogs() {
|
||||
List<AbstractFile> absFiles;
|
||||
try {
|
||||
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
|
||||
absFiles = skCase.findAllFilesWhere("name ='contacts2.db' OR name ='contacts.db'"); //get exact file names
|
||||
if (absFiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (AbstractFile abstractFile : absFiles) {
|
||||
try {
|
||||
File jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
|
||||
ContentUtils.writeToFile(abstractFile, jFile);
|
||||
|
||||
findCallLogsInDB(jFile.toString(), abstractFile);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error parsing Call logs", e);
|
||||
for (AbstractFile abstractFile : skCase.findAllFilesWhere(fileNameQuery)) {
|
||||
try {
|
||||
File file = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
|
||||
ContentUtils.writeToFile(abstractFile, file);
|
||||
findCallLogsInDB(file.toString(), abstractFile);
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, "Error writing temporary call log db to disk", e);
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException e) {
|
||||
logger.log(Level.SEVERE, "Error finding Call logs", e);
|
||||
logger.log(Level.SEVERE, "Error finding call logs", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void findCallLogsInDB(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);
|
||||
statement = connection.createStatement();
|
||||
} catch (ClassNotFoundException | SQLException e) {
|
||||
logger.log(Level.SEVERE, "Error opening database", e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
resultSet = statement.executeQuery(
|
||||
"SELECT number,date,duration,type, name FROM calls ORDER BY date DESC;");
|
||||
|
||||
BlackboardArtifact bba;
|
||||
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath);
|
||||
Statement statement = connection.createStatement();) {
|
||||
|
||||
for (String tableName : tableNames) {
|
||||
try (ResultSet resultSet = statement.executeQuery(
|
||||
"SELECT number,date,duration,type, name FROM " + tableName + " ORDER BY date DESC;");) {
|
||||
logger.log(Level.INFO, "Reading call log from table {0} in db {1}", new Object[]{tableName, DatabasePath});
|
||||
while (resultSet.next()) {
|
||||
// name of person dialed or called. null if unregistered
|
||||
String name = resultSet.getString("name");
|
||||
String number = resultSet.getString("number");
|
||||
//duration of call in seconds
|
||||
Long duration = Long.valueOf(resultSet.getString("duration"));
|
||||
Long date = Long.valueOf(resultSet.getString("date")) / 1000;
|
||||
Long date = resultSet.getLong("date") / 1000;
|
||||
final CallDirection direction = CallDirection.fromType(resultSet.getInt("type"));
|
||||
String directionString = direction != null ? direction.getDisplayName() : "";
|
||||
final String number = resultSet.getString("number");
|
||||
final long duration = resultSet.getLong("duration");//duration of call is in seconds
|
||||
final String name = resultSet.getString("name");// name of person dialed or called. null if unregistered
|
||||
|
||||
String direction = "";
|
||||
switch (Integer.valueOf(resultSet.getString("type"))) {
|
||||
case 1:
|
||||
direction = "Incoming";
|
||||
break;
|
||||
case 2:
|
||||
direction = "Outgoing";
|
||||
break;
|
||||
case 3:
|
||||
direction = "Missed";
|
||||
break;
|
||||
}
|
||||
|
||||
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG); //create a call log and then add attributes from result set.
|
||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID(), moduleName, number));
|
||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID(), moduleName, date));
|
||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID(), moduleName, duration + date));
|
||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID(), moduleName, direction));
|
||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), moduleName, name));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error parsing Call logs to the Blackboard", e);
|
||||
} finally {
|
||||
try {
|
||||
if (resultSet != null) {
|
||||
resultSet.close();
|
||||
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG); //create a call log and then add attributes from result set.
|
||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID(), moduleName, number));
|
||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID(), moduleName, date));
|
||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID(), moduleName, duration + date));
|
||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID(), moduleName, directionString));
|
||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), moduleName, name));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error posting call log record to the Blackboard", ex);
|
||||
}
|
||||
statement.close();
|
||||
connection.close();
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error closing the database", e);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.log(Level.WARNING, "Could not read table {0} in db {1}", new Object[]{tableName, DatabasePath});
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.log(Level.SEVERE, "Could not parse call log; error connecting to db " + DatabasePath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static enum CallDirection {
|
||||
|
||||
INCOMING(1, "Incoming"), OUTGOING(2, "Outgoing"), MISSED(3, "Missed");
|
||||
|
||||
private final int type;
|
||||
|
||||
private final String displayName;
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
private CallDirection(int type, String displayName) {
|
||||
this.type = type;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
static CallDirection fromType(int t) {
|
||||
switch (t) {
|
||||
case 1:
|
||||
return INCOMING;
|
||||
case 2:
|
||||
return OUTGOING;
|
||||
case 3:
|
||||
return MISSED;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user