5566: Add more comments to modules.

This commit is contained in:
Raman Arora 2019-09-27 13:08:08 -04:00
parent fee109775c
commit 8580b9b6b9
4 changed files with 158 additions and 46 deletions

View File

@ -50,12 +50,52 @@ import json
import traceback
import general
"""
Finds the SQLite DB for Facebook messenger, parses the DB for contacts & messages,
and adds artifacts to the case.
"""
class FBMessengerAnalyzer(general.AndroidComponentAnalyzer):
"""
Facebook Messenger is a messaging application for Facebook users.
It can be used to have one-to-one as well as group message conversations -
text, send photos videos and other media file. It can also be used to make
phone calls - audio as well as video.
This module finds the SQLite DB for FB messenger, parses the DB for contacts,
messages, and call logs and creates artifacts.
FB messenger requires Facebook accounts. Although Facebook and Facebook Messenger are
two different applications with separate packages, their database structure is very similar
and FB messenger seems to share the FB database if FB is inatalled.
FB assigns each user a unique FB id, fbid - a long numeric id.
Each user also has a display name.
FB uses a notion of user key, which is of the form FACEBOOK:<fbid>
FB messenger version 239.0.0.41 has the following database structure:
- contacts_db2
-- A contacts table that stores the contacts/friends.
- threads_db2
-- A messages table to store the messages
--- A sender column - this is a JSON structure which has a the FB user key of sender.
--- A attachments column - a JSON structure that has details of the attachments,
--- A msg_type column: message type - indicates whether its a text/mms message or a audio/video call
--- A thread_key column - identifies the message thread
--- A timestamp_ms column - date/time message was sent
--- A text column - message text, if applicable
-- A thread_participants table to identify participants in a particular thread
--- A thread_key column - identifies a message thread
--- A user_key column to identify a particpant in the thread
-- A thread_users to identify the user details, primarliy name, of a user that has been a particiapnt in any thread
--- A user_key column - identifies a unique user
--- A name column - user display name
"""
def __init__(self):
self._logger = Logger.getLogger(self.__class__.__name__)
@ -70,13 +110,15 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer):
## Analyze contacts
def analyzeContacts(self, dataSource, fileManager, context):
## FB messenger and FB have same database structure for contacts.
## In our example the FB Messenger database was empty.
## In our dataset, the FB Messenger database was empty.
## But the FB database had the data.
contactsDbs = AppSQLiteDB.findAppDatabases(dataSource, "contacts_db2", True, self._FACEBOOK_PACKAGE_NAME)
for contactsDb in contactsDbs:
try:
## The device owner's FB account details can be found in the contacts table in a row with added_time_ms of 0.
selfAccountResultSet = contactsDb.runQuery("SELECT fbid, display_name FROM contacts WHERE added_time_ms = 0")
if selfAccountResultSet:
if not self.selfAccountAddress:
@ -90,7 +132,8 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer):
contactsDBHelper = CommunicationArtifactsHelper(self.current_case.getSleuthkitCase(),
self._MODULE_NAME, contactsDb.getDBFile(),
Account.Type.FACEBOOK)
## get the other contacts/friends
contactsResultSet = contactsDb.runQuery("SELECT fbid, display_name, added_time_ms FROM contacts WHERE added_time_ms <> 0")
if contactsResultSet is not None:
while contactsResultSet.next():
@ -147,14 +190,20 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer):
self._MODULE_NAME, threadsDb.getDBFile(),
Account.Type.FACEBOOK)
## Messages are found in the messages table. The participant ids can be found in the thread_participants table.
## Messages are found in the messages table.
## The participant ids can be found in the thread_participants table.
## Participant names are found in thread_users table.
## Joining these tables produces multiple rows per message, one row for each recipient
sqlString = "SELECT msg_id, text, sender, timestamp_ms, messages.thread_key as thread_key,"\
" snippet, thread_participants.user_key as user_key, thread_users.name as name FROM messages"\
" JOIN thread_participants ON messages.thread_key = thread_participants.thread_key"\
" JOIN thread_users ON thread_participants.user_key = thread_users.user_key"\
" ORDER BY msg_id"
## Joining these tables produces multiple rows per message, one row for each recipient.
## The result set is processed to collect the multiple recipients for a given message.
sqlString = """
SELECT msg_id, text, sender, timestamp_ms, messages.thread_key as thread_key,
snippet, thread_participants.user_key as user_key, thread_users.name as name
FROM messages
JOIN thread_participants ON messages.thread_key = thread_participants.thread_key
JOIN thread_users ON thread_participants.user_key = thread_users.user_key
ORDER BY msg_id
"""
messagesResultSet = threadsDb.runQuery(sqlString)
if messagesResultSet is not None:
@ -212,7 +261,7 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer):
# Get msg text
# Sometimes there may not be an explict msg text,
# but a app genrated snippet instead
# but an app generated snippet instead
msgText = messagesResultSet.getString("text")
if not msgText:
msgText = messagesResultSet.getString("snippet")

