From df1745dc37244e6226b80aa6420d3a7f6adac88b Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 13 Aug 2019 14:00:27 -0400 Subject: [PATCH 01/27] Added ExtractRecycyleBin module to RA --- .../recentactivity/Bundle.properties-MERGED | 9 +- .../recentactivity/ExtractRecycleBin.java | 279 ++++++++++++++++++ .../recentactivity/RAImageIngestModule.java | 2 + .../autopsy/recentactivity/Util.java | 18 ++ 4 files changed, 301 insertions(+), 7 deletions(-) create mode 100755 RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index 5e11018086..40771a0d41 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -2,14 +2,9 @@ cannotBuildXmlParser=Unable to build XML parser: cannotLoadSEUQA=Unable to load Search Engine URL Query Analyzer settings file, SEUQAMappings.xml: cannotParseXml=Unable to parse XML file: ChromeCacheExtractor.moduleName=ChromeCacheExtractor -# {0} - module name -# {1} - row number -# {2} - table length -# {3} - cache path ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries from {3} DataSourceUsage_AndroidMedia=Android Media Card DataSourceUsage_FlashDrive=Flash Drive -# {0} - OS name DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0}) DataSourceUsageAnalyzer.parentModuleName=Recent Activity Extract.indexError.message=Failed to index artifact for keyword search. @@ -51,6 +46,7 @@ ExtractOs.windowsVolume.label=OS Drive (Windows) ExtractOs.yellowDogLinuxOs.label=Linux (Yellow Dog) ExtractOs.yellowDogLinuxVolume.label=OS Drive (Linux Yellow Dog) ExtractOS_progressMessage=Checking for OS +ExtractRecycleBin_module_name=Recycle Bin ExtractSafari_Error_Getting_History=An error occurred while processing Safari history files. ExtractSafari_Error_Parsing_Bookmark=An error occured while processing Safari Bookmark files ExtractSafari_Error_Parsing_Cookies=An error occured while processing Safari Cookies files @@ -64,7 +60,7 @@ ExtractZone_progress_Msg=Extracting :Zone.Identifer files ExtractZone_Restricted=Restricted Sites Zone ExtractZone_Trusted=Trusted Sites Zone OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\n\The module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy. +OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\nThe module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy. OpenIDE-Module-Name=RecentActivity OpenIDE-Module-Short-Description=Recent Activity finder ingest module Chrome.moduleName=Chrome @@ -187,7 +183,6 @@ RecentDocumentsByLnk.parentModuleName.noSpace=RecentActivity RecentDocumentsByLnk.parentModuleName=Recent Activity RegRipperFullNotFound=Full version RegRipper executable not found. RegRipperNotFound=Autopsy RegRipper executable not found. -# {0} - file name SearchEngineURLQueryAnalyzer.init.exception.msg=Unable to find {0}. SearchEngineURLQueryAnalyzer.moduleName.text=Search Engine SearchEngineURLQueryAnalyzer.engineName.none=NONE diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java new file mode 100755 index 0000000000..10df98ae4c --- /dev/null +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -0,0 +1,279 @@ +/* + * + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * + * Copyright 2012 42six Solutions. + * Contact: aebadirad 42six com + * Project Contact/Architect: 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.recentactivity; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; +import org.sleuthkit.autopsy.ingest.IngestJobContext; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_DELETED; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskDataException; + +/** + * This module is based on the RecycleBin python module from Mark Mackinnon. + * + * @see + * Recycle_Bin.py + * + */ +final class ExtractRecycleBin extends Extract { + + private static final Logger logger = Logger.getLogger(ExtractRecycleBin.class.getName()); + + private static final String RECYCLE_BIN_ARTIFACT_NAME = "TSK_RECYCLE_BIN"; //NON-NLS + + private static final int V1_FILE_NAME_OFFSET = 24; + private static final int V2_FILE_NAME_OFFSET = 28; + + @Messages({ + "ExtractRecycleBin_module_name=Recycle Bin" + }) + ExtractRecycleBin() { + this.moduleName = Bundle.ExtractRecycleBin_module_name(); + } + + @Override + void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) { + FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), "recyclebin"); //NON-NLS + SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); + + // At this time it was decided tjat we would not include TSK_RECYCLE_BIN + // in the default list of BlackboardArtifact types. + try { + skCase.addBlackboardArtifactType(RECYCLE_BIN_ARTIFACT_NAME, "Recycle Bin"); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("%s may not have been created.", RECYCLE_BIN_ARTIFACT_NAME), ex); + } catch (TskDataException ex) { + logger.log(Level.WARNING, String.format("%s may have already been defined for this case", RECYCLE_BIN_ARTIFACT_NAME), ex); + } + + BlackboardArtifact.Type recycleBinArtifactType; + + try { + recycleBinArtifactType = skCase.getArtifactType(RECYCLE_BIN_ARTIFACT_NAME); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to retrive custom artifact type %s", RECYCLE_BIN_ARTIFACT_NAME), ex); // NON-NLS + // If this doesn't work bail. + return; + } + + List iFiles; + + try { + iFiles = fileManager.findFiles(dataSource, "$I%"); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Unable to find recycle bin I files.", ex); //NON-NLS + return; // No need to continue + } + + for (AbstractFile iFile : iFiles) { + + if (context.dataSourceIngestIsCancelled()) { + return; + } + + String tempFilePath = tempDirPath + File.separator + iFile.getName(); + + try { + try { + ContentUtils.writeToFile(iFile, new File(tempFilePath)); + } catch (IOException ex) { + logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", iFile.getName(), tempFilePath), ex); //NON-NLS + // if we cannot make a copy of the $I file for later processing + // move onto the next file + continue; + } + + RecycledFileMetaData metaData; + try { + metaData = parseIFile(tempFilePath); + } catch (IOException ex) { + logger.log(Level.WARNING, String.format("Unable to parse iFile %s", iFile.getName()), ex); //NON-NLS + // Unable to parse the $I file move onto the next file + continue; + } + + String rFileName = iFile.getName().replace("$I", "$R"); //NON-NLS + List rFiles; + + try { + rFiles = fileManager.findFiles(dataSource, rFileName, iFile.getParentPath()); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to find R file (%s) for I file (%s)", rFileName, iFile.getName()), ex); //NON-NLS + // If there are no $R files go on to the next $I file + continue; + } + + for (AbstractFile rFile : rFiles) { + if (context.dataSourceIngestIsCancelled()) { + return; + } + + if (iFile.getParentPath().equals(rFile.getParentPath())) { + try { + BlackboardArtifact bba = rFile.newArtifact(recycleBinArtifactType.getTypeID()); + bba.addAttribute(new BlackboardAttribute(TSK_PATH, getName(), metaData.getFileName())); + bba.addAttribute(new BlackboardAttribute(TSK_DATETIME_DELETED, getName(), metaData.getDeletedTimeStamp())); + + postArtifact(bba); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to add attributes to artifact %s", rFile.getName()), ex); //NON-NLS + } + } + } + } finally { + (new File(tempFilePath)).delete(); + } + } + + (new File(tempDirPath)).delete(); + } + + /** + * Parse the $I file. + * + * File format prior to Windows 10: + * + * + * + * + * + * + *
OffsetSizeDescription
08Header
88File Size
168Deleted Timestamp
24520File Name
+ * + * File format Windows 10+ + * + * + * + * + * + * + * + *
OffsetSizeDescription
08Header
88File Size
168Deleted TimeStamp
244File Name Length
28varFile Name
+ * + * For versions of Windows prior to 10, header = 0x01. Windows 10+ header == + * 0x02 + * + * @param iFilePath + * + * @throws FileNotFoundException + * @throws IOException + */ + RecycledFileMetaData parseIFile(String iFilePath) throws FileNotFoundException, IOException { + byte[] allBytes = Files.readAllBytes(Paths.get(iFilePath)); + + ByteBuffer byteBuffer = ByteBuffer.wrap(allBytes); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + + long version = byteBuffer.getLong(); + long fileSize = byteBuffer.getLong(); + long timestamp = byteBuffer.getLong(); + + // Convert from windows FILETIME to Unix Epoch seconds + timestamp = Util.filetimeToMillis(timestamp) / 1000; + + byte[] stringBytes; + + if (version == 1) { + stringBytes = Arrays.copyOfRange(allBytes, V1_FILE_NAME_OFFSET, allBytes.length); + } else { + int fileNameLength = byteBuffer.getInt(); + stringBytes = Arrays.copyOfRange(allBytes, V2_FILE_NAME_OFFSET, fileNameLength); + } + + String fileName = new String(stringBytes, "UTF-16LE"); //NON-NLS + + return new RecycledFileMetaData(fileSize, timestamp, fileName); + } + + /** + * Stores the data from the $I files. + */ + final class RecycledFileMetaData { + + private final long fileSize; + private final long deletedTimeStamp; + private final String fileName; + + /** + * Constructs a new instance. + * + * @param fileSize Size of the deleted file. + * @param deletedTimeStamp Time the file was deleted. + * @param fileName Name of the deleted file. + */ + RecycledFileMetaData(Long fileSize, long deletedTimeStamp, String fileName) { + this.fileSize = fileSize; + this.deletedTimeStamp = deletedTimeStamp; + this.fileName = fileName; + } + + /** + * Returns the size of the recycled file. + * + * @return Size of deleted file + */ + long getFileSize() { + return fileSize; + } + + /** + * Returns the time the file was deleted. + * + * @return deleted time in epoch seconds. + */ + long getDeletedTimeStamp() { + return deletedTimeStamp; + } + + /** + * Returns the name of the deleted file. + * + * @return String name of the deleted file + */ + String getFileName() { + return fileName; + } + } +} diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java index db815e9274..a52b5b65e1 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java @@ -77,6 +77,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule { Extract dataSourceAnalyzer = new DataSourceUsageAnalyzer(); Extract safari = new ExtractSafari(); Extract zoneInfo = new ExtractZoneIdentifier(); + Extract recycleBin = new ExtractRecycleBin(); extractors.add(chrome); extractors.add(firefox); @@ -84,6 +85,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule { extractors.add(edge); extractors.add(safari); extractors.add(recentDocuments); + extractors.add(recycleBin); extractors.add(SEUQA); // this needs to run after the web browser modules extractors.add(registry); // this should run after quicker modules like the browser modules and needs to run before the DataSourceUsageAnalyzer extractors.add(osExtract); // this needs to run before the DataSourceUsageAnalyzer diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java index a6c6416416..ff95c60ca8 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java @@ -51,6 +51,12 @@ import org.sleuthkit.datamodel.TskCoreException; class Util { private static Logger logger = Logger.getLogger(Util.class.getName()); + + /** Difference between Filetime epoch and Unix epoch (in ms). */ + private static final long FILETIME_EPOCH_DIFF = 11644473600000L; + + /** One millisecond expressed in units of 100s of nanoseconds. */ + private static final long FILETIME_ONE_MILLISECOND = 10 * 1000; private Util() { } @@ -176,4 +182,16 @@ class Util { } return results; } + + /** + * Converts a windows FILETIME to java-unix epoch milliseconds + * + * @param filetime 100 nanosecond intervals from jan 1, 1601 + * + * @return java-unix epoch milliseconds + */ + static long filetimeToMillis(final long filetime) { + return (filetime / FILETIME_ONE_MILLISECOND) - FILETIME_EPOCH_DIFF; + } + } From fa9db11e0c248fc8c940afa6c936e47bcc241d29 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 13 Aug 2019 14:26:06 -0400 Subject: [PATCH 02/27] Fixed typo --- .../org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 10df98ae4c..fe32281fff 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -50,7 +50,7 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; /** - * This module is based on the RecycleBin python module from Mark Mackinnon. + * This module is based on the RecycleBin python module from Mark McKinnon. * * @see * Recycle_Bin.py From ec4803309523cda4cd30dbf5eb925bfd10f3c485 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 14 Aug 2019 10:56:11 -0400 Subject: [PATCH 03/27] Added support for usernames --- .../recentactivity/ExtractRecycleBin.java | 65 ++++++++++++++++--- .../recentactivity/RAImageIngestModule.java | 2 +- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index fe32281fff..4cbcad3b62 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -30,7 +30,9 @@ import java.nio.ByteOrder; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; @@ -41,11 +43,13 @@ import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT; import org.sleuthkit.datamodel.BlackboardAttribute; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_DELETED; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; @@ -76,27 +80,36 @@ final class ExtractRecycleBin extends Extract { void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) { FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), "recyclebin"); //NON-NLS - SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); - - // At this time it was decided tjat we would not include TSK_RECYCLE_BIN + + // At this time it was decided that we would not include TSK_RECYCLE_BIN // in the default list of BlackboardArtifact types. try { - skCase.addBlackboardArtifactType(RECYCLE_BIN_ARTIFACT_NAME, "Recycle Bin"); //NON-NLS + tskCase.addBlackboardArtifactType(RECYCLE_BIN_ARTIFACT_NAME, "Recycle Bin"); //NON-NLS } catch (TskCoreException ex) { logger.log(Level.WARNING, String.format("%s may not have been created.", RECYCLE_BIN_ARTIFACT_NAME), ex); } catch (TskDataException ex) { - logger.log(Level.WARNING, String.format("%s may have already been defined for this case", RECYCLE_BIN_ARTIFACT_NAME), ex); + logger.log(Level.INFO, String.format("%s may have already been defined for this case", RECYCLE_BIN_ARTIFACT_NAME)); } BlackboardArtifact.Type recycleBinArtifactType; try { - recycleBinArtifactType = skCase.getArtifactType(RECYCLE_BIN_ARTIFACT_NAME); + recycleBinArtifactType = tskCase.getArtifactType(RECYCLE_BIN_ARTIFACT_NAME); } catch (TskCoreException ex) { logger.log(Level.WARNING, String.format("Unable to retrive custom artifact type %s", RECYCLE_BIN_ARTIFACT_NAME), ex); // NON-NLS // If this doesn't work bail. return; } + Map userNameMap; + + try { + userNameMap = makeUserNameMap(dataSource); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Unable to create OS Account user name map", ex); + // This is not the end of the world we will just continue without + // user names + userNameMap = new HashMap<>(); + } List iFiles; @@ -135,6 +148,9 @@ final class ExtractRecycleBin extends Extract { } String rFileName = iFile.getName().replace("$I", "$R"); //NON-NLS + String userID = getUserIDFromPath(iFile.getParentPath()); + String userName = userNameMap.get(userID); + List rFiles; try { @@ -155,6 +171,7 @@ final class ExtractRecycleBin extends Extract { BlackboardArtifact bba = rFile.newArtifact(recycleBinArtifactType.getTypeID()); bba.addAttribute(new BlackboardAttribute(TSK_PATH, getName(), metaData.getFileName())); bba.addAttribute(new BlackboardAttribute(TSK_DATETIME_DELETED, getName(), metaData.getDeletedTimeStamp())); + bba.addAttribute(new BlackboardAttribute(TSK_USER_NAME, getName(), userName != null ? userName : "")); postArtifact(bba); } catch (TskCoreException ex) { @@ -218,14 +235,44 @@ final class ExtractRecycleBin extends Extract { if (version == 1) { stringBytes = Arrays.copyOfRange(allBytes, V1_FILE_NAME_OFFSET, allBytes.length); } else { - int fileNameLength = byteBuffer.getInt(); - stringBytes = Arrays.copyOfRange(allBytes, V2_FILE_NAME_OFFSET, fileNameLength); + int fileNameLength = byteBuffer.getInt() * 2; //Twice the bytes for unicode + stringBytes = Arrays.copyOfRange(allBytes, V2_FILE_NAME_OFFSET, V2_FILE_NAME_OFFSET + fileNameLength); } String fileName = new String(stringBytes, "UTF-16LE"); //NON-NLS return new RecycledFileMetaData(fileSize, timestamp, fileName); } + + + private Map makeUserNameMap(Content dataSource) throws TskCoreException{ + Map userNameMap = new HashMap<>(); + + List accounts = blackboard.getArtifacts(TSK_OS_ACCOUNT.getTypeID(), dataSource.getId()); + + for (BlackboardArtifact account: accounts) { + BlackboardAttribute nameAttribute = getAttributeForArtifact(account, TSK_USER_NAME); + BlackboardAttribute idAttribute = getAttributeForArtifact(account, TSK_USER_ID); + + String userName = nameAttribute != null ? nameAttribute.getDisplayString() : ""; + String userID = idAttribute != null ? idAttribute.getDisplayString() : ""; + + if (!userID.isEmpty()) { + userNameMap.put(userID, userName); + } + } + + return userNameMap; + } + + private String getUserIDFromPath(String iFileParentPath) { + int index = iFileParentPath.indexOf("-") - 1; + return (iFileParentPath.substring(index)).replace("/", ""); + } + + private BlackboardAttribute getAttributeForArtifact(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException{ + return artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(type.getTypeID()))); + } /** * Stores the data from the $I files. diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java index a52b5b65e1..444a6d638d 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java @@ -85,12 +85,12 @@ public final class RAImageIngestModule implements DataSourceIngestModule { extractors.add(edge); extractors.add(safari); extractors.add(recentDocuments); - extractors.add(recycleBin); extractors.add(SEUQA); // this needs to run after the web browser modules extractors.add(registry); // this should run after quicker modules like the browser modules and needs to run before the DataSourceUsageAnalyzer extractors.add(osExtract); // this needs to run before the DataSourceUsageAnalyzer extractors.add(dataSourceAnalyzer); //this needs to run after ExtractRegistry and ExtractOs extractors.add(zoneInfo); // this needs to run after the web browser modules + extractors.add(recycleBin); // this needs to run after ExtractRegistry and ExtractOS browserExtractors.add(chrome); browserExtractors.add(firefox); From e1599ecb9a6d5bc48359c1d37fa22c7de47458d2 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 15 Aug 2019 10:03:40 -0400 Subject: [PATCH 04/27] Refactored to hopefully make codacy happy --- .../recentactivity/ExtractRecycleBin.java | 211 ++++++++++++------ 1 file changed, 143 insertions(+), 68 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 4cbcad3b62..08641a164e 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -78,17 +78,12 @@ final class ExtractRecycleBin extends Extract { @Override void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) { - FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); - String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), "recyclebin"); //NON-NLS - // At this time it was decided that we would not include TSK_RECYCLE_BIN // in the default list of BlackboardArtifact types. try { - tskCase.addBlackboardArtifactType(RECYCLE_BIN_ARTIFACT_NAME, "Recycle Bin"); //NON-NLS + createRecycleBinArtifactType(); } catch (TskCoreException ex) { logger.log(Level.WARNING, String.format("%s may not have been created.", RECYCLE_BIN_ARTIFACT_NAME), ex); - } catch (TskDataException ex) { - logger.log(Level.INFO, String.format("%s may have already been defined for this case", RECYCLE_BIN_ARTIFACT_NAME)); } BlackboardArtifact.Type recycleBinArtifactType; @@ -110,7 +105,8 @@ final class ExtractRecycleBin extends Extract { // user names userNameMap = new HashMap<>(); } - + + FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); List iFiles; try { @@ -119,72 +115,90 @@ final class ExtractRecycleBin extends Extract { logger.log(Level.WARNING, "Unable to find recycle bin I files.", ex); //NON-NLS return; // No need to continue } + + String tempRARecycleBinPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), "recyclebin"); //NON-NLS for (AbstractFile iFile : iFiles) { if (context.dataSourceIngestIsCancelled()) { return; } - - String tempFilePath = tempDirPath + File.separator + iFile.getName(); - - try { - try { - ContentUtils.writeToFile(iFile, new File(tempFilePath)); - } catch (IOException ex) { - logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", iFile.getName(), tempFilePath), ex); //NON-NLS - // if we cannot make a copy of the $I file for later processing - // move onto the next file - continue; - } - - RecycledFileMetaData metaData; - try { - metaData = parseIFile(tempFilePath); - } catch (IOException ex) { - logger.log(Level.WARNING, String.format("Unable to parse iFile %s", iFile.getName()), ex); //NON-NLS - // Unable to parse the $I file move onto the next file - continue; - } - - String rFileName = iFile.getName().replace("$I", "$R"); //NON-NLS - String userID = getUserIDFromPath(iFile.getParentPath()); - String userName = userNameMap.get(userID); - - List rFiles; - - try { - rFiles = fileManager.findFiles(dataSource, rFileName, iFile.getParentPath()); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, String.format("Unable to find R file (%s) for I file (%s)", rFileName, iFile.getName()), ex); //NON-NLS - // If there are no $R files go on to the next $I file - continue; - } - - for (AbstractFile rFile : rFiles) { - if (context.dataSourceIngestIsCancelled()) { - return; - } - - if (iFile.getParentPath().equals(rFile.getParentPath())) { - try { - BlackboardArtifact bba = rFile.newArtifact(recycleBinArtifactType.getTypeID()); - bba.addAttribute(new BlackboardAttribute(TSK_PATH, getName(), metaData.getFileName())); - bba.addAttribute(new BlackboardAttribute(TSK_DATETIME_DELETED, getName(), metaData.getDeletedTimeStamp())); - bba.addAttribute(new BlackboardAttribute(TSK_USER_NAME, getName(), userName != null ? userName : "")); - - postArtifact(bba); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, String.format("Unable to add attributes to artifact %s", rFile.getName()), ex); //NON-NLS - } - } - } - } finally { - (new File(tempFilePath)).delete(); - } + + processIFiles(dataSource, context, recycleBinArtifactType, iFile, userNameMap, tempRARecycleBinPath); } - (new File(tempDirPath)).delete(); + (new File(tempRARecycleBinPath)).delete(); + } + + /** + * Process each individual iFile. + * + * @param dataSource + * @param context + * @param recycleBinArtifactType Module created artifact type + * @param iFile The AbstractFile to process + * @param userNameMap Map of user ids to names + * @param tempRARecycleBinPath Temp directory path + */ + private void processIFiles(Content dataSource, IngestJobContext context, BlackboardArtifact.Type recycleBinArtifactType, AbstractFile iFile, Map userNameMap, String tempRARecycleBinPath) { + String tempFilePath = tempRARecycleBinPath + File.separator + iFile.getName(); + FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + try { + try { + ContentUtils.writeToFile(iFile, new File(tempFilePath)); + } catch (IOException ex) { + logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", iFile.getName(), tempFilePath), ex); //NON-NLS + // if we cannot make a copy of the $I file for later processing + // move onto the next file + return; + } + + RecycledFileMetaData metaData; + try { + metaData = parseIFile(tempFilePath); + } catch (IOException ex) { + logger.log(Level.WARNING, String.format("Unable to parse iFile %s", iFile.getName()), ex); //NON-NLS + // Unable to parse the $I file move onto the next file + return; + } + + String rFileName = iFile.getName().replace("$I", "$R"); //NON-NLS + String userID = getUserIDFromPath(iFile.getParentPath()); + String userName = ""; + if (!userID.isEmpty()) { + userName = userNameMap.get(userID); + } else { + // If the iFile doesn't have a user ID in its parent + // directory structure then it is not from the recyle bin + return; + } + + List rFiles; + + try { + rFiles = fileManager.findFiles(dataSource, rFileName, iFile.getParentPath()); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to find R file (%s) for I file (%s)", rFileName, iFile.getName()), ex); //NON-NLS + // If there are no $R files go on to the next $I file + return; + } + + for (AbstractFile rFile : rFiles) { + if (context.dataSourceIngestIsCancelled()) { + return; + } + + if (iFile.getParentPath().equals(rFile.getParentPath())) { + try { + postArtifact(createArtifact(rFile, recycleBinArtifactType, metaData.getFileName(), userName, metaData.getDeletedTimeStamp())); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to add attributes to artifact %s", rFile.getName()), ex); //NON-NLS + } + } + } + } finally { + (new File(tempFilePath)).delete(); + } } /** @@ -217,7 +231,7 @@ final class ExtractRecycleBin extends Extract { * @throws FileNotFoundException * @throws IOException */ - RecycledFileMetaData parseIFile(String iFilePath) throws FileNotFoundException, IOException { + private RecycledFileMetaData parseIFile(String iFilePath) throws FileNotFoundException, IOException { byte[] allBytes = Files.readAllBytes(Paths.get(iFilePath)); ByteBuffer byteBuffer = ByteBuffer.wrap(allBytes); @@ -244,7 +258,15 @@ final class ExtractRecycleBin extends Extract { return new RecycledFileMetaData(fileSize, timestamp, fileName); } - + /** + * Create a map of userids to usernames from the OS Accounts. + * + * @param dataSource + * + * @return A Map of userIDs and userNames + * + * @throws TskCoreException + */ private Map makeUserNameMap(Content dataSource) throws TskCoreException{ Map userNameMap = new HashMap<>(); @@ -265,14 +287,67 @@ final class ExtractRecycleBin extends Extract { return userNameMap; } + /** + * Helper functions to get the user ID from the iFile parent path. User ids + * will be of the form S-. + * + * @param iFileParentPath String parent path of the iFile + * + * @return String user id + */ private String getUserIDFromPath(String iFileParentPath) { int index = iFileParentPath.indexOf("-") - 1; - return (iFileParentPath.substring(index)).replace("/", ""); + if (index >= 0) { + return (iFileParentPath.substring(index)).replace("/", ""); + } else { + return ""; + } } + /** + * Gets the attribute for the given type from the given artifact. + * + * @param artifact BlackboardArtifact to get the attribute from + * @param type The BlackboardAttribute Type to get + * + * @return BlackboardAttribute for given artifact and type + * + * @throws TskCoreException + */ private BlackboardAttribute getAttributeForArtifact(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException{ return artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(type.getTypeID()))); } + + private void createRecycleBinArtifactType() throws TskCoreException { + try { + tskCase.addBlackboardArtifactType(RECYCLE_BIN_ARTIFACT_NAME, "Recycle Bin"); //NON-NLS + } catch (TskDataException ex) { + logger.log(Level.INFO, String.format("%s may have already been defined for this case", RECYCLE_BIN_ARTIFACT_NAME)); + } + + } + + /** + * Create the new artifact for the give rFile + * + * @param rFile AbstractFile to create the artifact for + * @param type Type of artifact to create + * @param fileName The original path of the deleted file + * @param userName The name of the user that deleted the file + * @param dateTime The time in epoch seconds that the file was deleted + * + * @return Newly created artifact + * + * @throws TskCoreException + */ + private BlackboardArtifact createArtifact(AbstractFile rFile, BlackboardArtifact.Type type, String fileName, String userName, long dateTime) throws TskCoreException{ + BlackboardArtifact bba = rFile.newArtifact(type.getTypeID()); + bba.addAttribute(new BlackboardAttribute(TSK_PATH, getName(), fileName)); + bba.addAttribute(new BlackboardAttribute(TSK_DATETIME_DELETED, getName(), dateTime)); + bba.addAttribute(new BlackboardAttribute(TSK_USER_NAME, getName(), userName == null || userName.isEmpty() ? "" : userName)); + + return bba; + } /** * Stores the data from the $I files. From 5721f3c7d4a150c1b869bff679573eab5f35f5c6 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 15 Aug 2019 10:27:09 -0400 Subject: [PATCH 05/27] merged in changes from other branch --- .../recentactivity/ExtractRecycleBin.java | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 08641a164e..3a34fd82bb 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -29,6 +29,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -107,6 +108,15 @@ final class ExtractRecycleBin extends Extract { } FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + + Map> rFileMap; + try { + rFileMap = makeRFileMap(dataSource); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to create $R file map for dataSource: %s", dataSource.getName()), ex); + return; // No $R files, no need to continue; + } + List iFiles; try { @@ -124,7 +134,7 @@ final class ExtractRecycleBin extends Extract { return; } - processIFiles(dataSource, context, recycleBinArtifactType, iFile, userNameMap, tempRARecycleBinPath); + processIFiles(context, recycleBinArtifactType, iFile, userNameMap, rFileMap, tempRARecycleBinPath); } (new File(tempRARecycleBinPath)).delete(); @@ -140,9 +150,8 @@ final class ExtractRecycleBin extends Extract { * @param userNameMap Map of user ids to names * @param tempRARecycleBinPath Temp directory path */ - private void processIFiles(Content dataSource, IngestJobContext context, BlackboardArtifact.Type recycleBinArtifactType, AbstractFile iFile, Map userNameMap, String tempRARecycleBinPath) { + private void processIFiles(IngestJobContext context, BlackboardArtifact.Type recycleBinArtifactType, AbstractFile iFile, Map userNameMap, Map> rFileMap, String tempRARecycleBinPath) { String tempFilePath = tempRARecycleBinPath + File.separator + iFile.getName(); - FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); try { try { ContentUtils.writeToFile(iFile, new File(tempFilePath)); @@ -173,15 +182,7 @@ final class ExtractRecycleBin extends Extract { return; } - List rFiles; - - try { - rFiles = fileManager.findFiles(dataSource, rFileName, iFile.getParentPath()); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, String.format("Unable to find R file (%s) for I file (%s)", rFileName, iFile.getName()), ex); //NON-NLS - // If there are no $R files go on to the next $I file - return; - } + List rFiles = rFileMap.get(rFileName); for (AbstractFile rFile : rFiles) { if (context.dataSourceIngestIsCancelled()) { @@ -287,6 +288,34 @@ final class ExtractRecycleBin extends Extract { return userNameMap; } + /** + * Get a list of files that start with $R and create a map of the file to + * their name. + * + * @param dataSource + * @return File map + * @throws TskCoreException + */ + private Map> makeRFileMap(Content dataSource) throws TskCoreException{ + FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + List rFiles = fileManager.findFiles(dataSource, "$R%"); + Map> fileMap = new HashMap<>(); + + for (AbstractFile rFile: rFiles) { + String fileName = rFile.getName(); + List fileList = fileMap.get(fileName); + + if(fileList == null) { + fileList = new ArrayList<>(); + fileMap.put(fileName, fileList); + } + + fileList.add(rFile); + } + + return fileMap; + } + /** * Helper functions to get the user ID from the iFile parent path. User ids * will be of the form S-. From 0aeabbb0cd54c1c66c2c90d9fab0dcc1663bfba6 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 15 Aug 2019 10:30:39 -0400 Subject: [PATCH 06/27] Fixed codacy issues --- .../sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 08641a164e..cfa6aa997d 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -162,7 +162,6 @@ final class ExtractRecycleBin extends Extract { return; } - String rFileName = iFile.getName().replace("$I", "$R"); //NON-NLS String userID = getUserIDFromPath(iFile.getParentPath()); String userName = ""; if (!userID.isEmpty()) { @@ -174,6 +173,8 @@ final class ExtractRecycleBin extends Extract { } List rFiles; + + String rFileName = iFile.getName().replace("$I", "$R"); //NON-NLS try { rFiles = fileManager.findFiles(dataSource, rFileName, iFile.getParentPath()); @@ -296,7 +297,7 @@ final class ExtractRecycleBin extends Extract { * @return String user id */ private String getUserIDFromPath(String iFileParentPath) { - int index = iFileParentPath.indexOf("-") - 1; + int index = iFileParentPath.indexOf('-') - 1; if (index >= 0) { return (iFileParentPath.substring(index)).replace("/", ""); } else { From 91b08e400199211449e8758e246afbe80aac18fc Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 22 Aug 2019 09:43:21 -0400 Subject: [PATCH 07/27] Inital pass of creating deleted files for recycle files. --- .../recentactivity/ExtractRecycleBin.java | 126 +++++++++++++++++- 1 file changed, 121 insertions(+), 5 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 926f8b2d9f..4c9f4b9618 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -35,6 +36,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; +import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -51,7 +53,10 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PAT import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.FsContent; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskDataException; /** @@ -134,7 +139,7 @@ final class ExtractRecycleBin extends Extract { return; } - processIFiles(context, recycleBinArtifactType, iFile, userNameMap, rFileMap, tempRARecycleBinPath); + processIFiles(dataSource, context, recycleBinArtifactType, iFile, userNameMap, rFileMap, tempRARecycleBinPath); } (new File(tempRARecycleBinPath)).delete(); @@ -150,7 +155,7 @@ final class ExtractRecycleBin extends Extract { * @param userNameMap Map of user ids to names * @param tempRARecycleBinPath Temp directory path */ - private void processIFiles(IngestJobContext context, BlackboardArtifact.Type recycleBinArtifactType, AbstractFile iFile, Map userNameMap, Map> rFileMap, String tempRARecycleBinPath) { + private void processIFiles(Content dataSource, IngestJobContext context, BlackboardArtifact.Type recycleBinArtifactType, AbstractFile iFile, Map userNameMap, Map> rFileMap, String tempRARecycleBinPath) { String tempFilePath = tempRARecycleBinPath + File.separator + iFile.getName(); try { try { @@ -188,7 +193,7 @@ final class ExtractRecycleBin extends Extract { if(rFiles == null) { return; } - + SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); for (AbstractFile rFile : rFiles) { if (context.dataSourceIngestIsCancelled()) { return; @@ -198,6 +203,16 @@ final class ExtractRecycleBin extends Extract { && iFile.getMetaFlagsAsString().equals(rFile.getMetaFlagsAsString())) { try { postArtifact(createArtifact(rFile, recycleBinArtifactType, metaData.getFileName(), userName, metaData.getDeletedTimeStamp())); + if(rFile instanceof FsContent) { + if(rFile.isDir()) { + AbstractFile directory = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent)rFile, metaData.getFileName()); + popuplateDirectory(Case.getCurrentCase().getSleuthkitCase(), directory, rFile.getChildren(), metaData.getFileName(), metaData.getDeletedTimeStamp()); + + } else { + AbstractFile folder = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent)rFile.getParent(), Paths.get(metaData.getFileName()).getParent().toString()); + addFileToDirectory(skCase, rFile, folder, Paths.get(metaData.getFileName()).getFileName().toString(), metaData.getDeletedTimeStamp()); + } + } } catch (TskCoreException ex) { logger.log(Level.WARNING, String.format("Unable to add attributes to artifact %s", rFile.getName()), ex); //NON-NLS } @@ -207,6 +222,34 @@ final class ExtractRecycleBin extends Extract { (new File(tempFilePath)).delete(); } } + + /** + * + * @param skCase + * @param folder + * @param children + * @param parentPath + * @param deletedTimeStamp + * @throws TskCoreException + */ + private void popuplateDirectory(SleuthkitCase skCase, AbstractFile folder, List recycledChildren, String parentPath, long deletedTimeStamp) throws TskCoreException { + if (recycledChildren == null) { + return; + } + + for(Content child: recycledChildren) { + if(child instanceof AbstractFile) { + AbstractFile fileChild = (AbstractFile) child; + if(fileChild.isFile()) { + addFileToDirectory(skCase, fileChild, folder, fileChild.getName(), deletedTimeStamp); + } else if(fileChild.isDir()) { + String newPath = parentPath + File.separator + fileChild.getName(); + AbstractFile childFolder = getOrMakeFolder(skCase, (FsContent)fileChild, parentPath); + popuplateDirectory(skCase, childFolder, fileChild.getChildren(), newPath, deletedTimeStamp); + } + } + } + } /** * Parse the $I file. @@ -383,7 +426,80 @@ final class ExtractRecycleBin extends Extract { return bba; } - + + private AbstractFile getOrMakeFolder(SleuthkitCase skCase, FsContent dataSource, String path) throws TskCoreException { + + String parentPath = getParentPath(path); + String folderName = getFileName(path); + + List files = null; + if(parentPath != null) { + if(!parentPath.equals("/")) { + parentPath = parentPath + "/"; + } + files = skCase.findAllFilesWhere(String.format("fs_obj_id=%s AND parent_path='%s' AND name='%s'", dataSource.getFileSystemId(), parentPath, folderName != null ? folderName : "")); + } else { + files = skCase.findAllFilesWhere(String.format("fs_obj_id=%s AND parent_path='/' AND name=''", dataSource.getFileSystemId())); + } + + if(files == null || files.isEmpty()) { + AbstractFile parent = getOrMakeFolder(skCase, dataSource, parentPath); + return skCase.addVirtualDirectory(parent.getId(), folderName); + + } else { + return files.get(0); + } + } + + private void addFileToDirectory (SleuthkitCase skCase, AbstractFile rFile, Content parentDir, String fileName, long deletedTime) throws TskCoreException { + FsContent fsContent = (FsContent)rFile; + + skCase.addFileSystemFile(fsContent.getFileSystemId(), + rFile.getDataSourceObjectId(), + rFile.getAttrType(), + rFile.getAttributeId(), + fileName, + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC, + rFile.getSize(), + 0,0,0,deletedTime, + rFile.getMetaAddr(), + (int)rFile.getMetaSeq(), + true, parentDir); + } + + /** + * + * @param path + * @return + */ + String normalizeFilePath(String pathString) { + if (pathString == null || pathString.isEmpty()) { + return null; + } + + Path path = Paths.get(pathString); + Path rootPath = path.getRoot(); + + String rootless = pathString.replace(rootPath.toString().replace("\\", ""), ""); + return rootless.replace("\\", "/"); + } + + String getFileName(String filePath) { + Path fileNamePath = Paths.get(filePath).getFileName(); + if(fileNamePath != null) { + return fileNamePath.toString(); + } + return filePath; + } + + String getParentPath(String path) { + Path parentPath = Paths.get(path).getParent(); + if(parentPath != null) { + return normalizeFilePath(parentPath.toString()); + } + return null; + } + /** * Stores the data from the $I files. */ @@ -430,7 +546,7 @@ final class ExtractRecycleBin extends Extract { * @return String name of the deleted file */ String getFileName() { - return fileName; + return fileName.trim(); } } } From 41c71a0b03273ce9d34fea7680a8a291a831674b Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 22 Aug 2019 12:02:26 -0400 Subject: [PATCH 08/27] updated after review comments --- .../recentactivity/ExtractRecycleBin.java | 329 ++++++++++-------- 1 file changed, 192 insertions(+), 137 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 4c9f4b9618..8beaa0bd87 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -36,7 +36,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -87,7 +86,7 @@ final class ExtractRecycleBin extends Extract { // At this time it was decided that we would not include TSK_RECYCLE_BIN // in the default list of BlackboardArtifact types. try { - createRecycleBinArtifactType(); + createRecycleBinArtifactType(); } catch (TskCoreException ex) { logger.log(Level.WARNING, String.format("%s may not have been created.", RECYCLE_BIN_ARTIFACT_NAME), ex); } @@ -102,16 +101,16 @@ final class ExtractRecycleBin extends Extract { return; } Map userNameMap; - + try { userNameMap = makeUserNameMap(dataSource); } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Unable to create OS Account user name map", ex); - // This is not the end of the world we will just continue without - // user names - userNameMap = new HashMap<>(); + logger.log(Level.WARNING, "Unable to create OS Account user name map", ex); + // This is not the end of the world we will just continue without + // user names + userNameMap = new HashMap<>(); } - + FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); Map> rFileMap; @@ -130,7 +129,7 @@ final class ExtractRecycleBin extends Extract { logger.log(Level.WARNING, "Unable to find recycle bin I files.", ex); //NON-NLS return; // No need to continue } - + String tempRARecycleBinPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), "recyclebin"); //NON-NLS for (AbstractFile iFile : iFiles) { @@ -138,24 +137,23 @@ final class ExtractRecycleBin extends Extract { if (context.dataSourceIngestIsCancelled()) { return; } - - processIFiles(dataSource, context, recycleBinArtifactType, iFile, userNameMap, rFileMap, tempRARecycleBinPath); + + processIFile(context, recycleBinArtifactType, iFile, userNameMap, rFileMap, tempRARecycleBinPath); } (new File(tempRARecycleBinPath)).delete(); } - + /** * Process each individual iFile. - * - * @param dataSource + * * @param context * @param recycleBinArtifactType Module created artifact type - * @param iFile The AbstractFile to process - * @param userNameMap Map of user ids to names - * @param tempRARecycleBinPath Temp directory path + * @param iFile The AbstractFile to process + * @param userNameMap Map of user ids to names + * @param tempRARecycleBinPath Temp directory path */ - private void processIFiles(Content dataSource, IngestJobContext context, BlackboardArtifact.Type recycleBinArtifactType, AbstractFile iFile, Map userNameMap, Map> rFileMap, String tempRARecycleBinPath) { + private void processIFile(IngestJobContext context, BlackboardArtifact.Type recycleBinArtifactType, AbstractFile iFile, Map userNameMap, Map> rFileMap, String tempRARecycleBinPath) { String tempFilePath = tempRARecycleBinPath + File.separator + iFile.getName(); try { try { @@ -187,10 +185,10 @@ final class ExtractRecycleBin extends Extract { } String rFileName = iFile.getName().replace("$I", "$R"); //NON-NLS - + List rFiles = rFileMap.get(rFileName); - - if(rFiles == null) { + + if (rFiles == null) { return; } SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); @@ -199,18 +197,18 @@ final class ExtractRecycleBin extends Extract { return; } - if (iFile.getParentPath().equals(rFile.getParentPath()) + if (iFile.getParentPath().equals(rFile.getParentPath()) && iFile.getMetaFlagsAsString().equals(rFile.getMetaFlagsAsString())) { try { postArtifact(createArtifact(rFile, recycleBinArtifactType, metaData.getFileName(), userName, metaData.getDeletedTimeStamp())); - if(rFile instanceof FsContent) { - if(rFile.isDir()) { - AbstractFile directory = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent)rFile, metaData.getFileName()); - popuplateDirectory(Case.getCurrentCase().getSleuthkitCase(), directory, rFile.getChildren(), metaData.getFileName(), metaData.getDeletedTimeStamp()); - + if (rFile instanceof FsContent) { + if (rFile.isDir()) { + AbstractFile directory = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent) rFile, metaData.getFileName()); + popuplateDeletedDirectory(Case.getCurrentCase().getSleuthkitCase(), directory, rFile.getChildren(), metaData.getFileName(), metaData.getDeletedTimeStamp()); + } else { - AbstractFile folder = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent)rFile.getParent(), Paths.get(metaData.getFileName()).getParent().toString()); - addFileToDirectory(skCase, rFile, folder, Paths.get(metaData.getFileName()).getFileName().toString(), metaData.getDeletedTimeStamp()); + AbstractFile folder = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent) rFile.getParent(), Paths.get(metaData.getFileName()).getParent().toString()); + addFileSystemFile(skCase, (FsContent)rFile, folder, Paths.get(metaData.getFileName()).getFileName().toString(), metaData.getDeletedTimeStamp()); } } } catch (TskCoreException ex) { @@ -222,30 +220,35 @@ final class ExtractRecycleBin extends Extract { (new File(tempFilePath)).delete(); } } - + /** - * - * @param skCase - * @param folder - * @param children - * @param parentPath - * @param deletedTimeStamp - * @throws TskCoreException + * Add the children of recycled $R folder to the folder. + * + * @param skCase The current Sleuthkit case + * @param parentFolder The folder to folder the deleted files are to be + * added. + * @param children The recycled children of the $R folder + * @param parentPath String path to the directory the children were + * deleted from + * @param deletedTimeStamp The time at which the files were deleted, + * inherited from the $R file. + * + * @throws TskCoreException */ - private void popuplateDirectory(SleuthkitCase skCase, AbstractFile folder, List recycledChildren, String parentPath, long deletedTimeStamp) throws TskCoreException { + private void popuplateDeletedDirectory(SleuthkitCase skCase, AbstractFile parentFolder, List recycledChildren, String parentPath, long deletedTimeStamp) throws TskCoreException { if (recycledChildren == null) { return; } - - for(Content child: recycledChildren) { - if(child instanceof AbstractFile) { - AbstractFile fileChild = (AbstractFile) child; - if(fileChild.isFile()) { - addFileToDirectory(skCase, fileChild, folder, fileChild.getName(), deletedTimeStamp); - } else if(fileChild.isDir()) { - String newPath = parentPath + File.separator + fileChild.getName(); - AbstractFile childFolder = getOrMakeFolder(skCase, (FsContent)fileChild, parentPath); - popuplateDirectory(skCase, childFolder, fileChild.getChildren(), newPath, deletedTimeStamp); + + for (Content child : recycledChildren) { + if (child instanceof FsContent) { + FsContent fsContent = (FsContent) child; + if (fsContent.isFile()) { + addFileSystemFile(skCase, fsContent, parentFolder, fsContent.getName(), deletedTimeStamp); + } else if (fsContent.isDir()) { + String newPath = parentPath + "\\" + fsContent.getName(); + AbstractFile childFolder = getOrMakeFolder(skCase, (FsContent) fsContent, parentPath); + popuplateDeletedDirectory(skCase, childFolder, fsContent.getChildren(), newPath, deletedTimeStamp); } } } @@ -290,7 +293,7 @@ final class ExtractRecycleBin extends Extract { long version = byteBuffer.getLong(); long fileSize = byteBuffer.getLong(); long timestamp = byteBuffer.getLong(); - + // Convert from windows FILETIME to Unix Epoch seconds timestamp = Util.filetimeToMillis(timestamp) / 1000; @@ -307,71 +310,73 @@ final class ExtractRecycleBin extends Extract { return new RecycledFileMetaData(fileSize, timestamp, fileName); } - + /** * Create a map of userids to usernames from the OS Accounts. - * + * * @param dataSource - * + * * @return A Map of userIDs and userNames - * - * @throws TskCoreException + * + * @throws TskCoreException */ - private Map makeUserNameMap(Content dataSource) throws TskCoreException{ + private Map makeUserNameMap(Content dataSource) throws TskCoreException { Map userNameMap = new HashMap<>(); - + List accounts = blackboard.getArtifacts(TSK_OS_ACCOUNT.getTypeID(), dataSource.getId()); - - for (BlackboardArtifact account: accounts) { + + for (BlackboardArtifact account : accounts) { BlackboardAttribute nameAttribute = getAttributeForArtifact(account, TSK_USER_NAME); BlackboardAttribute idAttribute = getAttributeForArtifact(account, TSK_USER_ID); - + String userName = nameAttribute != null ? nameAttribute.getDisplayString() : ""; String userID = idAttribute != null ? idAttribute.getDisplayString() : ""; - + if (!userID.isEmpty()) { userNameMap.put(userID, userName); } } - + return userNameMap; } - + /** - * Get a list of files that start with $R and create a map of the file to + * Get a list of files that start with $R and create a map of the file to * their name. - * + * * @param dataSource + * * @return File map - * @throws TskCoreException + * + * @throws TskCoreException */ - private Map> makeRFileMap(Content dataSource) throws TskCoreException{ + private Map> makeRFileMap(Content dataSource) throws TskCoreException { FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); List rFiles = fileManager.findFiles(dataSource, "$R%"); Map> fileMap = new HashMap<>(); - - for (AbstractFile rFile: rFiles) { + + for (AbstractFile rFile : rFiles) { String fileName = rFile.getName(); List fileList = fileMap.get(fileName); - - if(fileList == null) { + + if (fileList == null) { fileList = new ArrayList<>(); fileMap.put(fileName, fileList); } - + fileList.add(rFile); } - + return fileMap; } - + /** * Helper functions to get the user ID from the iFile parent path. User ids * will be of the form S-. - * + * * @param iFileParentPath String parent path of the iFile - * - * @return String user id + * + * @return String user id */ private String getUserIDFromPath(String iFileParentPath) { int index = iFileParentPath.indexOf('-') - 1; @@ -381,125 +386,175 @@ final class ExtractRecycleBin extends Extract { return ""; } } - + /** * Gets the attribute for the given type from the given artifact. - * + * * @param artifact BlackboardArtifact to get the attribute from - * @param type The BlackboardAttribute Type to get - * + * @param type The BlackboardAttribute Type to get + * * @return BlackboardAttribute for given artifact and type - * - * @throws TskCoreException + * + * @throws TskCoreException */ - private BlackboardAttribute getAttributeForArtifact(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException{ - return artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(type.getTypeID()))); + private BlackboardAttribute getAttributeForArtifact(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException { + return artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(type.getTypeID()))); } - + + /** + * Create TSK_RECYCLE_BIN artifact type. + * + * @throws TskCoreException + */ private void createRecycleBinArtifactType() throws TskCoreException { - try { + try { tskCase.addBlackboardArtifactType(RECYCLE_BIN_ARTIFACT_NAME, "Recycle Bin"); //NON-NLS } catch (TskDataException ex) { logger.log(Level.INFO, String.format("%s may have already been defined for this case", RECYCLE_BIN_ARTIFACT_NAME)); } } - + /** * Create the new artifact for the give rFile - * - * @param rFile AbstractFile to create the artifact for - * @param type Type of artifact to create + * + * @param rFile AbstractFile to create the artifact for + * @param type Type of artifact to create * @param fileName The original path of the deleted file * @param userName The name of the user that deleted the file * @param dateTime The time in epoch seconds that the file was deleted - * + * * @return Newly created artifact - * - * @throws TskCoreException + * + * @throws TskCoreException */ - private BlackboardArtifact createArtifact(AbstractFile rFile, BlackboardArtifact.Type type, String fileName, String userName, long dateTime) throws TskCoreException{ + private BlackboardArtifact createArtifact(AbstractFile rFile, BlackboardArtifact.Type type, String fileName, String userName, long dateTime) throws TskCoreException { BlackboardArtifact bba = rFile.newArtifact(type.getTypeID()); bba.addAttribute(new BlackboardAttribute(TSK_PATH, getName(), fileName)); bba.addAttribute(new BlackboardAttribute(TSK_DATETIME_DELETED, getName(), dateTime)); bba.addAttribute(new BlackboardAttribute(TSK_USER_NAME, getName(), userName == null || userName.isEmpty() ? "" : userName)); - + return bba; } - + + /** + * Returns a folder for the given path. If the path does not exist the + * the folder is created. + * + * @param skCase + * @param dataSource + * @param path + * + * @return AbstractFile for the given path. + * + * @throws TskCoreException + */ private AbstractFile getOrMakeFolder(SleuthkitCase skCase, FsContent dataSource, String path) throws TskCoreException { - + String parentPath = getParentPath(path); String folderName = getFileName(path); - + List files = null; - if(parentPath != null) { - if(!parentPath.equals("/")) { + if (parentPath != null) { + if (!parentPath.equals("/")) { parentPath = parentPath + "/"; } - files = skCase.findAllFilesWhere(String.format("fs_obj_id=%s AND parent_path='%s' AND name='%s'", dataSource.getFileSystemId(), parentPath, folderName != null ? folderName : "")); + + files = skCase.findAllFilesWhere(String.format("fs_obj_id=%s AND parent_path='%s' AND name='%s'", + dataSource.getFileSystemId(), SleuthkitCase.escapeSingleQuotes(parentPath), folderName != null ? SleuthkitCase.escapeSingleQuotes(folderName) : "")); } else { files = skCase.findAllFilesWhere(String.format("fs_obj_id=%s AND parent_path='/' AND name=''", dataSource.getFileSystemId())); } - - if(files == null || files.isEmpty()) { - AbstractFile parent = getOrMakeFolder(skCase, dataSource, parentPath); + + if (files == null || files.isEmpty()) { + AbstractFile parent = getOrMakeFolder(skCase, dataSource, parentPath); return skCase.addVirtualDirectory(parent.getId(), folderName); - } else { return files.get(0); } } - - private void addFileToDirectory (SleuthkitCase skCase, AbstractFile rFile, Content parentDir, String fileName, long deletedTime) throws TskCoreException { - FsContent fsContent = (FsContent)rFile; - - skCase.addFileSystemFile(fsContent.getFileSystemId(), - rFile.getDataSourceObjectId(), - rFile.getAttrType(), - rFile.getAttributeId(), - fileName, - TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC, - rFile.getSize(), - 0,0,0,deletedTime, - rFile.getMetaAddr(), - (int)rFile.getMetaSeq(), - true, parentDir); - } - + /** + * Adds a new file system file that is unallocated and maps to the original + * file in recycle bin directory. * - * @param path - * @return + * @param skCase The current case. + * @param recycleBinFile The file from the recycle bin. + * @param parentDir The directory that the recycled file was deleted. + * @param fileName The name of the file. + * @param deletedTime The time the file was deleted. + * + * @throws TskCoreException + */ + private void addFileSystemFile(SleuthkitCase skCase, FsContent recycleBinFile, Content parentDir, String fileName, long deletedTime) throws TskCoreException { + skCase.addFileSystemFile(recycleBinFile.getFileSystemId(), + recycleBinFile.getDataSourceObjectId(), + recycleBinFile.getAttrType(), + recycleBinFile.getAttributeId(), + fileName, + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC, + recycleBinFile.getSize(), + 0, 0, 0, deletedTime, + recycleBinFile.getMetaAddr(), + (int) recycleBinFile.getMetaSeq(), + true, parentDir); + } + + /** + * Clean up the windows path string to match what the autopsy db uses. + * + * @param path The file\folder path to normalize + * + * @return New path string with the root removed (ie X:) and the slashes + * changed from windows to unix. */ String normalizeFilePath(String pathString) { if (pathString == null || pathString.isEmpty()) { return null; } - + Path path = Paths.get(pathString); - Path rootPath = path.getRoot(); - - String rootless = pathString.replace(rootPath.toString().replace("\\", ""), ""); - return rootless.replace("\\", "/"); + int nameCount = path.getNameCount(); + if(nameCount > 0) { + String rootless = "/" + path.subpath(0, nameCount); + return rootless.replace("\\", "/"); + } else { + return "/"; + } } - + + /** + * Helper function get from the given path either the file name or + * the last directory in the path. + * + * @param filePath The file\directory path + * + * @return If file path, returns the file name. If directory path the + * The last directory in the path is returned. + */ String getFileName(String filePath) { Path fileNamePath = Paths.get(filePath).getFileName(); - if(fileNamePath != null) { + if (fileNamePath != null) { return fileNamePath.toString(); } return filePath; } - + + /** + * Returns the parent path for the given path. + * + * @param path Path string + * + * @return The parent path for the given path. + */ String getParentPath(String path) { Path parentPath = Paths.get(path).getParent(); - if(parentPath != null) { + if (parentPath != null) { return normalizeFilePath(parentPath.toString()); } return null; } - + /** * Stores the data from the $I files. */ @@ -524,7 +579,7 @@ final class ExtractRecycleBin extends Extract { /** * Returns the size of the recycled file. - * + * * @return Size of deleted file */ long getFileSize() { @@ -533,7 +588,7 @@ final class ExtractRecycleBin extends Extract { /** * Returns the time the file was deleted. - * + * * @return deleted time in epoch seconds. */ long getDeletedTimeStamp() { @@ -542,7 +597,7 @@ final class ExtractRecycleBin extends Extract { /** * Returns the name of the deleted file. - * + * * @return String name of the deleted file */ String getFileName() { From 7d1c3b37e9676a3e4198e1af4254427d5d44c137 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 22 Aug 2019 14:13:36 -0400 Subject: [PATCH 09/27] modified the temp name to be unique --- .../sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 8beaa0bd87..9690a04aa0 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -36,6 +36,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; +import org.joda.time.Instant; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -154,7 +155,7 @@ final class ExtractRecycleBin extends Extract { * @param tempRARecycleBinPath Temp directory path */ private void processIFile(IngestJobContext context, BlackboardArtifact.Type recycleBinArtifactType, AbstractFile iFile, Map userNameMap, Map> rFileMap, String tempRARecycleBinPath) { - String tempFilePath = tempRARecycleBinPath + File.separator + iFile.getName(); + String tempFilePath = tempRARecycleBinPath + File.separator + Instant.now().toString() + iFile.getName(); try { try { ContentUtils.writeToFile(iFile, new File(tempFilePath)); From 6385c5e0705f63256d8b2c8501873e98a633d990 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 22 Aug 2019 16:06:34 -0400 Subject: [PATCH 10/27] Added comments. No logic changes. --- .../recentactivity/ExtractRecycleBin.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 9690a04aa0..1086a346eb 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -101,8 +101,9 @@ final class ExtractRecycleBin extends Extract { // If this doesn't work bail. return; } + + // map SIDs to user names so that we can include that in the artifact Map userNameMap; - try { userNameMap = makeUserNameMap(dataSource); } catch (TskCoreException ex) { @@ -114,6 +115,7 @@ final class ExtractRecycleBin extends Extract { FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + // Collect all of the $R files so that we can later easily map them to corresponding $I file Map> rFileMap; try { rFileMap = makeRFileMap(dataSource); @@ -122,8 +124,8 @@ final class ExtractRecycleBin extends Extract { return; // No $R files, no need to continue; } + // Get the $I files List iFiles; - try { iFiles = fileManager.findFiles(dataSource, "$I%"); //NON-NLS } catch (TskCoreException ex) { @@ -133,6 +135,7 @@ final class ExtractRecycleBin extends Extract { String tempRARecycleBinPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), "recyclebin"); //NON-NLS + // cycle through the $I files and process each. for (AbstractFile iFile : iFiles) { if (context.dataSourceIngestIsCancelled()) { @@ -166,6 +169,7 @@ final class ExtractRecycleBin extends Extract { return; } + // get the original name, dates, etc. from the $I file RecycledFileMetaData metaData; try { metaData = parseIFile(tempFilePath); @@ -175,6 +179,7 @@ final class ExtractRecycleBin extends Extract { return; } + // each user has its own Recyle Bin folder. Figure out the user name based on its name . String userID = getUserIDFromPath(iFile.getParentPath()); String userName = ""; if (!userID.isEmpty()) { @@ -185,10 +190,9 @@ final class ExtractRecycleBin extends Extract { return; } + // get the corresponding $R file, which is in the same folder and has the file content String rFileName = iFile.getName().replace("$I", "$R"); //NON-NLS - List rFiles = rFileMap.get(rFileName); - if (rFiles == null) { return; } @@ -202,7 +206,13 @@ final class ExtractRecycleBin extends Extract { && iFile.getMetaFlagsAsString().equals(rFile.getMetaFlagsAsString())) { try { postArtifact(createArtifact(rFile, recycleBinArtifactType, metaData.getFileName(), userName, metaData.getDeletedTimeStamp())); + + // If we are processing a disk image, we will also make a deleted file entry so that the user + // sees the deleted file in its original folder. We re-use the metadata address so that the user + // can see the content. if (rFile instanceof FsContent) { + // if the user deleted a folder, then we need to recusively go into it. Note the contents of the $R folder + // do not have corresponding $I files anymore. Only the $R folder does. if (rFile.isDir()) { AbstractFile directory = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent) rFile, metaData.getFileName()); popuplateDeletedDirectory(Case.getCurrentCase().getSleuthkitCase(), directory, rFile.getChildren(), metaData.getFileName(), metaData.getDeletedTimeStamp()); @@ -280,7 +290,7 @@ final class ExtractRecycleBin extends Extract { * For versions of Windows prior to 10, header = 0x01. Windows 10+ header == * 0x02 * - * @param iFilePath + * @param iFilePath Path to local copy of file in temp folder * * @throws FileNotFoundException * @throws IOException @@ -440,7 +450,7 @@ final class ExtractRecycleBin extends Extract { /** * Returns a folder for the given path. If the path does not exist the - * the folder is created. + * the folder is created. Recursively makes as many parent folders as needed. * * @param skCase * @param dataSource From 4b9c08f19fd959516f719a1ea4514253f461452f Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 26 Aug 2019 11:52:23 -0400 Subject: [PATCH 11/27] Changed the order of the args for addFileSystemFile --- .../recentactivity/Bundle.properties-MERGED | 8 ++++- .../recentactivity/ExtractRecycleBin.java | 33 ++++++++++--------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index 40771a0d41..a54c840799 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -2,9 +2,14 @@ cannotBuildXmlParser=Unable to build XML parser: cannotLoadSEUQA=Unable to load Search Engine URL Query Analyzer settings file, SEUQAMappings.xml: cannotParseXml=Unable to parse XML file: ChromeCacheExtractor.moduleName=ChromeCacheExtractor +# {0} - module name +# {1} - row number +# {2} - table length +# {3} - cache path ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries from {3} DataSourceUsage_AndroidMedia=Android Media Card DataSourceUsage_FlashDrive=Flash Drive +# {0} - OS name DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0}) DataSourceUsageAnalyzer.parentModuleName=Recent Activity Extract.indexError.message=Failed to index artifact for keyword search. @@ -60,7 +65,7 @@ ExtractZone_progress_Msg=Extracting :Zone.Identifer files ExtractZone_Restricted=Restricted Sites Zone ExtractZone_Trusted=Trusted Sites Zone OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\nThe module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy. +OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\n\The module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy. OpenIDE-Module-Name=RecentActivity OpenIDE-Module-Short-Description=Recent Activity finder ingest module Chrome.moduleName=Chrome @@ -183,6 +188,7 @@ RecentDocumentsByLnk.parentModuleName.noSpace=RecentActivity RecentDocumentsByLnk.parentModuleName=Recent Activity RegRipperFullNotFound=Full version RegRipper executable not found. RegRipperNotFound=Autopsy RegRipper executable not found. +# {0} - file name SearchEngineURLQueryAnalyzer.init.exception.msg=Unable to find {0}. SearchEngineURLQueryAnalyzer.moduleName.text=Search Engine SearchEngineURLQueryAnalyzer.engineName.none=NONE diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 1086a346eb..f461a2d026 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -158,7 +158,7 @@ final class ExtractRecycleBin extends Extract { * @param tempRARecycleBinPath Temp directory path */ private void processIFile(IngestJobContext context, BlackboardArtifact.Type recycleBinArtifactType, AbstractFile iFile, Map userNameMap, Map> rFileMap, String tempRARecycleBinPath) { - String tempFilePath = tempRARecycleBinPath + File.separator + Instant.now().toString() + iFile.getName(); + String tempFilePath = tempRARecycleBinPath + File.separator + Instant.now().getMillis() + iFile.getName(); try { try { ContentUtils.writeToFile(iFile, new File(tempFilePath)); @@ -205,8 +205,8 @@ final class ExtractRecycleBin extends Extract { if (iFile.getParentPath().equals(rFile.getParentPath()) && iFile.getMetaFlagsAsString().equals(rFile.getMetaFlagsAsString())) { try { - postArtifact(createArtifact(rFile, recycleBinArtifactType, metaData.getFileName(), userName, metaData.getDeletedTimeStamp())); - + postArtifact(createArtifact(rFile, recycleBinArtifactType, metaData.getFullWindowsPath(), userName, metaData.getDeletedTimeStamp())); + // If we are processing a disk image, we will also make a deleted file entry so that the user // sees the deleted file in its original folder. We re-use the metadata address so that the user // can see the content. @@ -214,12 +214,12 @@ final class ExtractRecycleBin extends Extract { // if the user deleted a folder, then we need to recusively go into it. Note the contents of the $R folder // do not have corresponding $I files anymore. Only the $R folder does. if (rFile.isDir()) { - AbstractFile directory = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent) rFile, metaData.getFileName()); - popuplateDeletedDirectory(Case.getCurrentCase().getSleuthkitCase(), directory, rFile.getChildren(), metaData.getFileName(), metaData.getDeletedTimeStamp()); + AbstractFile directory = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent) rFile, metaData.getFullWindowsPath()); + popuplateDeletedDirectory(Case.getCurrentCase().getSleuthkitCase(), directory, rFile.getChildren(), metaData.getFullWindowsPath(), metaData.getDeletedTimeStamp()); } else { - AbstractFile folder = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent) rFile.getParent(), Paths.get(metaData.getFileName()).getParent().toString()); - addFileSystemFile(skCase, (FsContent)rFile, folder, Paths.get(metaData.getFileName()).getFileName().toString(), metaData.getDeletedTimeStamp()); + AbstractFile folder = getOrMakeFolder(Case.getCurrentCase().getSleuthkitCase(), (FsContent) rFile.getParent(), Paths.get(metaData.getFullWindowsPath()).getParent().toString()); + addFileSystemFile(skCase, (FsContent)rFile, folder, Paths.get(metaData.getFullWindowsPath()).getFileName().toString(), metaData.getDeletedTimeStamp()); } } } catch (TskCoreException ex) { @@ -498,16 +498,18 @@ final class ExtractRecycleBin extends Extract { * @throws TskCoreException */ private void addFileSystemFile(SleuthkitCase skCase, FsContent recycleBinFile, Content parentDir, String fileName, long deletedTime) throws TskCoreException { - skCase.addFileSystemFile(recycleBinFile.getFileSystemId(), + skCase.addFileSystemFile( recycleBinFile.getDataSourceObjectId(), - recycleBinFile.getAttrType(), - recycleBinFile.getAttributeId(), + recycleBinFile.getFileSystemId(), fileName, - TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC, - recycleBinFile.getSize(), - 0, 0, 0, deletedTime, recycleBinFile.getMetaAddr(), (int) recycleBinFile.getMetaSeq(), + recycleBinFile.getAttrType(), + recycleBinFile.getAttributeId(), + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC, + (short) (TskData.TSK_FS_META_FLAG_ENUM.UNALLOC.getValue() | TskData.TSK_FS_META_FLAG_ENUM.USED.getValue()), + recycleBinFile.getSize(), + 0, 0, 0, deletedTime, true, parentDir); } @@ -607,11 +609,12 @@ final class ExtractRecycleBin extends Extract { } /** - * Returns the name of the deleted file. + * Returns the full path to the deleted file or folder. This path will + * include the drive letter, ie C:\ * * @return String name of the deleted file */ - String getFileName() { + String getFullWindowsPath() { return fileName.trim(); } } From 0a18e51a92f4320688cedc491cb340156de333c7 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Fri, 6 Sep 2019 16:01:04 -0400 Subject: [PATCH 12/27] Added support to parseshell bags to ExtractRegistry --- .../recentactivity/Bundle.properties-MERGED | 3 + .../recentactivity/ExtractRegistry.java | 154 +++++++- .../recentactivity/ShellBagParser.java | 361 ++++++++++++++++++ 3 files changed, 510 insertions(+), 8 deletions(-) create mode 100755 RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index f27b253e16..80f22aa5ef 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -189,4 +189,7 @@ SearchEngineURLQueryAnalyzer.domainSubStr.none=NONE SearchEngineURLQueryAnalyzer.toString=Name: {0}\nDomain Substring: {1}\nCount: {2}\nSplit Tokens: \n{3} SearchEngineURLQueryAnalyzer.parentModuleName.noSpace=RecentActivity SearchEngineURLQueryAnalyzer.parentModuleName=Recent Activity +Shellbag_Artifact_Display_Name=Shell Bags +Shellbag_Key_Attribute_Display_Name=Key +Shellbag_Last_Write_Attribute_Display_Name=Last Write UsbDeviceIdMapper.parseAndLookup.text=Product: {0} diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index 522ef5a262..b139fa29e5 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -66,16 +66,20 @@ import static java.util.TimeZone.getTimeZone; import org.openide.util.Lookup; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; +import org.sleuthkit.autopsy.recentactivity.ShellBagParser.ShellBag; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException; import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskDataException; /** * Extract windows registry data using regripper. Runs two versions of @@ -86,7 +90,10 @@ import org.sleuthkit.datamodel.TskCoreException; @NbBundle.Messages({ "RegRipperNotFound=Autopsy RegRipper executable not found.", "RegRipperFullNotFound=Full version RegRipper executable not found.", - "Progress_Message_Analyze_Registry=Analyzing Registry Files" + "Progress_Message_Analyze_Registry=Analyzing Registry Files", + "Shellbag_Artifact_Display_Name=Shell Bags", + "Shellbag_Key_Attribute_Display_Name=Key", + "Shellbag_Last_Write_Attribute_Display_Name=Last Write" }) class ExtractRegistry extends Extract { @@ -103,6 +110,14 @@ class ExtractRegistry extends Extract { private final Path rrFullHome; // Path to the full version of RegRipper private Content dataSource; private IngestJobContext context; + + private static final String SHELLBAG_ARTIFACT_NAME = "RA_SHELL_BAG"; //NON-NLS + private static final String SHELLBAG_ATTRIBUTE_LAST_WRITE = "RA_SHELL_BAG_LAST_WRITE"; //NON-NLS + private static final String SHELLBAG_ATTRIBUTE_KEY= "RA_SHELL_BAG_KEY"; //NON-NLS + + BlackboardArtifact.Type shellBagArtifactType = null; + BlackboardAttribute.Type shellBagKeyAttributeType = null; + BlackboardAttribute.Type shellBagLastWriteAttributeType = null; ExtractRegistry() throws IngestModuleException { moduleName = NbBundle.getMessage(ExtractIE.class, "ExtractRegistry.moduleName.text"); @@ -166,6 +181,13 @@ class ExtractRegistry extends Extract { } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error fetching 'ntuser.dat' file."); //NON-NLS } + + // find the user-specific ntuser-dat files + try { + allRegistryFiles.addAll(fileManager.findFiles(dataSource, "usrclass.dat")); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Error finding 'usrclass.dat' files."), ex); //NON-NLS + } // find the system hives' String[] regFileNames = new String[]{"system", "software", "security", "sam"}; //NON-NLS @@ -175,7 +197,7 @@ class ExtractRegistry extends Extract { } catch (TskCoreException ex) { String msg = NbBundle.getMessage(this.getClass(), "ExtractRegistry.findRegFiles.errMsg.errReadingFile", regFileName); - logger.log(Level.WARNING, msg); + logger.log(Level.WARNING, msg, ex); this.addErrorMessage(this.getName() + ": " + msg); } } @@ -253,6 +275,13 @@ class ExtractRegistry extends Extract { this.addErrorMessage( NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults", this.getName(), regFileName)); + } else if (regFileNameLocal.toLowerCase().contains("ntuser") || regFileNameLocal.toLowerCase().contains("usrclass")) { + try { + List shellbags = ShellBagParser.parseShellbagOutput(regOutputFiles.fullPlugins); + createShellBagArtifacts(regFile, shellbags); + } catch (IOException | TskCoreException ex) { + logger.log(Level.WARNING, String.format("Unable to get shell bags from file %s", regOutputFiles.fullPlugins), ex); + } } try { Report report = currentCase.addReport(regOutputFiles.fullPlugins, @@ -311,6 +340,8 @@ class ExtractRegistry extends Extract { fullType = "sam"; //NON-NLS } else if (regFilePath.toLowerCase().contains("security")) { //NON-NLS fullType = "security"; //NON-NLS + }else if (regFilePath.toLowerCase().contains("usrclass")) { //NON-NLS + fullType = "usrclass"; //NON-NLS } else { return regOutputFiles; } @@ -811,13 +842,13 @@ class ExtractRegistry extends Extract { } // for return true; } catch (FileNotFoundException ex) { - logger.log(Level.SEVERE, "Error finding the registry file.", ex); //NON-NLS + logger.log(Level.WARNING, String.format("Error finding the registry file: %s", regFilePath), ex); //NON-NLS } catch (SAXException ex) { - logger.log(Level.SEVERE, "Error parsing the registry XML.", ex); //NON-NLS + logger.log(Level.WARNING, String.format("Error parsing the registry XML: %s", regFilePath), ex); //NON-NLS } catch (IOException ex) { - logger.log(Level.SEVERE, "Error building the document parser.", ex); //NON-NLS + logger.log(Level.WARNING, String.format("Error building the document parser: %s", regFilePath), ex); //NON-NLS } catch (ParserConfigurationException ex) { - logger.log(Level.SEVERE, "Error configuring the registry parser.", ex); //NON-NLS + logger.log(Level.WARNING, String.format("Error configuring the registry parser: %s", regFilePath), ex); //NON-NLS } finally { try { if (fstream != null) { @@ -979,7 +1010,114 @@ class ExtractRegistry extends Extract { progressBar.progress(Bundle.Progress_Message_Analyze_Registry()); analyzeRegistryFiles(); + } + + /** + * Create the shellbag artifacts from the list of ShellBag objects. + * + * @param regFile The data source file + * @param shellbags List of shellbags from source file + * + * @throws TskCoreException + */ + void createShellBagArtifacts(AbstractFile regFile, List shellbags) throws TskCoreException { + List artifacts = new ArrayList<>(); + for (ShellBag bag : shellbags) { + BlackboardArtifact artifact = regFile.newArtifact(getShellBagArtifact().getTypeID()); + artifact.addAttribute(new BlackboardAttribute(TSK_PATH, getName(), bag.getResource())); + artifact.addAttribute(new BlackboardAttribute(getKeyAttribute(), getName(), bag.getKey())); + long time = bag.getModified(); + if (time != 0) { + artifact.addAttribute(new BlackboardAttribute(TSK_DATETIME_MODIFIED, getName(), time)); + } + + time = bag.getCreated(); + if (time != 0) { + artifact.addAttribute(new BlackboardAttribute(TSK_DATETIME_CREATED, getName(), time)); + } + + time = bag.getAccessed(); + if (time != 0) { + artifact.addAttribute(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getName(), time)); + } + + time = bag.getLastWrite(); + if (time != 0) { + artifact.addAttribute(new BlackboardAttribute(getLastWriteAttribute(), getName(), time)); + } + + artifacts.add(artifact); + } + + postArtifacts(artifacts); + } + + /** + * Returns the custom Shellbag artifact type or creates it if it does not + * currently exist. + * + * @return BlackboardArtifact.Type for shellbag artifacts + * + * @throws TskCoreException + */ + private BlackboardArtifact.Type getShellBagArtifact() throws TskCoreException { + if (shellBagArtifactType == null) { + try { + tskCase.addBlackboardArtifactType(SHELLBAG_ARTIFACT_NAME, Bundle.Shellbag_Artifact_Display_Name()); //NON-NLS + } catch (TskDataException ex) { + // Artifact already exists + logger.log(Level.INFO, String.format("%s may have already been defined for this case", SHELLBAG_ARTIFACT_NAME), ex); + } + + shellBagArtifactType = tskCase.getArtifactType(SHELLBAG_ARTIFACT_NAME); + } + + return shellBagArtifactType; + } + + /** + * Gets the custom BlackboardAttribute type. The attribute type is created + * if it does not currently exist. + * + * @return The BlackboardAttribute type + * + * @throws TskCoreException + */ + private BlackboardAttribute.Type getLastWriteAttribute() throws TskCoreException { + if (shellBagLastWriteAttributeType == null) { + try { + shellBagLastWriteAttributeType = tskCase.addArtifactAttributeType(SHELLBAG_ATTRIBUTE_LAST_WRITE, + BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME, + Bundle.Shellbag_Last_Write_Attribute_Display_Name()); + } catch (TskDataException ex) { + // Attribute already exists get it from the case + shellBagLastWriteAttributeType = tskCase.getAttributeType(SHELLBAG_ATTRIBUTE_LAST_WRITE); + } + } + return shellBagLastWriteAttributeType; + } + + /** + * Gets the custom BlackboardAttribute type. The attribute type is created + * if it does not currently exist. + * + * @return The BlackboardAttribute type + * + * @throws TskCoreException + */ + private BlackboardAttribute.Type getKeyAttribute() throws TskCoreException { + if (shellBagKeyAttributeType == null) { + try { + shellBagKeyAttributeType = tskCase.addArtifactAttributeType(SHELLBAG_ATTRIBUTE_KEY, + BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, + Bundle.Shellbag_Key_Attribute_Display_Name()); + } catch (TskDataException ex) { + // The attribute already exists get it from the case + shellBagKeyAttributeType = tskCase.getAttributeType(SHELLBAG_ATTRIBUTE_KEY); + } + } + return shellBagKeyAttributeType; } /** diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java new file mode 100755 index 0000000000..d0aef93305 --- /dev/null +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java @@ -0,0 +1,361 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 Basis Technology Corp. + * + * Copyright 2012 42six Solutions. + * Contact: aebadirad 42six com + * Project Contact/Architect: 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.recentactivity; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * Parse the ntuser and ursclass regripper output files for shellbags. + */ +public class ShellBagParser { + + private final Logger logger = Logger.getLogger(ShellBagParser.class.getName()); + + static SimpleDateFormat DATE_TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + // Last Write date\time format from itempos plugin + static SimpleDateFormat DATE_TIME_FORMATTER2 = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyyy"); + + private ShellBagParser() { + } + + /** + * Parse the given file for shell bags. + * + * @param regFilePath Regripper output file + * + * @return List of the found shellbags + * + * @throws FileNotFoundException + * @throws IOException + */ + static List parseShellbagOutput(String regFilePath) throws FileNotFoundException, IOException { + List shellbags = new ArrayList<>(); + File regfile = new File(regFilePath); + + ShellBagParser sbparser = new ShellBagParser(); + + try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) { + String line = reader.readLine(); + while (line != null) { + line = line.trim(); + + if (line.matches("^shellbags_xp v.*")) { + shellbags.addAll(sbparser.parseShellBagsXP(reader)); + } else if (line.matches("^shellbags v.*")) { + shellbags.addAll(sbparser.parseShellBags(reader)); + } else if (line.matches("^itempos.*")) { + shellbags.addAll(sbparser.parseItempos(reader)); + } + + line = reader.readLine(); + } + } + + return shellbags; + } + + /** + * Parse the output from the shellbag_xp plugin. + * + * @param reader File reader + * + * @return List of found shellbags + * + * @throws IOException + */ + List parseShellBagsXP(BufferedReader reader) throws IOException { + List shellbags = new ArrayList<>(); + String line = reader.readLine(); + + while (line != null && !isSectionSeparator(line)) { + + if (isShellbagXPDataLine(line)) { + String[] tokens = line.split("\\|"); + if (tokens.length >= 6) { + shellbags.add(new ShellBag(tokens[5].trim(), "Software\\Microsoft\\Windows\\ShellNoRoam\\BagMRU", tokens[0].trim(), tokens[1].trim(), tokens[2].trim(), tokens[3].trim())); + } + } + + line = reader.readLine(); + } + + return shellbags; + } + + /** + * Parse the output of the shellbags regripper plugin. + * + * @param reader + * @return List of found shellbags + * + * @throws IOException + */ + List parseShellBags(BufferedReader reader) throws IOException { + List shellbags = new ArrayList<>(); + String line = reader.readLine(); + String regPath = "Local Settings\\Software\\Microsoft\\Windows\\Shell\\BagMRU"; + + while (line != null && !isSectionSeparator(line)) { + + if (isShellbagDataLine(line)) { + String[] tokens = line.split("\\|"); + String path = tokens[6].replaceAll("\\[.*?\\]", "").trim(); + int index = line.lastIndexOf('['); + String endstuff = ""; + if (index != -1) { + endstuff = line.substring(index, line.length() - 1).replace("[Desktop", ""); + } + if (tokens.length >= 7) { + shellbags.add(new ShellBag(path, regPath + endstuff, tokens[0].trim(), tokens[1].trim(), tokens[2].trim(), tokens[3].trim())); + } + } + + line = reader.readLine(); + } + + return shellbags; + } + + /** + * Parse the output of the Itempos regripper plugin. + * + * @param reader + * + * @return List of found shell bags. + * + * @throws IOException + */ + List parseItempos(BufferedReader reader) throws IOException { + List shellbags = new ArrayList<>(); + String bagpath = ""; + String lastWrite = ""; + String line = reader.readLine(); + + while (line != null && !isSectionSeparator(line)) { + + if (isItemposDataLine(line)) { + String[] tokens = line.split("\\|"); + if (tokens.length >= 5) { + shellbags.add(new ShellBag(tokens[4].trim(), bagpath, lastWrite, tokens[1].trim(), tokens[2].trim(), tokens[3].trim())); + } + } else if (line.contains("Software\\")) { + bagpath = line.trim(); + lastWrite = ""; + } else if (line.contains("LastWrite:")) { + lastWrite = line.replace("LastWrite:", "").trim(); + } + + line = reader.readLine(); + } + + return shellbags; + } + + /** + * Return whether or not the given line is a plugin output separator. + * + * The format of the plugin output separators is: + * ---------------------------------------- + * + * @param line + * + * @return True if the line is a section separator + */ + boolean isSectionSeparator(String line) { + if (line == null || line.isEmpty()) { + return false; + } + + return line.trim().matches("^-+"); + } + + /** + * This data rows from the itempos plugin are in the format: + * | | | | + * The times are in the format YYYY-MM-dd HH:mm:ss + * + * @param line + * + * @return + */ + boolean isItemposDataLine(String line) { + return line.matches("^\\d*?\\s*?\\|.*?\\|.*?\\|.*?\\|.*?"); + } + + /** + * The data rows from the shellbags_xp plug look like + * | | | | + * | + * + * The times are in the format YYYY-MM-dd HH:mm:ss + * + * @param line + * + * @return + */ + boolean isShellbagXPDataLine(String line) { + return line.matches("^(\\d+?.*?\\s*? | \\s*?)\\|.*?\\|.*?\\|.*?\\|.*?\\|.*?"); + } + + /** + * The data rows from the shellbags plug look like + * | | | | + * | + * + * The times are in the format YYYY-MM-dd HH:mm:ss + * + * @param line + * + * @return + */ + boolean isShellbagDataLine(String line) { + return line.matches("^(\\d+?.*?\\s*? | \\s*?)\\|.*?\\|.*?\\|.*?\\|.*?\\|.*?\\|.*?"); + } + + /** + * Class to hold the shell bag data. + * + */ + class ShellBag { + + private String resource = ""; + private String key = ""; + private String lastWrite = ""; + private String modified = ""; + private String accessed = ""; + private String created = ""; + + /** + * Creates a new shell bag object. + * + * Any of the parameters can be ""; + * + * @param resource String from the "Resource" or "Name" column, depending on the plugin + * @param key String registry key value + * @param lastWrite Depending on the plugin lastWrite is either Last write value or the MRU Time value + * @param modified Modified time string + * @param accessed Accessed time string + * @param created Created time string + */ + ShellBag(String resource, String key, String lastWrite, String modified, String accessed, String created) { + this.resource = resource; + this.key = key; + this.lastWrite = lastWrite; + this.accessed = accessed; + this.modified = modified; + this.created = created; + } + + /** + * Returns the resource string. + * + * @return The shellbag resource or empty string. + */ + String getResource() { + return resource == null ? "" : resource; + } + + /** + * Returns the key string. + * + * @return The shellbag key or empty string. + */ + String getKey() { + return key == null ? "" : key; + } + + /** + * Returns the last time in seconds since java epoch or + * 0 if no valid time was found. + * + * @return The time in seconds or 0 if no valid time. + */ + long getLastWrite() { + return parseDateTime(lastWrite); + } + + /** + * Returns the last time in seconds since java epoch or + * 0 if no valid time was found. + * + * @return The time in seconds or 0 if no valid time. + */ + long getModified() { + return parseDateTime(modified); + } + + /** + * Returns the last time in seconds since java epoch or + * 0 if no valid time was found. + * + * @return The time in seconds or 0 if no valid time. + */ + long getAccessed() { + return parseDateTime(accessed); + } + + /** + * Returns the last time in seconds since java epoch or + * 0 if no valid time was found. + * + * @return The time in seconds or 0 if no valid time. + */ + long getCreated() { + return parseDateTime(created); + } + + /** + * Returns the date\time in seconds from epoch for the given string with + * format yyyy-MM-dd HH:mm:ss; + * + * @param dateTimeString String of format yyyy-MM-dd HH:mm:ss + * + * @return time in seconds from java epoch + */ + long parseDateTime(String dateTimeString) { + if (!dateTimeString.isEmpty()) { + try { + return DATE_TIME_FORMATTER.parse(dateTimeString).getTime() / 1000; + } catch (ParseException ex) { + // The parse of the string may fail because there are two possible formats. + } + + try { + return DATE_TIME_FORMATTER2.parse(dateTimeString).getTime() / 1000; + } catch (ParseException ex) { + + } + } + return 0; + } + } + +} From 37327f49c32ac1db8041ea088af96f78fee8c93c Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 9 Sep 2019 12:56:48 -0400 Subject: [PATCH 13/27] Modified code to add shellbag attributes in one call --- .../recentactivity/ExtractRegistry.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index b139fa29e5..55a1af1e61 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -1023,29 +1023,33 @@ class ExtractRegistry extends Extract { void createShellBagArtifacts(AbstractFile regFile, List shellbags) throws TskCoreException { List artifacts = new ArrayList<>(); for (ShellBag bag : shellbags) { + Collection attributes = new ArrayList<>(); BlackboardArtifact artifact = regFile.newArtifact(getShellBagArtifact().getTypeID()); - artifact.addAttribute(new BlackboardAttribute(TSK_PATH, getName(), bag.getResource())); - artifact.addAttribute(new BlackboardAttribute(getKeyAttribute(), getName(), bag.getKey())); + attributes.add(new BlackboardAttribute(TSK_PATH, getName(), bag.getResource())); + attributes.add(new BlackboardAttribute(getKeyAttribute(), getName(), bag.getKey())); - long time = bag.getModified(); + long time; + time = bag.getLastWrite(); if (time != 0) { - artifact.addAttribute(new BlackboardAttribute(TSK_DATETIME_MODIFIED, getName(), time)); + attributes.add(new BlackboardAttribute(getLastWriteAttribute(), getName(), time)); + } + + time = bag.getModified(); + if (time != 0) { + attributes.add(new BlackboardAttribute(TSK_DATETIME_MODIFIED, getName(), time)); } time = bag.getCreated(); if (time != 0) { - artifact.addAttribute(new BlackboardAttribute(TSK_DATETIME_CREATED, getName(), time)); + attributes.add(new BlackboardAttribute(TSK_DATETIME_CREATED, getName(), time)); } time = bag.getAccessed(); if (time != 0) { - artifact.addAttribute(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getName(), time)); + attributes.add(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getName(), time)); } - time = bag.getLastWrite(); - if (time != 0) { - artifact.addAttribute(new BlackboardAttribute(getLastWriteAttribute(), getName(), time)); - } + artifact.addAttributes(attributes); artifacts.add(artifact); } From 5ad1f282aa6631f9d385e8e1cd62a673fc80b45f Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 11 Sep 2019 15:02:33 -0400 Subject: [PATCH 14/27] Modified handle TagDeleted functions to check for both artifact and content tags --- .../autopsy/timeline/FilteredEventsModel.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/FilteredEventsModel.java b/Core/src/org/sleuthkit/autopsy/timeline/FilteredEventsModel.java index 457939f04c..44975ade85 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/FilteredEventsModel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/FilteredEventsModel.java @@ -512,8 +512,14 @@ public final class FilteredEventsModel { DeletedContentTagInfo deletedTagInfo = evt.getDeletedTagInfo(); Content content = autoCase.getSleuthkitCase().getContentById(deletedTagInfo.getContentID()); - boolean tagged = autoCase.getServices().getTagsManager().getContentTagsByContent(content).isEmpty() == false; - Set updatedEventIDs = deleteTag(content.getId(), null, deletedTagInfo.getTagID(), tagged); + boolean isContentTagged = autoCase.getServices().getTagsManager().getContentTagsByContent(content).isEmpty() == false; + boolean isArtifactTagged = false; + + if(content instanceof BlackboardArtifact) { + isArtifactTagged = autoCase.getServices().getTagsManager().getBlackboardArtifactTagsByArtifact((BlackboardArtifact)content).isEmpty() == false; + } + + Set updatedEventIDs = deleteTag(content.getId(), null, deletedTagInfo.getTagID(), isArtifactTagged || isContentTagged); return postTagsDeleted(updatedEventIDs); } @@ -521,8 +527,9 @@ public final class FilteredEventsModel { DeletedBlackboardArtifactTagInfo deletedTagInfo = evt.getDeletedTagInfo(); BlackboardArtifact artifact = autoCase.getSleuthkitCase().getBlackboardArtifact(deletedTagInfo.getArtifactID()); - boolean tagged = autoCase.getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact).isEmpty() == false; - Set updatedEventIDs = deleteTag(artifact.getObjectID(), artifact.getArtifactID(), deletedTagInfo.getTagID(), tagged); + boolean isArtifactTagged = autoCase.getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact).isEmpty() == false; + boolean isContentTagged = autoCase.getServices().getTagsManager().getContentTagsByContent(artifact).isEmpty() == false; + Set updatedEventIDs = deleteTag(artifact.getObjectID(), artifact.getArtifactID(), deletedTagInfo.getTagID(), isArtifactTagged || isContentTagged); return postTagsDeleted(updatedEventIDs); } From ea60f0292c888968d74d14c5897585ce73e0df4a Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 11 Sep 2019 16:20:45 -0400 Subject: [PATCH 15/27] added the creation and modifty time to the file system file --- .../sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index f461a2d026..f1f46677de 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -48,7 +48,10 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT; import org.sleuthkit.datamodel.BlackboardAttribute; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_DELETED; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME; @@ -444,7 +447,6 @@ final class ExtractRecycleBin extends Extract { bba.addAttribute(new BlackboardAttribute(TSK_PATH, getName(), fileName)); bba.addAttribute(new BlackboardAttribute(TSK_DATETIME_DELETED, getName(), dateTime)); bba.addAttribute(new BlackboardAttribute(TSK_USER_NAME, getName(), userName == null || userName.isEmpty() ? "" : userName)); - return bba; } @@ -509,7 +511,7 @@ final class ExtractRecycleBin extends Extract { TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC, (short) (TskData.TSK_FS_META_FLAG_ENUM.UNALLOC.getValue() | TskData.TSK_FS_META_FLAG_ENUM.USED.getValue()), recycleBinFile.getSize(), - 0, 0, 0, deletedTime, + recycleBinFile.getCtime(), recycleBinFile.getCrtime(), recycleBinFile.getAtime(), deletedTime, true, parentDir); } From ef0446708d139310d5487fd87f6a2655aacdd02b Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 12 Sep 2019 09:44:38 -0400 Subject: [PATCH 16/27] cleaned up imports --- .../sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index f1f46677de..3fa746cf82 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -48,10 +48,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT; import org.sleuthkit.datamodel.BlackboardAttribute; -import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED; -import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_DELETED; -import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME; From bbaa32957d2376f33fae8da395d93cb536edb1ae Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 16 Sep 2019 11:24:03 -0400 Subject: [PATCH 17/27] Made the tag and hash hit filters generic --- .../autopsy/timeline/FilteredEventsModel.java | 44 ----------- .../timeline/ui/detailview/EventNodeBase.java | 54 +++++++------ .../filtering/datamodel/RootFilterState.java | 42 +++++----- .../filtering/datamodel/SqlFilterState.java | 9 +++ .../filtering/datamodel/TagsFilterState.java | 78 ------------------- 5 files changed, 56 insertions(+), 171 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/TagsFilterState.java diff --git a/Core/src/org/sleuthkit/autopsy/timeline/FilteredEventsModel.java b/Core/src/org/sleuthkit/autopsy/timeline/FilteredEventsModel.java index 457939f04c..c49c85049d 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/FilteredEventsModel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/FilteredEventsModel.java @@ -35,9 +35,7 @@ import javafx.beans.InvalidationListener; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.FXCollections; -import javafx.collections.ObservableList; import javafx.collections.ObservableMap; -import javafx.collections.ObservableSet; import static org.apache.commons.collections4.CollectionUtils.emptyIfNull; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; import org.joda.time.DateTimeZone; @@ -58,7 +56,6 @@ import org.sleuthkit.autopsy.timeline.events.TagsAddedEvent; import org.sleuthkit.autopsy.timeline.events.TagsDeletedEvent; import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.FilterState; import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.RootFilterState; -import org.sleuthkit.autopsy.timeline.ui.filtering.datamodel.TagsFilterState; import org.sleuthkit.autopsy.timeline.utils.CacheLoaderImpl; import org.sleuthkit.autopsy.timeline.utils.FilterUtils; import org.sleuthkit.autopsy.timeline.zooming.ZoomState; @@ -70,7 +67,6 @@ import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.Tag; -import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TimelineManager; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TimelineEvent; @@ -81,10 +77,8 @@ import org.sleuthkit.datamodel.TimelineFilter.DataSourcesFilter; import org.sleuthkit.datamodel.TimelineFilter.EventTypeFilter; import org.sleuthkit.datamodel.TimelineFilter.FileTypesFilter; import org.sleuthkit.datamodel.TimelineFilter.HashHitsFilter; -import org.sleuthkit.datamodel.TimelineFilter.HashSetFilter; import org.sleuthkit.datamodel.TimelineFilter.HideKnownFilter; import org.sleuthkit.datamodel.TimelineFilter.RootFilter; -import org.sleuthkit.datamodel.TimelineFilter.TagNameFilter; import org.sleuthkit.datamodel.TimelineFilter.TagsFilter; import org.sleuthkit.datamodel.TimelineFilter.TextFilter; @@ -129,8 +123,6 @@ public final class FilteredEventsModel { private final LoadingCache> eventCountsCache; /** Map from datasource id to datasource name. */ private final ObservableMap datasourcesMap = FXCollections.observableHashMap(); - private final ObservableSet< String> hashSets = FXCollections.observableSet(); - private final ObservableList tagNames = FXCollections.observableArrayList(); // end caches /** @@ -171,8 +163,6 @@ public final class FilteredEventsModel { }; datasourcesMap.addListener(filterSyncListener); - hashSets.addListener(filterSyncListener); - tagNames.addListener(filterSyncListener); requestedFilter.set(getDefaultFilter()); @@ -248,15 +238,11 @@ public final class FilteredEventsModel { */ synchronized private void populateFilterData() throws TskCoreException { SleuthkitCase skCase = autoCase.getSleuthkitCase(); - hashSets.addAll(eventManager.getHashSetNames()); //because there is no way to remove a datasource we only add to this map. for (DataSource ds : skCase.getDataSources()) { datasourcesMap.putIfAbsent(ds.getId(), ds.getName()); } - - //should this only be tags applied to files or event bearing artifacts? - tagNames.setAll(skCase.getTagNamesInUse()); } /** @@ -269,22 +255,8 @@ public final class FilteredEventsModel { * with the tags in use in the case */ public void syncFilters(RootFilterState rootFilterState) { - TagsFilterState tagsFilterState = rootFilterState.getTagsFilterState(); - for (TagName tagName : tagNames) { - tagsFilterState.getFilter().addSubFilter(new TagNameFilter(tagName)); - } - for (FilterState tagFilterState : rootFilterState.getTagsFilterState().getSubFilterStates()) { - // disable states for tag names that don't exist in case. - tagFilterState.setDisabled(tagNames.contains(tagFilterState.getFilter().getTagName()) == false); - } - DataSourcesFilter dataSourcesFilter = rootFilterState.getDataSourcesFilterState().getFilter(); datasourcesMap.entrySet().forEach(entry -> dataSourcesFilter.addSubFilter(newDataSourceFromMapEntry(entry))); - - HashHitsFilter hashSetsFilter = rootFilterState.getHashHitsFilterState().getFilter(); - for (String hashSet : hashSets) { - hashSetsFilter.addSubFilter(new HashSetFilter(hashSet)); - } } /** @@ -351,10 +323,8 @@ public final class FilteredEventsModel { -> dataSourcesFilter.addSubFilter(newDataSourceFromMapEntry(dataSourceEntry))); HashHitsFilter hashHitsFilter = new HashHitsFilter(); - hashSets.stream().map(HashSetFilter::new).forEach(hashHitsFilter::addSubFilter); TagsFilter tagsFilter = new TagsFilter(); - tagNames.stream().map(TagNameFilter::new).forEach(tagsFilter::addSubFilter); FileTypesFilter fileTypesFilter = FilterUtils.createDefaultFileTypesFilter(); @@ -388,20 +358,6 @@ public final class FilteredEventsModel { return events; } - /** - * get a count of tagnames applied to the given event ids as a map from - * tagname displayname to count of tag applications - * - * @param eventIDsWithTags the event ids to get the tag counts map for - * - * @return a map from tagname displayname to count of applications - * - * @throws org.sleuthkit.datamodel.TskCoreException - */ - public Map getTagCountsByTagName(Set eventIDsWithTags) throws TskCoreException { - return eventManager.getTagCountsByTagName(eventIDsWithTags); - } - public List getEventIDs(Interval timeRange, FilterState filter) throws TskCoreException { final Interval overlap; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java index 17c6e3c394..1977d3ce6d 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java @@ -269,7 +269,7 @@ public abstract class EventNodeBase extends StackP } /** - * defer tooltip content creation till needed, this had a surprisingly large + * defer tooltip content creation until needed, this had a surprisingly large * impact on speed of loading the chart */ @NbBundle.Messages({"# {0} - counts", @@ -293,37 +293,35 @@ public abstract class EventNodeBase extends StackP @Override protected String call() throws Exception { - HashMap hashSetCounts = new HashMap<>(); - if (tlEvent.getEventIDsWithHashHits().isEmpty() == false) { - try { - //TODO:push this to DB - for (TimelineEvent tle : eventsModel.getEventsById(tlEvent.getEventIDsWithHashHits())) { - Set hashSetNames = sleuthkitCase.getContentById(tle.getFileObjID()).getHashSetNames(); - for (String hashSetName : hashSetNames) { - hashSetCounts.merge(hashSetName, 1L, Long::sum); - } - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error getting hashset hit info for event.", ex); //NON-NLS - } - } - String hashSetCountsString = hashSetCounts.entrySet().stream() - .map((Map.Entry t) -> t.getKey() + " : " + t.getValue()) - .collect(Collectors.joining("\n")); +// HashMap hashSetCounts = new HashMap<>(); +// if (tlEvent.getEventIDsWithHashHits().isEmpty() == false) { +// try { +// //TODO:push this to DB +// for (TimelineEvent tle : eventsModel.getEventsById(tlEvent.getEventIDsWithHashHits())) { +// Set hashSetNames = sleuthkitCase.getContentById(tle.getFileObjID()).getHashSetNames(); +// for (String hashSetName : hashSetNames) { +// hashSetCounts.merge(hashSetName, 1L, Long::sum); +// } +// } +// } catch (TskCoreException ex) { +// LOGGER.log(Level.SEVERE, "Error getting hashset hit info for event.", ex); //NON-NLS +// } +// } +// String hashSetCountsString = hashSetCounts.entrySet().stream() +// .map((Map.Entry t) -> t.getKey() + " : " + t.getValue()) +// .collect(Collectors.joining("\n")); - Map tagCounts = new HashMap<>(); - if (tlEvent.getEventIDsWithTags().isEmpty() == false) { - tagCounts.putAll(eventsModel.getTagCountsByTagName(tlEvent.getEventIDsWithTags())); - } - String tagCountsString = tagCounts.entrySet().stream() - .map((Map.Entry t) -> t.getKey() + " : " + t.getValue()) - .collect(Collectors.joining("\n")); +// Map tagCounts = new HashMap<>(); +// if (tlEvent.getEventIDsWithTags().isEmpty() == false) { +// tagCounts.putAll(eventsModel.getTagCountsByTagName(tlEvent.getEventIDsWithTags())); +// } +// String tagCountsString = tagCounts.entrySet().stream() +// .map((Map.Entry t) -> t.getKey() + " : " + t.getValue()) +// .collect(Collectors.joining("\n")); return Bundle.EventNodeBase_tooltip_text(getEventIDs().size(), getEventType(), getDescription(), TimeLineController.getZonedFormatter().print(getStartMillis()), - TimeLineController.getZonedFormatter().print(getEndMillis() + 1000)) - + (hashSetCountsString.isEmpty() ? "" : Bundle.EventNodeBase_toolTip_hashSetHits(hashSetCountsString)) - + (tagCountsString.isEmpty() ? "" : Bundle.EventNodeBase_toolTip_tags(tagCountsString)); + TimeLineController.getZonedFormatter().print(getEndMillis() + 1000)); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/RootFilterState.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/RootFilterState.java index 66f53c8998..d33a32ed21 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/RootFilterState.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/RootFilterState.java @@ -35,21 +35,21 @@ import org.sleuthkit.datamodel.TimelineFilter.EventTypeFilter; import org.sleuthkit.datamodel.TimelineFilter.FileTypeFilter; import org.sleuthkit.datamodel.TimelineFilter.FileTypesFilter; import org.sleuthkit.datamodel.TimelineFilter.HashHitsFilter; -import org.sleuthkit.datamodel.TimelineFilter.HashSetFilter; import org.sleuthkit.datamodel.TimelineFilter.HideKnownFilter; import org.sleuthkit.datamodel.TimelineFilter.RootFilter; import org.sleuthkit.datamodel.TimelineFilter.TextFilter; +import org.sleuthkit.datamodel.TimelineFilter.TagsFilter; /** A FilterState for RootFilters. Provides named access to the sub - * filterstates. + * filter states. */ public class RootFilterState extends CompoundFilterState { private final CompoundFilterState eventTypeFilterState; private final SqlFilterState knownFilterState; private final SqlFilterState textFilterState; - private final TagsFilterState tagsFilterState; - private final CompoundFilterState hashHitsFilterState; + private final SqlFilterState tagsFilterState; + private final SqlFilterState hashHitsFilterState; private final CompoundFilterState dataSourcesFilterState; private final CompoundFilterState fileTypesFilterState; @@ -63,8 +63,8 @@ public class RootFilterState extends CompoundFilterState(delegate.getEventTypeFilter()), new SqlFilterState<>(delegate.getKnownFilter()), new SqlFilterState<>(delegate.getTextFilter()), - new TagsFilterState(delegate.getTagsFilter()), - new CompoundFilterState<>(delegate.getHashHitsFilter()), + new SqlFilterState<>(delegate.getTagsFilter()), + new SqlFilterState<>(delegate.getHashHitsFilter()), new CompoundFilterState<>(delegate.getDataSourcesFilter()), new CompoundFilterState<>(delegate.getFileTypesFilter()) ); @@ -74,8 +74,8 @@ public class RootFilterState extends CompoundFilterState eventTypeFilterState, SqlFilterState knownFilterState, SqlFilterState textFilterState, - TagsFilterState tagsFilterState, - CompoundFilterState hashHitsFilterState, + SqlFilterState tagsFilterState, + SqlFilterState hashHitsFilterState, CompoundFilterState dataSourcesFilterState, CompoundFilterState fileTypesFilterState) { super(filter, Arrays.asList(eventTypeFilterState, knownFilterState, textFilterState, tagsFilterState, hashHitsFilterState, dataSourcesFilterState, fileTypesFilterState)); @@ -133,11 +133,11 @@ public class RootFilterState extends CompoundFilterState getTagsFilterState() { return tagsFilterState; } - public CompoundFilterState getHashHitsFilterState() { + public SqlFilterState getHashHitsFilterState() { return hashHitsFilterState; } @@ -161,17 +161,17 @@ public class RootFilterState extends CompoundFilterState> getSubFilterStates() { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/SqlFilterState.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/SqlFilterState.java index 5180dd3425..2f33ebec61 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/SqlFilterState.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/SqlFilterState.java @@ -36,6 +36,15 @@ public class SqlFilterState extends AbstractF // the "Hide Known Filters", "Tags", "Hashsets" and "Text". // There are better ways to do this, but this works in a pinch this(filter, !(filter instanceof TimelineFilter.HideKnownFilter || filter instanceof TimelineFilter.TagsFilter || filter instanceof TimelineFilter.HashHitsFilter || filter instanceof TimelineFilter.TextFilter)); + + selectedProperty().addListener(selectedProperty -> { + if (filter instanceof TimelineFilter.TagsFilter) { + ((TimelineFilter.TagsFilter)filter).setTagged(isSelected()); + } else if (filter instanceof TimelineFilter.HashHitsFilter) { + ((TimelineFilter.HashHitsFilter)filter).setTagged(isSelected()); + } + }); + } /** diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/TagsFilterState.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/TagsFilterState.java deleted file mode 100755 index 12b17ed201..0000000000 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/TagsFilterState.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2018-2019 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.timeline.ui.filtering.datamodel; - -import com.google.common.collect.Lists; -import java.util.Collection; -import javafx.collections.ListChangeListener; -import org.sleuthkit.datamodel.TimelineFilter.TagNameFilter; -import org.sleuthkit.datamodel.TimelineFilter.TagsFilter; - -/** - * Specialization of CompoundFilterState for TagName/Tags-Filter. - * - * Newly added subfilters made to be SELECTED when they are added. - */ -public class TagsFilterState extends CompoundFilterState { - - public TagsFilterState(TagsFilter delegate) { - super(delegate); - installSelectNewFiltersListener(); - - } - - public TagsFilterState(TagsFilter delegate, Collection> subFilterStates) { - super(delegate, subFilterStates); - installSelectNewFiltersListener(); - } - - private void installSelectNewFiltersListener() { - getSubFilterStates().addListener((ListChangeListener.Change> change) -> { - while (change.next()) { - change.getAddedSubList().forEach(filterState -> filterState.setSelected(true)); - } - }); - } - - @Override - public TagsFilterState copyOf() { - TagsFilterState copy = new TagsFilterState(getFilter().copyOf(), - Lists.transform(getSubFilterStates(), FilterState::copyOf)); - - copy.setSelected(isSelected()); - copy.setDisabled(isDisabled()); - return copy; - } - - @Override - public TagsFilter getActiveFilter() { - if (isActive() == false) { - return null; - } - - TagsFilter copy = new TagsFilter(); - //add active subfilters to copy. - getSubFilterStates().stream() - .filter(FilterState::isActive) - .map(FilterState::getActiveFilter) - .forEach(copy::addSubFilter); - - return copy; - } -} From d48658407082c8e8ecda412f3529db59974046af Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Tue, 17 Sep 2019 09:04:58 -0400 Subject: [PATCH 18/27] Update Shellbag plugin to newer version Update Shellbag plugin to newer version in regripper --- thirdparty/rr-full/plugins/shellbags.pl | 299 ++++++++++++++---------- 1 file changed, 176 insertions(+), 123 deletions(-) diff --git a/thirdparty/rr-full/plugins/shellbags.pl b/thirdparty/rr-full/plugins/shellbags.pl index 5b8587af38..d8e770471e 100644 --- a/thirdparty/rr-full/plugins/shellbags.pl +++ b/thirdparty/rr-full/plugins/shellbags.pl @@ -3,6 +3,10 @@ # RR plugin to parse (Vista, Win7/Win2008R2) shell bags # # History: +# 20190715 - updated to parse WPD devices better +# 20180702 - update to parseGUID function +# 20180117 - modification thanks to input/data from Mike Godfrey +# 20160706 - update # 20150325 - updated parsing based on input from Eric Zimmerman # 20140728 - updated shell item 0x01 parsing # 20131216 - updated to support shell item type 0x52 @@ -31,7 +35,7 @@ # Moore for writing the shell bag parser for Registry Decoder, as well as # assistance with some parsing. # -# License: GPL v3 +# # copyright 2015 Quantum Analytics Research, LLC # Author: H. Carvey, keydet89@yahoo.com #----------------------------------------------------------- @@ -47,12 +51,12 @@ my %config = (hive => "USRCLASS\.DAT", hasShortDescr => 1, hasDescr => 0, hasRefs => 0, - version => 20150325); + version => 20190715); sub getConfig{return %config} sub getShortDescr { - return "Shell/BagMRU traversal in Win7 USRCLASS.DAT hives"; + return "Shell/BagMRU traversal in Win7+ USRCLASS\.DAT hives"; } sub getDescr{} sub getRefs {} @@ -90,6 +94,7 @@ my %cp_guids = ("{bb64f8a7-bee7-4e1a-ab8d-7d8273f7fdb6}" => "Action Center", "{a3dd4f92-658a-410f-84fd-6fbbbef2fffe}" => "Internet Options", "{a304259d-52b8-4526-8b1a-a1d6cecc8243}" => "iSCSI Initiator", "{725be8f7-668e-4c7b-8f90-46bdb0936430}" => "Keyboard", + "{bf782cc9-5a52-4a17-806c-2a894ffeeac5}" => "Language Settings", "{e9950154-c418-419e-a90a-20c5287ae24b}" => "Location and Other Sensors", "{1fa9085f-25a2-489b-85d4-86326eedcd87}" => "Manage Wireless Networks", "{6c8eec18-8d75-41b2-a177-8831d59d2d50}" => "Mouse", @@ -178,8 +183,8 @@ sub pluginmain { my $class = shift; my $hive = shift; ::logMsg("Launching shellbags v.".$VERSION); - ::rptMsg("shellbags v.".$VERSION); # banner - ::rptMsg("(".getHive().") ".getShortDescr()."\n"); # banner + ::rptMsg("shellbags v.".$VERSION); + ::rptMsg("(".getHive().") ".getShortDescr()."\n"); my %item = (); my $reg = Parse::Win32Registry->new($hive); @@ -226,6 +231,13 @@ sub traverse { my $type = unpack("C",substr($values{$v},2,1)); +# DEBUG ------------------------------------------------ +# ::rptMsg($key->get_path()."\\".$v); +# ::rptMsg(sprintf "Type = 0x%x",$type); +# probe($values{$v}); +# ::rptMsg(""); +# DEBUG ------------------------------------------------ + # Need to first check to see if the parent of the item was a zip folder # and if the 'zipsubfolder' value is set to 1 if (exists ${$parent}{zipsubfolder} && ${$parent}{zipsubfolder} == 1) { @@ -245,6 +257,9 @@ sub traverse { # System Folder %item = parseSystemFolderEntry($values{$v}); } + elsif ($type == 0x2a) { + $item{name} = substr($values{$v},0x3,3); + } elsif ($type == 0x2e) { # Device %item = parseDeviceEntry($values{$v}); @@ -374,11 +389,10 @@ sub parseVariableEntry { # Ref: http://msdn.microsoft.com/en-us/library/aa965725(v=vs.85).aspx my $stuff = $segs{"{b725f130-47ef-101a-a5f1-02608c9eebac}"}; - my $tag = 1; + my $t = 1; my $cnt = 0x10; - while($tag) { + while($t) { my $sz = unpack("V",substr($stuff,$cnt,4)); - return %item unless (defined $sz); my $id = unpack("V",substr($stuff,$cnt + 4,4)); #-------------------------------------------------------------- # sub-segment types @@ -388,14 +402,14 @@ sub parseVariableEntry { # 0x0c - size #-------------------------------------------------------------- if ($sz == 0x00) { - $tag = 0; + $t = 0; next; } elsif ($id == 0x0a) { my $num = unpack("V",substr($stuff,$cnt + 13,4)); my $str = substr($stuff,$cnt + 13 + 4,($num * 2)); - $str =~ s/\x00//g; + $str =~ s/\00//g; $item{name} = $str; } $cnt += $sz; @@ -406,24 +420,41 @@ sub parseVariableEntry { elsif (substr($data,4,4) eq "AugM") { %item = parseFolderEntry($data); } +# Code for Windows Portable Devices +# Added 20190715 + elsif (parseGUID(substr($data,42,16)) eq "{27e2e392-a111-48e0-ab0c-e17705a05f85}") { + my ($n0, $n1, $n2) = unpack("VVV",substr($data,62,12)); + + my $n0_name = substr($data,0x4A,($n0 * 2)); + $n0_name =~ s/\00//g; + + my $n1_name = substr($data,(0x4A + ($n0 * 2)),($n1 * 2)); + $n1_name =~ s/\00//g; + + if ($n0_name eq "") { + $item{name} = $n1_name; + } + else { + $item{name} = $n0_name; + } + } # Following two entries are for Device Property data elsif ($tag == 0x7b || $tag == 0xbb || $tag == 0xfb) { my ($sz1,$sz2,$sz3) = unpack("VVV",substr($data,0x3e,12)); $item{name} = substr($data,0x4a,$sz1 * 2); - $item{name} =~ s/\x00//g; + $item{name} =~ s/\00//g; } elsif ($tag == 0x02 || $tag == 0x03) { my ($sz1,$sz2,$sz3,$sz4) = unpack("VVVV",substr($data,0x26,16)); $item{name} = substr($data,0x36,$sz1 * 2); - $item{name} =~ s/\x00//g; + $item{name} =~ s/\00//g; } elsif (unpack("v",substr($data,6,2)) == 0x05) { my $o = 0x26; my $t = 1; while ($t) { my $i = substr($data,$o,1); - return %item unless (defined $i); - if ($i =~ m/\x00/) { + if ($i =~ m/\00/) { $t = 0; } else { @@ -447,7 +478,7 @@ sub parseNetworkEntry { my %item = (); $item{type} = unpack("C",substr($data,2,1)); - my @n = split(/\x00/,substr($data,4,length($data) - 4)); + my @n = split(/\00/,substr($data,4,length($data) - 4)); $item{name} = $n[0]; return %item; } @@ -464,13 +495,13 @@ sub parseZipSubFolderItem { # Get the opened/accessed date/time $item{datetime} = substr($data,0x24,6); - $item{datetime} =~ s/\x00//g; + $item{datetime} =~ s/\00//g; if ($item{datetime} eq "N/A") { } else { $item{datetime} = substr($data,0x24,40); - $item{datetime} =~ s/\x00//g; + $item{datetime} =~ s/\00//g; my ($date,$time) = split(/\s+/,$item{datetime},2); my ($mon,$day,$yr) = split(/\//,$date,3); my ($hr,$min,$sec) = split(/:/,$time,3); @@ -483,9 +514,9 @@ sub parseZipSubFolderItem { my $sz2 = unpack("V",substr($data,0x58,4)); my $str1 = substr($data,0x5C,$sz *2) if ($sz > 0); - $str1 =~ s/\x00//g; + $str1 =~ s/\00//g; my $str2 = substr($data,0x5C + ($sz * 2),$sz2 *2) if ($sz2 > 0); - $str2 =~ s/\x00//g; + $str2 =~ s/\00//g; if ($sz2 > 0) { $item{name} = $str1."\\".$str2; @@ -548,10 +579,10 @@ sub parseURIEntry { my $sz = unpack("V",substr($data,0x2a,4)); my $uri = substr($data,0x2e,$sz); - $uri =~ s/\x00//g; + $uri =~ s/\00//g; my $proto = substr($data,length($data) - 6, 6); - $proto =~ s/\x00//g; + $proto =~ s/\00//g; $item{name} = $proto."://".$uri." [".gmtime($item{uritime})."]"; @@ -601,8 +632,8 @@ sub parseGUID { my $d3 = unpack("v",substr($data,6,2)); my $d4 = unpack("H*",substr($data,8,2)); my $d5 = unpack("H*",substr($data,10,6)); - my $guid = sprintf "{%08x-%x-%x-$d4-$d5}",$d1,$d2,$d3; - + my $guid = sprintf "{%08x-%04x-%04x-$d4-$d5}",$d1,$d2,$d3; + if (exists $cp_guids{$guid}) { return "CLSID_".$cp_guids{$guid}; } @@ -625,6 +656,10 @@ sub parseDeviceEntry { my $ofs = unpack("v",substr($data,4,2)); my $tag = unpack("V",substr($data,6,4)); +#----------------------------------------------------- +# DEBUG +# ::rptMsg("parseDeviceEntry, tag = ".$tag); +#----------------------------------------------------- if ($tag == 0) { my $guid1 = parseGUID(substr($data,$ofs + 6,16)); my $guid2 = parseGUID(substr($data,$ofs + 6 + 16,16)); @@ -632,13 +667,17 @@ sub parseDeviceEntry { } elsif ($tag == 2) { $item{name} = substr($data,0x0a,($ofs + 6) - 0x0a); - $item{name} =~ s/\x00//g; + $item{name} =~ s/\00//g; } else { my $ver = unpack("C",substr($data,9,1)); - + my $idx = unpack("C",substr($data,3,1)); + + if ($idx == 0x80) { + $item{name} = parseGUID(substr($data,4,16)); + } # Version 3 = XP - if ($ver == 3) { + elsif ($ver == 3) { my $guid1 = parseGUID(substr($data,$ofs + 6,16)); my $guid2 = parseGUID(substr($data,$ofs + 6 + 16,16)); $item{name} = $guid1."\\".$guid2 @@ -649,14 +688,11 @@ sub parseDeviceEntry { my $userlen = unpack("V",substr($data,30,4)); my $devlen = unpack("V",substr($data,34,4)); my $user = substr($data,0x28,$userlen * 2); - $user =~ s/\x00//g; + $user =~ s/\00//g; my $dev = substr($data,0x28 + ($userlen * 2),$devlen * 2); - $dev =~ s/\x00//g; + $dev =~ s/\00//g; $item{name} = $user; - } - elsif (unpack("C",substr($data,3,1)) == 0x80) { - $item{name} = parseGUID(substr($data,4,16)); - } + } # Version unknown else { $item{name} = "Device Entry - Unknown Version"; @@ -697,7 +733,7 @@ sub parseControlPanelEntry { # #----------------------------------------------------------- sub parseFolderEntry { - my $data = shift; + my $data = shift; my %item = (); $item{type} = unpack("C",substr($data,2,1)); @@ -726,85 +762,105 @@ sub parseFolderEntry { my @m = unpack("vv",substr($data,$ofs_mdate,4)); ($item{mtime_str},$item{mtime}) = convertDOSDate($m[0],$m[1]); -# Need to read in short name; nul-term ASCII -# $item{shortname} = (split(/\x00/,substr($data,12,length($data) - 12),2))[0]; - $ofs_shortname = $ofs_mdate + 6; - my $tag = 1; - my $cnt = 0; - my $str = ""; - while($tag) { - my $s = substr($data,$ofs_shortname + $cnt,1); - return %item unless (defined $s); - if ($s =~ m/\x00/ && ((($cnt + 1) % 2) == 0)) { - $tag = 0; - } - else { - $str .= $s; - $cnt++; - } - } -# $str =~ s/\x00//g; - my $shortname = $str; - my $ofs = $ofs_shortname + $cnt + 1; -# Read progressively, 1 byte at a time, looking for 0xbeef - $tag = 1; - $cnt = 0; - while ($tag) { - my $s = substr($data,$ofs + $cnt,2); - return %item unless (defined $s); - if (unpack("v",$s) == 0xbeef) { - $tag = 0; - } - else { - $cnt++; - } - } - $item{extver} = unpack("v",substr($data,$ofs + $cnt - 4,2)); -# printf "Version: 0x%x\n",$item{extver}; - $ofs = $ofs + $cnt + 2; +# DEBUG ------------------------------------------------ +# Added 20160706 based on sample data provided by J. Poling - @m = unpack("vv",substr($data,$ofs,4)); - ($item{ctime_str},$item{ctime}) = convertDOSDate($m[0],$m[1]); - $ofs += 4; - @m = unpack("vv",substr($data,$ofs,4)); - ($item{atime_str},$item{atime}) = convertDOSDate($m[0],$m[1]); - - my $jmp; - if ($item{extver} == 0x03) { - $jmp = 8; - } - elsif ($item{extver} == 0x07) { - $jmp = 26; - } - elsif ($item{extver} == 0x08) { - $jmp = 30; - } - elsif ($item{extver} == 0x09) { - $jmp = 34; - } - else {} - - if ($item{type} == 0x31 && $item{extver} >= 0x07) { - my @n = unpack("Vvv",substr($data,$ofs + 8, 8)); - if ($n[2] != 0) { - $item{mft_rec_num} = getNum48($n[0],$n[1]); - $item{mft_seq_num} = $n[2]; -# ::rptMsg("MFT: ".$item{mft_rec_num}."/".$item{mft_seq_num}); -# probe($data); - } - } - - $ofs += $jmp; - - $str = substr($data,$ofs,length($data) - 30); - my $longname = (split(/\x00\x00/,$str,2))[0]; - $longname =~ s/\x00//g; - - if ($longname ne "") { - $item{name} = $longname; + if (length($data) < 0x30) { +# start at offset 0xE, read in nul-term ASCII string (until "\00" is reached) + $ofs_shortname = 0xE; + my $tag = 1; + my $cnt = 0; + my $str = ""; + while($tag) { + my $s = substr($data,$ofs_shortname + $cnt,1); + if ($s =~ m/\00/) { + $tag = 0; + } + else { + $str .= $s; + $cnt++; + } + } + $item{name} = $str; } else { - $item{name} = $shortname; +# Need to read in short name; nul-term ASCII +# $item{shortname} = (split(/\00/,substr($data,12,length($data) - 12),2))[0]; + $ofs_shortname = $ofs_mdate + 6; + my $tag = 1; + my $cnt = 0; + my $str = ""; + while($tag) { + my $s = substr($data,$ofs_shortname + $cnt,1); + if ($s =~ m/\00/ && ((($cnt + 1) % 2) == 0)) { + $tag = 0; + } + else { + $str .= $s; + $cnt++; + } + } +# $str =~ s/\00//g; + my $shortname = $str; + my $ofs = $ofs_shortname + $cnt + 1; +# Read progressively, 1 byte at a time, looking for 0xbeef + my $tag = 1; + my $cnt = 0; + while ($tag) { + if (unpack("v",substr($data,$ofs + $cnt,2)) == 0xbeef) { + $tag = 0; + } + else { + $cnt++; + } + } + $item{extver} = unpack("v",substr($data,$ofs + $cnt - 4,2)); +# printf "Version: 0x%x\n",$item{extver}; + $ofs = $ofs + $cnt + 2; + + my @m = unpack("vv",substr($data,$ofs,4)); + ($item{ctime_str},$item{ctime}) = convertDOSDate($m[0],$m[1]); + $ofs += 4; + my @m = unpack("vv",substr($data,$ofs,4)); + ($item{atime_str},$item{atime}) = convertDOSDate($m[0],$m[1]); + + my $jmp; + if ($item{extver} == 0x03) { + $jmp = 8; + } + elsif ($item{extver} == 0x07) { + $jmp = 26; + } + elsif ($item{extver} == 0x08) { + $jmp = 30; + } + elsif ($item{extver} == 0x09) { + $jmp = 34; + } + else {} + + if ($item{type} == 0x31 && $item{extver} >= 0x07) { + my @n = unpack("Vvv",substr($data,$ofs + 8, 8)); + if ($n[2] != 0) { + $item{mft_rec_num} = getNum48($n[0],$n[1]); + $item{mft_seq_num} = $n[2]; +# ::rptMsg("MFT: ".$item{mft_rec_num}."/".$item{mft_seq_num}); +# probe($data); + } + } + + $ofs += $jmp; + + my $str = substr($data,$ofs,length($data) - 30); + my $longname = (split(/\00\00/,$str,2))[0]; + $longname =~ s/\00//g; + + if ($longname ne "") { + $item{name} = $longname; + } + else { + $item{name} = $shortname; + } } return %item; } @@ -855,9 +911,7 @@ sub parseFolderEntry2 { my $tag = 1; while ($tag) { - my $s = substr($data,$ofs,2); - return %item unless (defined $s); - if (unpack("v",$s) == 0xbeef) { + if (unpack("v",substr($data,$ofs,2)) == 0xbeef) { $tag = 0; } else { @@ -894,9 +948,9 @@ sub parseFolderEntry2 { # } # ::rptMsg(""); - $item{name} = (split(/\x00\x00/,$str,2))[0]; - $item{name} =~ s/\x13\x20/\x2D\x00/; - $item{name} =~ s/\x00//g; + $item{name} = (split(/\00\00/,$str,2))[0]; + $item{name} =~ s/\13\20/\2D\00/; + $item{name} =~ s/\00//g; return %item; } @@ -907,7 +961,7 @@ sub parseNetworkEntry { my $data = shift; my %item = (); $item{type} = unpack("C",substr($data,2,1)); - my @names = split(/\x00/,substr($data,5,length($data) - 5)); + my @names = split(/\00/,substr($data,5,length($data) - 5)); $item{name} = $names[0]; return %item; } @@ -919,9 +973,9 @@ sub parseDatePathItem { my $data = shift; my %item = (); $item{datestr} = substr($data,0x18,30); - my ($file,$dir) = split(/\x00\x00/,substr($data,0x44,length($data) - 0x44)); - $file =~ s/\x00//g; - $dir =~ s/\x00//g; + my ($file,$dir) = split(/\00\00/,substr($data,0x44,length($data) - 0x44)); + $file =~ s/\00//g; + $dir =~ s/\00//g; $item{name} = $dir.$file; return %item; } @@ -958,7 +1012,6 @@ sub shellItem0x52 { while ($tag) { $d = substr($data,0x32 + $cnt,2); - return %item unless (defined $d); if (unpack("v",$d) == 0) { $tag = 0; } @@ -967,7 +1020,7 @@ sub shellItem0x52 { $cnt += 2; } } - $item{name} =~ s/\x00//g; + $item{name} =~ s/\00//g; if ($item{subtype} < 3) { $ofs = 0x32 + $cnt + 2; @@ -977,7 +1030,7 @@ sub shellItem0x52 { } $sz = unpack("V",substr($data,$ofs,4)); $item{str} = substr($data,$ofs + 4,$sz * 2); - $item{str} =~ s/\x00//g; + $item{str} =~ s/\00//g; return %item; } @@ -1058,4 +1111,4 @@ sub getNum48 { } } -1; +1; \ No newline at end of file From 12bd88e8d318cd22cab991e4caa6869f169b8eae Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 17 Sep 2019 10:59:45 -0400 Subject: [PATCH 19/27] Added bcpkix jar to fix NoClassDefFoundError. --- Core/nbproject/project.properties | 3 +- Core/nbproject/project.xml | 364 +++++++++++++++--------------- 2 files changed, 181 insertions(+), 186 deletions(-) diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index d9f4d9824a..d85eda3bc1 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -3,6 +3,7 @@ file.reference.apache-mime4j-core-0.8.2.jar=release\\modules\\ext\\apache-mime4j file.reference.apache-mime4j-dom-0.8.2.jar=release\\modules\\ext\\apache-mime4j-dom-0.8.2.jar file.reference.asm-7.0.jar=release\\modules\\ext\\asm-7.0.jar file.reference.bcmail-jdk15on-1.60.jar=release\\modules\\ext\\bcmail-jdk15on-1.60.jar +file.reference.bcpkix-jdk15on-1.60.jar=release\\modules\\ext\\bcpkix-jdk15on-1.60.jar file.reference.bcprov-jdk15on-1.60.jar=release\\modules\\ext\\bcprov-jdk15on-1.60.jar file.reference.boilerpipe-1.1.0.jar=release\\modules\\ext\\boilerpipe-1.1.0.jar file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar @@ -16,7 +17,6 @@ file.reference.commons-io-2.6.jar=release\\modules\\ext\\commons-io-2.6.jar file.reference.commons-lang3-3.8.1.jar=release\\modules\\ext\\commons-lang3-3.8.1.jar file.reference.commons-pool2-2.4.2.jar=release/modules/ext/commons-pool2-2.4.2.jar file.reference.cxf-rt-rs-client-3.3.0.jar=release\\modules\\ext\\cxf-rt-rs-client-3.3.0.jar -file.reference.dd-plist-1.20.jar=release/modules/ext/dd-plist-1.20.jar file.reference.dec-0.1.2.jar=release\\modules\\ext\\dec-0.1.2.jar file.reference.fontbox-2.0.13.jar=release\\modules\\ext\\fontbox-2.0.13.jar file.reference.geoapi-3.0.1.jar=release\\modules\\ext\\geoapi-3.0.1.jar @@ -55,7 +55,6 @@ file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-common file.reference.metadata-extractor-2.11.0.jar=release\\modules\\ext\\metadata-extractor-2.11.0.jar file.reference.netcdf4-4.5.5.jar=release\\modules\\ext\\netcdf4-4.5.5.jar file.reference.openjson-1.0.10.jar=release\\modules\\ext\\openjson-1.0.10.jar -file.reference.opennlp-tools-1.9.0.jar=release\\modules\\ext\\opennlp-tools-1.9.0.jar file.reference.parso-2.0.10.jar=release\\modules\\ext\\parso-2.0.10.jar file.reference.pdfbox-2.0.13.jar=release\\modules\\ext\\pdfbox-2.0.13.jar file.reference.pdfbox-tools-2.0.13.jar=release\\modules\\ext\\pdfbox-tools-2.0.13.jar diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 967399cc20..06fcd10d1b 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -350,49 +350,29 @@ release\modules\ext\commons-lang3-3.8.1.jar - ext/jempbox-1.8.16.jar - release\modules\ext\jempbox-1.8.16.jar - - - ext/jackcess-2.2.0.jar - release\modules\ext\jackcess-2.2.0.jar - - - ext/jericho-html-3.3.jar - release/modules/ext/jericho-html-3.3.jar + ext/gax-grpc-1.44.0.jar + release/modules/ext/gax-grpc-1.44.0.jar ext/cdm-4.5.5.jar release\modules\ext\cdm-4.5.5.jar - - ext/httpservices-4.5.5.jar - release\modules\ext\httpservices-4.5.5.jar - - - ext/xz-1.8.jar - release\modules\ext\xz-1.8.jar - - - ext/commons-validator-1.6.jar - release/modules/ext/commons-validator-1.6.jar - ext/sis-utility-0.8.jar release\modules\ext\sis-utility-0.8.jar - ext/jna-5.1.0.jar - release\modules\ext\jna-5.1.0.jar + ext/opencensus-api-0.19.2.jar + release/modules/ext/opencensus-api-0.19.2.jar + + + ext/gax-httpjson-0.61.0.jar + release/modules/ext/gax-httpjson-0.61.0.jar ext/boilerpipe-1.1.0.jar release\modules\ext\boilerpipe-1.1.0.jar - - ext/jbig2-imageio-3.0.2.jar - release\modules\ext\jbig2-imageio-3.0.2.jar - ext/jsoup-1.11.3.jar release\modules\ext\jsoup-1.11.3.jar @@ -401,22 +381,10 @@ ext/sevenzipjbinding.jar release/modules/ext/sevenzipjbinding.jar - - ext/apache-mime4j-dom-0.8.2.jar - release\modules\ext\apache-mime4j-dom-0.8.2.jar - ext/mchange-commons-java-0.2.9.jar release/modules/ext/mchange-commons-java-0.2.9.jar - - ext/pdfbox-2.0.13.jar - release\modules\ext\pdfbox-2.0.13.jar - - - ext/xmlbeans-3.0.2.jar - release\modules\ext\xmlbeans-3.0.2.jar - ext/jackson-databind-2.9.7.jar release\modules\ext\jackson-databind-2.9.7.jar @@ -425,41 +393,33 @@ ext/jai-imageio-core-1.4.0.jar release\modules\ext\jai-imageio-core-1.4.0.jar + + ext/api-common-1.7.0.jar + release/modules/ext/api-common-1.7.0.jar + ext/jcl-over-slf4j-1.7.25.jar release\modules\ext\jcl-over-slf4j-1.7.25.jar - ext/curator-recipes-2.8.0.jar - release/modules/ext/curator-recipes-2.8.0.jar + ext/okhttp-2.7.5.jar + release/modules/ext/okhttp-2.7.5.jar ext/tika-core-1.20.jar release\modules\ext\tika-core-1.20.jar - - ext/tagsoup-1.2.1.jar - release\modules\ext\tagsoup-1.2.1.jar - ext/StixLib.jar release/modules/ext/StixLib.jar - - ext/jackson-core-2.9.7.jar - release\modules\ext\jackson-core-2.9.7.jar - - - ext/sis-metadata-0.8.jar - release\modules\ext\sis-metadata-0.8.jar - ext/bcprov-jdk15on-1.60.jar release\modules\ext\bcprov-jdk15on-1.60.jar - ext/parso-2.0.10.jar - release\modules\ext\parso-2.0.10.jar + ext/google-auth-library-credentials-0.15.0.jar + release/modules/ext/google-auth-library-credentials-0.15.0.jar ext/json-simple-1.1.1.jar @@ -473,18 +433,10 @@ ext/commons-codec-1.11.jar release\modules\ext\commons-codec-1.11.jar - - ext/apache-mime4j-core-0.8.2.jar - release\modules\ext\apache-mime4j-core-0.8.2.jar - ext/jmatio-1.5.jar release\modules\ext\jmatio-1.5.jar - - ext/sleuthkit-postgresql-4.6.7.jar - release/modules/ext/sleuthkit-postgresql-4.6.7.jar - ext/tika-parsers-1.20.jar release\modules\ext\tika-parsers-1.20.jar @@ -497,18 +449,10 @@ ext/commons-pool2-2.4.2.jar release/modules/ext/commons-pool2-2.4.2.jar - - ext/commons-io-2.6.jar - release\modules\ext\commons-io-2.6.jar - ext/jdom-2.0.5-contrib.jar release/modules/ext/jdom-2.0.5-contrib.jar - - ext/SparseBitSet-1.1.jar - release/modules/ext/SparseBitSet-1.1.jar - ext/openjson-1.0.10.jar release\modules\ext\openjson-1.0.10.jar @@ -517,38 +461,18 @@ ext/isoparser-1.1.22.jar release\modules\ext\isoparser-1.1.22.jar - - ext/c3p0-0.9.5.jar - release/modules/ext/c3p0-0.9.5.jar - ext/xmpcore-5.1.3.jar release/modules/ext/xmpcore-5.1.3.jar - - ext/zookeeper-3.4.6.jar - release/modules/ext/zookeeper-3.4.6.jar - ext/javax.activation-1.2.0.jar release\modules\ext\javax.activation-1.2.0.jar - - ext/commons-csv-1.6.jar - release\modules\ext\commons-csv-1.6.jar - - - ext/jdom-2.0.5.jar - release/modules/ext/jdom-2.0.5.jar - ext/rome-1.12.0.jar release\modules\ext\rome-1.12.0.jar - - ext/jackson-annotations-2.9.7.jar - release\modules\ext\jackson-annotations-2.9.7.jar - ext/javax.annotation-api-1.3.2.jar release\modules\ext\javax.annotation-api-1.3.2.jar @@ -557,49 +481,25 @@ ext/vorbis-java-core-0.8.jar release\modules\ext\vorbis-java-core-0.8.jar - - ext/netcdf4-4.5.5.jar - release\modules\ext\netcdf4-4.5.5.jar - ext/java-libpst-0.8.1.jar release\modules\ext\java-libpst-0.8.1.jar - ext/opennlp-tools-1.9.0.jar - release\modules\ext\opennlp-tools-1.9.0.jar - - - ext/sis-netcdf-0.8.jar - release\modules\ext\sis-netcdf-0.8.jar + ext/okio-1.6.0.jar + release/modules/ext/okio-1.6.0.jar ext/curator-framework-2.8.0.jar release/modules/ext/curator-framework-2.8.0.jar - - ext/sentiment-analysis-parser-0.1.jar - release\modules\ext\sentiment-analysis-parser-0.1.jar - - - ext/commons-collections4-4.2.jar - release\modules\ext\commons-collections4-4.2.jar - ext/commons-dbcp2-2.1.1.jar release/modules/ext/commons-dbcp2-2.1.1.jar - ext/jgraphx-v3.8.0.jar - release/modules/ext/jgraphx-v3.8.0.jar - - - ext/juniversalchardet-1.0.3.jar - release\modules\ext\juniversalchardet-1.0.3.jar - - - ext/jython-standalone-2.7.0.jar - release/modules/ext/jython-standalone-2.7.0.jar + ext/google-http-client-appengine-1.29.0.jar + release/modules/ext/google-http-client-appengine-1.29.0.jar ext/uimafit-core-2.4.0.jar @@ -609,26 +509,26 @@ ext/jackcess-encrypt-2.1.4.jar release\modules\ext\jackcess-encrypt-2.1.4.jar - - ext/jhighlight-1.0.3.jar - release\modules\ext\jhighlight-1.0.3.jar - ext/junrar-2.0.0.jar release\modules\ext\junrar-2.0.0.jar - ext/jul-to-slf4j-1.7.25.jar - release\modules\ext\jul-to-slf4j-1.7.25.jar + ext/google-http-client-1.29.0.jar + release/modules/ext/google-http-client-1.29.0.jar - ext/postgresql-9.4.1211.jre7.jar - release/modules/ext/postgresql-9.4.1211.jre7.jar + ext/bcpkix-jdk15on-1.60.jar + release\modules\ext\bcpkix-jdk15on-1.60.jar ext/slf4j-api-1.7.25.jar release\modules\ext\slf4j-api-1.7.25.jar + + ext/google-cloud-core-1.70.0.jar + release/modules/ext/google-cloud-core-1.70.0.jar + ext/geoapi-3.0.1.jar release\modules\ext\geoapi-3.0.1.jar @@ -641,18 +541,10 @@ ext/jdom2-2.0.6.jar release\modules\ext\jdom2-2.0.6.jar - - ext/httpclient-4.5.6.jar - release\modules\ext\httpclient-4.5.6.jar - ext/uimaj-core-3.0.1.jar release\modules\ext\uimaj-core-3.0.1.jar - - ext/curator-client-2.8.0.jar - release/modules/ext/curator-client-2.8.0.jar - ext/sqlite-jdbc-3.25.2.jar release/modules/ext/sqlite-jdbc-3.25.2.jar @@ -670,65 +562,133 @@ release\modules\ext\grib-4.5.5.jar - ext/fontbox-2.0.13.jar - release\modules\ext\fontbox-2.0.13.jar + ext/gax-1.44.0.jar + release/modules/ext/gax-1.44.0.jar - ext/activemq-all-5.11.1.jar - release/modules/ext/activemq-all-5.11.1.jar + ext/jempbox-1.8.16.jar + release\modules\ext\jempbox-1.8.16.jar - ext/dec-0.1.2.jar - release\modules\ext\dec-0.1.2.jar - - - ext/Rejistry-1.1-SNAPSHOT.jar - release/modules/ext/Rejistry-1.1-SNAPSHOT.jar - - - ext/dd-plist-1.20.jar - release/modules/ext/dd-plist-1.20.jar - - - ext/sevenzipjbinding-AllPlatforms.jar - release/modules/ext/sevenzipjbinding-AllPlatforms.jar - - - ext/bcmail-jdk15on-1.60.jar - release\modules\ext\bcmail-jdk15on-1.60.jar - - - ext/vorbis-java-tika-0.8.jar - release\modules\ext\vorbis-java-tika-0.8.jar + ext/jackcess-2.2.0.jar + release\modules\ext\jackcess-2.2.0.jar ext/grpc-context-1.19.0.jar release/modules/ext/grpc-context-1.19.0.jar - ext/gax-grpc-1.44.0.jar - release/modules/ext/gax-grpc-1.44.0.jar + ext/jericho-html-3.3.jar + release/modules/ext/jericho-html-3.3.jar - ext/opencensus-api-0.19.2.jar - release/modules/ext/opencensus-api-0.19.2.jar + ext/httpservices-4.5.5.jar + release\modules\ext\httpservices-4.5.5.jar - ext/gax-httpjson-0.61.0.jar - release/modules/ext/gax-httpjson-0.61.0.jar + ext/xz-1.8.jar + release\modules\ext\xz-1.8.jar - ext/api-common-1.7.0.jar - release/modules/ext/api-common-1.7.0.jar + ext/commons-validator-1.6.jar + release/modules/ext/commons-validator-1.6.jar - ext/google-auth-library-credentials-0.15.0.jar - release/modules/ext/google-auth-library-credentials-0.15.0.jar + ext/jna-5.1.0.jar + release\modules\ext\jna-5.1.0.jar + + + ext/jbig2-imageio-3.0.2.jar + release\modules\ext\jbig2-imageio-3.0.2.jar + + + ext/sleuthkit-postgresql-4.6.7.jar + release/modules/ext/sleuthkit-postgresql-4.6.7.jar + + + ext/apache-mime4j-dom-0.8.2.jar + release\modules\ext\apache-mime4j-dom-0.8.2.jar + + + ext/pdfbox-2.0.13.jar + release\modules\ext\pdfbox-2.0.13.jar + + + ext/xmlbeans-3.0.2.jar + release\modules\ext\xmlbeans-3.0.2.jar + + + ext/curator-recipes-2.8.0.jar + release/modules/ext/curator-recipes-2.8.0.jar + + + ext/tagsoup-1.2.1.jar + release\modules\ext\tagsoup-1.2.1.jar + + + ext/jackson-core-2.9.7.jar + release\modules\ext\jackson-core-2.9.7.jar + + + ext/sis-metadata-0.8.jar + release\modules\ext\sis-metadata-0.8.jar + + + ext/parso-2.0.10.jar + release\modules\ext\parso-2.0.10.jar + + + ext/apache-mime4j-core-0.8.2.jar + release\modules\ext\apache-mime4j-core-0.8.2.jar + + + ext/commons-io-2.6.jar + release\modules\ext\commons-io-2.6.jar + + + ext/SparseBitSet-1.1.jar + release/modules/ext/SparseBitSet-1.1.jar + + + ext/c3p0-0.9.5.jar + release/modules/ext/c3p0-0.9.5.jar + + + ext/zookeeper-3.4.6.jar + release/modules/ext/zookeeper-3.4.6.jar + + + ext/commons-csv-1.6.jar + release\modules\ext\commons-csv-1.6.jar + + + ext/jdom-2.0.5.jar + release/modules/ext/jdom-2.0.5.jar + + + ext/jackson-annotations-2.9.7.jar + release\modules\ext\jackson-annotations-2.9.7.jar ext/google-api-client-1.27.0.jar release/modules/ext/google-api-client-1.27.0.jar + + ext/netcdf4-4.5.5.jar + release\modules\ext\netcdf4-4.5.5.jar + + + ext/sis-netcdf-0.8.jar + release\modules\ext\sis-netcdf-0.8.jar + + + ext/sentiment-analysis-parser-0.1.jar + release\modules\ext\sentiment-analysis-parser-0.1.jar + + + ext/commons-collections4-4.2.jar + release\modules\ext\commons-collections4-4.2.jar + ext/opencensus-contrib-http-util-0.19.2.jar release/modules/ext/opencensus-contrib-http-util-0.19.2.jar @@ -738,21 +698,57 @@ release/modules/ext/google-auth-library-oauth2-http-0.15.0.jar - ext/google-http-client-appengine-1.29.0.jar - release/modules/ext/google-http-client-appengine-1.29.0.jar + ext/jgraphx-v3.8.0.jar + release/modules/ext/jgraphx-v3.8.0.jar - ext/google-http-client-1.29.0.jar - release/modules/ext/google-http-client-1.29.0.jar + ext/juniversalchardet-1.0.3.jar + release\modules\ext\juniversalchardet-1.0.3.jar - ext/google-cloud-core-1.70.0.jar - release/modules/ext/google-cloud-core-1.70.0.jar + ext/jython-standalone-2.7.0.jar + release/modules/ext/jython-standalone-2.7.0.jar + + + ext/jhighlight-1.0.3.jar + release\modules\ext\jhighlight-1.0.3.jar + + + ext/jul-to-slf4j-1.7.25.jar + release\modules\ext\jul-to-slf4j-1.7.25.jar + + + ext/postgresql-9.4.1211.jre7.jar + release/modules/ext/postgresql-9.4.1211.jre7.jar + + + ext/httpclient-4.5.6.jar + release\modules\ext\httpclient-4.5.6.jar + + + ext/curator-client-2.8.0.jar + release/modules/ext/curator-client-2.8.0.jar + + + ext/fontbox-2.0.13.jar + release\modules\ext\fontbox-2.0.13.jar + + + ext/activemq-all-5.11.1.jar + release/modules/ext/activemq-all-5.11.1.jar ext/google-cloud-core-http-1.70.0.jar release/modules/ext/google-cloud-core-http-1.70.0.jar + + ext/Rejistry-1.1-SNAPSHOT.jar + release/modules/ext/Rejistry-1.1-SNAPSHOT.jar + + + ext/dec-0.1.2.jar + release\modules\ext\dec-0.1.2.jar + ext/google-http-client-jackson2-1.29.0.jar release/modules/ext/google-http-client-jackson2-1.29.0.jar @@ -766,20 +762,20 @@ release/modules/ext/google-cloud-translate-1.70.0.jar - ext/gax-1.44.0.jar - release/modules/ext/gax-1.44.0.jar + ext/sevenzipjbinding-AllPlatforms.jar + release/modules/ext/sevenzipjbinding-AllPlatforms.jar ext/google-api-services-translate-v2-rev20170525-1.27.0.jar release/modules/ext/google-api-services-translate-v2-rev20170525-1.27.0.jar - ext/okhttp-2.7.5.jar - release/modules/ext/okhttp-2.7.5.jar + ext/bcmail-jdk15on-1.60.jar + release\modules\ext\bcmail-jdk15on-1.60.jar - ext/okio-1.6.0.jar - release/modules/ext/okio-1.6.0.jar + ext/vorbis-java-tika-0.8.jar + release\modules\ext\vorbis-java-tika-0.8.jar From d99a8822456744aeac12c129ce3c2738e341d981 Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 17 Sep 2019 11:59:28 -0400 Subject: [PATCH 20/27] Updated version of opennlp-tools. --- Core/nbproject/project.properties | 1 + Core/nbproject/project.xml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index d85eda3bc1..945b30562a 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -55,6 +55,7 @@ file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-common file.reference.metadata-extractor-2.11.0.jar=release\\modules\\ext\\metadata-extractor-2.11.0.jar file.reference.netcdf4-4.5.5.jar=release\\modules\\ext\\netcdf4-4.5.5.jar file.reference.openjson-1.0.10.jar=release\\modules\\ext\\openjson-1.0.10.jar +file.reference.opennlp-tools-1.9.1.jar=release\\modules\\ext\\opennlp-tools-1.9.1.jar file.reference.parso-2.0.10.jar=release\\modules\\ext\\parso-2.0.10.jar file.reference.pdfbox-2.0.13.jar=release\\modules\\ext\\pdfbox-2.0.13.jar file.reference.pdfbox-tools-2.0.13.jar=release\\modules\\ext\\pdfbox-tools-2.0.13.jar diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 06fcd10d1b..53c318a22b 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -521,6 +521,10 @@ ext/bcpkix-jdk15on-1.60.jar release\modules\ext\bcpkix-jdk15on-1.60.jar + + ext/opennlp-tools-1.9.1.jar + release\modules\ext\opennlp-tools-1.9.1.jar + ext/slf4j-api-1.7.25.jar release\modules\ext\slf4j-api-1.7.25.jar From 643f53368e224eeaa7e26c13db4a6f92bdb0d839 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 17 Sep 2019 14:38:58 -0400 Subject: [PATCH 21/27] Doxygen fixes --- .../autopsy/casemodule/services/Services.java | 2 +- .../autopsy/coreutils/AppDBParserHelper.java | 14 +++++++------- .../sleuthkit/autopsy/coreutils/AppSQLiteDB.java | 6 +++--- .../org/sleuthkit/autopsy/coreutils/ExecUtil.java | 2 +- .../report/caseuco/CaseUcoFormatExporter.java | 4 ++-- .../autopsy/timeline/actions/AddManualEvent.java | 1 + .../ui/detailview/datamodel/DetailsViewModel.java | 1 + .../filtering/datamodel/CompoundFilterState.java | 2 -- .../ui/listvew/datamodel/CombinedEvent.java | 1 - .../autopsy/timeline/utils/TimelineDBUtils.java | 2 +- .../ThunderbirdMboxFileIngestModule.java | 2 +- 11 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java index 02f98f2887..81bc6a643c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java @@ -80,7 +80,7 @@ public class Services implements Closeable { /** * Gets the artifacts blackboard for the current case. * - * @return @org.sleuthkit.datamodel.Blackboard Blackboard for the current + * @return org.sleuthkit.datamodel.Blackboard Blackboard for the current * case. */ public org.sleuthkit.datamodel.Blackboard getArtifactsBlackboard() { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/AppDBParserHelper.java b/Core/src/org/sleuthkit/autopsy/coreutils/AppDBParserHelper.java index 538ea07098..01771f0581 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/AppDBParserHelper.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/AppDBParserHelper.java @@ -283,8 +283,8 @@ public final class AppDBParserHelper { /** * Adds a relations between the two specified account instances. * - * @param selfAccount device owner account - * @param otherAccount other account + * @param selfAccountInstance device owner account + * @param otherAccountInstance other account * @param sourceArtifact artifact from which relationship is derived. * @param relationshipType type of relationship * @param dateTime date/time of relationship @@ -316,7 +316,7 @@ public final class AppDBParserHelper { * @param readStatus message read or not * @param subject message subject, may be empty * @param messageText message body, may be empty - * @param threadId, message thread id + * @param threadId message thread id * * @return message artifact */ @@ -347,7 +347,7 @@ public final class AppDBParserHelper { * @param readStatus message read or not * @param subject message subject, may be empty * @param messageText message body, may be empty - * @param threadId, message thread id + * @param threadId message thread id * * @param otherAttributesList additional attributes * @@ -385,7 +385,7 @@ public final class AppDBParserHelper { * @param readStatus message read or not * @param subject message subject, may be empty * @param messageText message body, may be empty - * @param threadId, message thread id + * @param threadId message thread id * * * @return message artifact @@ -867,7 +867,7 @@ public final class AppDBParserHelper { * @param accessTime last access time * @param referrer referrer, may be empty * @param title website title, may be empty - * @param programName, application recording the history + * @param programName application recording the history * * @return artifact created */ @@ -884,7 +884,7 @@ public final class AppDBParserHelper { * @param accessTime last access time * @param referrer referrer, may be empty * @param title website title, may be empty - * @param programName, application recording the history + * @param programName application recording the history * @param otherAttributesList other attributes * * diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java b/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java index 6812f6daf3..bb8a1ed227 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/AppSQLiteDB.java @@ -95,8 +95,8 @@ public final class AppSQLiteDB implements Closeable { * AppSQLiteDB to help query the DB. * * A list of AppSQLiteDB instances is returned, one for each - * match found., - * . + * match found. + * * @param dataSource data source to search in * @param dbName db file name to search * @param matchExactName whether to look for exact file name or a pattern match @@ -174,7 +174,7 @@ public final class AppSQLiteDB implements Closeable { * @param dbName db file name to search * @param matchExactName whether to look for exact file name or a pattern match * @param dbPath path to match - * @param matchExactName whether to look for exact path name or a substring match + * @param matchExactPath whether to look for exact path name or a substring match * * @return a collection of AppSQLiteDBFileBundle * diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java index 9a211c57a0..022b507212 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ExecUtil.java @@ -206,7 +206,7 @@ public final class ExecUtil { * @param terminator The ProcessTerminator used to determine if the process * should be killed. * - * @returnthe exit value of the process + * @return the exit value of the process * * @throws SecurityException if a security manager exists and vetoes any * aspect of running the process. diff --git a/Core/src/org/sleuthkit/autopsy/report/caseuco/CaseUcoFormatExporter.java b/Core/src/org/sleuthkit/autopsy/report/caseuco/CaseUcoFormatExporter.java index 03bffed89d..d3ab17ffe9 100755 --- a/Core/src/org/sleuthkit/autopsy/report/caseuco/CaseUcoFormatExporter.java +++ b/Core/src/org/sleuthkit/autopsy/report/caseuco/CaseUcoFormatExporter.java @@ -198,7 +198,7 @@ public final class CaseUcoFormatExporter { } /** - * Exports files that are tagged w/ the following TagNames and that belong to + * Exports files that are tagged with the following TagNames and that belong to * the following interesting file sets (set name attributes of TSK_INTERSTING_FILE_HIT * and TSK_INTERESTING_ARTIFACT_HIT). Artifacts that are tagged with * the following TagNames also have their associated source files included. @@ -208,7 +208,7 @@ public final class CaseUcoFormatExporter { * @param tagTypes Collection of TagNames to match * @param interestingItemSets Collection of SET_NAMEs to match on in TSK_INTERESTING_FILE_HITs * and TSK_INTERESTING_ARTIFACT_HITs. - * @param outputFilePath Path to the folder that the CASE-UCO report should be written into + * @param caseReportFolder Path to the folder that the CASE-UCO report should be written into * @param progressPanel UI Component to be updated with current processing status */ @NbBundle.Messages({ diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/AddManualEvent.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/AddManualEvent.java index 5d02925db9..33220b173a 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/AddManualEvent.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/AddManualEvent.java @@ -127,6 +127,7 @@ public class AddManualEvent extends Action { * Use the supplied ManualEventInfo to make an TSK_TL_EVENT artifact which * will trigger adding a TimelineEvent. * + * @param controller * @param eventInfo The ManualEventInfo with the info needed to create an * event. * diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/datamodel/DetailsViewModel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/datamodel/DetailsViewModel.java index 8bb257867c..f37cce6035 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/datamodel/DetailsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/datamodel/DetailsViewModel.java @@ -102,6 +102,7 @@ final public class DetailsViewModel { } /** + * @param uiFilter * @param zoom * * @return a list of aggregated events that are within the requested time diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/CompoundFilterState.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/CompoundFilterState.java index 6723242141..e85fabe4da 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/CompoundFilterState.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/CompoundFilterState.java @@ -121,8 +121,6 @@ public class CompoundFilterState eventMap) { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/utils/TimelineDBUtils.java b/Core/src/org/sleuthkit/autopsy/timeline/utils/TimelineDBUtils.java index 5c67852ae5..5fde45aa13 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/utils/TimelineDBUtils.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/utils/TimelineDBUtils.java @@ -63,7 +63,7 @@ public class TimelineDBUtils { * into a set of X using the mapper to convert from string to X. If * groupConcat is empty, null, or all whitespace, returns an empty list. * - * @param the type of elements to return + * X the type of elements to return * @param groupConcat a string containing the group_concat result ( a comma * separated list) * @param mapper a function from String to X diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java index f428b455cf..3f1daa1a1c 100644 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/ThunderbirdMboxFileIngestModule.java @@ -411,7 +411,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule { * appropriate artifacts and derived files. * * @param partialEmailsForThreading - * @param fileMessageIterator + * @param fullMessageIterator * @param abstractFile */ private void processEmails(List partialEmailsForThreading, Iterator fullMessageIterator, AbstractFile abstractFile) { From 5e3a283658e2d9b9d6dd61ff9404cd86d0e63e5b Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 17 Sep 2019 14:54:15 -0400 Subject: [PATCH 22/27] Updated carved files icon --- docs/doxygen-user/images/photorec_output.PNG | Bin 82308 -> 83724 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/doxygen-user/images/photorec_output.PNG b/docs/doxygen-user/images/photorec_output.PNG index 168e8b0272b8429f465c5fdda15db20cba016efd..566e6a4652f827ea48bbd1f045552f49e8823bfc 100644 GIT binary patch delta 63479 zcma%iWl$YU7j1$Ef&>UI0fM``YjA?Qy9d_^?ht~zJHZ`-26uN4?(Xo0d++zE-oICM z&W|J0J>9)!?X~v!`$30CLjO>J-+cE0m6g8y0{gmBvqK)ZxUDPWdU^2L;*~OV$&*?j zt5jky^7;AGfLS=HUj-X7A8qtKGBZa_w}m2nG;XJKzFS}mMAEGPlq94Kz;rZrnRWUe zsr$4+Ws;1U;XRv-=E4S<^5?}bm|v@=ALy1J9<#bt&*Nz3t2VbDynmPd@^C!9@jl^H zow!>%QTJ>Gf?tY@vx{-Oc;}<9(IX}cdX9#jI*6S@a_eDg7XDmD8g%4 z5gm-gU`x&ui07Pw%^r&s!#D=KkS`!>`*H zci|Z{rl!oc+UBn8%*<#plm=c3BN_a1va(1QJEIxQh*yc0PYTn4yGzix`IiHb(qcs3dh72t!Dd{UD z&{;|zmw_v)AoBR{O?{@a%kEwK`}Z#c1A~CGv-42F(8cy}%vb5UvB^nnEUZuDl1|4BNp z{l6=q1QRK9o0n}Uq5l~G97AO7pVN8$r!;wPSn_|Dz*WP%2tc zc-;j%#@nNMe)0eYzq>)(7fE<(pv6&d6boT6!4+h zKcb_3fNYAdi{RyxiN{23=$-G4^i7h{!OzvgYi7w}rl#cP=H{Ne!i2=k%nqF+g~bEl z&h`%sNQQhGXF<#u?HwCK0nd^6+kflRk7qvq0s~H3U!SnFq{YO}GD-Hc#2v#`jntz{)*WWgRM z0_V~{A8+wckBJ*0Z92jYs)@cio|8I&YFkw_CjZb37^X?RJR9ASf_uA|G=`O0+2nQi z z9+yTDo#jMlX60uGyEp4l&H=lFYv3@$uSB#P&ZHJ_S3BX*GqB~rLJq4#)96o{$WxeGkzsT>nG)*yTei|(7k_b^u=@lt;}?Sh## zMd_XpZ}_|c8YcrMgsGWXFg~~Q>Gh(m!_(C)Gw=)^LS@uh0KKRF(6RZMh@x5ZcCux| zVb!37loSayb=b;^&XNtgcN-u{M*r$@bi{YirMFM-G_K6sR(*Fax&TK+z7Y+i%DZ?p zD}1bc%Q5kt6x`eH-%&77e+s15RedhY1PLFGS*rI!cuVj95a{4yZFiT~SKP(Zmcnhj zS-UXf5^%8W;~mJDuvtG)@!uPt{>Jp~k2-csgdGYQo++y33AMH)g7xDg(6aYsBjxW* z==zv|tCbNoqU#k$cm%k|VqD$9>2j|wbx}2PgSSZ5iX`jkXyode_`1~Rhm&g8GlT8n zlwNZFyDu}pG{tpwbtkUFPamGNT$Y`33kn>zhmzo;9WI91qxQ?lAjCn7yPxD^aL329 zmgp`Q+WDSwz2?%KU-Uk6f*Z@z7Ui+TS@DdL{|FLZzx?nAy)xJGu0KVFaORYodq zcKe(-dWvV=d$(B}&EsZyY_K(>dm1LgE}9A{@Gxb1x3S~hK~JC#Ir{vAKHi&u1LwUL za-Oya+TdJgpj8|se$?6CK4E*NWb<=k7S^mwT2frG*3Zr_LssA5X`0P%D<2IcBayMbI0}hbZ4!|L+u2M zlP~{dp|A2~hOwRQ2xakGbCH$itcKHKPiysmGf#^tPDz_`qxmicsHvBQWU2q^A=I^Mlde-<;0Q!0P@+=?LYeUP#3L$|F@{lz`=M_pL{aw>GHk2Z z!I}4Z{F@6!`Rz5EooUJC(%+XWfcJ=jLAFlFC?l+Z&UY3fCxS<4*)oL4zSQ36u(JUl z_oJ`ze1KZ~#Y__FAA3Z=^DDQIfxg;RdFHaUWY}_k-rDj$?pGZHGz1XeWvrdOMLW1V z9&DaJJ;RIlfB$P?IC_WhFLjh?{)?A2fAfrI8Z1@SeB#aLdhZ(&+&@;MLU!GPKH8sO}H#<≦hpGH=LV`N=w60IL8Z%Ls$9Te-w@GgrU$T=L7cp zQEEaAvfQ058s@r}m(XyxokDJfwiZfVmIC4lwG)VI^NE%g#2@VW4e#dvH*5Jm_MjFwrV8fLI1yl!%@_3dH5iAVA#y^CrZm=ume1<^i-UA`%i| zsL1~?-q72gru(xA{bs(Hdu5kxiKlxqi;h~jH%b8eUP>>>q zTYq1lgqfC1HlK-+(T}7g%74-g%$Rc_(oqc1@pM2a=jJD8xjcFwx5!Z}wdh*mC5ih- zEMi`M;klQE&FfJY^?Y-6dJ%&%Ykj+nAz;6=}YG-OivZPwz@$Z|`vCnxUvU*6o#ih_=gVb$a1avEha< zaX!lwoKN6waMW0SKZsm+(TPL)Y2f_W^yOaIN+Un~{N{993xaE#G94bi3zqjlz0sNz zc5$%_;^cID7;i>J9ImyfOcmg@)P;lN6h!$t=--Kx6#^rq@UyhE^qn;by(sI!V$mMu;4Ut;y;)tr*YstvjsB&e%G&E zpD_bP_=9qg&3<=U8*lZA<5x0j(*<2OPpg>Wf? z^QDV&CB>p~vu4e}hi5YTD1=TeVb+-qNU;2kV|n+JSo4dV7;y3*E_JE;ms%A z5_bIa=SR+>T2ehNll632!*d!`e1x&-G@XvyO6u(y40#gpLigs)r#D|j1eJ{2W?Nv4 z4e74L@k-TmO3)(p*c(Q!VS6#mH5K*Ck5HUq&u%9ufRCgV-V^r7)_DqdQFNx3;oqlT zx2%$qf(o?GlLzsJmkxm>_qw{tO7>5o1_=Qjzt25WAMBOVV4Di}n)A&U^bMP%%&ivc zQvHsC)PNicyp(cOh&}g? z^=EGZt*|k2i4=QP)-#;PZ0Wkhlf5(V?)SQ0Afo)jr%$Zu16nPn+3l>t^?ufA?f#SU z%;A>uC}`&#@Zk8k$T0pBR0vWAw=5R#C#j@9{j9RUL@twUcggX{Qx5au$C*|>c>X{{ zctW6cjU9hMZ`DV_kZy6Jb4UEapYccZ&8xqOice~s;pqk#e?f&!JO6V85sP9?5D5g~ zbb_8_;gK1psJA$XGbwt!QF>$hGm=pGx`fbZ_RJm0GN_230M!Le58@ia(AL?|&B^F6 zV*GcN)g;0?odxWCd(#eP#iJR1(1Jlo3fF)R;#93d!f!^ej8c#8_G67njcaGeu@xOj zFC87pWbEA#p zgEtqDrtKXK%_U(f#cweWt7>e*dwyk?W;t#uP8~d{+l25lYbecA4=~Ln;1{gujGk3p z`4}ejG>kyuTy54C)E=99#WpaW*E_v5ow^oAJ9z(ub?K;!yAD3*YH9 z2fEdI9S}wMAV}lPu@%dIl)0R*$u8}%Kjl1E+5SMVjABV66&zfNQZjdC;Zbqc0@GX4 ztOf=+t+ZdNJ&B#F3P5($VqeGgyUV1oy;U_g;X7pewoSdYFKs^j>*`bAZ~cxR5H=q{sBY89z(gHdO9v$vobDwPvqL?zufC|W|4kZ>%fCOO|#*uRCsvFLfy|L zYZBwrPNpQDFDM({>0tWpY$F{ZPuD*XP9fV8DUi$9F46t3#nVd=0)x`akD(VeAnT3DNFLvw-&sNmu_=R!K#%61I5~AKX42L(axIR-^ z0@uVBVefq3D01|-gIKL^@ONxShae0rY~#MLs)$wAWvbi7Pc#nqA!i)kX_gbmHRzT| z19Z`MHr*U8Z*=fJDzmUE>nos#;;&%cWmD#UDm5+T5QZN($mH-WMO3Bu#jyt2C9*%8|t_bvzlrl|7TP!@!(u z8OaH(y-7r%uqw`hu2{ewKkRT!Ks1g*Xr2sx5@4gCqrmeadCtmUDu2eHZA*>^UrIn}miXzf~( zobjh;J~a|4?u1rXc^pS7smVdU8}Lgy6_SLkpuvCH$r`Rx_ppvSj3amp?uVccvjRv3 zw=deZS>Ng$*UnaLNa=1Ak9r2CZ=1+2d9j5N(1$Vww3-;mG_C1PAXlx@PPelU*E(nM(VB z&%Oao2jqKenD>VKnf!bl!?om05!n{9EEocD0b_X>${xPVO(0zWrzohayIR_u4^rY^ zfNpqSh8w7n;X&2Y!|Kr2eK=x`8vOd+$!~4NbHreFJ zi4;$1X?QPN^k)QI{(x&@$BItTM?nAu>g^lxN+IRR-OC~!EA>eh7MT>MEpFWMFDOt% zdvq54p($WM0Kvbxt*xo6D^|v6(CUe}va*sgbh{CgK1g-Q$&u62MudmI2g}I5zP?Y? z)KV7U#rlz`k?C@NaMHvE0;@@YkcbZ`TPW-lq6-^{F+4&pk z&9Q^_8lQlr2Y`1#Hh0n#l^2RS_mT!v9GV;&jDVBe^XG{6H*x~?TKP(PFc?ftNHAG_ zNyb0DmX%ApB#fl2V~0JE9~56wK);2TT_ofnt4RFzWtT(hqs;wHFA8T){q7CKLr^i@ zPSqgYCiw31Rui@MO65NBOjS`v49;8gmKyXvZUH7EpGM?YR0!G}{x*E)MP98BJY4SI z{6%t2P_K(&4^q))UXLSo8jjB@%3-Ikng$e7uA{Hd+1yvK>~;4;l(?t;N~$Svx0#O$@PwQh@S(u@4*E*Ge9RO5}_41 zUgFeQc!$i7BFWAbHGrxKxigZ6kiRevEmF2Ved7K?Tpg#4p_G5Bx`_9D~ zNI1tE_O1v`vVauD*`24Oi%U!bkkGr)9X8Gq0rFf;&CQKhGf@&UU}hL%>(R(fDuhlX zx;7Xv1nKVG{e2u-_a@lWyUga2Fgnq9hpYGWo_BS0O-<-EgP0B_w%?Bl5HsXLhIUAP zcpq?u(j8=%crezlG`aqD+HDwn(1uU=_-k|K$o5;QY0{ZnQ`0Wb70CcF>zObsB)ig- z$lm0)6LoF~l5pP$LF0tjF%Yu@^@H8RL!2O}e+?^J7$Vi)WgC;Q>u7gWh&?9N<@$=ki)X;0ZYt%+*O!g_bZLxUoP=o-q z^iL2$VYnUdo)SS8K|w=f0JH5@6wK6&lzZ%VTrLby{E@4wHj8q0669V}~g5dg|?5Vj%!C3n8lHfm4~HJr|2= z0fAwLHGQ)b@M~@uL;VO`ACXWWmYCht_aE}Y(Xm($3mfpyM;WbsY3$2T?c#%jcZK;` z_pB^3@5&GhxY;fj%Cml7pOiN5twNAL0=xWYk8&>%S4T66JB{=&+jh?iJL4I0CJNvh zp=7^@i2R4jtV8dfHy>_#KXQaZKte*+)YW~PR#uHpPaj!Z`vgj;6q2rQ$H7R6E~*a# zv{VjzUr^ATm_W6YUzO=N$ehd8ORma)1)j1993Dt4-A5ce`w+fhoj#mJRF3jLCbGZi*My8ccx$hmTCVllJ{$ghtKgP1 z>ag6_+Mn`*v&qwRaVPLf2UY(J;|kN5;Afz^4ODjb@bKF(3C_yWpO}Qyo&r4&)Xmyf zM^8@~K+0KU5?BKdp+95Ds$g7E=0X;BRmCsr@+e7Qi3e)8XN7U!|*ya;T zKj`ZqPiKGr_e)@4;O@~;_ra9`Q_|_3CrC8{uObc?H#hdIFqOmG02!N>rhs*b$>?}R z&2_ladN7Q4yhZ$#^)vY=JlyY>r@l)TW+z;^reeG^G5Ly6RUDjI!3bgdly_b(c# zm5O+m?BkoSbU8z1esDTs3RrliVsfBGtU0<%&!}OUFFIqT#@U=p0(h9?HJHJgzl_FWi0cA;bi= zybgm(&{ILiqfQS*9iIHnmZ#sZuY7(x_#;!SS3YEVnFF1!>5LXrnI&`+Y=sK z6oGOAC^B$@kqHz_Qn{SqWhNPtq(NTn{{H^-!Ar||9xxUVKykWp%zoQ%o*I2@j8Sc= zh0rBRPl2gnN5|@b5q`_gwD&#b$X@kt-B%TLp|rse*1vM=&PlZ3ITImi5-xlOHDF%` zzeEK?JFs9ob>#ui`V7=M#z9;d`jJ|#)swS+=^Fz3swXqG3e8S&N!iBZ-9^j8adT>$ zT|7{2IvR*68YcCpAubKwRfstj8Y9q>4%<*#3SDx_KE7B8hm46-Q~IT6fSZZYcY6K} z9n1E!9>!^2o#&}xv_LSJz*r0(%C%Hj) zb#;La1V6wyR6DB^)^C(7)@{>WWX`em{2HXU;h0EkL3LeaE!O~}He~L8<)$^L-w0mL zwul1WyDg&zs9^!IU4MVSzL^=E%%p@Ia%m8#InlAc^2Dz%VmmPhMiP!UVHmV{%%d%C z^Ixm~{lS+3wz06fP)1erpU=4%d)Z`goi!ghFu8r1Kh}Yh|MN;DfeBmqD1J8?nq`;}+Z2w3Slvz|r>X{w%S;d-|umO|~^#f=Jeo zX<`x!3y+MPo4K+nJ=cADQD>$}?wC+8F;4M8su;!|*YQrd@95R)u$bGF5uCuVPa7}$ZC{g<4%Wfr9BWR|=w9YCB zD(gcoVBDAyF)aV-$i3g}%zstyvghnbwaW|%PpT*>vJ6|0Lc8v+3`A^A|MHgSs3l-5 zSeC*sa zZ4ggjr@L-W?#SqWU&_EcR5fg_2i;xbdz=*)XB`3UPt^%t$RZ2z_pvf{du_vaaI&^? z$fhHyq}0qYL*ehGLs8EHQcakm)6ydHed=qCLoWpwL%#~iq>A0AQx&clq+LW1C;WoK zfw7K9)yuVFtT^|DRP=iwrno5WR{9#OSu9pjF45z<#UC4(>fekTkhAjd zM4|5h#tXw`Ay(x>`!9Z~DDTy8u$(+2%ke`!*J59;R>x-fC3Igt{dS_homs(zux)V+ zPf5qhtUo4r&NNT3!J>eVNyII|NVm38DIm~V@NH|W{X=?Il7+dLo0QkBZ znG5=v5J?FtgM(ojDgv%ah~M;lfUN%gVOUW{VMxUbpH*}#Ho5m!5Kc@MuP$0bu<(fh zz*Y~Qq@~Jli~azYLLDzd9~nxOoLpQ%0pIOY5onJtl3`PnP1y-cLa048t@IUR%58h% zTWIn!V-8`?AnWs)jyNMX0uPG~B?DWcE=qHxLG0E@vSi)jrgCc1#5r;DGHTZcf3?!( zmK4L6x+s;W8|}fIM`c-zi*Hqly4RmufW3TCNSii<117zBnWZuSam?MdJ$IUNSc@}n zwB2u8KS1eUze}CR=unto+H0^&b|}#4n)L{D04&z!$fM45G?`CopQ9(O%N_EMfR8%1 zkEHpRrGLVckF3f|vqtjJKF1lW+3Qy;DJ1IsAu{2fUzS#Iqudr@Vpm?LLlDKIDw@X* z<`5CVz=1Dfg2Ogre7f48APDg^OAegG8O+Ci@UaLDEj}~DiMYnF!eCz%zT?@NQsFoi zNuw@n4^uyeMrUipc1e|SX_-}!2B2Zhrb0eIGhg={HP8}$P?5TO+gwIqLGcd0#sIQ= z7v6ulA~JeaOI{+TS+q6Hzp*<}8%b!MMeW+j;`pA^0~f-)_(tKm>2zo5s@L270cQ7Z z)5gX$R}kOJ)Bo3^%Y~TjT0{FamZe~mYpy$jlKq4eKDUf&kb>LhGBV?dAK-6=dqTGH0zU^<1&CfLJx(&L=+CKpk6dbJ=A2pvhd7(w8 zx7r|8(K{+URc(h%?xa~6hkqc6UosaCS@n1(x30(^K|)%}A|Dg>^l{07IbB=c+TFvR z%01SqBFj1Ic+k$4Y5;IoG#J~HO|@E2pDxK9Cw(?5lk`H{bXmyB z0iRB5iZyCE%}SCm)*WO-9Sy(qpwV^+EPb|M#u~;}Sdf+cYOk-uJ}e6T7Y$p+LRtwM zI*Q$}XQl9B6hI3WNaJ|(GLDC;Z*mwxP@Lj|twqa~~!>v%e z@b_bG@0`xcWiYoO3)MxCaWf=83b4%^rFbu<>cWaEdi~X@jqUK^W5~-wykX)Q8y&Ob zZ|xvbLX5qXjxW1KhwrDrW6s+eKCBdUxQiDsoYoT1SA6H8<(#T=Ix{<=)R>04+dt^f0n27H9$IWb2=*OseV76lteVnbl~F0~z1R<6&a z;vj)@z~pbESQ*L2ZG~%S)*lP}#^XN$fpY6#(j>qb5 zmr(C+6ya6Vj-W8$KQ(LL>0~WWF1ANB&P4U1vH2i4$ufhpOfANieZraJArE%P^rsT~ z#l-POA+OwIBROW?dr{=$F>P;EeY(NH&~}4tOwg5*b;hvneZds{a*Qynr6KEp7`^-x z;F)GgfNGLeFNQa_(?Ikk>Lyvvc0_{=uNfRHv?|V9!L3r4{bg*_-j-K~7sY)2-ZFH4 z+46^dQ58iLS(J&tIB?;Ms{Y)V z$BNjqwPS5zmutmv@-^{*lI0eG=_jffKsQsWJiCG@ks#GbU+I!e_W6E+3?AXL_rL9! z3%s<;-vmwDmj!O5V$KcMf!l z>g&j2oV2&b>%qsn6NgN3q2?Dy z_0yZ_ZVYryzu?sQ&o+|DMb{jnOK=WIh%!x2L;LsBP6{ziU`^5lCIdE@UbvWk7RX{c z29y=Lo72ONeG%^q=vV#`>@-nZ8|rzjn0)Q*%`M|M*9^UBoxJ1lU9YMH!iYwh+uPBzKdknN&aCM)Nku8J7BiOGO3 zukA~M60BL|k1^et(*<|1TiBGl>RP=Z=H0~L;C4QgnC~x0p;cDK#>2~OYs>KQX@6NS zQVSn?t)P9_8~yCisVUfIyPG|Fwr*m%I9QGUR%KCu;>mdclXWy#GH|`5!t7Qz=x$k9 zdQ0rxMg`3)b)W{8F+vcgO(NPlJf8ku57z@h>kg*KSHE zLQ%bK!K&r@+8L~R#-=ED`PQA}ODQNiesPF}4ILC_7FWEr4olhC^%PvM{N?&5(wlmr zj&=jjXE=~LDwamwiTqn&JcL3#+>+^>SxZcodacvMH8PRbpzBdb z{A~APHZF@5{i||x=3JP1kKw~^)!qO}=LlAWO9HKpy6BwDE?CIFTVn3H)}Awf``h<; z|7{#$25K_S0Pk+(@4iIhH?o60Z}T1R+wQuk1u+zxIT zk5_9bx36c;4ByS~9qp|TB~=?4oBT|Q_W7bPRuiopKPgQHwn&e&oXU1DJ<;00 zsu6*b6jXh%2N=ag22qxePCW5ZbSa&(RFn`bdLJ=L{?|*;!a?Qe^s)TxxGF1FKsdZ= zVlg6x;9v!BGo7`H5G9m!>JJM0hdXVjb>Q1L3-a_ZH{`Wp9;7^WtB#E29~-hpF4X+g ze%B`5g~kln)_da>KCko()0gmUte3w5XD;s)tu3iw(H$Op|ueAzi2N8#c~k};a9cttpQb?WEKZ8p2q|VVs!f! zRFnuhp^Y`E*&rTK^L7ir@Ic&m159N|7r{g!ZSMAA_*gBuPvf^=InSEc>T#E(!nXHm?0ek)XZkbZdSI?JZQo2!97lFZ1lDf(qFceB%cB+VUB_XK<7 zsVIOyji<-MdbnlwUR)Na|2>jar|SCqEFp2C8kO0iuKIUXAXh?JrM5ao_z$Ik4Cg59 zFQ+q#VLE+KG0Vf~qArNlT;`en{y`}$%KF&TtV5FO#)zbn5SuEUv*?uW{~%tu5#E0w zuR-@-QD8A|LuYi5Sg}p`7VP%~0b~y5nJUR-@L={ejMMG%B&YW1@BA;bgnBzoMPFbmmSBL24t$Z&6#mk{ zqmgz-T%Dw4C!VBDN1+ITr<&=>U!JH}avAJOCij6hH4#Z7UO#(#T_ z?$Jsf$+*2}?3t&p7;;EBmbKG7*IWH^>W<4s6o>(;`Uhx5GBVlaT+GU|Z0boWnr@_YI2ZE^dF?6m$hE!RcOR8sLV}Mq(k+sutXTe3Y1Tv#c5`I7 z40$MK5GD@i7N}cyhXvw!zf-S2i}OF@ z=(0T}wq5adn@S!34ZuXc=&79B5SwnVd}{;cys#FBczQ=_$5H6BY;8w{IYd>O^ygBZ zrTYTj^YByZ#NBODp3m-2sSs^~VwhDmME30tIV<^QCKOV5QI9F9bv;r~T6!kkQZryo zY1Y2*%y3FCV)}d9E}DBz;Jn)S52Fktxf+F3$&^Z*crjyJCEd-&k+TKd5^BSm%*n9e z-AmVKsGLBzQaCB%R&qtLN@Bv0g^1Rky$R9b!lm9~!V~)w3m?( z5q%+aLr<4|NMft1V(Ra2!4d8M#0yvw?WrSxocJ{RpHn?#u&k&!r{_;-Fr1-PI$82V zD72(A4Z}vYRc@@HJ zO;z*Bb{w+xCSOp3>H^@v!S#Y23p8L_Ke@NwPHL>QjrBW}33DL*M$p4+d@Btuuv^d58VhzE<6#uRmem(hPPnbfWqwGb}fEU6As=O=byE|(7 z@|&3iB7pUA`_p44{#2o-qINHSbBrwwHmgMhjw_nihILIwDKcQl`uFQJ-1K77VZjD? z$V&4myNx{-{=KNu{r3bX-r;2zA|e7b&HeCmd$(_>)64H~!ZF^~eG%!J5j?}%=+TnLsveA=Z^bVzMveV29$^97eIG1S5uL`b;f3WQ z7uwXSfOwB;7R+fcl>5CH^uj7Z%z1N(vJ?#?Z0M$y>Ak_<6?(ZHd;{gKcZ`uMD2EuT zKgvsbu?+3rAGn4)Fo~&q92BwQ`Jq-cGxLm4sI)=>C&)P-%sw8@Lhe)glW{p=P07UY z=Y|EFRS}NU;Y};SAQCu2UQ=`QKF~ZZ;6JTc{wZ)nB&AG*sNi?|8!RS2aGDrQ)im2TTdCW#g-X@?*r;N_#U&emMg-SPqte0KdxZZ5GwM9XIOwWJg7Mmlk zVA~wAZ5e-lT@=$|KV;33B`~1{!(JnNpj6Pi0r8lRe@-t&)7NE-2WOrfF3V?q5xASg_e6dS+^8W2=_@x z3WUAK#@RP@wL{5R9rcyMuwNwS?{Z>S`-%SE8HY88xo#Hwf|x+*-(YORCc9z?Zzow?)6PO87wB02*@MM~gZL-rIom+TPXSx~ zUBn<@7g=R~m|*|RVf=SN_~W!|>DeIBsY)pqTQ7%ccvXl)WbOg0iW`}uEt%b@*gSib zQ^vuCW|~>@q(mcjK`&LpE@+_Iem(Ib&r#)f*z|4oXanWm(BEIEb=N!RnQPMAgZ6h; zu~q-}f-MZvJi3(CH(9aOW`E+i@i+fU+D7E2s13s!9N}hCHq5 zjI-(3CTo7Zj$1zhk-%zF)PBP;Eai|Z{TeUKspEX)HDR;2BVN8#br%Sb~xk&54HhgszJ4;txWo3abBgvFH_JDcs@B0P- zLMUy`k1eGSsUvfoPy8H;Dq?iFl3(}r=dHcgV-Z6Tvy-5=F5mb53lXBaf z3z@6VBkgmbhl1*$?#M_uk`+jLbc6$?zL+RzotHltShj}1+w&I;op<@Y$#(6RZ+YC9 z#z>EjRoBzv+M@+lb|Tve*#yGSw3MQ)6ZvKjsyf4Obk`%AU6(i;`0rX9NkQ zKuEA?&N083q0mo!2PW*`371Ia~_@pkM z$9KZYY@fUxTh%D=@$uJ9Xa4J-{F|TxRz9-k0zK$aoUVr0DZb8h08tqcVO7rRQ_#D)+4}ckI7tvFQ64PJN0mGp=qPGPvWO z-Pbw3`jdDDia>$1ubnX#U)X%XCkGjx4o%Gxw1fa{eDxHzXhn?yfcN4(@O14?IcBcW z+dq^YFCi>v%gsf5zXT}Gzxh4KC++0tL8o2L!2IJM8i2t#m&*6zq`qZDH^DQx1D{*% zdUaV#`<&rr@{V`H`-YoO{VO>%FCt^;+N+8LQ*DA#JI~hqs`hFT&lmh|)qV6o9vZ4> zczZjQZ5!Hw)KtdTxJkbr5mq6x0h?s-2CN3%GJi3i)ZM&_H{A7VA(6h@Ce4J-5!7~__PXS{k z{<(YgeC0rHU>R)GKoLnlmcj=$+T2j=W~7mtnmnIki@!8|CiWfEG<3Hp%Y>KTHg-=M z!8RH;OcMp%@?Z6lOF>(k zQodoL7AQ3H{4K8GQHkZBd51+bH1yv3&GMSwnawNqr@fMHXgiK-g<~KG@!Fhvr zgQ8Ae8O!h~=`{IsN8AoLF!P`NY>c#j`o!QiMTt4u!-Aqt!Mc0>silSI`e+ezrOoXw zG+0#BFv~piemb+Ah{o=Xr}xM2H8t%US;cG}aFMfum3g80!GE%Evx&+mzT{mOVSQl# z;0^Os%{7i=Mez|yl6)Q$Y@UJ%!{~1aZv>y&DVPG)$e76Rj<>J9uCN5Iz^CneOnyU3 zylKKEPaN;IP<{$4Pd?UcO^qt;DJ?eWyxhQKRA`WFdqk91iV&Y1>s)jU4sMuJgr3$c z{r<1GlnEdPC@FKCLa5ct%Y5|EIwwN^SAC?*Zcjomw1c0u#-FuMhVjk_+(&@JoyJ7r zdIQ--Rh*w?(E&)vF+ubi=lH|a1WHojLKtLiN6tZXR76zvunQoeh)_}=nnPAnL=V4bSz{`5yXQ zEHS$-ir;*Ejk@&QNX8AjFu|mZy!DvA0x~XRB5XYzP-3irb~L$U37j z;f5_vp;VxmiYH_^uG7J{M@Ar@|af^?DrLK{w{AUJV52lRHsY1ej#Q*-=vN`u(^;` zUT8dOqXP8Ei+%xG=f@-nP$ti!oB%B{w&=P?0Y=N z2112Q6cE53T0$3oBCrY}Oq3Q-Tn8KXPVe;R3hdNvV8EuX_wS1eyQmPpc;ZFQDh#Fj zilx5e-XKQdFwc}NYF8*u@%)69$Cv_kNmJ=Z4W`f4Oun|zI)6Q>HDvdzZ;dA#Knzfx z9C2@Pe%N(zJt(rKGV&P1EN@QA_N4{RDbb;b@_5cR{X92YBWixTL|$K*x;+ioV>O)0 zrk)I%6!U7FdQ1e!P!d&;8IvL=qft{zMC}FX`h~ zGF!Zf-i&RY`6a(Fk>+}xw9J0Kl|i(6gTL(U>8;lA<{nmAzTIP_YZQ2LI+nEai~=#H zNtloxbQ+EY*!JDJk$<}iil)jX%^-hz(#BtI+(#dTQ5i;E=`ni&Cnf zTSnhcEQj^8uP<_zh7|>9$>vzR4&Ua{ol!SETre1uA~JSi791^sL-I{s;t27lXKD8) z!V@locfq@2SB}NHB>ZHP^=ez}^LrsP(@I1i@E{JBcpeU`?N{Zb*P+O;<)26(O#2F$ zIC96wc}2v;G8^cjsbGS3WitK`Wp4pgSF~mcM<5WK;7$m^-JJjl1b4UK?ye^U3vR(J zxVyW%yL<49yZ?v0_j-DIUiZvj1yxWLF5#ZD_gVI>of@ZEkt{q!ST&l%8jdM$;tTE1 zY^p2-@Bahh$A*iSF}##p!>WYe*B`T&tO8utmU0(;Xb!urTK)_F!1Yc#c$1U5bxJSd z$U2eY{_X&rU4|(k1Xp*@vlPHN^In2X-rWW*i6`qVg{dnQk?g!`QVu+>gL6#hF647wB1S_+1d1<53kgX&YaiH-XfP=zyG%Bm;}W z-0!tPTT)6l+v3TQCTOO=H-~) z=3L(9S$2EZ_Hw#dm7pwq+ZnKkXDV4=bTjH};-ROZ;^L~`IV2DqyOs6e^b#CN8YvI6 zTn)tIFZ9i(QcBri*jOYQNgfm9qQJH?n*!ZF!~a6GsPoaY2)8)qp$S_|VAypgLl*nTA=5td^f zf3;Q`><*vJi}Q4_n2ZaWc_FEIC(r_tY`rQ1xeIi+av#O=P3E~vvJdZ=Q+7I3ntK|E z05sI~fO$zJdx_1CfX`jC&U<8YOhmEZb8~++cxIZ`tfeD0ly~6nP#bj8-hn7u#c?6F z%>BBgb}zqx>`OuXrj*@uc0@w! zdJ{!yfuO@o01m7`WuMdltGeeL1bB$^m{OB$W0U#IMI+!k9^|8 z!Z;YxA1StL5$1QgjoZn=Z!8*NySqwbzq0dsU{&dpi0eh~s*EM|erS0Y z;3_$F@fC`^tGZaz25Y9cR@{>o1O;SXi$|VVL;GLyioV?4Z_9=PgkPEt*b+)q`xkPg z#vS(vZbw?85~5uG5xff=ui5DeDUW(3opHkQxFy#gWXib~;;MokT!|lNtXz)CE;%Nf z%{eTA0avty%&cd}$`d68<~Nj7~}7r{Pij+cq3> z`1L$&5Rr8GtrboebD4sJ6itlN1~Ia83gQp=T0Z7nh<+)Be%Hpw@f1ov?GtiJ<;>8-FHPvcpQHjqwiG&oWUFzGo- znHEn(Z8BO&DTypmw(>d3K)+E^w#r{P2gb=Jms(AB@GXq)cxI|%MdX{I(5`(3%%8Fq zx^I%>WJ9t}SakJ5)EN^dzwz)%R4#=F(`LM}<^h81Z9n3D6rFM)(;eBl?Z(}HS0bes zEt?Oxr_wZR;7mm3hHXd^jXbd9qJk*f2kE3?OH zB?&cmqD!4}a6kLx$`Hnut!>F&COTMrV;8s-2I+A;iX|D3d^nh^I(pk&#}E?SaP;O= z!@1mTid*PS>UHNL&18V1rrn&(UVkvTFCfa8oSaOfR%zV+id<39gpPTlpC+couISKc z|03J<6fR&jb5zMNw0|g-;&)9!>e*5CgiUr(8ZzJNDPFAI!D$4M*3&Vu6@jbZbN05K z<2hgHdC6QUPM6kF99k%u*h@*9wI6R(tN-9i`P+vjM9^AN_8c`kewrALaoQE2m!Bg} zLgLdXbd7_bp_Vv0`i}ChP4vALL0wp)r8e&D*ejr(e`m9EEUHk==HhF&IPLw(&e8Sp zwkN4Cn72zJ!9Y#YetL8`tUa4RIGk-uIkY77ywAx^tUAbOK)#Ll zBxFN)wD7y�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� z*BBl^P0ag77h%rP9ZC`}dM(yi#fzgd8Z3u6drNvfNXrh+f z=_wwIj1s!EG;zqhp+F𝔩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 BgR=n9b~x>?&fxwnJCYQ$vxT1I`J)`M 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 aKb2CVJ7z_#Q77P4p3zj*RVlx38T=pYLwFAW From dda667d064930bd536a690ad291e729f2b1439d7 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 17 Sep 2019 15:10:46 -0400 Subject: [PATCH 23/27] Updated portable case doc --- .../images/portable_case_folder.png | Bin 12149 -> 14228 bytes docs/doxygen-user/portable_case.dox | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/doxygen-user/images/portable_case_folder.png b/docs/doxygen-user/images/portable_case_folder.png index a02bd4e087bcbacf3ab2ae96422d5939ab65420c..1e3a5b98df05eb8df9607de5b48f31217540cbce 100644 GIT binary patch literal 14228 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 q2>rW|65t_^X|lh`s1G3rmVzX)h literal 12149 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 diff --git a/docs/doxygen-user/portable_case.dox b/docs/doxygen-user/portable_case.dox index b476206a38..34dcc7bf57 100644 --- a/docs/doxygen-user/portable_case.dox +++ b/docs/doxygen-user/portable_case.dox @@ -2,7 +2,7 @@ \section portable_case_overview Overview -A portable case is a partial copy of a normal Autopsy case that can be opened from anywhere. It contains a subset of the data from its original case and has been designed to make it easy to share relevant data with other examiners. +A portable case is a partial copy of a normal Autopsy case that can be opened from anywhere. It contains a subset of the data from its original case and has been designed to make it easy to share relevant data with other examiners. Portable cases will contain a \ref report_case_uco report detailing the contents of the portable case. The general use case is as follows: @@ -29,7 +29,7 @@ A portable case can contain tagged files and results and data from the Interesti \image html portable_case_interesting_items.png -You can tag any additional files you want to include in the portable case. See the \ref tagging_page page for details on how to create tags. You can see what tags you've added in the \ref tree_viewer_page. +You can tag any additional files you want to include in the portable case. See the \ref tagging_page page for details on how to create tags. Note that the outlines from \ref image_tagging "image tags" will also be visible in the portable case. You can see what tags you've added in the \ref tree_viewer_page. \image html portable_case_tags.png @@ -39,7 +39,7 @@ The portable case will be placed in the "Reports" folder in the current case. \image html portable_case_report_panel.png -Here you can see an unpackaged portable case. It will be named with the original case name plus "(Portable)". The portable case is initially missing many of the normal Autopsy folders - these will be created the first time a user opens it. +Here you can see an unpackaged portable case. It will be named with the original case name plus "(Portable)". The portable case is initially missing many of the normal Autopsy folders - these will be created the first time a user opens it. It will however start with a "Reports" folder that contains an automatically generated \ref report_case_uco report. \image html portable_case_folder.png From 7d2aedcf95f390bf41d22597e382c4ce60718d30 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 17 Sep 2019 15:13:40 -0400 Subject: [PATCH 24/27] removed commented out code --- .../timeline/ui/detailview/EventNodeBase.java | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java index 1977d3ce6d..19aada1393 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java @@ -293,32 +293,6 @@ public abstract class EventNodeBase extends StackP @Override protected String call() throws Exception { -// HashMap hashSetCounts = new HashMap<>(); -// if (tlEvent.getEventIDsWithHashHits().isEmpty() == false) { -// try { -// //TODO:push this to DB -// for (TimelineEvent tle : eventsModel.getEventsById(tlEvent.getEventIDsWithHashHits())) { -// Set hashSetNames = sleuthkitCase.getContentById(tle.getFileObjID()).getHashSetNames(); -// for (String hashSetName : hashSetNames) { -// hashSetCounts.merge(hashSetName, 1L, Long::sum); -// } -// } -// } catch (TskCoreException ex) { -// LOGGER.log(Level.SEVERE, "Error getting hashset hit info for event.", ex); //NON-NLS -// } -// } -// String hashSetCountsString = hashSetCounts.entrySet().stream() -// .map((Map.Entry t) -> t.getKey() + " : " + t.getValue()) -// .collect(Collectors.joining("\n")); - -// Map tagCounts = new HashMap<>(); -// if (tlEvent.getEventIDsWithTags().isEmpty() == false) { -// tagCounts.putAll(eventsModel.getTagCountsByTagName(tlEvent.getEventIDsWithTags())); -// } -// String tagCountsString = tagCounts.entrySet().stream() -// .map((Map.Entry t) -> t.getKey() + " : " + t.getValue()) -// .collect(Collectors.joining("\n")); - return Bundle.EventNodeBase_tooltip_text(getEventIDs().size(), getEventType(), getDescription(), TimeLineController.getZonedFormatter().print(getStartMillis()), TimeLineController.getZonedFormatter().print(getEndMillis() + 1000)); From f542ca7520f9faf71cec235530668d87549f224f Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 17 Sep 2019 15:29:29 -0400 Subject: [PATCH 25/27] Updates based on review comment --- .../timeline/ui/detailview/EventNodeBase.java | 5 ----- .../ui/filtering/datamodel/RootFilterState.java | 12 ------------ 2 files changed, 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java index 19aada1393..3ee088f2ad 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/EventNodeBase.java @@ -24,15 +24,12 @@ import com.google.common.collect.Sets; import com.google.common.eventbus.Subscribe; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.logging.Level; -import java.util.stream.Collectors; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; @@ -82,9 +79,7 @@ import static org.sleuthkit.autopsy.timeline.ui.detailview.EventNodeBase.show; import static org.sleuthkit.autopsy.timeline.ui.detailview.MultiEventNodeBase.CORNER_RADII_3; import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.DetailViewEvent; import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TimelineEventType; -import org.sleuthkit.datamodel.TimelineEvent; /** * diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/RootFilterState.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/RootFilterState.java index d33a32ed21..e3c8b8d6d5 100755 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/RootFilterState.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/RootFilterState.java @@ -161,18 +161,6 @@ public class RootFilterState extends CompoundFilterState> getSubFilterStates() { ImmutableMap, Integer> filterOrder From ba24db42ba632c395300972bc68e6e6749886c8c Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Wed, 18 Sep 2019 09:24:38 -0400 Subject: [PATCH 26/27] Update ArtifactSelectionDialog.java Fix index out of bounds error --- .../autopsy/report/ArtifactSelectionDialog.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java index b0655dfa2b..4ab05a11aa 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java +++ b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java @@ -54,7 +54,7 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { /** * Creates new form ArtifactSelectionDialog - * + * * @param parent The parent window * @param modal Block user-input to other top-level windows. */ @@ -110,9 +110,11 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { @Override public void mousePressed(MouseEvent evt) { int index = artifactList.locationToIndex(evt.getPoint()); - BlackboardArtifact.Type type = model.getElementAt(index); - artifactTypeSelections.put(type, !artifactTypeSelections.get(type)); - artifactList.repaint(); + if (index >= 0) { + BlackboardArtifact.Type type = model.getElementAt(index); + artifactTypeSelections.put(type, !artifactTypeSelections.get(type)); + artifactList.repaint(); + } } }); } From 716e0227dd00891475aa4914d18551973f12385a Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Wed, 18 Sep 2019 11:58:00 -0400 Subject: [PATCH 27/27] Update FileViewer.java Add check if abstract is file and ignore if it is. --- Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java index dddf0f6296..1b0d048f35 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java @@ -117,7 +117,7 @@ public class FileViewer extends javax.swing.JPanel implements DataContentViewer } AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class); - if (file == null) { + if ((file == null) || (file.isDir())) { return; } @@ -189,7 +189,7 @@ public class FileViewer extends javax.swing.JPanel implements DataContentViewer } AbstractFile aFile = node.getLookup().lookup(AbstractFile.class); - if (aFile == null) { + if ((aFile == null) || (aFile.isDir())) { return false; }