23 package org.sleuthkit.autopsy.recentactivity;
25 import com.google.gson.JsonArray;
26 import com.google.gson.JsonElement;
27 import com.google.gson.JsonIOException;
28 import com.google.gson.JsonObject;
29 import com.google.gson.JsonParser;
30 import com.google.gson.JsonSyntaxException;
31 import org.openide.util.NbBundle;
34 import java.util.logging.Level;
37 import java.io.FileNotFoundException;
38 import java.io.FileReader;
39 import java.io.IOException;
40 import org.apache.commons.io.FilenameUtils;
41 import org.openide.util.NbBundle.Messages;
53 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
55 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
57 import org.
sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
64 class Chrome
extends Extract {
66 private static final String HISTORY_QUERY =
"SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, "
67 +
"last_visit_time, urls.hidden, visits.visit_time, (SELECT urls.url FROM urls WHERE urls.id=visits.url) AS from_visit, visits.transition FROM urls, visits WHERE urls.id = visits.url";
68 private static final String COOKIE_QUERY =
"SELECT name, value, host_key, expires_utc,last_access_utc, creation_utc FROM cookies";
69 private static final String DOWNLOAD_QUERY =
"SELECT full_path, url, start_time, received_bytes FROM downloads";
70 private static final String DOWNLOAD_QUERY_V30 =
"SELECT current_path AS full_path, url, start_time, received_bytes FROM downloads, downloads_url_chains WHERE downloads.id=downloads_url_chains.id";
71 private static final String LOGIN_QUERY =
"SELECT origin_url, username_value, date_created, signon_realm from logins";
72 private static final String AUTOFILL_QUERY =
"SELECT name, value, count, date_created " +
73 " FROM autofill, autofill_dates " +
74 " WHERE autofill.pair_id = autofill_dates.pair_id"
76 private static final String AUTOFILL_QUERY_V8X =
"SELECT name, value, count, date_created, date_last_used from autofill";
77 private static final String WEBFORM_ADDRESS_QUERY =
"SELECT first_name, middle_name, last_name, address_line_1, address_line_2, city, state, zipcode, country_code, number, email, date_modified " +
78 " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
79 " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
81 private static final String WEBFORM_ADDRESS_QUERY_V8X =
"SELECT first_name, middle_name, last_name, full_name, street_address, city, state, zipcode, country_code, number, email, date_modified, use_date, use_count" +
82 " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
83 " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
84 private final Logger logger = Logger.getLogger(this.getClass().getName());
85 private Content dataSource;
86 private IngestJobContext context;
89 "Progress_Message_Chrome_History=Chrome History",
90 "Progress_Message_Chrome_Bookmarks=Chrome Bookmarks",
91 "Progress_Message_Chrome_Cookies=Chrome Cookies",
92 "Progress_Message_Chrome_Downloads=Chrome Downloads",
93 "Progress_Message_Chrome_FormHistory=Chrome Form History",
94 "Progress_Message_Chrome_AutoFill=Chrome Auto Fill",
95 "Progress_Message_Chrome_Logins=Chrome Logins",
96 "Progress_Message_Chrome_Cache=Chrome Cache",
100 moduleName = NbBundle.getMessage(Chrome.class,
"Chrome.moduleName");
104 public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
105 this.dataSource = dataSource;
106 this.context = context;
109 progressBar.progress(Bundle.Progress_Message_Chrome_History());
111 if (context.dataSourceIngestIsCancelled()) {
115 progressBar.progress(Bundle.Progress_Message_Chrome_Bookmarks());
117 if (context.dataSourceIngestIsCancelled()) {
121 progressBar.progress(Bundle.Progress_Message_Chrome_Cookies());
123 if (context.dataSourceIngestIsCancelled()) {
127 progressBar.progress(Bundle.Progress_Message_Chrome_Logins());
129 if (context.dataSourceIngestIsCancelled()) {
133 progressBar.progress(Bundle.Progress_Message_Chrome_AutoFill());
135 if (context.dataSourceIngestIsCancelled()) {
139 progressBar.progress(Bundle.Progress_Message_Chrome_Downloads());
141 if (context.dataSourceIngestIsCancelled()) {
145 progressBar.progress(Bundle.Progress_Message_Chrome_Cache());
146 ChromeCacheExtractor chromeCacheExtractor =
new ChromeCacheExtractor(dataSource, context, progressBar);
147 chromeCacheExtractor.getCaches();
153 private void getHistory() {
154 FileManager fileManager = currentCase.getServices().getFileManager();
155 List<AbstractFile> historyFiles;
157 historyFiles = fileManager.findFiles(dataSource,
"History",
"Chrome");
158 }
catch (TskCoreException ex) {
159 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getHistory.errMsg.errGettingFiles");
160 logger.log(Level.SEVERE, msg, ex);
161 this.addErrorMessage(this.getName() +
": " + msg);
166 List<AbstractFile> allocatedHistoryFiles =
new ArrayList<>();
167 for (AbstractFile historyFile : historyFiles) {
168 if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
169 allocatedHistoryFiles.add(historyFile);
174 if (allocatedHistoryFiles.isEmpty()) {
175 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getHistory.errMsg.couldntFindAnyFiles");
176 logger.log(Level.INFO, msg);
181 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
183 while (j < historyFiles.size()) {
184 String temps = RAImageIngestModule.getRATempPath(currentCase,
"chrome") + File.separator + historyFiles.get(j).getName() + j +
".db";
185 final AbstractFile historyFile = historyFiles.get(j++);
186 if (historyFile.getSize() == 0) {
190 ContentUtils.writeToFile(historyFile,
new File(temps), context::dataSourceIngestIsCancelled);
191 }
catch (ReadContentInputStreamException ex) {
192 logger.log(Level.WARNING, String.format(
"Error reading Chrome web history artifacts file '%s' (id=%d).",
193 historyFile.getName(), historyFile.getId()), ex);
194 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getHistory.errMsg.errAnalyzingFile",
195 this.getName(), historyFile.getName()));
197 }
catch (IOException ex) {
198 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
199 temps, historyFile.getName(), historyFile.getId()), ex);
200 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getHistory.errMsg.errAnalyzingFile",
201 this.getName(), historyFile.getName()));
204 File dbFile =
new File(temps);
205 if (context.dataSourceIngestIsCancelled()) {
209 List<HashMap<String, Object>> tempList;
210 tempList = this.dbConnect(temps, HISTORY_QUERY);
211 logger.log(Level.INFO,
"{0}- Now getting history from {1} with {2}artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
212 for (HashMap<String, Object> result : tempList) {
213 Collection<BlackboardAttribute> bbattributes =
new ArrayList<BlackboardAttribute>();
214 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
215 RecentActivityExtracterModuleFactory.getModuleName(),
216 ((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"")));
217 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
218 RecentActivityExtracterModuleFactory.getModuleName(),
219 (Long.valueOf(result.get(
"last_visit_time").toString()) / 1000000) - Long.valueOf(
"11644473600")));
220 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
221 RecentActivityExtracterModuleFactory.getModuleName(),
222 ((result.get(
"from_visit").toString() != null) ? result.get(
"from_visit").toString() :
"")));
223 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
224 RecentActivityExtracterModuleFactory.getModuleName(),
225 ((result.get(
"title").toString() != null) ? result.get(
"title").toString() :
"")));
226 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
227 RecentActivityExtracterModuleFactory.getModuleName(),
228 NbBundle.getMessage(this.getClass(),
"Chrome.moduleName")));
229 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
230 RecentActivityExtracterModuleFactory.getModuleName(),
231 (NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
""))));
233 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
235 bbartifacts.add(bbart);
241 IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
242 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
243 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, bbartifacts));
249 private void getBookmark() {
250 FileManager fileManager = currentCase.getServices().getFileManager();
251 List<AbstractFile> bookmarkFiles;
253 bookmarkFiles = fileManager.findFiles(dataSource,
"Bookmarks",
"Chrome");
254 }
catch (TskCoreException ex) {
255 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getBookmark.errMsg.errGettingFiles");
256 logger.log(Level.SEVERE, msg, ex);
257 this.addErrorMessage(this.getName() +
": " + msg);
261 if (bookmarkFiles.isEmpty()) {
262 logger.log(Level.INFO,
"Didn't find any Chrome bookmark files.");
267 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
270 while (j < bookmarkFiles.size()) {
271 AbstractFile bookmarkFile = bookmarkFiles.get(j++);
272 if (bookmarkFile.getSize() == 0) {
275 String temps = RAImageIngestModule.getRATempPath(currentCase,
"chrome") + File.separator + bookmarkFile.getName() + j +
".db";
277 ContentUtils.writeToFile(bookmarkFile,
new File(temps), context::dataSourceIngestIsCancelled);
278 }
catch (ReadContentInputStreamException ex) {
279 logger.log(Level.WARNING, String.format(
"Error reading Chrome bookmark artifacts file '%s' (id=%d).",
280 bookmarkFile.getName(), bookmarkFile.getId()), ex);
281 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile",
282 this.getName(), bookmarkFile.getName()));
284 }
catch (IOException ex) {
285 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
286 temps, bookmarkFile.getName(), bookmarkFile.getId()), ex);
287 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile",
288 this.getName(), bookmarkFile.getName()));
292 logger.log(Level.INFO,
"{0}- Now getting Bookmarks from {1}",
new Object[]{moduleName, temps});
293 File dbFile =
new File(temps);
294 if (context.dataSourceIngestIsCancelled()) {
299 FileReader tempReader;
301 tempReader =
new FileReader(temps);
302 }
catch (FileNotFoundException ex) {
303 logger.log(Level.SEVERE,
"Error while trying to read into the Bookmarks for Chrome.", ex);
304 this.addErrorMessage(
305 NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzeFile", this.getName(),
306 bookmarkFile.getName()));
310 final JsonParser parser =
new JsonParser();
311 JsonElement jsonElement;
312 JsonObject jElement, jRoot, jBookmark;
313 JsonArray jBookmarkArray;
316 jsonElement = parser.parse(tempReader);
317 jElement = jsonElement.getAsJsonObject();
318 jRoot = jElement.get(
"roots").getAsJsonObject();
319 jBookmark = jRoot.get(
"bookmark_bar").getAsJsonObject();
320 jBookmarkArray = jBookmark.getAsJsonArray(
"children");
321 }
catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
322 logger.log(Level.WARNING,
"Error parsing Json from Chrome Bookmark.", ex);
323 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile3",
324 this.getName(), bookmarkFile.getName()));
328 for (JsonElement result : jBookmarkArray) {
329 JsonObject address = result.getAsJsonObject();
330 if (address == null) {
333 JsonElement urlEl = address.get(
"url");
336 url = urlEl.getAsString();
341 JsonElement nameEl = address.get(
"name");
342 if (nameEl != null) {
343 name = nameEl.getAsString();
348 JsonElement dateEl = address.get(
"date_added");
349 if (dateEl != null) {
350 date = dateEl.getAsLong();
352 date = Long.valueOf(0);
354 String domain = NetworkUtils.extractDomain(url);
356 BlackboardArtifact bbart = bookmarkFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
357 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
359 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
360 RecentActivityExtracterModuleFactory.getModuleName(), url));
361 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
362 RecentActivityExtracterModuleFactory.getModuleName(), name));
363 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
364 RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf(
"11644473600")));
365 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
366 RecentActivityExtracterModuleFactory.getModuleName(),
367 NbBundle.getMessage(this.getClass(),
"Chrome.moduleName")));
368 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
369 RecentActivityExtracterModuleFactory.getModuleName(), domain));
370 bbart.addAttributes(bbattributes);
373 this.indexArtifact(bbart);
374 bbartifacts.add(bbart);
375 }
catch (TskCoreException ex) {
376 logger.log(Level.SEVERE,
"Error while trying to insert Chrome bookmark artifact{0}", ex);
377 this.addErrorMessage(
378 NbBundle.getMessage(
this.getClass(),
"Chrome.getBookmark.errMsg.errAnalyzingFile4",
379 this.getName(), bookmarkFile.getName()));
385 IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
386 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
387 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bbartifacts));
393 private void getCookie() {
395 FileManager fileManager = currentCase.getServices().getFileManager();
396 List<AbstractFile> cookiesFiles;
398 cookiesFiles = fileManager.findFiles(dataSource,
"Cookies",
"Chrome");
399 }
catch (TskCoreException ex) {
400 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getCookie.errMsg.errGettingFiles");
401 logger.log(Level.SEVERE, msg, ex);
402 this.addErrorMessage(this.getName() +
": " + msg);
406 if (cookiesFiles.isEmpty()) {
407 logger.log(Level.INFO,
"Didn't find any Chrome cookies files.");
412 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
414 while (j < cookiesFiles.size()) {
415 AbstractFile cookiesFile = cookiesFiles.get(j++);
416 if (cookiesFile.getSize() == 0) {
419 String temps = RAImageIngestModule.getRATempPath(currentCase,
"chrome") + File.separator + cookiesFile.getName() + j +
".db";
421 ContentUtils.writeToFile(cookiesFile,
new File(temps), context::dataSourceIngestIsCancelled);
422 }
catch (ReadContentInputStreamException ex) {
423 logger.log(Level.WARNING, String.format(
"Error reading Chrome cookie artifacts file '%s' (id=%d).",
424 cookiesFile.getName(), cookiesFile.getId()), ex);
425 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getCookie.errMsg.errAnalyzeFile",
426 this.getName(), cookiesFile.getName()));
428 }
catch (IOException ex) {
429 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
430 temps, cookiesFile.getName(), cookiesFile.getId()), ex);
431 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getCookie.errMsg.errAnalyzeFile",
432 this.getName(), cookiesFile.getName()));
435 File dbFile =
new File(temps);
436 if (context.dataSourceIngestIsCancelled()) {
441 List<HashMap<String, Object>> tempList = this.dbConnect(temps, COOKIE_QUERY);
442 logger.log(Level.INFO,
"{0}- Now getting cookies from {1} with {2}artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
443 for (HashMap<String, Object> result : tempList) {
444 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
445 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
446 RecentActivityExtracterModuleFactory.getModuleName(),
447 ((result.get(
"host_key").toString() != null) ? result.get(
"host_key").toString() :
"")));
448 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
449 RecentActivityExtracterModuleFactory.getModuleName(),
450 (Long.valueOf(result.get(
"last_access_utc").toString()) / 1000000) - Long.valueOf(
"11644473600")));
452 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
453 RecentActivityExtracterModuleFactory.getModuleName(),
454 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
455 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
456 RecentActivityExtracterModuleFactory.getModuleName(),
457 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
458 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
459 RecentActivityExtracterModuleFactory.getModuleName(),
460 NbBundle.getMessage(this.getClass(),
"Chrome.moduleName")));
461 String domain = result.get(
"host_key").toString();
462 domain = domain.replaceFirst(
"^\\.+(?!$)",
"");
463 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
464 RecentActivityExtracterModuleFactory.getModuleName(), domain));
466 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
468 bbartifacts.add(bbart);
475 IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
476 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
477 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, bbartifacts));
483 private void getDownload() {
484 FileManager fileManager = currentCase.getServices().getFileManager();
485 List<AbstractFile> downloadFiles;
487 downloadFiles = fileManager.findFiles(dataSource,
"History",
"Chrome");
488 }
catch (TskCoreException ex) {
489 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getDownload.errMsg.errGettingFiles");
490 logger.log(Level.SEVERE, msg, ex);
491 this.addErrorMessage(this.getName() +
": " + msg);
495 if (downloadFiles.isEmpty()) {
496 logger.log(Level.INFO,
"Didn't find any Chrome download files.");
501 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
503 while (j < downloadFiles.size()) {
504 AbstractFile downloadFile = downloadFiles.get(j++);
505 if (downloadFile.getSize() == 0) {
508 String temps = RAImageIngestModule.getRATempPath(currentCase,
"chrome") + File.separator + downloadFile.getName() + j +
".db";
510 ContentUtils.writeToFile(downloadFile,
new File(temps), context::dataSourceIngestIsCancelled);
511 }
catch (ReadContentInputStreamException ex) {
512 logger.log(Level.WARNING, String.format(
"Error reading Chrome download artifacts file '%s' (id=%d).",
513 downloadFile.getName(), downloadFile.getId()), ex);
514 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
515 this.getName(), downloadFile.getName()));
517 }
catch (IOException ex) {
518 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
519 temps, downloadFile.getName(), downloadFile.getId()), ex);
520 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
521 this.getName(), downloadFile.getName()));
524 File dbFile =
new File(temps);
525 if (context.dataSourceIngestIsCancelled()) {
530 List<HashMap<String, Object>> tempList;
532 if (isChromePreVersion30(temps)) {
533 tempList = this.dbConnect(temps, DOWNLOAD_QUERY);
535 tempList = this.dbConnect(temps, DOWNLOAD_QUERY_V30);
538 logger.log(Level.INFO,
"{0}- Now getting downloads from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
539 for (HashMap<String, Object> result : tempList) {
540 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
541 String fullPath = result.get(
"full_path").toString();
542 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
543 RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
544 long pathID = Util.findID(dataSource, fullPath);
546 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
547 NbBundle.getMessage(
this.getClass(),
548 "Chrome.parentModuleName"), pathID));
550 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
551 RecentActivityExtracterModuleFactory.getModuleName(),
552 ((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"")));
554 Long time = (Long.valueOf(result.get(
"start_time").toString()) / 1000000) - Long.valueOf(
"11644473600");
558 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
559 RecentActivityExtracterModuleFactory.getModuleName(), time));
560 String domain = NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() :
"");
561 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
562 RecentActivityExtracterModuleFactory.getModuleName(), domain));
563 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
564 RecentActivityExtracterModuleFactory.getModuleName(),
565 NbBundle.getMessage(this.getClass(),
"Chrome.moduleName")));
567 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
569 bbartifacts.add(bbart);
574 for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(fullPath), FilenameUtils.getPath(fullPath))) {
575 BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
576 downloadSourceArt.addAttributes(createDownloadSourceAttributes(result.get(
"url").toString()));
578 bbartifacts.add(downloadSourceArt);
581 }
catch (TskCoreException ex) {
582 logger.log(Level.SEVERE, String.format(
"Error creating download source artifact for file '%s'", fullPath), ex);
589 IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
590 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
591 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
597 private void getLogins() {
599 FileManager fileManager = currentCase.getServices().getFileManager();
600 List<AbstractFile> loginDataFiles;
602 loginDataFiles = fileManager.findFiles(dataSource,
"Login Data",
"Chrome");
603 }
catch (TskCoreException ex) {
604 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getLogin.errMsg.errGettingFiles");
605 logger.log(Level.SEVERE, msg, ex);
606 this.addErrorMessage(this.getName() +
": " + msg);
610 if (loginDataFiles.isEmpty()) {
611 logger.log(Level.INFO,
"Didn't find any Chrome Login Data files.");
616 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
618 while (j < loginDataFiles.size()) {
619 AbstractFile loginDataFile = loginDataFiles.get(j++);
620 if (loginDataFile.getSize() == 0) {
623 String temps = RAImageIngestModule.getRATempPath(currentCase,
"chrome") + File.separator + loginDataFile.getName() + j +
".db";
625 ContentUtils.writeToFile(loginDataFile,
new File(temps), context::dataSourceIngestIsCancelled);
626 }
catch (ReadContentInputStreamException ex) {
627 logger.log(Level.WARNING, String.format(
"Error reading Chrome login artifacts file '%s' (id=%d).",
628 loginDataFile.getName(), loginDataFile.getId()), ex);
629 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
630 this.getName(), loginDataFile.getName()));
632 }
catch (IOException ex) {
633 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
634 temps, loginDataFile.getName(), loginDataFile.getId()), ex);
635 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
636 this.getName(), loginDataFile.getName()));
639 File dbFile =
new File(temps);
640 if (context.dataSourceIngestIsCancelled()) {
644 List<HashMap<String, Object>> tempList = this.dbConnect(temps, LOGIN_QUERY);
645 logger.log(Level.INFO,
"{0}- Now getting login information from {1} with {2}artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
646 for (HashMap<String, Object> result : tempList) {
647 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
649 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
650 RecentActivityExtracterModuleFactory.getModuleName(),
651 ((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() :
"")));
654 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
655 RecentActivityExtracterModuleFactory.getModuleName(),
656 (Long.valueOf(result.get(
"date_created").toString()) / 1000000) - Long.valueOf(
"11644473600")));
658 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
659 RecentActivityExtracterModuleFactory.getModuleName(),
660 (NetworkUtils.extractDomain((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() :
""))));
662 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
663 RecentActivityExtracterModuleFactory.getModuleName(),
664 ((result.get(
"username_value").toString() != null) ? result.get(
"username_value").toString().replaceAll(
"'",
"''") :
"")));
666 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
667 RecentActivityExtracterModuleFactory.getModuleName(),
668 ((result.get(
"signon_realm").toString() != null) ? result.get(
"signon_realm").toString() :
"")));
670 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes);
672 this.indexArtifact(bbart);
673 bbartifacts.add(bbart);
679 IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
680 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
681 BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT, bbartifacts));
689 private void getAutofill() {
691 FileManager fileManager = currentCase.getServices().getFileManager();
692 List<AbstractFile> webDataFiles;
694 webDataFiles = fileManager.findFiles(dataSource,
"Web Data",
"Chrome");
695 }
catch (TskCoreException ex) {
696 String msg = NbBundle.getMessage(this.getClass(),
"Chrome.getAutofills.errMsg.errGettingFiles");
697 logger.log(Level.SEVERE, msg, ex);
698 this.addErrorMessage(this.getName() +
": " + msg);
702 if (webDataFiles.isEmpty()) {
703 logger.log(Level.INFO,
"Didn't find any Chrome Web Data files.");
708 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
710 while (j < webDataFiles.size()) {
711 AbstractFile webDataFile = webDataFiles.get(j++);
712 if (webDataFile.getSize() == 0) {
715 String tempFilePath = RAImageIngestModule.getRATempPath(currentCase,
"chrome") + File.separator + webDataFile.getName() + j +
".db";
717 ContentUtils.writeToFile(webDataFile,
new File(tempFilePath), context::dataSourceIngestIsCancelled);
718 }
catch (ReadContentInputStreamException ex) {
719 logger.log(Level.WARNING, String.format(
"Error reading Chrome Autofill artifacts file '%s' (id=%d).",
720 webDataFile.getName(), webDataFile.getId()), ex);
721 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getAutofill.errMsg.errAnalyzingFiles",
722 this.getName(), webDataFile.getName()));
724 }
catch (IOException ex) {
725 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
726 tempFilePath, webDataFile.getName(), webDataFile.getId()), ex);
727 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Chrome.getLogin.errMsg.errAnalyzingFiles",
728 this.getName(), webDataFile.getName()));
731 File dbFile =
new File(tempFilePath);
732 if (context.dataSourceIngestIsCancelled()) {
738 boolean isSchemaV8X = Util.checkColumn(
"date_created",
"autofill", tempFilePath);
741 bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X));
743 bbartifacts.addAll(getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X));
747 IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
748 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
749 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, bbartifacts));
762 private Collection<BlackboardArtifact> getFormAutofillArtifacts (AbstractFile webDataFile, String dbFilePath ,
boolean isSchemaV8X ) {
764 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
767 String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
770 List<HashMap<String, Object>> autofills = this.dbConnect(dbFilePath, autoFillquery);
771 logger.log(Level.INFO,
"{0}- Now getting Autofill information from {1} with {2}artifacts identified.",
new Object[]{moduleName, dbFilePath, autofills.size()});
772 for (HashMap<String, Object> result : autofills) {
773 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
776 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
777 NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"),
778 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
780 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
781 RecentActivityExtracterModuleFactory.getModuleName(),
782 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
784 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
785 RecentActivityExtracterModuleFactory.getModuleName(),
786 (Integer.valueOf(result.get(
"count").toString()))));
788 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
789 RecentActivityExtracterModuleFactory.getModuleName(),
790 Long.valueOf(result.get(
"date_created").toString())));
794 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
795 RecentActivityExtracterModuleFactory.getModuleName(),
796 Long.valueOf(result.get(
"date_last_used").toString())));
800 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes);
802 this.indexArtifact(bbart);
803 bbartifacts.add(bbart);
820 private Collection<BlackboardArtifact> getFormAddressArtifacts (AbstractFile webDataFile, String dbFilePath ,
boolean isSchemaV8X ) {
821 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
823 String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
824 : WEBFORM_ADDRESS_QUERY;
827 List<HashMap<String, Object>> addresses = this.dbConnect(dbFilePath, webformAddressQuery);
828 logger.log(Level.INFO,
"{0}- Now getting Web form addresses from {1} with {2}artifacts identified.",
new Object[]{moduleName, dbFilePath, addresses.size()});
829 for (HashMap<String, Object> result : addresses) {
830 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
833 String first_name = result.get(
"first_name").toString() != null ? result.get(
"first_name").toString() :
"";
834 String middle_name = result.get(
"middle_name").toString() != null ? result.get(
"middle_name").toString() :
"";
835 String last_name = result.get(
"last_name").toString() != null ? result.get(
"last_name").toString() :
"";
838 String email_Addr = result.get(
"email").toString() != null ? result.get(
"email").toString() :
"";
839 String phone_number = result.get(
"number").toString() != null ? result.get(
"number").toString() :
"";
842 String city = result.get(
"city").toString() != null ? result.get(
"city").toString() :
"";
843 String state = result.get(
"state").toString() != null ? result.get(
"state").toString() :
"";
844 String zipcode = result.get(
"zipcode").toString() != null ? result.get(
"zipcode").toString() :
"";
845 String country_code = result.get(
"country_code").toString() != null ? result.get(
"country_code").toString() :
"";
848 String full_name =
"";
849 String street_address =
"";
850 long date_modified = 0;
855 full_name = result.get(
"full_name").toString() != null ? result.get(
"full_name").toString() :
"";
856 street_address = result.get(
"street_address").toString() != null ? result.get(
"street_address").toString() :
"";
857 date_modified = result.get(
"date_modified").toString() != null ? Long.valueOf(result.get(
"date_modified").toString()) : 0;
858 use_count = result.get(
"use_count").toString() != null ? Integer.valueOf(result.get(
"use_count").toString()) : 0;
859 use_date = result.get(
"use_date").toString() != null ? Long.valueOf(result.get(
"use_date").toString()) : 0;
861 String address_line_1 = result.get(
"address_line_1").toString() != null ? result.get(
"street_address").toString() :
"";
862 String address_line_2 = result.get(
"address_line_2").toString() != null ? result.get(
"address_line_2").toString() :
"";
863 street_address = String.join(
" ", address_line_1, address_line_2);
867 if (email_Addr != null && !email_Addr.isEmpty()) {
869 Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, email_Addr, NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"), webDataFile);
870 }
catch (NoCurrentCaseException | TskCoreException ex) {
871 logger.log(Level.SEVERE, String.format(
"Error creating email account instance for '%s' from Chrome WebData file '%s' .",
872 email_Addr, webDataFile.getName()), ex);
876 if (phone_number != null && !phone_number.isEmpty()) {
878 Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, phone_number, NbBundle.getMessage(
this.getClass(),
"Chrome.parentModuleName"), webDataFile);
879 }
catch (NoCurrentCaseException | TskCoreException ex) {
880 logger.log(Level.SEVERE, String.format(
"Error creating phone account instance for '%s' from Chrome WebData file '%s' .",
881 phone_number, webDataFile.getName()), ex);
886 if (full_name == null || full_name.isEmpty()) {
887 full_name = String.join(
" ", first_name, middle_name, last_name);
889 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME_PERSON,
890 RecentActivityExtracterModuleFactory.getModuleName(),
893 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
894 RecentActivityExtracterModuleFactory.getModuleName(),
897 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
898 RecentActivityExtracterModuleFactory.getModuleName(),
901 String locationAddress = String.join(
", ", street_address, city, state, zipcode, country_code);
902 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCATION,
903 RecentActivityExtracterModuleFactory.getModuleName(),
906 if (date_modified > 0) {
907 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
908 RecentActivityExtracterModuleFactory.getModuleName(),
913 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
914 RecentActivityExtracterModuleFactory.getModuleName(),
919 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
920 RecentActivityExtracterModuleFactory.getModuleName(),
925 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS, webDataFile, bbattributes);
927 this.indexArtifact(bbart);
928 bbartifacts.add(bbart);
936 private boolean isChromePreVersion30(String temps) {
937 String query =
"PRAGMA table_info(downloads)";
938 List<HashMap<String, Object>> columns = this.dbConnect(temps, query);
939 for (HashMap<String, Object> col : columns) {
940 if (col.get(
"name").equals(
"url")) {