View File

@ -46,13 +46,21 @@ from org.sleuthkit.datamodel.blackboardutils import ArtifactsHelper
import traceback
import general
"""
Finds the SQLite DB for Android installed applications, parses the DB,
and adds artifacts to the case.
"""
class InstalledApplicationsAnalyzer(general.AndroidComponentAnalyzer):
moduleName = "Android Installed Applications Analyzer"
"""
Android has a database to track the applications that are
purchased and installed on the phone.
This module finds the SQLite DB for insalled application, and creates artifacts.
Android 5.1.1 has the following database structure istalled applications:
- library.db
-- A ownership table that stores pplications purchased, with purchase date
"""
def __init__(self):
self._logger = Logger.getLogger(self.__class__.__name__)
@ -67,7 +75,7 @@ class InstalledApplicationsAnalyzer(general.AndroidComponentAnalyzer):
try:
current_case = Case.getCurrentCaseThrows()
libraryDbHelper = ArtifactsHelper(current_case.getSleuthkitCase(),
self.moduleName, libraryDb.getDBFile())
self._MODULE_NAME, libraryDb.getDBFile())
queryString = "SELECT doc_id, purchase_time FROM ownership"
ownershipResultSet = libraryDb.runQuery(queryString)
if ownershipResultSet is not None:

View File

@ -52,6 +52,30 @@ and adds artifacts to the case.
"""
class OperaAnalyzer(general.AndroidComponentAnalyzer):
"""
Opera is a web browser on Android phones.
This module finds the SQLite DB for Opera, parses the DB for bookmarks,
downloads, web history, cookies, autofill and creates artifacts.
Opera version 53.1.2569 has the following database structure:
- cookies
-- A cookies table to store cookies
- history
-- A urls table to store history of visted urls
-- A downloads table to store downloads
- Web Data
-- A autofill table to store discrete autofill name/value pairs
-- A autofill_profile_names to store name fields (first name, middle name, last name)
-- A autofill_profiles to store the physical snailmail address (street address, city, state, country, zip)
-- A autofill_profile_phones to store phone numbers
-- A autofill_profile_emails to store email addresses
"""
moduleName = "Opera Parser"
progName = "Opera"
@ -68,7 +92,7 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer):
for cookiesDb in cookiesDbs:
try:
cookiesDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(),
self.moduleName, cookiesDb.getDBFile())
self._MODULE_NAME, cookiesDb.getDBFile())
cookiesResultSet = cookiesDb.runQuery("SELECT host_key, name, value, creation_utc FROM cookies")
if cookiesResultSet is not None:
while cookiesResultSet.next():
@ -98,7 +122,7 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer):
for historyDb in historyDbs:
try:
historyDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(),
self.moduleName, historyDb.getDBFile())
self._MODULE_NAME, historyDb.getDBFile())
historyResultSet = historyDb.runQuery("SELECT url, title, last_visit_time FROM urls")
if historyResultSet is not None:
while historyResultSet.next():
@ -127,7 +151,7 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer):
for downloadsDb in downloadsDbs:
try:
downloadsDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(),
self.moduleName, downloadsDb.getDBFile())
self._MODULE_NAME, downloadsDb.getDBFile())
queryString = "SELECT target_path, start_time, url FROM downloads"\
" INNER JOIN downloads_url_chains ON downloads.id = downloads_url_chains.id"
downloadsResultSet = downloadsDb.runQuery(queryString)
@ -156,7 +180,7 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer):
for autofillDb in autofillDbs:
try:
autofillDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(),
self.moduleName, autofillDb.getDBFile())
self._MODULE_NAME, autofillDb.getDBFile())
autofillsResultSet = autofillDb.runQuery("SELECT name, value, count, date_created FROM autofill")
if autofillsResultSet is not None:
while autofillsResultSet.next():
@ -184,14 +208,15 @@ class OperaAnalyzer(general.AndroidComponentAnalyzer):
for webFormAddressDb in webFormAddressDbs:
try:
webFormAddressDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(),
self.moduleName, webFormAddressDb.getDBFile())
queryString = "SELECT street_address, city, state, zipcode, country_code, date_modified, first_name, last_name, number, email FROM autofill_profiles "\
" INNER JOIN autofill_profile_names"\
" ON autofill_profiles.guid = autofill_profile_names.guid"\
" INNER JOIN autofill_profile_phones"\
" ON autofill_profiles.guid = autofill_profile_phones.guid"\
" INNER JOIN autofill_profile_emails"\
" ON autofill_profiles.guid = autofill_profile_emails.guid"
self._MODULE_NAME, webFormAddressDb.getDBFile())
queryString = """
SELECT street_address, city, state, zipcode, country_code,
date_modified, first_name, last_name, number, email
FROM autofill_profiles
INNER JOIN autofill_profile_names ON autofill_profiles.guid = autofill_profile_names.guid
INNER JOIN autofill_profile_phones ON autofill_profiles.guid = autofill_profile_phones.guid
INNER JOIN autofill_profile_emails ON autofill_profiles.guid = autofill_profile_emails.guid
"""
webFormAddressResultSet = webFormAddressDb.runQuery(queryString)
if webFormAddressResultSet is not None:
while webFormAddressResultSet.next():

View File

@ -46,12 +46,34 @@ from org.sleuthkit.datamodel.blackboardutils import WebBrowserArtifactsHelper
import traceback
import general
"""
Finds the SQLite DB for S-Browser, parses the DB for Bookmarks, Cookies, Web History
and adds artifacts to the case.
"""
class SBrowserAnalyzer(general.AndroidComponentAnalyzer):
"""
SBrowser is the default/native browser on Android phones.
This module finds the SQLite DB for SBrowser, parses the DB for bookmarks,
downloads, web history, cookies, autofill and creates artifacts.
SBrowser has the following database structure:
- sbrowser.db
-- A bookmarks table that store bookmarks
- cookies
-- A cookies table to store cookies
- history
-- A urls table to store history of visted urls
-- A downloads table to store downloads
- Web Data
-- A autofill table to store discrete autofill name/value pairs
-- A autofill_profile_names to store name fields (first name, middle name, last name)
-- A autofill_profiles to store the physical snailmail address (street address, city, state, country, zip)
-- A autofill_profile_phones to store phone numbers
-- A autofill_profile_emails to store email addresses
"""
def __init__(self):
self._logger = Logger.getLogger(self.__class__.__name__)
self._PACKAGE_NAME = "com.sec.android.app.sbrowser"
@ -182,7 +204,12 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer):
try:
autofillDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(),
self._MODULE_NAME, autofillDb.getDBFile())
autofillsResultSet = autofillDb.runQuery("SELECT name, value, count, date_created FROM autofill INNER JOIN autofill_dates ON autofill.pair_id = autofill_dates.pair_id")
queryString = """
SELECT name, value, count, date_created
FROM autofill
INNER JOIN autofill_dates ON autofill.pair_id = autofill_dates.pair_id
"""
autofillsResultSet = autofillDb.runQuery(queryString)
if autofillsResultSet is not None:
while autofillsResultSet.next():
creationTime = autofillsResultSet.getLong("date_created") / 1000000 - 11644473600 # Webkit time
@ -210,13 +237,16 @@ class SBrowserAnalyzer(general.AndroidComponentAnalyzer):
try:
webFormAddressDbHelper = WebBrowserArtifactsHelper(self.current_case.getSleuthkitCase(),
self._MODULE_NAME, webFormAddressDb.getDBFile())
queryString = "SELECT street_address, city, state, zipcode, country_code, date_modified, first_name, last_name, number, email FROM autofill_profiles "\
" INNER JOIN autofill_profile_names"\
" ON autofill_profiles.guid = autofill_profile_names.guid"\
" INNER JOIN autofill_profile_phones"\
" ON autofill_profiles.guid = autofill_profile_phones.guid"\
" INNER JOIN autofill_profile_emails"\
" ON autofill_profiles.guid = autofill_profile_emails.guid"
"""
Autofill form data is split across multiple tables. The quqery below joins the various tables.
"""
queryString = """
SELECT street_address, city, state, zipcode, country_code, date_modified, first_name, last_name, number, email
FROM autofill_profiles
INNER JOIN autofill_profile_names ON autofill_profiles.guid = autofill_profile_names.guid
INNER JOIN autofill_profile_phones ON autofill_profiles.guid = autofill_profile_phones.guid
INNER JOIN autofill_profile_emails ON autofill_profiles.guid = autofill_profile_emails.guid
"""
webFormAddressResultSet = webFormAddressDb.runQuery(queryString)
if webFormAddressResultSet is not None:
while webFormAddressResultSet.next():